© 2000 Compaq Computer Corporation
A Quick Introduction to Using the Ladebug Debugger
It supports debugging simple programs, as well as situations involving multiple threads, multiple processes, core files, kernels, and remote systems.
The official Software Product Description is part of the Developers' Toolkit Software Product Description.
The Ladebug website -
Convention | Meaning | % | A percent sign (%) represents the C shell system prompt. | # | A pound sign (#) represents the default superuser prompt. |
UPPERCASE
lowercase |
The Tru64 UNIX operating system differentiates between lowercase and uppercase characters. On the operating system level, you must type examples, syntax descriptions, function definitions, and literal strings that appear in text exactly as shown. | Ctrl/C | This symbol indicates that you must press the Ctrl key while you simultaneously press another key (in this case, C). | monospaced text | This typeface indicates the exact name of a routine, partition, path name, directory, or file. This typeface is also used in interactive examples. | monospaced bold text | In interactive examples, this typeface indicates input that you enter. In syntax statements and text, this typeface indicates the exact name of a command or keyword. | monospaced italic text | Monospaced italic type indicates variable values, place holders, function argument names, and in syntax definitions, non-terminal names. When a non-terminal name consists of more than one word, the words are joined using the underscore (_), for example, breakpoint_command. | italic text | Italic type indicates book names or emphasized terms. |
foo_bar : item1 | item2 | item3 |
A colon starts the syntax definition of a non-terminal name (in this example, foo_bar. Vertical bars separating items that appear in syntax definitions indicate that you choose one item from among those listed. | [] | In syntax definitions, brackets indicate items that are optional. |
option ;...
option ,... option ... |
A set of three horizontal ellipses indicates that you can enter additional parameters, options, or values. A {semicolon, comma, space} preceding the ellipses indicates successive items must be separated by {semicolons, commas, spaces}. | setld(8) | Cross-references to online man pages include the appropriate section number in parentheses. For example, setld(8) indicates that you can find the material on the setld command in Section 8 of the reference pages. The man command % man 8 setld shows the man page for this reference. |
---|
You look for a bug by doing the following:
If the problem only occurs in optimized code, use the -g3 switch.
For example, if your terminal is 47x80, you need to set the following:
% stty rows 47 ; setenv LINES 47 % stty cols 80 ; setenv COLS 80There are four basic alternatives for getting the debugger started on a process:
% ladebug a.out Welcome to the Ladebug Debugger Version 4.0-58 ------------------ object file name: /usr/users/user1/a.out Reading symbolic information ...done (ladebug) stop in main [#1: stop in int main(void) ] (ladebug) run
% ladebug Welcome to the Ladebug Debugger Version 4.0-58 (ladebug) load a.out Reading symbolic information ...done (ladebug) stop in main [#1: stop in int main(void) ] (ladebug) run
% a.out & [2] 27859 % jobs [2] Running ... % ladebug a.out -pid 27859 Attached to process id 27859 ....Type Ctrl/C to interrupt the process.
% a.out & [2] 27859 % jobs [2] Running ... % ladebug (ladebug) attach 27859 a.out Attached to process id 27859 ....Type Ctrl/C to interrupt the process.
(ladebug) you type here
When you enter commands, you use the left and right arrow keys to move within the line and the up and down arrow keys to recall previous commands for editing. When you finish entering a command, press the Enter key to submit the completed line to the debugger for processing.
You can continue a line by ending the line to be continued with a backslash (\) character.
On a blank line, press the Enter key to re-execute the most recent valid command.
Two very useful commands are:
(ladebug) help (ladebug) quit
(ladebug) source filenameThe command causes the debugger to read and execute Ladebug commands from filename.
Processes contain one or more threads of execution. The threads execute functions. Functions are sequences of instructions that come from source lines within source files.
As you enter debugger commands to manipulate your process, it would be very tedious to have to repeatedly specify which thread, source file, etc. you wish the command to be applied to. To prevent this, each time the debugger stops the process, it re-establishes a static context and a dynamic context for your commands. The components of the static context are independent of this run of your program; the components of the dynamic context are dependent on this run.
You can change most of these individually to point to other instances, as described in the relevant portions of this manual, and the debugger will modify the rest of the static and dynamic context to keep the various components consistent.
After you specify the program (either on the shell command line or using the load command), but before you have requested the debugger to create the process, you can still do things that seem to require a running process, for example, you can create breakpoints and examine sources.
Any breakpoints that you create will be inserted into the process as soon as possible after it exec()s your program.
To have the debugger create the process (rather than attaching to an existing process), you request it to run, specifying, if necessary, any input and output redirection and arguments.
% ladebug a.out Welcome to the Ladebug Debugger Version 4.0-58 (ladebug) run or (ladebug) run args or (ladebug) run > output-file or (ladebug) run args > output-file < input-fileThe result of using any of the preceding command variations is similar to having attached to a running process. The rerun command repeats the previous run command with the same arguments and files.
(ladebug) run ^C Interrupt (for process) Stopping process localhost:27903 (a.out). Thread received signal INT stopped at [int main(int):5 0x120001138] 5 while (argc < 2 && i < 10000000)
(ladebug) run
Thread received signal SEGV
stopped at [void buggy(char*, char*):13 0x120001ba4]
13 output[k] = input[k];
(ladebug) stop in main
[#1: stop in int main(void) ]
(ladebug) run
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
(ladebug) watch variable nodeList._firstNode write
[#2: watch variable nodeList._firstNode 0x11fffeb48, 0x11fffeb4f write ]
(ladebug) cont
[2] Address 0x11fffeb48 was accessed at:
List<Node>::List(void): x_list.cxx
[line 121, 0x120001d74] stq r31, 0(r1)
0x11fffeb48: Old value = 0xfffffffffffffff8
0x11fffeb48: New value = 0x0000000000000000
[2] stopped at [List<Node>::List(void):123 0x120001d78]
123 }
% ladebug a.out
(ladebug) file
x_list.cxx
(ladebug) list 180: 10
180 main()
181 {
182 List<Node> nodeList;
183
184 // add entries to list
185 //
> 186 IntNode* newNode = new IntNode(1);
187 nodeList.append(newNode);
188
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
(ladebug) /CompoundNode
197 CompoundNode* cNode2 = new CompoundNode(10.123, 5);
Aliases are short-hand forms of longer commands.
This example shows using the W alias, which lists up to 20 lines
around the
current line. Note that '>' marks the current line.
(ladebug) alias W
W list $curline - 10:20
(ladebug) W
176
177
178 // The driver for this test
179 //
180 main()
181 {
182 List<Node> nodeList;
183
184 // add entries to list
185 //
> 186 IntNode* newNode = new IntNode(1);
187 nodeList.append(newNode);
188
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
190 nodeList.append(cNode);
191
192 nodeList.append(new IntNode(3));
193
194 IntNode* newNode2 = new IntNode(4);
195 nodeList.append(newNode2);
(ladebug) thread
Thread Name State Substate Policy Pri
------ ------------------------- --------------- ----------- ------------ ---
>* 2 <anonymous> running SCHED_OTHER 19
(ladebug) show thread
Thread Name State Substate Policy Pri
------ ------------------------- --------------- ----------- ------------ ---
1 default thread running SCHED_OTHER 19
-1 manager thread blk SCS SCHED_RR 19
-2 null thread for VP 0 ready new null thread 0
-3 null thread for VP 1 ready null thread 0
-4 null thread for VP 0 ready new null thread 0
-5 null thread for VP 0 ready new null thread 0
>* 2 <anonymous> running SCHED_OTHER 19
Note that '>' marks the current thread.
You can select any thread to be the focus of commands that show things. For example:
(ladebug) thread 1
Thread Name State Substate Policy Pri
------ ------------------------- --------------- ----------- ------------ ---
> 1 default thread running SCHED_OTHER 19
(ladebug) where 4
>0 0x12000224c in ((Node*)0x140002000)->Node() "x_list.cxx":77
#1 0x120002298 in ((IntNode*)0x140002000)->IntNode(data=2) "x_list.cxx":88
#2 0x120002338 in ((CompoundNode*)0x140002000)->CompoundNode(fdata=12.34500026702881, idata=2) "x_list.cxx":101
#3 0x1200024fc in main() "x_list.cxx":189
(ladebug) up 2
>2 0x120002338 in ((CompoundNode*)0x140002000)->CompoundNode(fdata=12.34500026702881, idata=2) "x_list.cxx":101
101 CompoundNode::CompoundNode(float fdata, int idata)
(ladebug) list $curline - 10: 20
91 void IntNode::printNodeData() const
92 {
93 cout << " type is integer, value is ";
94 cout << _data << endl;
95 }
96
97
98 //=============================================================================
99 // CompoundNode definition
100 //
> 101 CompoundNode::CompoundNode(float fdata, int idata)
102 :
103 IntNode(idata),
104 _fdata (fdata)
105 {
106 }
107 void CompoundNode::printNodeData() const
108 {
109 cout << " type is compound, value is ";
110 cout << _fdata << endl;
(ladebug) down 1
>1 0x120002298 in ((IntNode*)0x140002000)->IntNode(data=2) "x_list.cxx":88
88 IntNode::IntNode(int data) : _data(data)
(ladebug) print fdata
12.34500026702881
(ladebug) print idata
2
(ladebug) print idata + 59
61
(ladebug) print this
0x140002000
(ladebug) print *this
class CompoundNode {
_fdata = 0;
_data = 0; // class IntNode
_nextNode = 0x0; // class IntNode::Node
}
(ladebug) run
Thread received signal SEGV
stopped at [void buggy(char*, char*):13 0x120001ba4]
13 output[k] = input[k];
(ladebug) ($curpc - 20)/10i
CompoundNode::CompoundNode(float, int): x_list.cxx
[line 105, 0x120002328] cpys $f17,$f17,$f0
[line 105, 0x12000232c] bis r31, r18, r8
[line 101, 0x120002330] bis r31, r19, r16
[line 101, 0x120002334] bis r31, r8, r17
[line 101, 0x120002338] bsr r26, IntNode
*[line 101, 0x12000233c] ldq r18, -32712(gp)
[line 101, 0x120002340] lda r18, 48(r18)
[line 101, 0x120002344] stq r18, 8(r19)
[line 101, 0x120002348] sts $f0, 24(r19)
[line 106, 0x12000234c] bis r31, r19, r0
(ladebug) alias wi
wi ($curpc - 20)/10 i
(ladebug) $pc/10x
0x12000233c: 8038 a65d 0030 2252 0008 b653 0018 9813
0x12000234c: 0400 47f3
(ladebug) $pc/6xx
0x12000233c: a65d8038 22520030 b6530008 98130018
0x12000234c: 47f30400 47f5041a
(ladebug) $pc/2X
0x12000233c: 22520030a65d8038 98130018b6530008
You can examine registers.
(ladebug) print $r16
5368717312
(ladebug) printf "0x%lx", $r16
0x140002000
(ladebug) alias px
px printf "0x%lx",
(ladebug) printregs
$r0 [$v0] = 1 $r1 [$t0] = 5368717312
$r2 [$t1] = 4 $r3 [$t2] = 3
$r4 [$t3] = 2 $r5 [$t4] = 5368717312
$r6 [$t5] = 0 $r7 [$t6] = 4831847228
$r8 [$t7] = 2 $r9 [$s0] = 342210368
$r10 [$s1] = 0 $r11 [$s2] = 4096
$r12 [$s3] = 351026560 $r13 [$s4] = 4096
$r14 [$s5] = 340603688 $r15 [$s6] = 1
$r16 [$a0] = 5368717312 $r17 [$a1] = 2
$r18 [$a2] = 2 $r19 [$a3] = 5368717312
$r20 [$a4] = 5368717360 $r21 [$a5] = 4831847680
$r22 [$t8] = 1 $r23 [$t9] = 544
$r24 [$t10] = 4396973371008 $r25 [$t11] = 1
$r26 [$ra] = 4831847228 $r27 [$t12] = 0
$r28 [$at] = 4831845184 $r29 [$gp] = 5368742704
$r30 [$sp] = 4831834192 $r31 [$zero]= 0
$f0 = 12.34500026702881 $f1 = 0
$f2 = 0 $f3 = 0
$f4 = 0 $f5 = 0
$f6 = 0 $f7 = 0
$f8 = 0 $f9 = 0
$f10 = 0 $f11 = 1.747017862805721e-315
$f12 = 0.1 $f13 = 0
$f14 = 2.035550460865936e-320 $f15 = 1.235164114603116e-322
$f16 = 0 $f17 = 12.34500026702881
$f18 = 0 $f19 = 3.004589850472947e-315
$f20 = 1.491996452932239e-315 $f21 = 1.491996670321123e-315
$f22 = 1.665939358333324e-315 $f23 = 0
$f24 = 1.665945484747333e-315 $f25 = 3.004595759498071e-315
$f26 = 1.491991887765672e-315 $f27 = 8.267835780756879e-315
$f28 = 1.665945405696829e-315 $f29 = 1.665945800949346e-315
$f30 = 1.491996433169613e-315 $f31 = 0
$pc = 0x12000233c $ps = 0x8
$fpcr = 0x800000000000000 $vfp = 0x11ffff050
Continue until another interesting thing happens |
|
|
|
Single step by line, but step over calls |
|
|
|
Single step to a new line, stepping into calls |
|
|
|
Continue until control returns to the caller |
|
|
|
Single step by instruction, over calls |
|
|
|
Single step by instruction, into calls |
|
|
|
(ladebug) list $curline - 10: 20
172
173 if (i == 1) cout << "The list is empty ";
174 cout << endl << endl;
175 }
176
177
178 // The driver for this test
179 //
180 main()
181 {
> 182 List<Node> nodeList;
183
184 // add entries to list
185 //
186 IntNode* newNode = new IntNode(1);
187 nodeList.append(newNode);
188
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
190 nodeList.append(cNode);
191
(ladebug) next
stopped at [int main(void):186 0x120002420]
186 IntNode* newNode = new IntNode(1);
(ladebug) next 7
stopped at [int main(void):197 0x12000265c]
197 CompoundNode* cNode2 = new CompoundNode(10.123, 5);
(ladebug) step
stopped at [CompoundNode::CompoundNode(float, int):101 0x120002330]
101 CompoundNode::CompoundNode(float fdata, int idata)
(ladebug) list $curline - 2: 6
99 // CompoundNode definition
100 //
> 101 CompoundNode::CompoundNode(float fdata, int idata)
102 :
103 IntNode(idata),
104 _fdata (fdata)
(ladebug) step
stopped at [IntNode::IntNode(int):88 0x120002294]
88 IntNode::IntNode(int data) : _data(data)
(ladebug) list $curline - 2: 5
86 // IntNode definition
87 //
> 88 IntNode::IntNode(int data) : _data(data)
89 {
90 }
(ladebug) return IntNode
stopped at [CompoundNode::CompoundNode(float, int):101 0x12000233c]
101 CompoundNode::CompoundNode(float fdata, int idata)
(ladebug) return CompoundNode
stopped at [int main(void):197 0x1200026ac]
197 CompoundNode* cNode2 = new CompoundNode(10.123, 5);
(ladebug) step
stopped at [int main(void):198 0x1200026dc]
198 nodeList.append(cNode2);
(ladebug) step
stopped at [void List<Node>::append(class Node* const):148 0x120001d9c]
148 if (!_firstNode)
(ladebug) list $curline: 8
> 148 if (!_firstNode)
149 _firstNode = node;
150 else {
151 Node* currentNode = _firstNode;
152 while (currentNode->getNextNode())
153 currentNode = currentNode->getNextNode();
154 currentNode->setNextNode(node);
155 }
(ladebug) step 2
stopped at [void List<Node>::append(class Node* const):152 0x120001dc0]
152 while (currentNode->getNextNode())
The following example demonstrates stepping at the instruction level:
(ladebug) $curpc - 20/14i
void List<Node>::append(class Node* const): x_list.cxx
[line 149, 0x120001dac] ldq r3, 24(sp)
[line 149, 0x120001db0] stq r2, 0(r3)
[line 149, 0x120001db4] br r31, 0x120001e0c
[line 151, 0x120001db8] ldq r4, 24(sp)
[line 151, 0x120001dbc] ldq r9, 0(r4)
*[line 152, 0x120001dc0] bis r31, r9, r16
[line 152, 0x120001dc4] ldq r27, -32584(gp)
[line 152, 0x120001dc8] jsr r26, (r27), getNextNode
[line 152, 0x120001dcc] ldah gp, 8192(r26)
[line 152, 0x120001dd0] lda gp, 25956(gp)
[line 152, 0x120001dd4] beq r0, 0x120001df4
[line 153, 0x120001dd8] bis r31, r9, r16
[line 153, 0x120001ddc] ldq r27, -32584(gp)
[line 153, 0x120001de0] jsr r26, (r27), getNextNode
(ladebug) stepi
stopped at [void List<Node>::append(class Node* const):152 0x120001dc4] ldq r27, -32584(gp)
(ladebug) nexti
stopped at [void List<Node>::append(class Node* const):152 0x120001dc8] jsr r26, (r27), getNextNode
(ladebug) stepi
stopped at [class Node* Node::getNextNode(void):81 0x120002264] bis r31, r16, r1
(ladebug) return getNextNode
stopped at [void List<Node>::append(class Node* const):152 0x120001dcc]
152 while (currentNode->getNextNode())
(ladebug) nexti 2
stopped at [void List<Node>::append(class Node* const):152 0x120001dd4] beq r0, 0x120001df4
In a program that does not use multiple threads, you can use snapshots to save your state before you step over the call. Then clone that snapshot to get another process positioned just before the call so you can step into it.
The following example shows the stages of a snapshot being used in this way.
(ladebug) next 2
stopped at [int main(void):187 0x120002498]
187 nodeList.append(newNode);
(ladebug) list $curline - 10: 20
177
178 // The driver for this test
179 //
180 main()
181 {
182 List<Node> nodeList;
183
184 // add entries to list
185 //
186 IntNode* newNode = new IntNode(1);
> 187 nodeList.append(newNode);
188
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
190 nodeList.append(cNode);
191
192 nodeList.append(new IntNode(3));
193
194 IntNode* newNode2 = new IntNode(4);
195 nodeList.append(newNode2);
196
(ladebug) save snapshot
# 1 saved at 00:19:24 (PID: 23771).
stopped at [int main(void):187 0x120002498]
187 nodeList.append(newNode);
(ladebug) next
stopped at [int main(void):189 0x1200024b0]
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
(ladebug) list $curline - 10: 20
179 //
180 main()
181 {
182 List<Node> nodeList;
183
184 // add entries to list
185 //
186 IntNode* newNode = new IntNode(1);
187 nodeList.append(newNode);
188
> 189 CompoundNode* cNode = new CompoundNode(12.345, 2);
190 nodeList.append(cNode);
191
192 nodeList.append(new IntNode(3));
193
194 IntNode* newNode2 = new IntNode(4);
195 nodeList.append(newNode2);
196
197 CompoundNode* cNode2 = new CompoundNode(10.123, 5);
198 nodeList.append(cNode2);
(ladebug) clone snapshot
Process has exited
Process 26917 cloned from Snapshot 1.
# 1 saved at 00:19:24 (PID: 23771).
stopped at [int main(void):187 0x120002498]
187 nodeList.append(newNode);
NOTE: fork() was used by the debugger both to create the snapshot and to clone it.
(ladebug) list $curline - 10: 20
177
178 // The driver for this test
179 //
180 main()
181 {
182 List<Node> nodeList;
183
184 // add entries to list
185 //
186 IntNode* newNode = new IntNode(1);
> 187 nodeList.append(newNode);
188
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
190 nodeList.append(cNode);
191
192 nodeList.append(new IntNode(3));
193
194 IntNode* newNode2 = new IntNode(4);
195 nodeList.append(newNode2);
196
Some additional details have been moved to the parallel portion of the Ladebug Debugger Advanced Topics so they do not hinder the reading of this section.
However, you can do the following to make it easier:
The debugging information is propagated into the a.out or *.so by ld(1). It is removed by strip(1). If you strip your programs, keep the unstripped version to use with the debugger.
The debugging information can cause .o files to be very large, causing long link times, but even so it can also be incomplete. C++ users can use the cxx -gall and -gall_pattern switches. See the cxx(1) man page.
The ladebug command invokes the Ladebug debugger.
The following is the shell syntax to invoke the debugger:
ladebug [ -c file ] [ -gui ] [ -i file ] [ -I directory ] [ -k ] [ -line serial_line ] [ -nosharedobjs ] [ -pid process_id ] [ -prompt string ] [ -remote ] [ -rp remote_debug_protocol ] [ -tty terminal_device ] [ -V ] [ executable_file [ core_file ] ]The following table describes the options and parameters:
Options and Parameters | Description |
---|---|
-c | Specifies an initialization command file. The default initialization file is .dbxinit. The debugger searches for this file during startup, first in the current directory. If it is not there, the debugger searches your home directory. This file is processed after the target process has been loaded or attached to. |
-gui | Activates the debugger's graphical user interface (GUI). |
-i | Specifies a pre-initialization command file. The default pre-initialization file is .ladebugrc. The debugger searches for this file during startup, first in the current directory and then in your home directory. This file is processed before the debugger has connected to the application being debugged, so that commands such as set $stoponattach = 1 will have taken effect when the connection is made. |
-I | Specifies the directory containing the source code for the target program, in a manner similar to the use command. Use multiple -I options to specify more than one directory. The debugger searches directories in the order in which they were specified on the command line. |
-k or -kernel | Enables local kernel debugging. |
-line | Specifies the serial line for remote kernel debugging. This must be used with -rp. |
-nosharedobjs | Prevents the reading of symbol table information for any shared objects loaded when the process executes. Later in the debug session, you can enter the readsharedobj command to read the symbol table information for a specified object. |
-pid | Specifies the process ID of the process to be debugged. This option cannot be used with any remote or kernel debugging flags. |
-prompt | Specifies a debugger prompt. The default debugger prompt is (ladebug). If the prompt argument contains spaces or special characters, enclose the argument in quotes (" "). |
-remote | Enables remote kernel debugging for use with the kdebug kernel debugger. |
-rp | Specifies the remote debug protocol. Currently only kdebug is supported; -rp kdebug enables remote kernel debugging. |
-tty | Specifies the terminal device for remote kernel debugging. This must be used with -rp . |
-V | Causes the debugger to print its version number and exit without starting a debugging session. |
executable_file | Specifies the program executable file. |
core_file | Specifies the core file. |
For example, to invoke the debugger on an executable file:
% ladebug executable_fileTo invoke the debugger on a core file:
% ladebug executable_file core_fileTo invoke the debugger and attach to a running process:
% ladebug -pid process_id executable_fileTo invoke the debugger and attach to a running process when you don't know what file it is executing:
% ladebug -pid process_idTo start the Ladebug GUI:
% ladebug -guiTo invoke the debugger on the local kernel:
% ladebug -k /vmunixTo invoke the debugger on the remote kernel:
% ladebug -remote vmunix
You can control your debugger process entirely through the Emacs GUD (Grand Unified Debugger) buffer mode, which is a variant of shell mode. All the Ladebug commands are available and you can use the shell mode history commands to repeat them.
Ladebug version 4.0-48 and higher supports GNU Emacs Version 19 and higher.
Ladebug version 4.0-58 and higher supports Lucid XEmacs Version 19.14 and higher.
The information in the following sections assumes you are familiar with Emacs and are using the Emacs notation for naming keys and key sequences.
For each Emacs session, before you can invoke the debugger, you must load the Ladebug-specific Emacs LISP code, as follows:
M-x load-fileAt the Load file: prompt, type:
/usr/lib/emacs/lisp/ladebug.el
You can also place a load-file call in your Emacs initialization file (~/.emacs). For example:
(load-file "/usr/lib/emacs/lisp/ladebug.el")To start the debugger with Emacs, type:
M-x ladebugThe following invocation line displays:
Run the debugger (like this): ladebugEdit the invocation line by typing the target program and pressing Return. Emacs remembers the invocation. To debug the same program again, you need only press Return.
Emacs displays the GUD buffer and runs the debugger within it; the debugger starts and displays its (ladebug) prompt, indicating readiness. The GUD buffer saves all of the commands you type and the program output for you to edit. In general, interact with the debugger in the GUD buffer as you would with a debugger started from a shell.
One of the benefits of running the debugger under Emacs is to get closer correlation between program execution and source. When your program stops, for example at a breakpoint, Emacs displays the source of your program in a second buffer (source buffer) and indicates the current execution line with =>.
NOTE: If the source is already loaded into a buffer, Emacs often finds that buffer. However, in some NFS mounting situations, Emacs may use an alternate name for some directories and will create a second buffer for your source (often with <2> appended to the name). Be careful that you do not modify the original buffer or kill it outright.
By default, Emacs sets its current working directory to be the directory containing the target program. Because the debugger does not do this when invoked directly, you may need to change the source code search path when using the debugger from within Emacs. To set an alternate source code search path, use the Ladebug map source directory command.
All Emacs editing functions and GUD key bindings are available. For example:
C-x SPC
M-x infoThen select the Emacs menu, then the Debuggers menu.
XEmacs will come up with the source buffer displayed. Use C-x 2 and a buffer menu to select the control buffer.
quit_command :quit
Alternative, you can type exit, which is a pre-defined alias for quit.
help_command :You can use this command to access the online help for the debugger. Enter help to see a list of help topics. Enter help command to see a list of Ladebug commands. Enter help ladebug to see a list of function-oriented Ladebug commands.help [ topic ]
You can start the GUI in either of two ways:
For example:
% ladebug -gui
guion_command :For example:gui
(ladebug) gui
When you use the GUI, you may use the mouse as well as the original
terminal window to enter debugger commands.
You can shut down the GUI and leave the command line session running by selecting File/Close All. In this case, you can restart the GUI any time with the (ladebug) gui command.
To end the command-line session and exit the GUI, select File/Exit Debugger in the GUI window.
% ladebug -prompt ">> " sample >> quitYou can also change the prompt by setting the $prompt debugger variable.
(ladebug) set $prompt = "newPrompt>> "
newPrompt>>
Example Command | If used in .ladebugrc | If used in .dbxinit | Assume the command, "set
$stoponattach = 1", is in one of these
files and you invoked the debugger as:
% ladebug -pid process_id executable_file |
The debugger attaches and stops. | The debugger attaches and waits for you to enter Ctrl/C; subsequent attaches will stop. |
---|---|---|
Assume the command, "stop in main", is in one of these files: | The debugger generates a message that there is no main in which to place a breakpoint, because there is no target yet. | The debugger sets the breakpoint (assuming there is a main in the target). |
Each line from stdin is copied to the record input file, if you have requested that file.
Each line is scanned from the beginning, looking for backslash ('\') characters which 'quote' their immediate following character. If the line ends in a quoted newline, then another line is similarly processed from stdin and appended to the first one, with the quoted newline removed.
Whether or not command line editing is enabled, you can always use your terminal's cut-and-paste function to avoid excessive typing while entering input.
For assembled lines that begin with an '!' character, the following rules apply:
In the first two cases, any remaining characters after the digits are appended to the assembled line.
For lines that begin with an '^' character, these rules apply:
'!' and '^' cannot be used in command lists built with '{}'; for example {print3; !!3} will not parse. They may be used in scripts.
History in a command list is not limited by '{}', but goes all the way back. For example:
(ladebug) print 1
1
(ladebug) stop in main { print 2; history 3}
[#1: stop in int main(void) { print 2; history 3} ]
(ladebug) run
2
11: print 1
12: stop in main {print 2; history 3}
13: run
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
Note: Commands in breakpoint action lists are
not entered into the history list.
If the '#' is the very first character in the line, the '#' is not discarded because a completely empty line has special meaning.
If there are no formal parameters, this match consumes no more of the input.
Again, the characters within strings are not tested. Nesting is caused by '(' and ')' characters outside of strings.
The following table shows how various environment variables expand and assumes that the home directory is /usr/users/hercules and the environment variable BIN is /usr/users/hercules/bin.
load ~/a.out | load /usr/users/hercules/a.out |
load $BIN/a.out | load /usr/users/hercules/bin/a.out |
load ${BIN}2/a\$b | load /usr/users/hercules/bin2/a$b |
map source directory $BIN ${BIN}2 | map source directory \ /usr/users/hercules/bin/usr/users/\ hercules/bin /usr/users/hercules/bin/usr/users/\ hercules/bin2 |
stop at "$BIN/a.out":20 | stop at "/usr/users/hercules/\ bin/a.out":20 |
run $BIN/a.out ~/core | run /usr/users/hercules/bin/a.out \ /usr/users/hercules/core |
As the debugger starts tokenizing a line into a command, it starts processing the characters using the lexical state LKEYWORDS. It uses the rules for lexical tokens in this state, recognizing the longest sequence of characters that forms a lexical token.
After the lexical token is recognized, the debugger appends it to the tokenized form of the line, perhaps changes to another lexical state, and starts on the next token.
input : command_list | commentA command list is a sequence of commands that are executed one after the other.
command_list : commandA comment is a line that begins with a '#' character.;... | command ; | command
comment :Any text after an unquoted '#' is ignored by the debugger. If the first non-whitespace character on a line is a '#' character, the whole line is ignored.#
Note: The difference between a command line which is blank and a command line which is a comment: The blank line causes the debugger to repeat the previous command while the comment line does not.
Commands usually start with, and often contain, keywords. These keywords must be lowercase.
A command is one of:
command : alias_command | attach_command | braced_command_list | breakpoint_command | browse_source_command | call_stack_command | command_repetition_command | continue_command | detach_command | dbgvar_command | edit_file_command | environment_variable_command | execute_commands_from_file_command | execute_shell_command | guion_command | help_command | history_command | kernel_debugging_command | kill_command | load_command | look_around_command | machinecode_level_command | modifying_command | multiprocess_command | quit_command | record_command | run_command | snapshot_command | shared_library_command | thread_command | unload_command
In debugger commands, the identifiers in the following list are treated as keywords unless they are somewhere within parentheses:
For example:
(ladebug) print state
line: 24 Unable to parse input as legal command or C++ expression.
(ladebug) print (state)
1
(ladebug) print (3 * state) + 4
7
It is possible to surround a command_list with braces to make it work like a single command. There are places in the grammar that require a braced_command_list just for readability, or to assist the debugger in understanding your input.
braced_command_list :{ command_list }
There are three different varieties of debugger variables:
User-defined variables | Created by you and can be set to a value of any type. |
Preference variables | Can be modified by you to change debugger behavior. You can only set the variable to a value that is valid for that particular variable. |
Display/state variables | Displays the parts of the current debugger state and cannot be modified by you. |
For more information about debugger variables, see Appendix 1Debugger variables.
The commands that specifically deal with debugger variables are:
dbgvar_command :set |dbgvar_name = expression | set dbgvar_name set | unset dbgvar_name
The dbgvar_name should not exist anywhere in your program, or you may confuse yourself about which of the occurrences you are actually dealing with. The predefined debugger variables all start with a dollar sign ($), to help avoid this confusion. It is strongly recommended that you follow the same practice; in a future release of Ladebug, Ladebug will require that all debugger variables start with a dollar sign.
NOTE: If there is a debugger variable which shares a name with a program variable, and you print an expression involving that name, which of the two Ladebug finds is undefined.
The first form creates the debugger variable if it doesn't already exist. It then sets the value of the debugger variable to the result of evaluating the expression.
(ladebug) set $myLoopCounter = 0
(ladebug) print $myLoopCounter
0
The second form is equivalent to the command set dbgvar_name = 1.
(ladebug) print $stoponattach
0
(ladebug) set $stoponattach
(ladebug) print $stoponattach
1
The set form shows all the debugger variables and their values.
(ladebug) set
$ascii = 0
$beep = 1
$catchexecs = 0
$catchforkinfork = 0
$catchforks = 0
$curevent = 0
$curfile = "x_list.cxx"
$curfilepath = "../src/x_list.cxx"
$curline = 182
$curpc = 0x3ff8001bde8
$curprocess = 14688
$cursrcline = 182
$curthread = 3
$dbxoutputformat = 0
$dbxuse = 0
$decints = 0
$doverbosehelp = 1
$editline = 1
$eventecho = 1
$funcsig = 1
$giveladebughints = 1
$hasmeta = 0
$hexints = 0
$historylines = 20
$indent = 1
$lang = "C++"
$lasteventmade = 0
$lc_ctype = "en_US.ISO8859-1"
$listwindow = 20
$main = "\"x_list.cxx\"`main"
$maxstrlen = 128
$myLoopCounter = 0
$octints = 0
$overloadmenu = 1
$page = 1
$pagewindow = 0
$pimode = 1
$prompt = "(ladebug) "
$repeatmode = 1
$showlineonstartup = 0
$showwelcomemsg = 1
$stackargs = 1
$statusargs = 1
$stepg0 = 0
$stoponattach = 1
$stopparentonfork = 0
$usedynamictypes = 1
$verbose = 0
To see the value of just one debugger variable, print it. For example:
(ladebug) print $catchexecs
0
The unset form deletes the debugger variable. Some predefined debugger variables either can't be deleted, or are automatically recreated in the future when needed.
(ladebug) unset $myLoopCounter
(ladebug) print $myLoopCounter
Symbol "$myLoopCounter" is not defined.
Error: no value for $myLoopCounter
command_repetition_command :To repeat the last command line, enter two exclamation points or press the Return key. You can also enter !-1.!! | ! integer | !- integer | ! string
To repeat a command line entered during the current debugging session, enter an exclamation point followed by the integer associated with the command line. (Use the history command to see a list of commands used.) For example, to repeat the seventh command used in the current debugging session, enter !7. Enter !-3 to repeat the third-to-the-last command. See also History replacement of the line.
To repeat the most recent command starting with a string, use the last form of the command. For example, to repeat a command that started with bp, enter !bp.
There are other ways to reuse old commands and save typing effort:
If you place commands in a file, you can execute them directly from the file rather than cutting and pasting them to the terminal.
execute_commands_from_file_command :Use the source command to read and execute commands from a file. (Note that you can also execute debugger commands when you invoke the debugger by creating an initialization file named .dbxinit.) These commands can be nested, and as each comes to an end, reading resumes from where it left off in the previous file.source filename | playback input filename
Be aware, however, that blank lines in these files repeat the last command, just as they do when entered from the terminal. Format the commands as if they were entered at the debugger prompt.
Use '#' to create comments to format your scripts.
The following example shows how to execute a debugger script. Given the following script:
(ladebug) sh cat ../src/myscript
step
where 2
The following example shows how to execute it.
(ladebug) run
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
(ladebug) source ../src/myscript
stopped at [List<Node>::List(void):121 0x120001d74]
121 List<NODETYPE>::List() : _firstNode(NULL)
>0 0x120001d74 in ((List<Node>*)0x11ffff228)->List() "x_list.cxx":121
#1 0x120002400 in main() "x_list.cxx":182
When a command file is executed, the value of the
$pimode debugger
variable determines whether the commands are echoed. If the $pimode
variable is set to 1, commands are echoed; if $pimode is set to 0
(the default), commands are not echoed. The debugger output resulting
from the commands is always echoed.
record_command :record io [ filename ] | record input [ filename ] | record output [ filename ]
Use record input to save Ladebug commands to a file. The commands in the file can be executed using the source command or the playback input command.
If no file name is specified, the debugger creates a file with a random file name in /tmp as the record file. The debugger issues a message giving the name of that file.
To stop recording debugger input or output, redirect as shown in the following example or exit the debugger:
(ladebug) record input /dev/null
(ladebug) record output /dev/null
The following example shows how to use the
record input command to record a series of debugger commands in a
file named myscript.
(ladebug) record input myscript
(ladebug) stop in main
[#1: stop in int main(void) ]
(ladebug) run
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
(ladebug) record input /dev/null
The recorded input in myscript :
(ladebug) sh cat myscript
stop in main
run
record input /dev/null
The record output command saves the debugger output to a file.
The output is simultaneously written to stdout (normal output) or
stderr (error messages). For example:
(ladebug) record output myscript
(ladebug) stop in List<Node>::append
[#2: stop in void List<Node>::append(class Node* const) ]
(ladebug) cont
[2] stopped at [void List<Node>::append(class Node* const):148 0x120001d9c]
148 if (!_firstNode)
(ladebug) next
stopped at [void List<Node>::append(class Node* const):149 0x120001da8]
149 _firstNode = node;
After the above commands are executed, myscript contains:
(ladebug) sh cat myscript
[#2: stop in void List<Node>::append(class Node* const) ]
[2] stopped at [void List<Node>::append(class Node* const):148 0x120001d9c]
148 if (!_firstNode)
stopped at [void List<Node>::append(class Node* const):149 0x120001da8]
149 _firstNode = node;
The record io command saves both input to and output from the debugger. For example:
(ladebug) record io myscript (ladebug) stop in main [#1: stop in int main(void) ] (ladebug) run [1] stopped at [int main(void):12 0x120001130] 12 int i; (ladebug) quit % cat myscript (ladebug) stop in main [#1: stop in int main(void) ] (ladebug) run [1] stopped at [int main(void):12 0x120001130] 12 int i; (ladebug) quit
history_command :For example:history [ integer_constant ]
(ladebug) history 6
18: stop in main
19: run
20: stop in CompoundNode::CompoundNode
21: cont
22: print "history_EXAMPLE START"
23: history 6
When the debugger is tokenizing a command line, it expands aliases and then retokenizes the expansion.
alias_command :alias [ alias_name ] | alias alias_name [ ( argument_name ,... ) ] string | unalias alias_name
The following example shows how to define and use an alias.
(ladebug) alias cs
alias cs is not defined
(ladebug) alias cs "stop at 186; run"
(ladebug) cs
[#1: stop at "x_list.cxx":186 ]
[1] stopped at [int main(void):186 0x120002420]
186 IntNode* newNode = new IntNode(1);
The following example further modifies the cs alias to specify the breakpoint's line number when you enter the cs command.
(ladebug) alias cs (x) "stop at x; run"
(ladebug) cs(186)
[#2: stop at "x_list.cxx":186 ]
Process has exited
[2] stopped at [int main(void):186 0x120002420]
186 IntNode* newNode = new IntNode(1);
Use the unalias command followed by an alias name to delete the
specified alias.
execute_shell_command :For example, you can spawn a shell from the debugger by issuing:sh string
(ladebug) sh ls out
out
(ladebug)
To execute more than one command at the specified
shell, spawn a shell as follows, for example:
(ladebug) sh csh
% ls out
out
% ls *.b
recio.b
stdio.b
% exit
(ladebug)
edit_file_command :The editor is given the string as the file name to edit. If no file name is specified, the editor is given the current file. If there is no current file, the editor is started without a file.edit [ string ]
If the EDITOR environment variable is undefined, the debugger invokes the vi editor.
The following example shows invoking the Emacs editor on file chars.c:
(ladebug) sh printenv EDITOR emacs (ladebug) file chars.c (ladebug) editThe following example shows invoking the nedit editor on file ~/foo/bar.f:
(ladebug) sh printenv EDITOR nedit (ladebug) edit ~/foo/bar.f
Specifying an executable file on the shell command line or executing the load command causes the debugger to gain control of a process that you may request it to create later.
NOTE: In the background, the debugger immediately creates a process executing the program, stalls it, and uses it to answer questions about which shared libraries are mapped, etc. This process never continues, and is killed when:
Using the run command on such a potential process causes the debugger to create a process which is identified as currently running and recreatable.
Specifying a pid on the shell command line or executing the attach command causes the debugger to know about the process as currently running and not recreatable.
Catching a fork() causes the new child process to be identified as currently running and not recreatable.
As you enter the debugger commands to manipulate your process, it would be very tedious to have to repeatedly specify which thread, source file, etc., you wish the command to be applied to. To prevent this, each time the debugger stops the process, it re-establishes a static context and a dynamic context for your commands. The components of the static context are independent of this run of your program; the components of the dynamic context are dependent on this run.
Some pieces of these contexts are available as debugger variables.
You can switch most of these individually to point to other instances, as described in the relevant portions of this manual, and the debugger will modify the rest of the static and dynamic context to keep the various components consistent.
However, sometimes the program requires more context, or a process may already have been created. Perhaps it is part of a pipe, perhaps it is a long-running process, or perhaps it is created from a shell script or makefile.
Hence, the following situations are possible:
For example:
% ladebug a.outor
% ladebug (ladebug) load a.out
For example:
% ladebug -pid process_id a.outor
% ladebug (ladebug) attach process_id a.out
When you do this, the process continues execution until it raises a signal that the debugger intercepts, for example, $stoponattach.
One method you can use to make the attach work in a predictable way is to modify your program to loop in a known function until the debugger interrupts it, for example, when you use Ctrl/C:
volatile int endStallForDebugger=0; void stallForDebugger() { while (!endStallForDebugger) ; } int main() { ... stallForDebugger(); ... }
(ladebug) assign endStallForDebugger = 1 (ladebug) set any needed breakpoints etc. (ladebug) cont
load_command :For example:load filename [ filename ]
% ladebug /usr/examples/x_listor:
(ladebug) listobj
Program is not active
(ladebug) load /usr/examples/x_list
Reading symbolic information ...done
(ladebug) listobj
section Start Addr End Addr
------------------------------------------------------------------------------
/usr/examples/x_list
.text 0x120000000 0x120003fff
.data 0x140000000 0x140001fff
/usr/lib/cmplrs/cxx/libcxx.so
.text 0x3ff81f00000 0x3ff81f31fff
.data 0x3ffc1700000 0x3ffc1707fff
.bss 0x3ffc1708000 0x3ffc170803f
/usr/shlib/libexc.so
.text 0x3ff807b0000 0x3ff807b5fff
.data 0x3ffc0210000 0x3ffc0211fff
/usr/shlib/libc.so
.text 0x3ff80080000 0x3ff8019ffff
.data 0x3ffc0080000 0x3ffc0093fff
.bss 0x3ffc0094000 0x3ffc00a040f
The second file name is used to specify a core file. If you specify a core file,
the debugger acts as though it is attached
to the process just before it died, except that you cannot execute commands
that require a runnable process, such as commands that try to continue the
process or evaluate function calls.
Creating a process both creates the debugger's knowledge of it, and makes it the current process that the debugger is controlling.
The opposite of loading an executable file is unloading an executable file.
unload_command :The unload command removes all related symbol table information that the debugger associated with the process being debugged, specified by either a process id or executable file. For example:unload pid ,... | unload filename
(ladebug) listobj
section Start Addr End Addr
------------------------------------------------------------------------------
/usr/examples/x_list
.text 0x120000000 0x120003fff
.data 0x140000000 0x140001fff
/usr/lib/cmplrs/cxx/libcxx.so
.text 0x3ff81f00000 0x3ff81f31fff
.data 0x3ffc1700000 0x3ffc1707fff
.bss 0x3ffc1708000 0x3ffc170803f
/usr/shlib/libexc.so
.text 0x3ff807b0000 0x3ff807b5fff
.data 0x3ffc0210000 0x3ffc0211fff
/usr/shlib/libc.so
.text 0x3ff80080000 0x3ff8019ffff
.data 0x3ffc0080000 0x3ffc0093fff
.bss 0x3ffc0094000 0x3ffc00a040f
(ladebug) unload
Process has exited
(ladebug) listobj
Program is not active
run_command :rerun is a synonym for run.run [ argument_string ] [ io_redirection ... ] | rerun [ argument_string ] [ io_redirection ... ]
If the rerun command is specified without arguments, the arguments and io_redirection entered with the most recent run command entered with arguments are used. If the last modification time and/or size of the binary file or any of the shared objects used by the binary file has changed since the last run or rerun command was issued, the debugger automatically rereads the symbol table information. If this happens, the old breakpoint settings may no longer be valid after the new symbol table information is read.
The argument_string provides both the argc and argv for the created process in the same way a shell does.
The debugger breaks up the argument_string into words, and supports several shell features, including tilde (~) and environment variable expansion, wildcard substitution, single quote ('), double quote ("), and single character quote (\).
The io_redirection allows you to change stdin, stdout, and stderr, which are otherwise inherited from the debugger process.
io_redirection :The various forms have the same effect as in the csh(1) shell. NOTE: Although the grammar currently allows more than the following forms of redirection, you should only use the following because we may change the grammar in the future.< filename | > filename | 1> filename | 2> filename | >& filename
> filename Redirect stdout 1> filename Redirect stdout 2> filename Redirect stderr >& filename Redirect stdout and stderr 1> filename 2> filename Redirect stdout and stderr to different filesFor example:
(ladebug) stop in main
[#1: stop in int main(void) ]
(ladebug) run -s > prog.output
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
You can kill the current process:
kill_command :Killing a process leaves the debugger running. Any breakpoints previously set are retained. You can later rerun the program. For example:kill
(ladebug) show process
Current Process: localhost:523 (/usr/examples/x_list) paused.
(ladebug) kill
Process has exited
(ladebug) rerun
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
Information: you can restart the execution of your program
from saved positions. Enter "help snapshot" for details.
attach_command :The process is specified by its pid.attach pid [ filename ]
pid : expressionExample:
(ladebug) attach 12345 a.outThe file name must be an executable file that the process is executing, or a copy of it, or an unstripped copy of it. If file name is not specified, the current executable is used.
Attaching to a process both creates the debugger's knowledge of it, and makes it the current process that the debugger is controlling. When you do this, the process continues execution until it raises a signal that the debugger intercepts. Usually you do this by typing Ctrl/C or using the shell command kill in another window. Any other mechanism for raising a signal within the process will also do. You can set the debugger variable $stoponattach to 1 to direct the debugger to immediately stop any process that it attaches to.
(ladebug) ^C Interrupt (for process) Stopping process localhost:16077 (loop.out). Thread received signal INT stopped at [int main(void):3 0x120001100] 3 while (1) ;
The opposite of attaching to a process is detaching from a process. When you detach the debugger from a process, all breakpoints are removed and the process continues to run but the debugger can no longer identify or control it.
detach_command :Example:detach pid ,...
(ladebug) detach 12345,789
NOTE: The environment commands have no effect on the environment of any currently running process. The environment commands do NOT change or show the environment variables of the debugger or of the current process. They only affect the environment variables that will be used when a new process is created.
environment_variable_command : show_environment_variable_command | set_environment_variable_command | unset_environment_variable_commandTo print either all the environment variables that are currently set, or a specific one, use a show_environment_variable_command.
show_environment_variable_command :NOTE: export and setenv without any arguments are equivalent.printenv [ environment_variable_name ] |export | setenv
To add or change an environment variable, use a set_environment_variable_command. If the environment_variable_value is not specified, the environment variable value is set to "".
set_environment_variable_command :export environment_variable_name = environment_variable_value | setenv environment_variable_name environment_variable_value
environment_variable_value : stringFor example:
(ladebug) printenv TOOLDIRECTORY
Error: Environment variable 'TOOLDIRECTORY' was not found in the environment.
(ladebug) setenv TOOLDIRECTORY /usr/examples/tools
(ladebug) printenv TOOLDIRECTORY
TOOLDIRECTORY=/usr/examples/tools
To remove an environment variable, use the unsetenv command.
unset_environment_variable_command :unsetenv environment_variable_name |unsetenv *
If * is specified, all environment variables are removed.
NOTE: There is no way of simply getting back to the initial state of the environment variables after the debugger starts.
At any one time, only one of the processes the debugger controls can be controlled by the user. The rest are stalled. You must explicitly switch the debugger to the process you want to work with, stalling the one it was controlling.
multiprocess_command : show_process_command | switch_process_command
You can show the processes the debugger controls.
show_process_command :Example:show process [ all ] |process all : all | *
(ladebug) show process
>localhost:18348 (/usr/examples/x_list) loaded.
You can explicitly command the debugger to control a different process.
switch_process_command :The process you are switching away from remains stalled until either the debugger exits, or you switch to it and continue it.process pid |process filename
The following example creates two processes and switches from one to the other.
(ladebug) process
There is no current process.
You may start one by using the `load' or `attach' commands.
(ladebug) load /usr/examples/x_list
Reading symbolic information ...done
(ladebug) process
>localhost:18331 (/usr/examples/x_list) loaded.
(ladebug) set $old_process = $curprocess
(ladebug) print $old_process
18331
(ladebug) load /usr/examples/x_segv
Reading symbolic information ...done
(ladebug) process
localhost:18331 (/usr/examples/x_list) loaded.
>localhost:18327 (/usr/examples/x_segv) loaded.
(ladebug) process $old_process
(ladebug) process
>localhost:18331 (/usr/examples/x_list) loaded.
localhost:18327 (/usr/examples/x_segv) loaded.
Both the run command and the attach command switch the debugger to the process they operate on.
When a fork occurs, the debugger sets the debugger variables $childprocess and $parentprocess to the child and parent process IDs, respectively.
In the following example, the debugger notifies you that the child process has stopped. The parent process continues to run.
(ladebug) set $catchforks = 1
(ladebug) run
Process 29027 forked. The child process is 29023.
Process 29023 stopped on fork.
stopped at [int main(void):6 0x120001178]
6 int pid = fork();
fork.c: I am the parent.
Process has exited with status 0
(ladebug) show process
>localhost:29028 (/usr/examples/fork) loaded.
localhost:29023 (/usr/examples/fork) paused.
Note:
Continuing the previous example, the following shows how to switch the debugger to the child process. Listing the source code shows the source for the child process.
(ladebug) process $childprocess
(ladebug) show process
localhost:29028 (/usr/examples/fork) loaded.
>localhost:29023 (/usr/examples/fork) paused.
(ladebug) list
7
8 if (pid == 0)
9 {
10 printf("fork.c: I am the child.\n");
11 }
12 else
13 {
14 printf("fork.c: I am the parent.\n");
15 }
16 }
NOTE:
In the following scenario, you set the predefined variable $catchforks and $catchexecs to 1. The debugger will notify you when an exec occurs. Because $catchforks is set, you will also be tracking the child process and, therefore, you will be notified of any exec in the child process.
The following example shows an exec occurring on the current context and the child process stopped on the runtime-loader entry point.
(ladebug) set $catchforks = 1
(ladebug) set $catchexecs = 1
(ladebug) run
Process 14839 forked. The child process is 14835.
Process 14835 stopped on fork.
stopped at [int main(void):8 0x1200011f8]
8 if ((pid = fork()) == 0)
x_exec.c: I am the parent.
Process has exited with status 0
(ladebug) show process
>localhost:14918 (x_exec) loaded.
localhost:14835 (x_exec) paused.
(ladebug) process $childprocess
(ladebug) list 6: 13
6 int pid;
7
> 8 if ((pid = fork()) == 0)
9 {
10 printf("About to exec \n");
11 fflush(stdout); /* Make sure the output gets out! */
12 execlp("announcer", "announcer", NULL);
13 printf("After exec \n");
14 }
15 else
16 {
17 printf("x_exec.c: I am the parent.\n");
18 }
(ladebug) cont
About to exec
The process 14835 has execed the image "./announcer".
Reading symbolic information ...done
stopped at [ 0x3ff8001bf48]
5 printf("announcer.c: I am here!! \n");
Note:
By default, compilation does not strip the symbol table information and optimization is only partial. If you do not change these defaults, there should not be a problem.
For example:
(ladebug) patch @foo = 20
You can modify the current thread context by setting $tid to a valid thread identifier.
The debugger variable $tid is the same as $curthread except that $tid is used for kernel debugging.
Invoke the debugger with the following command:
# ladebug -k /vmunix /dev/memThe -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.
Now you can use Ladebug commands to display the current process identification numbers (pids) and trace the execution of processes. The following example shows the use of the kps command to display the process IDs:
kernel_debugging_command :For example:kps
(ladebug) kps 00000 kernel idle 00001 init 00003 kloadsrv 00020 update 02082 dtexec 02092 dtterm 02093 csh ...The Ladebug commands cont, next, rerun, run, step, 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 you want to examine the stack of, for example, the kloadsrv daemon, you set the $pid symbol to its pid(3) and enter the where command, as in the following example:
(ladebug) set $pid = 3 (ladebug) where >0 0xfffffc00002b3a10 in thread_block()Examining the stack trace may reveal the problem. Then you can modify parameters, restart daemons, or take other corrective actions.
The operating system can crash in the following ways:
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 the uerf utility to examine the error log. Using these tools, you can determine which function called the panic() routine.
Crash dump files, such as vmunix.n and vmcore.n, usually reside in the /var/adm/crash directory. The version number (n in vmunix.n and vmcore.n ) must match for the two files.
For example, you might use the following command to examine dump files:
# ladebug -k vmunix.1 vmcore.1
(ladebug) print savedefp/33X ffffffff9618d940: 0000000000000000 fffffc000046f888 ffffffff9618d950: ffffffff86329ed0 0000000079cd612f . . . ffffffff9618da30: 0000000000901402 0000000000001001 ffffffff9618da40: 0000000000002000
(ladebug) print *pmsgbuf struct msgbuf { msg_magic = 405601; msg_bufx = 1851; msg_bufr = 1343; msg_bufc = "Alpha boot: available memory from 0x6ca000 to 0x3f16000\nDigital UNIX V4.0B (Rev. 564); Fri Jul 11 11:25:29 EDT 1997 \nphysical m"; }
See Compaq TRU64 UNIX Kernel Debugging and the crashdc man page for more information.
(ladebug) assign partial_dump = 0
See Compaq TRU64 UNIX Kernel Debugging for more information.
NOTE: Crash dump analysis is possible only with local, not remote, kernel debugging.
To determine why a problem is happening, you usually want to execute your program up to or just before the point that the first evidence of the problem is observed. Then you can examine the internal state of your program and try to identify something that explains the visible problem. Possibly you will see right away how the problem occurs, in which case you are finished debugging. You then correct your program, recompile, relink, and confirm that the correction works as intended.
Often, you will see something about the program state that is wrong but not how it got that way. In that case, you need to make a guess at where the mistake might have occurred. Then, repeat this whole process, trying to stop at or just before the possible trouble point.
For simple problems, it may be easy to describe the conditions under which you want to stop the program; for example, "the first time traverse is called" or "when division_by_zero occurs". Other situations may require either more complex descriptions or repeated trial-and-error attempts to discover the critical information needed to solve your problem. Breakpoints provide the means by which you specify to the debugger an event (or condition) under which you want to intervene in the execution of your program and what action(s) you want the debugger to take when that event is detected.
You can define breakpoints based on:
Breakpoint commands include the following:
breakpoint_command : breakpoint_definition_command | simple_stop_command | signal_command | obsolete_breakpoint_definition_command | breakpoint_table_command
A particularly common breakpoint is:
(ladebug) stop in main
[#1: stop in int main(void) ]
This command tells the debugger that when execution enters the function
main, you want the debugger to suspend execution and return control
to you.
The debugger responds to a breakpoint command by displaying how it recorded the request internally. The debugger assigns a number to the breakpoint (in this case, it is 1), which it uses later to refer to that breakpoint. The debugger does not just repeat the command as you entered it; it provides a more complete description of the function main to help you confirm that it has correctly identified the function you meant.
Later, after you cause the program to execute, if that event occurs, the debugger reports the event and then prompts you for what to do next.
(ladebug) run
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
Both the event part and the action part of a breakpoint definition command consist of several subparts:
breakpoint_definition_command : disposition [where the detector, thread_filter (if specified), and logical_filter (if specified) collectively specify the event part, and the disposition, quiet keyword (if specified) and breakpoint_actions (if specified) collectively specify the action part.quiet ] detector [ thread_filter ] [ logical_filter ] [ breakpoint_actions ]
NOTE: There are additional obsolete forms of breakpoint definition that are retained only for backward compatibility with earlier versions of the debugger. These forms are explained later. The obsolete forms may be eliminated in a future release.
There are three distinct points in time at which a breakpoint definition has an effect:
The command is parsed, names and expressions that occur in any of the event parts are evaluated, and the breakpoint actions are parsed and checked for correctness (but not evaluated).
For each breakpoint (that is not disabled), appropriate modifications are made to the program to enable detection of the specified event.
The thread filter specification (if present) and logical filter (if present) are evaluated to determine whether the breakpoint as a whole has triggered. If not, then execution is resumed (silently). If so, the breakpoint actions are performed, after which execution stops or resumes according to the specified disposition.
disposition : stop | whenstop specifies that when the event specified by the breakpoint occurs and all processing for that breakpoint has been completed, the debugger should prompt for further commands.
when specifies that when the event specified by the breakpoint occurs and all processing for that breakpoint has been completed, the debugger may resume execution of the program. See the section When multiple breakpoints trigger at once for an explanation of how the debugger determines when to resume execution.
By default, when an event is detected and the debugger determines that the breakpoint actions should be performed, the debugger prints a line that identifies the breakpoint, for example:
(ladebug) when in main { stop }
[#1: when in int main(void) { stop } ]
(ladebug) run
[1] when [int main(void):182 0x1200023f8]
[1] stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
The optional quiet keyword tells the debugger to omit this
information.
There are several kinds of detector, each corresponding to a particular kind of event.
detector : place_detector | watch_detector | signal_detector | unaligned_detector
A place detector specifies a place or location in your program. It can refer to the beginning of a function, a particular line in one of your source files, a specific value of the PC (program counter), or certain sets of these.
A watch detector specifies a variable or other memory location(s) that should be monitored to detect certain kinds of access (read, write, and so on).
A signal detector specifies a set of UNIX signals to be monitored.
An unaligned detector specifies any kind of memory access using an unaligned access.
place_detector : in function_name | in all function_name | pc address_expression | atline_specifier | every proc entry | every procedure entry | every instruction | expression
in function_name specifies the event where execution reaches the entry of the named function.
If the function name is ambiguous (there can be more than one function that matches the name in some languages, including C++), the debugger prompts you with a list of alternatives from which to choose.
(ladebug) stop in foo
Select an overloaded function
----------------------------------------------------
1 int C::foo(double*)
2 void C::foo(float)
3 void C::foo(int)
4 void C::foo(void)
5 None of the above
----------------------------------------------------
2
[#4: stop in void C::foo(float) ]
If you choose the last option ("None of the above") then no function is
selected and no breakpoint is defined.
in all function_name is the same as in function_name except that it specifies all of the functions that match the given name, whether one or more.
(ladebug) stop in all foo
[#3: stop in all foo ]
pc address_expression specifies the event where execution reaches the given machine address.
(ladebug) stop pc 0x120002498
[#7: stop PC == 0x120002498 ]
at line_specifier
specifies the event where code associated with a particular
line of the source is reached.
(ladebug) stop at 190
[#8: stop at "x_list.cxx":190 ]
If there is no code associated with the given line number, the debugger
finds and substitutes the closest higher line number that has
associated code.
every procedure entry specifies that a breakpoint should be established for every function entry point in the program.
(ladebug) stop every procedure entry
[#9: stop every procedure entry ]
NOTE: This command can be very time-consuming because it searches your entire program including all shared libraries that it references and establishes breakpoints for every entry point in every executable image! This can also considerably slow execution of your program as it runs.
A disadvantage of this command is that it establishes breakpoint for hundreds or even thousands of entry points about which you have little or no information. For example, if you use stop every proc entry immediately after loading a program and then run it, the debugger will stop or trace over 100 entry points before reaching your main entry point! About the only thing that you can do if execution stops at most such unknown places is continue until some function relevant to your debugging is reached.
every instruction specifies a breakpoint for every instruction in your entire program.
(ladebug) stop every instruction
[#10: stop every instruction ]
When used with the stop
disposition, a subsequent continue behaves essentially the same
as a step by instruction command (see stepi).
When used with the when disposition, subsequent next and step commands allow you to trace all of the instructions that are executed as a result of those stepping commands. Beware that even when next is used to step over a called routine, the trace output includes all of the instructions that are executed within the called routine (and any routines that it calls). NOTE: This command will slow execution of your program considerably.
The detector expression (that is, an expression not preceded by one of the keywords in, at, or pc) specifies either a function name or line number depending on how the expression is parsed and evaluated. An expression that evaluates to the name of a function is handled just like the equivalent command that uses in in the detector; otherwise, it is handled like the equivalent command that uses at in the detector.
watch_detector : basic_watch_detector watch_detector_modifiers basic_watch_detector : variable variable_name | memorystart_address_expression | memory start_address_expression , end_address_expression | memory start_address_expression : byte_count_expression watch_detector_modifiers : [ access_modifier ] [ within_modifier ] access_modifier : write | read | changed | any within_modifier : within function_name
You can specify a variable whose memory is to be watched, or specify the memory directly. The accesses that are considered can be limited to those that write (the default), read, write and actually change the value, as well as including all accesses.
If a variable is specified, the memory to be watched includes all of the memory for that variable, as determined by the variable's type.
(ladebug) whatis _nextNode
class Node* _nextNode
(ladebug) stop variable _nextNode write
[#3: stop variable _nextNode 0x140001800, 0x140001807 write ]
This watches for write access to variable _nextNode
which is allocated in the 8 bytes
at the address shown in the last line of the above example.
If memory is specified directly in terms of its address, the memory to be watched is defined as follows:
(ladebug) when memory 0x140001800 any
[#4: when memory 0x140001800, 0x140001807 any ]
(ladebug) stop memory 0x140001800, 0x140001803 read
[#5: stop memory 0x140001800, 0x140001803 read ]
This watches the 4 bytes specified on the command line.
(ladebug) stop memory 0x140001800:2 changed
[#6: stop memory 0x140001800, 0x140001801 changed ]
This watches the 2 bytes specified on the command line for a change
in contents.
If a within_modifier is specified, then only those accesses that occur within the given function (but not any function it calls) are watched.
(ladebug) whatis t
int t
(ladebug) stop variable t write within foo
[#2: stop variable t 0x140000248, 0x14000024b write within void C::foo(void) ]
(ladebug) cont
[2] Address 0x140000248 was accessed at:
void C::foo(void): x_overload.cxx
[line 22, 0x12000195c] stl r31, 0(r2)
0x140000248: Old value = 0x0000000f
0x140000248: New value = 0x00000000
[2] stopped at [void C::foo(void):22 0x120001960]
22 void C::foo() { t = 0; state++; return; }
signal_detector : signal signal_id ,... signal_id : integer | signal_nameSignals may be specified by numeric value or by their conventional UNIX names, without or without the leading "SIG".
(ladebug) stop signal 11, 3, 2
[#2: stop signal 11, 3, 2 ]
Note that if the debugger catches a signal event, then a subsequent simple
continue will resume execution without
raising the signal again in your process. However, a signal can be specified
as part of the continue command to send the signal to
your process when it resumes.
unaligned_detector : unaligned
Unaligned accesses are automatically handled by the Tru64 UNIX operating system. By default, an unaligned access results in an information message and then is corrected so that your program can continue. (You or your system manager can choose a different default. See the uac(1) man page for details.) This message looks like this:
Unaligned access pid=30231va=0x11ffff791 pc=0x120001af4 ra=0x120001b84 inst=0xa0220000
You can request the debugger to detect unaligned accesses:
(ladebug) stop unaligned access
[#1: stop unaligned access ]
(ladebug) run
Thread encountered Unaligned Access
[1] stopped at [int unalignedAccess(void):27 0x120001af8]
27 return y;
thread_filter : threadThe thread_id expressions are evaluated at the time the breakpoint command is entered and each must yield an integer value.thread_id ,...
A detected event is retained for further consideration if and only if the thread in which the event occurs matches one of the given thread ids. If not, the detection is quietly ignored.
Note that if the thread_filter does not indicate a match, then any related logical filter is not evaluated.
logical_filter : if expressionA detected event is retained for further consideration if and only if the given expression evaluates to true. If not, the detection is quietly ignored.
The expression is checked syntactically in the context of the place where the breakpoint command is given: it must be syntactically valid according to the language rules that apply there. However, the expression is not evaluated and names that occur in the expression need not be visible. After the syntax check, the expression is remembered in an internal form and is not re-checked later when it is evaluated.
If an error occurs when the expression is evaluated, for example, because a name in the expression is not defined, then the error is reported and the value of the expression is assumed to be true.
Note that an error in the expression does not change the disposition. If continuation was specified, then that is still what occurs.
(ladebug) when in List<Node>::append if x
[#5: when in void List<Node>::append(class Node* const) if x ]
(ladebug) cont
Symbol "x" is not defined.
[Error while evaluating breakpoint condition - taken as true]
[5] when [void List<Node>::append(class Node* const):148 0x120001d9c]
Symbol "x" is not defined.
[Error while evaluating breakpoint condition - taken as true]
[5] when [void List<Node>::append(class Node* const):148 0x120001d9c]
[4] stopped at [int main(void):194 0x1200025cc]
194 IntNode* newNode2 = new IntNode(4);
It is valid for a logical filter expression to contain a call to another routine in your program. Such a call is evaluated in the same way as if it occurred in a call or print command. However, execution of the called routine might result in triggering a breakpoint; this is called a recursive breakpoint and is discussed later.
breakpoint_actions : { action_list } action_list : command | command ; | command ;...
A simple_stop_command is a stop without any detector or other parameters.
simple_stop_command : stopIf used within a breakpoint action list it specifies that the disposition for the breakpoint should be to stop after completion of action list processing, even if the breakpoint was specified with the when disposition. If used outside an action list, it has no effect.
Note that a simple stop command does not terminate action list processing; it only affects the disposition that applies later.
(ladebug) when in List<Node>::print { stop ; print "*** stopped ***"}
[#6: when in void List<Node>::print(void) { stop ; print "*** stopped ***"} ]
(ladebug) cont
[6] when [void List<Node>::print(void):162 0x120001e70]
*** stopped ***
[6] stopped at [void List<Node>::print(void):162 0x120001e70]
162 Node* currentNode = _firstNode;
The history command does not display commands that are performed as part of the action list of a breakpoint.
It is easy in such cases to lose track of just what state breakpoint processing is really in and/or where you really are in your program. Such confusion may mislead or misdirect your debugging effort. For further discussion, see the section on Recursive breakpoints.
The debugger does not explicitly prohibit these commands, but their behavior within action lists is implementation-defined and subject to change from release to release. In very specialized cases, you may be able to obtain useful results by using them in action lists, but do not expect the same behavior over the long term.
When more than one breakpoint detector triggers, the thread filters and logical filters of all the breakpoints involved are processed before the action part of any breakpoint is performed.
After the set of breakpoints that trigger is determined, the action parts of each of them are performed in an undefined order.
After all action parts are performed, execution of the program is resumed if and only if all of the breakpoints so specify in their disposition. If any one of them specifies break, the debugger prompts you for further commands.
In all of these cases, the debugger temporarily "suspends" processing of the current breakpoint to start your program executing again and then waits for that execution to complete. As long as no new breakpoint is triggered during that execution, all will be fine. However, if a new breakpoint triggers, in particular one with the stop disposition, then you may be prompted for new command input for the recursive breakpoint even before the initial breakpoint has completed. Further, continuing execution may ultimately allow the original breakpoint to complete, at which time its disposition will come into play.
It is easy in such cases to lose track of just what state breakpoint processing is really in and/or where you really are in your program. Such confusion may mislead or misdirect your debugging effort. See example which locates suspended execution in nested function calls.
(ladebug) list 3: 25
3 class C {
4 public:
5 void foo();
6 void foo(int);
7 void foo(float);
8 int foo(double *);
9 };
10
11 C o;
12 C* p = new C;
13 int t = 0;
14 int state = 1;
15
16 main(){
17 t++;
18 o.foo();
19
20 }
21
22 void C::foo() { t = 0; state++; return; }
23 void C::foo(int i) { state++; return; }
24 void C::foo(float f) { state++; return; }
25 int C::foo(double *) { return state;}
Member functions must be named in a way that makes them visible at the current position according to the normal C++ visibility rules.
(ladebug) stop in main
[#1: stop in int main(void) ]
(ladebug) run
[1] stopped at [int main(void):17 0x120001924]
17 t++;
(ladebug) stop in foo
Symbol "foo" is not defined.
foo has no valid breakpoint address
Warning: Breakpoint not set
If not positioned within a member function of a class, it is generally necessary to name the desired member function using type qualification, an object of the class type, or a pointer to an object of the class type.
(ladebug) stop in C::foo
Select an overloaded function
----------------------------------------------------
1 int C::foo(double*)
2 void C::foo(float)
3 void C::foo(int)
4 void C::foo(void)
5 None of the above
----------------------------------------------------
3
[#5: stop in void C::foo(int) ]
(ladebug) stop in o.foo
Select an overloaded function
----------------------------------------------------
1 int C::foo(double*)
2 void C::foo(float)
3 void C::foo(int)
4 void C::foo(void)
5 None of the above
----------------------------------------------------
1
[#6: stop in int C::foo(double*) ]
(ladebug) stop in p->foo
Select an overloaded function
----------------------------------------------------
1 int C::foo(double*)
2 void C::foo(float)
3 void C::foo(int)
4 void C::foo(void)
5 None of the above
----------------------------------------------------
4
[#7: stop in void C::foo(void) ]
You can avoid the ambiguity associated with an overloaded function by specifying a complete signature for the function name.
(ladebug) stop in C::foo(void)
[#8: stop in void C::foo(void) ]
(ladebug) stop in C::foo(int)
[#9: stop in void C::foo(int) ]
Debugging of template instantiations is illustrated using this source text.
(ladebug) list 144: 13
144 template <class NODETYPE>
145 void List<NODETYPE>::append(NODETYPE* const node)
146 {
147
148 if (!_firstNode)
149 _firstNode = node;
150 else {
151 Node* currentNode = _firstNode;
152 while (currentNode->getNextNode())
153 currentNode = currentNode->getNextNode();
154 currentNode->setNextNode(node);
155 }
156 }
Normal debugging commands then apply to the instantiation (not the template as such).
(ladebug) whatis List<Node>::append
void List<Node>::append(class Node*)
(ladebug) stop in List<Node>::append
[#1: stop in void List<Node>::append(class Node* const) ]
(ladebug) run
[1] stopped at [void List<Node>::append(class Node* const):148 0x120001d9c]
148 if (!_firstNode)
(ladebug) where 2
>0 0x120001d9c in ((List<Node>*)0x11fffed08)->append(node=0x140001800) "x_list.cxx":148
#1 0x1200024a4 in main() "x_list.cxx":187
terminate | Gains control when any unhandled exception occurs, which will result in program termination. | unexpected | Gains control when a function containing an exception specification tries to throw an exception that is not included in that specification. |
These special library functions are illustrated using the following source:
(ladebug) list 30: 29
30 // Throw an exception. The "throw(int)" syntax tells the compiler that
31 // only integer exceptions can escape this method. This will result in
32 // an unexpected exception from C++.
33 //
34 void throwAnException() throw(int)
35 {
36 throw "Bug";
37 }
38
39 // Provide some depth to the stack, for demonstration purposes
40 //
41 void someOperation()
42 {
43 int z = unalignedAccess(); // Some tests ignore this exception
44 throwAnException();
45 }
46
47 main()
48 {
49 try {
50 someOperation();
51 }
52 catch(char* str) {
53 cout << "Caught exception [" << str << "]" << endl;
54 }
55 catch(...) {
56 cout << "Caught something" << endl;
57 }
58 }
You can trace the flow of execution as in the following:
(ladebug) stop at 52
[#1: stop at "x_signals.cxx":52 ]
(ladebug) stop in all terminate
[#2: stop in all terminate ]
Information: An <opaque> type was presented during execution of the previous command. For complete type information on this symbol, recompilation of the program will be necessary. Consult the compiler man pages for details on producing full symbol table information using the -g (and -gall for cxx) flags.
(ladebug) stop in all unexpected
[#3: stop in all unexpected ]
(ladebug) run ...
[3] stopped at [<opaque> unexpected(void) 0x3ff81f2effc]
(ladebug) where
>0 0x3ff81f2effc in unexpected(0x0, 0x0, 0x0, 0x0, 0x0, 0x0) in /usr/lib/cmplrs/cxx/libcxx.so
#1 0x120001b38 in throwAnException() "x_signals.cxx":36
#2 0x120001b88 in someOperation() "x_signals.cxx":44
#3 0x120001bc4 in main() "x_signals.cxx":50
#4 0x1200019c8 in __start(0x0, 0x0, 0x0, 0x0, 0x0, 0x0) in /usr/examples/x_signals
(ladebug) cont
[3] stopped at [<opaque> unexpected(...) 0x3ff81f160b4]
(ladebug) where
>0 0x3ff81f160b4 in unexpected(0x3ffc1700078, 0x3ff81f14c10, 0x0, 0x0, 0x0, 0x0) in /usr/lib/cmplrs/cxx/libcxx.so
#1 0x3ff81f2effc in unexpected(0x3ffc1700078, 0x3ff81f14c10, 0x0, 0x0, 0x0, 0x0) in /usr/lib/cmplrs/cxx/libcxx.so
#2 0x120001b38 in throwAnException() "x_signals.cxx":36
#3 0x120001b88 in someOperation() "x_signals.cxx":44
#4 0x120001bc4 in main() "x_signals.cxx":50
#5 0x1200019c8 in __start(0x3ffc1700078, 0x3ff81f14c10, 0x0, 0x0, 0x0, 0x0) in /usr/examples/x_signals
(ladebug) cont
[2] stopped at [<opaque> terminate(...) 0x3ff81f15f7c]
(ladebug) where
>0 0x3ff81f15f7c in terminate(0x3ffc1700090, 0x3ff81f14c10, 0x11fffeb98, 0x0, 0xa0, 0x0) in /usr/lib/cmplrs/cxx/libcxx.so
#1 0x3ff81f16100 in unexpected(0x3ffc1700090, 0x3ff81f14c10, 0x11fffeb98, 0x0, 0xa0, 0x0) in /usr/lib/cmplrs/cxx/libcxx.so
#2 0x3ff81f2effc in unexpected(0x3ffc1700090, 0x3ff81f14c10, 0x11fffeb98, 0x0, 0xa0, 0x0) in /usr/lib/cmplrs/cxx/libcxx.so
#3 0x120001b38 in throwAnException() "x_signals.cxx":36
#4 0x120001b88 in someOperation() "x_signals.cxx":44
#5 0x120001bc4 in main() "x_signals.cxx":50
#6 0x1200019c8 in __start(0x3ffc1700090, 0x3ff81f14c10, 0x11fffeb98, 0x0, 0xa0, 0x0) in /usr/examples/x_signals
(ladebug) cont
Thread received signal ABRT
stopped at [<opaque> __kill(...) 0x3ff800ea6c8]
signal_command : catch_command | ignore_command catch_command : catch [ signal_id ] ignore_command : ignore [ signal_id ]
A catch command with an operand specifies that the given UNIX signal should be caught and handled by the debugger. The signal can be specified by integer number or by standard signal name, with or without the leading "SIG". The catch command is equivalent to the breakpoint command:
(ladebug) catch BUS
or
(ladebug) stop signal 10
[#1: stop signal 10 ]
with these exceptions:
An ignore command with an operand specifies that the given UNIX signal should not be caught or handled by the debugger; rather such a signal is passed to your program. The ignore command is equivalent to deleting the breakpoint created by a catch command for that signal.:
(ladebug) ignore BUS
A catch command without an operand lists all signals that are currently being handled. Similarly, an ignore command without an operand lists the signals that are currently being ignored. Together the two lists show all signals known to the debugger.
You can issue these commands immediately after the debugger starts to show which signals are caught and which are ignored by default:
(ladebug) catch
INT, QUIT, ILL, TRAP, ABRT, EMT, FPE, BUS, SEGV, SYS, PIPE, TERM, URG, STOP, TTIN, TTOU, XCPU, XFSZ, PROF, USR1, USR2, VTALRM, RTMIN, RTMIN1, RTMIN2, RTMIN3, RTMIN4, RTMIN5, RTMIN6, RTMIN7, RTMAX, RTMAX7, RTMAX6, RTMAX5, RTMAX4, RTMAX3, RTMAX2, RTMAX1
(ladebug) ignore
HUP, KILL, ALRM, TSTP, CONT, CHLD, WINCH, IO
Note: Signals RTMIN, RTMIN1,...,RTMIN7, RTMAX, and RTMAX7,...,RTMAX1
apply only on Tru64 UNIX.
(ladebug) catch unaligned
This command is very much like the command:
stop unalignedAlthough this looks like a normal catch command, it differs in several respects:
NOTE: You cannot specify unaligned in a signal detector of a normal breakpoint definition.
You can request the debugger to ignore unaligned accesses when catch unaligned is in effect (the default) using
(ladebug) ignore unaligned
However, if a breakpoint was defined using an
unaligned access detector, then it must
be disabled using a disable or
delete breakpoint command.
If you give the command ignore SIGINT, then it is no longer possible to regain control of your program using Ctrl/C. In that case, signal SIGINT is delivered directly to your program. Unless your program has explicitly arranged otherwise, SIGINT will result in program termination.
The debugger keeps track of the exec() calls that occur so that it can keep track of various properties associated with each executable file. In particular, the breakpoint table is one of those properties. Thus, if you run or rerun your program, the same breakpoints can be re-established, even though a new process is initiated. Similarly, if you work with more than one process, each process has a distinct breakpoint table associated with it.
When a dlopen() system call occurs, the debugger re-processes the current breakpoint table and automatically sets up the means to detect any events that apply to the newly loaded image.
When a dlclose() system call occurs, the debugger also re-processes the breakpoint and de-activates any events that apply to the unloaded image.
obsolete_breakpoint_definition_command : obsolete_watch_breakpoint_definition_command | obsolete_trace_breakpoint_definition_command | obsolete_stopi_breakpoint_definition_command | obsolete_wheni_breakpoint_definition_command | obsolete_tracei_breakpoint_definition_command
obsolete_watch_breakpoint_definition_command : watch obsolete_watch_detector [ obsolete_watch_modifiers ] [ breakpoint_actions ] obsolete_watch_detector : variable variable_name | [ memory ] start_address_expression | [ memory ] start_address_expression , end_address_expression | [ memory ] start_address_expression : byte_count_expression obsolete_watch_modifiers : [ access_modifier ] [ thread_filter ] [ within_modifier ] [ logical_filter ]The differences between an obsolete watchpoint and a stop command are:
(ladebug) watch variable _firstNode write
[#3: watch variable _firstNode 0x11ffff0c8, 0x11ffff0cf write ]
(ladebug) cont
[3] Address 0x11ffff0c9 was accessed at:
void List<Node>::append(class Node* const): x_list.cxx
[line 149, 0x120001db0] stq r2, 0(r3)
0x11ffff0c8: Old value = 0x0000000000000000
0x11ffff0c8: New value = 0x0000000140002c00
[3] stopped at [void List<Node>::append(class Node* const):149 0x120001db4]
149 _firstNode = node;
obsolete_trace_breakpoint_definition_command : trace [ variable_name ] [ thread_filter ] [ where_modifier ] [ logical_filter ] [ breakpoint_actions ] | trace function_name [ logical_filter ] [ breakpoint_actions ] | traceThe differences between an obsolete tracepoint and a when command are:line_number [ logical_filter ] [ breakpoint_actions ] where_modifier : in function_name | at line_number
Note that the debugger implementation for detecting variable changes tends to be slowat each place where control might be stopped, as specified by the where modifier and filters, the value of the variable is compared to the value remembered at the time execution began.
(ladebug) trace in List<Node>::print
[#7: trace in void List<Node>::print(void) ]
(ladebug) trace i in List<Node>::print
[#8: trace i in void List<Node>::print(void) ]
(ladebug) trace List<Node>::print if i { print "Test 1"}
[#9: trace in void List<Node>::print(void) if i { print "Test 1"} ]
If the trace command is given with no arguments, the debugger prints a trace identification line when each function in your program is entered.
(ladebug) trace
[#10: trace ]
(ladebug) status
#10 at procedure entry { trace-proc }
This is equivalent to the when every proc entry command
(with equivalent performance degradation).
obsolete_stopi_breakpoint_definition_command : stopi [ expression ] [ thread_filter ] [ match_address ] [ logical_filter ] obsolete_tracei_breakpoint_definition_command : tracei [ expression ] [ thread_filter ] [ match_address ] [ logical_filter ] obsolete_wheni_breakpoint_definition_command : wheni [ expression ] [ thread_filter ] [ match_address ] [ logical_filter ] breakpoint_actions match_address : at address_expression
The stopi, tracei, and wheni forms of breakpoint definition are similar to the corresponding stop, trace, and when forms, with these differences:
Note that the Ladebug implementation for detecting variable changes tends to be slow: at each place where control might be stopped, as specified by the where modifier and filters, the value of the variable is compared to the value remembered at the time execution began.
Most importantly, the variable change and filter tests are performed after every instruction is executed, making these definitions especially demanding on program performance.
breakpoint_table_command : show_all_breakpoints_command | delete_breakpoint_command | enable_breakpoint_command | disable_breakpoint_commandEach entry in the breakpoint table has the following properties:
In addition to the main effects of a breakpoint definition as discussed in Breakpoint definitions, a breakpoint definition also sets the debugger variable $lasteventmade to the breakpoint number of the breakpoint just defined. This value can be recalled for later use if desired.
(ladebug) stop in List<Node>::append
[#2: stop in void List<Node>::append(class Node* const) ]
(ladebug) cont
[2] stopped at [void List<Node>::append(class Node* const):148 0x120001d9c]
148 if (!_firstNode)
(ladebug) print $lasteventmade
2
(ladebug) set $my_break = $lasteventmade
(ladebug) print $my_break
2
If an error occurs in a breakpoint command, the variable $lasteventmade is not changed.
show_all_breakpoints_command : statusEach entry in the current breakpoint table is displayed showing all of its properties.
(ladebug) status
#1 PC==0x1200023f8 in int main(void) "x_list.cxx":182 { stop }
#2 PC==0x120001d9c in void List<Node>::append(class Node* const) "x_list.cxx":148 { break }
#3 Access memory (write) 0x11ffff0c8 to 0x11ffff0cf { stop }
When large or complex values are passed by value to the routine in the status line, the output can be voluminous. You can set the control variable $statusargs to 0 to suppress the output of argument type information in the status line.
disable_breakpoint_command : disable all | disable breakpoint_number_expression ,... enable_breakpoint_command : enable all | enable breakpoint_number_expression ,... delete_breakpoint_command : delete all | delete breakpoint_number_expression ,...For example:
(ladebug) disable 1
(ladebug) status
#1 PC==0x1200023f8 in int main(void) "x_list.cxx":182 { stop } Disabled
#2 PC==0x120001d9c in void List<Node>::append(class Node* const) "x_list.cxx":148 { break }
#3 Access memory (write) 0x11ffff0c8 to 0x11ffff0cf { stop }
(ladebug) disable 10 - 8,1 + 1 + 1
(ladebug) status
#1 PC==0x1200023f8 in int main(void) "x_list.cxx":182 { stop } Disabled
#2 PC==0x120001d9c in void List<Node>::append(class Node* const) "x_list.cxx":148 { break } Disabled
#3 Access memory (write) 0x11ffff0c8 to 0x11ffff0cf { stop } Disabled
(ladebug) delete 1
(ladebug) status
#2 PC==0x120001d9c in void List<Node>::append(class Node* const) "x_list.cxx":148 { break } Disabled
#3 Access memory (write) 0x11ffff0c8 to 0x11ffff0cf { stop } Disabled
(ladebug) enable all
(ladebug) status
#2 PC==0x120001d9c in void List<Node>::append(class Node* const) "x_list.cxx":148 { break }
#3 Access memory (write) 0x11ffff0c8 to 0x11ffff0cf { stop }
The debugger has to find and read any source files that you wish it to display or search. The debugger itself has no need to read the source files. All the information for the debugger comes from the executable files or shared libraries.
The debugger supports commands to:
browse_source_command : source_directory_mapping_command | source_searchlist_command | select_source_file_command | list_source_file_command | search_source_file_command
The debugger has "source directory mapping" commands that:
% pwd /usr/users/ladebug/sandbox/test/src/common/Examples % ls -R bin/ src/ ./bin: x_solarSystem* ./src: solarSystemSrc/ ./src/solarSystemSrc: base_class_includes/ main/ star.cxx derived_class_includes/ orbit.cxx heavenlyBody.cxx planet.cxx ./src/solarSystemSrc/base_class_includes: heavenlyBody.h orbit.h ./src/solarSystemSrc/derived_class_includes: planet.h star.h ./src/solarSystemSrc/main: solarSystem.cxx % cd src % cc -g -o ../bin/x_solarSystem \ -IsolarSystemSrc/base_class_includes \ -IsolarSystemSrc/derived_class_includes \ main/solarSystem.cxx heavenlyBody.cxx orbit.cxx planet.cxx star.cxxThen you move the directory solarSystemSrc elsewhere:
% mv solarSystemSrc movedSolarSystemSrcNow debug x_solarSystem in /usr/users/ladebug/sandbox/test/src/common/Examples/bin:
(ladebug) list $curline - 10: 20
Source file not found or not readable, tried...
solarSystemSrc/main/solarSystem.cxx
./solarSystemSrc/main/solarSystem.cxx
../src/solarSystemSrc/main/solarSystem.cxx
/usr/proj/ladebug-builds/build-latest/test/src/common/Examples/bin-alpha-osf1/solarSystemSrc/main/solarSystem.cxx
./solarSystem.cxx
../src/solarSystem.cxx
/usr/proj/ladebug-builds/build-latest/test/src/common/Examples/bin-alpha-osf1/solarSystem.cxx
The debugger cannot find the file because it has been moved to another
directory.
(ladebug) show source directory
.
solarSystemSrc
...
/usr/include/cxx
Information: You can further expand a '...' using the command
show source directory <directory>
or
show all source directory <directory>
where <directory> is the directory on the line above the '...'.
The first command displays only the children of <directory>, whereas
the second command displays all the descendants of <directory>.
This command displays a summary of the source directories in a.out. The
“...” here means that there is one or more source directories under
src.
(ladebug) map source directory solarSystemSrc ../src/movedSolarSystemSrc
(ladebug) list $curline - 10: 20
104
105 // Insert the new entry appropriately
106 //
107 if (iAmBiggerThan < biggestCount) {
108 biggestMoons[iAmBiggerThan] = moon;
109 }
110 }
111
112 void main()
113 {
> 114 unsigned int j = 1; // for scoping examples
115 for (unsigned int i = 0; i < biggestCount; i++)
116 biggestMoons[i] = NULL;
117
118 Star *sun = new Star("Sol", G, 2);
119 buildOurSolarSystem(sun);
120 sun->printBodyAndItsSatellites(j);
121 printBiggestMoons();
122 }
This command directs the debugger to look for source files originally in
solarSystemSrc in movedSolarSystemSrc instead. This
time, the debugger finds the source file.
(ladebug) show all source directory
.
solarSystemSrc *=> ../src/movedSolarSystemSrc
solarSystemSrc/base_class_includes => ../src/movedSolarSystemSrc/base_class_includes
solarSystemSrc/derived_class_includes => ../src/movedSolarSystemSrc/derived_class_includes
solarSystemSrc/main => ../src/movedSolarSystemSrc/main
/usr/include/cxx
This command gives a complete list of source directories. As you can
see, solarSystemSrc is mapped to movedSolarSystemSrc.
As a side effect of mapping
solarSystemSrc to movedSolarSystemSrc,
the subdirectories in solarSystemSrc are
mapped to their counterparts under movedSolarSystemSrc.
To summarize, the debugger provides the following four commands for checking and setting source directory mappings:
source_directory_mapping_command :Use the show source directory command to display the directory mapping information of directory_name and its child directories (or immediate subdirectory). If directory_name is not specified, the mapping information of all the source directories whose parent is not a source directory is displayed.show source directory [ directory_name ] | show all source directory [ directory_name ] | map source directory from_directory_name to_directory_name | unmap source directory from_directory_name
(ladebug) show source directory
.
solarSystemSrc *=> ../src/movedSolarSystemSrc
...
/usr/include/cxx
(ladebug) show all source directory
.
solarSystemSrc *=> ../src/movedSolarSystemSrc
solarSystemSrc/base_class_includes => ../src/movedSolarSystemSrc/base_class_includes
solarSystemSrc/derived_class_includes => ../src/movedSolarSystemSrc/derived_class_includes
solarSystemSrc/main => ../src/movedSolarSystemSrc/main
/usr/include/cxx
This command is identical to the previous command except that the
mapping information of all the descendants of directory_name is displayed.
When you further expand a '...' where directory is the directory on the line above the '...':
The unmap source directory command maps from_directory_name back to itself; in other words,if from_directory_name has been mapped to some other directory, this command will restore its default mapping.
(ladebug) show source directory
.
solarSystemSrc *=> ../src/movedSolarSystemSrc
...
/usr/include/cxx
(ladebug) show source directory solarSystemSrc
solarSystemSrc *=> ../src/movedSolarSystemSrc
solarSystemSrc/base_class_includes => ../src/movedSolarSystemSrc/base_class_includes
solarSystemSrc/derived_class_includes => ../src/movedSolarSystemSrc/derived_class_includes
solarSystemSrc/main => ../src/movedSolarSystemSrc/main
NOTE: *=> means that you are setting the mapping explicitly
using the map source directory command, whereas => means
that the mapping is derived from an explicit set.
(ladebug) unmap source directory solarSystemSrc
Source file not found or not readable, tried...
solarSystemSrc/main/solarSystem.cxx
./solarSystemSrc/main/solarSystem.cxx
../src/solarSystemSrc/main/solarSystem.cxx
/usr/proj/ladebug-builds/build-latest/test/src/common/Examples/bin-alpha-osf1/solarSystemSrc/main/solarSystem.cxx
./solarSystem.cxx
../src/solarSystem.cxx
/usr/proj/ladebug-builds/build-latest/test/src/common/Examples/bin-alpha-osf1/solarSystem.cxx
(ladebug) show source directory solarSystemSrc
solarSystemSrc
solarSystemSrc/base_class_includes
solarSystemSrc/derived_class_includes
solarSystemSrc/main
Usually the compiler copies the source file names from the shell command line into the .o files, without further prepending the current working directory, so that you can use links or other mechanisms to move the files around without invalidating the information.
The debugger looks in a use_list of directories to find the first occurrence of a source file. The use_list is specified as one or more directory names, without trailing slashes.
By default, the use_list is: (1) the current directory and (2) the directory containing the executable file. Each process has its own use_list. You can also use the ladebug command -I option to specify search directories.
The debugger searches for a source file (dir_name/base_name) using the following algorithm:
The following commands let you view and modify the use_list.
source_searchlist_command : use_command | unuse_commandEnter the use command without an argument to list the directories the debugger searches for source code files. Specify a directory argument to make source code files in that directory available to the debugger. You can also use the ladebug command -I option to specify search directories, which puts those directories in the use_list.
You can customize your debugger environment source-code search paths by adding commands to your .dbxinit file that use the use command.
use_command :use [directory_name ...]
If the directory_name is specified, it is either appended to or replaces the use_list, depending on whether the value of the $dbxuse debugger variable is zero (append) or non-zero (replace).
The unuse command removes entries from the use_list.
unuse_command :unuse [directory_name ...] | unuse *
Enter the unuse command without the directory_name to set the search list to the default (the home directory, the current directory, and the directory containing the executable file). Include the directory names to remove them from the search list. The asterisk (*) argument removes all directories from the search list.
Whenever the process stops, the current source file is set to the source file for the code currently executing.
Other commands up, down, class, and file also set the current source file.
You can see and modify the current source file selection.
select_source_file_command :file [ filename ]
Enter the file command without a file name to display the name of the current file scope. Include the file name to change the file scope. Change the file scope to set a breakpoint in a function not in the file currently being executed.
To see source code for or set a breakpoint in a function not in the file currently being executed, use the file command to set the file scope.
The following example uses the file command to set the debugger file scope to a file different from the main program, and then stops at line number 26 in that file.
(ladebug) run
[1] stopped at [void main(void):114 0x120004040]
114 unsigned int j = 1; // for scoping examples
(ladebug) list 24: 10
24 Moon *phobos = new Moon("Phobos", 9, 11, mars);
25 Moon *deimos = new Moon("Deimos", 23, 6, mars);
26
27 Planet *jupiter = new Planet("Jupiter", 778330, sun);
28 Moon *io = new Moon("Io", 422, 1815, jupiter);
29 Moon *europa = new Moon("Europa", 671, 1569, jupiter);
30 Moon *ganymede = new Moon("Ganymede", 1070, 2631, jupiter);
31 Moon *callisto = new Moon("Callisto", 1883, 2400, jupiter);
32 Moon *amalthea = new Moon("Amalthea", 181, 98, jupiter);
33
(ladebug) file star.cxx
(ladebug) list 24: 10
24 // Stars are simple objects
25 //
26 Star::Star(
27 char* name,
28 StellarClass classification,
29 StellarSubclass subclassification)
30 : HeavenlyBody(name),
31 _classification(classification),
32 _subclassification(subclassification)
33 {
(ladebug) stop at 26
[#2: stop at "solarSystemSrc/star.cxx":26 ]
(ladebug) cont
[2] stopped at [Star::Star(char*, StellarClass, StellarSubclass):26 0x120004b4c]
26 Star::Star(
However, there are some primitive inspection capabilities built into the debugger. The list command displays source lines beginning with the source code line corresponding to one of the following:
list_source_file_command :list [ line_expression ] | list line_expression , line_expression | list line_expression : line_expression line_expression : expression
If specified, the first expression must evaluate to either an integer (in which case it is the line number within the current source file of the first line to display) or a function (in which case the first line of the function is the first line to display).
Specify the exact range of source lines by including either a comma followed by the expression for the last line, or a colon followed by the expression for the the number of lines.
Such a second expression must evaluate to an integer value.
If a second expression is not given, the debugger shows 20 lines, fewer if the end of source file is reached.
For example, to list lines 16 through 20:
(ladebug) list 16, 20
16
17 class Node {
18 public:
19 Node ();
20
For example, to list 6 lines beginning with line 16:
(ladebug) list 16: 6
16
17 class Node {
18 public:
19 Node ();
20
21 virtual void printNodeData() const = 0;
search_source_file_command :/ [ string ] |? [ string ]
NOTE:
The / form searches forward from the most recently listed line; the ? form searches backward. Like most searches, it will stop at the end (or beginning) of the file being searched, and will wrap if the command is repeated at that point.
When the string is omitted, the previous search continues from where it found the string.
When the string is present, the search starts from either the start (/) or the end (?) of the current line.
When a match is found, the debugger lists the line number and the line, but that line does not become the current line.
For example:
(ladebug) /_firstNode
69 NODETYPE* _firstNode;
(ladebug) ?append
65 void append (NODETYPE* const node);
(ladebug) /append
145 void List<NODETYPE>::append(NODETYPE* const node)
To specify the thread level, set the $threadlevel debugger variable to:
For example:
(ladebug) set $threadlevel = "decthreads"
For core file debugging, the $threadlevel is always set to native.
There are a variety of commands to manipulate the threads.
thread_command : show_thread_command | switch_thread_command | show_condition_variable_command | show_mutex_variable_command | pthread_command
show_thread_command :show thread [ thread_id_list ] [thread-state-filter ] thread_id_list :thread_id ,... | * thread_state_filter : with state eqthread_state eq :== (for Ada, C, and C++) | .eq. (for Fortran) | = (for Cobol) | equal [ to ] (for Cobol) thread_state : ready | running | terminated | blocked
Use the show thread command without parameters to list all the threads known to the debugger.
If you specify one or more thread identifiers, the debugger displays information about the threads you specify, if the thread matches what you specified in the list. If you omit a thread specification, the debugger displays information for all threads.
Use the show thread commands to list threads that have specific characteristics, such as threads that are currently blocked.
For example:
(ladebug) print $threadlevel
"decthreads"
(ladebug) show thread
Thread Name State Substate Policy Pri
------ ------------------------- --------------- ----------- ------------ ---
1 default thread running SCHED_OTHER 19
-1 manager thread blk SCS SCHED_RR 19
-2 null thread for VP 0 ready new null thread 0
-3 null thread for VP 1 ready null thread 0
-4 null thread for VP 0 ready new null thread 0
-5 null thread for VP 0 ready new null thread 0
>* 2 <anonymous> running SCHED_OTHER 19
(ladebug) set $threadlevel = "native"
(ladebug) print $threadlevel
"native"
(ladebug) show thread
Id State
>* 0x9 stopped
>* 0x9 unstarted
0x3 unstarted
0x7 unstarted
You can switch to a different thread as the current thread. The debugger variable $curthread contains the thread identifier of the current thread. The $curthread value is updated when program execution stops or completes.
switch_thread_command : thread [ thread_id ]
The current thread can be modified by assigning $curthread a valid thread identifier. This is equivalent to issuing the thread thread_id command.
When there is no process or program, $curthread is set to 0.
Use the thread command without a thread identifier to identify the current thread. Supply a thread identifier to make another thread the current thread.
show_mutex_variable_command :If you specify one or more mutex identifiers, the debugger displays information about only those mutexes specified, provided that the list matches the identifiers of currently available mutexes. If you omit the mutex identifier specification, the debugger displays information about all mutexes currently available.show mutex [ mutex_id_list ] [mutex_state_filter ] mutex_id_list : mutex_id ,... | (mutex_id ,...) mutex_state_filter : with state eq mutex_state mutex_state : locked
Use the show mutex with state == locked command to display information exclusively for locked mutexes.
If $verbose is set to 1, the sequence numbers of the threads locking the mutexes are displayed.
The following example shows the output from a simple show mutex command.
(ladebug) show mutex
Mutex Name State Owner Pri Type Waiters (+Count)
------ ------------------------- ----- ------ --- -------- --------------------
1 malloc Normal
2 brk Normal
3 exc cr Recurs
4 exc read rwl Normal
5 known mutex queue Normal
6 known cond queue Normal
7 VM 0 lookaside Normal
8 VM 1 lookaside Normal
9 VM 2 lookaside Normal
10 VM 0 cache Normal
11 VM 1 cache Normal
12 VM 2 cache Normal
13 thread 1 mutex Normal
14 thread 1 wait Normal
15 thread -1 mutex Normal
16 thread -1 wait Normal
17 thread -2 mutex Normal
18 thread -2 wait Normal
19 thread -3 mutex Normal
20 thread -3 wait Normal
21 thread -4 mutex Normal
22 thread -4 wait Normal
23 thread -5 mutex Normal
24 thread -5 wait Normal
25 debugger client registry Normal
26 Global lock Recurs
27 <anonymous> Normal
28 <anonymous> Normal
29 <anonymous> Normal
30 thread 2 mutex Normal
31 thread 2 wait Normal
32 thread 0 mutex Normal
33 thread 0 wait Normal
If the application being debugged has no pthreads or the $threadlevel is set to native, an appropriate message is issued.
show_condition_variable_command :show condition [ condition_id_list ] [condition_state_filter ] condition_id_list :condition_id ,... | (condition_id ,...) condition_state_filter : with state eq condition_state condition_state : wait
Use the show condition command to list information about currently available condition variables. If you supply one or more condition identifiers, the debugger displays information about the condition variables you specify, provided that the list matches the identities of currently available condition variables. If you omit the condition variable specification, the debugger displays information about all the condition variables currently available.
Use the show condition with state == wait command to display information only for condition variables that have one or more threads waiting. If $verbose is set to 1, the sequence numbers of the threads waiting on the condition are displayed.
The following example shows output from a simple show condition command.
(ladebug) show condition
Cond Name Mutex Type Waiters (+Count)
------ ------------------------- ------ ----- ---------------------------------
10 thread -3 wait
3 thread 1 join
11 thread -4 join
6 thread -1 wait
12 thread -4 wait
2 <anonymous>
13 thread -5 join
7 thread -2 join
14 thread -5 wait
4 thread 1 wait
15 <anonymous>
8 thread -2 wait
16 thread 2 join
1 <anonymous>
17 thread 2 wait
9 thread -3 join
18 thread 0 join
5 thread -1 join
19 thread 0 wait
If the application being debugged has no pthreads or the $threadlevel is set to native, an appropriate message is issued.
You can use the where command to display the stack trace of current threads. You can specify one or more threads or all threads.
The print command evaluates an optional expression in the context of the current thread and displays the result.
The call command evalutes an expression in the context of the current thread and makes the call in the context of the current thread.
The printregs command prints the registers for the current thread.
You can pass an undocumented string directly into the undocumented pthread debugging support. This is an internal debugging aid, not intended for general use.
pthread_command :pthread string
The machine-code generated for these functions maintains this call stack. Some of this maintenance is done before the call, some at the start of the called function, some at the end of the called function, and some after the call.
Non-optimized machine-code is usually very easy to correlate with the source code, but optimized machine-code can be tricky. Details of this are given later in this section.
The debugger controls the call stacks of all the threads, and lets you examine and manipulate them, and use them as a basis for further queries.
call_stack_command : show_stack_command | change_stack_frame_command | pop_stack_frame_command
When your process is stopped by the debugger, you can show the call stack of the thread that was the cause of the stoppage, or of any other thread.
show_stack_command :This shows the most recent call frames on the call stack of the current or specified threads.where [ expression ] [ thread_specifier ] thread_specifier : thread thread_id ,... | thread all
If specified, the expression must evaluate to a non-negative integer, and specifies the number of call frames to show. If not specified, all the call frames for the thread are shown.
If specified, the thread_specifier specifies the threads whose call stacks are to be shown. If not specified, just the current thread is used.
When large and complex values are passed by value to a routine on the stack, the output of the where, up, down, and dump command can be voluminous. You can set the control variable $stackargs to 0 to suppress the output of argument values in the where, up, down, and dump commands.
The stack trace provides the following information for each call level:
Call level | The number used to refer to a call level on the stack. The function entered most recently is at level 0. |
Memory address | The address of the next instruction to be executed at this level. |
Function name | The name of the function for the memory address. |
File name | The source file for the memory address. |
Line number | The number of the next source line of the memory address. |
(ladebug) stop in List<Node>::print
[#3: stop in void List<Node>::print(void) ]
(ladebug) cont
[3] stopped at [void List<Node>::print(void):162 0x120001e70]
162 Node* currentNode = _firstNode;
(ladebug) where 2
>0 0x120001e70 in ((List<Node>*)0x11fffec28)->print() "x_list.cxx":162
#1 0x1200026fc in main() "x_list.cxx":200
You can select one of the call frames as the starting point for examining variables. This call frame provides both the current scope within the program for which variables exist, and tells the debugger which instance of those variables you want to see the values for.
change_stack_frame_command :up [ expression ] | down [ expression ] | func [ loc ]
Use the up command or the down command without the expression to change to the call frame located one level up or down the stack.
Specify an expression that evaluates to an integer to change the call frame up or down the specified number of levels. If the number of levels exceeds the number of active calls on the stack, the debugger issues a warning message and the call frame does not change.
When the current call frame is changed, the debugger displays the source line corresponding to the last instruction executed in the function executing the selected call frame.
When large and complex values are passed by value to a routine on the stack, the output of the where, up, down, and dump command can be voluminous. You can set the control variable $stackargs to 0 to suppress the output of argument values in the where, up, down, and dump commands.
Use the func command without the loc to display the current function.
To change the function scope to a function that has a call frame in the call stack, specify the loc as either the name of the function or as an integer expression evaluating to the call level. If the name is specified, the most recently entered call frame for that function becomes the current call frame.
If there are no frames to select from, the debugger context is set to the static context of the named function. The current scope and current language are set based on that function. Types and static variables local to that function are now visible and can be evaluated.
If you enter an integer expression, the debugger moves to the frame at level n, just as if you had entered up n.
In the following example, the current call frame is changed to one for method Planet::print so that a variable in that instance of print() can be displayed.
(ladebug) where 4
#0 0x1200047dc in ((Planet*)0x140002860)->print(i=2) "solarSystemSrc/planet.cxx":19
#1 0x12000422c in ((HeavenlyBody*)0x140002860)->printBodyAndItsSatellites(i=2) "solarSystemSrc/heavenlyBody.cxx":62
>2 0x120004254 in ((HeavenlyBody*)0x140002000)->printBodyAndItsSatellites(i=1) "solarSystemSrc/heavenlyBody.cxx":68
#3 0x120004110 in main() "solarSystemSrc/main/solarSystem.cxx":120
(ladebug) list $curline - 5: 10
62 print(i);
63
64 // Recursively deal with the satellites. Redeclare i for scoping examples.
65 //
66 unsigned int j = 1;
67 for (HeavenlyBody* i = _firstSatellite; i; i = i->_outerNeighbor) {
> 68 i->printBodyAndItsSatellites(j++);
69 }
70 }
(ladebug) whatis i
class HeavenlyBody* i
(ladebug) print i
0x140002860
(ladebug) func Planet::print
virtual void Planet::print(unsigned int) in solarSystemSrc/planet.cxx line No. 19:
19 cout << "(" << i
(ladebug) where 4
>0 0x1200047dc in ((Planet*)0x140002860)->print(i=2) "solarSystemSrc/planet.cxx":19
#1 0x12000422c in ((HeavenlyBody*)0x140002860)->printBodyAndItsSatellites(i=2) "solarSystemSrc/heavenlyBody.cxx":62
#2 0x120004254 in ((HeavenlyBody*)0x140002000)->printBodyAndItsSatellites(i=1) "solarSystemSrc/heavenlyBody.cxx":68
#3 0x120004110 in main() "solarSystemSrc/main/solarSystem.cxx":120
(ladebug) list $curline - 5: 10
14 {
15 }
16
17 void Planet::print(unsigned int i) const
18 {
> 19 cout << "(" << i
20 << ") Planet [" << HeavenlyBody::name() << "]; ";
21 printOrbitalParameters();
22 cout << endl;
23 }
(ladebug) whatis i
unsigned int i
(ladebug) print i
2
In the previous example, instead of entering
func Planet::print you can enter
down 2. (You would use down in this case because
the current call frame at the start of the example was not the bottommost
frame.) Note that the final stack trace in this example lists
a call frame for function Planet::print as the current call frame
(denoted by the > character).
pop_stack_frame_command :The pop command removes one or more call frames from the call stack. The default is one call frame. The pop command undoes the work already done by the removed execution frames. It does not, however, reverse side effects such as changes to global variables. Because it is extremely unlikely this will fix up all the effects of a half-executed call, this command is not recommended for general use. Furthermore, the pop command does not provide a way to specify a return value when the frame being discarded corresponds to a function that should return a value. You may need to use the assign command to restore the values of global variables.pop [ expression ]
Instead of the pop command, you may want to use the return command which finishes the call corresponding to the selected frame.
Depending on the information the compiler makes available to the debugger, inlined calls may or may not show up in the call stack display.
Outlined calls will show up, and be correlated to the code they came from. The compiler will probably have supplied the debugger with some invented name for the function.
look_around_command : various_print_command | c++_look_around_command | call_command | whatis_command | whereis_command | which_command
various_print_command : print_command | printf_command | print_registers_command | dump_command
print_command :For an array, the debugger prints every cell in the array if you do not specify a specific cell.print [ expression ,... ] | rescoped_expression |printable_type rescoped_expression : filename ` qual_symbol | ` qual_symbol qual_symbol : expression | qual_symbol ` expression
Consider the following declarations in a C++ program:
(ladebug) list 59: 2
59 const unsigned int biggestCount = 10;
60 static Moon *biggestMoons[biggestCount];
The following example uses the print command to display a
nonstring array.
(ladebug) print biggestMoons
[0] = 0x140002bc0,[1] = 0x140002f20,[2] = 0x140002c20,[3] = 0x140002b00,[4] = 0x140002920,[5] = 0x140002b60,[6] = 0x1400032e0,[7] = 0x1400031c0,[8] = 0x140002ec0,[9] = 0x140003220
The following example shows how to print individual values of an array.
(ladebug) print biggestMoons[3]
0x140002b00
(ladebug) print *biggestMoons[3]
class Moon {
_radius = 1815;
_name = 0x1200020b0="Io"; // class Planet::HeavenlyBody
_innerNeighbor = 0x0; // class Planet::HeavenlyBody
_outerNeighbor = 0x140002b60; // class Planet::HeavenlyBody
_firstSatellite = 0x0; // class Planet::HeavenlyBody
_lastSatellite = 0x0; // class Planet::HeavenlyBody
_primary = 0x140002aa0; // class Planet::Orbit
_distance = 422; // class Planet::Orbit
_name = 0x140004280="Jupiter 1"; // class Planet::Orbit
}
(ladebug) whatis newNode
class IntNode* newNode
(ladebug) print newNode
0x140001800
(ladebug) print *newNode
class IntNode {
_data = 1;
_nextNode = 0x0; // class Node
}
printf_command :For example:printf [format_string [, expression ,... ]]
(ladebug) printf "The PC is 0x%x", $pc
The PC is 0x120002700
print_registers_command :For example:printregs
(ladebug) printregs
$r0 [$v0] = 4396996887520 $r1 [$t0] = 0
$r2 [$t1] = 16384 $r3 [$t2] = 0
$r4 [$t3] = 8192 $r5 [$t4] = 4395900160076
$r6 [$t5] = 0 $r7 [$t6] = 0
$r8 [$t7] = 0 $r9 [$s0] = 346509056
$r10 [$s1] = 338495152 $r11 [$s2] = 4096
$r12 [$s3] = 0 $r13 [$s4] = 303122176
$r14 [$s5] = 4096 $r15 [$s6] = 303514008
$r16 [$a0] = 4395931657104 $r17 [$a1] = 4395931692608
$r18 [$a2] = 43 $r19 [$a3] = 0
$r20 [$a4] = 0 $r21 [$a5] = 3125
$r22 [$t8] = 0 $r23 [$t9] = 4395899898312
$r24 [$t10] = 0 $r25 [$t11] = 0
$r26 [$ra] = 4831848192 $r27 [$t12] = 4395931628176
$r28 [$at] = 0 $r29 [$gp] = 5368742704
$r30 [$sp] = 4831833072 $r31 [$zero]= 0
$f0 = 10.1230001449585 $f1 = 0
$f2 = 0 $f3 = 0
$f4 = 0 $f5 = 0
$f6 = 0 $f7 = 0
$f8 = 0 $f9 = 0
$f10 = 0 $f11 = 0
$f12 = 0.1 $f13 = 0
$f14 = 2.035550460865936e-320 $f15 = 0
$f16 = 10.1230001449585 $f17 = 10.1230001449585
$f18 = 10.1230001449585 $f19 = 10.1230001449585
$f20 = 0 $f21 = 0
$f22 = 0 $f23 = 0
$f24 = 0 $f25 = 0
$f26 = 0 $f27 = 0
$f28 = 0 $f29 = 0
$f30 = 0 $f31 = 0
$pc = 0x120002700 $ps = 0x8
$fpcr = 0x800000000000000 $vfp = 0x11fffec90
Use the dump . command (include the dot) to list the parameters and local variables for all functions active on the stack.
dump_command :For example:dump qual_symbol | dump .
(ladebug) dump
>0 0x120002700 in main() "x_list.cxx":200
nodeList=class { ... }
newNode=0x140001800
cNode=0x140002000
newNode2=0x140001840
cNode2=0x140002030
When large and complex values are passed by value to a routine on the stack, the output of the where, up, down, and dump command can be voluminous. You can set the control variable $stackargs to 0 to suppress the output of argument values in the where, up, down, and dump commands.
call_command :Specify the function as if you were calling it from within the program. If the function has no parameters, specify empty parentheses.call call_expression
For multithreaded applications, the call is made in the context of the current thread.
For C++: When you set the $overloadmenu debugger variable to 1 and call an overloaded function, the debugger lists the overloaded functions and calls the function you specify.
When the function you call completes normally, the debugger restores the stack and current context that existed before the function was called.
While the program counter is saved and restored, calling a function does not shield the program state from alteration if the function you call allocates memory or alters global variables. If the function affects global program variables, for instance, those variables will be permanently changed.
Functions compiled without the debugger option to include debugging information may lack important parameter information and are less likely to yield consistent results when called.
The call command executes the specified function with the parameters you supply and then returns control to you (at the Ladebug prompt) when the function returns. The call command discards the return value of the function. If you embed the function call in the expression argument of a print command, the debugger prints the return value after the function returns.
The following example shows both methods of calling a function.
(ladebug) call earth->distance()
(ladebug) print earth->distance()
149600
In the previous example, the call command results in the return value being
discarded while the embedded call passes the return value of the function to
the print command, which in turn prints the value. You can also
embed the call within a more involved expression, as shown in the following
example:
(ladebug) print earth->distance() - 100000
49600
(ladebug) print mars->distance() - earth->distance()
78340
(ladebug) call io->print(3)
(3) Moon [Io], radius [1815] km; <Jupiter 1> orbits at 422 Megameters
All breakpoints or tracepoints defined and enabled during the session are
active when
executing a called function. When program execution halts during function
execution, you can examine program information, execute one line or
instruction, continue execution of the function, or call another function.
When you call a function when execution is suspended in a called function, you are nesting function calls, as shown in the following example:
(ladebug) where 2
>0 0x120003cf0 in buildOurSolarSystem(sun=0x140002000) "solarSystemSrc/main/solarSystem.cxx":55
#1 0x120004100 in main() "solarSystemSrc/main/solarSystem.cxx":119
(ladebug) status
#1 PC==0x120003cf0 in void buildOurSolarSystem(class Star*) "solarSystemSrc/main/solarSystem.cxx":55 { break }
#2 PC==0x1200047dc in virtual void Planet::print(unsigned int) "solarSystemSrc/planet.cxx":19 { break }
#3 PC==0x1200044b4 in Megameters Orbit::distance(void) "solarSystemSrc/orbit.cxx":41 { break }
(ladebug) call mars->print(1)
[2] stopped at [virtual void Planet::print(unsigned int):19 0x1200047dc]
19 cout << "(" << i
(ladebug) where
>0 0x1200047dc in ((Planet*)0x140002980)->print(i=1) "solarSystemSrc/planet.cxx":19
(ladebug) next
stopped at [virtual void Planet::print(unsigned int):21 0x120004874]
21 printOrbitalParameters();
(ladebug) print distance()
[3] stopped at [Megameters Orbit::distance(void):41 0x1200044b4]
41 return _distance;
(ladebug) where
>0 0x1200044b4 in ((Orbit*)0x1400029b0)->distance() "solarSystemSrc/orbit.cxx":41
(ladebug) disable 3
(ladebug) cont
Called Procedure Returned
stopped at [virtual void Planet::print(unsigned int):21 0x120004874]
21 printOrbitalParameters();
(ladebug) where
>0 0x120004874 in ((Planet*)0x140002980)->print(i=1) "solarSystemSrc/planet.cxx":21
(ladebug) cont
(1) Planet [Mars]; <Sol 4> orbits at 227940 Megameters
Called Procedure Returned
stopped at [void buildOurSolarSystem(class Star*):55 0x120003cf0]
55 Planet *pluto = new Planet("Pluto", 5913520, sun);
whatis_command :The following example uses the whatis command to determine the storage representation for the data member _classification.whatis whatis_expression
(ladebug) whatis sun->_classification
const StellarClass _classification
(ladebug) whatis StellarClass
enum "solarSystemSrc/derived_class_includes/star.h"`StellarClass
{O, B, A, F, G, K, M, R, N, S} StellarClass
(ladebug) print sun->_classification
G
The scope information of a variable usually consists of the name of the source file that contains the function in which the variable is declared, the name of that function, and the name of the variable. The components of the scope information are separated by back-quotes (`).
whereis_command :The whereis command is useful for obtaining information needed to differentiate overloaded identifiers that are in different units, or within different routines in the same unit. The following example shows how to set breakpoints in two C++ methods, both named print.whereis whereis_name whereis_name : identifier_or_typedef_name | ( identifier_or_typedef_name )
(ladebug) whereis print
"solarSystemSrc/base_class_includes/heavenlyBody.h"`HeavenlyBody::print
"solarSystemSrc/derived_class_includes/planet.h"`Moon::print
"solarSystemSrc/derived_class_includes/planet.h"`Planet::print
"solarSystemSrc/derived_class_includes/star.h"`Star::print
(ladebug) stop in "solarSystemSrc/derived_class_includes/planet.h"`Planet::print
[#2: stop in virtual void Planet::print(unsigned int) ]
(ladebug) stop in "solarSystemSrc/derived_class_includes/star.h"`Star::print
[#3: stop in virtual void Star::print(unsigned int) ]
The scope information of a variable usually consists of the name of the source file that contains the function in which the variable is declared, the name of that function, and the name of the variable. The components of the scope information are separated by back-quotes (`).
which_command :The following example shows how to use the whereis and which commands to determine a variable's scope.which which_name which_name : identifier_or_typedef_name | ( identifier_or_typedef_name )
(ladebug) where 4
>0 0x1200047dc in ((Planet*)0x140002860)->print(i=2) "solarSystemSrc/planet.cxx":19
#1 0x12000422c in ((HeavenlyBody*)0x140002860)->printBodyAndItsSatellites(i=2) "solarSystemSrc/heavenlyBody.cxx":62
#2 0x120004254 in ((HeavenlyBody*)0x140002000)->printBodyAndItsSatellites(i=1) "solarSystemSrc/heavenlyBody.cxx":68
#3 0x120004110 in main() "solarSystemSrc/main/solarSystem.cxx":120
(ladebug) which i
"solarSystemSrc/planet.cxx"`Planet::print`i
(ladebug) assign i = 10
(ladebug) print i
10
(ladebug) whereis i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::satelliteNumber`i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::printBodyAndItsSatellites`i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::printBodyAndItsSatellites`i
"solarSystemSrc/star.cxx"`Star::print`i
"solarSystemSrc/planet.cxx"`Planet::print`i
"solarSystemSrc/planet.cxx"`Moon::print`i
"solarSystemSrc/derived_class_includes/planet.h"`Planet::print`i
"solarSystemSrc/base_class_includes/heavenlyBody.h"`HeavenlyBody::print`i
"solarSystemSrc/base_class_includes/heavenlyBody.h"`HeavenlyBody::printBodyAndItsSatellites`i
"solarSystemSrc/main/solarSystem.cxx"`printBiggestMoons`i
"solarSystemSrc/main/solarSystem.cxx"`trackBiggestMoons`i
"solarSystemSrc/main/solarSystem.cxx"`main`i
(ladebug) func HeavenlyBody::printBodyAndItsSatellites
void HeavenlyBody::printBodyAndItsSatellites(unsigned int) in solarSystemSrc/heavenlyBody.cxx line No. 62:
62 print(i);
(ladebug) which i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::printBodyAndItsSatellites`i
(ladebug) print i
2
The class command lets you set the scope to a class in the program you are debugging.
c++_look_around_command :If class_name is not specified, the class command displays the current class context.class [ class_name ]
Setting the class scope nullifies the function scope and vice versa. To get back to the default (current function) scope, use the command func 0
Explicitly setting the debugger's current context to a class allows for visibility into a class to:
After the class scope is set, you can set breakpoints in the class's member functions and examine data without explicitly mentioning the class name. If you do not want to affect the current context, you can use the scope resolution operator (::) to access a class whose members are not currently visible. Use the class command without an argument to display the current class scope. Specify an argument to change the class scope. After the class scope is set, refer to members of the class by omitting the classname:: prefix.
The following example shows the use of the class command to set the
class scope to List
(ladebug) stop in append
Symbol "append" is not defined.
append has no valid breakpoint address
Warning: Breakpoint not set
(ladebug) class List<Node>
class List<Node> {
List(void);
~List(void);
void append(class Node*);
void print(void);
class Node* _firstNode;
}
(ladebug) stop in append
[#1: stop in void List<Node>::append(class Node* const) ]
The whatis command displays the class type declaration, including:
For classes that are derived from other classes, the data members and member functions inherited from the base class are not displayed. Any member functions that are redefined from the base class are displayed.
The print command lets you display the value of data members and static members. Information regarding the public, private, or protected status of class members is not provided, since the debugger relaxes the related access rules to be more helpful to users.
The type signatures of member functions, constructors, and destructors are displayed in a form that is appropriate for later use in resolving references to overloaded functions.
The following example shows the whatis and print commands in conjunction with a class.
(ladebug) list 43: 12
43 // Compound Node - contains integer and float data items
44 //
45 class CompoundNode : public IntNode {
46 public:
47 CompoundNode (float fdata, int idata);
48
49 void printNodeData() const;
50
51 private:
52 float _fdata;
53 };
54
(ladebug) whatis CompoundNode
class CompoundNode : IntNode {
CompoundNode(float, int);
virtual void printNodeData(void);
float _fdata;
}
(ladebug) whatis CompoundNode::CompoundNode
CompoundNode::CompoundNode(float, int)
(ladebug) stop in CompoundNode::printNodeData
[#1: stop in virtual void CompoundNode::printNodeData(void) ]
(ladebug) run
The list is:
Node 1 type is integer, value is 1
[1] stopped at [virtual void CompoundNode::printNodeData(void):109 0x12000236c]
109 cout << " type is compound, value is ";
(ladebug) print _fdata
12.345
You can also display individual object members using the member access operators, period (.) and right arrow (->), in a print command.
You can use the scope resolution operator (::) to refer to global variables, to refer to hidden members in base classes, to explicitly refer to a member that is inherited, or otherwise to name a member hidden by the current context.
When you are in the context of a nested class, you must use the scope resolution operator to access members of the enclosing class.
The following example shows how to use the whatis and print commands to display object information.
(ladebug) whatis this
const class CompoundNode* const this
(ladebug) whatis *this
class CompoundNode : IntNode {
CompoundNode(float, int);
virtual void printNodeData(void);
float _fdata;
}
(ladebug) print *this
class CompoundNode {
_fdata = 12.345;
_data = 2; // class IntNode
_nextNode = 0x140001820; // class IntNode::Node
}
(ladebug) print _fdata, _data
12.345 2
(ladebug) print this->_fdata, this->_data
12.345 2
The static type of a class pointer or reference is its type as defined in the source code and thus cannot change. The dynamic type is the type of the object being referenced, before any casts were made to that object and thus may change during program execution.
The debugger provides a debugger variable, $usedynamictypes, which allows you to control which form of the type information will be displayed. The default value for this variable is true (1), which indicates that the dynamic type information will be displayed. Setting this variable to false (0) instructs the debugger to display static type information. The output of the following commands will be affected: print, trace, tracei, and whatis.
The display of dynamic type information is supported for C++ class pointers and references. All other types display their static type information. In addition, if the dynamic type of an object cannot be determined, the debugger defaults to the use of the static type information.
This debugger functionality does not relax the C++ visibility rules regarding object member access through a pointer/reference (only members of the static type are accessible). For more information about the C++ visibility rules, see The Annotated C++ Reference Manual.
In order for the dynamic type information to be displayed, the object's static type must have at least one virtual function defined as part of its interface (either one it introduced or one it inherited from a base class). If no virtual functions are present for an object, only the static type information for that object will be available for display.
The following example shows debugger output with $usedynamictypes set to 0 (false).
(ladebug) print $usedynamictypes
0
(ladebug) print *this
class HeavenlyBody {
_name = 0x120002088="Moon";
_innerNeighbor = 0x0;
_outerNeighbor = 0x0;
_firstSatellite = 0x0;
_lastSatellite = 0x0;
}
The following example displays debugger output with $usedynamictypes
set to 1 (true). The output is for the same object as the previous example,
at the same point in program execution.
(ladebug) print $usedynamictypes
1
(ladebug) print *this
class Moon {
_radius = 1738;
_name = 0x120002088="Moon"; // class Planet::HeavenlyBody
_innerNeighbor = 0x0; // class Planet::HeavenlyBody
_outerNeighbor = 0x0; // class Planet::HeavenlyBody
_firstSatellite = 0x0; // class Planet::HeavenlyBody
_lastSatellite = 0x0; // class Planet::HeavenlyBody
_primary = 0x1400028c0; // class Planet::Orbit
_distance = 384; // class Planet::Orbit
_name = 0x1400040f0="Earth 1"; // class Planet::Orbit
}
Pointers to members of a class are not supported.
When you use the print command to display the format of C++ classes, the class name (or structure/union name) is displayed at the top of the output. Data members of a class that are inherited from another class are commented using a double slash (//). Only those data members that are inherited within the current class being printed are commented.
The following example shows how the debugger uses C++ style comments to identify inherited class members. In the example, class CompoundNode inherits from class IntNode, which inherits from class Node. When printing a class CompoundNode object, the data member _data is commented with "// class IntNode", signifying that it is inherited from class IntNode. The member _nextNode is commented with "// class IntNode::Node" showing that it is inherited from class IntNode which inherits it from class Node. This commenting is also provided for C++ structs.
(ladebug) where 3
>0 0x12000224c in ((Node*)0x140002000)->Node() "x_list.cxx":77
#1 0x120002298 in ((IntNode*)0x140002000)->IntNode(data=2) "x_list.cxx":88
#2 0x120002338 in ((CompoundNode*)0x140002000)->CompoundNode(fdata=12.34500026702881, idata=2) "x_list.cxx":101
(ladebug) whatis *this
class Node {
Node(void);
class Node* getNextNode(void);
void setNextNode(void);
class Node* _nextNode;
}
(ladebug) print *this
class Node {
_nextNode = 0x0;
}
(ladebug) up 1
>1 0x120002298 in ((IntNode*)0x140002000)->IntNode(data=2) "x_list.cxx":88
88 IntNode::IntNode(int data) : _data(data)
(ladebug) whatis *this
class IntNode : Node {
IntNode(int);
virtual void printNodeData(void);
int _data;
}
(ladebug) print *this
class IntNode {
_data = 0;
_nextNode = 0x0; // class Node
}
(ladebug) up 1
>2 0x120002338 in ((CompoundNode*)0x140002000)->CompoundNode(fdata=12.34500026702881, idata=2) "x_list.cxx":101
101 CompoundNode::CompoundNode(float fdata, int idata)
(ladebug) whatis *this
class CompoundNode : IntNode {
CompoundNode(float, int);
virtual void printNodeData(void);
float _fdata;
}
(ladebug) print *this
class CompoundNode {
_fdata = 0;
_data = 0; // class IntNode
_nextNode = 0x0; // class IntNode::Node
}
If you have two members in an object with the same name but different base
class types (multiple inheritance), you can refer to the members using the following syntax:
object.class::memberor
object->class::memberThis syntax is more effective than using the object.member and object->member syntaxes, which can be ambiguous. In all cases, the debugger uses the C++ language rules as defined in The Annotated C++ Reference Manual to determine which member you are specifying.
The following example shows a case where the expanded syntax can be used.
(ladebug) print *jupiter
class Planet {
_name = 0x1200020a8="Jupiter"; // class HeavenlyBody
_innerNeighbor = 0x140002980; // class HeavenlyBody
_outerNeighbor = 0x140002ce0; // class HeavenlyBody
_firstSatellite = 0x140002b00; // class HeavenlyBody
_lastSatellite = 0x140002c80; // class HeavenlyBody
_primary = 0x140002000; // class Orbit
_distance = 778330; // class Orbit
_name = 0x140004230="Sol 5"; // class Orbit
}
(ladebug) print jupiter->_name
Ambiguous reference
Selecting '_name' failed!
Error: no value for jupiter->_name
(ladebug) print jupiter->HeavenlyBody::_name
0x1200020a8="Jupiter"
(ladebug) print jupiter->Orbit::_name
0x140004230="Sol 5"
Sometimes the debugger does not see class type names with internal linkage. When this happens, the debugger issues the following error message:
Name is overloaded.Trying to examine an inlined member function that is not called results in the following error:
Member function has been inlined.The debugger will report this error regardless of the setting of the -noinline_auto compilation flag. As a workaround, include a call to the given member function somewhere in your program. (The call does not need to be executed.)
If a program is not compiled with the -g flag, a breakpoint set on an inlined member function may confuse the debugger.
If the $overloadmenu variable is set to 1 (the default), whenever you specify a function name that is overloaded, a menu will appear with all the possible functions; you must select from this menu. In this example, a breakpoint is set in foo, which is overloaded.
(ladebug) set $overloadmenu = 1
(ladebug) stop in C::foo
Select an overloaded function
----------------------------------------------------
1 int C::foo(double*)
2 void C::foo(float)
3 void C::foo(int)
4 void C::foo(void)
5 None of the above
----------------------------------------------------
1
[#10: stop in int C::foo(double*) ]
If you prefer this method, set the $overloadmenu variable to 0. To see the possible type signatures for the overloaded function, first display all the declarations of an overloaded function by using the whatis command.
You cannot select a version of an overloaded function that has a type signature containing ellipsis points (...). Pointers to functions with type signatures that contain the list parameter or ellipsis arguments are not supported.
Use the specific function type signature to refer to the desired version of the overloaded function. If a function has no parameter, include the void parameter as the function's type signature. In the following example, the function context is set to foo(double *), which is overloaded.
(ladebug) func foo
Error: foo is overloaded
(ladebug) func foo(double *)
int C::foo(double*) in x_overload.cxx line No. 25:
25 int C::foo(double *) { return state;}
(ladebug) whatis CompoundNode::__vptr
(array [subrange 0 ... 0 of int] of vtbl)* __vptr
The __vptr variable contains the addresses of all virtual functions associated with the class. Several other class members are generated by the compiler for internal use.
The compiler generates additional parameters for nonstatic member functions. When the $verbose debugger variable is set to 1, these extra parameters are displayed as part of each member function's type signature. If you specify a version of an overloaded function by entering its type signature and the variable is set to 1, you must include these parameters. Do not include these parameters if the variable is set to 0.
When the $verbose variable is set to 1, the output of the dump command includes not only standard program variables but also compiler-generated temporary variables.
The following example prints class information using the whatis command under different settings of the $verbose variable.
(ladebug) set $verbose = 0
(ladebug) whatis CompoundNode
class CompoundNode : IntNode {
CompoundNode(float, int);
virtual void printNodeData(void);
float _fdata;
}
(ladebug) set $verbose = 1
(ladebug) whatis CompoundNode
class CompoundNode : IntNode {
array [subrange 0 ... 0 of int] of vtbl* __vptr;
CompoundNode(class CompoundNode*, float, int);
virtual void printNodeData(const class CompoundNode*);
float _fdata;
}
machinecode_level_command : address_expressionThe first command displays the values stored in each of the memory chunks specified by the count, whose size depend on mode (see below), starting at address_expression. If count is not specified, 1 is assumed. The second command displays the values stored in the memory block starting at address_expression and ending at address_expression./[ count ] [mode ] | address_expression , address_expression / [ mode ]
You can display stored values in the following formats by specifying
mode:
mode : d Print a short word in decimal | dd Print a 32-bit (4-byte) decimal display | D Print a long word in decimal | u Print a short word in unsigned decimal | uu Print a 32-bit (4-byte) unsigned decimal display | U Print a long word in unsigned decimal | o Print a short word in octal | oo Print a 32-bit (4-byte) octal display | O Print a long word in octal | x Print a short word in hexadecimal | xx Print a 32-bit (4-byte) hexadecimal display | X Print a long word in hexadecimal | b Print a byte in hex | c Print a byte as a character | s Print a string of characters (a C-style string ending in null) | C Print a wide character as a character | S Print a null terminated string of wide characters | f Print a single precision real number | g Print a double precision real number | L Print a long double precision real number | i Disassemble machine instructionsIf mode is not specified, the mode used in the previous / command is assumed. In the case that there is no previous / command, 'X' is assumed.
Only those users familiar with machine-language programming and executable-file-code structure will find low-level debugging useful.
For more information on machine-level debugging, see Machine-level debugging in Ladebug Debugger Advanced Topics.
shared_library_command :Use the listobj command to list all loaded objects, including the main image and the shared libraries.listobj | readsharedobj filename | delsharedobj filename
For each object, the information listed consists of the full object name (with pathname) and the starting and ending addresses for the .text, .data, and .bss sections.
Use the readsharedobj command to read in the symbol table information for the specified shared object. This object must be a shared library or loadable kernel module. The command can be used only when a debuggee program is specified; that is, either the debugger has been invoked with it, or the debuggee was loaded by the load command.
Conversely, use the delsharedobj command to remove the symbol table information for the shared object from the debugger.
modifying_command :assign target = expression | patch target = expression target : unary_expression
The following example shows how to deposit the value 5 into the data member _data of a C++ object.
(ladebug) print node->_data
2
(ladebug) assign node->_data = 5
(ladebug) print node->_data
5
The following example shows how to change the value associated with a variable
and the value associated with an expression.
(ladebug) print *node
class CompoundNode {
_fdata = 12.345;
_data = 5; // class IntNode
_nextNode = 0x0; // class IntNode::Node
}
(ladebug) assign node->_data = -32
(ladebug) assign node->_fdata = 3.14159 * 4.2 * 4.2
(ladebug) assign node->_nextNode = _firstNode
(ladebug) print *node
class CompoundNode {
_fdata = 55.4176;
_data = -32; // class IntNode
_nextNode = 0x140001800; // class IntNode::Node
}
assign [classname::]member = ["filename"] `expression assign [object.]member = ["filename"] `expressionFor C++, use the assign command to modify static and object data members in a class, and variables declared as reference types, type const, or type static. The address referred to by a reference type cannot be changed, but the value at that address can be changed.
(ladebug) print *(int *)(5368717328)
-32
(ladebug) assign *(int *)(5368717328) = 1024
(ladebug) print *(int *)(5368717328)
1024
Use this command exclusively when you need to change the on-disk binary. Use the assign command when you need only to modify debuggee memory. If the image is executing when you issue the patch command, the corresponding location in the debuggee address space is updated as well. (The debuggee is updated regardless of whether the patch to disk succeeded, as long as the source and destination expressions can be processed by the assign command.) If your program is loaded but not yet started, the patch to disk is performed without the corresponding assign to memory.
(ladebug) run [1] stopped at [int main(void):24 0x120001324] 24 return 0; (ladebug) patch i = 10 0x1400000d0 = 10 (ladebug) patch j = i + 12 0x1400000d8 = 22 (ladebug)
After this is done, use the following commands to continue executing the program.
continue_command : step_into_command | step_over_command | step_out_of_command | cont_command | cont_from_place_command
Use the step command to execute a line of source code. When the line being stepped contains a function call, the step command steps into the function and stops at the first executable statement.
Use the stepi command to step into the next machine instruction. When the instruction contains a function call, the stepi command steps into the function being called.
For multithreaded applications, use these commands to step the current thread while putting all other threads on hold.
If the optional expression argument is supplied, the debugger evaluates the expression as a positive integer that specifies the number of times to execute the command. The expression can be any expression that is valid in the current context.
step_into_command :step [ step_number ] |stepi [ step_number ]
In the following example, two step commands continue executing a C++ program.step_number : expression
(ladebug) step
stopped at [void List<Node>::append(class Node* const):149 0x120001da8]
149 _firstNode = node;
(ladebug) step
stopped at [void List<Node>::append(class Node* const):156 0x120001e0c]
156 }
The following example shows stepping by
instruction (stepi). To see stepping into calls, see the
next example.
(ladebug) $curpc/4i
void List<Node>::append(class Node* const): x_list.cxx
*[line 156, 0x120001e0c] ldq r26, 0(sp)
[line 156, 0x120001e10] ldq r9, 8(sp)
[line 156, 0x120001e14] lda sp, 32(sp)
[line 156, 0x120001e18] ret r31, (r26), 1
(ladebug) stepi
stopped at [void List<Node>::append(class Node* const):156 0x120001e10] ldq r9, 8(sp)
(ladebug) stepi
stopped at [void List<Node>::append(class Node* const):156 0x120001e14] lda sp, 32(sp)
(ladebug) stepi
stopped at [void List<Node>::append(class Node* const):156 0x120001e18] ret r31, (r26), 1
(ladebug) stepi
stopped at [int main(void):187 0x1200024a8] ldah gp, 8192(r26)
Use the nexti command to execute a machine instruction. When the instruction contains a function call, the nexti command executes the function being called and stops the process at the instruction immediately after the call instruction.
For multithreaded applications, use these commands to step the current thread while putting all other threads on hold.
If the optional expression argument is supplied, the debugger evaluates the expression as a positive integer that specifies the number of times to execute the command. The expression can be any expression that is valid in the current context.
step_over_command :For example:next [ step_number ] |nexti [ step_number ]
(ladebug) next
stopped at [int main(void):189 0x1200024b0]
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
(ladebug) next
stopped at [int main(void):190 0x120002530]
190 nodeList.append(cNode);
The following example shows the difference between
stepi and nexti over the same call:
(ladebug) cont
[2] stopped at [void List<Node>::append(class Node* const):152 0x120001dc4]
152 while (currentNode->getNextNode())
(ladebug) $curpc/4i
void List<Node>::append(class Node* const): x_list.cxx
*[line 152, 0x120001dc4] ldq r27, -32584(gp)
[line 152, 0x120001dc8] jsr r26, (r27), getNextNode
[line 152, 0x120001dcc] ldah gp, 8192(r26)
[line 152, 0x120001dd0] lda gp, 25956(gp)
(ladebug) nexti
stopped at [void List<Node>::append(class Node* const):152 0x120001dc8] jsr r26, (r27), getNextNode
(ladebug) stepi
stopped at [class Node* Node::getNextNode(void):81 0x120002264] bis r31, r16, r1
(ladebug) cont
[2] stopped at [void List<Node>::append(class Node* const):152 0x120001dc4]
152 while (currentNode->getNextNode())
(ladebug) nexti
stopped at [void List<Node>::append(class Node* const):152 0x120001dc8] jsr r26, (r27), getNextNode
(ladebug) nexti
stopped at [void List<Node>::append(class Node* const):152 0x120001dcc] ldah gp, 8192(r26)
step_out_of_command :In the following example, the next command is used to step through process execution in the append method. The return command is used to finish the append method and return control to the caller.return | return qual_symbol
(ladebug) next
stopped at [void List<Node>::append(class Node* const):153 0x120001dd8]
153 currentNode = currentNode->getNextNode();
(ladebug) return append
stopped at [int main(void):192 0x1200025b0]
192 nodeList.append(new IntNode(3));
cont_command :When you use the cont command, the debugger resumes execution of the entire process.cont [ in loc ] | cont [ signal ] [ to_source_line ] |number_expression cont [ signal ] |conti to address_expression to_source_line : to [filename_string :] line_number number_expression : address_expression
In the following example, a cont command resumes process execution after it was suspended by a breakpoint.
(ladebug) list $curline - 5: 10
187 nodeList.append(newNode);
188
189 CompoundNode* cNode = new CompoundNode(12.345, 2);
190 nodeList.append(cNode);
191
> 192 nodeList.append(new IntNode(3));
193
194 IntNode* newNode2 = new IntNode(4);
195 nodeList.append(newNode2);
196
(ladebug) stop at 195
[#3: stop at "x_list.cxx":195 ]
(ladebug) cont
[3] stopped at [int main(void):195 0x120002644]
195 nodeList.append(newNode2);
The signal parameter value can be either a signal number or a string name (for
example, SIGSEGV). The default is 0, which allows the process to continue
execution without specifying a signal. If you specify a signal parameter value,
the process continues execution with that signal.
The in argument is used to continue until the named function is reached. The function name must be valid. If the function name is overloaded and you do not resolve the scope of the function in the command line, the debugger prompts you with the list of overloaded functions bearing that name from which to choose.
The to parameter value is used to resume execution and then halt when the specified source line is reached.
The form of the optional to parameter must be either:
You can set a one-time breakpoint on an instruction address before continuing by entering conti to address_expression.
You can modify the PC before continuing using the goto command, however this is extremely dangerous and can yield unpredictable results. We don't recommend using this command.
cont_from_place_command :goto line_expression
snapshot_command : save_snapshot_command | clone_snapshot_command | show_snapshot_command | delete_snapshot_command
save_snapshot_command :In the following example, the first line of the save snapshot message shows the snapshot_number (1), the time it is saved, and the ID number of the process that implements the snapshot. The next two lines show the status of the snapshot.save snapshot
(ladebug) save snapshot
# 1 saved at 13:27:54 (PID: 29077).
stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
Use the clone snapshot command to revert the state of the debuggee process to that of a previously saved snapshot. By doing this, you can conveniently return to the state saved in the snapshot as opposed to re-running the process and re-entering the debugger command sequence that brought you to that state.
Note that rerun and clone snapshot are different in that rerun always executes the process from the beginning, whereas clone snapshot doesn't execute the process at all; it simply duplicates the saved snapshot (using a mechanism similar to the fork system call) and "pretends" that the process execution has stopped at the point when the snapshot was saved.
clone_snapshot_command :The clone snapshot command clones the snapshot specified by snapshot_id. If no snapshot_id is specified, the most recently saved existing snapshot is cloned.clone snapshot [ snapshot_id ]
There are two side-effects to cloning a snapshot:
(ladebug) show process
>localhost:29013 (/usr/examples/x_list) paused.
(ladebug) clone snapshot
Process has exited
Process 29089 cloned from Snapshot 1.
# 1 saved at 13:27:54 (PID: 29077).
stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
(ladebug) show process
>localhost:29089 (/usr/examples/x_list) paused.
show_snapshot_command :For example:show snapshot [ snapshot_id_list ] snapshot_id_list : snapshot_id ,... | all | *
(ladebug) show snapshot all
# 1 saved at 13:27:54 (PID: 29077).
stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
delete_snapshot_command :For example:delete snapshot [ snapshot_id_list ]
(ladebug) show snapshot all
# 1 saved at 13:27:54 (PID: 29077).
stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
(ladebug) delete snapshot
(ladebug) show snapshot all
No snapshots have been saved.
Support for these features is limited to programs compiled using compilers from Compaq Computer Corp. These include Compaq Fortran 90, Compaq C and Compaq C++.
Taking advantage of these features only requires compilation of your program as described below. The debugger automatically takes advantage of specialized information that is included in the resulting executable program.
There are no Ladebug commands that control the debugger behavior when debugging optimized code. Rather, existing commands sometimes behave somewhat differently than you would see in the absence of optimization.
The sections below provide some insight into how Compaq compilers and the debugger deal with the consequences of key optimizations and how that may influence debugging of your program.
Why would you ever try to debug an optimized version? The most likely reason is that the program appears to work correctly when unoptimized but somehow fails when optimized. As a result, you may have little choice but to try to isolate the problem using the optimized program.
The most common reason that a program apparently works correctly when unoptimized but fails when optimized is this:
Your program performs some action whose behavior is undefined or implementation dependent, and the optimized version is different from the unoptimized version when performing this action.
For example, your program might read and depend on the value of a variable that did not get assigned a value. When executed in unoptimized form, the value that happens to be in that variable might accidently result in the desired behavior. But when optimized, the variable might have some other value that leads to different behavior. As another example, sometimes your program may be subtly dependent on the exact order in which operations are performedand optimization can result in a different order. There are many other examples that are beyond the scope of this discussion.
It is also possible that there is a bug in the compiler. While it does happen, experience with Compaq compilers indicates that this is rare.
In any case, to determine the cause or nature of the problem requires debugging using the optimized version. Then you can determine how best to resolve the problem. (Of course, you could also choose to reduce the level of optimization, possibly to none, to obtain the desired behavior but that may not result in acceptable performance.)
Note that the -g3 option differs from the -g option in that it does not affect the optimization level. That is, -g (equivalently -g2) sets the optimization level to zero (that is, -O0), even overriding an explicit optimization setting; -g3 leaves the optimization level alone. See the manual pages for the respective compilers for further details.
Split lifetime information in the debugging symbol table describes each of the child variables associated with the main variable, where it is allocated, and the exact range of addresses over which each child is valid.
Because assignments may not occur in the same order as in the source code, the split lifetime information also includes a list of all of the places that the current value may have been assigned. In general this is a list of possibilities because several execution paths may converge bringing together multiple assignment possibilities; the debugger does not trace the exact execution path that reaches a stopping point so it can only report the set of relevant alternatives.
When a variable does not have a value at the current location, the debugger cannot print a value for it and reports an error as follows:
(ladebug) print L
Info: symbol L is defined but not allocated (optimized away)
Error: no value for symbol L
Error: no value for L
The first error message line indicates that there is a symbol L, but that it does not (currently) have a value. The preceding informational line distinguishes between two cases:
If a variable is not declared at all, then the error report looks like:
(ladebug) print L
Symbol "L" is not defined.
Error: no value for L
When a variable has a value, there may also be information concerning
where that variable was assigned:
(ladebug) print j
2
Value assigned at line 5
The value may be assigned from several places:
(ladebug) print k
3
Value assigned at one of these lines: 6, 11
It is possible, though unusual, for the same line to be listed more
than once; this means that there is more than one instruction from
the same line that assigns a value.
The following limitations apply:
Semantic stepping causes the program to execute up to, but not including, an instruction that causes a semantic effect, as well as being in a different line. Instructions that cause semantic effects are instructions that:
Debugging optimized code information in the symbol table includes a detailed description of the possibly multiple disjoint instruction ranges that belong to or make up a scope. This helps assure that variable lookups find the right symbols at the current location.
You are not likely to directly perceive the effects and benefits of this support; just know that it is part of "getting the right answer" in the presence of optimization.
Use with caution
down, dump, func, return, where, pop, up
These commands generally depend on there being a distinct call frame on the execution stack for each called function. However, inlining can merge a called routine into the caller with the result that there is one frame instead of the two (or more) that might be expected. These commands can be used, but be careful to make sure that you end up in the frame you intend after each use and/or don't get misled.
next, nexti
For a call that is inlined, the next and nexti commands will appear to step into the called function instead of stepping over it.
Avoid completely
assign
It is generally not possible to reliably assign to a variable before the value of the variable has been used.
goto
It is generally not possible to reliably determine where the first instruction of a line begins or to avoid repeating instructions from the destination line that may have already been executed.if logical filter in breakpoint commands
The condition expression may not have a value at all in some places where the expression needs to be evaluated. Worse yet, the debugger sometimes attempts to cache the address of a variable, which does not correctly support split variables.watch variable
The debugger does not support watching a split variable. This command will most likely fail because the debugger cannot watch a variable (child or otherwise) that is allocated in a register; even if it does appear to succeed, the debugger will be watching the location of just one child even when that location is not relevant.operator &
It is generally not possible to reliably determine whether a variable has only one lifetime and thus a unique address.
To make the debugger more useful, it relaxes some standard C++ name visibility rules. For example, you can reference public, protected, and private class members.
The following limitations apply when you debug a C++ program:
Limitations for debugging templates include:
Be aware of the following data-type limitations when you debug a Fortran program:
The following limitations apply only to Compaq Fortran 90:
Binary operations and unary operations | Only integer, floating, and Boolean expressions are easily expressed. |
a+b,-,* | a+b,-,* |
a/b | a/b |
a = b /= < <= > >= | a = = b != < <= > >= |
a and b | a&&b |
a or b | a | | b |
a rem b | a%b |
not(a=b) | !(a==b) |
-a | -a |
Qualified expressions | None. There is no easy way of evaluating subtype bounds. |
Type conversions | Only simple numeric conversions are supported, and
the bounds checking cannot be done. Furthermore,
float -> integer truncates rather than rounds.
integer -> float
(ladebug) print (float) (2147483647)
|
Attributes | None, but if E is an enumeration type with default
representations for the values then
E'PRED(X) is the same as x-1. E'SUCC(X) is the same as x+1 |
p.all | *p (pointer reference) |
p.m | p -> m (member of an "access record" type) |
All types
The debugger, unlike the Ada language, allows out-of-bounds assignments to be performed.
Integer types
If integer types of different sizes are mixed (for example, byte-integer and word-integer), the one with the smaller size is converted to the larger size.
Floating-point types
If integer and floating-point types are mixed in an expression, the debugger converts the integer type to a floating-point type.
The debugger displays floating-point values that are exact integers in integer literal format.
Fixed-point types
The debugger displays fixed-point values as real-type literals or as structures. The structure contains values for the sign and the mantissa. To display the structure's value, multiply the sign and mantissa values. For example:
(ladebug) list 5
5 procedure a_showFixedPointType is
6
7 type FixedPoint is delta 0.1 range -3.0 .. 9.0;
8 myVar : FixedPoint := 1.0;
9
10 begin
> 11 myVar := myVar + 1.0;
12 end;
(ladebug) print myVar
struct packed object {
fixed_point, small = 0.625E-1 * mantissa = 16;
}
(ladebug) print 6.25E-02 * 16
1.0
Enumeration types
The debugger displays enumeration values as the actual enumeral or its position.
Enumeration values must be manually converted to 'pos values before you can use them as array indices.
Array types
The debugger displays string array values in horizontal ASCII format, enclosed in quotation ("x") marks. A single component (character) is displayed within single quotation ('x') marks.
The debugger allows you to assign a component value to a single component; you cannot assign using an entire array or array aggregate.
Arrays whose components are neither a single bit nor a multiple of bytes are described to the debugger as structures; a print command displays only the first component of such arrays.
Records
The debugger cannot display record components whose offsets from the start of the record are not known at compile time.
For variant records, however, the debugger can display the entire record object that has been declared with the default variant value. The debugger allows you to print or assign a value to a component of a record variant that is not active.
Access types
The debugger does not support allocators, so you cannot create new access objects with the debugger. When you specify the name of an access object, the debugger displays the memory location of the object it designates. You can examine the memory location value.
(ladebug) list 10: 3
10 01 firstItem PIC 9(9)v99.
11 01 secondItem PIC 9999v99.
12 01 thirdItem PIC 9(13)v9(5).
The debugger allows assignment of the values 1.23 or 8765.22 to firstItem, but does not allow assignment of the value 1.2 to firstItem. The following debugger commands are supported because the quantities on both sides of the assignment operator (=) have the same scale:
(ladebug) print firstItem, secondItem
2.46 1234.56
(ladebug) assign firstItem = 1.23
(ladebug) assign secondItem = 8765.22
(ladebug) print firstItem, secondItem
1.23 8765.22
(ladebug) assign firstItem = secondItem
(ladebug) print firstItem, secondItem
8765.22 8765.22
The following debugger commands are not supported because the quantities
involved are of different scales:
(ladebug) assign firstItem = 1.2
This item may only be assigned values of equivalent scale (-2)
(ladebug) assign thirdItem = firstItem
This item may only be assigned values of equivalent scale (-5)
(ladebug) assign secondItem = firstItem
This item may only be assigned values with a maximum precision of (6)
Another effect of COBOL language syntax is in the debugger memory-examine command. For example, to look at the next 10 program instructions, you would normally use:
(ladebug) &coboldata/10i
Bad or unimplemented printout mode for examine command.
Using X instead.
0x120002a90: 23bd5c8027bb2000
When debugging COBOL programs, you need to enter this command as follows:
(ladebug) &coboldata/10 i
coboldata(void): c_coboldata.cob
[line 2, 0x120002a90] ldah gp, 8192(r27)
[line 2, 0x120002a94] lda gp, 23680(gp)
[line 2, 0x120002a98] lda sp, -144(sp)
[line 2, 0x120002a9c] stq r26, 48(sp)
[line 2, 0x120002aa0] stq r9, 56(sp)
[line 2, 0x120002aa4] ldq r9, -32720(gp)
[line 2, 0x120002aa8] ldah r2, -1(gp)
[line 2, 0x120002aac] ldq r27, -32488(gp)
[line 2, 0x120002ab0] ldq r16, -32736(gp)
[line 58, 0x120002ab4] lda r9, -21(r9)
Add a space between the count (10) and the mode indicator (i).
$ascii | Prints ASCII or all ISO Latin-1. | |
$beep | Beeps on illegal command line editing. | |
$catchexecs | Stops execution on program exec. | |
$catchforkinfork | Notifies you as soon as the forked process is created (otherwise you are notified when the call finishes). | |
$catchforks | Notifies you on program fork. | |
$childprocess | When the debugger detects a fork, it assigns the child process ID to $childprocess. | |
$curevent | Current breakpoint number. | |
$curfile | Current source file. | |
$curfilepath | Current source file access path. | |
$curline | Current source line. | |
$curpc | Current point of program execution. | |
$curprocess | Current process ID. | |
$cursrcline | Last source line plus one. | |
$curthread | Current thread ID. | |
$dbxoutputformat | Displays various data structures in dbx format. | |
$dbxuse | Replaces current use paths. | |
$decints | Displays integers in decimal radix. | |
$doverbosehelp | Displays the help menu front page. | |
$editline | Enables command line editing. | |
$eventecho | Echoes events with event numbers. | |
$funcsig | Displays function signature at breakpoint. | |
$giveladebughints | Displays hints on Ladebug features. | |
$hasmeta | Interprets multibyte characters. | |
$hexints | Displays integers in hex radix. | |
$historylines | Number of commands to show for history. | |
$indent | Prints structures with indentation. | |
$lang | Programming language of current routine. | |
$lasteventmade | Number of last (successful) breakpoint definition. | |
$lc_ctype | Current locale information. | |
$listwindow | Number of lines to show for list. | |
$main | Name of first routine in program. | |
$maxstrlen | Largest string to print fully. | |
$octints | Displays integers in octal radix. | |
$overloadmenu | Prompts for choice of overloaded C++ name. | |
$page | Paginates debugger terminal output. | |
$pagewindow | Number of lines per output page. | |
$parentprocess | When the debugger detects a fork, it assigns the parent process ID to $parentprocess. | |
$pimode | Echoes input to log file on playback input. | |
$prompt | Specifies debugger prompt. | |
$repeatmode | Repeats previous command on | |
$showlineonstartup | Displays the first executable line in main. | |
$showwelcomemsg | Displays welcome message at startup time. | |
$stackargs | Shows arguments in the call stack. | |
$statusargs | Prints breakpoints without parameters. | |
$stepg0 | Steps over routines with minimal symbols. | |
$stoponattach | Stops the running process on attach. | |
$stopparentonfork | Stops parent process execution on fork. When set to a non-zero value, this variable instructs the debugger to stop the parent process after it forks a child process. The child process continues to run if $catchforks is set, otherwise it does not. The default is 0. | |
$threadlevel | DECthreads or native threads. | |
$usedynamictypes | Evaluates using C++ static or dynamic type. | |
$verbose | Produces even more output. |
UNIX is a registered trademark and The Open Group is a trademark of The Open Group in the United States and/or other countries. All other product names mentioned herein may be the trademarks or registered trademarks of their respective companies.
Confidential computer software. Valid license from Compaq required for possession, use, or copying. Consistent with FAR 12.211 and 12.212, Commercial Computer Software, Computer Software Documentation, and Technical Data for Commercial Items are licensed to the U.S. Government under vendor's standard commercial license.
Compaq shall not be liable for technical or editorial errors or omissions contained herein. The information in this publication is subject to change without notice and is provided "as is" without warranty of any kind. The entire risk arising out of the use of this information remains with recipient. In no event shall Compaq be liable for any direct, consequential, incidental, special, punitive, or other damages whatsoever (including without limitation, damages for loss of business profits, business interruption, or loss of business information), even if Compaq has been advised of the possibility of such damages.
The limited warranties for Compaq products are exclusively set forth in the documentation accompanying such products. Nothing herein should be construed as constituting a further or additional warranty.