Ladebug Debugger Manual

Compaq Tru64 UNIX Version 5.1A or higher

Ladebug Version 67, February 2002

Information in This Page Is for Use by All Ladebug Customers

© 2002 Compaq Information Technologies Group, L.P.

Table of Contents

About This Manual Part I: A Quick Introduction to Using the Ladebug Debugger Part II: A Guide to Using the Ladebug Debugger
Part III: Advanced Topics


  • Appendixes

    About This Manual

    What Is the Ladebug Debugger?

    This manual explains how to use the Compaq Ladebug debugger for Version 67 or higher. Earlier versions of the debugger may not support all the capabilities documented in this manual.

    Ladebug is a symbolic source-level debugger with a choice of command line or graphical user interface.

    Ladebug provides extensive support for debugging programs written in C, C++, and Fortran (77 and 90) for the following operating systems:

    Ladebug also offers limited support for COBOL and Ada programming.

    The official Software Product Description is part of the Developers' Toolkit Software Product Description (SPD 44.36).

    Obtaining a Ladebug Kit

    Ladebug kits, manuals, and answers to the frequently asked questions (FAQs) are available from the following sources:

    Audience

    This manual is intended for programmers who have a basic understanding of one of the programming languages that the Ladebug debugger supports (C, C++, Fortran, COBOL, and Ada) and the Compaq Tru64 UNIX or Linux for Alpha operating systems.

    Organization

    This manual is organized as follows:

    Related Documentation

    The following documents contain related information:

    Reporting Problems

    Send mail to Ladebug.Support@Compaq.com.

    What to Report

    Please provide the following information when you enter your problem report. Doing so will make it easier for us to reproduce and analyze your problem. If you do not provide this information, we may have to ask you for it.

    The Ladebug development team can use ftp to fetch sources and executables if you can place them in an anonymous FTP area. If not, you may be asked to use another method.

    Conventions

    The following conventions are used in this manual:

    Convention Meaning
    % A percent sign (%) represents the C shell system prompt.
    # A pound sign (#) represents the default superuser prompt.
    UPPERCASE
    lowercase
    The Tru64 UNIX operating system differentiates between lowercase and uppercase characters. On the operating system level, you must type examples, syntax descriptions, function definitions, and literal strings that appear in text exactly as shown.
    Ctrl/C This symbol indicates that you must press the Ctrl key while you simultaneously press another key (in this case, C).
    monospaced text This typeface indicates a routine, partition, pathname, directory, file, or non-terminal name. This typeface is also used in interactive examples.
    monospaced bold text In interactive examples, this typeface indicates input that you enter. In syntax statements and text, this typeface indicates the exact name of a command or keyword.
    monospaced italic text Monospaced italic type indicates variable values, place holders, and function argument names.

    In syntax definitions, monospaced italic text indicates non-terminal names. When a non-terminal name consists of more than one word, the words are joined using the underscore (_), for example, breakpoint_command.

    italic text Italic type indicates book names or emphasized terms.
    foo_bar
        : item1
        | item2
        | item3
    A colon starts the syntax definition of a non-terminal name (in this example, foo_bar. Vertical bars separating items that appear in syntax definitions indicate that you choose one item from among those listed.
    [] In syntax definitions, brackets indicate items that are optional.
    option ;...
    option ,...
    option  ...
    A set of three horizontal ellipses indicates that you can enter additional parameters, options, or values. A semicolon, comma, or space preceding the ellipses indicates successive items must be separated by semicolons, commas, or spaces.
    setld(8) Cross-references to online reference pages include the appropriate section number in parentheses. For example, setld(8) indicates that you can find the material on the setld command in Section 8 of the reference pages. The man command % man 8 setld shows the reference page for this command.

    In this manual, some examples show Ladebug version numbers as "Version n". When you use the debugger, the actual version numbers appear on your screen.


    Part I
    A Quick Introduction to Using the Ladebug Debugger

    Part I provides all the information you need to make simple use of the debugger.

    Chapter 1—Overview

    You look for a bug by doing the following:

    1. Find a repeatable reproducer of the bug — the simpler the reproducer is, the simpler the following steps will be to do.

    2. Prepare your program for debugging.

    3. Start the debugger.

    4. Give commands to the debugger.

      • Command the debugger to do one of the following:
        • Prepare to create a process running the program.
        • Attach to and interrupt a process that you created using normal UNIX methods.

      • Command the debugger to create breakpoints that will pause the process as close as possible to where the bug happened.

      • If you are using the debugger to create the process, tell it to create the process now.

    5. Do whatever it takes to reproduce the bug, so that the breakpoints will stop the process close to where the bug has caused something detectably wrong to happen.

    6. Look around to determine the location of the bug:
      • If the bug is in code where the debugger has stopped the process, exit the debugger and fix the bug.
      • If the bug has not happened yet, remove any breakpoints that are triggering too often, create other breakpoints that work better at locating the problem, and continue the process.
      • If the bug has already occurred, take the same steps of creating breakpoints and so on, except with the process running backward. Unfortunately, reverse execution is a difficult problem (how do you un-erase that disk?), so the compilers and the debugger do not support it. Instead, you have to rerun from an earlier position (a snapshot if you made one, or else the beginning of the program), first creating breakpoints that stop the process sooner.

    1.1 Preparing a Program for Debugging

    Compile and link your program using the -g switch, as follows:
    
    

    If the problem only occurs in optimized code, use the -g3 switch.

    1.2 Starting the Debugger

    Before you start the debugger, make sure that you have correctly set the size information for your terminal; otherwise, the debugger's command line editing support may act unpredictably. For example, if your terminal is 47x80, you may need to set the following: Following are four basic alternatives for running the debugger on a process:

    If your call stack seems to be missing routines, you may be seeing the result of a compiler optimization known as "tail calls."

    If your call stack is corrupted, you may see random numbers without any routine names. In this case, it is likely that your application has gotten lost. Typically, this type of call stack display means that your application has lost track of the real stack and real code location, and is now executing random bits of memory, interpreting them as instructions.

    If you are coding in C++, one of the most common ways to get a corrupt stack is for your code to try to execute a method on an invalid object. If the object has already been deleted, has not yet been initialized, is not there, or is of a completely different type, then the virtual function table will not be correct, and the application will be treating random memory as the virtual function table and calling a random place. In this case, you may find the history tool useful to locate the problem. See the Ladebug Web page FAQ for more information about the history tool.

    8.3.1 Navigating the Call Stack

    You can select one of the call frames as the starting point for examining variables. This call frame provides the current scope in the program for which variables exist, and tells the debugger which instance of those variables whose values you want to see:
    change_stack_frame_command
            : up   [ expression ]
            | down [ expression ]
            | func [ loc ]
    

    Use the up command or the down command without the expression to change to the call frame located one level up or down the stack. Specify an expression that evaluates to an integer to change the call frame up or down the specified number of levels. If the number of levels exceeds the number of active calls on the stack in the specified direction, the debugger issues a warning message and the call frame does not change.

    When the current call frame changes, the debugger displays the source line corresponding to the last instruction executed in the function executing the selected call frame.

    When large and complex values are passed by value to a routine on the stack, the output of the up and down commands can be voluminous. You can set the control variable $stackargs to 0 to suppress the output of argument values in the up and down commands.

    Use the func command without the loc to display the current function. To change the function scope to a function that has a call frame in the call stack, specify the loc either as the name of the function or as an integer expression evaluating to the call level. If you specify the name, the most-recently entered call frame for that function becomes the current call frame.

    If no frames are available to select from, the debugger context is set to the static context of the named function. The current scope and current language are set based on that function. Types and static variables local to that function are now visible and can be evaluated.

    If you enter an integer expression, the debugger moves to the frame at level n, just as if you had entered up n at the level 0 function.

    In the following example, the current call frame is changed to one for method Planet::print so that a variable in that instance of print() can be displayed:

    In the previous example, instead of entering func Planet::print, you can enter down 2. (You would use down in this case because the current call frame at the start of the example was not the bottommost frame.) The final stack trace in this example lists a call frame for function Planet::print as the current call frame (denoted by the > character).

    8.3.2 The pop Command

    The pop command removes one or more call frames from the call stack:
    pop_stack_frame_command
            : pop [ expression ]
    
    The default is one call frame. The pop command undoes the work already done by the removed execution frames. It does not, however, reverse side effects, such as changes to global variables.

    NOTE: Because it is extremely unlikely this will fix all the effects of a half-executed call, this command is not recommended for general use. Furthermore, the pop command does not provide a way to specify a return value when the frame being discarded corresponds to a function that should return a value. You may need to use the assign command to restore the values of global variables.

    Instead of the pop command, you may want to use the return command, which finishes the call corresponding to the selected frame.

    8.3.3 Call Frames and Optimized Code

    When optimized machine code is generated by the compilers, the compiler generates code that maintains the call stack, but sometimes the function boundaries are changed in one of two ways:

    Depending on the information the compiler makes available to the debugger, inlined calls may or may not show up in the call stack display. Outlined calls do show up, and are correlated to the code they came from. The compiler will probably have supplied the debugger with some invented name for the function.

    8.3.4 Call Frames and Machine Code Correlation

    On a RISC processor, such as a Compaq Alpha processor, the following is the machine code typically generated for a call to a function: When the thread is partway through the call frame creation or tear-down, the debugger will still show the call frame, but will not be able to show correct values for the variables or parameters.

    8.3.5 Special C++ Issues

    For nonstatic member functions, the implicit this pointer is displayed as the address on the stack trace along with the class type of the object, as shown in the following example:

    8.4 Looking at the Data

    After you have seen the call stack (show_stack_command), selected the call frame containing the variables you wish to examine (change_stack_frame_command), and looked at the source this function is executing (looking at the source) , you usually want to examine some of the variables or even evaluate some expressions. You can use the print command and the call command to do this. You can also use the following commands to help you determine what to look at and what you are seeing:
    look_around_command
            : various_print_command
            | c++_look_around_command
            | call_command
            | whatis_command
            | whereis_command
            | which_command
    
    various_print_command
            : print_command
            | printf_command
    	| printi_command
            | print_registers_command
    	| printt_command
            | dump_command
    

    8.4.1 The print Command

    You can print the values of one or more expressions or all local variables. You can also use the print command to evaluate complex expressions involving typecasts, pointer dereferences, multiple variables, constants, and any legal operators allowed by the language of the program you are debugging:
    print_command
            : print [ expression ,... ]
            | print rescoped_expression
            | print printable-type
            | printb [ expression ,... ]
    	| printd [ expression ,... ]
    	| printo [ expression ,... ]
    	| printx [ expression ,... ]
    	    
    rescoped_expression
            : filename ` qual_symbol
            | ` qual_symbol
    
    qual_symbol
            : expression
            | qual_symbol ` expression
    
    For an array, the debugger prints every cell in the array if you do not specify a specific cell. For arrays or lists, you can use debugger variables and aliases to do a traversal of the data structure (see the array navigation example).

    Use the $hexints, $decints, or $octints variables to select a radix for the output of the print command. If you do not want to change the radix permanently, use the printx, printd, printo, and printb commands to print expressions in hexadecimal, decimal, octal, or binary base format, respectively.

    Consider the following declarations in a C++ program:

    The following example uses the print command to display a nonstring array: The following example shows how to print individual values of an array:
    8.4.1.1 Dereferencing Pointers
    Pointers are variables that contain addresses. By dereferencing a pointer in the command interface, you can print the value at the address pointed to by the pointer. In C and C++ programs, variables containing a pointer are dereferenced using the * operator. The following example shows how to dereference a pointer in C++ programs:
    8.4.1.2 Printing C Strings
    The debugger does not print more than the first $maxstrlen characters of a null-terminated string. Change this debugger variable if it is showing either more or less than you wish to see.
    8.4.1.3 Printing Floating Point Numbers
    Floating point numbers are represented inside the computer in binary floating point. They are converted to decimal floating point when printed. The two formats are not the same, and some numbers are easily represented in decimal but not in binary (for example the number 1.1). The internal binary form for such numbers is an approximation, the closest that can be made given the number of bits available.

    Normally, when a binary floating point number is printed, the shortest decimal number that would be represented by that binary number is used as the number to print, as it is a legitimate representation of the internal binary number. However, to see a more exact (extended form) representation of a binary floating point number, you can set the $floatshrinking debugger variable to 0 (zero).

    The following example shows the result of converting 1.1 (shortened form) to the closest long double binary floating point number (extended form):

    	(ladebug) p $floatshrinking
        	1
        	(ladebug) p 1.1
        	1.1
        	(ladebug) set $floatshrinking = 0
        	(ladebug) p 1.1
        	1.10000000000000000000000000000000008
    
    Currently, the extended forms are only available for long double variables and expressions.

    For more detail on floating point representation, see ANSI IEEE Standard 754-1985.

    8.4.1.4 Restrictions on the print Command
    Expressions containing labels are not supported. Variables involving static anonymous unions and enumerated types may not be able to be printed. Printing a structure that is declared but not defined in a compilation unit may generate an error message indicating that the structure is opaque.

    8.4.2 The printf Command

    Use the printf command to format and display a complex structure. The first argument is a string expression of characters and conversion specifications using the same format specifiers as the printf C function. The printf command requires a running target program because it uses libc.
    printf_command
            : printf [ format_string [ , expression  ,... ] ]
    
    For example:

    8.4.3 The printi Command

    The printi command takes one or more numerical expressions and interprets each one as an assembly instruction, printing out the instruction, and its arguments when applicable. This command is typically used by engineers performing machine-level debugging.
    printi_command
    	: printi [ expression  ,... ]
    
    For example:

    8.4.4 The printregs Command

    Use the printregs command to display the values of all the hardware registers. The list of registers displayed by the debugger is machine-dependent. By default, most values are displayed in decimal radix. To display the register values in hexadecimal radix, set the $hexints variable to 1.
    print_registers_command
            : printregs
    
    For example:

    8.4.5 The printt Command

    The printt command takes one or more numerical expressions and interprets each one as the number of seconds since the Epoch (00:00:00 UTC 1 Jan 1970; see ctime(3) for more information).
    printt_command
            : printt [ expression  ,... ]
    
    For example:

    8.4.6 The dump Command

    Use the dump command without an argument to list the parameters and local variables in the current function. To list the parameters and local variables in an active function, specify it as an argument.

    Use the dump . command (include the dot) to list the parameters and local variables for all functions active on the stack:

    dump_command
            : dump qual_symbol
            | dump .
    
    For example:

    When large and complex values are passed by value to a routine on the stack, the output of the dump command can be voluminous. You can set the control variable $stackargs to 0 (zero) to suppress the output of argument values in the dump command.

    8.4.7 The call Command

    After a breakpoint or a signal suspends program execution, you can execute a single function in your program by using the call command, or by including a function call in the expression argument of a debugger command. Calling a function lets you test the function's operation with a specific set of parameters.
    call_command
            : call call-expression
    
    Specify the function as if you were calling it from within the program. If the function has no parameters, specify empty parentheses (()). For multithreaded applications, the call is made in the context of the current thread. For C++ applications, when you set the $overloadmenu debugger variable to 1 and call an overloaded function, the debugger lists the overloaded functions and calls the function you specify. When the function you call completes normally, the debugger restores the stack and the current context that existed before the function was called.

    While the program counter is saved and restored, calling a function does not shield the program state from alteration if the function you call allocates memory or alters global variables. If the function affects global program variables, for instance, those variables will be changed permanently.

    Functions compiled without the debugger option to include debugging information may lack important parameter information and are less likely to yield consistent results when called.

    The call command executes the specified function with the parameters you supply and then returns control to you (at the Ladebug prompt) when the function returns. The call command discards the return value of the function. If you embed the function call in the expression argument of a print command, the debugger prints the return value after the function returns. The following example shows both methods of calling a function:

    In the previous example, the call command results in the return value being discarded while the embedded call passes the return value of the function to the print command, which in turn prints the value. You can also embed the call within a more involved expression, as shown in the following example: All breakpoints or tracepoints defined and enabled during the session are active when a called function is executing. When program execution halts during function execution, you can examine program information, execute one line or instruction, continue execution of the function, or call another function.

    When you call a function when execution is suspended in a called function, you are nesting function calls, as shown in the following example:

    Restrictions on the call Command

    The debugger supports function calls and expression evaluations that call functions, with the following limitations:

    8.4.8 The whatis Command

    You can print information about the basic nature of a whatis_expression. The expression can be a normal language expression or the name of a type, function, or other language entity. The debugger shows you information about the entity rather than evaluating it. However, it will evaluate any contained expressions, such as pointers, needed to determine the entity to which you are referring.
    whatis_command
            : whatis whatis_expression
    
    The following example uses the whatis command to determine the storage representation for the data member _classification:

    8.4.9 The whereis Command

    The whereis command lists all declarations of a variable and each declaration's fully qualified scope information.

    The scope information of a variable usually consists of the name of the source file that contains the function in which the variable is declared, the name of that function, and the name of the variable. The components of the scope information are separated by back-quotes (`).

    whereis_command
            : whereis whereis_name
    	| whereis whereis_string
    
    whereis_name
            : identifier_or_typedef_name
            | ( identifier_or_typedef_name )
    	
    whereis_string
    	: string
    
    You can use the whereis command with the whereis_name to obtain information needed to differentiate overloaded identifiers that are in different units, or within different routines in the same unit. The following example shows how to set breakpoints in two C++ methods, both named print: See also the which command for another example of the whereis command.

    If you are not sure how to spell a symbol, you can use the whereis command with the whereis_string to search the symbol table for the regular expression represented by the quoted string. All symbols that match the rules of the regular expression are displayed in ascending order. For example:

    You can use the $symbolsearchlimit debugger variable to specify the maximum number of symbols that are returned by the whereis command for a regular expression search. The default value for the $symbolsearchlimit variable is 100; a value of 0 indicates no limit.

    8.4.10 The which Command

    Use the which command to determine which declaration an identifier resolves to. The which command shows the fully qualified scope information for the instance of the specified expression in the current scope.

    The scope information of a variable usually consists of the name of the source file that contains the function in which the variable is declared, the name of that function, and the name of the variable. The components of the scope information are separated by back-quotes (`).

    which_command
            : which which_name
    
    which_name
            : identifier_or_typedef_name
            | ( identifier_or_typedef_name )
    
    The following example shows how to use the whereis and which commands to determine a variable's scope:

    8.4.11 Notes on C++ Debugging

    The following sections describe the debugger commands specific to debugging C++ programs.
    8.4.11.1 Setting the Class Scope Using the class Command
    The debugger maintains the concept of a current context in which to perform lookup of program variable names. The current context includes a file scope and either a function scope or a class scope. The debugger automatically updates the current context when program execution suspends.

    The class command lets you set the scope to a class in the program you are debugging:

    c++_look_around_command
            : class [ class_name ]
    
    If class_name is not specified, the class command displays the current class context.

    Setting the class scope nullifies the function scope and vice versa. To return to the default (current function) scope, use the command func 0.

    Explicitly setting the debugger's current context to a class enables you to view a class to:

    After the class scope is set, you can set breakpoints in the class's member functions and examine data without explicitly mentioning the class name. If you do not want to affect the current context, you can use the scope resolution operator (::) to access a class whose members are not currently visible. Use the class command without an argument to display the current class scope. Specify an argument to change the class scope. After the class scope is set, refer to members of the class by omitting the classname:: prefix.

    The following example shows the use of the class command to set the class scope to List<Node> in order to make member function append visible so a breakpoint can be set in append:

    8.4.11.2 Displaying Class Information
    The whatis and print commands display information on a class. Use the whatis command to display static information about the classes. Use the print command to view dynamic information about class objects.

    The whatis command displays the class type declaration, including the following:

    For classes that are derived from other classes, the data members and member functions inherited from the base class are not displayed. Any member functions that are redefined from the base class are displayed.

    The print command lets you display the value of data members and static members. Information regarding the public, private, or protected status of class members is not provided, because the debugger relaxes the related access rules to be more helpful to users.

    The type signatures of member functions, constructors, and destructors are displayed in a form that is appropriate for later use in resolving references to overloaded functions.

    The following example shows the whatis and print commands in conjunction with a class:

    8.4.11.3 Displaying Object Information
    The whatis and print commands display information on instances of classes (objects). Use the whatis command to display the class type of an object. Use the print command to display the current value of an object.

    You can also display individual object members using the member access operators, period (.), and right arrow (->) in a print command.

    You can use the scope resolution operator (::) to refer to global variables, to refer to hidden members in base classes, to explicitly refer to a member that is inherited, or to name a member hidden by the current context.

    When you are in the context of a nested class, you must use the scope resolution operator to access members of the enclosing class.

    The following example shows how to use the whatis and print commands to display object information:

    8.4.11.4 Displaying Static and Dynamic Type Information
    When displaying object information for C++ class pointers or references, you have the option of viewing either static type information or dynamic type information.

    The static type of a class pointer or reference is its type as defined in the source code, and thus cannot change. The dynamic type is the type of the object being referenced, before any casts were made to that object, and thus may change during program execution.

    The debugger provides a debugger variable, $usedynamictypes, which allows you to control which form of the type information is displayed. The default value for this variable is true (1), which indicates that the dynamic type information is displayed. Setting this variable to false (0) instructs the debugger to display static type information. The output of the print, trace, tracei, and whatis commands are affected.

    The display of dynamic type information is supported for C++ class pointers and references. All other types display static type information. In addition, if the dynamic type of an object cannot be determined, the debugger defaults to the use of static type information.

    This debugger functionality does not relax the C++ visibility rules regarding object member access through a pointer/reference (only members of the static type are accessible). For more information about the C++ visibility rules, see The Annotated C++ Reference Manual (by Margaret E. Ellis and Bjarne Stroustrup, 1990, Addison-Wesley Publishing Company).

    In order for dynamic type information to be displayed, the object's static type must have at least one virtual function defined as part of its interface (either one it introduced or one it inherited from a base class). If no virtual functions are present for an object, only the static type information for that object is available for display.

    The following example shows debugger output with $usedynamictypes set to 0 (false):

    The following example displays debugger output with $usedynamictypes set to 1 (true). The output is for the same object as the previous example, at the same point in program execution.
    8.4.11.5 Displaying Virtual and Inherited Class Information
    When you use the print command to display information on an instance of a derived class, the debugger displays both the new class members as well as the members inherited from a base class. Pointers to members of a class are not supported.

    When you use the print command to display the format of C++ classes, the class name (or structure/union name) is displayed at the top of the output. Data members of a class that are inherited from another class are commented using a double slash (//). Only those data members that are inherited within the current class being printed are commented.

    The following example shows how the debugger uses C++ style comments to identify inherited class members. In the example, class CompoundNode inherits from class IntNode, which inherits from class Node. When printing a class CompoundNode object, the data member _data is commented with "// class IntNode", signifying that it is inherited from class IntNode. The member _nextNode is commented with "// class IntNode::Node", showing that it is inherited from class IntNode, which inherits it from class Node. This commenting is also provided for C++ structs.

    If two members in an object have the same name but different base class types (multiple inheritance), you can refer to the members using the following syntax:
         object.class::member
    
    or
         object->class::member
    
    This syntax is more effective than using the object.member and object->member syntaxes, which can be ambiguous. In all cases, the debugger uses the C++ language rules as defined in The Annotated C++ Reference Manual to determine which member you are specifying.

    The following example shows a case in which the expanded syntax can be used:

    8.4.11.6 Member Functions on the Stack Trace
    The implicit this pointer, which is a part of all nonstatic member functions, is displayed as the address on the stack trace. The class type of the object is also given.

    Sometimes the debugger does not see class type names with internal linkage. When this happens, the debugger issues the following error message:

         Name is overloaded.
    
    Trying to examine an inlined member function that is not called results in the following error:
         Member function has been inlined.
    
    The debugger will report this error regardless of the setting of the -noinline_auto compilation flag. As a workaround, include a call to the given member function somewhere in your program. (The call does not need to be executed.)

    If a program is not compiled with the -g flag, a breakpoint set on an inlined member function may confuse the debugger.

    8.4.11.7 Resolving Ambiguous References to Overloaded Functions
    In most cases, the debugger works with one specific function at a time. In the case of overloaded function names, you must specify the desired overloaded function. Following are two ways to resolve references to overloaded function names, both under the control of the $overloadmenu debugger variable (the default setting of this debugger variable is 1):
    8.4.11.8 Advanced Program Information —Verbose Mode
    By default, the debugger gives no information on virtual base class pointers for the following: By setting the $verbose debugger variable to 1, you can request that this information be printed in subsequent debugger responses. When the $verbose debugger variable is set to 1 and you display the contents of a class using the whatis command, several of the class members listed are not in the source code of the original class definition. The following line shows specific output from the whatis command for one of the additional members: The __vptr variable contains the addresses of all virtual functions associated with the class. The compiler generates several other class members for internal use.

    The compiler generates additional parameters for nonstatic member functions. When the $verbose debugger variable is set to 1, these extra parameters are displayed as part of each member function's type signature. If you specify a version of an overloaded function by entering its type signature and the variable is set to 1, you must include these parameters. Do not include these parameters if the variable is set to 0.

    When the $verbose variable is set to 1, the output of the dump command includes not only standard program variables but also compiler-generated temporary variables.

    The following example prints class information using the whatis command under different settings of the $verbose variable:

    8.5 Looking at the Generated Code

    This section discusses the following topics:

    8.5.1 Memory Display and Search Commands

    You can use the following commands to read arbitrary memory locations in your program:
    machinecode_level_command
         : examine_command
         : search_command
    
    examine_command
         : address_expression / [ count ] [ mode ]
         | address_expression ? [ count ] [ mode ]
         | address_expression , address_expression / [ mode ]
    
    search_command
         : address_expression / [ count ] search_mode   value  mask 
         | address_expression ? [ count ]  search_mode  value  mask 
         | address_expression , address_expression /  search_mode  value  mask 
    
    count
         : integer_constant	
    
    mode
         : d 	Print a short (2 byte) word in decimal
         | dd      	Print a 32-bit (4 byte) decimal display
         | D      	Print a long (8 byte) word in decimal
         | u	Print a short (2 byte) word in unsigned decimal
         | uu	Print a 32-bit (4 byte) unsigned decimal display
         | U	Print a long (8 byte) word in unsigned decimal
         | o	Print a short (2 byte) word in octal
         | oo	Print a 32-bit (4 byte) octal display
         | O	Print a long (8 byte) word in octal
         | x	Print a short (2 byte) word in hexadecimal
         | xx	Print a 32-bit (4 byte) hexadecimal display
         | X       	Print a long (8 byte) word in hexadecimal
         | b       	Print a byte in hex
         | c       	Print a byte as a character
         | s       	Print a string of characters (a C-style string ending in null)
         | C       	Print a wide character as a character
         | S       	Print a null terminated string of wide characters
         | f       	Print a single precision real number
         | g       	Print a double precision real number
         | L       	Print a long double precision real number
         | i       	Disassemble machine instructions
    
    search_mode
         : m   	32-bit search mode
         | M       	64-bit search mode
    
    value
         : integer_constant
         
    mask
         : integer_constant
    
    The first examine_command displays the count number of memory values in the requested format, starting at address_expression. If count is not specified, 1 is assumed. The count value must be a positive value.

    If you want to see memory values leading up to the address_expression, use the second examine_command. The second examine_command displays count number of memory values in the requested format ending at the address_expression. If count is not specified, 1 is assumed. The count value must be a positive value.

    The third examine_command displays memory values in the requested format starting at the smaller of the two address_expressions and ending at the larger address_expression.

    You can display stored values in the following formats by specifying mode. If mode is not specified, the mode used in the previous / command is assumed. If no previous / command exists, X is assumed.

    When disassembling machine instructions, use the $regstyle variable to customize how the registers are displayed.

    The search_commands allow you to search memory. Use the address_expression and count to determine the range of memory to search. Use the search_mode to specify whether you want to search 32-bit or 64-bit chunks. The debugger will start at the specified starting address and read a chunk of memory (either 32 or 64 bits in size) and apply the mask and comparison on that chunk of memory. For example, if you want to search memory for a particular instruction or search an array of either integer or floating-point values, the 32-bit search would be efficient because machine instructions and integer and floating-point data types are 32 bits in length.

    Use the value to specify the memory value to seek. Use the mask to specify those bits that must match the same bits in the specified value. To ensure that a possible match will be found, the debugger applies the mask to the input value prior to starting the search, to remove any bits that could prevent a match from occurring. Then, for each memory location searched, the debugger applies the mask to the memory value and then compares it with this new input value. If a match is found, then the address and memory value are displayed.

    For example, suppose the user wants to check an array of 100 integers in memory to see if any values are NULL (0):

    	(ladebug) array,&(array[99])/m 0x0 0xfffffff
    	0x1400005d0:  0x00000000
    
    Suppose the user wants to find the first occurrence of the particular value 0x55 in the thousand-element array data: Use the debugger variable $memorymatchall to cause the debugger to output all matches in the specified range. For example, suppose you want to find all occurrences of numbers ending in the value 0x55 in the same array:

    8.5.2 Machine-Level Debugging

    The debugger lets you debug your programs at the machine-code level as well as at the source-code level. Using debugger commands, you can examine and edit values in memory, print the values of all machine registers, and step through program execution one machine instruction at a time.

    Only those users familiar with machine-language programming and executable file code structure will find low-level debugging useful.

    For more information on machine-level debugging, see Machine-Level Debugging in Part III.

    8.6 Looking at Shared Libraries

    Most programs consist of a main image and shared libraries. Use the listobj command to show them. Most programmers will not need to use the readsharedobj or delsharedobj commands unless they use the -nosharedobjs option on the command line.
    shared_library_command
            : listobj
            | readsharedobj filename
            | delsharedobj  filename
    
    Use the listobj command to list all loaded objects, including the main image and the shared libraries. For each object, the information listed consists of the full object name (with pathname) and the starting and ending addresses for the .text, .data, and .bss sections.

    Use the readsharedobj command to read in the symbol table information for the specified shared object. This object must be a shared library or loadable kernel module. You can use the command only when you specify the debuggee; that is, either the debugger has been invoked with it, or the debuggee was loaded by the load command.

    Conversely, use the delsharedobj command to remove the symbol table information for the shared object from the debugger.

    Chapter 9—Modifying the Process

    In addition to the normal side effects of evaluating expressions, including calls, you can explicitly modify the memory of the current process and also modify the actual loadable file (either executable file or shared library) that has been mapped into memory:
    modifying_command
            : assign target = expression
            | patch  target = expression
    
    target
            : unary_expression
    
    
    The following sections discuss these commands.

    9.1 The assign Command

    Use the assign command to change the value associated with a variable, memory address, or expression that is accessible according to the scope and visibility rules of the language. The expression can be any expression that is valid in the current context.

    The following example shows how to deposit the value 5 into the data member _data of a C++ object:

    The following example shows how to change the value associated with a variable and the value associated with an expression: For C++, use the assign command to modify static and object data members in a class, and variables declared as reference types, type const, or type static. You cannot change the address referred to by a reference type, but you can change the value at that address.
         assign [classname::]member = ["filename"] `expression
            assign [object.]member = ["filename"] `expression
    

    NOTE: Do not use the assign command to change the PC. When you change the PC, no adjustment to the contents of registers or memory is made. This means that if you adjust the PC forward, the skipped instructions are not executed and any changes they would have made do not occur. If you adjust the PC backward, the instructions you backed up over are not undone, and any changes they made will be in effect when execution continues again.

    Because most instructions change registers or memory in ways that can impact the meaning of the application, changing the PC is very likely to cause your application to do incorrect calculations and arrive at the wrong answer. Access violations and other errors and signals may result from changing the value in the PC.

    The assign Command in Machine-Level Debugging

    You can use the assign command to alter the contents of memory specified by an address as shown in the following example:

    See Machine-Level Debugging for more information.

    9.2 The patch Command

    Use the patch command to correct bad data or instructions in executable disk files. You can patch the text, initialized data, or read-only data areas. You cannot patch the bss segment, or stack and register locations, because they do not exist on disk files.

    Use this command exclusively when you need to change the on-disk binary. Use the assign command when you need only to modify debuggee memory. If the image is executing when you issue the patch command, the corresponding location in the debuggee address space is updated as well. (The debuggee is updated regardless of whether the patch to disk succeeded, as long as the source and destination expressions could have been processed by an assign command.) If your program is loaded but not yet started, the patch to disk is performed without the corresponding assign to memory.

    NOTE: When you use the patch command, the original binary is not overwritten, but is saved with the string ~backup appended to the file name. This allows you to revert to the original binary if necessary. A file with the string ~temp appended to the file name may also be created. You can delete it after the debugging session is over.

    Chapter 10—Continuing Execution of the Process

    Before continuing the process, decide whether or not to make a snapshot, in case you want to revert to that snapshot state and try a different set of steps. After creating the snapshot, use the following commands to continue executing the program:
    continue_command
            : step_into_command
            | step_over_command
            | step_out_of_command
            | cont_command
            | cont_from_place_command
    

    10.1 The step and stepi Commands

    Use the step command to execute a line of source code. When the line being stepped contains a function call, the step command steps into the function and stops at the first executable statement.

    Use the stepi command to step into the next machine instruction. When the instruction contains a function call, the stepi command steps into the function being called.

    NOTE: If the instruction is a load locked instruction, special rules apply for stepi.

    For multithreaded applications, use these commands to step the current thread while putting all other threads on hold.

    If you supply the optional expression argument, the debugger evaluates the expression as a positive integer that specifies the number of times to execute the command. The expression can be any expression that is valid in the current context.

    step_into_command
            : step  [ step_number ]
            | stepi [ step_number ]
    
    step_number
            :  expression
    
    In the following example, two step commands continue executing a C++ program: The following example shows stepping by instruction (stepi). To see stepping into calls, see the next example.

    10.2 The next and nexti Commands

    Use the next command to execute a line of source code. When the next line to be executed contains a function call, the next command executes the function being called and stops the process at the line immediately after the function call.

    Use the nexti command to execute a machine instruction. When the instruction contains a function call, the nexti command executes the function being called and stops the process at the instruction immediately after the call instruction.

    For multithreaded applications, use these commands to move the current thread while putting all other threads on hold.

    If you supply the optional expression argument, the debugger evaluates the expression as a positive integer that specifies the number of times to execute the command. The expression can be any expression that is valid in the current context.

    step_over_command
            : next  [ step_number ]
            | nexti [ step_number ]
    
    step_number
            :  expression
    
    For example: The following example shows the difference between stepi and nexti over the same call:

    10.3 The return Command

    Use the return command without an argument to continue execution of the current function until it returns to its caller. If you include a function name, execution continues until control is returned to the specified function. The function must be active on the call stack.
    step_out_of_command
            : return
            | return [qual_symbol_opt]
    
    qual_symbol_opt
    	: expression
    	| qual_symbol_opt ` expression
    
    In the following example, the next command is stepping through process execution in the append method. The return command finishes the append method and returns control to the caller. The return command is sensitive to the user's location in the call stack. Suppose function A calls function B, which calls function C. Execution has stopped in function C, and you entered the up command, so you were now in function B, at the point where it called function C. Using the return command here would return you to function A, at the point where function A called function B. Functions B and C will have completed execution.

    10.4 The cont Command

    Use the cont command without a parameter value to resume process execution until a breakpoint, a signal, an error, or normal process termination is encountered. Specify a signal parameter value to send an operating system signal to the process.
    cont_command
            : cont [ in loc ]
            | cont [ signal ] [ to_source_line ]
            | number_expression cont [ signal ]
            | conti to address_expression
    
    to_source_line
            : to [filename_string :] line_number
    
    number_expression
            : expression
    	
    signal
            : integer_constant
    	| signal_name
    	
    
    When you use the cont command, the debugger resumes execution of the entire process.

    In the following example, a cont command resumes process execution after it was suspended by a breakpoint:

    The signal parameter value can be either a signal number or a string name (for example, SIGSEGV). The default is 0, which allows the process to continue execution without specifying a signal. If you specify a signal parameter value, the process continues execution with that signal.

    Use the in argument to continue until the named function is reached. The function name must be valid. If the function name is overloaded and you do not resolve the scope of the function in the command line, the debugger prompts you with the list of overloaded functions bearing that name from which to choose.

    Use the to parameter value to resume execution and then halt when the specified source line is reached. Use one of the following forms of the optional to parameter:

    You can repeat the cont command (n +1) times by entering n cont.

    You can set a one-time breakpoint on an instruction address before continuing by entering conti to address_expression.

    10.5 The goto Command

    The goto command is intended for advanced users who want to skip over the execution of a portion of source code. In general, its usage is not recommended.
    cont_from_place_command
            : goto line_expression
    
    line_expression
    	: expression
    

    Chapter 11—Using Snapshots as an Undo Mechanism

    You can save the current state of the debuggee process in a snapshot, and later revert to that state and try a different set of steps. Conceptually speaking, this feature is similar to the undo function in text editors, except that with snapshots you have control of the granularity of each undo. See the Introduction for a quick overview.
    snapshot_command
            : save_snapshot_command
            | clone_snapshot_command
            | show_snapshot_command
            | delete_snapshot_command
    
    The following sections discuss these commands and address the limitations of snapshots.

    11.1 The save snapshot Command

    Use the save snapshot command to save the state of the current process in a snapshot. Snapshots are numbered sequentially starting from 1.
    save_snapshot_command
            : save snapshot 
    
    In the following example, the first line of the save snapshot message shows the snapshot_number (1), the time it is saved, and the ID number of the process that implements the snapshot. The next two lines show the status of the snapshot.

    11.2 The clone snapshot Command

    Use the clone snapshot command to revert the state of the debuggee process to that of a previously saved snapshot. By doing this, you can conveniently return to the state saved in the snapshot as opposed to rerunning the process and re-entering the debugger command sequence that brought you to that state.

    Note that rerun and clone snapshot are different in that rerun always executes the process from the beginning, whereas clone snapshot does not execute the process at all; it simply duplicates the saved snapshot (using a mechanism similar to the fork system call) and behaves as though the process execution has stopped at the point when the snapshot was saved.

    The clone snapshot command clones the snapshot specified by snapshot_id. If no snapshot_id is specified, the most-recently saved existing snapshot is cloned.

    clone_snapshot_command
            : clone snapshot  [ snapshot_id ]
    
    snapshot_id
    	: expression
    

    Cloning a snapshot has the following two side effects:

    11.3 The show snapshot Command

    Use the show snapshot * and show snapshot all commands to display all the snapshots that have been saved from the current process. Use show snapshot snapshot_id_list to display the snapshots specified. If no snapshots are specified, the most-recently saved existing snapshot is displayed.
    show_snapshot_command
            : show snapshot [ snapshot_id_list ]
    
    snapshot_id_list
            : snapshot_id ,...
            | all
            | *
    	
    snapshot_id
    	: expression	
    	
    
    For example:

    11.4 The delete snapshot Command

    Use the delete snapshot * and delete snapshot all commands to delete all the snapshots that have been saved from the current process. Use delete snapshot snapshot_id_list to delete the specified snapshots. If no snapshots are specified, the most-recently saved existing snapshot is deleted.
    delete_snapshot_command
            : delete snapshot [ snapshot_id_list ]
    
    snapshot_id_list
            : snapshot_id ,...
            | all
            | *
    	
    snapshot_id
    	: expression	
    
    For example:

    11.5 Snapshot Limitations

    Snapshots have the following limitations:

    Chapter 12—Debugging Optimized Code

    This chapter provides insight into how highly optimizing compilers and the debugger deal with the consequences of key optimizations and how that may influence debugging of your program.

    This chapter contains the following sections:

    12.1 Why Debug Optimized Code?

    Highly optimizing compilers, such as those supplied with the Tru64 UNIX operating system, generally transform a program in many ways to make your program run as quickly as possible. Expressions may be combined, rearranged, or even eliminated if it is determined they are not needed; expressions and even complete statements may be moved out of loops; the order of statements may be changed; calls to functions may be replaced with a copy of the called function (inlining), the instructions for a single statement may be interspersed with instructions for other statements both before and after, and so on. All of these transformations greatly complicate the ability of a debugger to display information about the state and progress of your program or to control its execution. The compilers and the debugger try to avoid presenting erroneous, misleading, or incomplete information when debugging optimized code, but this not always possible. For these reasons, it is almost always easier to debug an unoptimized version of your program.

    Why would you ever try to debug an optimized version? The most likely reason is that the program appears to work correctly when unoptimized but somehow fails when optimized. As a result, you may have little choice but to try to isolate the problem using the optimized program.

    The most common reason that a program apparently works correctly when unoptimized but fails when optimized is this:

    Your program performs some action whose behavior is undefined or implementation dependent, and the optimized version is different from the unoptimized version when performing this action.

    For example, your program might read and depend on the value of a variable that was not assigned a value. When executed in unoptimized form, the value that happens to be in that variable might accidently result in the desired behavior. But when optimized, the variable might have some other value that leads to different behavior. As another example, sometimes your program may be subtly dependent on the exact order in which operations are performed—and optimization can result in a different order. There are many other examples that are beyond the scope of this discussion.

    It is also possible that there is a bug in the compiler. While it does happen, experience with the compilers supplied with the operating system indicates that this is rare.

    In any case, to determine the cause or nature of the problem requires debugging using the optimized version. Then you can determine how best to resolve the problem. (Of course, you could also choose to reduce the level of optimization, possibly to none, to obtain the desired behavior, but that may not result in acceptable performance.)

    12.2 Program Preparation

    Preparing a program for debugging with optimization involves compiling that program using the -g3 option. All other preparation is unchanged.

    The -g3 option differs from the -g option in that it does not affect the optimization level. That is, -g (equivalent to -g2) sets the optimization level to zero (that is, -O0), even overriding an explicit optimization setting; -g3 leaves the optimization level unchanged. See the reference pages for the respective compilers for further details.

    12.3 Split Lifetime Variables

    A variable is said to have split lifetimes if the set of fetches and stores of the variable can be partitioned such that none of the values stored in one subset are ever fetched in another subset. When such a partition exists, the variable can be split into several independent child variables, each corresponding to a partition. As independent variables, the child variables can be allocated independently. The effect is that the original variable can be thought to reside in different locations at different points in time—sometimes in a register, sometimes in memory, and sometimes nowhere at all. Indeed, it is even possible for the multiple child variables to be active simultaneously.

    Split lifetime information in the debugging symbol table describes each of the child variables associated with the main variable, where it is allocated, and the exact range of addresses over which each child is valid.

    Because assignments may not occur in the same order as in the source code, the split lifetime information also includes a list of all of the places where the current value may have been assigned. In general, this is a list of possibilities, because several execution paths may converge, bringing together multiple assignment possibilities; the debugger does not trace the exact execution path that reaches a stopping point, so it can only report the set of relevant alternatives.

    When a variable does not have a value at the current location, the debugger cannot print a value for it and reports an error as follows:

    The first error message line indicates that there is a symbol L, but that it does not currently have a value. The preceding informational line distinguishes between two cases:

    If a variable is not declared at all, then the error report looks like the following:

    When a variable has a value, there may also be information concerning where that variable was assigned: The value may be assigned from several places: It is possible, though unusual, for the same line to be listed more than once; this means that there is more than one instruction from the same line that assigns a value.

    The following limitations apply:

    12.4 Semantic Stepping

    A major problem with stepping through optimized code by line using the next and step commands in some debuggers is that the apparent source program location "bounces" forward and back, forward and back, with the same line often appearing again and again. In large part this bouncing is due to a compiler optimization called code scheduling, in which instructions that arise from the same source line are scheduled, that is, reordered and intermixed with other instructions, for better execution performance. For example, in sample programs from a prominent benchmark suite, the average number of instructions in sequence that share the same line number is typically between 2 and 3—and typically 50 to 70 percent of those sequences consist of just 1 instruction.

    Semantic stepping causes the program to execute up to, but not including, an instruction that causes a semantic effect, as well as being in a different line. Instructions that cause semantic effects are instructions that:

    The visible effect of Ladebug's support of semantic stepping is that the step and next commands generally make normal progress through your program. The effects of optimization cannot be hidden entirely, however; there will be some occasional stepping backward as well as forward due to code reordering, and some lines and statements will not appear because they were optimized away, but the result will be generally more usable.

    12.5 Discontiguous Scopes

    In addition to the blurring of line number boundaries as described in the discussion of semantic stepping, a similar blurring occurs at the beginning and end of an inner scope boundary. That is, one instruction may be related to the beginning of a new scope (and line) in which a new variable is declared and becomes visible, while the next instruction may revert to a source location (line) before the scope begins.

    Debugging optimized code information in the symbol table includes a detailed description of the possibly multiple disjoint instruction ranges that belong to or make up a scope. This helps assure that variable lookups find the right symbols at the current location.

    You are not likely to directly perceive the effects and benefits of this support; just know that it is part of obtaining correct information in the presence of optimization.

    12.6 Tail Calls

    If you enter the where command and the resulting stack seems to be missing routines, you may be seeing the result of a compiler optimization called tail calls. That optimization works as follows:

    If a procedure MIDDLE calls a procedure INNER just before returning and certain conditions are met, then MIDDLE might simply jump to INNER, instead of saving its own context on the stack first. In this case, INNER will eventually return directly to MIDDLE's caller, OUTER, and there will be no record of MIDDLE's existence on the stack.

    Then if you stop the application in INNER and enter the where command, you will see INNER and OUTER, but not MIDDLE.

    Because this transformation can occur more than once, it is possible for several intermediate calls to appear missing from the context stack. The following example shows one instance of this transformation:

    The conditions that permit this optimization include but are not restricted to the following:

    See your compiler documentation for more information.

    12.7 Alpha Linux Features

    If you are debugging optimized code under the Alpha Linux operating system, the following information applies:

    12.8 General Cautions

    When debugging optimized code, you must use some Ladebug commands with caution or avoid them completely.

    Use with Caution

    down, dump, func, return, where, pop, up

    These commands generally depend on a distinct call frame being on the execution stack for each called function. However, inlining can merge a called routine into the caller, resulting in one frame instead of the two (or more) that might be expected. You can use these commands, but be careful to make sure that you end up in the frame you intend after each use and do not be misled.

    next, nexti

    For a call that is inlined, the next and nexti commands will appear to step into the called function instead of stepping over it.

    Avoid Completely

    assign

    It is generally not possible to reliably assign to a variable before the value of the variable has been used.

    goto

    It is generally not possible to reliably determine where the first instruction of a line begins or to avoid repeating instructions from the destination line that may have been executed already.
    if logical filter in breakpoint commands
    The condition expression may not have a value at all in some places where the expression needs to be evaluated. Worse yet, the debugger sometimes attempts to cache the address of a variable, which does not correctly support split variables.
    watch variable
    The debugger does not support watching a split variable. This command will most likely fail because the debugger cannot watch a variable (child or otherwise) that is allocated in a register; even if it does appear to succeed, the debugger will be watching the location of just one child, even when that location is not relevant.
    operator &
    It is generally not possible to reliably determine whether a variable has only one lifetime and thus a unique address.

    Chapter 13—Support Limitations

    This chapter contains sections describing the limitations on support for the following languages:

    13.1 Limitations on Support for Compaq C++

    The debugger interprets C++ names and expressions using the language rules described in The Annotated C++ Reference Manual (Ellis and Stroustrup, 1990, Addison-Wesley). C++ is a distinct language, rather than a superset of C. Where the semantics of C and C++ differ, the debugger provides the interpretation appropriate for the language of the program being debugged.

    To be more useful, the debugger relaxes some standard C++ name visibility rules. For example, you can reference public, protected, and private class members as well as public ones.

    The following limitations apply to debugging a C++ program:

    Limitations for debugging templates include the following:

    13.2 Limitations on Support for Compaq Fortran

    The debugger and the Tru64 UNIX operating system support the Compaq Fortran language with certain limitations, which are described in the following sections.

    Be aware of the following limitations when you debug a Fortran program:

    The following limitations apply only to Compaq Fortran 90:

    13.2.1 Limitations on Procedure Invocations

    Following are the limitations on Compaq Fortran procedure invocations:

    13.3 Limitations on Support for Compaq Ada

    The debugger and the Tru64 UNIX operating system support the Compaq Ada language with certain limitations, which are described in the following sections.

    13.3.1 Limitations on Expressions

    Expressions in Ladebug commands use C source language syntax for operators and expressions. Data is printed as the equivalent C data type. The following table shows Ada expressions and Ladebug equivalents.

    Ada Expression
    Debugger Equivalent
    Binary operations and unary operations Only integer, floating, and Boolean expressions are easily expressed.
    a+b,-,*a+b,-,*
    a/ba/b
    a = b /= < <= > >= a = = b != < <= > >=
    a and ba&&b
    a or ba | | b
    a rem ba%b
    not(a=b)!(a==b)
    -a-a
    Qualified expressionsNone. There is no easy way of evaluating subtype bounds.
    Type conversions Only simple numeric conversions are supported, and the bounds checking cannot be done. Furthermore, float -> integer truncates rather than rounds.

    integer -> float

    (ladebug) print (float) (2147483647)
    2147483648.0
    (ladebug) print (double) (2147483647)
    2147483647.0

    AttributesNone, but if E is an enumeration type with default representations for the values, then:
    E'PRED(X) is the same as x-1.
    E'SUCC(X) is the same as x+1
    p.all *p (pointer reference)
    p.m p -> m (member of an "access record" type)

    13.3.2 Limitations on Data Types

    This section lists the limitation notes by data type. For more information on these types, with examples, see the Developing Ada Programs on Tru64 UNIX Systems manual. Also see the Compaq Ada release notes for detailed information on debugging.

    All Types

    The debugger, unlike the Ada language, allows out-of-bounds assignments to be performed.

    Integer Types

    If integer types of different sizes are mixed (for example, byte-integer and word-integer), the one with the smaller size is converted to the larger size.

    Floating-Point Types

    If integer and floating-point types are mixed in an expression, the debugger converts the integer type to a floating-point type.

    The debugger displays floating-point values that are exact integers in integer literal format.

    Fixed-Point Types

    The debugger displays fixed-point values as real-type literals or as structures. The structure contains values for the sign and the mantissa. To display the structure's value, multiply the sign and mantissa values. For example:

    Enumeration Types

    The debugger displays enumeration values as the actual enumeral or its position.

    You must manually convert enumeration values to 'pos values before you can use them as array indices.

    Array Types

    The debugger displays string array values in horizontal ASCII format, enclosed in quotation ("x") marks. A single component (character) is displayed within single quotation ('x') marks.

    The debugger allows you to assign a component value to a single component; you cannot assign using an entire array or array aggregate.

    Arrays whose components are neither a single bit nor a multiple of bytes are described to the debugger as structures; a print command displays only the first component of such arrays.

    Records

    The debugger cannot display record components whose offsets from the start of the record are not known at compile time.

    For variant records, however, the debugger can display the entire record object that has been declared with the default variant value. The debugger allows you to print or assign a value to a component of a record variant that is not active.

    Access Types

    The debugger does not support allocators, so you cannot create new access objects with the debugger. When you specify the name of an access object, the debugger displays the memory location of the object it designates. You can examine the memory location value.

    13.3.3 Limitations on Tasking Programs

    When you debug Ada tasking programs, you use the debugger and the DEC Ada ada_debug routine.

    13.4 Limitations on Support for Compaq COBOL

    This section describes the limitations on support for Compaq COBOL.

    13.4.1 Limitations on Assignment

    The following limitations apply to assignment in COBOL debugging:

    13.4.2 Other Limitations

    Other limitations when you debug COBOL programs include the following:

    Part III
    Advanced Topics

    Part III provides information to make advanced use of the debugger by expanding on topics presented in Part II.

    It is intended to be used as a reference and therefore contains a wide variation in the level of information provided in each section.

    Chapter 14—Preparing Your Program for Debugging

    This chapter describes how you can modify your program to wait for the debugger and to print a stack trace.

    14.1 Modifying Your Program to Wait for the Debugger

    To modify your program to wait for the debugger, complete the following steps:
    1. Add some code similar to the following :
              void loopForDebugger()
              {
                  if (!getenv("loopForDebugger")) return;
                  static volatile int debuggerPresent = 0;
                  while (!debuggerPresent);
              }
      
    2. Call this function at some convenient point.
    3. Use the debugger's attach capability to bring the process under control.

    When you have the process under debugger control, you can assign a nonzero value to debuggerPresent, and continue your program. For example:

            % setenv loopForDebugger ""
            % a.out arg1 arg2 &
            % ladebug -pid 1709 a.out
            ^C
            (ladebug) assign debuggerPresent = 1
            ...
            (ladebug) cont
    

    14.2 Modifying Your Program to Print a Stack Trace

    This section contains code you can use to modify your program to print a stack trace.

    You can also call the debugBreak function to start the debugger at some specified point after your program starts executing. For more information about debugBreak, see the Ladebug Web site FAQ.

    /*% cc -g traceback.c -lexc
    **% a.out
    */
    struct exception_info;
    /* To suppress compilation warnings from sym.h */
    #include <demangle.h>
    #include <excpt.h>
    #include <setjmp.h>
    #include <signal.h>
    #include <sym.h>
    #include <unistd.h>
    
    
    static void printHeader(void)
    {
        printf("Diagnostic stack trace ...\n");
    }
    
    
    static void printTrailer(void)
    {
        printf("end of diagnostic stack trace.\n");
    }
    
    
    #define RETURNADDRREG (26)
    #define FAULTING_ADDRESS sc_traparg_a0
    
    extern unsigned long _procedure_string_table;
    extern unsigned long _procedure_table_size;
    extern unsigned long _procedure_table;
    extern unsigned long _ftext;           /* Start address of the program text.*/
    extern unsigned long _etext;           /* First address above the program text.*/
    
    
    
    /* Turn a PC into the name of the routine containing that PC.
    */
    char* programCounterToName(
        unsigned long programCounter);
    
    
    /* Unwind the stack one level.
    */
    void unwindOneLevel(
        struct sigcontext*  unwindSignalContext,
        void *              runtimeProcedurePtr);
    
    
    void printFrame(
        void *        rpdp,
        unsigned long programCounter)
    {
        char* procedureName;
    
        /* Get the procedure name.
        */
        procedureName = programCounterToName(programCounter);
    
        printf("%p %s\n",
            (void* ) programCounter,  procedureName ? procedureName : "");
    }
    
    
    char* programCounterToName(
        unsigned long programCounter)
    {
        long int          procedureTableSize;
        char *            procedureNameTable;
        char *            procedureName;
        long int          currentProcedure;
        long int          procedure;
        pRPDR             runTimePDPtr;
        int               found;
        unsigned long int address;
    
        found = 0;
        procedureName = 0;
    
        procedureTableSize = (long int)&_procedure_table_size;
        procedureNameTable = (char *)&_procedure_string_table;
        runTimePDPtr = (pRPDR)&_procedure_table;
    
        /* The table of run time procedure descriptors is ordered by
         procedure start address. Search the table (linearly) for the
         first procedure with a start address larger than the one for
         which we are looking.
        */
        for (currentProcedure = 0;
           currentProcedure < procedureTableSize;
           currentProcedure++) {
    
            /* Because of the way the linker builds the table we need to make
             special cases of the first and last entries. The linker uses 0
             for the address of the procedure in the first entry, here we
             substitute the start address of the text segment. The linker
             uses -1 for the address of the procedure in the last entry,
             here we substitute the end address of the text segment. For all
             other entries the procedure address is obtained from the table.*/
    
            if (currentProcedure == 0)                             /* first entry */
                address = (unsigned long int)&_ftext;
            else if (currentProcedure == procedureTableSize - 1)   /* last entry */
                address = (unsigned long int)&_etext;
            else                                                   /* other entries */
                address = runTimePDPtr[currentProcedure].adr;
    
            if (address > programCounter) {
                if (currentProcedure != 0) {
                    /* the PC is in this image */
                    found = 1;
                    procedure = currentProcedure - 1; /* the PC is in preceeding procedure */
                    break; /* stop searching */
                } else {
                    /* the PC is outside this image (at a lower address) */
                    break; /* stop searching */            }
            }
        }
    
        if (found) {
            /* the PC is inside this image */
            procedureName = &procedureNameTable[runTimePDPtr[procedure].irpss];
        } else {
            /* the PC is outside this image, probably in a different shared object */
            procedureName = 0;
        }
    
        return procedureName;
    }
    
    
    void unwindOneLevel(
        struct sigcontext *unwindSignalContext,
        void *             runtimeProcedurePtr)
    {
        unwind(unwindSignalContext, (pdsc_crd *)runtimeProcedurePtr);
    }
    
    
    /* Print a stack trace.
    */
    void printStackWkr(struct sigcontext *signalContextPtr)
    {
        struct sigcontext unwindSignalContext;
        void *runTimeProcedurePtr;
    
        unsigned long int stackpointer    = 0;
        unsigned long int programCounter  = 0;
        unsigned long int returnAddress   = 0;
        unsigned long int faultingAddress = 0;
    
        printHeader();
    
        /* Set the initial context for the unwind.
        */
        unwindSignalContext = *signalContextPtr;
    
        /* Pick out the return address and program counter.
        */
        returnAddress  = unwindSignalContext.sc_regs[RETURNADDRREG];
        programCounter = unwindSignalContext.sc_pc;
    
        /* This is the address that caused the fault when we tried to access
         it.
        */
        faultingAddress = signalContextPtr->FAULTING_ADDRESS;
    
        /* Special cases for bogus program counter values. If the program
         counter is zero or the fault occurred when we were trying to
         fetch an instruction (because the program counter itself was bad)
         then we cannot unwind the stack.
        */
        if (programCounter == 0) {
    
            printf("PC is zero - stack trace not available.\n");
    
        } else if (programCounter == faultingAddress) {
    
            printf("bad PC (%p) - stack trace not available.\n",
                faultingAddress);
    
        } else {
    
            unsigned int sameSpCount = 0;
    
            /* Loop through all the stack frames.
            */
            while  ((returnAddress != 0) && (programCounter != 0)) {
    
                /* Get the run time procedure descriptor for this frame.
                */
                runTimeProcedurePtr = find_rpd(programCounter);
    
                /* Print a frame.
                */
                printFrame(runTimeProcedurePtr, programCounter);
    
                /* Unwind one level.
                */
                unwindOneLevel(&unwindSignalContext, runTimeProcedurePtr);
                returnAddress   = unwindSignalContext.sc_regs[RETURNADDRREG];
                programCounter  = unwindSignalContext.sc_pc;
    
                if (unwindSignalContext.sc_sp <= stackpointer) {
                    sameSpCount++;
                    if (sameSpCount == 10) break;
                } else {
                    sameSpCount  = 0;
                    stackpointer = unwindSignalContext.sc_sp;
                }
            }
        }
    
        printTrailer();
    }
    
    /* Discard one stack frame by silently unwinding.
    */
    long int discardOneLevel(
        long int programCounter,
        struct sigcontext *signalContextPtr)
    {
        void *runTimeProcedurePtr;
    
        runTimeProcedurePtr = find_rpd(programCounter);
        unwindOneLevel(signalContextPtr, runTimeProcedurePtr);
        return signalContextPtr->sc_pc;
    }
    
    
    void printStack(int levelsToDiscard)
    {
        long int programCounter;
        void *runTimeProcedurePtr;
        jmp_buf context;
        struct sigcontext *signalContextPtr;
    
        /* Capture the current context.
        */
        setjmp(context);
        signalContextPtr = (struct sigcontext *)context;
        programCounter = signalContextPtr->sc_pc;
    
        /* Discard the frame for this routine.
        */
        programCounter = discardOneLevel(programCounter, signalContextPtr);
    
        /* Discard any other frames requested by our caller.
        */
        if (levelsToDiscard > 0) {
            int levels;
            for (levels = 0; levels < levelsToDiscard; levels++) {
                programCounter = discardOneLevel(programCounter, signalContextPtr);
            }
        }
    
        /* Now that we have the right context, print the stack trace.
        */
        printStackWkr(signalContextPtr);
    
    }
    
    /* Example of usage follows. */
    
    void innermost()
    {
        printStack(0);
    }
    
    
    void middle()
    {
        innermost();
    }
    
    
    int main()
    {
        middle();
        return 0;
    }
    

    Chapter 15—Debugger's Command Processing Structure

    This chapter is divided into the following sections:

    15.1 Lexical Elements of Commands

    After the debugger assembles complete lines of input from the characters it reads from stdin or from the file specified in the source command (as described in Part II), each line is then converted into a sequence of lexical elements known as lexemes. For example, print(a++); is converted into the following lexemes:
    	print
    	(
    	a
    	++ 
    	)
    	;
    

    The sequence of lexemes is then recognized as Ladebug commands containing language-specific expressions by a process known as parsing. The recognition is based on a set of rules known as a grammar. The debugger uses a single grammar for commands regardless of the current program's language, but it has language-specific subgrammars for some of the pieces of commands, such as names, expressions, and so on.

    15.1.1 Lexical States

    The debugger starts processing each line according to the rules of the LKEYWORD lexical state. It recognizes the longest lexeme it can, according to these rules. After recognizing the lexeme, it may stay in the same state, or it may change to a different lexical state with different rules.

    The debugger moves between the following lexical states as it recognizes the lexemes:

    Lexical State Description
    LBPT Breakpoint commands have lexemes that change the lexical state to LBPT.
    LEXPORT The command export changes the lexical state to LEXPORT. This state recognizes an evironment variable identifier.
    LFILE Commands that require file names have lexemes that change the lexical state to LFILE so that things like mysrc/foo.txt are recognized as a file name, and not as a variable mysrc being divided by a structure data member foo.txt.
    LFINT Commands that require either a file name or a process ID have lexemes to change the lexical state to LFINT.
    LKEYWORD All but one of the Ladebug commands begin with one or more keywords. The exception is the examine command. The debugger recognizes the '{' and ';' lexemes that precede a command, and uses those to reset to the LKEYWORD state for the beginning of the next command.
    LLINE Commands that require arbitrary character input have lexemes that change the lexical state to LLINE.
    LNORM Language expressions involve language-specific lexemes. The lexemes that precede an expression change the lexical state to LNORM, and then LNORM recognizes the language-specific lexemes.
    LSETENV The command setenv changes the lexical state to LSETENV. This state recognizes an evironment variable identifier.
    LSIGNAL Commands that require signal names have lexemes that change the lexical state to LSIGNAL.
    LWORD Commands that require shell words have lexemes that change the lexical state to LWORD.

    The rules that each lexical state uses are described in the following sections, in a format known as a lex regular expression. Rather than repeating some of descriptions, a set of common subrules is described first. After the common subrules, we describe the initial state, the rules, and for each recognized token, the next lexical state.

    15.1.2 Identifiers

    All languages have a concept of an identifier, composed of letters, digits, and other special characters. The debugger also uses keywords composed of letters; therefore, rules are required to determine which identifiers are actually Ladebug keywords.

    All Ladebug commands, except examine, begin with leading keywords. Because the examine command begins with an expression, all identifiers must be recognized as such from both the LKEYWORD state that starts commands and the LNORM state that the debugger uses for processing expressions.

    Some Ladebug commands have keywords embedded in them following expressions, and the ends of expressions are hard to recognize. You can use identifiers that have the same spelling as an embedded keyword simply by enclosing the whole expression in parentheses (()). For more information on using keywords within commands, see Section 4.4.4.

    Furthermore, the C and C++ grammars need to know whether an identifier is a typedef or struct/class identifier. The debugger currently makes the determination at the time the whole command is parsed, rather than deferring the determination to when the expression itself is being evaluated. This can result in a misidentification of the identifier.

    When in the following four lexical states, the debugger can recognize identifiers:

    If your operating system supports internationalization (I18N), {LT} equates to {LTI18N}.

    15.1.3 Embedded Keywords

    The complete set of embedded keywords follows:

    Lexeme Representation Initial Lexical State Changed Lexical State Language Specific?
    ANY any LNORM LNORM Shared by all
    AT at LBPT, LNORM LNORM Shared by all
    CHANGED changed LNORM LNORM Shared by all
    IF if LBPT LNORM Shared by all
    IN in LBPT, LNORM LNORM Shared by all
    IN_ALL in{Whitespace}all {Whitespace} LBPT, LNORM LNORM Shared by all
    POLICY policy LNORM LNORM Shared by all
    PRIORITY priority LNORM LNORM Shared by all
    READ read LNORM LNORM Shared by all
    THREAD thread LNORM LNORM Shared by all
    THREAD_ALL thread{Whitespace}all
    thread{Whitespace} *
    LNORM LNORM Shared by all
    TO to LNORM LNORM Shared by all
    WITH_STATE with{Whitespace}state LNORM LNORM Shared by all
    WITHIN within LNORM LNORM Shared by all
    WRITE write LNORM LNORM Shared by all

    NOTE: THREAD is both a leading and an embedded keyword.

    15.1.4 Leading Keywords

    Leading keywords are recognized only at the beginning of commands. You do not need to use parentheses (()) to use them as a normal identifier, unless they occur at the start of an examine command.

    Leading keywords may differ between languages. The complete set follows:

    Lexeme Representation
    (Some May Be Language Specific)
    Initial Lexical State Changed Lexical State Language Specific?
    ALIAS alias LKEYWORD LNORM Shared by all
    ASSIGN assign LKEYWORD LNORM Shared by all
    ATTACH attach LKEYWORD LNORM Shared by all
    CALL call LKEYWORD LNORM Shared by all
    CATCH catch LKEYWORD LSIGNAL Shared by all
    CATCH_UNALIGN catch{Whitespace}unaligned LKEYWORD LNORM Shared by all
    CLASS class LKEYWORD LNORM C++ Special Case
    CLONE_SNAPSHOT clone{Whitespace}snapshot LKEYWORD LNORM Shared by all
    CONDITION condition LKEYWORD LNORM Shared by all
    CONT cont LKEYWORD LNORM Shared by all
    CONTI conti LKEYWORD LNORM Shared by all
    CONT_THREAD cont{Whitespace}thread LKEYWORD LNORM Shared by all
    DELETE delete LKEYWORD LNORM Shared by all, also used for C++ special case
    DELETE_ALL delete{Whitespace}*
    delete{Whitespace}all
    LKEYWORD LNORM Shared by all
    DELSHAREDOBJ delsharedobj LKEYWORD LFILE Shared by all
    DETACH detach LKEYWORD LNORM Shared by all
    DISABLE disable LKEYWORD LNORM Shared by all
    DISABLE_ALL disable{Whitespace}*
    disable{Whitespace}all
    LKEYWORD LNORM Shared by all
    DOWN down LKEYWORD LNORM Shared by all
    DUMP dump LKEYWORD LNORM Shared by all
    EDIT edit LKEYWORD LFILE Shared by all
    ELSE else LKEYWORD LKEYWORD Shared by all
    ENABLE enable LKEYWORD LNORM Shared by all
    ENABLE_ALL enable{Whitespace}*
    enable{Whitespace}all
    LKEYWORD LNORM Shared by all
    EXPAND_AGGREGATED_MESSAGE expand{Whitespace}aggregated{Whitespace}message LKEYWORD LNORM Shared by all
    EXPORT export LKEYWORD LNORM Shared by all
    FILECMD file LKEYWORD LFILE Shared by all
    FILEEXPR fileexpr LKEYWORD LFILE Shared by all
    FOCUS focus LKEYWORD LNORM Shared by all
    FOCUS_ALL focus{Whitespace}*
    focus{Whitespace}all
    LKEYWORD LNORM Shared by all
    FUNC func LKEYWORD LNORM Shared by all
    GOTO goto LKEYWORD LNORM Shared by all
    GUI gui LKEYWORD LNORM Shared by all
    HELP help LKEYWORD LLINE Shared by all
    HISTORY history LKEYWORD LNORM Shared by all
    HPFGET hpfget LKEYWORD LNORM Fortran
    IF if LKEYWORD LNORM Shared by all
    IGNORE ignore LKEYWORD LSIGNAL Shared by all
    IGNORE_UNALIGN ignore{Whitespace}unaligned LKEYWORD LNORM Shared by all
    INPUT input LKEYWORD LFILE Shared by all
    IO io LKEYWORD LFILE Shared by all
    KILL kill LKEYWORD LNORM Shared by all
    KPS kps LKEYWORD LNORM Shared by all
    LIST list LKEYWORD LNORM Shared by all
    LISTOBJ listobj LKEYWORD LNORM Shared by all
    LOAD load LKEYWORD LFILE Shared by all
    MAP_SOURCE_DIRECTORY map{Whitespace}source{Whitespace}directory LKEYWORD LNORM Shared by all
    MUTEX mutex LKEYWORD LNORM Shared by all
    NEXT next LKEYWORD LNORM Shared by all
    NEXTI nexti LKEYWORD LNORM Shared by all
    OUTPUT output LKEYWORD LFILE Shared by all
    PATCH patch LKEYWORD LNORM Shared by all
    PLAYBACK playback LKEYWORD LKEYWORD Shared by all
    POP pop LKEYWORD LNORM Shared by all
    PRINT print LKEYWORD LNORM Shared by all
    PRINTB printb LKEYWORD LNORM Shared by all
    PRINTD printd LKEYWORD LNORM Shared by all
    PRINTENV printenv LKEYWORD LNORM Shared by all
    PRINTF printf LKEYWORD LNORM Shared by all
    PRINTI printi LKEYWORD LNORM Shared by all
    PRINTO printo LKEYWORD LNORM Shared by all
    PRINTT printt LKEYWORD LNORM Shared by all
    PRINTX printx LKEYWORD LNORM Shared by all
    PRINTREGS printregs LKEYWORD LNORM Shared by all
    PROCESS process LKEYWORD LNORM Shared by all
    PROCESS_ALL process{Whitespace}*
    process{Whitespace}all
    LKEYWORD LNORM Shared by all
    PTHREAD pthread LKEYWORD LNORM Shared by all
    QUESTION ? LKEYWORD LNORM Shared by all
    QUIT quit LKEYWORD LNORM Shared by all
    READSHAREDOBJ readsharedobj LKEYWORD LFILE Shared by all
    RECORD record LKEYWORD LKEYWORD Shared by all
    RERUN rerun LKEYWORD LWORD Shared by all
    RETURN return LKEYWORD LNORM Shared by all
    RUN run LKEYWORD LWORD Shared by all
    SAVE_SNAPSHOT save{Whitespace}snapshot LKEYWORD LNORM Shared by all
    SET set LKEYWORD LNORM Shared by all
    SETENV setenv LKEYWORD LNORM Shared by all
    SH sh LKEYWORD LNORM Shared by all
    SHOW show LKEYWORD LKEYWORD Shared by all
    SHOW_AGGREGATED_MESSAGE show{Whitespace}aggregated{Whitespace}message LKEYWORD LNORM Shared by all
    SHOW_AGGREGATED_MESSAGE_ALL show{Whitespace}aggregated{Whitespace}message{Whitespace}*
    show{Whitespace}aggregated{Whitespace}message{Whitespace}all
    LKEYWORD LNORM Shared by all
    SHOW_PROCESS_SET show{Whitespace}process{Whitespace}set LKEYWORD LNORM Shared by all
    SHOW_PROCESS_SET_ALL show{Whitespace}process{Whitespace}set{Whitespace}*
    show{Whitespace}process{Whitespace}set{Whitespace}all
    LKEYWORD LNORM Shared by all
    SHOW_SOURCE_DIRECTORY show{Whitespace}source{Whitespace}directory LKEYWORD LNORM Shared by all
    SHOW_ALL_SOURCE_DIRECTORY show{Whitespace}all{Whitespace}source{Whitespace}directory LKEYWORD LNORM Shared by all
    SLASH / LKEYWORD LNORM Shared by all
    SNAPSHOT snapshot LKEYWORD LNORM Shared by all
    SNAPSHOT_ALL snapshot all LKEYWORD LNORM Shared by all
    SOURCE source LKEYWORD LFILE Shared by all
    STATUS status LKEYWORD LNORM Shared by all
    STEP step LKEYWORD LNORM Shared by all
    STEPI stepi LKEYWORD LNORM Shared by all
    STOP stop LKEYWORD LBPT Shared by all
    STOPI stopi LKEYWORD LNORM Shared by all
    THREAD thread LKEYWORD LNORM Shared by all
    TRACE trace LKEYWORD LNORM Shared by all
    TRACEI tracei LKEYWORD LNORM Shared by all
    UNALIAS unalias LKEYWORD LNORM Shared by all
    UNLOAD unload LKEYWORD LNORM Shared by all
    UNMAP_SOURCE_DIRECTORY unmap{Whitespace}source{Whitespace}directory LKEYWORD LNORM Shared by all
    UNRECORD unrecord LKEYWORD LNORM Shared by all
    UNSET unset LKEYWORD LNORM Shared by all
    UNSETENV unsetenv LKEYWORD LNORM Shared by all
    UNSETENV_ALL unsetenv{Whitespace}* LKEYWORD LNORM Shared by all
    UNUSE unuse LKEYWORD LFILE Shared by all
    UP up LKEYWORD LNORM Shared by all
    USE use LKEYWORD LFILE Shared by all
    VERSION version LKEYWORD LNORM Shared by all
    WATCH watch LKEYWORD LNORM Shared by all
    WATCH_MEMORY watch{Whitespace}memory LKEYWORD LNORM Shared by all
    WATCH_VARIABLE watch{Whitespace}variable LKEYWORD LNORM Shared by all
    WHATIS whatis LKEYWORD LNORM Shared by all
    WHEN when LKEYWORD LBPTChapter Shared by all
    WHENI wheni LKEYWORD LNORM Shared by all
    WHERE where LKEYWORD LNORM Shared by all
    WHEREIS whereis LKEYWORD LNORM Shared by all
    WHERE_THREAD where{Whitespace}thread LKEYWORD LNORM Shared by all
    WHERE_THREAD_ALL where{Whitespace}thread{Whitespace}*
    where{Whitespace}thread{Whitespace}all
    LKEYWORD LNORM Shared by all
    WHICH which LKEYWORD LNORM Shared by all

    15.1.5 Reserved Identifiers

    Some identifiers are recognized as reserved words, regardless of whether they are inside parentheses (()).

    The reserved words may differ between languages. The complete set follows:

    Lexeme Representation
    (Some May Be Language Specific)
    Initial Lexical State Changed Lexical Language Specific?
    AND AND LNORM LNORM COBOL
    MOD MOD LNORM LNORM COBOL
    NOT NOT LNORM LNORM COBOL
    OR OR LNORM LNORM COBOL
    BYCONTENT (BY[ \t]+)?CONTENT LNORM LNORM COBOL
    BYDESCRIPTOR (BY[ \t]+)?DESCRIPTOR LNORM LNORM COBOL
    BYREFERENCE (BY[ \t]+)?REFERENCE LNORM LNORM COBOL
    BYVALUE (BY[ \t]+)?VALUE LNORM LNORM COBOL
    CHAR char LNORM LNORM C, C++
    CLASS class LNORM LNORM C++
    CONST const LNORM LNORM C, C++
    DELETE delete LNORM LNORM C++
    DOUBLE double LNORM LNORM C, C++
    ENUM enum LNORM LNORM C, C++
    FLOAT float LNORM LNORM C, C++
    GIVING GIVING LNORM LNORM COBOL
    INT int LNORM LNORM C, C++
    LONG long LNORM LNORM C, C++
    NEW new LNORM LNORM C++
    OF OF LNORM LNORM COBOL
    OPERATOR operator LNORM LNORM C++
    REFERENCEOF REFERENCE([ \t]+"OF")? LNORM LNORM COBOL
    SHORT short LNORM LNORM C, C++
    SIGNED signed LNORM LNORM C, C++
    SIGNNEG (IS[ \t]+)?"NEGATIVE"
    (IS[ \t]+)?"NOT"[ \t]+"POSITIVE"
    LNORM LNORM COBOL
    SIGNNOTZERO (IS[ \t]+)?"NOT"[ \t]+"ZERO" LNORM LNORM COBOL
    SIGNPOS (IS[ \t]+)?"POSITIVE"
    (IS[ \t]+)?"NOT"[ \t]+"NEGATIVE"
    LNORM LNORM COBOL
    SIGNZERO (IS[ \t]+)?"ZERO" LNORM LNORM COBOL
    SIZEOF sizeof LNORM LNORM C, C++, Fortran
    STRUCT struct LNORM LNORM C, C++
    UNION union LNORM LNORM C, C++
    UNSIGNED unsigned LNORM LNORM C, C++
    USING USING LNORM LNORM COBOL
    VOID void LNORM LNORM C, C++
    VOLATILE volatile LNORM LNORM C, C++

    15.1.6 Lexemes Shared by All Languages

    Because the debugger supports multiple languages, some of the rules must be language specific. To distinguish between the characters used for a particular language to represent a lexeme and the lexeme itself, the debugger names the lexemes, rather than using any one language's representation. For example, the lexeme GE corresponds to Fortran's '.GE.', to C's '>=', and to COBOL's 'IS NOT LESS THAN'.

    Some lexemes have the same representation in all languages, especially those that form part of the Ladebug commands apart from the language-specific expressions.

    15.1.6.1 Common Elements of Lexemes
    The following tables list common elements of lexemes.

    ConceptRule RepresentationDescription
    Decimal digit DG [0-9] One character from '0'..'9'.
    Octal digit OC [0-7] One character from '0'..'7'.
    Hexadecimal digit HX [0-9a-fA-F] Any of the characters '0'..'9' and any of the letters 'A'..'F' and 'a'..'f'.
    Single letter LT [A-Za-z_$] Any of the characters 'A'..'Z', 'a'..'z', and the underscore (_) and dollar sign ($) characters.
    Single letter
    from the International Character Set
    LT18N [A-Za-z_$\200-\377] Any of the characters 'A'..'Z', 'a'..'z', the underscore (_) and dollar sign ($) characters, and any character in the top half of the 8-bit character set.
    Shell 'word' WD [^ \t;\n<>'"] Any character except space, tab, semicolon (;), linefeed, less than (<), greater than (>), and quotes (' or ").
    File name FL [^ \t\n\}\;\<>] Any character except space, tab, semicolon (;), linefeed, right brace (}), less than (<), greater than (>), and tick (`).
    Optional exponent Exponent [eE][+-]?{DG}+ Numbers often allow an optional exponent. It is represented as an 'e' or 'E' followed by an optional plus (+) or minus (-), and then one or more decimal digits.
    Whitespace Whitespace [ \t]+ Whitespace is often used to separate two lexemes that would otherwise be misconstrued as a single lexeme. For example, stop in is two keywords, but stopin is an identifier. Apart from this separating property, Whitespace is usually ignored. Whitespace is a sequence of one or more tabs or spaces.
    String literal stringChar ([^"\\\n]|([\\]({simpleEscape}|
    {octalEscape}|{hexEscape})))
    Any character except the terminating quote character ("), or a new line (\n). If the character is a backslash (\), it is followed by an escaped sequence of characters.
    Character literal charChar ([^'\\\n]|([\\]({simpleEscape}|
    {octalEscape}|{hexEscape})))
    Any character except the terminating quote (') character, or a new line (\n). If the character is a backslash (\), it is followed by an escaped sequence of characters.
    Environment variable identifier EID [^ \t\n<>;='"&\|] Any character except space, tab, linefeed, less-than (<), greater-than (>), semicolon (;), equal sign (=), quotes (' or "), ampersand (&), backslash (\), and bar (|).
    Universal character name UCN \\u{HX}{4}|\\U{HX}{8} A universal character name is a backslash (\) followed by either a lowercase 'u' and 4 hexadecimal digits, or an uppercase 'U' and 8 hexadecimal digits.

    The escaped sequence of characters can be one of following three forms:

    ConceptRule RepresentationDescription
    Simple escape simpleEscape ([A-Za-z'"?#*\\]) One of 'A'-'Z' or 'a'-'z'. Some of these have special meanings, the most common being 'n' for new line and 't' for tab. Can be a quote (' or ") character that does not finish the literal, a question mark (?), a pound sign (#), an asterisk (*), or a backslash (\), which then becomes part of the string literal rather than causing a further escape sequence.
    Octal escape octalEscape (OC{1,3}) 1 to 3 octal digits, the combined numeric value of which is the character that becomes part of the string literal.
    Hexadecimal escape hexEscape ([xX]HX{1,8}) An 'x' or an 'X' followed by 1 to 8 hexadecimal digits, the combined numeric value of which is the character that becomes part of the string literal.

    15.1.6.2 Whitespace and Command-Separating Lexemes Shared by All Languages
    In all lexical states, unescaped new lines produce the NEWLINE token and change the lexical state to be LKEYWORD.

    In all lexical states except LLINE, a semicolon also changes the lexical state to be LKEYWORD.

    Initial State LKEYWORD, LNORM, LFILE, LLINE, LWORD, LSIGNAL, LBPT
    Regular expression[\n]
    LexemeNEWLINE
    Change to stateLKEYWORD

    This is because SEMICOLON is the command separator.

    Initial State LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT, LWORD
    Regular expression";"
    LexemeSEMICOLON
    Change to stateLKEYWORD

    Commands can be nested, and the following transitions support this:

    Initial State LNORM
    Regular expression"{"
    LexemeLBRACE
    Change to stateLKEYWORD

    Initial State LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT
    Regular expression"}"
    LexemeRBRACE
    Change to stateLKEYWORD

    In most lexical states, the spaces, tabs, and escaped new lines are ignored. In the LLINE state, the spaces and tabs are part of the line, but escaped new lines are still ignored. In the LWORD state, the spaces and tabs are ignored, but escaped new lines are not.

    Initial State LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT
    Regular expression[ \t]
    \\\n
    LexemeIgnored
    Change to stateUnchanged

    Initial State LLINE
    Regular expression\\\n
    LexemeIgnored
    Change to stateUnchanged

    Initial State LWORD
    Regular Expression[ \t]
    LexemeIgnored
    Change to StateUnchanged

    15.1.6.3 LNORM Lexemes Shared by All Languages
    The state stays in LNORM.

    LexemeRegular Expression
    ANY any
    AT at
    ATSIGN "@"
    CHANGED changed
    CHARACTERconstant [lL][']{charChar}+[']
    COLON ":"
    COMMA ","
    DOLLAR "$"
    DOT "."
    GE ">="
    GREATER ">"
    HASH unknown
    IF if
    IN in
    IN_ALL in{Whitespace}all{Whitespace}
    INTEGERconstant "0"[kK]{HX}+
    LE "<="
    LESS "<"
    LPAREN "("
    POLICY policy
    PRIORITY priority
    RPAREN ")"
    READ read
    SLASH "/"
    STAR "*"
    STATE state
    STRINGliteral ["]{stringChar}*["]
    THREAD thread
    THREAD_ALL thread{Whitespace}all
    thread{Whitespace}"*"
    TICK "`"
    TO to
    WIDECHARACTERconstant [lL][']{charChar}+[']
    WIDESTRINGliteral [lL]["]{stringChar}*["]
    WITH with
    WITHIN within
    WRITE write

    15.1.6.4 LBPT Lexemes Shared by All Languages

    LexemeRegular Expression Initial Lexical StateChanged Lexical State
    IN in LBPTLNORM
    IN_ALL in{Whitespace}all LBPTLNORM
    INTEGERconstant "0"[kK]{HX}+ LBPTLBPT
    AT at LBPTLNORM
    PC_IS pc LBPTLNORM
    SIGNAL signal LBPTLNORM
    UNALIGNED unaligned LBPTLNORM
    VARIABLE variable LBPTLNORM
    MEMORY memory LBPTLNORM
    EVERY_INSTRUCTION every{Whitespace}instructionLBPTLNORM
    EVERY_PROC_ENTRY every{Whitespace}proc[edure]{Whitespace}entry LBPTLNORM
    QUIET quiet LBPTLBPT

    15.1.6.5 LFILE Lexemes Shared by All Languages
    Files are one or more characters that can appear in a file name.

    The state is left as LFILE, so that commands such as use and unuse can have lists of files.

    LexemeRegular Expression
    FILENAME {FL}+

    15.1.6.6 LKEYWORD Lexemes Shared by All Languages
    The state remains in LKEYWORD.

    LexemeRegular Expression
    INTEGERconstant "0"{OC}+
    "0"[xX]{HX}+
    {DG}+
    "0"[kK]{HX}+

    15.1.6.7 LLINE Lexemes Shared by All Languages
    All characters up to the next new line are assembled into a STRINGliteral.
    15.1.6.8 LWORD Lexemes Shared by All Languages
    Once the lexical state has been set to LWORD, it will stay there until a NEWLINE or a SEMICOLON is found. Both of these cause the lexical state to become LKEYWORD again. The individual words recognized can be any of the following, but in each case, the state stays LWORD:

    LexemeRegular Expression
    GREATER ">"
    LESS "<"
    GREATERAMPERSAND ">&"
    ONEGREATER "1>"
    TWOGREATER "2>"
    STRINGliteral [']{charChar}*[']
    ["]{stringChar}*["]
    STRINGliteral {WD}* that does not end in a backslash
    WIDECHARACTERconstant [lL][']{charChar}+[']
    WIDESTRINGliteral [lL]["]{stringChar}*["]

    15.1.6.9 LSIGNAL Lexemes Shared by All Languages
    The state stays in LSIGNAL.

    LexemeRegular Expression
    INTEGERconstant {DG}+
    IDENTIFIER {LT}({LT}|{DG})*

    15.1.6.10 LSETENV and LEXPORT Lexemes Shared by All Languages
    LexemeRegular Expression
    ENVARID {EID}+

    15.1.7 Lexemes That Are Represented Differently in Each Language

    Lexeme Representation
    (Some May Be Language Specific)
    Initial Lexical State Changed Lexical State Language Specific?
    ALPHASDIGITSI18N [0-9A-Za-z_$\200-\377] LNORM, LBPT LNORM COBOL
    ALPHASDIGITS
    HYPHENI18N
    [0-9A-Za-z_$\200-\377\-] LNORM, LBPT LNORM COBOL
    AMPERSAND "&" LNORMUnchanged C, C++, Fortran, Ada
    AND AND LNORMUnchanged COBOL
    ANDAND "&&" LNORMUnchanged C, C++, Ada
    ANDassign "&=" LNORMUnchanged C, C++
    ARROW "->" LNORM Unchanged C, C++, Ada
    ARROWstar "->*" LNORM Unchanged C++
    ASSIGNOP "=" LNORM Unchanged C, C++, Fortran, Ada, COBOL
    BRACKETS "[]" LNORM Unchanged C, C++, Ada
    CLCL "::" LNORM Unchanged C++
    DECR "--" LNORM Unchanged C, C++, Ada
    DIVassign "/=" LNORM Unchanged C, C++, Ada
    DOTstar ".*" LNORM Unchanged C++
    ELLIPSIS "..." LNORM Unchanged C++
    EQ "=="
    ".EQ."
    (IS[ \t]+)?
      ("="|("EQUAL"([ \t]+"TO")?))
    LNORM Unchanged C, C++, Ada, Fortran
    Fortran
    COBOL
     
    ERassign "^=" LNORM Unchanged C, C++
    EXPON "**" LNORM Unchanged COBOL
    GE ".GE."
    (IS[ \t]+)?
      "NOT"[ \t]+
      ("<"|("LESS"([ \t]+"THAN")?))
    (IS[ \t]+)?
      (">="|("GREATER"([ \t]+"THAN")?[ \t]
      +"OR"[ \t]+"EQUAL"([ \t]+"TO")?))
    LNORM Unchanged Fortran
    COBOL
     
     
     
     
    GREATER ".GT."
    (IS[ \t]+)?
      (">"|("GREATER"([ \t]+"THAN")?))
    LNORM Unchanged Fortran
    COBOL
     
    HAT "^" LNORM Unchanged C, C++, Ada
    INCR "++" LNORM Unchanged C, C++, Ada
    LBRACKET "[" LNORM Unchanged C, C++, Fortran, Ada
    LE ".LE."
    (IS[ \t]+)?"NOT"[ \t]+
      (">"|("GREATER"([ \t]+"THAN")?))
    (IS[ \t]+)?
      ("<="|("LESS"([ \t]+"THAN")?[ \t]+
      "OR"[ \t]+"EQUAL"([ \t]+"TO")?))
    LNORM Unchanged Fortran
    COBOL
     
     
     
    LESS ".LT."
    (IS[ \t]+)?
      ("<"|("LESS"([ \t]+"THAN")?))
    LNORM Unchanged Fortran
    COBOL
     
    LOGAND ".AND." LNORM Unchanged Fortran
    LOGEQV ".EQV." LNORM Unchanged Fortran
    LOGNEQV ".NEQV." LNORM Unchanged Fortran
    LOGNOT ".NOT." LNORM Unchanged Fortran
    LOGOR ".OR." LNORM Unchanged Fortran
    LOGXOR ".XOR." LNORM Unchanged Fortran
    LS "<<" LNORM Unchanged C, C++, Ada
    LSassign "<<=" LNORM Unchanged C, C++
    MINUS "-" LNORM Unchanged C, C++, Fortran, Ada, COBOL
    MINUSassign "-=" LNORM Unchanged C, C++
    MOD "%"
    MOD
    LNORM Unchanged C, C++, Ada, COBOL
    MODassign "%=" LNORM Unchanged C, C++, Ada
    MULTassign "*=" LNORM Unchanged C, C++, Ada
    NE "!="
    ".NE."
    "/="
    (IS[ \t]+)?
      "NOT"[ \t]+("="|("EQUAL"([ \t]+"TO")?))
    LNORM Unchanged C, C++, Ada
    Fortran

    COBOL

    NOT "!"
    NOT
    LNORM Unchanged C, C++, Ada,
    COBOL
    OPENSLASH "(/" LNORM Unchanged Fortran
    OR "|"
    OR
    LNORM Unchanged C, C++, Ada, COBOL
    OROR "||" LNORM Unchanged C, C++, Ada
    ORassign "|=" LNORM Unchanged C, C++
    PARENS "()" LNORM Unchanged C++
    PERCENT "%" LNORM Unchanged Fortran
    PLUS "+" LNORM Unchanged C, C++, Fortran, COBOL
    PLUSassign "+=" LNORM Unchanged C, C++, Ada
    QUESTION "?" LNORM Unchanged C, C++, Ada
    RBRACKET "]" LNORM Unchanged C, C++, Fortran, Ada
    RS ">>" LNORM Unchanged C, C++, Ada
    RSassign ">>=" LNORM Unchanged C, C++
    SLASHCLOSE "/)" LNORM Unchanged Fortran
    SLASHSLASH "//" LNORM Unchanged Fortran
    STARSTAR "**" LNORM Unchanged Fortran
    TWIDDLE "~" LNORM Unchanged C, C++, Ada
    15.1.7.1 LKEYWORD Lexemes Specific to C++
    If a C++ identifier is followed by a "::", it is assumed to be a class or namespace identifier.

    If a C++ identifier is followed by a "<", complex and dubious checks are made to try to match a complete template instance specifier.

    15.1.7.2 LNORM Lexemes Specific to C and C++
    The lexemes in the following table are specific to C and C++. The state stays in LNORM.

    Lexeme Representation Language
    ARROW "->" C, C++
    INCR "++" C, C++
    DECR "--" C, C++
    LS "<<" C, C++
    RS ">>" C, C++
    EQ "==" C, C++
    NE "!=" C, C++
    ANDAND "&&" C, C++
    OROR "||" C, C++
    MULTassign "*=" C, C++
    DIVassign "/=" C, C++
    MODassign "%=" C, C++
    PLUSassign "+=" C, C++
    MINUSassign "-=" C, C++
    LSassign "<<=" C, C++
    RSassign ">>=" C, C++
    ANDassign "&=" C, C++
    ERassign "^=" C, C++
    ORassign "|=" C, C++
    PLUS "+" C, C++
    MINUS "-" C, C++
    MOD "%" C, C++
    HAT "^" C, C++
    AMPERSAND "&" C, C++
    OR "|" C, C++
    TWIDDLE "~" C, C++
    NOT "!" C, C++
    BRACKETS "[]" C, C++
    ASSIGNOP "=" C, C++
    LBRACKET "[" C, C++
    RBRACKET "]" C, C++
    QUESTION "?" C, C++
    CHAR char C, C++
    DOUBLE double C, C++
    FLOAT float C, C++
    INT int C, C++
    LONG long C, C++
    SHORT short C, C++
    SIGNED signed C, C++
    UNSIGNED unsigned C, C++
    VOID void C, C++
    CONST const C, C++
    VOLATILE volatile C, C++
    SIZEOF sizeof C, C++
    ENUM enum C, C++
    STRUCT struct C, C++
    UNION union C, C++
    INTEGERconstant "0"{OC}+
    "0"[xX]{HX}+
    {DG}+
    C, C++
    FLOATINGconstant {DG}*"."{DG}*
    {DG}*"."{DG}* {Whitespace}?{Exponent}
    {DG}+{Whitespace}?{Exponent }
    C, C++
    IDENTIFIER, TYPEDEFname {LT}|{UCN})({LT}|{UCN}|{DG})* C, C++

    The lexemes in the following table are specific to C++. The state stays in LNORM.

    Lexeme Representation Language
    OPERATOR operator C++
    NEW new C++
    DELETE delete C++
    CLASS class C++
    ELLIPSIS "..." C++
    CLCL "::" C++
    THIS this C++
    DOTstar ".*" C++
    ARROWstar "->*" C++
    PARENS "()" C++

    15.1.7.3 LNORM Lexemes Specific to Fortran
    The lexemes in the following table are specific to Fortran. The state stays in LNORM.

    Lexeme Representation
    PLUS "+"
    MINUS "-"
    STARSTAR "**"
    LESS ".LT."
    LE ".LE."
    EQ ".EQ."
    NE ".NE."
    GE ".GE."
    GREATER ".GT."
    EQ "=="
    NE "/="
    LOGNOT ".NOT."
    LOGAND ".AND."
    LOGOR ".OR."
    LOGEQV ".EQV."
    LOGNEQV ".NEQV."
    LOGXOR ".XOR."
    PERCENT "%"
    ASSIGNOP "="
    SLASHSLASH "//"
    OPENSLASH "(/"
    SLASHCLOSE "/)"
    LBRACKET "["
    RBRACKET "]"
    AMPERSAND "&"
    SIZEOF sizeof
    INTEGERconstant ".TRUE."
    ".FALSE."
    "0"{OC}+
    "0X"{HX}+
    {DG}+
    IDENTIFIER, TYPEDEFname {LT}({LT}|{DG})*
    FortranName [A-Za-z$]({LT}|{DG})*
    FortranNamedKind "_"{FortranName}
    FortranNumericKind "_"{DG}+
    FortranKind {FortranNamedKind}
    {FortranNumericKind}
    FortranCharacterNamedKind {FortranName}"_"
    FortranCharacterNumericKind {DG}+"_"
    FortranCharacterKind {FortranCharacterNamedKind}
    {FortranCharacterNumericKind}
    RealWithDecimal ({DG}+"."{DG}*)
    ({DG}*"."{DG}+)
    ExponentVal [+-]?{DG}+
    RealEExponent [Ee]{ExponentVal}
    RealDExponent [Dd]{ExponentVal}
    RealQExponent [Qq]{ExponentVal}
    RealSingleConstant (({DG}+{RealEExponent})
    ({RealWithDecimal}{RealEExponent}?)){FortranKind}?
    RealDoubleConstant ({DG}+|{RealWithDecimal}){RealDExponent}
    RealQuadConstant ({DG}+|{RealWithDecimal}){RealQExponent}
    RealConstant {RealSingleConstant}
    {RealDoubleConstant}
    {RealQuadConstant}
    REALconstantWithKind RealConstant
    FortranBinaryValue [Bb]((['][01]+['])|(["][01]+["]))
    FortranOctalValue [Oo](([']{OC}+['])|(["]{OC}+["]))
    FortranHexValue [Zz](([']{HX}+['])|(["]{HX}+["]))
    FortranOctalValueAlternative (([']{OC}+['])|(["]{OC}+["]))[Oo]
    FortranHexValueAlternative (([']{HX}+['])|(["]{HX}+["]))[Xx]
    INTEGERconstantWithKind {DG}+{FortranKind}
    {DG}*"#"[0-9A-Za-z]+
    {FortranBinaryValue}
    {FortranOctalValue}
    {FortranHexValue}
    {FortranOctalValueAlternative}
    {FortranHexValueAlternative}
    LOGICALconstantWithKind ".TRUE."{FortranKind}?
    ".FALSE."{FortranKind}?
    CharSingleDelim [^'\\\n]|('')
    CharDoubleDelim [^"\\\n]|("")
    FortranOctalEscape {OC}{1,3}
    FortranHexEscape [Xx]{HX}{1,2}
    FortranEscapeChar [\\]([AaBbFfNnRrTtVv]|{FortranOctalEscape}
                             |{FortranHexEscape}|0|[\\])
    StringSingleDelim [']({CharSingleDelim}|[\\])*[']
    StringDoubleDelim ["]({CharDoubleDelim}|[\\])*["]
    FortranString {StringSingleDelim}
    {StringDoubleDelim}
    CStringSingleDelim [']({CharSingleDelim}|{FortranEscapeChar})*[']
    CStringDoubleDelim ["]({CharDoubleDelim}|{FortranEscapeChar})*["]
    FortranCString ({CStringSingleDelim}|{CStringDoubleDelim})[Cc]
    CHARACTERconstantWithKind {FortranString}
    {FortranCharacterKind}{FortranString}
    {FortranCharacterKind}?{FortranCString}

    15.1.7.4 LNORM Lexemes Specific to Ada
    The lexemes in the following table are specific to Ada. The state stays in LNORM.

    Lexeme Representation
    ARROW "->"
    INCR "++"
    DECR "--"
    LS "<<"
    RS ">>"
    EQ "=="
    NE "!="
    ANDAND "&&"
    OROR "||"
    MULTassign "*="
    DIVassign "/="
    MODassign "%="
    PLUSassign "+="
    MINUSassign "-="
    LSassign "<<="
    RSassign ">>="
    ANDassign "&="
    ERassign "^="
    ORassign "|="
    PLUS "+"
    MINUS "-"
    MOD "%"
    HAT "^"
    AMPERSAND "&"
    OR "|"
    TWIDDLE "~"
    NOT "!"
    BRACKETS "[]"
    ASSIGNOP "="
    LBRACKET "["
    RBRACKET "]"
    QUESTION "?"
    INTEGERconstant "0"{OC}+
    "0X"{HX}+
    {DG}+
    FLOATINGconstant {DG}*"."{DG}+
    {DG}*"."{DG}*{Whitespace}? {Exponent}
    {DG}+{Whitespace}?{Exponent}
    IDENTIFIER, TYPEDEFname {LT}({LT}|{DG})*

    15.1.7.5 LNORM Lexemes Specific to COBOL
    The lexemes in the following table are specific to COBOL. The state stays in LNORM.

    Lexeme Representation
    ALPHASDIGITSI18N [0-9A-Za-z_$\200-\377]
    ALPHASDIGITSHYPHENI18N [0-9\-A-Za-z_$\200-\377]
    CobolWord {ALPHASDIGITSI18N}|({ALPHASDIGITSI18N}{ALPHASDIGITSI18N})
    |({ALPHASDIGITSI18N}+{ALPHASDIGITSHYPHENI18N}
    +{ALPHASDIGITSI18N}+)
    ASSIGNOP "="
    PLUS "+"
    MINUS "-"
    EXPON "**"
    AMPERSAND "&"
    AND AND
    MOD MOD
    NOT NOT
    OR OR
    REFERENCEOF REFERENCE([ \t]+"OF")?
    OF OF
    GIVING GIVING
    USING USING
    BYREFERENCE (BY[ \t]+)?"REFERENCE"
    BYVALUE (BY[ \t]+)?"VALUE"
    BYCONTENT (BY[ \t]+)?"CONTENT"
    BYDESCRIPTOR (BY[ \t]+)?"DESCRIPTOR"
    SIGNPOS (IS[ \t]+)?"POSITIVE"
    (IS[ \t]+)?"NOT"[ \t]+"NEGATIVE"
    SIGNNEG (IS[ \t]+)?"NEGATIVE"
    (IS[ \t]+)?"NOT"[ \t]+"POSITIVE"
    SIGNZERO (IS[ \t]+)?"ZERO"
    SIGNNOTZERO (IS[ \t]+)?"NOT"[ \t]+"ZERO"
    EQ (IS[ \t]+)?("="|("EQUAL"([ \t]+"TO")?))
    LESS (IS[ \t]+)?("<"|("LESS"([ \t]+"THAN")?))
    GREATER (IS[ \t]+)?(">"|("GREATER"([ \t]+"THAN")?))
    NE (IS[ \t]+)?"NOT"[ \t]+("="|("EQUAL"([ \t]+"TO")?))
    GE (IS[ \t]+)?"NOT"[ \t]+("<"|("LESS"([ \t]+"THAN")?))
    (IS[ \t]+)?(">="|("GREATER"([ \t]+"THAN")?[ \t]+"OR"[ \t]+"EQUAL"([ \t]+"TO")?))
    LE (IS[ \t]+)?"NOT"[ \t]+(">"|("GREATER"([ \t]+"THAN")?))
    (IS[ \t]+)?("<="|("LESS" ([ \t]+"THAN")?[ \t]+"OR"[ \t]+"EQUAL"([ \t]+"TO")?))
    DECIMALconstant {DecLit}
    INTEGERconstant {IntLit}
    {CHexLit} HEXADECIMAL
    {CobolHexLit} HEXADECIMAL
    FLOATINGconstant {FloatLit}
    IDENTIFIER {CobolWord}

    15.2 Grammar of Commands

    Most of the grammar for commands has already been given in previous sections. This section concentrates on the grammar for expressions.

    15.2.1 Names and Expressions Within Commands

    The exact syntax of expressions is specific to the current language:
    expression
    	: expression for C
            | expression for C++
            | expression for Fortran
            | expression for Ada
            | expression for COBOL
    
    Often you can omit an expression from a command or use a convenient default instead, to change the meaning of a command:
    expression-opt
            : [ expression ]
    
    Identifiers, Keyword, and Typedef Names
    The debugger uses the normal language lookup rules for identifiers, (obeying scopes, and so on,) but also extends those rules as follows: You can subvert these rules by rescoping the name.

    NOTE: The debugger does not know where in the scope a declaration occurred, so all lookups consider all identifiers in the scope, whether or not they occurred before the current line.

    The lexical tokens for identifiers are specific to the current language, and also to the current lexical state.

    IDENTIFIER
            : identifier for LSIGNAL lexical state
            | identifier for C
            | identifier for C++
            | identifier for Fortran
            | identifier for Ada
            | identifier for COBOL
    
    TYPEDEFnames are lexically just identifiers, but when looking them up in the current scope, the debugger determines that they refer to types, such as TYPEDEFs, classes, or structs. This information is needed to correctly parse C and C++ expressions.
    TYPEDEFname
            : IDENTIFIER
    
    A few lexical tokens act as embedded keywords in some positions within expressions, but the debugger generally tries to accept them as though they were normal identifiers:
    identifier-or-key-word
            : IDENTIFIER
            | embedded-key-word
    
    embedded-key-word
            : ANY
            | CHANGED
            | READ
            | WRITE
    
    In other contexts, the debugger is also prepared to accept TYPEDEFnames (for example, int or the name of a class):
    identifier-or-typedef-name
            : identifier-or-typedef-name for C
            | identifier-or-typedef-name for C++
            | identifier-or-typedef-name for Fortran
            | identifier-or-typedef-name for Ada
            | identifier-or-typedef-name for COBOL
    
    Integer Constants
    The lexical tokens for integer constants are specific to the current language:
    integer_constant
        	: INTEGERconstant for C and C++
        	| INTEGERconstant for Fortran
        	| INTEGERconstant for Ada
        	| INTEGERconstant for COBOL
    
    Macros
    The debugger does not currently understand usages of macros, for example, uses of C and C++ preprocessor #define macros, and so on.
    Calls
    You can call any function whose address can be taken, provided that the parameters can also be passed, and the result returned:
    call-expression
    	: call-expression for C
    	| call-expression for C++
    	| call-expression for Fortran
    	| call-expression for Ada 
    	| call-expression for COBOL
    
    Parameters
    Each language may impose its own restrictions on exactly what can be passed as a parameter.

    Any expression can be passed by value, but C++ constructors and destructors will not be invoked. Evaluating parameters can involve evaluating nested calls.

    Anything whose address can be taken can be passed by reference.

    The debugger has limited understanding of array descriptors.

    Comma is both the argument separator and a valid operator in C and C++. Hence, argument lists are comma-separated assignment-expressions rather than full expressions:

    argument-expression-list
            : assignment-expression
            | assignment-expression COMMA argument-expression-list
    
    arg-expression-list-opt
            : [ argument-expression-list ]
    
    assignment-expression
            : assignment-expression for C
            | assignment-expression for C++
            | assignment-expression for Fortran
            | assignment-expression for Ada
            | assignment-expression for COBOL
    
    Return Results
    Any scalar or structure type can be the return result of a called function. Some simple array types are also supported, but the general cases are not.

    The C++ constructors and destructors are not invoked, which may cause problems.

    Addresses
    You can take the addresses of variables and other data that are in memory, and functions that have had code generated for them. You can also take the address of a line of source code.

    Some variables may be in registers; you cannot take their addresses.

    The optimizing compilers may move variables from one memory location to another, in which case you will obtain the address of the current memory location of the variable.

    The optimizing compilers may eliminate unused functions, as well as functions that have had all calls inlined. Static functions in header files may result in multiple copies of the code, and the address will be of only one of those copies.

    The optimizing compilers and linkers may skip some instructions on the way in during a call, so a breakpoint on the first few instructions may not be hit. When you set a breakpoint on a function, the debugger sets it deeper in the function, at the end of the entry sequence, to try to avoid this.

    The address of a line of source code is the address of the first instruction in memory that came from this line, but this instruction may be branched around, so it might not be executed before any other instruction from the same line.

    Address of a Source Line
    The debugger has extended the syntax of most languages to allow you to get the address of the first instruction that a source line generates. If you do not specify a file via the string, then the current file is used. If you specify a DOLLAR as the line-number, then the last line in the file that generated any instructions is used:
    line-address
            : ATSIGN string COLON line-number
            | ATSIGN line-number
    
    line-number
            : INTEGERconstant
            | DOLLAR
    
    Other Modified Forms of Expressions
    The whatis_command supports supersets of the normal expression syntax of the language:
    whatis-expressions
            : whatis-expressions for C
            | whatis-expressions for C++
            | whatis-expressions for Fortran
            | whatis-expressions for Ada
            | whatis-expressions for COBOL
    
    Some commands (notably the examine command and the cont command) have a syntax that inhibits the use of a full expression. In this case, a more limited form of expression is still allowed:
    address-exp
            : address-exp for C
            | address-exp for C++
            | address-exp for Fortran
            | address-exp for Ada
            | address-exp for COBOL
    
    The cont command and the change_stack_frame_commands have a form that specifies where to continue to, or where to cut the stack back to:
    loc
            : loc for C
            | loc for C++
            | loc for Fortran
            | loc for Ada
            | loc for COBOL
    
    The target of a modifying_command can only be a subset of the possible expressions, known as a unary-expression:
    unary-expression
            : unary-expression for C
            | unary-expression for C++
            | unary-expression for Fortran
            | unary-expression for Ada
            | unary-expression for COBOL
    
    Strings
    The syntax of strings is sensitive to the current lexical state and language:
    string
            : LNORM string
            | LLINE string
            | LWORD string
    
    Most of the languages have places where they allow a series of string literals to be equivalent to a single string formed of their concatenated characters:
    string-literal-list
            : string-literal-list for C
            | string-literal-list for C++
            | string-literal-list for Ada
    
    Rescoped Expressions
    Sometimes the normal language visibility rules are not sufficient for specifying the variable, function, and so on, to which you may want to refer. The debugger extends the language's idea of an expression with an additional possibility called a rescoped expression.

    Rescoped expressions cause the debugger to look up the identifiers and so on in the qual-symbol-opt, as though it were in the source file specified by the preceding filename-tick or qual-symbol-opt:

    rescoped-expression
            : filename-tick qual-symbol-opt
            | TICK qual-symbol-opt
    
    rescoped-typedef
            : filename-tick qual-typedef-opt
            | TICK qual-typedef-opt
    
    filename-tick
            : string-tick
    
    string-tick
            : string TICK
    
    qual-symbol-opt
            : expression                        /* Base (global) name */
            | qual-symbol-opt TICK expression   /* Qualified name */
    
    qual-typedef-opt
            : qual-typedef-opt for C
            | qual-typedef-opt for C++
            | qual-typedef-opt for Fortran
            | qual-typedef-opt for Ada
            | qual-typedef-opt for COBOL
    
    In the following example, rescoped expressions are used to distinguish which x the user is querying, because there are two variables named x (one local to main and one global): By default, a local variable is found before a global one, so that the plain x refers to the local variable: You can use the C++ :: operator to specify the global x in C++ code or rescoped expressions in any language: ,

    In the following example, the x variable is used in the following places to demonstrate how rescoping expressions can find the correct variable:

    When debugging a Fortran 90 program, you can refer to the components of a module using rescoped expressions. For example, when SERIES is a module in the file fft.f90, then "fft.f90"`SERIES`ORDER refers to the component ORDER in the module SERIES.
    Printable Types
    The lexical tokens for printable types are specific to the current language:
    printable-type
        	: printable-type for C
        	| printable-type for C++
        	| printable-type for Fortran
        	| printable-type for Ada
        	| printable-type for COBOL
    

    15.2.2 Expressions Specific to C

    The debugger has an almost complete understanding of C expressions, given the general restrictions:
    expression
            : assignment-expression
    
    constant-expression
            : conditional-expression
    
    C Identifiers
    The lookup rules are almost always correct for C:
    identifier-or-typedef-name
            : identifier-or-key-word
            | TYPEDEFname
    
    C Constants
    The numeric constants are treated exactly the same as in C. The enumeration constant identifiers go through the same grammar paths as variable identifiers, which produces basically the same effect as the C semantics:
    primary-expression
            : identifier-or-key-word
            | constant
            | string-literal-list
            | LPAREN expression RPAREN
            | process_set 
            | LPAREN process_range RPAREN
    
    string-literal-list
            : string
            | string-literal-list string
    
    constant
            : FLOATINGconstant
            | INTEGERconstant
            | CHARACTERconstant
            | WIDECHARACTERconstant
            | WIDESTRINGliteral
    
    C Rescoped Expressions
    The C implementation of rescoped expressions is the following:
    qual-typedef-opt
            : TYPEDEFname
            | qual-typedef-opt TICK TYPEDEFname
    
    whatis-expressions
            : expression
            | rescoped-expression
            | printable-type
    
    C Calls
    Following is the C implementation of calls:
    call-expression
            : expression
    
    function-call
            : postfix-expression LPAREN [arg-expression-list] RPAREN
    
    Restrictions and limits are documented here.
    C Addresses
    Following is the C implementation of addresses:
    address
            : AMPERSAND postfix-expression
            | line-address
            | postfix-expression
    
    address-exp
            : address
            | address-exp PLUS  address
            | address-exp MINUS address
            | address-exp STAR  address
    
    Restrictions and limits are documented here.
    C Loc Specifications
    The C implementation of loc is the following:
    loc
            : expression
            | rescoped-expression
    
    C Types
    The debugger understands the full C type specification grammar:
    type-specifier
            : basic-type-specifier
            | struct-union-enum-type-specifier
            | typedef-type-specifier
    
    basic-type-specifier
            : basic-type-name
            | type-qualifier-list basic-type-name
            | basic-type-specifier type-qualifier
            | basic-type-specifier basic-type-name
    
    type-qualifier-list
            : type-qualifier
            | type-qualifier-list type-qualifier
    
    type-qualifier
            : CONST
            | VOLATILE
    
    basic-type-name
            : VOID
            | CHAR
            | SHORT
            | INT
            | LONG
            | FLOAT
            | DOUBLE
            | SIGNED
            | UNSIGNED
    	
    printable-type
            : rescoped_typedef
    	| type_name	
    
    struct-union-enum-type-specifier
            : elaborated-type-name
            | type-qualifier-list elaborated-type-name
            | struct-union-enum-type-specifier type-qualifier
    
    typedef-type-specifier
            : TYPEDEFname
            | type-qualifier-list TYPEDEFname
            | typedef-type-specifier type-qualifier
    
    elaborated-type-name
            : struct-or-union-specifier
            | enum-specifier
    
    struct-or-union-specifier
            : struct-or-union opt-parenthesized-identifier-or-typedef-name
    
    opt-parenthesized-identifier-or-typedef-name
            : identifier-or-typedef-name
            | LPAREN opt-parenthesized-identifier-or-typedef-name RPAREN
    	
    struct-or-union
            : STRUCT
            | UNION
    
    enum-specifier
            : ENUM identifier-or-typedef-name
    
    type-name
            : type-specifier
            | type-specifier abstract-declarator
            | type-qualifier-list                       // Implicit "int"
            | type-qualifier-list abstract-declarator   // Implicit "int"
    
    type-name-list
            : type-name
            | type-name COMMA type-name-list
     
    abstract-declarator
            : unary-abstract-declarator
            | postfix-abstract-declarator
            | postfixing-abstract-declarator
    
    postfixing-abstract-declarator
            : array-abstract-declarator
            | LPAREN RPAREN
    
    array-abstract-declarator
            : BRACKETS
            | LBRACKET constant-expression RBRACKET
            | array-abstract-declarator LBRACKET constant-expression RBRACKET
    
    unary-abstract-declarator
            : STAR
            | STAR type-qualifier-list
            | STAR abstract-declarator
            | STAR type-qualifier-list abstract-declarator
    
    postfix-abstract-declarator
            : LPAREN unary-abstract-declarator RPAREN
            | LPAREN postfix-abstract-declarator RPAREN
            | LPAREN postfixing-abstract-declarator RPAREN
            | LPAREN unary-abstract-declarator RPAREN postfixing-abstract-declarator
    
    C Other Forms of Expressions
    The following expressions all have their usual C semantics:
    assignment-expression
            : conditional-expression
            | unary-expression ASSIGNOP    assignment-expression
            | unary-expression MULTassign  assignment-expression
            | unary-expression DIVassign   assignment-expression
            | unary-expression MODassign   assignment-expression
            | unary-expression PLUSassign  assignment-expression
            | unary-expression MINUSassign assignment-expression
            | unary-expression LSassign    assignment-expression
            | unary-expression RSassign    assignment-expression
            | unary-expression ANDassign   assignment-expression
            | unary-expression ERassign    assignment-expression
            | unary-expression ORassign    assignment-expression
    
    conditional-expression
            : logical-OR-expression
            | logical-OR-expression QUESTION expression COLON conditional-expression
    
    logical-OR-expression
            : logical-AND-expression
            | logical-OR-expression OROR logical-AND-expression
    
    logical-AND-expression
            : inclusive-OR-expression
            | logical-AND-expression ANDAND inclusive-OR-expression
    
    inclusive-OR-expression
            : exclusive-OR-expression
            | inclusive-OR-expression OR exclusive-OR-expression
    
    exclusive-OR-expression
            : AND-expression
            | exclusive-OR-expression HAT AND-expression
    
    AND-expression
            : equality-expression
            | AND-expression AMPERSAND equality-expression
    
    equality-expression
            : relational-expression
            | equality-expression EQ relational-expression
            | equality-expression NE relational-expression
    
    relational-expression
            : shift-expression
            | relational-expression LESS    shift-expression
            | relational-expression GREATER shift-expression
            | relational-expression LE      shift-expression
            | relational-expression GE      shift-expression
    
    shift-expression
            : additive-expression
            | shift-expression LS additive-expression
            | shift-expression RS additive-expression
    
    additive-expression
            : multiplicative-expression
            | additive-expression PLUS  multiplicative-expression
            | additive-expression MINUS multiplicative-expression
    
    multiplicative-expression
            : cast-expression
            | multiplicative-expression STAR  cast-expression
            | multiplicative-expression SLASH cast-expression
            | multiplicative-expression MOD   cast-expression
    
    cast-expression
            : unary-expression
            | LPAREN type-name RPAREN cast-expression
    
    unary-expression
            : postfix-expression
            | INCR unary-expression
            | DECR unary-expression
            | AMPERSAND cast-expression
            | STAR cast-expression
            | PLUS cast-expression
            | MINUS cast-expression
            | TWIDDLE cast-expression
            | NOT cast-expression
            | SIZEOF unary-expression
            | SIZEOF LPAREN type-name RPAREN
            | line-address
    
    postfix-expression
            : primary-expression
            | postfix-expression LBRACKET expression RBRACKET
            | function-call
    	| postfix-expression LPAREN type-name-list RPAREN
            | postfix-expression DOT   identifier-or-typedef-name
            | postfix-expression ARROW identifier-or-typedef-name
            | postfix-expression INCR
            | postfix-expression DECR
    

    15.2.3 Expressions Specific to C++

    C++ is a complex language, with a rich expression system. The debugger understands much of the system, but it does not understand how to evaluate some complex aspects of a C++ expression. It can correctly debug these when they occur in the source code.

    The aspects of the expression system not processed properly during debugger expression evaluation include the following:

    There are also some minor restrictions in the following grammar, compared with the full C++ expression grammar, to make it unambiguous:

    expression
            : assignment-expression
    
    constant-expression
            : conditional-expression
    
    C++ Identifiers
    The debugger correctly augments the general lookup rules when inside class member functions, to look up the members correctly.

    The debugger has only a limited understanding of namespaces. It correctly processes names such as UserNameSpace::NestedNamespace::userIdentifier, as well as C++ use-declarations, which introduce a new identifier into a scope.

    The debugger does not currently understand C++ using-directives.

    The debugger understands the relationship between struct and class identifiers and typedef identifiers:

    id-or-keyword-or-typedef-name
            : identifier-or-key-word
            | TYPEDEFname
    
    C++ Constants
    The debugger treats numeric constants the same as C++ does. The enumeration constant identifiers go though the same grammar paths as variable identifiers, which produces basically the same effect as the C++ semantics:
    constant
            : FLOATINGconstant
            | INTEGERconstant
            | CHARACTERconstant
            | WIDECHARACTERconstant
            | WIDESTRINGliteral
    
    C++ Calls
    The debugger does not understand the following aspects of C++ calls:
    call-expression
            : expression
    
    Restrictions and limits are documented here.
    C++ Addresses
    Following is the C++ implementation of addresses:
    address
            : AMPERSAND postfix-expression /* Address of */
            | line-address
            | postfix-expression
    
    address-exp
            : address
            | address-exp PLUS  address
            | address-exp MINUS address
            | address-exp STAR  address
    
    Restrictions and limits are documented here.
    C++ Loc
    Following is the C++ implementation of loc:
    loc
            : expression
            | rescoped-expression
    
    C++ Other Modified Forms of Expressions
    whatis-expressions
            : expression
            | printable-type
    
    C++ Rescoped Expressions
    The C++ implementation of rescoped expressions is as follows:
    qual-typedef-opt
            : type-name
            | qual-typedef-opt TICK type-name
    
    C++ Strings
    The C++ implementation of strings is as follows:
    string-literal-list
            : string
            | string-literal-list string
    
    C++ Identifier Expressions
    The debugger understands nested names. Namespaces go through the same paths as classes, hence the unusual use of TYPEDEFname:
    id-expression
    	: id-expression-internals
    
    id-expression-internals
    	: qualified-id
    	| id-or-keyword-or-typedef-name
    	| operator-function-name
    	| TWIDDLE id-or-keyword-or-typedef-name
    
    qualified-id
    	: nested-name-specifier qualified-id-follower 
    
    qualified-type
    	: nested-name-specifier TYPEDEFname
    
    nested-name-specifier
    	: CLCL
    	| TYPEDEFname CLCL
    	| nested-name-specifier TYPEDEFname CLCL
    
    qualified-id-follower
    	: identifier-or-key-word 
    	| operator-function-name
    	| TWIDDLE id-or-keyword-or-typedef-name
    
    C++ Types
    The debugger understands the full C++ type specification grammar:
    type-specifier
            : basic-type-specifier
            | struct-union-enum-type-specifier
            | typedef-type-specifier
    
    type-qualifier-list
            : type-qualifier
            | type-qualifier-list type-qualifier
    
    type-qualifier
            : CONST
            | VOLATILE
    
    basic-type-specifier
            : basic-type-name basic-type-name
            | basic-type-name type-qualifier
            | type-qualifier-list basic-type-name
            | basic-type-specifier type-qualifier
            | basic-type-specifier basic-type-name
    
    struct-union-enum-type-specifier
            : elaborated-type-name
            | type-qualifier-list elaborated-type-name
            | struct-union-enum-type-specifier type-qualifier
    
    typedef-type-specifier
            : TYPEDEFname type-qualifier
            | type-qualifier-list TYPEDEFname
            | typedef-type-specifier type-qualifier
    
    basic-type-name
            : VOID
            | CHAR
            | SHORT
            | INT
            | LONG
            | FLOAT
            | DOUBLE
            | SIGNED
            | UNSIGNED
    
    elaborated-type-name
            : aggregate-name
            | enum-name
    	
    printable-type
            : rescoped-typedef
    	| type-name	
    
    aggregate-name
            : aggregate-key opt-parenthesized-identifier-or-typedef-name
            | aggregate-key qualified-type
    
    opt-parenthesized-identifier-or-typedef-name
            : id-or-keyword-or-typedef-name
            | LPAREN opt-parenthesized-identifier-or-typedef-name RPAREN
    
    aggregate-key
            : STRUCT
            | UNION
            | CLASS
    
    enum-name
            : ENUM id-or-keyword-or-typedef-name
    
    parameter-type-list
            : PARENS type-qualifier-list-opt
    
    type-name
            : type-specifier
            | qualified-type
    	| basic-type-name
            | TYPEDEFname
            | type-qualifier-list
            | type-specifier abstract-declarator
            | basic-type-name abstract-declarator
    	| qualified-type abstract-declarator
    	| TYPEDEFname abstract-declarator
            | type-qualifier-list abstract-declarator
    
    abstract-declarator
            : unary-abstract-declarator
            | postfix-abstract-declarator
            | postfixing-abstract-declarator
    
    postfixing-abstract-declarator
            : array-abstract-declarator
            | parameter-type-list
    
    array-abstract-declarator
            : BRACKETS
            | LBRACKET constant-expression RBRACKET
            | array-abstract-declarator LBRACKET constant-expression RBRACKET
    
    unary-abstract-declarator
            : STAR
            | AMPERSAND
            | pointer-operator-type
            | STAR                  abstract-declarator
            | AMPERSAND             abstract-declarator
            | pointer-operator-type abstract-declarator
    
    postfix-abstract-declarator
            : LPAREN unary-abstract-declarator RPAREN
            | LPAREN postfix-abstract-declarator RPAREN
            | LPAREN postfixing-abstract-declarator RPAREN
            | LPAREN unary-abstract-declarator RPAREN postfixing-abstract-declarator
    
    pointer-operator-type
            : TYPEDEFname CLCL STAR type-qualifier-list-opt
            | STAR                  type-qualifier-list
            | AMPERSAND             type-qualifier-list
    
    C++ Other Forms of Expressions
    The following expressions all have the usual C++ semantics:
    primary-expression
            : constant
            | string-literal-list
       	| THIS
            | LPAREN expression RPAREN
            | operator-function-name
            | identifier-or-key-word
            | qualified-id
    	| process_set 
            | LPAREN process_range RPAREN
    
    operator-function-name
            : OPERATOR operator-predefined
            | OPERATOR basic-type-name
            | OPERATOR TYPEDEFname
            | OPERATOR LPAREN type-name RPAREN
            | OPERATOR type-qualifier
    	| OPERATOR qualified-type
    
    operator-predefined
    	: PLUS
    	| MINUS
    	| STAR
    	| ...
    	| DELETE
    	| COMMA
    
    type-qualifier-list-opt
            : [ type-qualifier-list ]
    
    postfix-expression
            : primary-expression
            | postfix-expression LBRACKET expression RBRACKET
            | postfix-expression PARENS 
            | postfix-expression LPAREN  argument-expression-list RPAREN
            | postfix-expression LPAREN  type-name-list RPAREN
            | postfix-expression DOT  id-expression
            | postfix-expression ARROW id-expression
            | postfix-expression INCR
            | postfix-expression DECR
            | TYPEDEFname LPAREN argument-expression-list RPAREN
            | TYPEDEFname LPAREN type-name-list RPAREN
            | basic-type-name LPAREN assignment-expression RPAREN
    
    type-name-list
            : type-name
            | type-name COMMA type-name-list
            | type-name comma-opt-ellipsis
            | ELLIPSIS
    
    comma-opt-ellipsis
            : ELLIPSIS
            | COMMA ELLIPSIS
    
    unary-expression
            : postfix-expression
            | INCR unary-expression
            | DECR unary-expression
            | line-address
            | AMPERSAND cast-expression
            | STAR cast-expression
            | MINUS cast-expression
            | PLUS cast-expression
            | TWIDDLE LPAREN cast-expression RPAREN
            | NOT cast-expression
            | SIZEOF unary-expression
            | SIZEOF LPAREN type-name RPAREN
            | allocation-expression
    
    allocation-expression
            : operator-new LPAREN type-name RPAREN operator-new-initializer
            | operator-new LPAREN argument-expression-list RPAREN LPAREN type-name RPAREN operator-new-initializer
    
    operator-new
            : NEW
            | CLCL NEW
    
    operator-new-initializer
            : [ PARENS ]
            | [ LPAREN argument-expression-list RPAREN ]
    
    cast-expression
            : unary-expression
            | LPAREN type-name RPAREN cast-expression
    
    deallocation-expression
            : cast-expression
            | DELETE               deallocation-expression
            | CLCL DELETE          deallocation-expression
            | DELETE BRACKETS      deallocation-expression
            | CLCL DELETE BRACKETS deallocation-expression
    
    point-member-expression
            : deallocation-expression
            | point-member-expression DOTstar    deallocation-expression
            | point-member-expression ARROWstar  deallocation-expression
    
    multiplicative-expression
            : point-member-expression
            | multiplicative-expression STAR  point-member-expression
            | multiplicative-expression SLASH point-member-expression
            | multiplicative-expression MOD   point-member-expression
    
    additive-expression
            : multiplicative-expression
            | additive-expression PLUS  multiplicative-expression
            | additive-expression MINUS multiplicative-expression
    
    shift-expression
            : additive-expression
            | shift-expression LS additive-expression
            | shift-expression RS additive-expression
    
    relational-expression
            : shift-expression
            | relational-expression LESS    shift-expression
            | relational-expression GREATER shift-expression
            | relational-expression LE      shift-expression
            | relational-expression GE     shift-expression
    
    equality-expression
            : relational-expression
            | equality-expression EQ relational-expression
            | equality-expression NE relational-expression
    
    AND-expression
            : equality-expression
            | AND-expression AMPERSAND equality-expression
    
    exclusive-OR-expression
            : AND-expression
            | exclusive-OR-expression HAT AND-expression
    
    inclusive-OR-expression
            : exclusive-OR-expression
            | inclusive-OR-expression OR exclusive-OR-expression
    
    logical-AND-expression
            : inclusive-OR-expression
            | logical-AND-expression ANDAND inclusive-OR-expression
    
    logical-OR-expression
            : logical-AND-expression
            | logical-OR-expression OROR logical-AND-expression
    
    conditional-expression
            : logical-OR-expression
            | logical-OR-expression QUESTION expression COLON conditional-expression
    
    assignment-expression
            : conditional-expression
            | unary-expression ASSIGNOP    assignment-expression
            | unary-expression MULTassign  assignment-expression
            | unary-expression DIVassign   assignment-expression
            | unary-expression MODassign   assignment-expression
            | unary-expression PLUSassign  assignment-expression
            | unary-expression MINUSassign assignment-expression
            | unary-expression LSassign    assignment-expression
            | unary-expression RSassign    assignment-expression
            | unary-expression ANDassign   assignment-expression
            | unary-expression ERassign    assignment-expression
            | unary-expression ORassign    assignment-expression
    

    15.2.4 Expressions Specific to Fortran

    This section contains expressions specific to Fortran.
    Fortran Identifiers
    The Fortran implementation of identifiers is as follows:
    identifier-or-typedef-name
            : identifier-or-key-word
            | TYPEDEFname
            | PROCEDUREname
    
    Fortran Constants
    The Fortran implementation of constants is as follows:
    real-or-imag-part
            : real_constant
            | PLUS real_constant
            | MINUS real_constant
            | integer_constant
            | PLUS integer_constant
            | MINUS integer_constant
    
    constant
            : real_constant
            | integer_constant
            | complex-constant
            | character_constant
    	| LOGICALconstantWithKind
    
    character_constant
    	: CHARACTERconstantWithKind
    	| string
    
    complex-constant
            : LPAREN real-or-imag-part COMMA real-or-imag-part RPAREN
    
    Fortran Rescoped Expressions
    The Fortran implementation of rescoped expressions is as follows:
    qual-typedef-opt
            : TYPEDEFname /* Base (global) name */
            | qual-typedef-opt TICK TYPEDEFname /* Qualified name */
    
    whatis-expressions
            : expression
            | rescoped-expression
            | printable_type
    
    Fortran Calls
    The Fortran implementation of calls is as follows:
    call-expression
            : call-stmt
    
    call-stmt
            : named-subroutine
            | named-subroutine LPAREN RPAREN
            | named-subroutine LPAREN actual-arg-spec-list RPAREN
    
    Fortran Addresses
    The Fortran implementation of addresses is as follows:
    address
            : line-address
            | primary   
    
    address-exp
            : address
            | address-exp PLUS  address
            | address-exp MINUS address
            | address-exp STAR  address
    
    Restrictions and limits are documented here.
    Fortran Loc
    The Fortran implementation of loc is as follows:
    loc
            : expression
            | rescoped-expression
    
    Fortran Types
    The Fortran implementation of types is as follows:
    type-name
            : TYPEDEFname
    
    printable-type
            : rescoped-typedef
    	| type-name	
    
    Other Forms of Fortran Expressions
    Following are other forms of Fortran expressions:
    expression
            : expr
            | named-procedure
    
    assignment-expression
            : expr
    
    constant-expression
            : constant
    
    unary-expression
            : variable
    
    expr
            : level-5-expr
            | expr defined-binary-op level-5-expr
    
    level-5-expr
            : equiv-operand
            | level-5-expr LOGEQV equiv-operand
            | level-5-expr LOGNEQV equiv-operand
            | level-5-expr LOGXOR equiv-operand
    
    equiv-operand
            : or-operand
            | equiv-operand LOGOR or-operand
    
    or-operand
            : and-operand
            | or-operand LOGAND and-operand
    
    and-operand
            : level-4-expr
            | LOGNOT and-operand
    
    level-4-expr
            : level-3-expr
            | level-3-expr LESS level-3-expr
            | level-3-expr GREATER level-3-expr
            | level-3-expr LE level-3-expr
            | level-3-expr GE level-3-expr
            | level-3-expr EQ level-3-expr
            | level-3-expr NE level-3-expr
    
    level-3-expr
            : level-2-expr
            | level-3-expr SLASHSLASH level-2-expr
    
    level-2-expr
            : add-operand
            | level-2-expr PLUS  add-operand
            | level-2-expr MINUS add-operand
    
    add-operand
            : add-operand-f90
            | add-operand-dec
            | unary-expr-dec
    
    add-operand-f90
            : mult-operand-f90
            | add-operand-f90 STAR  mult-operand-f90
            | add-operand-f90 SLASH mult-operand-f90
    
    mult-operand-f90
            : level-1-expr
            | level-1-expr STARSTAR mult-operand-f90
    
    add-operand-dec
            : mult-operand-dec
            | add-operand-f90 STAR  mult-operand-dec
            | add-operand-f90 SLASH mult-operand-dec
            | add-operand-f90 STAR  unary-expr-dec
            | add-operand-f90 SLASH unary-expr-dec
    
    mult-operand-dec
            : level-1-expr STARSTAR mult-operand-dec
            | level-1-expr STARSTAR unary-expr-dec
    
    unary-expr-dec
            : PLUS  add-operand
            | MINUS add-operand
    
    level-1-expr
            : primary
            | defined-unary-op primary
    
    defined-unary-op
    
            : DOT_LETTERS_DOT 
    
    primary
            : constant
            | variable
            | function-reference
            | LPAREN expr RPAREN
            | AMPERSAND variable 
            | process_set 
            | LPAREN process_range RPAREN
    	
    defined-binary-op
    
            : DOT_LETTERS_DOT 
    
    int-expr
            : expr
    
    scalar-int-expr
            : int-expr
    
    variable
            : named-variable
            | subobject
    
    named-variable
            : variable-name
    
    subobject
            : array-elt-or-sect
            | structure-component
            | known-substring
    
    known-substring
            : disabled-array-elt-or-sect LPAREN substring-range RPAREN
            | hf-array-abomination
    
    substring-range
            : scalar-int-expr COLON scalar-int-expr
            | scalar-int-expr COLON
            |                 COLON scalar-int-expr
            |                 COLON
    
    hf-array-abomination
            : named-variable 
    	    LPAREN section-subscript-list RPAREN
                LPAREN section-subscript RPAREN
            | structure PERCENT any-identifier
                LPAREN section-subscript-list RPAREN
                LPAREN section-subscript RPAREN
            | structure DOT any-identifier
                LPAREN section-subscript-list RPAREN
                LPAREN section-subscript RPAREN
    
    disabled-array-elt-or-sect
            : DISABLER array-elt-or-sect 
    
    array-elt-or-sect
            : named-variable LPAREN section-subscript-list RPAREN
            | structure PERCENT any-identifier LPAREN section-subscript-list RPAREN
            | structure DOT any-identifier LPAREN section-subscript-list RPAREN
    
    section-subscript-list
            : section-subscript
            | section-subscript COMMA section-subscript-list
    
    subscript
            : scalar-int-expr
    
    section-subscript
            : subscript
            | subscript-triplet
    
    subscript-triplet
            : subscript COLON subscript COLON stride
            | subscript COLON           COLON stride
            |           COLON subscript COLON stride
            |           COLON           COLON stride
            | subscript COLON subscript
            | subscript COLON
            |           COLON subscript
            |           COLON
    
    stride
            : scalar-int-expr
    
    structure-component
            : structure PERCENT any-identifier
            | structure DOT any-identifier
    
    structure
            : named-variable
            | structure-component
            | array-elt-or-sect
    
    function-reference
            : SIZEOF LPAREN expr RPAREN
            | named-function LPAREN RPAREN
            | named-function LPAREN actual-arg-spec-list RPAREN
    
    named-procedure
            :  PROCEDUREname
    
    named-function
            :  PROCEDUREname
    
    named-subroutine
            :  PROCEDUREname
    
    actual-arg-spec-list
            : actual-arg-spec
            | actual-arg-spec COMMA actual-arg-spec-list
    
    actual-arg-spec
            : actual-arg
    
    actual-arg
            : expr
    
    any-identifier
            : variable-name
    	| PROCEDUREname
    	
    variable-name
            : identifier-or-key-word
    
    PROCEDUREname
            : IDENTIFIER
    

    15.2.5 Expressions Specific to Ada

    This section contains expressions specific to Ada.
    Ada Constants
    The Ada implementation of constants is as follows. NOTE: ENUMERATIONconstant is not included in this section because it is like a variable with a type of "enumeration constant."

    constant
            : FLOATINGconstant
            | INTEGERconstant
    	| CHARACTERconstant
    
    Ada Rescoped Expressions
    The Ada implementation of rescoped expressions is as follows:
    qual-typedef-opt
            : TYPEDEFname  
            | qual-symbol-opt TICK TYPEDEFname 
    
    whatis-expressions
            : expression
            | rescoped-expression
            | printable_type
    
    Ada Calls
    The Ada implementation of calls is as follows:
    call-expression
            : expression
    
    Ada Addresses
    The Ada implementation of addresses is as follows:
    address
            : line-address
            | AMPERSAND postfix_expression 
            | LPAREN postfix_expression RPAREN
    
    address-exp
            : address
            | address-exp PLUS  address
            | address-exp MINUS address
            | address-exp STAR  address
    
    Ada Loc Specification
    The Ada implementation of loc is as follows:
    loc
            : expression
            | rescoped-expression
    
    Ada Types
    The Ada implementation of types is as follows:
    type-specifier
            : typedef-type-specifier
    
    typedef-type-specifier
            : TYPEDEFname
    
    identifier-or-typedef-name
            : identifier-or-key-word
            | TYPEDEFname
    
    type-name
            : type-specifier
            | type-specifier abstract-declarator
    
    printable-type
            : rescoped-typedef
    	| type-name	
    
    Other Forms of Ada Expressions
    Following are other forms of Ada expressions:
    primary-expression
    	: identifier-or-key-word  
            | constant  
            | string-literal-list
            | LPAREN expression RPAREN
            | process_set 
            | LPAREN process_range RPAREN
    	
    postfix-expression
            : primary-expression
            | postfix-expression LBRACKET expression RBRACKET
            | postfix-expression LPAREN arg-expression-list-opt RPAREN
            | postfix-expression DOT identifier-or-typedef-name
            | postfix-expression ARROW identifier-or-typedef-name
            | postfix-expression INCR
            | postfix-expression DECR
    
    string-literal-list
            : string
            | string-literal-list string
    
    unary-expression
            : postfix-expression
            | INCR unary-expression
            | DECR unary-expression
            | AMPERSAND cast-expression
            | line-address
            | STAR cast-expression
            | PLUS cast-expression
            | MINUS cast-expression
            | TWIDDLE cast-expression
            | NOT cast-expression
    
    cast-expression
            : unary-expression
            | LPAREN type-name RPAREN cast-expression
    
    multiplicative-expression
            : cast-expression
            | multiplicative-expression STAR  cast-expression
            | multiplicative-expression SLASH cast-expression
            | multiplicative-expression MOD   cast-expression
    
    additive-expression
            : multiplicative-expression
            | additive-expression PLUS  multiplicative-expression
            | additive-expression MINUS multiplicative-expression
    
    shift-expression
            : additive-expression
            | shift-expression LS additive-expression
            | shift-expression RS additive-expression
    
    relational-expression
            : shift-expression
            | relational-expression LESS    shift-expression
            | relational-expression GREATER shift-expression
            | relational-expression LE      shift-expression
            | relational-expression GE      shift-expression
    
    equality-expression
            : relational-expression
            | equality-expression EQ relational-expression
            | equality-expression NE relational-expression
    
    AND-expression
            : equality-expression
            | AND-expression AMPERSAND equality-expression
    
    exclusive-OR-expression
            : AND-expression
            | exclusive-OR-expression HAT AND-expression
    
    inclusive-OR-expression
            : exclusive-OR-expression
            | inclusive-OR-expression OR exclusive-OR-expression
    
    logical-AND-expression
            : inclusive-OR-expression
            | logical-AND-expression ANDAND inclusive-OR-expression
    
    logical-OR-expression
            : logical-AND-expression
            | logical-OR-expression OROR logical-AND-expression
    
    conditional-expression
            : logical-OR-expression
            | logical-OR-expression QUESTION expression COLON conditional-expression
    
    assignment-expression
            : conditional-expression
            | unary-expression ASSIGNOP assignment-expression
            | unary-expression MULTassign assignment-expression
            | unary-expression DIVassign assignment-expression
            | unary-expression MODassign assignment-expression
            | unary-expression PLUSassign assignment-expression
            | unary-expression MINUSassign assignment-expression
            | unary-expression LSassign assignment-expression
            | unary-expression RSassign assignment-expression
            | unary-expression ANDassign assignment-expression
            | unary-expression ERassign assignment-expression
            | unary-expression ORassign assignment-expression
    
    expression
            : assignment-expression
    
    constant-expression
            : conditional-expression
    
    abstract-declarator
            : unary-abstract-declarator
            | postfix-abstract-declarator
            | postfixing-abstract-declarator
    
    postfixing-abstract-declarator
            : array-abstract-declarator
            | LPAREN RPAREN
    
    array-abstract-declarator
            : BRACKETS
            | LBRACKET constant-expression RBRACKET
            | array-abstract-declarator LBRACKET constant-expression RBRACKET
    
    unary-abstract-declarator
            : STAR
            | STAR abstract-declarator
    
    postfix-abstract-declarator
            : LPAREN unary-abstract-declarator RPAREN
            | LPAREN postfix-abstract-declarator RPAREN
            | LPAREN postfixing-abstract-declarator RPAREN
            | LPAREN unary-abstract-declarator RPAREN postfixing-abstract-declarator
    

    15.2.6 Expressions Specific to COBOL

    This section contains expressions specific to COBOL.
    COBOL Constants
    The COBOL implementation of constants is as follows:
    constant
            : FLOATINGconstant
            | INTEGERconstant
            | DECIMALconstant
            | CHARACTERconstant
    	
    constant-expression
            : cobol-expression
    
    COBOL Rescoped Expressions
    The COBOL implementation of rescoped expressions is as follows:
    qual-typedef-opt
            : TYPEDEFname
            | qual-typedef-opt TICK TYPEDEFname
    
    COBOL Calls
    The COBOL implementation of calls is as follows:
    call-expression
            : identifier-or-key-word
            | identifier-or-key-word USING cobol-expression-list
    
    COBOL Addresses
    The COBOL implementation of addresses is as follows:
    address
            : INTEGERconstant  
            | line-address
            | address-language  
            | LPAREN cobol-expression RPAREN
    
    address-exp
            : address
            | address-exp PLUS  address
            | address-exp MINUS address
            | address-exp STAR  address
    
    address-language
            : AMPERSAND cobol-identifier
            | REFERENCEOF cobol-identifier
    
    COBOL Loc
    The COBOL implementation of loc is as follows:
    loc
            : cobol-identifier
            | rescoped-expression
    
    COBOL Types
    The COBOL implementation of types is as follows:
    printable-type
            : rescoped-typedef
    
    Other Forms of COBOL Expressions
    Following are other forms of COBOL expressions:
    assignment-expression
            : expression
    
    cobol-expression
            : cobol-identifier
            | constant
            | string
            | cobol-expression PLUS  cobol-expression
            | cobol-expression MINUS cobol-expression
            | cobol-expression STAR  cobol-expression
            | cobol-expression SLASH cobol-expression
            | cobol-expression EXPON cobol-expression
            | MINUS cobol-expression   
            | PLUS cobol-expression    
            | LPAREN cobol-expression RPAREN
            | process_set 
            | LPAREN process_range RPAREN
    
    cobol-expression-list
            : cobol-expression
            | cobol-expression COMMA cobol-expression-list
    
    cobol-identifier
            : qualification
            | subscript
            | refmod
    
    condition-expression
            : combined-condition
            | negated-simple-condition
    
    combined-condition
            : negated-simple-condition AND negated-simple-condition
            | negated-simple-condition OR  negated-simple-condition
            | LPAREN combined-condition RPAREN
    
    negated-simple-condition
            : simple-condition
            | NOT simple-condition
            | LPAREN NOT simple-condition RPAREN
    
    simple-condition
            : cobol-expression EQ       cobol-expression
            | cobol-expression ASSIGNOP cobol-expression
            | cobol-expression NE       cobol-expression
            | cobol-expression LESS     cobol-expression
            | cobol-expression GREATER  cobol-expression
            | cobol-expression LE       cobol-expression
            | cobol-expression GE       cobol-expression
            | cobol-expression SIGNPOS
            | cobol-expression SIGNNEG
            | cobol-expression SIGNZERO
            | cobol-expression SIGNNOTZERO
            | LPAREN simple-condition RPAREN
    
    expression
            : constant-expression
            | condition-expression
            | address-language
    
    identifier-or-typedef-name
            : identifier-or-key-word
    
    lvalue-expression
            : cobol-identifier
    
    qualification
            : identifier-or-key-word OF qualification
            | identifier-or-key-word
    
    refmod
            : qualification LPAREN cobol-expression COLON RPAREN
            | qualification LPAREN cobol-expression COLON cobol-expression RPAREN
            | subscript LPAREN cobol-expression COLON RPAREN
            | subscript LPAREN cobol-expression COLON cobol-expression RPAREN
    
    subscript
            : qualification LPAREN cobol-expression-list RPAREN
    
    unary-expression
            : lvalue-expression
    
    whatis-expressions
            : expression
            | rescoped-expression
            | rescoped-typedef
    

    Chapter 16—Debugging Core Files

    When the operating system encounters an unrecoverable error while running a process, for example a segmentation violation (SEGV), the system creates a file named core and places it in the current directory. The core file is not an executable file; it is a snaphot of the state of your process at the time the error occurred. It allows you to analyze the process at the point it crashed.

    This chapter discusses the following topics:

    It also contains a core file debugging example and a quick reference for transporting a core file.

    16.1 Invoking the Debugger on a Core File

    You can use the debugger to examine the process information in a core file. Use the following Ladebug command syntax to invoke the debugger on a core file:
           % ladebug executable_file core_file
    
    or
           (ladebug) load executable_file core_file
    
    The executable file is that which was being executed at the time the core file was generated.

    16.2 Debugging a Core File

    When debugging a core file, you can use the debugger to obtain a stack trace and the values of some variables, just as you would for a stopped process.

    The stack trace lists the functions in your program that were active when the dump occurred. By examining the values of a few variables along with the stack trace, you may be able to pinpoint the process state and the cause of the core dump. Core files cannot be executed; therefore the rerun, step, cont, and other commands will not work until you create a process using the run command.

    In addition, if the program is multithreaded, you can examine the thread information with the show thread and thread commands. You can examine the stack trace for a particular thread or for all threads with the where thread command.

    The following example uses a null pointer reference in the factorial function. This reference causes the process to abort and dump the core when it is executed. The dump command prints the value of the x variable as a null, and the print *x command reveals that you cannot dereference a null pointer.

           % cat testProgram.c
    
            #include <stdio.h>
            int factorial(int i)
    
            main() {
                    int i,f;
                    for (i=1 ; i<3 ; i++) {
                            f = factorial(i);
                            printf("%d! = %d\en",i,f);
                    }
            }
    
            int factorial(int i)
            int i;
            {
            int *x;
                     x = 0;
                     printf("%d",*x);
                     if (i<=1)
                             return (1);
                     else
                             return (i * factorial(i-1) );
            }
    
            % cc -o testProgram -g testProgram.c
            % testProgram
            Memory fault - core dumped.
            % ladebug testProgram core
            Welcome to the Ladebug Debugger Version n
            ------------------
            object file name: testProgram
            core file name: core
            Reading symbolic information ...done
            Core file produced from executable testProgram
            Thread terminated at PC 0x120000dc4 by signal SEGV
            (ladebug) where
            >0  0x120000dc4 in factorial(i=1) testProgram.c:13
            #1  0x120000d44 in main() testProgram.c:4
            (ladebug) dump
            >0  0x120000dc4 in factorial(i=1) testProgram.c:13
            printf("%d",*x);
            (ladebug) print *x
            Cannot dereference 0x0
            Error: no value for *x
            (ladebug)
    

    16.3 Transporting a Core File

    Transporting core files is usually necessary to debug a core file on a system other than that which produced it. It is sometimes possible to debug a core file on a system other than that which produced it if the current system is sufficiently similar to the original system, but it will not work correctly in general.

    Procedure for Transporting Core Files

    The following procedure (see also quick reference) shows how to transport the core files, including the Compaq POSIX Threads Library. In this example, a.out is the name of the executable and core is the name of the core file.

    You need to collect a variety of files from the original system. These include the executable, the core file, shared libraries used by the executable, and /usr/shlib/libpthreaddebug.so if the POSIX Threads Library is involved.

    Do the following steps (1 through 4) on the original system:

    1. Determine the shared objects in use:
             % ladebug a.out core
              (ladebug) listobj
              (ladebug) quit
      
    2. Cut, paste, and edit the result into a list of file names. Most will probably begin with /usr/shlib/.
    3. If /usr/shlib/libpthread.so is one of the files, add /usr/shlib/libpthreaddebug.so to the list. (If you have a privately delivered libpthread.so, there should be a privately delivered corresponding libpthreaddebug.so; use the privately delivered one.)
    4. Package the a.out, core and shared objects, for example, into a tar file. Be sure to use the tar h option to force tar to follow symbolic links as if they were normal files or directories.
             % tar cfvh mybug.tar
      
    Then do the following steps (5 through 14) on the current system:

    On the current system, the executable and core file are generally put in the current working directory, the shared objects are put in an application subdirectory, and libpthreaddebug.so is put in a debugger subdirectory.

    1. Create a directory for debugging the transported core files:
             % mkdir mybug
      
    2. Move to that directory:
             % cd mybug
      
    3. Get the package:
             % mv <wherever>/mybug.tar .
      
    4. Create the subdirectories applibs and dbglibs:
             % mkdir applibs dbglibs
      
    5. Unpackage the tar files. Be sure to use the tar s option to strip off any leading slashes from pathnames during extraction:
             % tar xfvs mybug.tar
      
    6. Move the shared objects (that were originally in /usr/shlib and are now in usr/shlib) into applibs:
         	% mv usr/shlib/* applibs
      

      If the tar xfvs output in step 9 moved shared objects into other directories, move them into applibs as well.

    7. Make libpthreaddebug.so exist in the dbglibs directory, for example, by linking it to the file in the applibs directory:
             % ln -s ../applibs/libpthreaddebug.so dbglibs/libpthreaddebug.so
      
    8. Set the LADEBUG_COREFILE_LIBRARY_PATH environment variable to the application subdirectory. This directs the debugger to look for shared objects (by their base names) in the application subdirectory before trying the system directories. If the POSIX Threads Library is involved, set the LD_LIBRARY_PATH environment variable to the debugger subdirectory so that the debugger will use the correct libpthreaddebug.so.
             % env LADEBUG_COREFILE_LIBRARY_PATH=applibs \
              LD_LIBRARY_PATH=dbglibs \
              ladebug a.out core
      
    9. Determine that the shared objects are in the applibs subdirectory rather than in /usr/shlib/:
             (ladebug) listobj
      
      For an alternative method when the debugger cannot be run on the original system, see the corefile_listobj.c example.
    10. Debug as usual:
             (ladebug)
      

    16.4 Core File Debugging Example

    The following is a complete example, from core creation, through transporting and core file debugging:
    1. Create the core file:
             % a.out -segv
              Segmentation fault (core dumped)
      
    2. Determine the shared objects using the debugger on the original system:
             % ladebug a.out core
              Welcome to the Ladebug Debugger Version n
              ------------------
              object file name: a.out
              core file name: core
              Reading symbolic information ...done
              Core file produced from executable a.out
              Thread 0x5 terminated at PC 0x3ff8058b448 by signal SEGV
              (ladebug) listobj
                  section         Start Addr           End Addr
              ------------------------------------------------------------------------------
              a.out
                   .text        0x120000000        0x120003fff
                   .data        0x140000000        0x140001fff
      
              /usr/shlib/libpthread.so
                   .text      0x3ff80550000      0x3ff8058bfff
                   .data      0x3ffc0180000      0x3ffc018ffff
                   .bss       0x3ffc0190000      0x3ffc01901af
      
              /usr/shlib/libmach.so
                   .text      0x3ff80530000      0x3ff8053ffff
                   .data      0x3ffc0170000      0x3ffc0173fff
      
              /usr/shlib/libexc.so
                   .text      0x3ff807b0000      0x3ff807b5fff
                   .data      0x3ffc0210000      0x3ffc0211fff
      
              /usr/shlib/libc.so
                   .text      0x3ff80080000      0x3ff8019ffff
                   .data      0x3ffc0080000      0x3ffc0093fff
                   .bss       0x3ffc0094000      0x3ffc00a040f
      
              (ladebug) quit
      
    3. Cut, paste, and edit the result into a list of file names. Note that libpthread.so is included, so add /usr/shlib/libpthreaddebug.so to the list.
    4. Create a tar file:
             % tar cfv mybug.tar a.out core \
                      /usr/shlib/libpthread.so /usr/shlib/libmach.so \
                      /usr/shlib/libexc.so /usr/shlib/libc.so \
                      /usr/shlib/libpthreaddebug.so
              a a.out 128 Blocks
              a core 2128 Blocks
              a /usr/shlib/libpthread.so 928 Blocks
              a /usr/shlib/libmach.so 208 Blocks
              a /usr/shlib/libexc.so 96 Blocks
              a /usr/shlib/libc.so symbolic link to ../../shlib/libc.so
              a /usr/shlib/libpthreaddebug.so 592 Blocks
      
      Note that libc.so is a symbolic link. Therefore, use the tar h option to force tar to follow symbolic links as if they were normal files or directories:
             % tar hcfv mybug.tar a.out core \
                      /usr/shlib/libpthread.so /usr/shlib/libmach.so \
                      /usr/shlib/libexc.so /usr/shlib/libc.so \
                      /usr/shlib/libpthreaddebug.so
              a a.out 128 Blocks
              a core 2128 Blocks
              a /usr/shlib/libpthread.so 928 Blocks
              a /usr/shlib/libmach.so 208 Blocks
              a /usr/shlib/libexc.so 96 Blocks
              a /usr/shlib/libc.so 3193 Blocks
              a /usr/shlib/libpthreaddebug.so 592 Blocks
      

      Now you have a package that you can transport.

    5. On the current system, create a directory for debugging, move to that directory, and get the package:
              % mkdir mybug
      	% cd mybug
      	% mv <wherever>/mybug.tar .
      
    6. Create the necessary subdirectories and unpackage the tar file using the s option:
              % mkdir applibs dbglibs
              % tar xfvs mybug.tar
              blocksize = 256
              x a.out, 65536 bytes, 128 tape blocks
              x core, 1089536 bytes, 2128 tape blocks
              x usr/shlib/libpthread.so, 475136 bytes, 928 tape blocks
              x usr/shlib/libmach.so, 106496 bytes, 208 tape blocks
              x usr/shlib/libexc.so, 49152 bytes, 96 tape blocks
              x usr/shlib/libc.so, 1634400 bytes, 3193 tape blocks
              x usr/shlib/libpthreaddebug.so, 303104 bytes, 592 tape blocks
      
    7. Move the original shared objects into applibs, and make libpthreaddebug.so exist in the dbglibs directory, for example, by linking it to the file in the applibs directory:
              % mv usr/shlib/* applibs
              % ln -s ../applibs/libpthreaddebug.so dbglibs/libpthreaddebug.so
      
      In this example, all shared objects were in usr/shlib/, so no other moving is needed.
    8. Observe the file system:
      
              % ls -lR
              total 4904
              -rwxr-xr-x   1 user1 ladebug    65536 Sep 17 11:20 a.out*
              drwxrwxr-x   2 user1 ladebug     8192 Sep 17 11:36 applibs/
              -rw-------   1 user1 ladebug  1089536 Sep 17 11:21 core
              drwxrwxr-x   2 user1 ladebug     8192 Sep 17 11:24 dbglibs/
              -rw-rw-r--   1 user1 ladebug  3737600 Sep 17 11:23 mybug.tar
              drwxrwxr-x   3 user1 ladebug     8192 Sep 17 11:36 usr/
      
              ./applibs:
              total 2632
              -rw-r--r--   1 user1 ladebug  1634400 Dec  7  1998 libc.so
              -rw-r--r--   1 user1 ladebug    49152 Jun 26  1998 libexc.so
              -rw-r--r--   1 user1 ladebug   106496 Dec 29  1997 libmach.so
              -rw-r--r--   1 user1 ladebug   475136 Dec  7  1998 libpthread.so
              -rw-r--r--   1 user1 ladebug   303104 Dec  7  1998 libpthreaddebug.so
      
              ./dbglibs:
              total 0
              lrwxrwxrwx   1 user1 ladebug       29 Sep 17 11:24 libpthreaddebug.so@ -> ../applibs/libpthreaddebug.so
      
              ./usr:
              total 8
              drwxrwxr-x   2 user1 ladebug     8192 Sep 17 11:36 shlib/
      
              ./usr/shlib:
              total 0
              %
      
      If other files need to be moved into applibs, do that as well and then re-observe the file system. In this example, there are none.

    9. Now set the environment variables as indicated:
             % env LADEBUG_COREFILE_LIBRARY_PATH=applibs \
              LD_LIBRARY_PATH=dbglibs \
              ladebug a.out core
              Welcome to the Ladebug Debugger Version n
              ------------------
              object file name: a.out
              core file name: core
              Reading symbolic information ...done
              Core file produced from executable a.out
              Thread 0x5 terminated at PC 0x3ff8058b448 by signal SEGV
      
    10. Issue the listobj command to ensure the application libraries are coming from applibs/. Find any that are not, either from the original system, or unpacked from the tar file but not yet moved into applibs.
             (ladebug) listobj
                  section         Start Addr           End Addr
              ------------------------------------------------------------------------------
              a.out
                   .text        0x120000000        0x120003fff
                   .data        0x140000000        0x140001fff
      
              applibs/libpthread.so
                   .text      0x3ff80550000      0x3ff8058bfff
                   .data      0x3ffc0180000      0x3ffc018ffff
                   .bss       0x3ffc0190000      0x3ffc01901af
      
              applibs/libmach.so
                   .text      0x3ff80530000      0x3ff8053ffff
                   .data      0x3ffc0170000      0x3ffc0173fff
      
              applibs/libexc.so
                   .text      0x3ff807b0000      0x3ff807b5fff
                   .data      0x3ffc0210000      0x3ffc0211fff
      
              applibs/libc.so
                   .text      0x3ff80080000      0x3ff8019ffff
                   .data      0x3ffc0080000      0x3ffc0093fff
                   .bss       0x3ffc0094000      0x3ffc00a040f
      
    11. Now debug as usual:
             (ladebug) where
              >0  0x3ff8058b448 in nxm_thread_kill(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libpthread.so
              #1  0x3ff80578c58 in pthread_kill(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libpthread.so
              #2  0x3ff8056cd34 in UnknownProcedure3FromFile69(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libpthread.so
              #3  0x3ff807b22d8 in UnknownProcedure4FromFile1(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libexc.so
              #4  0x3ff807b3824 in UnknownProcedure17FromFile1(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libexc.so
              #5  0x3ff807b3864 in exc_unwind(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libexc.so
              #6  0x3ff807b3af0 in exc_raise_signal_exception(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libexc.so
              #7  0x3ff8057a328 in UnknownProcedure6FromFile80(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libpthread.so
              #8  0x3ff800d6a30 in __sigtramp(0x140091c68, 0xb, 0x1, 0x0, 0x0, 0xfffffffffffffcc0) in applibs/libc.so
              #9  0x120001d94 in mandel_val(cr=0.01, ci=0.16, nmin=0, nmax=255) "mb_pi.c":62
              #10 0x12000274c in smp_fill_in_data(raw_mthread=0x11fffe998) "mb_pi.c":338
              #11 0x3ff80582068 in thdBase(0x0, 0x2, 0x0, 0x0, 0xff, 0x1) in applibs/libpthread.so
              (ladebug) quit
              %
      

    16.5 Quick Reference for Transporting a Core File

    This section contains a quick reference for transporting a core file.

    First, do the following steps on the original system:

    1. % ladebug a.out core

    2. (ladebug) listobj; quit
    3. Cut, paste, and edit into list of file names.
    4. Add /usr/shlib/libpthreaddebug.so, if libpthread.so
    5. .
    6. % tar cfvh mybug.tar a.out core <shlibs>
    Next, do the following steps on the current system:
    1. % mkdir mybug
    2. % cd mybug
    3. % mv mybug.tar
    4. % mkdir applibs dbglibs
    5. % tar sfvc mybug.tar
    6. % mv usr/shlib/* applibs
    7. % ln -s ../applibs/libptheaddebug.so dbglib/libptheaddebug.so

    8. The ../applibs is not a typo. Think of it as:
      % cd dbglibs
      % ln -s ../applibs/libpthreaddebug.so libpthreaddebug.so
      % cd ..
    9. % env LADEBUG_COREFILE_LIBRARY_PATH=applibs \
      LD_LIBRARY_PATH=dbglibs \
      ladebug a.out core
    10. (ladebug) listobj
    11. (ladebug)

    Chapter 17—Kernel Debugging

    This chapter discusses kernel debugging and contains information for each type of kernel debugging that you may use.

    This chapter contains the following sections:

    17.1 Overview of Kernel Debugging

    Local kernel debugging is useful for examining the state of the running kernel or any of its modules or components. If a process is hung, a system administrator might want to debug the kernel to find out what the process is caught on. The debugger has no ability to stop a local kernel, because that will stop the debugger, too.

    When a local kernel crashes, systems personnel typically want to know why. The kernel has been designed to save a copy of its memory state to a core file just before crashing. A copy of the kernel that crashed is also saved. These two files can be loaded into the debugger, and the state of the kernel just prior to the crash can be examined, to determine what went wrong.

    Remote kernel debugging is useful for systems engineers who are building and testing kernels and who need to have more control over the kernel. Breakpoints can be set in a kernel that is debugged remotely, which allow it to be stopped and examined more closely. Remote kernel debugging requires at least two machines, with the debugger running on one and the kernel to be tested on the other.

    17.1.1 Security

    The kernel is typically owned by root, so you may need to be the superuser (root login) to examine either the running system or crash dumps. Whether or not you need to be the superuser to debug a kernel directly depends on the directory and file protections of the files you attempt to examine.

    17.1.2 Compiling a Kernel for Debugging

    Ideally, the kernel should be compiled without full optimization and without stripping the kernel of its symbol table information, so that the debugger can provide you with the most information in the most friendly manner. However, most of the time this is not the case, and you are working with a stripped-down, highly optimized kernel. In these cases, the debugger is limited in what it can display. Information relating to source files is not available, and often function parameters and other variables are "optimized away."

    17.1.3 Special Features for Kernel Debugging

    The kernel is a complex piece of software. It contains kernel processes denoted by a process ID (pid). Some of these processes relate to user processes, and some are kernel specific.

    NOTE: Because the debugger supports multiprocessing as well as kernel debugging, you need to be able to distinguish between processes that the debugger is managing, and processes being managed within the kernel.

    Because the debugger command for managing multiple processes is process, this chapter refers to a process being debugged as a process, and refers to a process within the kernel being debugged as a pid.

    The debugger maintains two extra debugger variables when debugging a kernel: $pid and $tid. These variables assist you in establishing and changing the user context while debugging the kernel.

    The $pid variable contains the current pid that you are examining. You can switch the context to another pid within the kernel by setting $pid to the desired value. The debugger variable $curprocess, which is read-only, does not change. The value in the $curprocess variable is how the debugger refers to the kernel process as a whole. Typically, this value is the actual kernel process listed as [kernel idle] with the ps system command (or Ladebug kps command), but not always. In any case, the $pid variable controls the pid that you are examining within the kernel.

    The $tid variable contains the current thread ID that you are examining. It, too, can be used to switch the user context to a different thread (it simply calls the thread command with its new value).

    The debugger also supplies a kps command, which displays all the pids in the kernel. This command is not available for remote kernel debugging.

    
    kernel_debugging_command
            : kps
    
    For example, if you wanted to examine the stack of the kloadsrv daemon, you would first find out its pid:
    
        (ladebug) kps
        00000   kernel idle
        00001   init
        00003   kloadsrv
        00020   update
        02082   dtexec
        02092   dtterm
        02093   csh
        ...
    

    Then set the $pid accordingly and enter the where command:

        (ladebug) set $pid = 3
        (ladebug) where
        >0  0xfffffc00002b3a10 in thread_block()
    

    17.1.4 Patching a Disk File

    From within the debugger, you can use the patch command to correct bad data or instructions in an executable disk file. You can patch the text, initialized data, or read-only data areas. You cannot patch the bss segment because it does not exist in disk files. For example:

        (ladebug) patch @foo = 20
    

    17.1.5 KSEG Addresses

    You can specify addresses in the KSEG segment by prefixing the hexadecimal offset of the address with 0k; the debugger adds the KSEG base address to any such hexadecimal constant. For example, the constant 0k2400 is converted by the debugger into the actual address for the location at offset 0x2400 into the KSEG segment.

    17.1.6 Accessing libdpi as a Shared Object

    Tru64 UNIX provides libdpi (Debugger Process Interface library) for interacting with the kernel. The archive form (libdpi.a) is built into the debugger so kernel developers can debug the Tru64 UNIX kernel.

    However, kernel developers can also access libdpi as an external shared object. This is useful for the following tasks:

    If you need to use a libdpi that is different from the one linked into the debugger, contact Ladebug engineering for instructions on how to create an appropriate shared object version and how to use it.

    17.2 Local Kernel Debugging

    When you have a problem with a process, you can debug the running kernel or examine the values assigned to system parameters. (It is generally recommended that you avoid modifying the value of the parameters, which can cause problems with the kernel.)

    Invoke the debugger with the following command:

    	# ladebug -k /vmunix /dev/mem
    

    The -k flag maps virtual to physical addresses to enable local kernel debugging. The /vmunix and /dev/mem parameters cause the debugger to operate on the running kernel (the /dev/mem parameter is optional when debugging the live kernel, the debugger knows to look there for the kernel address space).

    Now you can use debugger commands to display information such as the current list of pids (kps), and trace the execution of processes. Note that the debugger motion commands such as cont, next, rerun, run, step, return, and stop are not available, nor can you change values in registers when you do local kernel debugging (stopping the kernel would also stop the debugger).

    17.3 Crash Dump Analysis

    If your system panics or crashes, you can often find the cause by using the debugger to analyze a crash dump. Keep in mind that the debugger is only one useful tool for determining the cause of a crash. Other tools and techniques are available to system personnel to aid in analyzing crash dumps. Some of them are mentioned briefly here.

    NOTE: You cannot perform crash dump analysis remotely with this debugger.

    17.3.1 Crash Dumps

    The operating system can crash in the following ways:

    If the system crashes because of a hardware fault or an unrecoverable software state, a dump function is invoked. The dump function copies the core memory into the primary default swap disk area as specified by the /etc/fstab file structure table and the /sbin/swapdefault file. At system reboot time, the information is copied into a file, called a crash dump file. Crash dump files are either partial (the default) or full. See Compaq TRU64 UNIX Kernel Debugging for more information.

    You can analyze the crash dump file to determine what caused the crash. For example, if a hardware trap occurred, you can examine variables, such as savedefp, the program counter ($pc), and the stack pointer ($sp), to help you determine why the crash occurred. If a software panic caused the crash, you can use the debugger to examine the crash dump and use the uerf utility to examine the error log. Using these tools, you can determine which function called the panic() routine.

    17.3.2 Guidelines for Examining Crash Dumps

    When you examine crash dump files, there is no one way to determine the cause of a system crash. However, the following guidelines can help you identify the events that led to the crash:

    For more information and for examples, see Compaq TRU64 UNIX Kernel Debugging. This manual contains detailed information on the following topics related to crash dump analysis:

    17.3.3 Analyzing a Crash Dump

    You can find Compaq Tru64 UNIX crash dump files in /var/adm/crash. There you will find a copy of the kernel that crashed (vmunix.number) and the core memory file (vmcore.number or vmzcore.number, depending on the operating system version). The number appended to these files distinguishes crashes, with the highest number denoting the most recent crash. These files are owned by root, so you must have root permissions to access them.

    To invoke the debugger on a kernel crash dump numbered 0 (zero), enter the following command:

    	# ladebug -k vmunix.0 vmzcore.0
    

    On startup, the debugger analyzes the core file to determine the final PC address of the crash, and outputs that information. You can use the debugger to inspect kernel data structures, global variables (such as the panic string), and kernel thread stacks, in order to determine why the kernel crashed.

    If you are going to view the stack using the where, up, down, and dump commands, you may want to set the control variable $stackargs to 0 (zero) to suppress the output of argument values, The kernel is typically compiled for high performance, which means those argument values have been optimized away. If the debugger is set to look for those arguments and cannot find them, it notifies you with error messages, causing the stack output to be full of repetitious warnings.

    When debugging a kernel memory fault, verify that the core memory has not been corrupted; otherwise, the debugger may present erroneous information. One quick way to check this is by comparing the global panic string with the panic string in the machine_slot structure of the machine that caused the crash. Select the appropriate machine_slot structure name depending on your operating system version, as follows:

    If the strings are different, the core memory file may be corrupted. The following example shows how to compare these strings:

    	# ladebug -k vmunix.0 vmzcore.0
    	Welcome to the Ladebug Debugger Version n 
    	------------------ 
    	object file name: vmunix.0 
    	core file name: vmzcore.0
    	Reading symbolic information ...done
    	Thread terminated at PC 0xfffffc0000457a48
    	done
    	(ladebug) print panicstr
    	0xfffffc0000640970="kernel memory fault"		    <== memory fault
    	(ladebug) print utsname
    	struct utsname {
      	  sysname = "OSF1";
      	  nodename = "";
      	  release = "X5.1";					    <== 5.n system
      	  version = "730";
      	  machine = "alpha";
    	}
    	(ladebug) print processor_ptr[paniccpu].m
    	struct machine_slot {
      	  is_cpu = 1;
      	  cpu_type = 15;
      	  cpu_subtype = 22;
      	  running = 1;
      	  cpu_ticks = [0] = 0,[1] = 0,[2] = 0,[3] = 0,[4] = 0;
      	  clock_freq = 1200;
      	  error_restart = 0;
      	  cpu_panicstr = 0xfffffc0000640970="kernel memory fault";  <== strings match
      	  cpu_panic_thread = 0xfffffc0001c51180;
    	}
    

    When you debug your code by working with a crash dump file, you can examine the exception frame using the debugger. The variable savedefp contains the location of the exception frame. (No exception frames are created when you force a system to dump.) Refer to the header file /usr/include/machine/reg.h to determine where registers are stored in the exception frame. The following example shows an exception frame:

        (ladebug) print savedefp/33X
    
        ffffffff9618d940:   0000000000000000 fffffc000046f888
        ffffffff9618d950:   ffffffff86329ed0 0000000079cd612f
        .
        .
        .
        ffffffff9618da30:   0000000000901402 0000000000001001
        ffffffff9618da40:   0000000000002000
    

    You can use the debugger to extract the preserved message buffer from a running system or use dump files to display system messages logged by the kernel. For example:

        (ladebug) print *pmsgbuf
        struct msgbuf {
        msg_magic = 405601;
        msg_bufx = 1851;
        msg_bufr = 1343;
        msg_bufc = "Alpha boot: available memory from 0x6ca000 to 0x3f16000\nTru64 UNIX V.n  (Rev. 564); Fri Jul 11 11:25:29 EDT 1997 \nphysical m";
        }
    

    The print command is regulated in length by the $maxstrlen debugger variable. Also, the print command does not expand the new line character. To see the full message string as formatted text, use the following command:

        (ladebug) printf "%s",pmsgbuf->msg_bufc
    

    17.3.4 Other Crash Dump Tools

    The crashdc utility collects critical data from operating system crash dump files or from a running kernel. You can use the data it collects to analyze the cause of a system crash. The crashdc utility uses existing system tools and utilities to extract information from crash dumps. The information garnered from crash dump files or from the running kernel includes the hardware and software configuration, current processes, the panic string (if any), and swap information.

    See Compaq TRU64 UNIX Kernel Debugging and crashdc(8) for more information.

    17.4 Remote Kernel Debugging

    For remote kernel debugging, use the Ladebug debugger in conjunction with the kdebug debugger, which is a tool for executing, testing, and debugging test kernels.

    Used alone, kdebug has its own syntax and commands, and allows local non-symbolic debugging of a running kernel across a serial line. See kdebug(8) for information about kdebug local kernel debugging.

    You use Ladebug commands to start and stop kernel execution, examine variable and register values, and perform other debugging tasks, just as you would when debugging user-space programs. The kdebug debugger, not the Ladebug debugger, performs the actual reads and writes to registers, memory, and the image itself (for example, when breakpoints are set).

    17.4.1 Connections Needed

    The kernel code to be debugged runs on a test system. The Ladebug debugger runs on a remote build system and communicates with the kernel code over a serial communication line or through a gateway system.

    You use a gateway system when you cannot physically connect the test and build systems. Connect the build system to the gateway system over a network. Connect the gateway system to the test system by a serial communication line.

    The following diagram shows the physical connection of the test and build systems (with no gateway):

       Build system              Serial line           Test system
       (with the Ladebug <------------------------->  (kernel code here)
        debugger)
    
    The following diagram shows the connections when you use a gateway system:
       Build system          Network     Gateway   Serial line    Test system
       (with the Ladebug  <----------->  system  <------------->  (kernel code
        debugger)                        with                      here)
                                         kdebug
                                         daemon
    

    The serial line provides a physical connection between communication ports on two systems; it consists of a BC16E cable and two H8571-J DECconnect Passive Adapters:

    The test system always uses the same communication port for kdebug debugger input and output:

    The build or gateway system, whichever is at the other end of the serial line from the test system, uses /etc/remote to specify the device to use for kdebug debugger input and output. Serial communication ports 1 and 2 correspond to device names /dev/tty00 and /dev/tty01, respectively:

    The following line in /etc/remote defines /dev/tty00 as the device to use for kdebug debugger input and output:

            kdebug:dv=/dev/tty00:br#9600:pa=none:
    

    For AlphaStation and AlphaServer systems, it is possible to change this definition to /dev/tty01 so the same serial port can be used for remote kernel debugging whether the system is used as a build, gateway, or test system:

            kdebug:dv=/dev/tty01:br#9600:pa=none:
    

    The first field, kdebug, is a label and has no significance except as an identifier, and "kdebug" is the default name for the serial line used by the debugger for kdebug debugger input and output.

    Using a Second Serial Line for Test System Console Emulation

    For AlphaStation and AlphaServer systems, it is also possible to redirect the test system console input and output to the build or gateway system at the other end of the serial line. This requires a second serial line connected between the communications ports of the build or gateway system and the test system that are not used for kdebug debugger input and output.

    To configure a second serial line, follow these steps:
    1. When the line has been connected, enter console mode on the test system by shutting it down; console mode is recognizable by the >>> prompt. At the prompt, enter the following command:
         >>> set console serial
      

      This redirects all console input and output to serial communication port 1 (/dev/tty00).

    2. On the build or gateway system, modify the /etc/remote file to define this second line. For example, in order to change the serial line used for kdebug debugger input and output to /dev/tty01 and create a useful label for /dev/tty00 to use for the test system console input and output, replace the original definition for kdebug in /etc/remote on the build or gateway system with the following:
           kdebug:dv=/dev/tty01:br#9600:pa=none:
           tstsys:dv=/dev/tty00:br#9600:pa=none:
      

    3. On the build or gateway system (in a window separate from the debugger window if on the build system), enter the following command:
         % tip tstsys
      

      You can use this separate window as the console for the test system.

    4. When finished, return to the console mode on the test system and enter the following command in the separate console window on the build or gateway system:
         >>> set console graphics
      

    5. Exit out of tip on the build or gateway system by entering a tilde and a period (˜.).

    17.4.2 System Requirements

    The test, build, and (if used) gateway systems must meet the following requirements for kdebug:

    You can verify the status of each of the system requirements by the using the following commands:

    17.4.3 Getting Ready to Use the kdebug Debugger

    To use the kdebug debugger, do the following:

    1. Attach the test system and the build system or the test system and the gateway system. See your hardware documentation for information about connecting systems to serial lines and networks.

    2. Configure the kernel to be debugged with the configuration file option OPTIONS KDEBUG. If you are debugging the installed kernel, you can do this by choosing KERNEL BREAKPOINT DEBUGGING from the Kernel Options menu.

    3. Recompile kernel files, if necessary. By default, the kernel is compiled with only partial debugging information, occasionally causing the debugger to display erroneous arguments or mismatched source lines. To correct this, recompile selected source files specifying the CDEBUGOPTS=-g argument.

    4. Copy the kernel to be tested to /vmunix on the test system. Retain an exact copy of this image on the build system.

    5. Install the Product Authorization Key (PAK) for the Developers' kit (OSF-DEV) if it is not already installed. For information about installing PAKs, see the Compaq Tru64 UNIX Software License Management manual.

    6. Determine the debugger variable settings or command-line options you will use. On the build system, add the following lines to your .dbxinit file if you need to override the default values (and you choose not to use the corresponding options). Alternatively, you can use the following lines within the debugger session, at the (ladebug) prompt:

            (ladebug) set $kdebug_host="<name_of_your_gateway_system>"
            (ladebug) set $kdebug_line="<name_of_your_serial_line>"
            (ladebug) set $kdebug_dbgtty="<name_of_your_tty>"
      
      • $kdebug_host specifies the node or address of the gateway system. By default, $kdebug_host is set to localhost when a gateway system is not used. For example:

      •       (ladebug) set $kdebug_host="decosf"
        
      • $kdebug_line specifies the serial line to use as defined in the /etc/remote file of the build system (or the gateway system, if one is being used). By default, $kdebug_line is set to kdebug. For example:

      •       (ladebug) set $kdebug_line="kdebug"
        
      • $kdebug_dbgtty sets the terminal on the gateway system to display the communication between the build and test systems, which is useful in debugging your setup. To determine the terminal name to supply to the $kdebug_dbgtty variable, enter the tty command in the desired window on the gateway system. By default, $kdebug_dbgtty is null. For example:

      •       (ladebug) set $kdebug_dbgtty="/dev/ttyp2"
        

      Instead of using debugger variables, you can specify any of the following options on the ladebug command line:

      • The -rn option specifies the node or address of the gateway system, and can be used instead of $kdebug_host.

      • The -line option specifies the serial line, and can be used instead of $kdebug_line.

      • The -tty option specifies the terminal name, and can be used instead of $kdebug_dbgtty.

      The preceding three options require the -remote option or its alternative, the -rp kdebug option, for example:

      # ladebug -remote -rn "decosf" -line "kdebug" -tty "/dev/ttyp2" /usr/test/vmunix
      
      The -rn, -line, and -tty options on this command line produce the same result as the preceding set command examples. This example assumes a copy of the test system's vmunix is in /usr/test on the build system.

      The variables you set in your .dbxinit file override any options you use on the ladebug command line. In your debugging session, you can still override the .dbxinit variable settings by using the set command at the (ladebug) prompt, prior to issuing the run command.

    7. If you are debugging on a symmetric multiprocessing (SMP) system , set the lockmode system attribute to 4, as shown:

         # sysconfig -r lockmode = 4
      

    8. Setting this system attribute makes debugging on an SMP system easier.

    17.4.4 Invoking the Debugger

    When the setup is complete, start the debugger as follows:

    1. Invoke the Ladebug debugger on the build system, supplying the pathname of the copy of the test kernel that resides on the build system. Set a breakpoint and start running the Ladebug debugger as follows (assuming that vmunix resides in the /usr/test directory):

         # ladebug -remote /usr/test/vmunix
          ...
          (ladebug) stop in panic
          [2] stop in panic
          (ladebug) stop in ttyretype
          [3] stop in ttyretype
       

      Because you cannot use Ctrl/C as an interrupt, set at least one breakpoint if you want the debugger to gain control of kernel execution. You can set a breakpoint any time after the execution of the kdebug_bootstrap() routine. Setting a breakpoint prior to the execution of this routine can result in unpredictable behavior. Setting a breakpoint in panic enables regaining control after a panic, and setting a breakpoint in ttyretype enables returning control to the debugger whenever Ctrl/R is entered at the console.

      NOTE: Pressing Ctrl/C causes the remote debugger to exit, not to interrupt as it does during local debugging.

    2. Halt the test system:

         # shutdown -h now
      

    3. At the console prompt, set the boot_osflags console variable to contain the value k (the default is usually the value a). For example:

         >>> set boot_osflags k
      

      Alternatively, you can enter the following command:

         >>> boot -flags k
      

      You can abbreviate the boot command to b and the -flags option to -fl. The boot command without the -flags option boots the machine using the current value for boot_osflags; with the -flags option, it uses the value specified in the option and does not change the value of the boot_osflags console variable. Other useful commands from the console prompt include show, which lists the values of console variables, and help, which provides information about other commands. For more information about the boot_osflags values, see the Compaq Tru64 UNIX System Administration manual and the Compaq Tru64 UNIX Installation Guide.

    4. With the Ladebug debugger started and waiting at a (ladebug) prompt with breakpoints already set and the test system waiting at the console prompt (>>>), start both the Ladebug debugger and test system kernel executing. You can start them in either order as follows:

      • Start the Ladebug debugger:

           (ladebug) run
        

      • Start the test system:

           >>> boot
        
        or
           >>> boot -flags k
        

    17.4.5 Breakpoint Behavior on SMP Systems

    If you set breakpoints in code that is executed on an SMP system, the breakpoints are handled serially. When a breakpoint is encountered on a particular CPU, the state of all the other processors in the system is saved and those processors spin, similar to how execution stops when a simple lock is obtained on a particular CPU.

    When the breakpoint is dismissed (for example, because you entered a step or cont command to the debugger), processing resumes on all processors.

    17.4.6 Troubleshooting Tips

    If you have completed the kdebug setup and it fails to work, read this section for help:

    Chapter 18—Machine-Level Debugging

    The debugger lets you debug your programs at the machine-code level as well as at the source-code level. Using debugger commands, you can examine and edit values in memory, print the values of all machine registers, and step through program execution one machine instruction at a time.

    Only those users familiar with machine-language programming and executable file code structure will find low-level debugging useful.

    This chapter contains the following sections:

    18.1 Examining Memory Addresses

    You can examine the value contained at an address in memory as follows:

    In addition to examining memory, you can also search memory in 32-bit and 64-bit chunks.

    18.1.1 Using the Examine Commands

    You can use the examine commands (/ and ?) to print the value contained at the address in one of a number of formats (decimal, octal, hexadecimal, and so on). See Memory Display Commands for more information.

    The debugger also maintains the $readtextfile debugger variable, which allows you to view the data from the text section of the executable directly from the binary file, rather than reading it from memory. You can use this variable to speed up the reading of instructions during kernel debugging, however, remember that you are reading from the file and not from the live image, which could be different.

    18.1.2 Using Pointer Arithmetic

    You can use C and C++ pointer-type conversions to display the contents of a single address in decimal. Using the print command, the syntax is as follows:
    	print *(int *)(address)
    
    Using the same pointer arithmetic, you can use the assign command to alter the contents of a single address. Use the following syntax:
    	assign *(int *)(address) = value
    
    The following example shows how to use pointer arithmetic to examine and change the contents of a single address:
           (ladebug) print *(int*)(0x10000000)
            4198916
           (ladebug) assign *(int*)(0x10000000) = 4194744
           (ladebug) print *(int*)(0x10000000)
            4194744
           (ladebug)
    

    18.1.3 Examining Machine-Level Registers

    The printregs command prints the values of all machine-level registers. The registers displayed by the debugger are machine dependent. The values are in decimal or hexadecimal, depending on the value of the $hexints variable (the default is 0, decimal). The register aliases are shown; for example, $r1 [$t0]. See the printregs command for more information.

    18.2 Stepping at the Machine Level

    The stepi and nexti commands let you step through program execution incrementally, like the step and next commands. The stepi and nexti commands execute one machine instruction at a time, as opposed to one line of source code. The following example shows stepping at the machine-instruction level:
           (ladebug) stop in main
            [#1: stop in main ]
            (ladebug) run
            [1] stopped at [main:4 0x120001180]
            4     for (i=1 ; i<3 ; i++) {
            (ladebug) stepi
            stopped at [main:4 0x120001184] stl     t0, 24(sp)
            (ladebug) [Return]
            stopped at [main:5 0x120001188] ldl     a0, 24(sp)
            (ladebug) [Return]
            stopped at [main:5 0x12000118c] ldq     t12, -32664(gp)
            (ladebug) [Return]
            stopped at [main:5 0x120001190] bsr     ra,
            (ladebug) [Return]
            stopped at [factorial:12 0x120001210]   ldah    gp, 8192(t12)
            (ladebug)
    
    At the machine-instruction level, you can step into, rather than over, a function's prologue. While within a function prologue, you may find that the stack trace, variable scope, and parameter list are not correct. Stepping out of the prologue and into the actual function updates the stack trace and variable information kept by the debugger.

    Single-stepping through function prologues that initialize large local variables is slow. As a workaround, use the next command.

    18.2.1 Load Locked Store Conditional Sequences

    Load locked store conditional sequences have special semantics. See the Alpha Architecture Reference Manual and the Alpha Architecture Handbook for more information.

    The debugger interaction with the target modifies the target state enough that the store conditional is guaranteed to fail. So that users can make progress, the debugger normally steps over the entire sequence as though it were one big instruction. This allows the application to continue normally.

    To debug inside the sequence, while understanding that this implies failure of the store, set a breakpoint inside the sequence and continue to the breakpoint. From there, you will be able to stepi or nexti.

    Chapter 19—Debugging Parallel Applications

    The Ladebug debugger Version 67 supports debugging of parallel applications on the Compaq Tru64 UNIX operating system. Earlier versions of Ladebug do not have this capability.

    Ladebug supports the following parallel launchers:

    This chapter contains the following sections:

    19.1 Overview

    The biggest challenge of debugging massively parallel applications is coping with large quantities of output from debuggers controlling the parallel application's processes. Ladebug helps you do this by condensing (aggregating) similar output into groups. Aggregation is performed by using the following two strategies:

    Another challenge of debugging massively parallel applications is controlling all processes or subsets of the parallel application's processes from the debugger in a consistent manner. The Ladebug debugger allows you to control all or a subset of your processes through a single user interface. At the startup of a parallel debugging session, Ladebug does the following:

    1. Detects the topology of your application and attaches a debugger to each of your application's processes.
    2. Builds an n-nary tree with the Ladebug debuggers as root and leaves with special processes called aggregators in the middle (shown in the following diagram). You can specify the tree's branching factor and the aggregator time delay.

    The root debugger is responsible for starting your parallel application and serves as your user interface. The aggregators perform output consolidation as described previously. The leaf debuggers control and query your application processes.

    The branching factor is the factor used to build the n-nary tree and determine the number of aggregators in the tree. For example, for 16 processes:

    You can set the value of the $parallel_branchingfactor variable from its default value of 8 to a value equal to or greater than 2 in the ladebug initialization file (.ladebugrc, and so on).

    When you delete $parallel_branchingfactor from the ladebug initialization file, the branching factor used in the startup mechanism is the default value.

    Aggregator delay specifies the time that aggregators wait before they aggregate and send messages down to the next level when not all of the expected messages have been received.

    You can change the value of the $parallel_aggregatordelay variable from its default value of 3000 milliseconds in the ladebug initialization file (.ladebugrc, etc.). See Parallel Debugging Tips for more information.

    When you delete $parallel_aggregatordelay from the ladebug initialization file, the aggregator delay used in the startup mechanism is the default value.

    NOTE: You can only change the values that are set for $parallel_branchingfactor and $parallel_aggregatordelay at startup, in the .ladebugrc file. After the program has started up, you cannot change these values.

    19.2 Starting a Parallel Debugging Session

    To start your parallel application under debugger control, issue the following commands at the shell (N represents number of processes): When the debugger starts your parallel application, it detects and attaches to all of your application's processes. At this point, your application stops before executing any user code and the debugger displays a prompt.

    You can now set any necessary breakpoints and use the continue command to continue the execution of your application.

    19.3 Using Ladebug Commands in a Parallel Debugging Session

    You can use most Ladebug commands just as you would when debugging a non-parallel application. Most commands are passed on to the leaf debuggers and you see aggregated output from them in your user interface. However, there are a few important exceptions.

    The following table shows debugger commands that can be accessed remotely, locally, and both remotely and locally for parallel debugging; and Ladebug commands that are disabled for parallel debugging.

    Remote
    Local
    Both Remote and
    Local
    Disabled
    #
    /
    ?
    assign
    call
    catch
    class
    cont/conti
    delete
    delsharedobj
    disable
    down
    dump
    enable
    examine_address
    file
    func
    goto
    history
    if
    ignore
    kill
    list
    listobj
    map/unmap source directory
    next/nexti
    pop
    print
    printb
    printd
    printf
    printi
    printo
    printregs
    printt
    printx
    process
    readsharedobj
    return
    show condition
    show mutex
    show process
    show source directory
    show thread
    status
    step/stepi
    stop/stopi
    thread
    trace/tracei
    use/unuse
    up
    watch
    whatis
    when/wheni
    where/whereis
    which
    !/history
    alias/unalias
    edit
    export
    help
    playback
    quit
    record/unrecord
    source
    export
    set/setenv
    sh
    unset/unsetenv
    attach/detach
    kps
    load/unload
    patch
    printenv
    rerun
    run
    snapshot

    Remote means commands will be sent to the leaf debuggers. Local means that commands are not sent to the leaf debuggers but are processed by the local Ladebug.

    In addition to the commands listed in the table, you can use four other Ladebug commands to assist parallel debugging:

    parallel_debugging_command
        :focus_command            
        |show_process_set_command 
        |show_aggregated_message_command 
        |expand_aggregated_message_command
    

    19.4 Working With Sets of Application Processes

    When there are many processes, it can be annoying or impractical to enumerate all the processes when one needs to focus on specific processes. Therefore, Ladebug introduces the concept of "process sets" and "process ranges" to let the user specify a group of processes in a compact form. Moreover, process sets come with the usual set operations, and both the sets and the ranges can be stored in debugger variables for manipulation, reference, or inspection at a later time.

    A process set is a bracketed list of process ranges separated by commas.

    NOTE: Because brackets ([..]) are part of the process set syntax, this section shows optional syntactic items enclosed in curly braces ({..}).

    process_set
    	: [ ]
    	| [ process_range {,...} ]
    
    NOTE: The set can be empty.

    A process range has the following three forms:

    process_range
    	: *
            | expression
            | { expression } : { expression }
    
    
    In the first form, the star (*) specifies all processes.

    You can use the second form as follows:

    You can use the third form to specify a contiguous range of processes. For example, 10:12 stands for the processes associated with pids 10, 11, and 12.

    NOTE: A range whose lower bound is greater than its upper bound is illegal and will be ignored.

    Because both the lower bound and the upper bound are optional, you can specify ranges as follows:

    Example
    Represents
    :5
    All processes whose pid is no greater than 5.
    20:
    All processes whose pid is no less than 20.

    NOTE: The process set [:] is equivalent to the process set [*].

    19.4.1 Using Debugger Variables to Store Process Sets and Ranges

    Like storing other data types supported by the debugger, you can store process sets and process ranges in debugger variables using the set command. For example:
    	(ladebug) set $set1 = [:7, 10, 15:20, 30:]
    	(ladebug) print $set1
    	[:7, 10, 15:20, 30:]
    

    In addition to using the print command, you can also use the show process set command to inspect the process set stored in a debugger variable. For example:

    show_process_set_command
              : show process set debugvar_name
              | show process set all 
    	  | show process set  
    

    If you do not specify the set name, or if you use the all specifier, the debugger displays all the process sets that are currently stored in debugger variables, as the continued example shows:

    	(ladebug) set $set2 = [8:9, 5:2, 22:27]
    	`5:2' is not a legal process range. Ignored.	
    	(ladebug) show process set $set2
    	$set2 = [8:9, 22:27]
    	(ladebug) show process set *
    	$set1 = [:7, 10, 15:20, 30:]
    	$set2 = [8:9, 22:27]
    

    19.4.2 Process Set Operations

    You can use the following three operations on process sets:

    Operation
    Represents
    Action
    +
    Set union
    Takes two sets S1 and S2 and returns a set whose elements are either in S1 or in S2.
    -
    Difference
    Takes two sets S1 and S2 and returns a set whose elements are in S1 but not in S2.
    unary -
    Negation
    Takes a single set S and returns the difference of [*] and S.

    The following example demonstrates these operations:

    	(ladebug) set $set1 = [:10, 15:18, 20:]
          	(ladebug) set $set2 = [10:16, 19]
         	(ladebug) set $set3 = $set1 + $set2
          	(ladebug) print $set3
          	[*]
          	(ladebug) print $set3 - $set2 
          	[:9, 17:18, 20:]
          	(ladebug) print -$set2
         	[:9, 17:18, 20:]
    

    19.4.3 Changing the Current Set with the focus Command

    You can use the focus command to change the current process set, which is the set of processes whose debuggers receive the remote command entered at the root debugger:

    focus_command
            : focus expression     
    	| focus all            
            | focus                
    

    The first form of the command sets the current process set to the set resulting from the evaluation of the given expression. The second form sets the current process set to the set that includes all processes. The third form displays the current process set.

    19.5 Working with Aggregated Messages

    As mentioned in the Overview, the root debugger collects the outputs from the leaf debuggers and presents you with an aggregated output. In most cases, this aggregation works fine, but it can be an impediment if you want to know the exact output from certain leaf debuggers.

    To remedy this, the debugger assigns a unique number (called a message_id) to each aggregated message and saves the message in the message_id_list. You can use the following commands to inspect the message list and expand its entries:

    show_aggregated_message_command 
             : show aggregated message message_id_list
             | show aggregated message all 
    	 | show aggregated message    
    
    message_id_list
    	: expression {,...}
    
    The first form of the command displays the aggregated messages in the list whose message IDs match the numbers specified in the message_id_list. The second form displays all the aggregated messages in the list. If no message_id is specified, the debugger shows the most recently added (newest) message.
    expand_aggregated_message_command
             : expand aggregated message  message_id_list 
             | expand aggregated message 
    
    This command expands the specified messages. If no message_id is specified, the debugger expands the most recently added (newest) message.

    You can control the length of the message list using the $aggregatedmsghistory debugger variable. If you set this variable to the default (0), the debugger records as many messages as the system will allow.

    19.6 Parallel Debugging Tips

    This section contains the following tips for debugging parallel applications: Tip 1. How to Aggregate Outputs

    If the debugger outputs are not aggregated as you would expect them to be, you can change the value of the $parallel_aggregatordelay debugger variable. The $parallel_aggregatordelay variable sets the expiration time for each of the aggregators when the aggregators have not received all the expected messages.

    In Aggregated Example 1, the value of $parallel_aggregatordelay is set to 100 milliseconds, which does not seem to be long enough for the debugging session's 32 processes. Changing the $parallel_aggregatordelay variable to 500 milliseconds results in the improved aggregation shown in Aggregated Example 2.

    NOTE: Because the default value of the $parallel_aggregatordelay is 3000 milliseconds, you should not normally have a problem with the aggregation delay. The purpose of these examples is to show the effect of changing the $parallel_aggregatordelay setting.

    Aggregated Example 1
    % ladebug -parallel /usr/bin/prun -n 32 ~/smg98/test/smg98
    Welcome to the Ladebug Debugger Version n
    Reading symbolic information ...done
    stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]	
    Source file not found or not readable, tried...
        ./loader.cc
        /usr/bin/loader.cc
    (Cannot find source file loader.cc)
    stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]	
    Source file not found or not readable, tried...
        ./loader.cc
        /usr/bin/loader.cc
    (Cannot find source file loader.cc)
    Process has exited
    (ladebug)    [8,13,16:31] Welcome to the Ladebug Debugger Version n
       [8,13,16:31] ------------------ 
       [8,13,16:31] object file name: /usr/users/user1/smg98/test/smg98 
       [8,13,16:31] Reading symbolic information ...   [8,13,16:31] done
    %1 [8,13,16:31] Attached to process id [14186471;16807748]  ....
       [8,13,16:31] Thread received signal TRAP
       [8,13,16:31] stopped at [ 0x3ff80006790]	
       [8,13,16:31] Thread received signal TRAP
       [8,13,16:31] stopped at [ 0x3ff80020328]	
       [8,13,16:31] [#1: stop quiet in int main(int, char**) ]
       [8,13,16:31]      66    int                 solver_id;
       [8,13,16:31]      67 
       [8,13,16:31] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [8,13,16:31]      69                      
       [8,13,16:31]      70    HYPRE_StructMatrix  A;
    
    (ladebug)    [0,2,4] Welcome to the Ladebug Debugger Version n
       [0] ------------------ 
       [0] object file name: /usr/users/user1/smg98/test/smg98 
       [0] Reading symbolic information ...   [0] done
       [0] Attached to process id 13138577  ....
       [0] Thread received signal TRAP
       [0] stopped at [ 0x3ff80006790]	
       [0] Thread received signal TRAP
       [1,3,6,15] Welcome to the Ladebug Debugger Version n
       [1:2,4,6] ------------------ 
       [1:2,4,6] object file name: /usr/users/user1/smg98/test/smg98 
       [2,4,6] Reading symbolic information ...   [2,4,6] done
    %2 [2,4,6] Attached to process id [13138579;13662398]  ....
       [2,4,6] Thread received signal TRAP
       [2,4,6] stopped at [ 0x3ff80006790]	
       [0] stopped at [ 0x3ff80020328]	
       [0] [#1: stop quiet in int main(int, char**) ]
       [0]      66    int                 solver_id;
       [0]      67 
       [0] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [0]      69                      
       [0]      70    HYPRE_StructMatrix  A;
    
    (ladebug)    [9:10] Welcome to the Ladebug Debugger Version n
       [3,10,15] ------------------ 
       [3,10,15] object file name: /usr/users/user1/smg98/test/smg98 
       [1,3,15] Reading symbolic information ...   [1,3,15] done
    %3 [1,3,15] Attached to process id [13138578;14710852]  ....
       [1,3,15] Thread received signal TRAP
       [1,3,15] stopped at [ 0x3ff80006790]	
       [1,3,6,15] Thread received signal TRAP
       [1,3,6,15] stopped at [ 0x3ff80020328]	
       [1,3,6,15] [#1: stop quiet in int main(int, char**) ]
       [1,3,6,15]      66    int                 solver_id;
       [1,3,6,15]      67 
       [1,3,6,15] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [1,3,6,15]      69                      
       [1,3,6,15]      70    HYPRE_StructMatrix  A;
    
    (ladebug)    [9] ------------------ 
       [9] object file name: /usr/users/user1/smg98/test/smg98 
       [9:10] Reading symbolic information ...   [9:10] done
    %4 [9:10] Attached to process id [14186472;14186473]  ....
       [9:10] Thread received signal TRAP
       [9:10] stopped at [ 0x3ff80006790]	
       [9:10] Thread received signal TRAP
       [9:10] stopped at [ 0x3ff80020328]	
       [10] [#1: stop quiet in int main(int, char**) ]
       [10]      66    int                 solver_id;
       [10]      67 
       [10] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [10]      69                      
       [10]      70    HYPRE_StructMatrix  A;
    
    (ladebug)    [9] [#1: stop quiet in int main(int, char**) ]
       [9]      66    int                 solver_id;
       [9]      67 
       [9] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [9]      69                      
       [9]      70    HYPRE_StructMatrix  A;
       [5,7,11:12,14] Welcome to the Ladebug Debugger Version n
       [5,7] ------------------ 
       [5,7] object file name: /usr/users/user1/smg98/test/smg98 
    
    (ladebug)    [11:12,14] ------------------ 
       [11:12,14] object file name: /usr/users/user1/smg98/test/smg98 
       [5,7,11:12,14] Reading symbolic information ...   [5,7,11:12,14] done
    %5 [5,7,11:12,14] Attached to process id [13662397;14710851]  ....
       [5,7,11:12,14] Thread received signal TRAP
       [5,7,11:12,14] stopped at [ 0x3ff80006790]	
       [5,7,11:12,14] Thread received signal TRAP
       [5,7,11:12,14] stopped at [ 0x3ff80020328]	
       [5,7,11:12,14] [#1: stop quiet in int main(int, char**) ]
       [5,7,11:12,14]      66    int                 solver_id;
       [5,7,11:12,14]      67 
       [5,7,11:12,14] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [5,7,11:12,14]      69                      
       [5,7,11:12,14]      70    HYPRE_StructMatrix  A;
    
    Aggregated Example 2
    % ladebug -parallel /usr/bin/prun -n 32 ~/smg98/test/smg98 
    Welcome to the Ladebug Debugger Version n
    Reading symbolic information ...done
    stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]	
    Source file not found or not readable, tried...
        ./loader.cc
        /usr/bin/loader.cc
    (Cannot find source file loader.cc)
    stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]	
    Source file not found or not readable, tried...
        ./loader.cc
        /usr/bin/loader.cc
    (Cannot find source file loader.cc)
    Process has exited
    (ladebug)    [0:31] Welcome to the Ladebug Debugger Version n
       [0:31] ------------------ 
       [0:31] object file name: /usr/users/user1/smg98/test/smg98 
       [0:31] Reading symbolic information ...   [0:31] done
    %1 [0:31] Attached to process id [13138610;16807808]  ....
       [0:31] Thread received signal TRAP
       [0:31] stopped at [ 0x3ff80006790]	
       [0:31] Thread received signal TRAP
       [0:31] stopped at [ 0x3ff80020328]	
       [0:31] [#1: stop quiet in int main(int, char**) ]
       [0:31]      66    int                 solver_id;
       [0:31]      67 
       [0:31] >    68    int                 A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
       [0:31]      69                      
       [0:31]      70    HYPRE_StructMatrix  A;
    
    (ladebug) next
    (ladebug)    [0:31] stopped at [int main(int, char**):110 0x120006dd8]	
       [0:31]     110    MPI_Init(&argc, &argv);
    
    The sample application used in the aggregated examples is located at: http://www.acl.lanl.gov/30TeraOpRFP/SampleApps/smg98/smg98.html

    Tip 2. How to Synchronize Processes

    If the processes become unsynchronized in the debugging session (for example, if you use the focus command on a subset of the total set and then use a next or some other motion command), the easiest way to get the processes back together is to use a cont to a future location where all processes have to go. The following example shows how the output from processes is not identical because different processes are at different locations in the program. Using the cont to command synchronizes the processes and aggregates the messages.

    (ladebug) next
    (ladebug)    [4:5,12] stopped at [int feedbackToDebugger(int, int, char*):17 0x120006bf4]
       [0:3,6:11] [3] stopped at [int feedbackToDebugger(int, int, char*):15 0x120006bf0]
       [4:5,12]      17   int pathSize = 1000;
       [0:3,6:11]      15   int i = 0;
    
    (ladebug) l
    (ladebug)    [0:3,6:11]      16   char path[1000];
       [4:5,12]      18   char hostname[1000];
       [0:3,6:11]      17   int pathSize = 1000;
       [4:5,12]      19   int hostnameSize = 1000;
       [0:3,6:11]      18   char hostname[1000];
       [4:5,12]      20   
       [0:3,6:11]      19   int hostnameSize = 1000;
       [4:5,12]      21   volatile int debuggerAttached = 0;
       [0:3,6:11]      20   
       [4:5,12]      22 
       [0:3,6:11]      21   volatile int debuggerAttached = 0;
       [4:5,12]      23   gethostname(hostname,hostnameSize);
    %3 [0:12]      [22;24] 
       [0:3,6:11]      23   gethostname(hostname,hostnameSize);
       [4:5,12]      25   getcwd(path,pathSize);
       [0:3,6:11]      24 
       [4:5,12]      26   strcat(path,"/"); 
       [0:3,6:11]      25   getcwd(path,pathSize);
       [4:5,12]      27   strcat(path,name); 
       [0:3,6:11]      26   strcat(path,"/"); 
       [4:5,12]      28 
       [0:3,6:11]      27   strcat(path,name); 
       [4:5,12]      29   // Print myid pid into ladebugAttach.myid
       [0:3,6:11]      28 
       [4:5,12]      30   sprintf(filename,"ladebugAttach.%d",myid); 
       [0:3,6:11]      29   // Print myid pid into ladebugAttach.myid
       [4:5,12]      31   file = fopen(filename,"w");
       [0:3,6:11]      30   sprintf(filename,"ladebugAttach.%d",myid); 
       [4:5,12]      32   if (file == NULL) {
       [0:3,6:11]      31   file = fopen(filename,"w");
       [4:5,12]      33     fprintf(stderr,"smg98: can't open %s for %s\n",filename, "w");
       [0:3,6:11]      32   if (file == NULL) {
       [4:5,12]      34     exit(1)
       [0:3,6:11]      33     fprintf(stderr,"smg98: can't open %s for %s\n",filename, "w");
       [4:5,12]      35   }
       [12]      36   fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path);
       [12]      37   fclose(file);
       [12]      38 
       [4:5]      36   fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path);
       [0:3,6:11]      34     exit(1);
       [0:3,6:11]      35   }
       [4:5]      37   fclose(file);
       [0:3,6:11]      36   fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path);
       [4:5]      38 
    
    (ladebug) cont to 36
       [0:13] stopped at [int feedbackToDebugger(int, int, char*):36 0x120006cb8]
       [0:13]      36   fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path);
    
    (ladebug) next
    (ladebug)    [0:13] stopped at [int feedbackToDebugger(int, int, char*):37 0x120006d0c]
       [0:13]      37   fclose(file);
    
    Tip 3. How to Use the -I Option in the Parallel Environment

    If the application source file is not in the same location as the application binary file, the debugger will display a message that it cannot find the application source file. Consider the following example:

    $ ladebug -parallel /bin/dmpirun -np 8 -hf ~/test/src/common/Funct/src/cpihostfile \
    ~/test/src/common/Funct/bin-alpha-osf1/cpi
    Welcome to the Ladebug Debugger Version n
    Reading symbolic information ...done
    stopped at [void MPIR_Breakpoint(void):43 0x120002fc0]
    Source file not found or not readable, tried...
        ./mpirun.c
        /bin/mpirun.c
    (Cannot find source file mpirun.c)
    Process has exited
    (ladebug) 
       [0:7] Welcome to the Ladebug Debugger Version n
       [0:7] ------------------ 
       [0:7] object file name: /usr/users/smith/ladebug-sandbox/test/src/common/Funct/bin-alpha-osf1/cpi 
       [0:7] Reading symbolic information ...   [0:7] done
       [0:7] Unable to switch to decthreads mode.
       [0:7] Source file not found or not readable, tried...
       [0:7]     ./cpi.c
       [0:7]     /usr/users/smith/ladebug-sandbox/test/src/common/Funct/bin-alpha-osf1/cpi.c
    

    Specifying the -I option before the -parallel option does not fix the problem because the -I option applies only to the root debugger. The root debugger only controls the launcher and will not look outside its location for the application source file. The -I option is not currently passed along to the leaf debuggers, which would resolve this problem.

    The following example shows how to cause the debugger to locate the application source file:

    (ladebug) use /usr/proj/debug/ladebug/test/src/common/Funct/src
       [0:7] Directory search path for source files:
       [0:7]  . /usr/users/smith/ladebug-sandbox/test/src/common/Funct/bin-alpha-sf1/usr/proj/debug/ladebug/test/src/common/Funct/src
    (ladebug) w
       [0:7]      20 
       [0:7]      21 double f(double);
       [0:7]      22 
       [0:7]      23 int main(int argc, char *argv[])
       [0:7]      24 {
       [0:7]      25     int done = 0, n, myid, numprocs, i;
       [0:7]      26     double PI25DT = 3.141592653589793238462643;
       [0:7]      27     double mypi, pi, h, sum, x;
       [0:7]      28     double startwtime = 0.0, endwtime;
       [0:7]      29     int  namelen;
    

    19.7 Parallel Debugging Example

    The following is an example of a parallel debugging session. Click on the links within the example for explanation.
    % ladebug -parallel /usr/bin/dmpirun -np 6 /usr/users/parallel/examples/cpi-DmpirunStop
    Welcome to the Ladebug Debugger Version n
    Reading symbolic information ...done
    stopped at [void MPIR_Breakpoint(void):43 0x120002fc0]
    Source file not found or not readable, tried...
        ./mpirun.c
        /usr/bin/mpirun.c
    (Cannot find source file mpirun.c)
    Process has exited
    (ladebug)    [0:5] Welcome to the Ladebug Debugger Version n
       [0:5] ------------------
       [0:5] object file name: /usr/users/parallel/examples/cpi-DmpirunStop
       [0:5] Reading symbolic information ...done
       [0:5]     52     int done = 0, n, myid, numprocs, i;
    (ladebug) stop in feedbackToDebugger
       [0:5] [#1: stop in int feedbackToDebugger(int, int, char*) ]
    (ladebug) focus [0:2]
    [0:2]>
    [0:2]> cont
    [0:2]>    [0:2] [1] stopped at [int feedbackToDebugger(int, int, char*):18 0x120001818]
       [0:2]      18   int i = 0;
    [0:2]> where
    [0:2]> %1 [0:2] >0  0x120001818 in feedbackToDebugger(myid=[0;2], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
       [0:2] #1  0x120001a48 in main(argc=1, argv=0x11fffc018) "cpi-user1.c":63
       [0:2] #2  0x120001758 in __start(...) in /usr/users/parallel/examples/cpi-DmpirunStop
    [0:2]> focus [3:5]
    [3:5]>
    [3:5]> cont
    [3:5]>    [3:5] [1] stopped at [int feedbackToDebugger(int, int, char*):18 0x120001818]
       [3:5]      18   int i = 0;
    [3:5]> where
    [3:5]> %2 [3:5] >0  0x120001818 in feedbackToDebugger(myid=[3;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
    [3:5] #1  0x120001a48 in main(argc=1, argv=0x11fffc018) "cpi-user1.c":63
    [3:5] #2  0x120001758 in __start(...) in /usr/users/parallel/examples/cpi-DmpirunStop
    [3:5]> focus [*]
    [0:5]>
    [0:5]> next
    [0:5]>    [0:5] stopped at [int feedbackToDebugger(int, int, char*):20 0x12000181c]
       [0:5]      20   int pathSize = 1000;
    [0:5]> where
    [0:5]> %4 [0:5] >0  0x12000181c in feedbackToDebugger(myid=[0;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
       [0:5] #1  0x120001a48 in main(argc=1, argv=0x11fffc018) "cpi-user1.c":63
       [0:5] #2  0x120001758 in __start(...) in /usr/users/parallel/examples/cpi-DmpirunStop
    [0:5]> show aggregated message
    %1 [0:2] >0  0x120001818 in feedbackToDebugger(myid=[0;2], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
    %2 [3:5] >0  0x120001818 in feedbackToDebugger(myid=[3;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
    %3 [0:5] >0  0x12000181c in feedbackToDebugger(myid=[0;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
    [0:5]> expand aggregated message 3
    %3 [0:5] >0  0x12000181c in feedbackToDebugger(myid=[0;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
     [0] >0  0x12000181c in feedbackToDebugger(myid=0, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
     [1] >0  0x12000181c in feedbackToDebugger(myid=1, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
     [2] >0  0x12000181c in feedbackToDebugger(myid=2, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
     [3] >0  0x12000181c in feedbackToDebugger(myid=3, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-S-BuildDmpirunStop") "cpi-user1.c":20
     [4] >0  0x12000181c in feedbackToDebugger(myid=4, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-S-BuildDmpirunStop") "cpi-user1.c":20
     [5] >0  0x12000181c in feedbackToDebugger(myid=5, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-S-BuildDmpirunStop") "cpi-user1.c":20
    [0:5]> quit
    
    The following are explanatory notes from the previous example:

    Component of Example
    Meaning
    -np 6
    This parallel session creates 6 processes.
    [0:5]
    This is a message from processes 0 to 5.
    %1
    This aggregated message contains messages with differing portions (in this case, the myid parameters are different from process to process), and 1 is the message id.
    focus [0:2]
    This focus command sets the current process set to include processes 0, 1, and 2.
    [0:2]>
    This prompt shows the current process set.
    show aggregated message
    This show aggregated message command displays all the aggregated messages saved in the message list.
    expand aggregated message 3
    This expand aggregated message command expands the aggregated message with message id 3.

    19.8 Using the mpirun_dbg.ladebug Startup File

    Use the following file, named mpirun_dbg.ladebug, to start up the debugger controlling your mpich processes:
    #!/bin/sh
    
    cmdLineArgs=""
    p4pgfile=""
    p4workdir=""
    prognamemain=""
    
    while [ 1 -le $# ] ; do
      arg=$1
      shift
      case $arg in
         -cmdlineargs)
            cmdLineArgs="$1"
            shift
    	;;
         -p4pg)
            p4pgfile="$1"
    	shift
    	;;
         -p4wd)
            p4workdir="$1"
    	shift
    	;;
         -progname)
            prognamemain="$1"
    	shift
    	;;
      esac   
    done
    #
    if [ -n "$LADEBUG_HOME" ] ; then
        ldbdir=$LADEBUG_HOME
    else
        ldbdir=""
    fi
    #
    if [ -f $ldbdir/ladebug.cat ] && [ -r $ldbdir/ladebug.cat ] ; then
      if [ -n "$NLSPATH" ];  then
         nlsmore=$NLSPATH
      else
         nlsmore=""
      fi
      NLSPATH=$ldbdir/$nlsmore
    fi
    #
    $ldbdir/ladebug -parallel $prognamemain `eval echo $cmdLineArgs` -p4pg $p4pgfile -p4wd $p4workdir -mpichtv
    

    Appendixes

    Appendix 1—Debugger Variables

    The debugger has the following predefined variables. Conventionally, a Ladebug debugger variable name is an identifier with a leading dollar sign ($).

    Variable
    Default Setting
    Description
    $aggregatedmsghistory
    0
    Controls the length of the aggregated message list. If set to the default (0), the debugger records as many messages as the system will allow.
    $ascii
    1
    Prints ASCII or all ISO Latin-1.
    $beep
    1
    Beeps on illegal command line editing.
    $catchexecs
    0
    Stops execution on program exec.
    $catchforkinfork
    0
    Notifies you as soon as the forked process is created (otherwise you are notified when the call finishes).
    $catchforks
    0
    Notifies you on program fork and stops child.
    $childprocess
    0
    When the debugger detects a fork, it assigns the child process ID to $childprocess.
    $curevent
    0
    Displays the current breakpoint number.
    $curfile
    (null)
    Displays the current source file.
    $curfilepath
    (null)
    Displays the current source file access path.
    $curline
    0
    Displays the current source line.
    $curpc
    0
    Displays the current point of program execution.
    $curprocess
    0
    Displays the current process ID.
    $cursrcline
    0
    Displays the last source line at end of the most recent source listing.
    $cursrcpc
    0
    Displays the PC address at end of the most recent machine code listing.
    $curthread
    0
    Displays the current thread ID.
    $dbxoutputformat
    0
    Displays various data structures in dbx format.
    $dbxuse
    0
    Replaces current use paths.
    $decints
    0
    Displays integers in decimal radix.
    $doverbosehelp
    1
    Displays the help menu front page.
    $editline
    1
    Enables command line editing.
    $eventecho
    1
    Echoes events with event numbers.
    $exitonterminationofprocesswithpid
    None
    If set to process ID (pid), when that process terminates, the debugger exits.
    $floatshrinking
    1
    If set to the default (1), the debugger prints binary floating point numbers using the shortest possible decimal number. If set to 0, the debugger prints the decimal number that is the closest representation in the number of decimal digits available of the internal binary number.
    $funcsig
    1
    Displays function signature at breakpoint.
    $giveladebughints
    1
    Displays hints on Ladebug features.
    $hasmeta
    0
    Interprets multibyte characters.
    $hexints
    0
    Displays integers in hex radix.
    $historylines
    20
    Defines the number of commands to show for history.
    $indent
    1
    Prints structures with indentation.
    $kdebug_host
    localhost
    Specifies the node name of the gateway system. The default "localhost" indicates no gateway system.
    $kdebug_line
    kdebug
    Specifies the label of the /etc/remote entry on the gateway system for the kdebug communication port.
    $kdebug_dbgtty
    (null)
    Specifies the pathname of the terminal window (output from tty (1)) on the gateway system used to display kdebug communication traffic. The default (null) indicates no gateway system.
    $ladebugpid
    None
    Value of the pid for Ladebug itself.
    $lang
    None
    Defines the programming language of current routine.
    $lasteventmade
    0
    Displays the number of last (successful) breakpoint definition.
    $lc_ctype
    "C"
    Displays the current locale information.
    $listwindow
    20
    Displays the number of lines to show for list.
    $main
    "main"
    Displays the name of the first routine in the program.
    $maxstrlen
    128
    Defines the largest string to print fully.
    $memorymatchall
    0
    When set to non-zero, displays all memory matches in the specified range. Otherwise, displays only the first memory match.
    $octints
    0
    Displays integers in octal radix.
    $overloadmenu
    1
    Prompts for choice of overloaded C++ name.
    $page
    1
    Paginates debugger terminal output.
    $pagewindow
    0
    Defines the number of lines per output page. The default of 0 causes the debugger to query the terminal for the page size.
    $parallel_aggregatordelay
    3000 milliseconds
    Set in the .ladebugrc file or or in the file used with the debugger invocation option -i, specifies the length of time that aggregators wait before they aggregate and send messages down to the next level when not all the expected messages have been received.
    $parallel_branchingfactor
    8
    Set in the .ladebugrc file or in the file used with the debugger invocation option -i, specifies the factor used to build the n-nary tree and determine the number of aggregators in the tree.
    $parentprocess
    0
    When the debugger detects a fork, it assigns the parent process ID to $parentprocess.
    $pimode
    0
    Echoes input to log file on playback input.
    $prompt
    "(ladebug) "
    Specifies debugger prompt.
    $readtextfile
    0
    If set to non-zero, reads instructions from the text area of the binary file rather than from the memory image.
    $regstyle
    1
    Controls the format of register names during disassembly. Valid settings are:
    • 0 = compiler names, for example, t0, ra, or zero.
    • 1 = hardware names, for example, r1, r26, or r31.
    • 2 = assembly names, for example, $1, $26, or $31.
    $repeatmode
    1
    Repeats previous command when you press the Return key.
    $showlineonstartup
    0
    Displays the first executable line in main.
    $showwelcomemsg
    1
    Displays welcome message at startup time.
    $stackargs
    1
    Shows arguments in the call stack if 1.
    $statusargs
    1
    Prints breakpoints with parameters if 1.
    $stepg0
    0
    Steps over routines with minimal symbols.
    $stoponattach
    0
    Stops the running process on attach.
    $stopparentonfork
    0
    Stops parent process execution on fork. When set to a nonzero value, this variable instructs the debugger to stop the parent process after it forks a child process. The child process continues to run if $catchforks is not set, otherwise stops. The default is 0.
    $symbolsearchlimit
    100
    Specifies the maximum number of symbols that are returned by the whereis command for a regular expression search. The default value is 100; a value of 0 indicates no limit.
    $threadlevel
    decthreads
    Specifies POSIX threads (DECthreads) or native threads.
    $usedynamictypes
    1
    Evaluates using C++ static or dynamic type.
    $verbose
    0
    Produces even more output.



    Appendix 2—Debugger Aliases

    The debugger has the following predefined aliases:

    Appendix 3—corefile_listobj.c Example

    You can use the following example as an alternative to the listobj command for cases in which the debugger cannot be run on the original system. See the Transporting Core Files section for more information.
    /*
      cc corefile_listobj.c -lxproc -o corefile_listobj
     */
    
    
    #include <stdio.h>
    #include <stdarg.h>
    #include <stdlib.h>
    
    #include <errno.h>
    
    typedef unsigned long vma_t;
    
    /* core file format */
    
    #include <sys/user.h>
    #include <sys/core.h>
    
    /* dynamic loader hookup */
    
    #include <loader.h>
    typedef int (*ldr_reader_func)(vma_t from,
                                   void * to,
                                   long nbytes,
                                   int is_string);
    extern pid_t ldr_core_process();
    extern int ldr_set_core_reader(ldr_reader_func reader);
    
    /********************************************************************/
    
    static FILE *                   corefile;
    static struct core_filehdr      corehdr;
    static int                      nsections;
    static struct core_scnhdr *     section_headers;
    
    int
    open_corefile(const char * corename)
    {
      size_t nread;
    
      corefile = fopen(corename, "rb");
      if (!corefile) {
        perror("Opening corefile");
        return -1;
      }
      nread = fread(&corehdr, sizeof(corehdr), 1, corefile);
      if (nread != 1) {
        perror("fread() of corefile header");
        return -1;
      }
      if (strncmp(corehdr.magic, "Core", 4) != 0) {
        fprintf(stderr, "Corefile header magic is not \"Core\"\n");
        return -1;
      }
      nsections = corehdr.nscns;
      section_headers = calloc(nsections, sizeof(section_headers[0]));
      if (!section_headers) {
        perror("Allocating corefile section headers");
        return -1;
      }
      nread = fread(section_headers, sizeof(section_headers[0]),
                    nsections, corefile);
      if (nread != nsections) {
        perror("fread() of corefile section headers");
        return -1;
      }
    
      return 0;
    }
    
    static int
    section_type_has_memory(int type)
    {
      switch (type) {
      case SCNTEXT: case SCNDATA: case SCNRGN: case SCNSTACK:
        return 1;
      case SCNREGS: case SCNOVFL:
      default:
        return 0;
      }
    }
    
    static int
    read_from_corefile(vma_t from,
                       void * to,
                       long nbytes,
                       int is_string)
    {
      vma_t getter = from;
      char * putter = (char *) to;
      long to_go = nbytes;
      int secnum;
      size_t nxfer;
    
    try_for_more:
      while (to_go > 0) {
        for (secnum = 0; secnum < nsections; secnum += 1) {
          if (section_type_has_memory(section_headers[secnum].scntype)) {
            vma_t vaddr = (vma_t) section_headers[secnum].vaddr;
            vma_t size  = (vma_t) section_headers[secnum].size;
            if (vaddr <= getter && getter < vaddr+size) {
              vma_t this_time = (size < to_go ? size : to_go);
              long file_offset = section_headers[secnum].scnptr+(getter-vaddr);
              if (fseek(corefile, file_offset, SEEK_SET) != 0) {
                perror("fseek() for corefile read");
                return -1;
              }
              nxfer = fread(putter, 1, this_time, corefile);
              if (nxfer != this_time) {
                perror("fread() of corefile data ");
                return -1;
              }
              to_go -= this_time;
              getter += this_time;
              putter += this_time;
              goto try_for_more;
            }
          }
        }
        fprintf("Couldn't find core address for %#lx\n", getter);
        return -1;
      }
      return 0;
    }
    
    int
    main(int argc, char* argv[])
    {
      pid_t process;
    
      if (argc != 2) {
        fprintf(stderr, "Usage is %s \n", argv[0]);
        return 1;
      }
      if (open_corefile(argv[1]) < 0)
        return -1;
    
      process = ldr_core_process();
      ldr_set_core_reader(read_from_corefile);
    
      if (ldr_xattach(process) < 0) {
        perror("Attaching to corefile");
        return 1;
      } else {
        ldr_module_t mod_id = LDR_NULL_MODULE;
        ldr_module_info_t info;
        size_t ret_size;
        while (1) {
          if (ldr_next_module(process, &mod_id) < 0) {
            perror("ldr_next_module");
            return 1;
          }
          if (mod_id == LDR_NULL_MODULE)
            break;
          if (ldr_inq_module(process, mod_id, &info,
                             sizeof(info), &ret_size) < 0) {
            perror("ldr_inq_module");
            return 1;
          }
          printf("%s\n", info.lmi_name);
        }
        ldr_xdetach(process);
        return 0;
      }
    }
    

    Appendix 4—Array Navigation Example

    The debugger provides parameterized aliases and debugger variables of arbitrary types. Clever use of these can do almost any list traversal.

    For example, here is how to navigate an array:

    alias elt(e_) "{ p e_ }"
    alias pa0(a)  "{ set $a = &a[0]; set $i = 0; elt($a[$i]); set $i = $i+1 }"
    alias pan     "{ elt($a[$i]); set $i = $i+1 }"
    pa0
    pan
    pan
    pan
    
    %ladebug a.out
    ...
    (ladebug) alias elt(e_) "{ p e_ }"
    (ladebug) alias a0(a)   "{ set $a = &a[0]; set $i = 0; elt($a[$i]); set $i = $i+1 }"
    (ladebug) alias pan     "{ elt($a[$i]); set $i = $i+1 }"
    ...
    (ladebug) pa0(a)
    struct S {
      next = 0x140000178;
    }
    (ladebug) pan
    struct S {
      next = 0x140000180;
    }
    (ladebug)
    struct S {
      next = 0x140000188;
    }
    (ladebug)
    struct S {
      next = 0x140000190;
    }
    

    Compaq, the Compaq logo, Alpha, AlphaServer, AlphaStation, DECconnect, and Tru64 are trademarks of Compaq Information Technologies Group, L.P., in the U.S. and/or other countries.

    Motif, UNIX, and The Open Group are trademarks of The Open Group in the U.S. and/or other countries. All other product names mentioned herein may be trademarks of their respective companies.

    Confidential computer software. Valid license from Compaq required for possession, use, or copying. Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under vendor's standard commercial license.

    Compaq shall not be liable for technical or editorial errors or omissions contained herein. The information in this publication is provided "as is" without warranty of any kind and is subject to change without notice. The warranties for Compaq products are set forth in the express limited warranty statements accompanying such products. Nothing herein should be construed as constituting an additional warranty.