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 get the process under control.

When you have the process under debugger control, you can assign a non-zero 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.

/*% 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 must 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
EXPORT export LKEYWORD LNORM Shared by all
FILECMD file LKEYWORD LFILE Shared by all
FILEEXPR fileexpr LKEYWORD LFILE 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_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
SNAPSHOT_* snapshot * 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 newline (\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 newline (\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 (|).

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 newline 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 newlines 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]
Lexeme:NEWLINE
Change to State:LKEYWORD

This is because SEMICOLON is the command separator.

Initial State: LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT, LWORD
Regular Expression:";"
Lexeme:SEMICOLON
Change to State:LKEYWORD

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

Initial State: LNORM
Regular Expression:"{"
Lexeme:LBRACE
Change to State:LKEYWORD

Initial State: LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT
Regular Expression:"}"
Lexeme:RBRACE
Change to State:LKEYWORD

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

Initial State: LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT
Regular Expression:[ \t]
\\\n
Lexeme:Ignored
Change to State:Unchanged

Initial State: LLINE
Regular Expression:\\\n
Lexeme:Ignored
Change to State:Unchanged

Initial State: LWORD
Regular Expression:[ \t]
Lexeme:Ignored
Change to State:Unchanged

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 "."
GREATER ">"
HASH unknown
IF if
IN in
IN_ALL in{Whitespace}all{Whitespace}
INTEGERconstant "0"[kK]{HX}+
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 newline 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++, Fortran, Ada, 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 C, C++, Fortran, Ada, COBOL
GREATER ">"
".GT."
(IS[ \t]+)?
  (">"|("GREATER"([ \t]+"THAN")?))
LNORM Unchanged Shared by all, also used for Fortran and COBOL special cases
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 C, C++, Fortran, Ada, COBOL
LESS "<"
".LT."
(IS[ \t]+)?
  ("<"|("LESS"([ \t]+"THAN")?))
LNORM Unchanged Shared by all, also used for Fortran and COBOL special cases
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++, Fortran, Ada
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++
LE "<=" C, C++
GE ">=" 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}({LT}|{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++

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."
LE "<="
EQ "=="
NE "/="
GE ">="
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 ">>"
LE "<="
GE ">="
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: These rules can be subverted 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 very 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 may 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:

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 though the same grammar paths as variable identifiers, which has basically the same effect as the C semantics.
primary-expression
        : identifier-or-key-word
        | constant
        | string-literal-list
        | LPAREN expression 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 has 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

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

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
NOTE: We are not including ENUMERATIONconstant in this section because we are treating it like a variable with a type of "enumeration constant".

constant
        : FLOATINGconstant
        | INTEGERconstant
	| CHARACTERconstant

Ada Rescoped Expressions
qual-typedef-opt : TYPEDEFname | qual-symbol-opt TICK TYPEDEFname whatis-expressions : expression | rescoped-expression | printable_type
Ada Calls
call-expression : expression
Ada Addresses
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
loc : expression | rescoped-expression
Ada Types
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
primary-expression : identifier-or-key-word | constant | string-literal-list | LPAREN expression 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
constant
        : FLOATINGconstant
        | INTEGERconstant
        | DECIMALconstant
        | CHARACTERconstant
	
constant-expression
        : cobol-expression

COBOL Rescoped Expressions
qual-typedef-opt : TYPEDEFname | qual-typedef-opt TICK TYPEDEFname
COBOL Calls
call-expression : identifier-or-key-word | identifier-or-key-word USING cobol-expression-list
COBOL Addresses
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
loc : cobol-identifier | rescoped-expression
COBOL Types
printable-type : rescoped-typedef
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 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 so on commands will not work until you create a process using the run command.

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

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

       % cat testProgram.c

        #include <stdio.h>
        int factorial(int i)

        main() {
                int i,f;
                for (i=1 ; i<3 ; i++) {
                        f = factorial(i);
                        printf("%d! = %d\en",i,f);
                }
        }

        int factorial(int i)
        int i;
        {
        int *x;
                 x = 0;
                 printf("%d",*x);
                 if (i<=1)
                         return (1);
                 else
                         return (i * factorial(i-1) );
        }

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

16.3 Transporting a Core File

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

Procedure for Transporting Core Files

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

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

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

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

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

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

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

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

16.4 Core File Debugging Example

The following is a complete example, from core creation, through transporting and core file debugging:
  1. Create the core file:
           % a.out -segv
            Segmentation fault (core dumped)
    
  2. Determine the shared objects using the debugger on the original system:
           % ladebug a.out core
            Welcome to the Ladebug Debugger Version 4.0-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 4.0-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

The following sections contain 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 filenames.
  4. Add /usr/shlib/libpthreaddebug.so, if libpthread.so
  5. % 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 sections 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 a 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, or pid. Some of these processes relate to user processes, and some are kernel-specific.

NOTE: Because the debugger supports multi-processing as well as kernel debugging, we 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, we will refer to a process being debugged as a process, and we will refer 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 the user 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 - see below), 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:


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

And 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 will add the KSEG base address to any such hexadecimal constant. For example, the constant 0k2400 will be converted by Ladebug into the actual address for the location at offset 0x2400 into the KSEG segment.

17.2 Local Kernel Debugging

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

Invoke the debugger with the following command:

    # ladebug -k /vmunix /dev/mem

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

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

17.3 Crash Dump Analysis

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

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

17.3.1 Crash Dumps

The operating system can crash in the following ways:

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

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

17.3.2 Guidelines for Examining Crash Dumps

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

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

17.3.3 Analyzing a Crash Dump

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

To invoke the debugger on a kernel crash dump numbered "0", 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 zero (0) 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 the user 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 4.0-64 (built Nov 12 2000 for 
	Compaq Tru64 UNIX)
	------------------ 
	object file name: vmunix.0 
	core file name: vmzcore.0
	Reading symbolic information ...done
	Thread terminated at PC 0xfffffc0000457a48
	done
	(ladebug) print panicstr
	0xfffffc0000640970="kernel memory fault"		    <== memory fault
	(ladebug) print utsname
	struct utsname {
  	  sysname = "OSF1";
  	  nodename = "";
  	  release = "X5.1";					    <== 5.n system
  	  version = "730";
  	  machine = "alpha";
	}
	(ladebug) print processor_ptr[paniccpu].m
	struct machine_slot {
  	  is_cpu = 1;
  	  cpu_type = 15;
  	  cpu_subtype = 22;
  	  running = 1;
  	  cpu_ticks = [0] = 0,[1] = 0,[2] = 0,[3] = 0,[4] = 0;
  	  clock_freq = 1200;
  	  error_restart = 0;
  	  cpu_panicstr = 0xfffffc0000640970="kernel memory fault";  <== strings match
  	  cpu_panic_thread = 0xfffffc0001c51180;
	}

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

    (ladebug) print savedefp/33X

    ffffffff9618d940:   0000000000000000 fffffc000046f888
    ffffffff9618d950:   ffffffff86329ed0 0000000079cd612f
    .
    .
    .
    ffffffff9618da30:   0000000000901402 0000000000001001
    ffffffff9618da40:   0000000000002000

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

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

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

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

17.3.4 Other Crash Dump Tools

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

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

Remote Kernel Debugging

For remote kernel debugging, the Ladebug debugger is used 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. The build system is connected to the gateway system over a network. The gateway system is connected 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 selecting KERNEL BREAKPOINT DEBUGGING from the Kernel Options menu.

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

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

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

  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 these 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 an symmetric multiprocessing (SMP) system , set the lockmode system attribute to 4, as shown:

       # sysconfig -r lockmode = 4
    

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

17.4.4 Invoking the Debugger

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

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

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

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

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

  2. Halt the test system:

       # shutdown -h now
    

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

       >>> set boot_osflags k
    

    Alternatively, you can enter the following command:

       >>> boot -flags k
    

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

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

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, refer to the following list 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:

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 that 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 step.