| Title and Contents |
However, you can do the following to make debugging easier:
.o files by compilers. The level of
information is controlled by compiler switches. See the reference page for your
compiler. The switch is probably -g.
The debugging information is propagated into the a.out or
*.so by the ld command.
It is removed by the strip command. 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) reference page.
debugBreak function to start the debugger
at some specified point in the program
This chapter describes the first two methods.
The debugBreak
function is described in the FAQ section of the Ladebug website
(http://www.compaq.com/ladebug).
This chapter also discusses the following topics:
The following is the shell syntax to invoke the debugger using the
ladebug command:
ladebug
[ -c file ]
[ -gui ]
[ -i file ]
[ -I directory ]
[ -interactive ]
[ -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 ladebug command
options and parameters:
| Options and Parameters | Description |
|---|---|
-c |
Specifies an initialization command file. The default initialization file is
.dbxinit. During startup, the debugger searches for this file 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) on Tru64 UNIX systems only. |
-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. |
-interactive |
Causes the debugger to act as though stdin is isatty(),
regardless of whether or not it is. This flag is sometimes useful when using
rsh to run the debugger. Currently, the only effect is to cause
the debugger to output the prompt to stdout when it is ready for
the next line of input. |
-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 (" ").
You can specify a debugger prompt when you start the debugger from a shell
with the -prompt option. The default prompt is
(ladebug).
You can also change the prompt by setting the
$prompt debugger variable. For example:
|
-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 do not 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 Grand Unified Debugger (GUD) 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 support GNU Emacs Version 19 and higher.
Ladebug Version 4.0-58 and higher support 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-file
At 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 ladebug
The following invocation line displays:
Run the debugger (like this): ladebug
Edit 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 from within Emacs is to get a 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:
step command by typing the command in the GUD
buffer.
C-x SPC
M-x info
Then 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_command
: quit
Alternatively, you can type exit, which is a pre-defined
alias for quit.
help command:
help_command
: help [ topic ]
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.
-gui
switch.
For example:
% ladebug -gui
guion_command
: gui
For example:
(ladebug) gui
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.
stdin, which is usually one of the following:
./.ladebugrc, if available, otherwise
~/.ladebugrc, if available
./ladebugresource
~/ladebugresource
/usr/lib/X11/app-defaults/ladebugresource
.ladebugrc and
.dbxinit are shown in the following table:
| 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:
|
The debugger attaches and stops. | The debugger attaches and waits for you to press 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).
|
This chapter discusses the following topics:
stdin. The debugger supports command
line editing when processing stdin if stdin is a
terminal and the
debugger variable $editline
is non-zero (the default; see the
set
command to change it). For this to work
correctly, you must set the terminal width to
the correct value. After editing, press the Return key to send the line to the
debugger.
history command.
The debugger copies each line from stdin to the
record input file,
if you have requested that file.
The debugger scans each line from the beginning, looking for backslash (\)
characters which 'quote' their immediately following character. If the line ends
in a quoted new line, then another line is similarly processed from stdin and
appended to the first one, with the quoted new line 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 exclamation point (!), 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 a caret (^), these rules apply:
Exclamation points and carets cannot be used in command lists built with
braces ({});
for example, {print3; !!3} will not parse. They may be used in scripts.
History in a command list is not limited by braces, 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 alias has 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.
run/rerun
The following table shows how various environment variables expand. It
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 |
|
stop at "$BIN/a.out":20 |
stop at "/usr/users/hercules/\
bin/a.out":20 |
run $BIN/a.out ~/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 the state of the tokenizer, and starts on the next token.
input
: command_list
| comment
A command_list is a sequence of commands that are executed one after
the other.
command_list
: command ;...
| command ;
| command
A comment is a line that begins with
a pound (#) character.
comment
: #
Any text after an unquoted pound character is ignored by the debugger. If the first
non-whitespace character on a line is a pound character, the whole line is
ignored.
NOTE: The difference between a blank command line and a command line that is a comment is that 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.
Following is a list of debugger commands:
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
thread
in
at
state
if
with
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. Some places
require a braced_command_list just for readability, or to assist
the debugger in understanding your input.
braced_command_list
: { command_list }
The following table lists the three different varieties of debugger variables:
| User-defined variables | You create these and can set them to a value of any type. |
| Preference variables | You modify these to change debugger behavior. You can only set a preference variable to a value that is valid for that particular variable. |
| Display/state variables | These variables display the parts of the current debugger state. You cannot modify them. |
For more information about debugger variables, see Appendix 1Debugger Variables.
The following commands deal specifically with debugger variables:
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 Ladebug release, all debugger variables
will be required to start with a dollar sign.
NOTE: If a debugger variable exists that shares a name with a program variable, and you print an expression involving that name, which of the two variables the debugger finds is undefined.
The first form creates the debugger variable if it does not already exist. It then sets the value of the debugger variable to the result of evaluating the expression. For example:
(ladebug) set $myLoopCounter = 0
(ladebug) print $myLoopCounter
0
The second form is equivalent to the command
set dbgvar_name = 1. For example:
(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
$childprocess = 0
$curevent = 0
$curfile = "x_list.cxx"
$curfilepath = "../src/x_list.cxx"
$curline = 182
$curpc = 0x3ff8001bf48
$curprocess = 10888
$cursrcline = 182
$cursrcpc = 0x3ff8001bf48
$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
$parentprocess = 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 cannot be deleted or are automatically recreated in the future
when needed. For example:
(ladebug) unset $myLoopCounter
(ladebug) print $myLoopCounter
Symbol "$myLoopCounter" is not defined.
command_repetition_command
: !!
| ! integer
| !- integer
| ! string
To repeat the last command line, enter two exclamation points
or press the Return key. You can also enter !-1.
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.
Following 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. For example:
execute_commands_from_file_command
: source filename
| playback input filename
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.
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 the pound character (#) to create comments to format your scripts.
The following is an example 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>*)0x11ffff288)->List<Node>::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 ]
| unrecord io
| unrecord input
| unrecord output
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, use the appropriate version of the unrecord command,
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
This example results in the following 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 the
following:
(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
If input or output is already being recorded, a new record input
command will close the old file and record to a new one, rather
than record simultaneously to two files. In that connection,
note that record io is equivalent to the combination of
record input and record output, and will cause any open
recording files to be closed.
history command. Use history_number to indicate
how many commands to show, starting with the most recent. If you do not
specify
$historylines, the 20 previous commands are
shown. See also
History replacement of the line.
history_command
: history [ integer_constant ]
For example:
(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.
system function.
This function is documented in the system (3) reference page.
The call results in the sh shell executing the string you
specify:
execute_shell_command
: sh string
For example, you can spawn a shell from the debugger by issuing:
(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 -f
% ls out
out
% ls *.b
recio.b
stdio.b
% exit
(ladebug)
edit command to invoke the editor defined
by the EDITOR environment variable.
edit_file_command
: edit [ string ]
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 no current file exists, the editor is started without a file.
If the EDITOR environment variable is undefined, the debugger
invokes the vi editor.
The following example invokes the Emacs editor on the file chars.c:
(ladebug) sh printenv EDITOR
emacs
(ladebug) file
chars.c
(ladebug) edit
The following example invokes the nedit editor on the file
~/foo/bar.f:
(ladebug) sh printenv EDITOR
nedit
(ladebug) edit ~/foo/bar.f
$curprocess contains the
process id
for this process. Naming and switching the debugger between
processes is described in Multiprocess Debugging.
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, and so on. This process never continues, and is killed when:
Using the run command on such a potential
process causes the debugger to create a process that 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, and so on, 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.
argc/argv, file descriptors, and so on. This is what
usually happens when you
run your program from a shell command line.
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:
stdin, stdout,
and stderr connected, you can run it as a child process of the
debugger process. For example:
% ladebug a.out
or
% ladebug
(ladebug) load a.out
For example:
% ladebug -pid process_id a.out
or
% 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,
SEGV. If you have set the $stoponattach
preference variable, it stops immediately.
One method you can use to make attaching to a process 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();
...
}
$stoponattach.
stallForDebugger variable, and continue
the execution of the process, so that it exits from the loop:
(ladebug) assign endStallForDebugger = 1
(ladebug) set any needed breakpoints etc.
(ladebug) cont
load command, you can tell the debugger which executable
file you intend to execute in some process. The load command
reads the symbol table information of an executable file and, optionally, a
core file. (This is done automatically when you give the debugger a file name
on the shell
command line.)
load_command
: load filename [ filename ]
For example:
% ladebug /usr/examples/x_list
or:
(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 at the point 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
: unload pid ,...
| unload filename
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 an executable file.
For example:
(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:
run_command
: run [ argument_string ] [ io_redirection ... ]
| rerun [ argument_string ] [ io_redirection ... ]
The rerun command is a synonym for the
run command.
If the rerun command is specified without
arguments, the arguments and io_redirection argument of the most recent
run
command entered with arguments are used. If the last modification time 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 argument allows you to change stdin, stdout, and
stderr, which are otherwise inherited from the debugger process.
For example:
io_redirection
: < filename
| > filename
| 1> filename
| 2> filename
| >& filename
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 forms because the grammar may change in a future release of the debugger.
> 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 files
For 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
: kill
Killing a process leaves the debugger running. Any breakpoints previously
set are retained. You can later rerun the program.
For example:
(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
: attach pid [ filename ]
The process is specified by its pid:
pid
: expression
For example:
(ladebug) attach 12345 a.out
The 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 pressing
Ctrl/C or by 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
: detach pid ,...
For example:
(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_command
To print either all the environment variables that are currently set, or a
specific one, use a show_environment_variable_command.
For example:
show_environment_variable_command
: printenv [ environment_variable_name ]
| export
| setenv
NOTE: The
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
: string
For 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 an asterisk (*) is specified, all environment variables are removed.
NOTE: There is no command to simply return to the initial
state of the environment variables after the debugger starts. You must use
set_environment_variable commands and
unset_environment_variable commands
appropriately.
fork, and
$catchforks was
set.
At any one time, you can control only one of the processes that the debugger controls. 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
: show process [ all ]
| process
all
: all
| *
For example:
(ladebug) show process
>localhost:18348 (/usr/examples/x_list) loaded.
You can explicitly command the debugger to control a different process:
switch_process_command
: process pid
| process filename
The process you are switching away from remains stalled until either the
debugger exits or until you switch to it and continue it.
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 on which they operate.
$catchforksWhen set to a non-zero value,
this variable instructs
the debugger to stop the child process on exit out of the fork() or
vfork() calls. The parent process continues to run. The default is 0 (zero).
$stopparentonforkWhen set to a
non-zero value, this variable instructs the debugger to stop the parent process
on exiting out of the fork() or vfork() calls after it forks a
child process. The child process
continues to run if $catchforks is 0; otherwise, it does not.
The default is 0 (zero).
$catchforkinforkWhen set to a
non-zero value, this variable
instructs the debugger to stay in the fork routine after the fork and notifies you as
soon as the forked
process is created; otherwise, you are notified when the call finishes. The default
is 0 (zero).
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 the following:
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 the following:
list command lists the source code for the current process.
$catchexecs to 1 to instruct the debugger to stop
the process and
notify you when an exec occurs. The process stops before executing any user
program code or
static initializations. You can debug the newly executed process.
The debugger keeps a history of the progression of
the executed files.
In the following scenario, you set the predefined variables
$catchforks and
$catchexecs to 1. The debugger will notify
you when an execution 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 the following:
process $childprocess to set the current process context to the child process.
exec occurs.
core and places it in the current directory.
The core file is not an executable file; it is a snapshot of the state of
your process at the time the error occurred. It allows you to analyze the
process at the point it crashed. For more information on core file debugging,
see Core File Debugging in the Ladebug Debugger Advanced Topics
on the Ladebug website.
root login) to examine either the running
system or crash dumps. Whether or not you need to be the superuser depends on
the directory and file protections for the files you attempt to examine.
By default, compilation does not strip the symbol table information and optimization is only partial. If you do not change these defaults, you should not encounter a problem.
patch command to correct
bad data or instructions in an executable disk file. The text, initialized data,
or read-only data areas can be patched. The bss segment cannot be
patched because it does not exist in disk files. For example:
(ladebug) patch @foo = 20
$tid contains the thread identifier of the
current thread. When no process or program exists, $tid is set to 0.
The $tid value is updated implicitly by the debugger
when program execution stops or completes.
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
: kps
For example:
(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 the kloadsrv daemon, for example,
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:
trap() function being invoked.
panic() function.
/etc/fstab
file structure table and the /sbin/swapdefault file. At system reboot
time, the information is copied into a file, called a crash dump file.
Crash dump files are either partial (the default) or full. See Compaq
TRU64 UNIX Kernel Debugging for more information.
You can analyze the crash dump file to determine what caused the crash. For
example, if a hardware trap occurred, you can examine variables, such as
savedefp, the program counter ($pc), and the stack pointer
($sp), to help
you determine why the crash occurred. If a software panic caused the crash, you
can use the debugger to examine the crash dump and use the uerf
utility to examine the error log. Using these tools, you can determine which
function called the panic() routine.
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
savedefp contains the
location of the exception frame. (No exception frames are created when you force
a system to dump.) Refer to the header file /usr/include/machine/reg.h
to determine where registers are stored in the exception frame. The following
example shows an exception frame:
(ladebug) print savedefp/33X ffffffff9618d940: 0000000000000000 fffffc000046f888 ffffffff9618d950: ffffffff86329ed0 0000000079cd612f . . . ffffffff9618da30: 0000000000901402 0000000000001001 ffffffff9618da40: 0000000000002000
(ladebug) print *pmsgbuf
struct msgbuf {
msg_magic = 405601;
msg_bufx = 1851;
msg_bufr = 1343;
msg_bufc = "Alpha boot: available memory from 0x6ca000 to 0x3f16000\nTru64 UNIX V.n (Rev. 564); Fri Jul 11 11:25:29 EDT 1997 \nphysical m";
}
crashdc utility collects critical data from operating system
crash dump files or from a running kernel. You can use the data it collects to
analyze the cause of a system crash. The crashdc utility uses existing
system tools and utilities to extract information from crash
dumps. The information garnered from crash dump files or from the running
kernel includes the hardware and software configuration, current processes, the
panic string (if any), and swap
information.
See Compaq TRU64 UNIX Kernel Debugging and the
crashdc(8) reference page for more information.
d flag to the boot_osflags console
environment variable.
partial_dump variable to 0 using the
debugger as
follows:
(ladebug) assign partial_dump = 0
partial_dump value of 1 indicates that partial dumps are to be generated.
See Compaq TRU64 UNIX Kernel Debugging for more information.
pmsgbuf, and in the panicstr global variable.
where command.) Most
likely, this thread will contain the events that led to the panic.
crashdc utility
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 at which you observe the first evidence of the problem. 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 you will not see 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
actions 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_commandThis chapter discusses the following topics:
The following is a particularly common breakpoint:
(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. For example:
(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 thequiet ] detector [ thread_filter ] [ logical_filter ] [ breakpoint_actions ]
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.
NOTE: Additional obsolete forms of breakpoint definition 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 | whenThe
stop command 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.
The when command 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.
quiet keywordBy 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.
The debugger uses several kinds of detectors, 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 locations 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 access detector specifies any kind of memory access using an unaligned access.
This section describes each type of detector.
place_detector : infunction_name | in all function_name | pc address_expression | at line_specifier | every proc entry | every procedure entry | every instruction | expression
The in function_name detector
specifies the event where execution reaches the entry of the
named function. For example:
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 from
----------------------------------------------------
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.
The in all function_name detector
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 ]
The pc address_expression detector
specifies the event where execution reaches the given machine address:
(ladebug) stop pc 0x120002498
[#7: stop PC == 0x120002498 ]
The at line_specifier detector
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 no code is associated with the given line number, the debugger
finds and substitutes the closest higher line number that has
associated code.
The every procedure entry detector 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.
The every instruction detector 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 : variablevariable_name | memory start_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, or can include 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. For example:
(ladebug) whatis _nextNode
class Node* 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. For example:
(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 SEGV, 3, SIGINT
[#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
administrator can choose a different default. See the uac(1)
reference 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 : threadThethread_id ,...
thread_id expressions are evaluated at the time the breakpoint command
is entered, and each must yield an integer value.
A detected event is retained for further consideration only if the thread in which the event occurs matches one of the given threads. 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 : ifA detected event is retained for further consideration only if the given expression evaluates toexpression
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 rechecked 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. For example:
(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.
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. For example:
(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.
call
continue
goto
next
return
step
It is easy in such cases to lose track of just what state breakpoint processing is really in 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.
attach and detach
run and rerun
process with an argument
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 only if all of the breakpoints so specify in their disposition. If any one of them specifies a break, the debugger prompts you for further commands.
call
continue
goto
next
return
step
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 or where you
really are in your program. Such confusion may mislead or misdirect your
debugging effort. See the
call command
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. For example:
(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. For example:
(ladebug) stop in C::foo
Select from
----------------------------------------------------
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 from
----------------------------------------------------
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 from
----------------------------------------------------
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. For example:
(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 the following 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>*)0x11ffff268)->List<Node>::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]
catch and
ignore, can be used to handle UNIX signal events:
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 debugger should
catch and handle the given UNIX signal. 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:
catch command.
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 stop unaligned
command:
Although this looks like a normal catch command, it
differs in several respects:
unaligned is not the name of a UNIX signal.
unaligned is never listed by either the
catch or ignore commands without
an argument.
catch commands, the following rules apply:
catch command.
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) by using the following
command:
(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.
SIGINT)
to your program. Because the debugger itself catches signal SIGINT by
default, this interrupts your program and returns control to the Ladebug
prompt.
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.
exec(), fork(), dlopen() and dlclose() System Calls
A process starts with a copy of its parent's memory as the result of a
fork() system call; after running for a while within that
memory, the process will often make an exec() system call to
start a new executable file within that process.
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 reprocesses 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 reprocesses 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
stop variable
or stop memory breakpoint:
obsolete_watch_breakpoint_definition_command : watch obsolete_watch_detector [ obsolete_watch_modifiers ] [ breakpoint_actions ] obsolete_watch_detector : variableAn obsolete watchpoint and avariable_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 ]
stop command differ in the following
respects:
watch instead of
stop.
memory is optional; if omitted, it is assumed.
(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;
when in
or when at breakpoint, possibly combined with watching
for a change of a variable's value:
obsolete_trace_breakpoint_definition_command : trace [Following are the differences between an obsolete tracepoint and avariable_name ] [ thread_filter ] [ where_modifier ] [ logical_filter ] [ breakpoint_actions ] | trace function_name [ logical_filter ] [ breakpoint_actions ] | trace line_number [ logical_filter ] [ breakpoint_actions ] where_modifier : in function_name | at line_number
when
command:
trace instead of
when.
true).
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. For example:
(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 the following 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 important, the variable change and filter tests are performed after every instruction is executed, making these definitions especially demanding on program performance.
at keyword is followed by an address in these commands,
instead of a line number.
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. For example:
(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.
status command to display the current breakpoint table:
show_all_breakpoints_command : statusEach entry in the current breakpoint table is displayed showing all of its properties. For example:
(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 | disableFor example:breakpoint_number_expression ,... enable_breakpoint_command : enable all | enable breakpoint_number_expression ,... delete_breakpoint_command : delete all | delete breakpoint_number_expression ,...
(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 }
browse_source_command
: source_directory_mapping_command
| source_searchlist_command
| select_source_file_command
| list_source_file_command
| search_source_file_command
Special debugging information that the compiler puts in the .o files
correlates the machine instructions and data back to the source files and the
positions they came from.
Source files are compiled and linked into executable files. During debugging, the debugger tries to find these source files to display them for you. If the source files have moved, or if the paths to them are relative, the debugger may not be able to locate them. All the information the debugger needs comes from the executable files or shared libraries, not the source files.
The debugger searches for a source file
(dir_name/base_name) using the following algorithm:
dir_name is mapped to
another source directory (mapped_dir_name), look for
mapped_dir_name/base_name. Otherwise, look for the original
file dir_name/base_name.
use_dir in
use_list, look for use_dir/dir_name/base_name.
Note that the use_list entries are tried in the order they appear in
the use_list.
use_dir in use_list, look for
use_dir/base_name. Just as in Step 2, the use_list
entries are tried in the order they appear in the use_list.
The debugger has source directory mapping commands that:
x_solarSystem as follows:
% 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.cxx
Then you move the directory solarSystemSrc elsewhere:
% mv solarSystemSrc movedSolarSystemSrc
Now 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/users303/brett/project_ladebug/sb/build-latest/test/src/common/Examples/bin-alpha-osf1/solarSystemSrc/main/solarSystem.cxx
./solarSystem.cxx
../src/solarSystem.cxx
/usr/users303/brett/project_ladebug/sb/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.
The following command displays a summary of the source directories
in a.out. The
ellipsis (...) here means that solarSystemSrc contains one or more source
directories.
(ladebug) show source directory
.
solarSystemSrc
...
/usr/include/cxx
Information: You can further expand ellipsis points (...) 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>.
The following command directs the debugger to look for source files originally
in
solarSystemSrc in movedSolarSystemSrc instead. This
time, the debugger finds the source file.
(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 }
The following 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.
(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
To summarize, the debugger provides the following four commands for checking and setting source directory mappings:
source_directory_mapping_command
: 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
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.
The show all source directory command is identical to the
show source directory command except that the
mapping information of all the descendants of directory_name is displayed:
(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
When you further expand ellipsis points (...) where directory is the directory on the line above the ellipsis points:
show source directory command displays only the children
of
directory_name.
show all source directory command displays all the
descendants of directory_name.
map source directory command to tell the debugger that the source
files in the directory from_directory_name can now be found in
to_directory_name.
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. For example:
(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
(ladebug) unmap source directory solarSystemSrc
(ladebug) show source directory solarSystemSrc
solarSystemSrc
solarSystemSrc/base_class_includes
solarSystemSrc/derived_class_includes
solarSystemSrc/main
NOTE: The symbol *=> means that you are setting the mapping
explicitly
using the map source directory command, whereas => means
that the mapping is derived from an existing explicit mapping.
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 following commands let you view and modify the use_list.
source_searchlist_command
: use_command
| unuse_command
Enter 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.
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 ]
: fileexpr [ expression ]
Use 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.
If the file name is not a literal, use the fileexpr
command. For example, if you have a script that calculates a file name in a debugger
variable or in a routine that returns a file name as a string, you can use
fileexpr to set the file.
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. This example also shows the
fileexpr command setting the current scope back to
the original file which is solarSystem.cxx.
(ladebug) run
[1] stopped at [void main(void):114 0x120004040]
114 unsigned int j = 1; // for scoping examples
(ladebug) file
solarSystemSrc/main/solarSystem.cxx
(ladebug) set $originalFile = "solarSystem.cxx"
(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*, enum StellarClass, StellarSubclass):26 0x120004b4c]
26 Star::Star(
(ladebug) file
solarSystemSrc/star.cxx
(ladebug) fileexpr $originalFile
(ladebug) file
solarSystemSrc/main/solarSystem.cxx
(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
edit command will display an
editor on the current file, using
the current definition of the EDITOR environment variable, if there is one.
However, some primitive inspection capabilities are built into the
debugger. The list command displays source lines, beginning with the
source code line corresponding to one of the following:
list
command
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 (the line number of the first line to display within the current source file) or a function (the first line of the function).
Specify the exact range of source lines as either a comma followed by the expression for the last line, or a colon followed by the expression for the the number of lines. This 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 string is actually just the rest of the line, not a string literal. The rest of the line is still having alias expansion done on it.
Use a slash (/) to search forward from the most recently
listed
line; use a question mark (?) to search 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:
_firstNode:(ladebug) /_firstNode
69 NODETYPE* _firstNode;
append before line 69:(ladebug) ?append
65 void append (NODETYPE* const node);
append after line 65:(ladebug) /append
145 void List<NODETYPE>::append(NODETYPE* const node)
pthreads (user application threads), also known as POSIX threads
To specify the thread level, set the
$threadlevel
debugger variable to one of the following strings:
decthreadsfor POSIX thread library debugging
nativefor kernel thread debugging.
For example:
(ladebug) set $threadlevel = "decthreads"
For core file debugging, the $threadlevel is always set to
"native".
You can use 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 eq thread_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.
switch_thread_command : thread [ thread_id ]The
$curthread value is updated when program
execution stops or completes.
You can modify the current thread 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:
pthreads
to synchronize access to shared resources, to ensure the following:
show mutex command to list information about currently available
pthread mutexes:
show_mutex_variable_command
: 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
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.
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 if the
$threadlevel is set
to native, an appropriate message is issued.
pthread synchronization object used in conjunction
with a mutex. A condition variable is used when a thread has locked a mutex to gain
access to data and then finds it must wait for some other thread to change some
aspect of the data before it can continue.
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 if the
$threadlevel is set to
native, an appropriate message is issued.
You can use the
The
The
The You can pass an undocumented string directly into the undocumented
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; you can use it to
examine and manipulate call stacks, and use them as a basis for further queries:
When your process is stopped by the debugger, you can show the call stack
of the thread that caused the stoppage, or the call stack of any other thread.
The following commands show the most recent call frames on the call stack of the current
or specified threads:
If specified, the expression must evaluate
to a nonnegative integer. You can specify the number of call frames to show.
If not specified, all the call frames for the thread are shown.
If specified, the
When large and complex values are passed by value to a routine on the
stack, the output of the
The stack trace provides the following information for each call level:
Use the
When the current call frame changes, the debugger displays the source line
corresponding to the last instruction executed in the function executing the
selected call frame.
When large and complex values are passed by value to a routine on the
stack, the output of the
Use the
If no frames are available to select from, the debugger context is set to the
static context of the named function. The current scope and current language
are set based on that function. Types and static variables local to that
function are now visible and can be evaluated.
If you enter an integer expression, the debugger moves to the frame at
level
In the following example, the current call frame is changed
to one for method NOTE: Because it is extremely
unlikely this will fix all the effects of a half-executed call, this command
is not recommended for general use. Furthermore, the
Instead of the
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 will be correlated to the code they came from.
The compiler will probably have supplied the debugger with some invented
name for the function.
Use the
Consider the following declarations in a C++ program:
Use the
When large and complex values are passed by value to a routine on the
stack, the output of the
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
When you call a function when execution is suspended in a called function,
you are nesting function calls, as shown in the following example:
The debugger supports function calls and expression evaluations that
call functions, with the following limitations:
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 (`).
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 (`).
The
Setting the class scope nullifies the function scope and vice versa. To return to the
default (current function) scope, use the command
Explicitly setting the debugger's current context to a class enables you to view a class
to:
After the class scope is set, you can set breakpoints in the class's
member functions and examine data without explicitly mentioning the class name.
If you do not want to affect the current context, you can use the scope
resolution operator (::) to access a class whose members are not currently
visible. Use the
The following example shows the use of the
The
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
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
You can also display individual object members using the member access
operators, period (.) and right arrow (->), in a
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
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,
The display of dynamic type information is supported for C++ class pointers
and references. All other types display static type information. In
addition, if the dynamic type of an object cannot be determined, the debugger
defaults to the use of static type information.
This debugger functionality does not relax the C++ visibility rules regarding
object member access through a pointer/reference (only members of the static
type are accessible). For more information about the C++ visibility rules, see
The Annotated C++ Reference Manual (by Margaret E. Ellis and Bjarne
Stroustrup, 1990, Addison-Wesley Publishing Company).
In order for dynamic type information to be displayed, the object's
static type must have at least one virtual function defined as part of its
interface (either one it introduced or one it inherited from a base class). If
no virtual functions are present for an object, only the static type
information for that object is available for display.
The following example shows debugger output with
When you use the
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.
The following example shows a case in which the expanded syntax can be used:
Sometimes the debugger does not see class type names with internal linkage. When
this happens, the debugger issues the following error message:
If a program is not compiled with the
If the
If you prefer this method, set the
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 points 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
The compiler generates additional parameters for nonstatic member functions. When the
When the
The following example prints class information using the
You can display stored values in the following formats by specifying
mode:
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
on the Ladebug website.
Use the
Conversely, use the
The following example shows how to deposit the value
You can use the
Use this command exclusively when you need to change the on-disk binary. Use the
Use the
Use the
For multithreaded applications, use these commands to step the current thread
while putting all other threads on hold.
If you supply the optional expression argument, the debugger evaluates the
expression as a positive integer that specifies the number of times to execute
the command. The expression can be any expression that is valid in the current
context.
Use the
For multithreaded applications, use these commands to step the current thread
while putting all other threads on hold.
If you supply the optional expression argument, the debugger evaluates the
expression as a positive integer that specifies the number of times to execute
the command. The expression can be any expression that is valid in the current
context.
In the following example, a
Use the
Use the
You can set a one-time breakpoint on an instruction address before continuing
by entering
NOTE: Modifying the PC before continuing using
the Use the
Note that
The Cloning a snapshot has two side effects:
If you are debugging optimized code under the Alpha Linux operating system,
the following information applies:
The sections that follow 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:
For example, your program might read and depend on the value of a
variable that was not assigned a value. When executed in
unoptimized form, the value that happens to be in that variable might
accidently result in the desired behavior. But when optimized, the
variable might have some other value that leads to different behavior.
As another example, sometimes your program may be subtly dependent on
the exact order in which operations are 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
Split lifetime information in the debugging symbol table describes
each of the child variables associated with the main variable, where
it is allocated, and the exact range of addresses over which each
child is valid.
Because assignments may not occur in the same order as in the source
code, the split lifetime information also includes a list of all of
the places where the current value may have been assigned. In general,
this is a list of possibilities, because several execution paths may
converge, bringing together multiple assignment possibilities; the debugger
does not trace the exact execution path that reaches a stopping point,
so it can only report the set of relevant alternatives.
When a variable does not have a value at the current location, the debugger
cannot print a value for it and reports an error as follows:
The first error message line indicates that there is a symbol L,
but that it does not currently have a value. The preceding informational
line distinguishes between two cases:
If a variable is not declared at all, then the error report looks
like the following:
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
Avoid Completely
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 to debugging a C++ program:
Limitations for debugging templates include the following:
Be aware of the following data-type limitations when you debug a Fortran
program:
The following limitations apply only to Compaq Fortran 90:
where command to display the
stack trace of current threads. You can specify one or more threads or all threads.
print command evaluates an optional
expression in the context of the current thread and displays the result.
call command evalutes an expression in the context
of the current thread and makes the call in the context of the current thread.
printregs command prints the registers for the
current thread.
8.2.7 Undocumented pthread Support
pthread debugging support. This is an internal debugging aid, not intended for
general use.
pthread_command
: 8.3 Looking at the Call Stack
Most programming languages have some concept of functions, routines, or
subroutines, capturing the notion of code that is invoked from many places.
A running program needs a call stack of call frames for the called functions.
Each call frame contains both the information needed to return to its caller
and the information needed to contain the local variables of the function.
call_stack_command
: show_stack_command
| change_stack_frame_command
| pop_stack_frame_command
show_stack_command
: thread_specifier specifies the
threads whose call stacks are to be shown. If not specified, just the
current thread is used.
where, up,
down, and dump commands 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 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.
8.3.1 Navigating the Call Stack
You can select one of the call frames as the starting point for examining
variables. This call frame provides the current scope in the program
for which variables exist, and tells the debugger which instance of those
variables whose values you want to see.
change_stack_frame_command
: up 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.
where, up,
down, and dump commands 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.
func command without the loc to display the
current function.
To change the function scope to a function that has a call frame in the
call stack, specify the loc either as the name of the function or as an integer
expression evaluating to
the call level. If you specify the name, the most-recently entered call
frame for that function becomes the current call frame.
n, just as if you had entered up n.
Planet::print so that a variable in that instance
of print() can be displayed:
In the previous example, instead of entering
(ladebug) where 4
#0 0x1200047dc in ((Planet*)0x140002860)->Planet::print(i=2) "solarSystemSrc/planet.cxx":19
#1 0x12000422c in ((HeavenlyBody*)0x140002860)->HeavenlyBody::printBodyAndItsSatellites(i=2) "solarSystemSrc/heavenlyBody.cxx":62
>2 0x120004254 in ((HeavenlyBody*)0x140002000)->HeavenlyBody::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)->Planet::print(i=2) "solarSystemSrc/planet.cxx":19
#1 0x12000422c in ((HeavenlyBody*)0x140002860)->HeavenlyBody::printBodyAndItsSatellites(i=2) "solarSystemSrc/heavenlyBody.cxx":62
#2 0x120004254 in ((HeavenlyBody*)0x140002000)->HeavenlyBody::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
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).
8.3.2 The
pop command
The pop command removes one or more call frames from the call
stack:
The default is one call frame. The pop_stack_frame_command
: 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.
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 command, you may want to use the
return command, which finishes the
call corresponding to the selected frame.
8.3.3 Call Frames and Optimized Code
When optimized machine code is generated by the compilers, the compiler
generates code that maintains the call stack,
but sometimes the function boundaries are changed in one of two ways:
8.3.4 Call Frames and Machine Code Correlation
On a RISC processor, such as an Alpha processor, the following is the
machine code typically generated for a call to a function:
When the thread is part way through the call frame creation or tear down, the
debugger will still show the call frame, but will not be able to show correct
values for the variables or parameters.
8.3.5 Special C++ Issues
For nonstatic member functions, the implicit this pointer is
displayed as the address on the stack trace along with the class type of
the object, as shown in the following example:
(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>*)0x11ffff288)->List<Node>::print() "x_list.cxx":162
#1 0x1200026fc in main() "x_list.cxx":200
8.4 Looking at the Data
After you have seen the call stack
(show_stack_command), selected the call
frame containing the variables you wish to examine
(change_stack_frame_command),
and looked at the source this function is executing
(looking at the source)
, you usually want to examine some of the
variables or even evaluate some expressions.
You can use the print command and the
call command to do this. You can also
use the following commands to help you determine what to look at and what you are
seeing:
look_around_command
: various_print_command
| c++_look_around_command
| call_command
| whatis_command
| whereis_command
| which_command
various_print_command
: print_command
| printf_command
| print_registers_command
| dump_command
8.4.1 The print Command
You can print the values of one or more expressions or all local variables. You can also use the
print
command to evaluate complex expressions involving typecasts, pointer
dereferences, multiple variables, constants, and any legal operators allowed by
the language of the program you are debugging:
For an array, the debugger prints every cell in the array if you do not specify
a specific cell.
print_command
: $hexints, $decints, or
$octints variables to
select a radix for the output of the print command.
Correspondingly,
if you do not want to change the radix permanently, use
the printx, printd, or
printo commands to
change the display radix temporarily.
The following example uses the (ladebug) list 59: 2
59 const unsigned int biggestCount = 10;
60 static Moon *biggestMoons[biggestCount];
print command to display a
nonstring array:
The following example shows how to print individual values of an array:
(ladebug) print biggestMoons
[0] = 0x140002bc0,[1] = 0x140002f20,[2] = 0x140002c20,[3] = 0x140002b00,[4] = 0x140002920,[5] = 0x140002b60,[6] = 0x1400032e0,[7] = 0x1400031c0,[8] = 0x140002ec0,[9] = 0x140003220
(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
}
8.4.1.1 Dereferencing Pointers
Pointers are variables that contain addresses. By dereferencing
a pointer in the command interface, you can print the value at the address
pointed to by
the pointer. In C and C++ programs, variables containing a pointer are dereferenced
using the * operator. The following example shows how to dereference a pointer
in C++ programs:
(ladebug) whatis newNode
class IntNode* newNode
(ladebug) print newNode
0x140001800
(ladebug) print *newNode
class IntNode {
_data = 1;
_nextNode = 0x0; // class Node
}
8.4.1.2 Printing C Strings
The debugger does not print more than the first
$maxstrlen characters
of a null-terminated string. Change this debugger variable if it is
showing either more or less than you wish to see.
8.4.1.3 Restrictions on the print Command
Expressions containing labels are not supported. Variables involving static
anonymous unions and enumerated types may not be able to be printed. Printing
a structure that is declared but not defined in a compilation unit may generate
an error message indicating that the structure is opaque.
8.4.2 The printf Command
Use the printf command to format and display a complex
structure. The first argument is a string expression of characters and
conversion specifications using the same format specifiers as the
printf C function.
For example:
printf_command
: (ladebug) printf "The PC is 0x%x", $pc
The PC is 0x120002700
8.4.3 The printregs Command
Use the printregs command to
display
the values of all the hardware registers. The list of registers displayed by the debugger is
machine-dependent. By default, most values are displayed in decimal radix. To display the
register values in hexidecimal radix, set the $hexints variable
to 1.
For example:
print_registers_command
: (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] = 342189472
$r10 [$s1] = 0 $r11 [$s2] = 4096
$r12 [$s3] = 351003456 $r13 [$s4] = 4096
$r14 [$s5] = 340581568 $r15 [$s6] = 1
$r16 [$a0] = 4395931657104 $r17 [$a1] = 4395931692608
$r18 [$a2] = 43 $r19 [$a3] = 0
$r20 [$a4] = 0 $r21 [$a5] = 3162
$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] = 4831834704 $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 = 1.513228014981478e-315
$f12 = 0.1 $f13 = 0
$f14 = 2.035550460865936e-320 $f15 = 3.00513504203182e-315
$f16 = 10.1230001449585 $f17 = 10.1230001449585
$f18 = 10.1230001449585 $f19 = 10.1230001449585
$f20 = 1.722711809292915e-315 $f21 = 1.513228014981478e-315
$f22 = 1.722711809292915e-315 $f23 = 1.667281912556707e-315
$f24 = 1.722711809292915e-315 $f25 = 1.513099478863056e-315
$f26 = 1.722714576060532e-315 $f27 = 1.513249931733528e-315
$f28 = 1.703843086550973e-315 $f29 = 0
$f30 = 1.722714576060532e-315 $f31 = 0
$pc = 0x120002700 $ps = 0x8
$fpcr = 0x800000000000000 $vfp = 0x11ffff2f0
8.4.4 The dump Command
Use the dump command without an argument to list the parameters and
local variables in the current function. To list the parameters and local
variables in an active function, specify it as an argument.
dump . command (include the dot) to list the parameters and
local variables for all functions active on the stack.
For example:
dump_command
: (ladebug) dump
>0 0x120002700 in main() "x_list.cxx":200
nodeList=class List<Node>{ ... }
newNode=0x140001800
cNode=0x140002000
newNode2=0x140001840
cNode2=0x140002030
where, up,
down, and dump commands 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.
8.4.5 The call Command
After a breakpoint or a signal suspends program execution, you can execute a
single function in your program by using the call command, or by
including a function call in the expression argument of a debugger command.
Calling a function lets you test the function's operation with a specific set
of parameters.
Specify the function as if you were calling it from within the program. If the
function has no parameters, specify empty parentheses.
For multithreaded applications, the call is made in the context of the current
thread. For C++ applications, when you set the
call_command
: $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.
call command executes the specified function with the parameters
you supply and then returns control to you (at the Ladebug prompt) when the
function returns. The call command discards the return value of the
function. If you embed the function call in the expression argument of a
print command, the debugger prints the return value after the
function returns. The following example shows both methods of calling a function:
In the previous example, the (ladebug) call earth->distance()
(ladebug) print earth->distance()
149600
call command results in the return value being
discarded while the embedded call passes the return value of the function to
the print command, which in turn prints the value. You can also
embed the call within a more involved expression, as shown in the following
example:
All breakpoints or tracepoints defined and enabled during the session are
active when
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.
(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
Restrictions on the call Command
(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);
int
if the functions are optimized. If the returns are a different type, it may
be necessary to cast the result when calling the optimized functions.
8.4.6 The whatis Command
You can print information about the basic nature of a
whatis_expression.
The expression can be a normal language expression or the name of a type, function,
or other language entity. The debugger shows you information about the
entity rather than evaluating it. However, it will evaluate any contained expressions,
such as pointers, needed to determine the entity to which you are referring.
The following example uses the whatis_command
: whatis command to determine the
storage representation for the data member _classification:
(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
8.4.7 The whereis Command
The whereis command lists all declarations of a variable and
each declaration's fully qualified scope information.
The whereis_command
: 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:
(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) ]
8.4.8 The which Command
Use the which command to determine which declaration an identifier
resolves to. The which command shows the fully qualified scope
information for the instance of the specified expression in the current scope.
The following example shows how to use the which_command
: whereis and
which
commands to determine a variable's scope:
(ladebug) where 4
>0 0x1200047dc in ((Planet*)0x140002860)->Planet::print(i=2) "solarSystemSrc/planet.cxx":19
#1 0x12000422c in ((HeavenlyBody*)0x140002860)->HeavenlyBody::printBodyAndItsSatellites(i=2) "solarSystemSrc/heavenlyBody.cxx":62
#2 0x120004254 in ((HeavenlyBody*)0x140002000)->HeavenlyBody::printBodyAndItsSatellites(i=1) "solarSystemSrc/heavenlyBody.cxx":68
#3 0x120004110 in main() "solarSystemSrc/main/solarSystem.cxx":120
(ladebug) which i
"solarSystemSrc/planet.cxx"`Planet::print(unsigned int)`i
(ladebug) assign i = 10
(ladebug) print i
10
(ladebug) whereis i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::satelliteNumber(class HeavenlyBody*)`i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::printBodyAndItsSatellites(unsigned int)`i
"solarSystemSrc/heavenlyBody.cxx"`HeavenlyBody::printBodyAndItsSatellites(unsigned int)`i
"solarSystemSrc/star.cxx"`Star::print(unsigned int)`i
"solarSystemSrc/planet.cxx"`Planet::print(unsigned int)`i
"solarSystemSrc/planet.cxx"`Moon::print(unsigned int)`i
"solarSystemSrc/derived_class_includes/planet.h"`Planet::print(unsigned int)`i
"solarSystemSrc/base_class_includes/heavenlyBody.h"`HeavenlyBody::print(unsigned int)`i
"solarSystemSrc/base_class_includes/heavenlyBody.h"`HeavenlyBody::printBodyAndItsSatellites(unsigned int)`i
"solarSystemSrc/main/solarSystem.cxx"`printBiggestMoons`i
"solarSystemSrc/main/solarSystem.cxx"`trackBiggestMoons(class Moon*)`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(unsigned int)`i
(ladebug) print i
2
8.4.9 Notes on C++ Debugging
The following sections describe the debugger commands specific to debugging C++
programs.
8.4.9.1 Setting the Class Scope Using the class Command
The debugger maintains the concept of a current context in which to perform
lookup of program variable names. The current context includes a file scope
and either a function scope or a class scope. The debugger automatically
updates the current context when program execution suspends.
class command lets you set the scope to a class in the program
you are debugging:
If c++_look_around_command
: class_name is not specified, the class command displays the
current class context.
func 0.
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.
class command to set the
class scope to List in order to make member function append visible
so a breakpoint can be set in append:
(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) ]
8.4.9.2 Displaying Class Information
The whatis and print commands display
information on a class.
Use the whatis command to display static information about the classes.
Use the print command to view dynamic information about class objects.
whatis command displays the class type declaration, including the
following:
print command lets you display the value of data members and
static members. Information regarding the public, private, or protected status
of class members is not provided, because the debugger relaxes the related
access rules to be more helpful to users.
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
8.4.9.3 Displaying Object Information
The whatis and print commands display information on
instances of classes (objects). Use the whatis command to display the
class type of an object. Use the print command to display the current
value of an object.
print command.
whatis and
print
commands to display object information:
(ladebug) whatis this
const class CompoundNode* const this
(ladebug) whatis *this
const class CompoundNode
(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
8.4.9.4 Displaying Static and Dynamic Type Information
When displaying object information for C++ class pointers or references, you
have the option of viewing either static type information or
dynamic type information.
$usedynamictypes, which allows
you to control which form of the type information is displayed. The
default value for this variable is true (1), which indicates that the dynamic
type information is displayed. Setting this variable to false (0)
instructs the debugger to display static type information. The output of the
print, trace, tracei, and
whatis commands are affected.
$usedynamictypes
set to 0 (false):
The following example displays debugger output with (ladebug) print $usedynamictypes
0
(ladebug) print *this
class HeavenlyBody {
_name = 0x120002088="Moon";
_innerNeighbor = 0x0;
_outerNeighbor = 0x0;
_firstSatellite = 0x0;
_lastSatellite = 0x0;
}
$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
}
8.4.9.5 Displaying Virtual and Inherited Class Information
When you use the print command to display information on an instance
of a derived class, the debugger displays both the new class members as well as the
members inherited from a base class. Pointers to members of a class are not supported.
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.
If two members in an object have the same name but different base
class types (multiple inheritance), you can refer to the members using the following syntax:
(ladebug) where 3
>0 0x12000224c in ((Node*)0x140002000)->Node::Node() "x_list.cxx":77
#1 0x120002298 in ((IntNode*)0x140002000)->IntNode::IntNode(data=2) "x_list.cxx":88
#2 0x120002338 in ((CompoundNode*)0x140002000)->CompoundNode::CompoundNode(fdata=12.34500026702881, idata=2) "x_list.cxx":101
(ladebug) whatis *this
class Node {
Node(void);
virtual void printNodeData(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::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::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
}
or
object.class::member
This syntax is more effective than using the object->class::member
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.
(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
Evaluating 'jupiter->_name' failed!
The value (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
}) does not have a field named '_name'!
(ladebug) print jupiter->HeavenlyBody::_name
Evaluating 'jupiter->HeavenlyBody::_name' failed!
The value (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
}) does not have a field named 'HeavenlyBody::_name'!
(ladebug) print jupiter->Orbit::_name
Evaluating 'jupiter->Orbit::_name' failed!
The value (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
}) does not have a field named 'Orbit::_name'!
8.4.9.6 Member Functions on the Stack Trace
The implicit this pointer, which is a part of all nonstatic member functions,
is displayed as the address on the stack trace. The class type of the object
is also given.
Trying to examine an inlined member function that is not called results in the
following error:
Name is overloaded.
The debugger will report this error regardless of the setting of the Member function has been inlined.
-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.)
-g flag, a breakpoint set on an inlined member function may confuse the debugger.
8.4.9.7 Resolving Ambiguous References to Overloaded Functions
In most cases, the debugger works with one specific function at a time. In the
case of overloaded function names, you must specify the desired overloaded
function. Following are two ways to resolve references to overloaded function names,
both under the control of the
$overloadmenu debugger variable (the
default setting of this debugger variable is 1):
$overloadmenu
variable is set to 1 (the default), whenever you specify a function name that
is overloaded,
a menu appears 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 from
----------------------------------------------------
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*) ]
$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.
foo(double *), as foo 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;}
8.4.9.8 Advanced Program Information —Verbose Mode
By default, the debugger gives no information on virtual base class pointers for the following:
By setting the $verbose debugger variable to 1, you can request that this
information be printed in subsequent debugger responses. When the $verbose debugger variable is set to 1
and you display the contents of a class using the
whatis command, several of the class members listed
are not in the source code of the original class definition. The following line shows specific output from the
whatis command for one of the additional members:
The (ladebug) whatis CompoundNode::__vptr
(array [subrange 0 ... 0 of int] of union {
void <member function>(void)* fptr;
int ioffset;
})* CompoundNode::__vptr
__vptr variable contains the addresses of all virtual functions associated
with the class. The compiler generates several other class members for internal use.
$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.
$verbose variable is set to 1, the output of the
dump command includes not only standard program variables but also compiler-generated temporary variables.
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 union {
void <member function>(void)* fptr;
int ioffset;
})* __vptr;
CompoundNode(class CompoundNode*, float, int);
virtual void printNodeData(const class CompoundNode*);
float _fdata;
}
8.5 Looking at the Generated Code
8.5.1 Memory Display Command - (
The debugger gives you a way to read and write arbitrary memory locations
in your program:
/)
The 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
machinecode_level_command
: address_expression. If the 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.
If mode is not specified, the mode used in the previous 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 instructions
/
command is assumed. If no previous /
command exists, X is assumed.
8.5.2 Machine-Level Debugging
The debugger lets you debug your programs at the machine-code level as well as at the
source-code level. Using debugger commands, you can examine and edit values in memory, print
the values of all machine registers, and step through program execution one machine instruction
at a time.
8.6 Looking at Shared Libraries
Use the shared_library_command
: listobj command to list all loaded objects,
including the main image and the shared libraries.
For each object, the information listed consists of the full
object name (with pathname) and the starting and ending
addresses for the .text, .data, and .bss sections.
readsharedobj command to read in the symbol table
information for the specified shared object. This object
must be a shared library or loadable kernel module.
You can use the command only when you specify the debuggee; that is, either
the debugger has been invoked with it, or
the debuggee was loaded by the load command.
delsharedobj command to remove the
symbol table information for the shared object from the debugger.
Chapter 9 - Modifying the Process
In addition to the normal side effects of evaluating expressions, including
calls, you can explicitly modify the memory of the current process and
also modify the actual loadable file (either executable file or shared
library) that has been mapped into memory:
The following sections discuss these commands.
modifying_command
: 9.1 The assign Command
Use the assign command to change the value associated with a variable,
memory address, or expression that is accessible according to the scope and visibility
rules of the language. The expression can be any expression that is valid in the
current context.
5 into the data
member _data of a C++ object:
The following example shows how to change the value associated with a variable
and the value associated with an expression:
(ladebug) print node->_data
2
(ladebug) assign node->_data = 5
(ladebug) print node->_data
5
For C++, use the (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 command to modify static and object data
members in a class, and variables declared as reference types, type const, or
type static. You cannot change the address referred to by a reference type, but
you can change the value at that address.
The assign Command in
Machine-Level Debugging
assign [classname::]member = ["filename"] `expression
assign [object.]member = ["filename"] `expression
assign command to alter the contents of memory
specified by an address. See Machine-Level Debugging for
more information.
(ladebug) print *(int *)(5368717328)
-32
(ladebug) assign *(int *)(5368717328) = 1024
(ladebug) print *(int *)(5368717328)
1024
9.2 The patch Command
Use the patch command to correct bad data or instructions in executable disk
files. You can patch the text, initialized data, or read-only data areas. You cannot patch
the bss segment, or stack and register locations,
because they do not exist on disk files.
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.
NOTE: When you use the (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)
patch command, the original binary
is not overwritten, but is saved with a tilde character (~) appended to the file name.
This allows you to revert to the original binary if necessary.
Chapter 10 - Continuing Execution of the Process
Before continuing the process, you should decide whether or not to make a
snapshot, in case you want to revert
to that snapshot state and try a different set of steps.
After creating the snapshot, use the following commands to continue executing the
program:
continue_command
: step_into_command
| step_over_command
| step_out_of_command
| cont_command
| cont_from_place_command
10.1 The step and stepi Commands
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.
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.
step_into_command
:
In the following example, two step commands
continue executing a C++ program:
The following example shows stepping by
instruction ((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 }
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)
10.2 The next and nexti Commands
Use the next command to execute a line of source code. When the next
line to be executed contains a function call, the next command executes
the function being called and stops the process at the line immediately after the function
call.
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 example:
step_over_command
:
The following example shows the difference between
(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);
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), Node::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), Node::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), Node::getNextNode
(ladebug) nexti
stopped at [void List<Node>::append(class Node* const):152 0x120001dcc] ldah gp, 8192(r26)
10.3 The return Command
Use the return command without an argument to continue execution of the
current function until it returns to its caller. If you include a function
name, execution continues until control is returned to the specified function.
The function must be active on the call stack.
In the following example, the step_out_of_command
: next command is
used to step through process execution in the
append method. The return command
finishes the append method and returns control to the caller.
(ladebug) next
stopped at [void List<Node>::append(class Node* const):153 0x120001dd8]
153 currentNode = currentNode->getNextNode();
(ladebug) return
stopped at [int main(void):192 0x1200025b0]
192 nodeList.append(new IntNode(3));
10.4 The cont Command
Use the cont command without a parameter value to resume process
execution until a breakpoint, a signal, an error, or normal process termination is
encountered. Specify a signal parameter value to send an operating system
signal to the process.
When you use the cont_command
: cont command, the debugger resumes execution of the
entire process.
cont command resumes process execution
after it was suspended by a breakpoint.
The signal parameter value can be either a signal number or a string name (for
example, SIGSEGV). The default is 0, which allows the process to continue
execution without specifying a signal. If you specify a signal parameter value,
the process continues execution with that signal.
(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);
in argument to continue until the named function is reached.
The function name must be valid. If the function name is overloaded and you do not
resolve the scope of
the function in the command line, the debugger prompts you with the list of
overloaded functions bearing that name from which to choose.
to parameter value 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 repeat the filename_string:line_number, which explicitly identifies both the source
file and the line number where execution is to be halted.
line_number, a positive numeric, which indicates the line number of
the current source file where execution is to be halted.
cont command
(n +1) times by entering
n cont.
conti to address_expression.
goto command is extremely dangerous
and can yield unpredictable results. Using this command is therefore not
recommended.
cont_from_place_command
: Chapter 11 - Using Snapshots as an Undo Mechanism
You can save the current state of the debuggee process in a snapshot, and later
revert to that state and try a different set of steps. Conceptually speaking,
this feature is similar to the undo function in text editors, except that with
snapshots you have control of the granularity of each undo. See the
Introduction for a quick overview.
The following sections discuss these commands and address the
limitations of snapshots.
snapshot_command
: save_snapshot_command
| clone_snapshot_command
| show_snapshot_command
| delete_snapshot_command
11.1 The save snapshot Command
Use the save snapshot command to save the state of the current process
in a snapshot. Snapshots are numbered sequentially starting from 1.
In the following example, the first line of the save_snapshot_command
: 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.
(ladebug) save snapshot
# 1 saved at 13:27:54 (PID: 29077).
stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
11.2 The clone snapshot Command
clone snapshot command to revert the state of the
debuggee process to that of a previously saved snapshot. By doing this,
you can conveniently return to the state saved in the snapshot as opposed
to rerunning the process and re-entering the debugger command sequence
that brought you to that state.
rerun and clone snapshot
are different in that
rerun always executes the process from the beginning, whereas
clone snapshot does not execute the process at all; it simply
duplicates the saved snapshot (using a mechanism similar to the fork system
call) and behaves as though the process execution has stopped at the point when the
snapshot was saved.
clone snapshot command clones the snapshot specified by
snapshot_id. If no snapshot_id is
specified, the most-recently saved existing snapshot is cloned.
clone_snapshot_command
:
show process after cloning a snapshot, you will see that
the process ID of the current process has changed to that of the cloned process.
For example:
(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.
11.3 The show snapshot Command
Use the show snapshot * and show snapshot all commands to
display all the snapshots that have been saved from the current process. Use
show snapshot snapshot_id_list to display the snapshots
specified. If no snapshots are specified, the most-recently saved existing
snapshot is displayed.
For example:
show_snapshot_command
: (ladebug) show snapshot all
# 1 saved at 13:27:54 (PID: 29077).
stopped at [int main(void):182 0x1200023f8]
182 List<Node> nodeList;
11.4 The delete snapshot Command
Use the delete snapshot * and delete snapshot all commands to
delete all the snapshots that have been saved from the current process. Use
delete snapshot snapshot_id_list to delete the specified
snapshots. If no snapshots are specified, the most-recently saved existing
snapshot is deleted.
For example:
delete_snapshot_command
: (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.
11.5 Snapshot limitations
Snapshots have the following limitations:
save snapshot command saves the state of the
current process only. If you are doing multiprocess debugging, you might want
to save a snapshot for each process.
Chapter 12 - Debugging Optimized Code (Linux Features)
You can debug optimized code under the Tru64 UNIX operating system.
12.1 Why Debug Optimized Code?
Highly optimizing compilers, such as those supplied by Compaq, generally
transform a program in many ways to make your program run as quickly
as possible. Expressions may be combined, rearranged or even
eliminated if it is determined they are not needed; expressions and even
complete statements may be moved out of loops; the order of statements
may be changed; calls to functions may be replaced with a copy of the
called function (inlining), the instructions for a single statement
may be interspersed with instructions for other statements both before
and after, and so on. All of these transformations greatly complicate
the ability of a debugger to display information about the state and
progress of your program or to control its execution. Compaq
compilers and the debugger try to avoid presenting erroneous, misleading, or
incomplete information when debugging optimized code, but this not
always possible. For these reasons, it is almost always easier to
debug an unoptimized version of your program.
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.
12.2 Program Preparation
For Compaq compilers, preparing a program for debugging with
optimization involves compiling that program using the -g3 option.
All other preparation is unchanged.
-g3 option differs from the -g option in
that it does not affect the optimization level. That is, -g
(equivalent to -g2)
sets the optimization level to zero (that is, -O0), even overriding
an explicit optimization setting; -g3 leaves the optimization
level unchanged. See the reference pages for the respective compilers for further
details.
12.3 Split Lifetime Variables
A variable is said to have split lifetimes if the set of fetches and
stores of the variable can be partitioned such that none of the values
stored in one subset are ever fetched in another subset. When such a
partition exists, the variable can be split into several independent
child variables, each corresponding to a partition. As independent
variables, the child variables can be allocated independently. The
effect is that the original variable can be thought to reside in
different locations at different points in time--sometimes in a
register, sometimes in memory, and sometimes nowhere at all. Indeed,
it is even possible for the multiple child variables to be active
simultaneously.
(ladebug) print L
Info: symbol L is defined but not allocated (optimized away)
Error: no value for symbol L
When a variable has a value, there may also be information concerning
where that variable was assigned:
(ladebug) print L
Symbol "L" is not defined.
The value may be assigned from several places:
(ladebug) print j
2
Value assigned at line 5
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.
(ladebug) print k
3
Value assigned at one of these lines: 6, 11
12.4 Semantic Stepping
A major problem with stepping through optimized code by line using the
next and
step commands
is that the apparent source program location
"bounces" forward and back, forward and back, with the same line often
appearing again and again. In large part this bouncing is due to a
compiler optimization called code scheduling, in which instructions
that arise from the same source line are scheduled, that is, reordered
and intermixed with other instructions, for better execution
performance. For example, in sample programs from a prominent
benchmark suite, the average number of instructions in sequence that
share the same line number is typically between 2 and 3and typically
50 to 70 percent of those sequences consist of just 1 instruction.
The visible effect of this support is that the step and
next
commands generally make normal progress through your
program. The effects of optimization cannot be hidden entirely,
however; there will be some occasional stepping backward as well as
forward due to code reordering, and some lines/statements will not
appear because they were optimized away, but the result will be
generally more usable.
12.5 Discontiguous Scopes
In addition to the blurring of line number boundaries as described in
the discussion of semantic stepping, a similar blurring occurs at the
beginning and end of an inner scope boundary. That is, one
instruction may be related to the beginning of a new scope (and line)
in which a new variable is declared and becomes visible, while the next
instruction may revert to a source location (line) before the scope
begins.
12.6 General Cautions
When debugging optimized code, some Ladebug commands
should be used with caution or even avoided completely.
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, resulting in
one frame instead of the two (or more) that might be
expected. You can use these commands, but be careful
to make sure that you end up in the frame you intend
after each use and do not be misled.
next, nexti
For a call that is inlined, the
next
and nexti
commands will appear to step into the called function
instead of stepping over it.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.
Chapter 13 - Limitations
This chapter contains sections which describe the
limitations on support for the following languages:
13.1 Limitations on Support for Compaq C++
The debugger interprets C++ names and expressions using the language rules described
in The Annotated C++ Reference Manual (Ellis and Stroustrup, 1990,
Addison-Wesley). C++ is a distinct language, rather than a superset of C. Where
the semantics of C and C++ differ, the debugger provides the interpretation
appropriate for the language of the program being debugged.
-g flag, do not set a
breakpoint on an inline member function; it may confuse the debugger.
new and
delete. As alternatives, use the
malloc() and
free()
routines from C.
13.2 Limitations on Support for Compaq Fortran
The debugger and the Tru64 UNIX operating system support the Compaq Fortran language
with certain limitations, which are described in the following sections.
13.2.1 Limitations on Procedure Invocations
Following are the limitations on Compaq Fortran procedure invocations:
as described in the Compaq Fortran Language Reference Manual
section that discusses categories of intrinsic functions.
13.3 Limitations on Support for Compaq Ada
The debugger and the Tru64 UNIX operating system support the Compaq Ada language with
certain limitations, which are described in the following sections.
13.3.1 Limitations on Expressions
Expressions in Ladebug commands use C source language syntax for operators and
expressions. Data is printed as the equivalent C data type.
The following table shows Ada expressions and Ladebug equivalents.