Title and Contents

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 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 HP 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 HP 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 HP 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 HP 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 HP 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>"
    

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

    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 HP Tru64 UNIX System Administration manual and the HP 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:

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 HP 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