Title and Contents |
It is intended to be used as a reference and therefore contains a wide variation in the level of information provided in each section.
void loopForDebugger()
{
if (!getenv("loopForDebugger")) return;
static volatile int debuggerPresent = 0;
while (!debuggerPresent);
}
attach
capability to bring
the process under control.
When you have the process under debugger control, you can assign
a nonzero value to debuggerPresent
, and continue your program. For example:
% setenv loopForDebugger ""
% a.out arg1 arg2 &
% ladebug -pid 1709 a.out
^C
(ladebug) assign debuggerPresent = 1
...
(ladebug) cont
You can also call the
debugBreak
function to start the
debugger at some specified point after your program starts executing.
For more information about debugBreak
, see the
Ladebug
Web site FAQ.
/*% cc -g traceback.c -lexc
**% a.out
*/
struct exception_info;
/* To suppress compilation warnings from sym.h */
#include <demangle.h>
#include <excpt.h>
#include <setjmp.h>
#include <signal.h>
#include <sym.h>
#include <unistd.h>
static void printHeader(void)
{
printf("Diagnostic stack trace ...\n");
}
static void printTrailer(void)
{
printf("end of diagnostic stack trace.\n");
}
#define RETURNADDRREG (26)
#define FAULTING_ADDRESS sc_traparg_a0
extern unsigned long _procedure_string_table;
extern unsigned long _procedure_table_size;
extern unsigned long _procedure_table;
extern unsigned long _ftext; /* Start address of the program text.*/
extern unsigned long _etext; /* First address above the program text.*/
/* Turn a PC into the name of the routine containing that PC.
*/
char* programCounterToName(
unsigned long programCounter);
/* Unwind the stack one level.
*/
void unwindOneLevel(
struct sigcontext* unwindSignalContext,
void * runtimeProcedurePtr);
void printFrame(
void * rpdp,
unsigned long programCounter)
{
char* procedureName;
/* Get the procedure name.
*/
procedureName = programCounterToName(programCounter);
printf("%p %s\n",
(void* ) programCounter, procedureName ? procedureName : "");
}
char* programCounterToName(
unsigned long programCounter)
{
long int procedureTableSize;
char * procedureNameTable;
char * procedureName;
long int currentProcedure;
long int procedure;
pRPDR runTimePDPtr;
int found;
unsigned long int address;
found = 0;
procedureName = 0;
procedureTableSize = (long int)&_procedure_table_size;
procedureNameTable = (char *)&_procedure_string_table;
runTimePDPtr = (pRPDR)&_procedure_table;
/* The table of run time procedure descriptors is ordered by
procedure start address. Search the table (linearly) for the
first procedure with a start address larger than the one for
which we are looking.
*/
for (currentProcedure = 0;
currentProcedure < procedureTableSize;
currentProcedure++) {
/* Because of the way the linker builds the table we need to make
special cases of the first and last entries. The linker uses 0
for the address of the procedure in the first entry, here we
substitute the start address of the text segment. The linker
uses -1 for the address of the procedure in the last entry,
here we substitute the end address of the text segment. For all
other entries the procedure address is obtained from the table.*/
if (currentProcedure == 0) /* first entry */
address = (unsigned long int)&_ftext;
else if (currentProcedure == procedureTableSize - 1) /* last entry */
address = (unsigned long int)&_etext;
else /* other entries */
address = runTimePDPtr[currentProcedure].adr;
if (address > programCounter) {
if (currentProcedure != 0) {
/* the PC is in this image */
found = 1;
procedure = currentProcedure - 1; /* the PC is in preceeding procedure */
break; /* stop searching */
} else {
/* the PC is outside this image (at a lower address) */
break; /* stop searching */ }
}
}
if (found) {
/* the PC is inside this image */
procedureName = &procedureNameTable[runTimePDPtr[procedure].irpss];
} else {
/* the PC is outside this image, probably in a different shared object */
procedureName = 0;
}
return procedureName;
}
void unwindOneLevel(
struct sigcontext *unwindSignalContext,
void * runtimeProcedurePtr)
{
unwind(unwindSignalContext, (pdsc_crd *)runtimeProcedurePtr);
}
/* Print a stack trace.
*/
void printStackWkr(struct sigcontext *signalContextPtr)
{
struct sigcontext unwindSignalContext;
void *runTimeProcedurePtr;
unsigned long int stackpointer = 0;
unsigned long int programCounter = 0;
unsigned long int returnAddress = 0;
unsigned long int faultingAddress = 0;
printHeader();
/* Set the initial context for the unwind.
*/
unwindSignalContext = *signalContextPtr;
/* Pick out the return address and program counter.
*/
returnAddress = unwindSignalContext.sc_regs[RETURNADDRREG];
programCounter = unwindSignalContext.sc_pc;
/* This is the address that caused the fault when we tried to access
it.
*/
faultingAddress = signalContextPtr->FAULTING_ADDRESS;
/* Special cases for bogus program counter values. If the program
counter is zero or the fault occurred when we were trying to
fetch an instruction (because the program counter itself was bad)
then we cannot unwind the stack.
*/
if (programCounter == 0) {
printf("PC is zero - stack trace not available.\n");
} else if (programCounter == faultingAddress) {
printf("bad PC (%p) - stack trace not available.\n",
faultingAddress);
} else {
unsigned int sameSpCount = 0;
/* Loop through all the stack frames.
*/
while ((returnAddress != 0) && (programCounter != 0)) {
/* Get the run time procedure descriptor for this frame.
*/
runTimeProcedurePtr = find_rpd(programCounter);
/* Print a frame.
*/
printFrame(runTimeProcedurePtr, programCounter);
/* Unwind one level.
*/
unwindOneLevel(&unwindSignalContext, runTimeProcedurePtr);
returnAddress = unwindSignalContext.sc_regs[RETURNADDRREG];
programCounter = unwindSignalContext.sc_pc;
if (unwindSignalContext.sc_sp <= stackpointer) {
sameSpCount++;
if (sameSpCount == 10) break;
} else {
sameSpCount = 0;
stackpointer = unwindSignalContext.sc_sp;
}
}
}
printTrailer();
}
/* Discard one stack frame by silently unwinding.
*/
long int discardOneLevel(
long int programCounter,
struct sigcontext *signalContextPtr)
{
void *runTimeProcedurePtr;
runTimeProcedurePtr = find_rpd(programCounter);
unwindOneLevel(signalContextPtr, runTimeProcedurePtr);
return signalContextPtr->sc_pc;
}
void printStack(int levelsToDiscard)
{
long int programCounter;
void *runTimeProcedurePtr;
jmp_buf context;
struct sigcontext *signalContextPtr;
/* Capture the current context.
*/
setjmp(context);
signalContextPtr = (struct sigcontext *)context;
programCounter = signalContextPtr->sc_pc;
/* Discard the frame for this routine.
*/
programCounter = discardOneLevel(programCounter, signalContextPtr);
/* Discard any other frames requested by our caller.
*/
if (levelsToDiscard > 0) {
int levels;
for (levels = 0; levels < levelsToDiscard; levels++) {
programCounter = discardOneLevel(programCounter, signalContextPtr);
}
}
/* Now that we have the right context, print the stack trace.
*/
printStackWkr(signalContextPtr);
}
/* Example of usage follows. */
void innermost()
{
printStack(0);
}
void middle()
{
innermost();
}
int main()
{
middle();
return 0;
}
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.
The debugger moves between the following lexical states as it recognizes the lexemes:
Lexical State | Description |
LBPT | Breakpoint commands have lexemes that change the lexical state to LBPT. |
LEXPORT | The command export changes the lexical state to
LEXPORT. This state recognizes an evironment variable identifier. |
LFILE | Commands that require file names have lexemes that change the
lexical state to LFILE so that things like mysrc/foo.txt are
recognized as
a file name, and not as a variable mysrc being divided by a
structure data member foo.txt . |
LFINT | Commands that require either a file name or a process ID have lexemes to change the lexical state to LFINT. |
LKEYWORD | All but one of the Ladebug commands begin with one or more
keywords. The exception is the examine command.
The debugger recognizes the '{' and ';' lexemes that precede a
command, and uses those to reset to the LKEYWORD state for the beginning of
the next command. |
LLINE | Commands that require arbitrary character input have lexemes that change the lexical state to LLINE. |
LNORM | Language expressions involve language-specific lexemes. The lexemes that precede an expression change the lexical state to LNORM, and then LNORM recognizes the language-specific lexemes. |
LSETENV | The command setenv changes the lexical state to
LSETENV. This state recognizes an evironment variable identifier.
|
LSIGNAL | Commands that require signal names have lexemes that change the lexical state to LSIGNAL. |
LWORD | Commands that require shell words have lexemes that change the lexical state to LWORD. |
The rules that each lexical state uses are described in the following sections, in a format known as a lex regular expression. Rather than repeating some of descriptions, a set of common subrules is described first. After the common subrules, we describe the initial state, the rules, and for each recognized token, the next lexical state.
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:
Language | Regular Expression |
C, C++, Fortran, Ada | {LT}({LT}|{DG})* |
COBOL | CobolWord |
Language | Regular Expression |
All | {LT}({LT}|{DG})* |
{LT}
equates to {LTI18N}
.
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
|
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.
()
) 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}*
|
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}*
|
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}*
|
LKEYWORD | LNORM |
Shared by all |
EXPAND_AGGREGATED_MESSAGE |
expand{Whitespace}aggregated{Whitespace}message |
LKEYWORD | LNORM |
Shared by all |
EXPORT |
export |
LKEYWORD | LNORM |
Shared by all |
FILECMD |
file |
LKEYWORD | LFILE |
Shared by all |
FILEEXPR |
fileexpr |
LKEYWORD | LFILE |
Shared by all |
FOCUS |
focus |
LKEYWORD | LNORM |
Shared by all |
FOCUS_ALL |
focus {Whitespace }*
focus {Whitespace }all |
LKEYWORD | LNORM |
Shared by all |
FUNC |
func |
LKEYWORD | LNORM |
Shared by all |
GOTO |
goto |
LKEYWORD | LNORM |
Shared by all |
GUI |
gui |
LKEYWORD | LNORM |
Shared by all |
HELP |
help |
LKEYWORD | LLINE |
Shared by all |
HISTORY |
history |
LKEYWORD | LNORM |
Shared by all |
HPFGET |
hpfget |
LKEYWORD | LNORM |
Fortran |
IF |
if |
LKEYWORD | LNORM |
Shared by all |
IGNORE |
ignore |
LKEYWORD | LSIGNAL |
Shared by all |
IGNORE_UNALIGN |
ignore{Whitespace}unaligned |
LKEYWORD | LNORM |
Shared by all |
INPUT |
input |
LKEYWORD | LFILE |
Shared by all |
IO |
io |
LKEYWORD | LFILE |
Shared by all |
KILL |
kill |
LKEYWORD | LNORM |
Shared by all |
KPS |
kps |
LKEYWORD | LNORM |
Shared by all |
LIST |
list |
LKEYWORD | LNORM |
Shared by all |
LISTOBJ |
listobj |
LKEYWORD | LNORM |
Shared by all |
LOAD |
load |
LKEYWORD | LFILE |
Shared by all |
MAP_SOURCE_DIRECTORY |
map{Whitespace}source{Whitespace}directory |
LKEYWORD | LNORM |
Shared by all |
MUTEX |
mutex |
LKEYWORD | LNORM |
Shared by all |
NEXT |
next |
LKEYWORD | LNORM |
Shared by all |
NEXTI |
nexti |
LKEYWORD | LNORM |
Shared by all |
OUTPUT |
output |
LKEYWORD | LFILE |
Shared by all |
PATCH |
patch |
LKEYWORD | LNORM |
Shared by all |
PLAYBACK |
playback |
LKEYWORD | LKEYWORD |
Shared by all |
POP |
pop |
LKEYWORD | LNORM |
Shared by all |
PRINT |
print |
LKEYWORD | LNORM |
Shared by all |
PRINTB |
printb |
LKEYWORD | LNORM |
Shared by all |
PRINTD |
printd |
LKEYWORD | LNORM |
Shared by all |
PRINTENV |
printenv |
LKEYWORD | LNORM |
Shared by all |
PRINTF |
printf |
LKEYWORD | LNORM |
Shared by all |
PRINTI |
printi |
LKEYWORD | LNORM |
Shared by all |
PRINTO |
printo |
LKEYWORD | LNORM |
Shared by all |
PRINTT |
printt |
LKEYWORD | LNORM |
Shared by all |
PRINTX |
printx |
LKEYWORD | LNORM |
Shared by all |
PRINTREGS |
printregs |
LKEYWORD | LNORM |
Shared by all |
PROCESS |
process |
LKEYWORD | LNORM |
Shared by all |
PROCESS_ALL |
process{Whitespace}*
|
LKEYWORD | LNORM |
Shared by all |
PTHREAD |
pthread |
LKEYWORD | LNORM |
Shared by all |
QUESTION |
? |
LKEYWORD | LNORM |
Shared by all |
QUIT |
quit |
LKEYWORD | LNORM |
Shared by all |
READSHAREDOBJ |
readsharedobj |
LKEYWORD | LFILE |
Shared by all |
RECORD |
record |
LKEYWORD | LKEYWORD |
Shared by all |
RERUN |
rerun |
LKEYWORD | LWORD |
Shared by all |
RETURN |
return |
LKEYWORD | LNORM |
Shared by all |
RUN |
run |
LKEYWORD | LWORD |
Shared by all |
SAVE_SNAPSHOT |
save{Whitespace}snapshot |
LKEYWORD | LNORM |
Shared by all |
SET |
set |
LKEYWORD | LNORM |
Shared by all |
SETENV |
setenv |
LKEYWORD | LNORM |
Shared by all |
SH |
sh |
LKEYWORD | LNORM |
Shared by all |
SHOW |
show |
LKEYWORD | LKEYWORD |
Shared by all |
SHOW_AGGREGATED_MESSAGE |
show{Whitespace}aggregated{Whitespace}message |
LKEYWORD | LNORM |
Shared by all |
SHOW_AGGREGATED_MESSAGE_ALL |
show{Whitespace}aggregated{Whitespace}message{Whitespace}*
show{Whitespace}aggregated{Whitespace}message{Whitespace}all |
LKEYWORD | LNORM |
Shared by all |
SHOW_PROCESS_SET |
show{Whitespace}process{Whitespace}set |
LKEYWORD | LNORM |
Shared by all |
SHOW_PROCESS_SET_ALL |
show{Whitespace}process{Whitespace}set{Whitespace}*
show{Whitespace}process{Whitespace}set{Whitespace}all |
LKEYWORD | LNORM |
Shared by all |
SHOW_SOURCE_DIRECTORY |
show{Whitespace}source{Whitespace}directory
|
LKEYWORD | LNORM |
Shared by all |
SHOW_ALL_SOURCE_DIRECTORY |
show{Whitespace}all{Whitespace}source{Whitespace}directory |
LKEYWORD | LNORM |
Shared by all |
SLASH |
/ |
LKEYWORD | LNORM |
Shared by all |
SNAPSHOT |
snapshot |
LKEYWORD | LNORM |
Shared by all |
SNAPSHOT_ALL |
snapshot all |
LKEYWORD | LNORM |
Shared by all |
SOURCE |
source |
LKEYWORD | LFILE |
Shared by all |
STATUS |
status |
LKEYWORD | LNORM |
Shared by all |
STEP |
step |
LKEYWORD | LNORM |
Shared by all |
STEPI |
stepi |
LKEYWORD | LNORM |
Shared by all |
STOP |
stop |
LKEYWORD | LBPT |
Shared by all |
STOPI |
stopi |
LKEYWORD | LNORM |
Shared by all |
THREAD |
thread |
LKEYWORD | LNORM |
Shared by all |
TRACE |
trace |
LKEYWORD | LNORM |
Shared by all |
TRACEI |
tracei |
LKEYWORD | LNORM |
Shared by all |
UNALIAS |
unalias |
LKEYWORD | LNORM |
Shared by all |
UNLOAD |
unload |
LKEYWORD | LNORM |
Shared by all |
UNMAP_SOURCE_DIRECTORY |
unmap{Whitespace}source{Whitespace}directory |
LKEYWORD | LNORM |
Shared by all |
UNRECORD |
unrecord |
LKEYWORD | LNORM |
Shared by all |
UNSET |
unset |
LKEYWORD | LNORM |
Shared by all |
UNSETENV |
unsetenv |
LKEYWORD | LNORM |
Shared by all |
UNSETENV_ALL |
unsetenv{Whitespace}* |
LKEYWORD | LNORM |
Shared by all |
UNUSE |
unuse |
LKEYWORD | LFILE |
Shared by all |
UP |
up |
LKEYWORD | LNORM |
Shared by all |
USE |
use |
LKEYWORD | LFILE |
Shared by all |
VERSION |
version |
LKEYWORD | LNORM |
Shared by all |
WATCH |
watch |
LKEYWORD | LNORM |
Shared by all |
WATCH_MEMORY |
watch{Whitespace}memory |
LKEYWORD | LNORM |
Shared by all |
WATCH_VARIABLE |
watch{Whitespace}variable |
LKEYWORD | LNORM |
Shared by all |
WHATIS |
whatis |
LKEYWORD | LNORM |
Shared by all |
WHEN |
when |
LKEYWORD | LBPTChapter |
Shared by all |
WHENI |
wheni |
LKEYWORD | LNORM |
Shared by all |
WHERE |
where |
LKEYWORD | LNORM |
Shared by all |
WHEREIS |
whereis |
LKEYWORD | LNORM |
Shared by all |
WHERE_THREAD |
where{Whitespace}thread |
LKEYWORD | LNORM |
Shared by all |
WHERE_THREAD_ALL |
where{Whitespace}thread{Whitespace}*
|
LKEYWORD | LNORM |
Shared by all |
WHICH |
which |
LKEYWORD | LNORM |
Shared by all |
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" |
LNORM | LNORM |
COBOL |
SIGNNOTZERO |
(IS[ \t]+)?"NOT"[ \t]+"ZERO" |
LNORM | LNORM |
COBOL |
SIGNPOS |
(IS[ \t]+)?"POSITIVE" |
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++ |
Some lexemes have the same representation in all languages, especially those that form part of the Ladebug commands apart from the language-specific expressions.
Concept | Rule | Representation | Description |
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}|
|
Any character except the terminating quote character ("), or a new line (\n). If the character is a backslash (\), it is followed by an escaped sequence of characters. |
Character literal | charChar | ([^'\\\n]|([\\]({simpleEscape}|
|
Any character except the terminating quote (') character, or a new line (\n). If the character is a backslash (\), it is followed by an escaped sequence of characters. |
Environment variable identifier | EID | [^ \t\n<>;='"&\|] |
Any character except space, tab, linefeed, less-than (<), greater-than (>), semicolon (;), equal sign (=), quotes (' or "), ampersand (&), backslash (\), and bar (|). |
Universal character name | UCN | \\u{HX}{4}|\\U{HX}{8} |
A universal character name is a backslash (\) followed by either a lowercase 'u' and 4 hexadecimal digits, or an uppercase 'U' and 8 hexadecimal digits. |
The escaped sequence of characters can be one of following three forms:
Concept | Rule | Representation | Description |
Simple escape | simpleEscape | ([A-Za-z'"?#*\\])
|
One of 'A'-'Z' or 'a'-'z'. Some of these have special meanings, the most common being 'n' for new line and 't' for tab. Can be a quote (' or ") character that does not finish the literal, a question mark (?), a pound sign (#), an asterisk (*), or a backslash (\), which then becomes part of the string literal rather than causing a further escape sequence. |
Octal escape | octalEscape | (OC{1,3})
|
1 to 3 octal digits, the combined numeric value of which is the character that becomes part of the string literal. |
Hexadecimal escape | hexEscape | ([xX]HX{1,8})
|
An 'x' or an 'X' followed by 1 to 8 hexadecimal digits, the combined numeric value of which is the character that becomes part of the string literal. |
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 new lines are ignored. In the LLINE state, the spaces and tabs are part of the line, but escaped new lines are still ignored. In the LWORD state, the spaces and tabs are ignored, but escaped new lines are not.
Initial State | LKEYWORD, LNORM, LFILE, LSIGNAL, LBPT |
Regular expression | [ \t] |
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 |
Lexeme | Regular Expression |
ANY |
any |
AT |
at |
ATSIGN |
"@" |
CHANGED |
changed |
CHARACTERconstant |
[lL][']{charChar}+['] |
COLON |
":" |
COMMA |
"," |
DOLLAR |
"$" |
DOT |
"." |
GE |
">=" |
GREATER |
">" |
HASH |
unknown |
IF |
if |
IN |
in |
IN_ALL |
in{Whitespace}all{Whitespace} |
INTEGERconstant |
"0"[kK]{HX}+ |
LE |
"<=" |
LESS |
"<" |
LPAREN |
"(" |
POLICY |
policy |
PRIORITY |
priority |
RPAREN |
")" |
READ |
read |
SLASH |
"/" |
STAR |
"*" |
STATE |
state |
STRINGliteral |
["]{stringChar}*["] |
THREAD |
thread |
THREAD_ALL |
thread{Whitespace}all
thread{Whitespace}"*" |
TICK |
"`" |
TO |
to |
WIDECHARACTERconstant |
[lL][']{charChar}+['] |
WIDESTRINGliteral |
[lL]["]{stringChar}*["] |
WITH |
with |
WITHIN |
within |
WRITE |
write |
Lexeme | Regular Expression | Initial Lexical State | Changed Lexical State |
IN |
in |
LBPT | LNORM |
IN_ALL |
in{Whitespace}all |
LBPT | LNORM |
INTEGERconstant |
"0"[kK]{HX}+ |
LBPT | LBPT |
AT |
at |
LBPT | LNORM |
PC_IS |
pc |
LBPT | LNORM |
SIGNAL |
signal |
LBPT | LNORM |
UNALIGNED |
unaligned |
LBPT | LNORM |
VARIABLE |
variable |
LBPT | LNORM |
MEMORY |
memory |
LBPT | LNORM |
EVERY_INSTRUCTION |
every{Whitespace}instruction | LBPT | LNORM |
EVERY_PROC_ENTRY |
every{Whitespace}proc[edure]{Whitespace}entry |
LBPT | LNORM |
QUIET |
quiet |
LBPT | LBPT |
The state is left as LFILE, so that commands such as use
and
unuse
can have lists of files.
Lexeme | Regular Expression |
FILENAME |
{FL}+ |
Lexeme | Regular Expression |
INTEGERconstant |
"0"{OC}+ "0"[kK]{HX}+ |
Lexeme | Regular Expression |
GREATER |
">" |
LESS |
"<" |
GREATERAMPERSAND |
">&" |
ONEGREATER |
"1>" |
TWOGREATER |
"2>" |
STRINGliteral |
[']{charChar}*['] |
STRINGliteral |
{WD}* that does not end in a backslash |
WIDECHARACTERconstant |
[lL][']{charChar}+['] |
WIDESTRINGliteral |
[lL]["]{stringChar}*["] |
Lexeme | Regular Expression |
INTEGERconstant |
{DG}+ |
IDENTIFIER |
{LT}({LT}|{DG})* |
Lexeme | Regular Expression |
ENVARID |
{EID} + |
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
|
[0-9A-Za-z_$\200-\377\-] |
LNORM, LBPT | LNORM |
COBOL |
AMPERSAND |
"&" |
LNORM | Unchanged | C, C++, Fortran, Ada |
AND |
AND |
LNORM | Unchanged | COBOL |
ANDAND |
"&&" |
LNORM | Unchanged | C, C++, Ada |
ANDassign |
"&=" |
LNORM | Unchanged | 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 |
"=="
|
LNORM | Unchanged | C, C++, Ada, Fortran
Fortran COBOL |
ERassign |
"^=" |
LNORM | Unchanged | C, C++ |
EXPON |
"**" |
LNORM | Unchanged | COBOL |
GE |
".GE." |
LNORM | Unchanged | Fortran
COBOL |
GREATER |
".GT." |
LNORM | Unchanged | Fortran
COBOL |
HAT |
"^" |
LNORM | Unchanged | C, C++, Ada |
INCR |
"++" |
LNORM | Unchanged | C, C++, Ada |
LBRACKET |
"[" |
LNORM | Unchanged | C, C++, Fortran, Ada |
LE |
".LE." |
LNORM | Unchanged | Fortran
COBOL |
LESS |
".LT." |
LNORM | Unchanged | Fortran
COBOL |
LOGAND |
".AND." |
LNORM | Unchanged | Fortran |
LOGEQV |
".EQV." |
LNORM | Unchanged | Fortran |
LOGNEQV |
".NEQV." |
LNORM | Unchanged | Fortran |
LOGNOT |
".NOT." |
LNORM | Unchanged | Fortran |
LOGOR |
".OR." |
LNORM | Unchanged | Fortran |
LOGXOR |
".XOR." |
LNORM | Unchanged | Fortran |
LS |
"<<" |
LNORM | Unchanged | C, C++, Ada |
LSassign |
"<<=" |
LNORM | Unchanged | C, C++ |
MINUS |
"-" |
LNORM | Unchanged | C, C++, Fortran, Ada, COBOL |
MINUSassign |
"-=" |
LNORM | Unchanged | C, C++ |
MOD |
"%" |
LNORM | Unchanged | C, C++, Ada, COBOL |
MODassign |
"%=" |
LNORM | Unchanged | C, C++, Ada |
MULTassign |
"*=" |
LNORM | Unchanged | C, C++, Ada |
NE |
"!="
|
LNORM | Unchanged | C, C++, Ada
Fortran COBOL |
NOT |
"!" |
LNORM | Unchanged | C, C++, Ada,
COBOL |
OPENSLASH |
"(/" |
LNORM | Unchanged | Fortran |
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 |
If a C++ identifier is followed by a "<", complex and dubious checks are made to try to match a complete template instance specifier.
Lexeme | Representation | Language |
ARROW |
"->" |
C, C++ |
INCR |
"++" |
C, C++ |
DECR |
"--" |
C, C++ |
LS |
"<<" |
C, C++ |
RS |
">>" |
C, C++ |
EQ |
"==" |
C, C++ |
NE |
"!=" |
C, C++ |
ANDAND |
"&&" |
C, C++ |
OROR |
"||" |
C, C++ |
MULTassign |
"*=" |
C, C++ |
DIVassign |
"/=" |
C, C++ |
MODassign |
"%=" |
C, C++ |
PLUSassign |
"+=" |
C, C++ |
MINUSassign |
"-=" |
C, C++ |
LSassign |
"<<=" |
C, C++ |
RSassign |
">>=" |
C, C++ |
ANDassign |
"&=" |
C, C++ |
ERassign |
"^=" |
C, C++ |
ORassign |
"|=" |
C, C++ |
PLUS |
"+" |
C, C++ |
MINUS |
"-" |
C, C++ |
MOD |
"%" |
C, C++ |
HAT |
"^" |
C, C++ |
AMPERSAND |
"&" |
C, C++ |
OR |
"|" |
C, C++ |
TWIDDLE |
"~" |
C, C++ |
NOT |
"!" |
C, C++ |
BRACKETS |
"[]" |
C, C++ |
ASSIGNOP |
"=" |
C, C++ |
LBRACKET |
"[" |
C, C++ |
RBRACKET |
"]" |
C, C++ |
QUESTION |
"?" |
C, C++ |
CHAR |
char |
C, C++ |
DOUBLE |
double |
C, C++ |
FLOAT |
float |
C, C++ |
INT |
int |
C, C++ |
LONG |
long |
C, C++ |
SHORT |
short |
C, C++ |
SIGNED |
signed |
C, C++ |
UNSIGNED |
unsigned |
C, C++ |
VOID |
void |
C, C++ |
CONST |
const |
C, C++ |
VOLATILE |
volatile |
C, C++ |
SIZEOF |
sizeof |
C, C++ |
ENUM |
enum |
C, C++ |
STRUCT |
struct |
C, C++ |
UNION |
union |
C, C++ |
INTEGERconstant |
"0"{OC}+
|
C, C++ |
FLOATINGconstant |
{DG}*"."{DG}*
|
C, C++ |
IDENTIFIER, TYPEDEFname |
{LT}|{UCN})({LT}|{UCN}|{DG})* |
C, C++ |
The lexemes in the following table are specific to C++. The state stays in LNORM.
Lexeme | Representation | Language |
OPERATOR |
operator |
C++ |
NEW |
new |
C++ |
DELETE |
delete |
C++ |
CLASS |
class |
C++ |
ELLIPSIS |
"..." |
C++ |
CLCL |
"::" |
C++ |
THIS |
this |
C++ |
DOTstar |
".*" |
C++ |
ARROWstar |
"->*" |
C++ |
PARENS |
"()" |
C++ |
Lexeme | Representation |
PLUS |
"+" |
MINUS |
"-" |
STARSTAR |
"**" |
LESS |
".LT." |
LE |
".LE." |
EQ |
".EQ." |
NE |
".NE." |
GE |
".GE." |
GREATER |
".GT." |
EQ |
"==" |
NE |
"/=" |
LOGNOT |
".NOT." |
LOGAND |
".AND." |
LOGOR |
".OR." |
LOGEQV |
".EQV." |
LOGNEQV |
".NEQV." |
LOGXOR |
".XOR." |
PERCENT |
"%" |
ASSIGNOP |
"=" |
SLASHSLASH |
"//" |
OPENSLASH |
"(/" |
SLASHCLOSE |
"/)" |
LBRACKET |
"[" |
RBRACKET |
"]" |
AMPERSAND |
"&" |
SIZEOF |
sizeof |
INTEGERconstant |
".TRUE."
|
IDENTIFIER, TYPEDEFname |
{LT}({LT}|{DG})* |
FortranName |
[A-Za-z$]({LT}|{DG})*
|
FortranNamedKind |
"_"{FortranName} |
FortranNumericKind |
"_"{DG}+
|
FortranKind |
{FortranNamedKind} |
FortranCharacterNamedKind |
{FortranName}"_" |
FortranCharacterNumericKind |
{DG}+"_" |
FortranCharacterKind |
{FortranCharacterNamedKind} |
RealWithDecimal |
({DG}+"."{DG}*) |
ExponentVal |
[+-]?{DG}+ |
RealEExponent |
[Ee]{ExponentVal}
|
RealDExponent |
[Dd]{ExponentVal} |
RealQExponent |
[Qq]{ExponentVal} |
RealSingleConstant |
(({DG}+{RealEExponent}) |
RealDoubleConstant |
({DG}+|{RealWithDecimal}){RealDExponent}
|
RealQuadConstant |
({DG}+|{RealWithDecimal}){RealQExponent}
|
RealConstant |
{RealSingleConstant} |
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} |
LOGICALconstantWithKind |
".TRUE."{FortranKind}? |
CharSingleDelim |
[^'\\\n]|('') |
CharDoubleDelim |
[^"\\\n]|("") |
FortranOctalEscape |
{OC}{1,3} |
FortranHexEscape |
[Xx]{HX}{1,2} |
FortranEscapeChar |
[\\]([AaBbFfNnRrTtVv]|{FortranOctalEscape} |
StringSingleDelim |
[']({CharSingleDelim}|[\\])*['] |
StringDoubleDelim |
["]({CharDoubleDelim}|[\\])*["] |
FortranString |
{StringSingleDelim} |
CStringSingleDelim |
[']({CharSingleDelim}|{FortranEscapeChar})*['] |
CStringDoubleDelim |
["]({CharDoubleDelim}|{FortranEscapeChar})*["] |
FortranCString |
({CStringSingleDelim}|{CStringDoubleDelim})[Cc] |
CHARACTERconstantWithKind |
{FortranString} |
Lexeme | Representation |
ARROW |
"->" |
INCR |
"++" |
DECR |
"--" |
LS |
"<<" |
RS |
">>" |
EQ |
"==" |
NE |
"!=" |
ANDAND |
"&&" |
OROR |
"||" |
MULTassign |
"*=" |
DIVassign |
"/=" |
MODassign |
"%=" |
PLUSassign |
"+=" |
MINUSassign |
"-=" |
LSassign |
"<<=" |
RSassign |
">>=" |
ANDassign |
"&=" |
ERassign |
"^=" |
ORassign |
"|=" |
PLUS |
"+" |
MINUS |
"-" |
MOD |
"%" |
HAT |
"^" |
AMPERSAND |
"&" |
OR |
"|" |
TWIDDLE |
"~" |
NOT |
"!" |
BRACKETS |
"[]" |
ASSIGNOP |
"=" |
LBRACKET |
"[" |
RBRACKET |
"]" |
QUESTION |
"?" |
INTEGERconstant |
"0"{OC}+
|
FLOATINGconstant |
{DG}*"."{DG}+
|
IDENTIFIER, TYPEDEFname |
{LT}({LT}|{DG})* |
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 ]
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
TYPEDEFname
s are lexically just identifiers, but when looking them up in the
current scope, the debugger determines that they refer to types, such as
TYPEDEF
s, classes, or struct
s. 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 TYPEDEFname
s
(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_constant
: INTEGERconstant for C and C++
| INTEGERconstant for Fortran
| INTEGERconstant for Ada
| INTEGERconstant for COBOL
#define
macros, and so on.
call-expression
: call-expression for C
| call-expression for C++
| call-expression for Fortran
| call-expression for Ada
| call-expression for COBOL
Any expression can be passed by value, but C++ constructors and destructors will not be invoked. Evaluating parameters can involve evaluating nested calls.
Anything whose address can be taken can be passed by reference.
The debugger has limited understanding of array descriptors.
Comma is both the argument separator and a valid operator in C and C++. Hence,
argument lists are comma-separated
assignment-expressions
rather than
full expressions:
argument-expression-list
: assignment-expression
| assignment-expression COMMA argument-expression-list
arg-expression-list-opt
: [ argument-expression-list ]
assignment-expression
: assignment-expression for C
| assignment-expression for C++
| assignment-expression for Fortran
| assignment-expression for Ada
| assignment-expression for COBOL
The C++ constructors and destructors are not invoked, which may cause problems.
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.
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
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
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 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):
(ladebug) list $curline - 10: 20
1 long x = 5; // global x
2
3 int main()
4 {
5 int x = 7; // local x
6 int y = x - ::x;
> 7 return (y);
8 }
By default, a local variable is found before a global one,
so that the plain x
refers to the local variable:
(ladebug) whatis x
int x
(ladebug) which x
"x_rescoped.cxx"`main`x
(ladebug) whatis "x_rescoped.cxx"`main`x
int x
You can use the C++ ::
operator to specify the global
x
in C++ code or rescoped expressions in any language:
,
(ladebug) whatis ::x
long x
(ladebug) whatis "x_rescoped.cxx"`x
long x
(ladebug) print "x_rescoped.cxx"`x
5
In the following example,
the x
variable is used in the following places to
demonstrate how rescoping expressions can find the correct variable:
main
Foo
Foo
's member function SetandGet
CastAndAdd
function, but
visible as a parameter
(ladebug) list $curline - 10: 20
10 double x = 3.1415;
11
12 int CastAndAdd(char x) {
13 int result = ((int)::x) + x;
14 return result;
15 }
16
17 float Foo::SetandGet() { // multiple scopes!
18 long x = (long)::x; // local x = global x
19 Foo::x = (float)x; // member x = local x
> 20 return Foo::x; // return member x
21 }
22
23 int main () {
24 int x = 7;
25 x -= CastAndAdd((char)1);
26
27 Foo thefoo;
28 x -= (int)thefoo.SetandGet();
29 return x;
(ladebug) whatis x
long x
(ladebug) which x
"x_rescoped2.cxx"`Foo::SetandGet`x
(ladebug) whatis ::x
double x
(ladebug) whatis Foo::x
float Foo::x
(ladebug) whatis main`x
int x
(ladebug) whatis CastAndAdd`x
char x
When debugging a Fortran 90 program, you can refer to the components of a
module using rescoped expressions. For example, when SERIES
is a
module in the file fft.f90
, then "fft.f90"`SERIES`ORDER
refers to the component
ORDER
in the module SERIES
.
printable-type
: printable-type for C
| printable-type for C++
| printable-type for Fortran
| printable-type for Ada
| printable-type for COBOL
expression
: assignment-expression
constant-expression
: conditional-expression
identifier-or-typedef-name
: identifier-or-key-word
| TYPEDEFname
primary-expression
: identifier-or-key-word
| constant
| string-literal-list
| LPAREN expression RPAREN
| process_set
| LPAREN process_range RPAREN
string-literal-list
: string
| string-literal-list string
constant
: FLOATINGconstant
| INTEGERconstant
| CHARACTERconstant
| WIDECHARACTERconstant
| WIDESTRINGliteral
qual-typedef-opt
: TYPEDEFname
| qual-typedef-opt TICK TYPEDEFname
whatis-expressions
: expression
| rescoped-expression
| printable-type
call-expression
: expression
function-call
: postfix-expression LPAREN [arg-expression-list] RPAREN
Restrictions and limits are documented here.
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.
loc
is the following:
loc
: expression
| rescoped-expression
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
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
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
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
constant
: FLOATINGconstant
| INTEGERconstant
| CHARACTERconstant
| WIDECHARACTERconstant
| WIDESTRINGliteral
call-expression
: expression
Restrictions and limits are documented here.
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.
loc
:
loc
: expression
| rescoped-expression
whatis-expressions
: expression
| printable-type
qual-typedef-opt
: type-name
| qual-typedef-opt TICK type-name
string-literal-list
: string
| string-literal-list string
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
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
primary-expression : constant | string-literal-list | THIS | LPAREN expression RPAREN | operator-function-name | identifier-or-key-word | qualified-id | process_set | LPAREN process_range RPAREN operator-function-name : OPERATOR operator-predefined | OPERATOR basic-type-name | OPERATOR TYPEDEFname | OPERATOR LPAREN type-name RPAREN | OPERATOR type-qualifier | OPERATOR qualified-type operator-predefined : PLUS | MINUS | STAR | ... | DELETE | COMMA type-qualifier-list-opt : [ type-qualifier-list ] postfix-expression : primary-expression | postfix-expression LBRACKET expression RBRACKET | postfix-expression PARENS | postfix-expression LPAREN argument-expression-list RPAREN | postfix-expression LPAREN type-name-list RPAREN | postfix-expression DOT id-expression | postfix-expression ARROW id-expression | postfix-expression INCR | postfix-expression DECR | TYPEDEFname LPAREN argument-expression-list RPAREN | TYPEDEFname LPAREN type-name-list RPAREN | basic-type-name LPAREN assignment-expression RPAREN type-name-list : type-name | type-name COMMA type-name-list | type-name comma-opt-ellipsis | ELLIPSIS comma-opt-ellipsis : ELLIPSIS | COMMA ELLIPSIS unary-expression : postfix-expression | INCR unary-expression | DECR unary-expression | line-address | AMPERSAND cast-expression | STAR cast-expression | MINUS cast-expression | PLUS cast-expression | TWIDDLE LPAREN cast-expression RPAREN | NOT cast-expression | SIZEOF unary-expression | SIZEOF LPAREN type-name RPAREN | allocation-expression allocation-expression : operator-new LPAREN type-name RPAREN operator-new-initializer | operator-new LPAREN argument-expression-list RPAREN LPAREN type-name RPAREN operator-new-initializer operator-new : NEW | CLCL NEW operator-new-initializer : [ PARENS ] | [ LPAREN argument-expression-list RPAREN ] cast-expression : unary-expression | LPAREN type-name RPAREN cast-expression deallocation-expression : cast-expression | DELETE deallocation-expression | CLCL DELETE deallocation-expression | DELETE BRACKETS deallocation-expression | CLCL DELETE BRACKETS deallocation-expression point-member-expression : deallocation-expression | point-member-expression DOTstar deallocation-expression | point-member-expression ARROWstar deallocation-expression multiplicative-expression : point-member-expression | multiplicative-expression STAR point-member-expression | multiplicative-expression SLASH point-member-expression | multiplicative-expression MOD point-member-expression additive-expression : multiplicative-expression | additive-expression PLUS multiplicative-expression | additive-expression MINUS multiplicative-expression shift-expression : additive-expression | shift-expression LS additive-expression | shift-expression RS additive-expression relational-expression : shift-expression | relational-expression LESS shift-expression | relational-expression GREATER shift-expression | relational-expression LE shift-expression | relational-expression GE shift-expression equality-expression : relational-expression | equality-expression EQ relational-expression | equality-expression NE relational-expression AND-expression : equality-expression | AND-expression AMPERSAND equality-expression exclusive-OR-expression : AND-expression | exclusive-OR-expression HAT AND-expression inclusive-OR-expression : exclusive-OR-expression | inclusive-OR-expression OR exclusive-OR-expression logical-AND-expression : inclusive-OR-expression | logical-AND-expression ANDAND inclusive-OR-expression logical-OR-expression : logical-AND-expression | logical-OR-expression OROR logical-AND-expression conditional-expression : logical-OR-expression | logical-OR-expression QUESTION expression COLON conditional-expression assignment-expression : conditional-expression | unary-expression ASSIGNOP assignment-expression | unary-expression MULTassign assignment-expression | unary-expression DIVassign assignment-expression | unary-expression MODassign assignment-expression | unary-expression PLUSassign assignment-expression | unary-expression MINUSassign assignment-expression | unary-expression LSassign assignment-expression | unary-expression RSassign assignment-expression | unary-expression ANDassign assignment-expression | unary-expression ERassign assignment-expression | unary-expression ORassign assignment-expression
identifier-or-typedef-name
: identifier-or-key-word
| TYPEDEFname
| PROCEDUREname
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
qual-typedef-opt
: TYPEDEFname /* Base (global) name */
| qual-typedef-opt TICK TYPEDEFname /* Qualified name */
whatis-expressions
: expression
| rescoped-expression
| printable_type
call-expression
: call-stmt
call-stmt
: named-subroutine
| named-subroutine LPAREN RPAREN
| named-subroutine LPAREN actual-arg-spec-list RPAREN
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.
loc
is as follows:
loc
: expression
| rescoped-expression
type-name
: TYPEDEFname
printable-type
: rescoped-typedef
| type-name
expression : expr | named-procedure assignment-expression : expr constant-expression : constant unary-expression : variable expr : level-5-expr | expr defined-binary-op level-5-expr level-5-expr : equiv-operand | level-5-expr LOGEQV equiv-operand | level-5-expr LOGNEQV equiv-operand | level-5-expr LOGXOR equiv-operand equiv-operand : or-operand | equiv-operand LOGOR or-operand or-operand : and-operand | or-operand LOGAND and-operand and-operand : level-4-expr | LOGNOT and-operand level-4-expr : level-3-expr | level-3-expr LESS level-3-expr | level-3-expr GREATER level-3-expr | level-3-expr LE level-3-expr | level-3-expr GE level-3-expr | level-3-expr EQ level-3-expr | level-3-expr NE level-3-expr level-3-expr : level-2-expr | level-3-expr SLASHSLASH level-2-expr level-2-expr : add-operand | level-2-expr PLUS add-operand | level-2-expr MINUS add-operand add-operand : add-operand-f90 | add-operand-dec | unary-expr-dec add-operand-f90 : mult-operand-f90 | add-operand-f90 STAR mult-operand-f90 | add-operand-f90 SLASH mult-operand-f90 mult-operand-f90 : level-1-expr | level-1-expr STARSTAR mult-operand-f90 add-operand-dec : mult-operand-dec | add-operand-f90 STAR mult-operand-dec | add-operand-f90 SLASH mult-operand-dec | add-operand-f90 STAR unary-expr-dec | add-operand-f90 SLASH unary-expr-dec mult-operand-dec : level-1-expr STARSTAR mult-operand-dec | level-1-expr STARSTAR unary-expr-dec unary-expr-dec : PLUS add-operand | MINUS add-operand level-1-expr : primary | defined-unary-op primary defined-unary-op :
DOT_LETTERS_DOT primary : constant | variable | function-reference | LPAREN expr RPAREN | AMPERSAND variable | process_set | LPAREN process_range RPAREN defined-binary-op :
DOT_LETTERS_DOT int-expr : expr scalar-int-expr : int-expr variable : named-variable | subobject named-variable : variable-name subobject : array-elt-or-sect | structure-component | known-substring known-substring : disabled-array-elt-or-sect LPAREN substring-range RPAREN | hf-array-abomination substring-range : scalar-int-expr COLON scalar-int-expr | scalar-int-expr COLON | COLON scalar-int-expr | COLON hf-array-abomination : named-variable LPAREN section-subscript-list RPAREN LPAREN section-subscript RPAREN | structure PERCENT any-identifier LPAREN section-subscript-list RPAREN LPAREN section-subscript RPAREN | structure DOT any-identifier LPAREN section-subscript-list RPAREN LPAREN section-subscript RPAREN disabled-array-elt-or-sect : DISABLER array-elt-or-sect array-elt-or-sect : named-variable LPAREN section-subscript-list RPAREN | structure PERCENT any-identifier LPAREN section-subscript-list RPAREN | structure DOT any-identifier LPAREN section-subscript-list RPAREN section-subscript-list : section-subscript | section-subscript COMMA section-subscript-list subscript : scalar-int-expr section-subscript : subscript | subscript-triplet subscript-triplet : subscript COLON subscript COLON stride | subscript COLON COLON stride | COLON subscript COLON stride | COLON COLON stride | subscript COLON subscript | subscript COLON | COLON subscript | COLON stride : scalar-int-expr structure-component : structure PERCENT any-identifier | structure DOT any-identifier structure : named-variable | structure-component | array-elt-or-sect function-reference : SIZEOF LPAREN expr RPAREN | named-function LPAREN RPAREN | named-function LPAREN actual-arg-spec-list RPAREN named-procedure : PROCEDUREname named-function : PROCEDUREname named-subroutine : PROCEDUREname actual-arg-spec-list : actual-arg-spec | actual-arg-spec COMMA actual-arg-spec-list actual-arg-spec : actual-arg actual-arg : expr any-identifier : variable-name | PROCEDUREname variable-name : identifier-or-key-word PROCEDUREname : IDENTIFIER
constant
: FLOATINGconstant
| INTEGERconstant
| CHARACTERconstant
qual-typedef-opt
: TYPEDEFname
| qual-symbol-opt TICK TYPEDEFname
whatis-expressions
: expression
| rescoped-expression
| printable_type
call-expression
: expression
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
loc
is as follows:
loc
: expression
| rescoped-expression
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
primary-expression
: identifier-or-key-word
| constant
| string-literal-list
| LPAREN expression RPAREN
| process_set
| LPAREN process_range RPAREN
postfix-expression
: primary-expression
| postfix-expression LBRACKET expression RBRACKET
| postfix-expression LPAREN arg-expression-list-opt RPAREN
| postfix-expression DOT identifier-or-typedef-name
| postfix-expression ARROW identifier-or-typedef-name
| postfix-expression INCR
| postfix-expression DECR
string-literal-list
: string
| string-literal-list string
unary-expression
: postfix-expression
| INCR unary-expression
| DECR unary-expression
| AMPERSAND cast-expression
| line-address
| STAR cast-expression
| PLUS cast-expression
| MINUS cast-expression
| TWIDDLE cast-expression
| NOT cast-expression
cast-expression
: unary-expression
| LPAREN type-name RPAREN cast-expression
multiplicative-expression
: cast-expression
| multiplicative-expression STAR cast-expression
| multiplicative-expression SLASH cast-expression
| multiplicative-expression MOD cast-expression
additive-expression
: multiplicative-expression
| additive-expression PLUS multiplicative-expression
| additive-expression MINUS multiplicative-expression
shift-expression
: additive-expression
| shift-expression LS additive-expression
| shift-expression RS additive-expression
relational-expression
: shift-expression
| relational-expression LESS shift-expression
| relational-expression GREATER shift-expression
| relational-expression LE shift-expression
| relational-expression GE shift-expression
equality-expression
: relational-expression
| equality-expression EQ relational-expression
| equality-expression NE relational-expression
AND-expression
: equality-expression
| AND-expression AMPERSAND equality-expression
exclusive-OR-expression
: AND-expression
| exclusive-OR-expression HAT AND-expression
inclusive-OR-expression
: exclusive-OR-expression
| inclusive-OR-expression OR exclusive-OR-expression
logical-AND-expression
: inclusive-OR-expression
| logical-AND-expression ANDAND inclusive-OR-expression
logical-OR-expression
: logical-AND-expression
| logical-OR-expression OROR logical-AND-expression
conditional-expression
: logical-OR-expression
| logical-OR-expression QUESTION expression COLON conditional-expression
assignment-expression
: conditional-expression
| unary-expression ASSIGNOP assignment-expression
| unary-expression MULTassign assignment-expression
| unary-expression DIVassign assignment-expression
| unary-expression MODassign assignment-expression
| unary-expression PLUSassign assignment-expression
| unary-expression MINUSassign assignment-expression
| unary-expression LSassign assignment-expression
| unary-expression RSassign assignment-expression
| unary-expression ANDassign assignment-expression
| unary-expression ERassign assignment-expression
| unary-expression ORassign assignment-expression
expression
: assignment-expression
constant-expression
: conditional-expression
abstract-declarator
: unary-abstract-declarator
| postfix-abstract-declarator
| postfixing-abstract-declarator
postfixing-abstract-declarator
: array-abstract-declarator
| LPAREN RPAREN
array-abstract-declarator
: BRACKETS
| LBRACKET constant-expression RBRACKET
| array-abstract-declarator LBRACKET constant-expression RBRACKET
unary-abstract-declarator
: STAR
| STAR abstract-declarator
postfix-abstract-declarator
: LPAREN unary-abstract-declarator RPAREN
| LPAREN postfix-abstract-declarator RPAREN
| LPAREN postfixing-abstract-declarator RPAREN
| LPAREN unary-abstract-declarator RPAREN postfixing-abstract-declarator
constant
: FLOATINGconstant
| INTEGERconstant
| DECIMALconstant
| CHARACTERconstant
constant-expression
: cobol-expression
qual-typedef-opt
: TYPEDEFname
| qual-typedef-opt TICK TYPEDEFname
call-expression
: identifier-or-key-word
| identifier-or-key-word USING cobol-expression-list
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
loc
: cobol-identifier
| rescoped-expression
printable-type
:
rescoped-typedef
assignment-expression : expression cobol-expression : cobol-identifier | constant | string | cobol-expression PLUS cobol-expression | cobol-expression MINUS cobol-expression | cobol-expression STAR cobol-expression | cobol-expression SLASH cobol-expression | cobol-expression EXPON cobol-expression | MINUS cobol-expression | PLUS cobol-expression | LPAREN cobol-expression RPAREN | process_set | LPAREN process_range RPAREN cobol-expression-list : cobol-expression | cobol-expression COMMA cobol-expression-list cobol-identifier : qualification | subscript | refmod condition-expression : combined-condition | negated-simple-condition combined-condition : negated-simple-condition AND negated-simple-condition | negated-simple-condition OR negated-simple-condition | LPAREN combined-condition RPAREN negated-simple-condition : simple-condition | NOT simple-condition | LPAREN NOT simple-condition RPAREN simple-condition : cobol-expression EQ cobol-expression | cobol-expression ASSIGNOP cobol-expression | cobol-expression NE cobol-expression | cobol-expression LESS cobol-expression | cobol-expression GREATER cobol-expression | cobol-expression LE cobol-expression | cobol-expression GE cobol-expression | cobol-expression SIGNPOS | cobol-expression SIGNNEG | cobol-expression SIGNZERO | cobol-expression SIGNNOTZERO | LPAREN simple-condition RPAREN expression : constant-expression | condition-expression | address-language identifier-or-typedef-name : identifier-or-key-word lvalue-expression : cobol-identifier qualification : identifier-or-key-word OF qualification | identifier-or-key-word refmod : qualification LPAREN cobol-expression COLON RPAREN | qualification LPAREN cobol-expression COLON cobol-expression RPAREN | subscript LPAREN cobol-expression COLON RPAREN | subscript LPAREN cobol-expression COLON cobol-expression RPAREN subscript : qualification LPAREN cobol-expression-list RPAREN unary-expression : lvalue-expression whatis-expressions : expression | rescoped-expression | rescoped-typedef
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. % 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.
The stack trace lists the functions in your program that were active when the
dump occurred. By examining the values of a few variables along with
the stack trace, you may be able to pinpoint the process state and the cause
of the core dump. Core files cannot be executed; therefore the rerun
,
step
, cont
, and other commands will not work until you create
a process using the run
command.
In addition, if the program is multithreaded, you can examine the thread
information with the
show thread
and
thread
commands. You can
examine the stack trace for a particular thread or for all threads with the
where thread
command.
The following example uses a null pointer reference in the factorial
function.
This reference causes the process to abort and dump the core when it is
executed. The dump
command prints the value of the x
variable
as a null, and the print *x
command reveals that you cannot
dereference a null pointer.
% cat testProgram.c
#include <stdio.h>
int factorial(int i)
main() {
int i,f;
for (i=1 ; i<3 ; i++) {
f = factorial(i);
printf("%d! = %d\en",i,f);
}
}
int factorial(int i)
int i;
{
int *x;
x = 0;
printf("%d",*x);
if (i<=1)
return (1);
else
return (i * factorial(i-1) );
}
% cc -o testProgram -g testProgram.c
% testProgram
Memory fault - core dumped.
% ladebug testProgram core
Welcome to the Ladebug Debugger Version n
------------------
object file name: testProgram
core file name: core
Reading symbolic information ...done
Core file produced from executable testProgram
Thread terminated at PC 0x120000dc4 by signal SEGV
(ladebug) where
>0 0x120000dc4 in factorial(i=1) testProgram.c:13
#1 0x120000d44 in main() testProgram.c:4
(ladebug) dump
>0 0x120000dc4 in factorial(i=1) testProgram.c:13
printf("%d",*x);
(ladebug) print *x
Cannot dereference 0x0
Error: no value for *x
(ladebug)
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:
% ladebug a.out core
(ladebug) listobj
(ladebug) quit
/usr/shlib/
.
/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.)
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
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.
% mkdir mybug
% cd mybug
% mv <wherever>/mybug.tar .
applibs
and dbglibs
:
% mkdir applibs dbglibs
tar s
option to strip off
any leading slashes from pathnames during extraction:
% tar xfvs mybug.tar
/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.
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
libpthreaddebug.so.
% env LADEBUG_COREFILE_LIBRARY_PATH=applibs \
LD_LIBRARY_PATH=dbglibs \
ladebug a.out core
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.
(ladebug)
% a.out -segv
Segmentation fault (core dumped)
% ladebug a.out core
Welcome to the Ladebug Debugger Version n
------------------
object file name: a.out
core file name: core
Reading symbolic information ...done
Core file produced from executable a.out
Thread 0x5 terminated at PC 0x3ff8058b448 by signal SEGV
(ladebug) listobj
section Start Addr End Addr
------------------------------------------------------------------------------
a.out
.text 0x120000000 0x120003fff
.data 0x140000000 0x140001fff
/usr/shlib/libpthread.so
.text 0x3ff80550000 0x3ff8058bfff
.data 0x3ffc0180000 0x3ffc018ffff
.bss 0x3ffc0190000 0x3ffc01901af
/usr/shlib/libmach.so
.text 0x3ff80530000 0x3ff8053ffff
.data 0x3ffc0170000 0x3ffc0173fff
/usr/shlib/libexc.so
.text 0x3ff807b0000 0x3ff807b5fff
.data 0x3ffc0210000 0x3ffc0211fff
/usr/shlib/libc.so
.text 0x3ff80080000 0x3ff8019ffff
.data 0x3ffc0080000 0x3ffc0093fff
.bss 0x3ffc0094000 0x3ffc00a040f
(ladebug) quit
libpthread.so
is included, so add
/usr/shlib/libpthreaddebug.so
to the list.
% 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.
% mkdir mybug
% cd mybug
% mv <wherever>/mybug.tar .
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
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.
% 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.
% env LADEBUG_COREFILE_LIBRARY_PATH=applibs \
LD_LIBRARY_PATH=dbglibs \
ladebug a.out core
Welcome to the Ladebug Debugger Version n
------------------
object file name: a.out
core file name: core
Reading symbolic information ...done
Core file produced from executable a.out
Thread 0x5 terminated at PC 0x3ff8058b448 by signal SEGV
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
(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
%
First, do the following steps on the original system:
ladebug a.out core
listobj; quit
/usr/shlib/libpthreaddebug.so
, if libpthread.so
tar cfvh mybug.tar a.out core <shlibs>
mkdir mybug
cd mybug
mv mybug.tar
mkdir applibs dbglibs
tar sfvc mybug.tar
mv usr/shlib/* applibs
ln -s ../applibs/libptheaddebug.so dbglib/libptheaddebug.so
cd dbglibs
ln -s ../applibs/libpthreaddebug.so libpthreaddebug.so
cd ..
env LADEBUG_COREFILE_LIBRARY_PATH=applibs \
LD_LIBRARY_PATH=dbglibs \
ladebug a.out core
listobj
This chapter discusses kernel debugging and contains information for each type of kernel debugging that you may use.
This chapter contains the following sections:
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.
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.
Ideally, the kernel should be compiled without full optimization and without stripping the kernel of its symbol table information, so that the debugger can provide you with the most information in the most friendly manner. However, most of the time this is not the case, and you are working with a stripped-down, highly optimized kernel. In these cases, the debugger is limited in what it can display. Information relating to source files is not available, and often function parameters and other variables are "optimized away."
The kernel is a complex piece of software. It contains kernel processes denoted by a process ID (pid). Some of these processes relate to user processes, and some are kernel specific.
NOTE: Because the debugger supports multiprocessing as well as kernel debugging, you need to be able to distinguish between processes that the debugger is managing, and processes being managed within the kernel.
Because the debugger command for managing multiple processes is
process
, this
chapter refers to a process being debugged as a process, and refers
to a process within the kernel being debugged as a pid.
The debugger maintains two extra debugger variables when debugging a kernel:
$pid
and $tid
. These variables assist
you in establishing and changing the user context while debugging the
kernel.
The $pid
variable contains the current pid that you are
examining. You can switch the context to another pid within the kernel by
setting $pid
to the desired value. The debugger variable
$curprocess
, which is read-only,
does not change. The value in the $curprocess
variable is how the
debugger refers to the kernel process as a whole. Typically, this value is
the actual kernel process listed as [kernel idle]
with the
ps
system command (or Ladebug
kps
command), but
not always. In any case, the $pid
variable controls the pid
that you are
examining within the kernel.
The $tid
variable contains the current thread ID that you
are examining. It, too, can be used to switch the user context to a different
thread (it simply calls the
thread
command with its new value).
The debugger also supplies a kps
command, which displays all
the pids in the kernel. This command is not available for
remote kernel debugging.
kernel_debugging_command
: kps
For example, if you wanted to examine the stack of the kloadsrv
daemon, you would first find out its pid:
(ladebug) kps
00000 kernel idle
00001 init
00003 kloadsrv
00020 update
02082 dtexec
02092 dtterm
02093 csh
...
Then set the $pid
accordingly and enter the
where
command:
(ladebug) set $pid = 3 (ladebug) where >0 0xfffffc00002b3a10 in thread_block()
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
You can specify addresses in the KSEG segment by prefixing the
hexadecimal offset of the address with 0k
; the debugger adds the
KSEG base address to any such hexadecimal constant. For example,
the constant 0k2400
is converted by the debugger into the
actual address for the location at offset 0x2400 into the KSEG segment.
libdpi
as a Shared Object
Tru64 UNIX provides libdpi
(Debugger Process Interface library) for interacting with the
kernel. The archive form (libdpi.a
) is built into the debugger so kernel developers
can debug the Tru64 UNIX kernel.
However, kernel developers can also access libdpi
as an external shared object. This is useful
for the following tasks:
libdpi
libdpi
that is
compatible with the target kernel
If you need to use a libdpi
that is different from the one
linked into the debugger, contact Ladebug engineering for instructions
on how to create an appropriate shared object version and how to use it.
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).
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.
The operating system can crash in the following ways:
trap()
function being invoked.
panic()
function.
If the system crashes because of a hardware fault or an unrecoverable software
state, a dump function is invoked. The dump function copies the core memory
into the primary default swap disk area as specified by the
/etc/fstab
file structure table and the
/sbin/swapdefault
file. At system reboot time, the information is
copied into a file, called a crash dump file. Crash dump files are either
partial (the default) or full. See HP TRU64 UNIX Kernel
Debugging for more information.
You can analyze the crash dump file to determine what caused the crash. For
example, if a hardware trap occurred, you can examine variables, such as
savedefp
, the program counter ($pc
), and the stack
pointer ($sp
), to help you determine why the crash occurred. If a
software panic caused the crash, you can use the debugger to examine the crash
dump and use the uerf
utility to examine the error log. Using these
tools, you can determine which function called the panic()
routine.
When you examine crash dump files, there is no one way to determine the cause of a system crash. However, the following guidelines can help you identify the events that led to the crash:
pmsgbuf
, and in the
panicstr
global variable.
where
command.) Most likely, this thread will contain the
events that led to the panic.
For more information and for examples, see HP TRU64 UNIX Kernel Debugging. This manual contains detailed information on the following topics related to crash dump analysis:
crashdc
utility
You can find HP Tru64 UNIX crash dump files in /var/adm/crash
.
There you will find a copy of the kernel that crashed
(vmunix.number
) and the core memory file
(vmcore.number
or
vmzcore.number
, depending on the operating system
version). The number appended to these files distinguishes crashes, with the
highest number denoting the most recent crash. These files are owned by
root
, so you must have root permissions to access them.
To invoke the debugger on a kernel crash dump numbered 0 (zero), enter the following command:
# ladebug -k vmunix.0 vmzcore.0
On startup, the debugger analyzes the core file to determine the final PC address of the crash, and outputs that information. You can use the debugger to inspect kernel data structures, global variables (such as the panic string), and kernel thread stacks, in order to determine why the kernel crashed.
If you are going to view the stack using the
where
, up
,
down
, and dump
commands, you may want to set the control variable
$stackargs
to 0 (zero) to suppress
the output of argument values, The kernel is typically compiled for high
performance, which means those argument values have been optimized away. If
the debugger is set to look for those arguments and cannot find them, it
notifies you with error messages, causing the stack output to be full of
repetitious warnings.
When debugging a kernel memory fault, verify that the core memory has not been
corrupted; otherwise, the debugger may present erroneous information. One quick
way to check this is by comparing the global panic string with the panic string
in the machine_slot
structure of the machine that caused the
crash. Select the appropriate machine_slot
structure name depending
on your operating system version, as follows:
machine_slot[paniccpu]
.
processor_ptr[paniccpu].m
.
If the strings are different, the core memory file may be corrupted. The following example shows how to compare these strings:
# ladebug -k vmunix.0 vmzcore.0 Welcome to the Ladebug Debugger Version n ------------------ object file name: vmunix.0 core file name: vmzcore.0 Reading symbolic information ...done Thread terminated at PC 0xfffffc0000457a48 done (ladebug) print panicstr 0xfffffc0000640970="kernel memory fault" <== memory fault (ladebug) print utsname struct utsname { sysname = "OSF1"; nodename = ""; release = "X5.1"; <== 5.n system version = "730"; machine = "alpha"; } (ladebug) print processor_ptr[paniccpu].m struct machine_slot { is_cpu = 1; cpu_type = 15; cpu_subtype = 22; running = 1; cpu_ticks = [0] = 0,[1] = 0,[2] = 0,[3] = 0,[4] = 0; clock_freq = 1200; error_restart = 0; cpu_panicstr = 0xfffffc0000640970="kernel memory fault"; <== strings match cpu_panic_thread = 0xfffffc0001c51180; }
When you debug your code by working with a crash dump file, you can examine the
exception frame using the debugger. The variable savedefp
contains
the location of the exception frame. (No exception frames are created when you
force a system to dump.) Refer to the header file
/usr/include/machine/reg.h
to determine where registers are stored
in the exception frame. The following example shows an exception frame:
(ladebug) print savedefp/33X ffffffff9618d940: 0000000000000000 fffffc000046f888 ffffffff9618d950: ffffffff86329ed0 0000000079cd612f . . . ffffffff9618da30: 0000000000901402 0000000000001001 ffffffff9618da40: 0000000000002000
You can use the debugger to extract the preserved message buffer from a running system or use dump files to display system messages logged by the kernel. For example:
(ladebug) print *pmsgbuf struct msgbuf { msg_magic = 405601; msg_bufx = 1851; msg_bufr = 1343; msg_bufc = "Alpha boot: available memory from 0x6ca000 to 0x3f16000\nTru64 UNIX V.n (Rev. 564); Fri Jul 11 11:25:29 EDT 1997 \nphysical m"; }
The print
command is regulated in length by the
$maxstrlen
debugger variable. Also,
the print
command does not expand the new line character. To see the
full message string as formatted text, use the following command:
(ladebug) printf "%s",pmsgbuf->msg_bufc
The crashdc
utility collects critical data from operating system
crash dump files or from a running kernel. You can use the data it collects to
analyze the cause of a system crash. The crashdc
utility uses
existing system tools and utilities to extract information from crash dumps. The
information garnered from crash dump files or from the running kernel includes
the hardware and software configuration, current processes, the panic string (if
any), and swap information.
See HP TRU64 UNIX Kernel Debugging and
crashdc
(8) for more information.
For remote kernel debugging, use the Ladebug debugger in conjunction with
the kdebug
debugger, which is a tool for executing, testing, and
debugging test kernels.
Used alone, kdebug
has its own syntax and commands, and allows
local non-symbolic debugging of a running kernel across a serial line. See
kdebug
(8) for information about kdebug
local
kernel debugging.
You use Ladebug commands to start and stop kernel execution, examine variable
and register values, and perform other debugging tasks, just as you would when
debugging user-space programs. The kdebug
debugger, not the Ladebug
debugger, performs the actual reads and writes to registers, memory, and the
image itself (for example, when breakpoints are set).
The kernel code to be debugged runs on a test system. The Ladebug debugger runs on a remote build system and communicates with the kernel code over a serial communication line or through a gateway system.
You use a gateway system when you cannot physically connect the test and build systems. Connect the build system to the gateway system over a network. Connect the gateway system to the test system by a serial communication line.
The following diagram shows the physical connection of the test and build systems (with no gateway):
Build system Serial line Test system (with the Ladebug <-------------------------> (kernel code here) debugger)The following diagram shows the connections when you use a gateway system:
Build system Network Gateway Serial line Test system (with the Ladebug <-----------> system <-------------> (kernel code debugger) with here) kdebug daemon
The serial line provides a physical connection between communication ports on two systems; it consists of a BC16E cable and two H8571-J DECconnect Passive Adapters:
The test system always uses the same communication port for kdebug
debugger input and output:
/dev/tty00
at installation time.
ace
console serial interface operating as the test system, this
device is always the serial communications port 2 identified as
/dev/tty01
.
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:
/dev/tty00
at installation time.
kdebug
in /etc/remote
. By
default, this device is the serial communications port 1 identified as
/dev/tty00
, but you can change it if desired by modifying
/etc/remote
.
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.
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:>>> set console serial
This redirects all console input and output to serial communication port 1
(/dev/tty00
).
/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:
% tip tstsys
You can use this separate window as the console for the test system.
>>> set console graphics
tip
on the build or gateway system by entering a
tilde and a period (˜.
).
The test, build, and (if used) gateway systems must meet the following
requirements for kdebug
:
Test system: Must be running Version 2.0 or higher of the Tru64 UNIX operating system, must have the Kernel Debugging Tools subset loaded, and must have the Kernel Breakpoint Debugger kernel option configured.
Build system: Must be running Version 3.2 or higher of the Tru64 UNIX operating system. Also, this system must contain a copy of the kernel code you are testing and, preferably, the source used to build that kernel code.
You can verify the status of each of the system requirements by the using the following commands:
Tru64 operating system version: Enter the command:
% uname -a
Kernel Debugging Tools subset: Enter the command:
% setld -i | grep -i kernel | grep installed
Kernel Breakpoint Debugger kernel option: There are two methods to verify this option:
% /sbin/sysconfig -s kdebug
This should indicate that kdebug
is loaded and configured.
Look for a file in /sys/config
with the same name as the
node in question, except in all uppercase characters. For example, if
the name of the node is "mine", look for a file named
/sys/config/MINE
and search it for a line containing
"options KDEBUG". If present, it means the Kernel Breakpoint Debugger
kernel option has been configured.
To use the kdebug
debugger, do the following:
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.
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.
Copy the kernel to be tested to /vmunix
on the test system.
Retain an exact copy of this image on the build system.
Install the Product Authorization Key (PAK) for the Developers' kit (OSF-DEV) if it is not already installed. For information about installing PAKs, see the HP Tru64 UNIX Software License Management manual.
Determine the debugger variable settings or command-line options you will
use. On the build system, add the following lines to your
.dbxinit
file if you need to override the default values (and
you choose not to use the corresponding options).
Alternatively, you can use the following lines within the debugger session, at the
(ladebug)
prompt:
(ladebug) set $kdebug_host="<name_of_your_gateway_system>" (ladebug) set $kdebug_line="<name_of_your_serial_line>" (ladebug) set $kdebug_dbgtty="<name_of_your_tty>"
$kdebug_host
specifies the node or address of the gateway
system. By default, $kdebug_host
is set to
localhost
when a gateway system is not used. For example:
(ladebug) set $kdebug_host="decosf"
$kdebug_line
specifies the serial line to use as defined in
the /etc/remote
file of the build system (or the gateway
system, if one is being used). By default, $kdebug_line
is
set to kdebug
. For example:
(ladebug) set $kdebug_line="kdebug"
$kdebug_dbgtty
sets the terminal on the gateway system to
display the communication between the build and test systems, which is
useful in debugging your setup. To determine the terminal name to supply
to the $kdebug_dbgtty
variable, enter the tty
command in the desired window on the gateway system. By default,
$kdebug_dbgtty
is null. For example:
(ladebug) set $kdebug_dbgtty="/dev/ttyp2"
Instead of using debugger variables, you can specify any of the following
options on the ladebug
command line:
The -rn
option specifies the node or address of the gateway
system, and can be used instead of $kdebug_host
.
The -line
option specifies the serial line, and can be used
instead of $kdebug_line
.
The -tty
option specifies the terminal name, and can be
used instead of $kdebug_dbgtty
.
The preceding three options require the -remote
option or its
alternative, the -rp kdebug
option, for example:
# ladebug -remote -rn "decosf" -line "kdebug" -tty "/dev/ttyp2" /usr/test/vmunixThe
-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.
If you are debugging on a 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.
When the setup is complete, start the debugger as follows:
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.
Halt the test system:
# shutdown -h now
At the console prompt, set the boot_osflags
console variable to
contain the value k
(the default is usually the value
a
). For example:
>>> set boot_osflags k
Alternatively, you can enter the following command:
>>> boot -flags k
You can abbreviate the boot
command to b
and the
-flags
option to -fl
. The
boot
command without the -flags
option boots the
machine using the current value for boot_osflags
; with the
-flags
option, it uses the value specified in the option and
does not change the value of the boot_osflags
console variable.
Other useful commands from the console prompt include show
,
which lists the values of console variables, and help
, which
provides information about other commands. For more information about the
boot_osflags
values, see the HP Tru64 UNIX
System Administration manual and the HP Tru64 UNIX
Installation Guide.
With the Ladebug debugger started and waiting at a (ladebug)
prompt with breakpoints already set and the test system waiting at the
console prompt (>>>), start both the Ladebug debugger and test system kernel
executing. You can start them in either order as follows:
Start the Ladebug debugger:
(ladebug) run
Start the test system:
>>> bootor
>>> boot -flags k
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.
kdebug
setup and it fails to work, read
this section for help:
Be sure the serial line is attached properly. Use the
tip
command to test the connection. Log on to
the build system (or the gateway system if one is being used) as root and
enter the following command:
# tip kdebug
If the command does not return the message "connected," another process,
such as a print daemon, might be using the serial line port that you have
dedicated to the kdebug
debugger. To remedy this condition, do
the following:
Check the /etc/inittab
file to see if any processes are
using that line. If so, disable these lines until you finish with the
kdebug
session. See inittab
(4) for information
on disabling lines.
Use the ps
command to see if any processes
are using the line. For example, if you are using the
/dev/tty00
serial port for your kdebug
session, check for other processes using the serial line as follows:
# ps agxt00
If a process is using tty00
, kill that process.
Determine whether any unused kdebugd
gateway daemons are
running:
# ps agx | grep kdebugd
If one is running, kill the process.
kdebug
has not been configured into the kernel as specified in the section Getting Ready to Use the kdebug Debugger. Ensure
that the boot_osflags
console environment variable
specifies the k
flag and try booting the system again:
>>> set boot_osflags k >>> boot
.dbxinit
file correctly, or specify them correctly on the
command line. Determine the pseudoterminal line from which you ran
tip
by issuing the /usr/bin/tty
command.
For example:
# /usr/bin/tty /dev/ttyp2
The example shows that you are using pseudoterminal
/dev/ttyp2
. Edit your $HOME/.dbxinit
file on
the build system as follows:
Set the $kdebug_dbgtty
variable to
/dev/ttyp2
with this command:
(ladebug) set $kdebug_dbgtty="/dev/ttyp2"
Set the variable $kdebug_host
to the host name of the
system from which you entered the tip
command. For example,
if the host name is decosf
, the entry in the
.dbxinit
file should be:
(ladebug) set $kdebug_host="decosf"
Remove any settings of the $kdebug_line
variable:
(ladebug) set $kdebug_line=""
/dev/ttyp2
, which
kdebug
is starting.
If you are using a gateway system, ensure that the inetd
daemon
is running on the gateway system. Also, check the TCP/IP connection between
the build and gateway system using one of the following commands:
rlogin
, rsh
, or
rcp
.
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:
/
and ?
)
display the values stored in memory.
print
command,
with the appropriate pointer arithmetic, prints the value contained at the
address in decimal.
printregs
command
prints the values of all machine-level registers.In addition to examining memory, you can also search memory in 32-bit and 64-bit chunks.
/
and ?
) to print the
value contained at the address in one
of a number of formats (decimal, octal, hexadecimal, and so on). See
Memory Display Commands for more information.
The debugger also maintains the
$readtextfile
debugger variable, which allows you to view the
data from the text section of the executable directly
from the binary file, rather than reading it from memory. You can use
this variable to speed up the reading of instructions during kernel
debugging, however, remember that you are reading from the file and
not from the live image, which could be different.
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)
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.
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.
The debugger interaction with the target modifies the target state enough that the store conditional is guaranteed to fail. So that users can make progress, the debugger normally steps over the entire sequence as though it were one big instruction. This allows the application to continue normally.
To debug inside the sequence, while understanding
that this implies failure of the store, set a
breakpoint inside the sequence and continue to the breakpoint.
From there, you will be able to stepi
or
nexti
.
Ladebug supports the following parallel launchers:
prun
)
mpirun
)
dmpirun
)
This chapter contains the following sections:
[0-41] Welcome to the Ladebug Debugger Version n | Process range
[0-41]>2 0x120006d6c in feedback(myid=[0;41],np=42,name=0x11fffe018="mytest") "mytest.c":41 | | Process range Value range
Another challenge of debugging massively parallel applications is controlling all processes or subsets of the parallel application's processes from the debugger in a consistent manner. The Ladebug debugger allows you to control all or a subset of your processes through a single user interface. At the startup of a parallel debugging session, Ladebug does the following:
The root debugger is responsible for starting your parallel application and serves as your user interface. The aggregators perform output consolidation as described previously. The leaf debuggers control and query your application processes.
The branching factor is the factor used to build the n-nary tree and determine the number of aggregators in the tree. For example, for 16 processes:
You can set the value of the $parallel_branchingfactor
variable
from its default value of 8 to a value equal to or greater than 2 in the ladebug initialization
file (.ladebugrc
, and so on).
When you delete $parallel_branchingfactor
from the ladebug
initialization
file, the branching factor used in the startup mechanism is the
default value.
Aggregator delay specifies the time that aggregators wait before they aggregate and send messages down to the next level when not all of the expected messages have been received.
You can change the value of the $parallel_aggregatordelay
variable
from its default value of 3000 milliseconds in the ladebug
initialization file
(.ladebugrc
, etc.). See Parallel Debugging Tips for more
information.
When you delete $parallel_aggregatordelay
from the ladebug initialization
file, the aggregator delay used in the startup mechanism is the
default value.
NOTE: You can only change the values that are set for
$parallel_branchingfactor
and
$parallel_aggregatordelay
at startup, in the
.ladebugrc
file. After the program has started up, you cannot change
these values.
N
represents number of processes):
prun
launcher on
SC clusters:
% which ladebug /usr/bin/ladebug % setenv LADEBUG_HOME /usr/bin/ % which prun /bin/prun % ladebug -parallel /bin/prun -n N [prun options] /full/path/to/your/application
NOTE: Specify a full path both to your prun
launcher and to
your application's executable.
mpich
public
domain mpirun
launcher:
% which ladebug /usr/bin/ladebug % setenv LADEBUG_HOME /usr/bin/ % which mpirun /bin/mpirun % mpirun -dbg=ladebug -np N [mpich options] /full/path/to/your/application
NOTE: Specify a full path both to your mpirun
launcher and to
your application's executable. Make sure that there is a file called
mpirun_dbg.ladebug
in the directory in which
mpirun
is located.
dmpirun
launcher:
% which ladebug /usr/bin/ladebug % setenv LADEBUG_HOME /usr/bin/ % which dmpirun /bin/dmpirun % ladebug -parallel /bin/dmpirun -np N [dmpirun options] /full/path/to/your/applicationNOTE: Specify a full path both to your
dmpirun
launcher and to
your application's executable.
You can now set any necessary breakpoints and
use the continue
command to continue the execution
of your application.
The following table shows debugger commands that can be accessed remotely, locally, and both remotely and locally for parallel debugging; and Ladebug commands that are disabled for parallel debugging.
Local |
|||
#
/
?
assign
call
catch
class
cont/conti
delete
delsharedobj
disable
down
dump
enable
examine_address
file
func
goto
history
if
ignore
kill
list
listobj
map/unmap source directory
next/nexti
pop
print
printb
printd
printf
printi
printo
printregs
printt
printx
process
readsharedobj
return
show condition
show mutex
show process
show source directory
show thread
status
step/stepi
stop/stopi
thread
trace/tracei
use/unuse
up
watch
whatis
when/wheni
where/whereis
which |
!/history
alias/unalias
edit
export
help
playback
quit
record/unrecord
source |
export
set/setenv
sh
unset/unsetenv |
attach/detach
kps
load/unload
patch
printenv
rerun
run
snapshot |
Remote means commands will be sent to the leaf debuggers. Local means that commands are not sent to the leaf debuggers but are processed by the local Ladebug.
In addition to the commands listed in the table, you can use four other Ladebug commands to assist parallel debugging:
parallel_debugging_command :focus_command |show_process_set_command |show_aggregated_message_command |expand_aggregated_message_command
When there are many processes, it can be annoying or impractical to enumerate all the processes when one needs to focus on specific processes. Therefore, Ladebug introduces the concept of "process sets" and "process ranges" to let the user specify a group of processes in a compact form. Moreover, process sets come with the usual set operations, and both the sets and the ranges can be stored in debugger variables for manipulation, reference, or inspection at a later time.
A process set is a bracketed list of process ranges separated by commas.
NOTE: Because brackets ([..]) are part of the process set syntax, this section shows optional syntactic items enclosed in curly braces ({..}).
process_set : [ ] | [ process_range {,...} ]
NOTE: The set can be empty. A process range has the following three forms:
process_range : * | expression | { expression } : { expression }
In the first form, the star (*
) specifies all processes. You can use the second form as follows:
p
, then the range contains the process with pid p
only. r
, then the process range is the same as r
. You can use the third form to specify a contiguous range of processes. For example, 10:12
stands for the processes associated with pids
10, 11, and 12.
NOTE: A range whose lower bound is greater than its upper bound is illegal and will be ignored.
Because both the lower bound and the upper bound are optional, you can specify ranges as follows:
:5 | All processes whose pid is no greater than 5. |
20: | All processes whose pid is no less than 20. |
NOTE: The process set [:
] is equivalent to the process set [*].
set
command.
For example:
(ladebug) set $set1 = [:7, 10, 15:20, 30:]
(ladebug) print $set1
[:7, 10, 15:20, 30:]
In addition to using the print
command, you can also
use the show process set
command to inspect the process set
stored in a debugger variable. For example:
show_process_set_command
: show process set debugvar_name
| show process set all
| show process set
If you do not specify the set name, or if you use the all
specifier, the
debugger displays all the process sets that are currently stored in debugger variables, as the
continued example shows:
(ladebug) set $set2 = [8:9, 5:2, 22:27]
`5:2' is not a legal process range. Ignored.
(ladebug) show process set $set2
$set2 = [8:9, 22:27]
(ladebug) show process set *
$set1 = [:7, 10, 15:20, 30:]
$set2 = [8:9, 22:27]
+ |
Takes two sets S1 and S2 and returns a set whose elements are either in S1 or in S2. | |
- |
Takes two sets S1 and S2 and returns a set whose elements are in S1 but not in S2. | |
- |
Takes a single set S and
returns the difference of [* ] and S. |
The following example demonstrates these operations:
(ladebug) set $set1 = [:10, 15:18, 20:]
(ladebug) set $set2 = [10:16, 19]
(ladebug) set $set3 = $set1 + $set2
(ladebug) print $set3
[*]
(ladebug) print $set3 - $set2
[:9, 17:18, 20:]
(ladebug) print -$set2
[:9, 17:18, 20:]
You can use the focus
command to change the current
process set, which is the set of processes whose debuggers receive the remote
command entered at the root debugger:
focus_command : focus expression | focus all | focus
The first form of the command sets the current process set to the set resulting from the evaluation of the given expression. The second form sets the current process set to the set that includes all processes. The third form displays the current process set.
As mentioned in the Overview, the root debugger collects the outputs from the leaf debuggers and presents you with an aggregated output. In most cases, this aggregation works fine, but it can be an impediment if you want to know the exact output from certain leaf debuggers.
To remedy this, the debugger assigns a unique number (called a message_id
)
to each aggregated message and saves the message in the message_id_list
.
You can use the following commands to inspect the message list and expand its entries:
show_aggregated_message_command : show aggregated message message_id_list | show aggregated message all | show aggregated message message_id_list : expression {,...}The first form of the command displays the aggregated messages in the list whose message IDs match the numbers specified in the
message_id_list
.
The second form displays all the aggregated messages in the list. If no message_id
is
specified, the debugger shows the most recently added (newest) message.
expand_aggregated_message_command : expand aggregated message message_id_list | expand aggregated messageThis command expands the specified messages. If no
message_id
is
specified, the debugger expands the most recently added (newest) message.
You can control the length of the message list using the
$aggregatedmsghistory
debugger variable.
If you set this variable to the default (0), the debugger records as many messages as
the system will allow.
If the debugger outputs are not aggregated as you would expect them to be,
you can change the value of the $parallel_aggregatordelay
debugger variable. The $parallel_aggregatordelay
variable sets the expiration time for each of the aggregators when the aggregators
have not received all the expected messages.
In Aggregated Example 1, the value of $parallel_aggregatordelay
is
set to 100 milliseconds, which does not seem to be long enough for the debugging session's
32 processes. Changing the $parallel_aggregatordelay
variable to 500
milliseconds results in the improved aggregation shown in Aggregated Example 2.
NOTE: Because the default value of the $parallel_aggregatordelay
is 3000 milliseconds, you should not normally have a problem with the aggregation delay. The
purpose of these examples is to show the effect of changing the
$parallel_aggregatordelay
setting.
% ladebug -parallel /usr/bin/prun -n 32 ~/smg98/test/smg98
Welcome to the Ladebug Debugger Version n
Reading symbolic information ...done
stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]
Source file not found or not readable, tried...
./loader.cc
/usr/bin/loader.cc
(Cannot find source file loader.cc)
stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]
Source file not found or not readable, tried...
./loader.cc
/usr/bin/loader.cc
(Cannot find source file loader.cc)
Process has exited
(ladebug) [8,13,16:31] Welcome to the Ladebug Debugger Version n
[8,13,16:31] ------------------
[8,13,16:31] object file name: /usr/users/user1/smg98/test/smg98
[8,13,16:31] Reading symbolic information ... [8,13,16:31] done
%1 [8,13,16:31] Attached to process id [14186471;16807748] ....
[8,13,16:31] Thread received signal TRAP
[8,13,16:31] stopped at [ 0x3ff80006790]
[8,13,16:31] Thread received signal TRAP
[8,13,16:31] stopped at [ 0x3ff80020328]
[8,13,16:31] [#1: stop quiet in int main(int, char**) ]
[8,13,16:31] 66 int solver_id;
[8,13,16:31] 67
[8,13,16:31] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[8,13,16:31] 69
[8,13,16:31] 70 HYPRE_StructMatrix A;
(ladebug) [0,2,4] Welcome to the Ladebug Debugger Version n
[0] ------------------
[0] object file name: /usr/users/user1/smg98/test/smg98
[0] Reading symbolic information ... [0] done
[0] Attached to process id 13138577 ....
[0] Thread received signal TRAP
[0] stopped at [ 0x3ff80006790]
[0] Thread received signal TRAP
[1,3,6,15] Welcome to the Ladebug Debugger Version n
[1:2,4,6] ------------------
[1:2,4,6] object file name: /usr/users/user1/smg98/test/smg98
[2,4,6] Reading symbolic information ... [2,4,6] done
%2 [2,4,6] Attached to process id [13138579;13662398] ....
[2,4,6] Thread received signal TRAP
[2,4,6] stopped at [ 0x3ff80006790]
[0] stopped at [ 0x3ff80020328]
[0] [#1: stop quiet in int main(int, char**) ]
[0] 66 int solver_id;
[0] 67
[0] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[0] 69
[0] 70 HYPRE_StructMatrix A;
(ladebug) [9:10] Welcome to the Ladebug Debugger Version n
[3,10,15] ------------------
[3,10,15] object file name: /usr/users/user1/smg98/test/smg98
[1,3,15] Reading symbolic information ... [1,3,15] done
%3 [1,3,15] Attached to process id [13138578;14710852] ....
[1,3,15] Thread received signal TRAP
[1,3,15] stopped at [ 0x3ff80006790]
[1,3,6,15] Thread received signal TRAP
[1,3,6,15] stopped at [ 0x3ff80020328]
[1,3,6,15] [#1: stop quiet in int main(int, char**) ]
[1,3,6,15] 66 int solver_id;
[1,3,6,15] 67
[1,3,6,15] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[1,3,6,15] 69
[1,3,6,15] 70 HYPRE_StructMatrix A;
(ladebug) [9] ------------------
[9] object file name: /usr/users/user1/smg98/test/smg98
[9:10] Reading symbolic information ... [9:10] done
%4 [9:10] Attached to process id [14186472;14186473] ....
[9:10] Thread received signal TRAP
[9:10] stopped at [ 0x3ff80006790]
[9:10] Thread received signal TRAP
[9:10] stopped at [ 0x3ff80020328]
[10] [#1: stop quiet in int main(int, char**) ]
[10] 66 int solver_id;
[10] 67
[10] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[10] 69
[10] 70 HYPRE_StructMatrix A;
(ladebug) [9] [#1: stop quiet in int main(int, char**) ]
[9] 66 int solver_id;
[9] 67
[9] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[9] 69
[9] 70 HYPRE_StructMatrix A;
[5,7,11:12,14] Welcome to the Ladebug Debugger Version n
[5,7] ------------------
[5,7] object file name: /usr/users/user1/smg98/test/smg98
(ladebug) [11:12,14] ------------------
[11:12,14] object file name: /usr/users/user1/smg98/test/smg98
[5,7,11:12,14] Reading symbolic information ... [5,7,11:12,14] done
%5 [5,7,11:12,14] Attached to process id [13662397;14710851] ....
[5,7,11:12,14] Thread received signal TRAP
[5,7,11:12,14] stopped at [ 0x3ff80006790]
[5,7,11:12,14] Thread received signal TRAP
[5,7,11:12,14] stopped at [ 0x3ff80020328]
[5,7,11:12,14] [#1: stop quiet in int main(int, char**) ]
[5,7,11:12,14] 66 int solver_id;
[5,7,11:12,14] 67
[5,7,11:12,14] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[5,7,11:12,14] 69
[5,7,11:12,14] 70 HYPRE_StructMatrix A;
% ladebug -parallel /usr/bin/prun -n 32 ~/smg98/test/smg98
Welcome to the Ladebug Debugger Version n
Reading symbolic information ...done
stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]
Source file not found or not readable, tried...
./loader.cc
/usr/bin/loader.cc
(Cannot find source file loader.cc)
stopped at [void _rms_breakpoint(void):1470 0x3ffbff6053c]
Source file not found or not readable, tried...
./loader.cc
/usr/bin/loader.cc
(Cannot find source file loader.cc)
Process has exited
(ladebug) [0:31] Welcome to the Ladebug Debugger Version n
[0:31] ------------------
[0:31] object file name: /usr/users/user1/smg98/test/smg98
[0:31] Reading symbolic information ... [0:31] done
%1 [0:31] Attached to process id [13138610;16807808] ....
[0:31] Thread received signal TRAP
[0:31] stopped at [ 0x3ff80006790]
[0:31] Thread received signal TRAP
[0:31] stopped at [ 0x3ff80020328]
[0:31] [#1: stop quiet in int main(int, char**) ]
[0:31] 66 int solver_id;
[0:31] 67
[0:31] > 68 int A_num_ghost[6] = { 0, 0, 0, 0, 0, 0};
[0:31] 69
[0:31] 70 HYPRE_StructMatrix A;
(ladebug) next
(ladebug) [0:31] stopped at [int main(int, char**):110 0x120006dd8]
[0:31] 110 MPI_Init(&argc, &argv);
The sample application used in the aggregated examples is located at:
http://www.acl.lanl.gov/30TeraOpRFP/SampleApps/smg98/smg98.html
Tip 2. How to Synchronize Processes
If the processes become unsynchronized in the debugging session (for example,
if you use the focus
command on a subset
of the total set and then use a next
or some other
motion command), the easiest way to get the processes back together is to use
a cont to
a future location where all processes have to go.
The following example shows how the output from processes is not identical because
different processes are at different locations in the
program. Using the cont to
command synchronizes
the processes and aggregates the messages.
(ladebug) next (ladebug) [4:5,12] stopped at [int feedbackToDebugger(int, int, char*):17 0x120006bf4] [0:3,6:11] [3] stopped at [int feedbackToDebugger(int, int, char*):15 0x120006bf0] [4:5,12] 17 int pathSize = 1000; [0:3,6:11] 15 int i = 0; (ladebug) l (ladebug) [0:3,6:11] 16 char path[1000]; [4:5,12] 18 char hostname[1000]; [0:3,6:11] 17 int pathSize = 1000; [4:5,12] 19 int hostnameSize = 1000; [0:3,6:11] 18 char hostname[1000]; [4:5,12] 20 [0:3,6:11] 19 int hostnameSize = 1000; [4:5,12] 21 volatile int debuggerAttached = 0; [0:3,6:11] 20 [4:5,12] 22 [0:3,6:11] 21 volatile int debuggerAttached = 0; [4:5,12] 23 gethostname(hostname,hostnameSize); %3 [0:12] [22;24] [0:3,6:11] 23 gethostname(hostname,hostnameSize); [4:5,12] 25 getcwd(path,pathSize); [0:3,6:11] 24 [4:5,12] 26 strcat(path,"/"); [0:3,6:11] 25 getcwd(path,pathSize); [4:5,12] 27 strcat(path,name); [0:3,6:11] 26 strcat(path,"/"); [4:5,12] 28 [0:3,6:11] 27 strcat(path,name); [4:5,12] 29 // Print myid pid into ladebugAttach.myid [0:3,6:11] 28 [4:5,12] 30 sprintf(filename,"ladebugAttach.%d",myid); [0:3,6:11] 29 // Print myid pid into ladebugAttach.myid [4:5,12] 31 file = fopen(filename,"w"); [0:3,6:11] 30 sprintf(filename,"ladebugAttach.%d",myid); [4:5,12] 32 if (file == NULL) { [0:3,6:11] 31 file = fopen(filename,"w"); [4:5,12] 33 fprintf(stderr,"smg98: can't open %s for %s\n",filename, "w"); [0:3,6:11] 32 if (file == NULL) { [4:5,12] 34 exit(1) [0:3,6:11] 33 fprintf(stderr,"smg98: can't open %s for %s\n",filename, "w"); [4:5,12] 35 } [12] 36 fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path); [12] 37 fclose(file); [12] 38 [4:5] 36 fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path); [0:3,6:11] 34 exit(1); [0:3,6:11] 35 } [4:5] 37 fclose(file); [0:3,6:11] 36 fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path); [4:5] 38 (ladebug) cont to 36 [0:13] stopped at [int feedbackToDebugger(int, int, char*):36 0x120006cb8] [0:13] 36 fprintf(file," %ld %ld %s %s\n", myid, getpid(), hostname, path); (ladebug) next (ladebug) [0:13] stopped at [int feedbackToDebugger(int, int, char*):37 0x120006d0c] [0:13] 37 fclose(file);Tip 3. How to Use the
-I
Option in the Parallel
Environment
If the application source file is not in the same location as the application binary file, the debugger will display a message that it cannot find the application source file. Consider the following example:
$ ladebug -parallel /bin/dmpirun -np 8 -hf ~/test/src/common/Funct/src/cpihostfile \ ~/test/src/common/Funct/bin-alpha-osf1/cpi Welcome to the Ladebug Debugger Version n Reading symbolic information ...done stopped at [void MPIR_Breakpoint(void):43 0x120002fc0] Source file not found or not readable, tried... ./mpirun.c /bin/mpirun.c (Cannot find source file mpirun.c) Process has exited (ladebug) [0:7] Welcome to the Ladebug Debugger Version n [0:7] ------------------ [0:7] object file name: /usr/users/smith/ladebug-sandbox/test/src/common/Funct/bin-alpha-osf1/cpi [0:7] Reading symbolic information ... [0:7] done [0:7] Unable to switch to decthreads mode. [0:7] Source file not found or not readable, tried... [0:7] ./cpi.c [0:7] /usr/users/smith/ladebug-sandbox/test/src/common/Funct/bin-alpha-osf1/cpi.c
Specifying the -I
option before the -parallel
option does not fix the problem because the -I
option
applies only to the root debugger. The root debugger only controls the launcher
and will not look outside its location for the application source file. The -I
option is not currently passed along to the leaf debuggers, which would resolve this problem.
The following example shows how to cause the debugger to locate the application source file:
(ladebug) use /usr/proj/debug/ladebug/test/src/common/Funct/src [0:7] Directory search path for source files: [0:7] . /usr/users/smith/ladebug-sandbox/test/src/common/Funct/bin-alpha-sf1/usr/proj/debug/ladebug/test/src/common/Funct/src (ladebug) w [0:7] 20 [0:7] 21 double f(double); [0:7] 22 [0:7] 23 int main(int argc, char *argv[]) [0:7] 24 { [0:7] 25 int done = 0, n, myid, numprocs, i; [0:7] 26 double PI25DT = 3.141592653589793238462643; [0:7] 27 double mypi, pi, h, sum, x; [0:7] 28 double startwtime = 0.0, endwtime; [0:7] 29 int namelen;
% ladebug -parallel /usr/bin/dmpirun -np 6 /usr/users/parallel/examples/cpi-DmpirunStop
Welcome to the Ladebug Debugger Version n
Reading symbolic information ...done
stopped at [void MPIR_Breakpoint(void):43 0x120002fc0]
Source file not found or not readable, tried...
./mpirun.c
/usr/bin/mpirun.c
(Cannot find source file mpirun.c)
Process has exited
(ladebug) [0:5] Welcome to the Ladebug Debugger Version n
[0:5] ------------------
[0:5] object file name: /usr/users/parallel/examples/cpi-DmpirunStop
[0:5] Reading symbolic information ...done
[0:5] 52 int done = 0, n, myid, numprocs, i;
(ladebug) stop in feedbackToDebugger
[0:5] [#1: stop in int feedbackToDebugger(int, int, char*) ]
(ladebug) focus [0:2]
[0:2]>
[0:2]> cont
[0:2]> [0:2] [1] stopped at [int feedbackToDebugger(int, int, char*):18 0x120001818]
[0:2] 18 int i = 0;
[0:2]> where
[0:2]> %1 [0:2] >0 0x120001818 in feedbackToDebugger(myid=[0;2], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
[0:2] #1 0x120001a48 in main(argc=1, argv=0x11fffc018) "cpi-user1.c":63
[0:2] #2 0x120001758 in __start(...) in /usr/users/parallel/examples/cpi-DmpirunStop
[0:2]> focus [3:5]
[3:5]>
[3:5]> cont
[3:5]> [3:5] [1] stopped at [int feedbackToDebugger(int, int, char*):18 0x120001818]
[3:5] 18 int i = 0;
[3:5]> where
[3:5]> %2 [3:5] >0 0x120001818 in feedbackToDebugger(myid=[3;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
[3:5] #1 0x120001a48 in main(argc=1, argv=0x11fffc018) "cpi-user1.c":63
[3:5] #2 0x120001758 in __start(...) in /usr/users/parallel/examples/cpi-DmpirunStop
[3:5]> focus [*]
[0:5]>
[0:5]> next
[0:5]> [0:5] stopped at [int feedbackToDebugger(int, int, char*):20 0x12000181c]
[0:5] 20 int pathSize = 1000;
[0:5]> where
[0:5]> %4 [0:5] >0 0x12000181c in feedbackToDebugger(myid=[0;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
[0:5] #1 0x120001a48 in main(argc=1, argv=0x11fffc018) "cpi-user1.c":63
[0:5] #2 0x120001758 in __start(...) in /usr/users/parallel/examples/cpi-DmpirunStop
[0:5]> show aggregated message
%1 [0:2] >0 0x120001818 in feedbackToDebugger(myid=[0;2], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
%2 [3:5] >0 0x120001818 in feedbackToDebugger(myid=[3;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":18
%3 [0:5] >0 0x12000181c in feedbackToDebugger(myid=[0;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
[0:5]> expand aggregated message 3
%3 [0:5] >0 0x12000181c in feedbackToDebugger(myid=[0;5], np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
[0] >0 0x12000181c in feedbackToDebugger(myid=0, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
[1] >0 0x12000181c in feedbackToDebugger(myid=1, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
[2] >0 0x12000181c in feedbackToDebugger(myid=2, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-DmpirunStop") "cpi-user1.c":20
[3] >0 0x12000181c in feedbackToDebugger(myid=3, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-S-BuildDmpirunStop") "cpi-user1.c":20
[4] >0 0x12000181c in feedbackToDebugger(myid=4, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-S-BuildDmpirunStop") "cpi-user1.c":20
[5] >0 0x12000181c in feedbackToDebugger(myid=5, np=6, name=0x11fffe060="/usr/users/parallel/examples/cpi-S-BuildDmpirunStop") "cpi-user1.c":20
[0:5]> quit
The following are explanatory notes from the previous example:
|
This parallel session creates 6 processes. |
|
This is a message from processes 0 to 5. |
|
This aggregated message contains messages with differing
portions (in this case, the myid parameters are
different from process to process),
and 1 is the message id. |
|
This focus command sets the current process set to
include processes 0, 1, and 2. |
|
This prompt shows the current process set. |
|
This show aggregated message command
displays all the aggregated messages saved in the message list. |
|
This expand aggregated message
command expands the aggregated message with message id 3. |
mpirun_dbg.ladebug
, to start up
the debugger controlling your mpich
processes:
#!/bin/sh cmdLineArgs="" p4pgfile="" p4workdir="" prognamemain="" while [ 1 -le $# ] ; do arg=$1 shift case $arg in -cmdlineargs) cmdLineArgs="$1" shift ;; -p4pg) p4pgfile="$1" shift ;; -p4wd) p4workdir="$1" shift ;; -progname) prognamemain="$1" shift ;; esac done # if [ -n "$LADEBUG_HOME" ] ; then ldbdir=$LADEBUG_HOME else ldbdir="" fi # if [ -f $ldbdir/ladebug.cat ] && [ -r $ldbdir/ladebug.cat ] ; then if [ -n "$NLSPATH" ]; then nlsmore=$NLSPATH else nlsmore="" fi NLSPATH=$ldbdir/$nlsmore fi # $ldbdir/ladebug -parallel $prognamemain `eval echo $cmdLineArgs` -p4pg $p4pgfile -p4wd $p4workdir -mpichtv