The dbx debugger is a tool for source level debugging. The debugger can be used with C, Fortran, Pascal, assembly language, and machine code. After invoking dbx, you can issue dbx commands that control and trace execution, display variable and expression values, and display and edit source files. The dbx debugger is a command-line program.
The ladebug debugger, an alternate debugger, provides both command-line and graphical user interfaces. In addition to supporting some languages that are not supported by dbx, the ladebug debugger also supports features for debugging multithreaded programs. For more information about ladebug, see the Ladebug Debugger Manual.
This chapter provides information on the following topics:
Examples in this chapter refer to a sample program called sam. The C language source program (sam.c) is listed in Example 5-1.
In addition to the conventions outlined in the preface of this manual, an additional convention is used in the command descriptions in this chapter; certain words in uppercase indicate variables for which specific rules apply. These words are described in Table 5-1.
Keyword | Value |
ADDRESS | Any expression specifying a machine address. |
COMMAND_LIST | One or more commands, each separated by semicolons. |
DIR | Directory name. |
EXP | Any expression including program variable names for the command. Expressions can contain dbx variables, for example, ($listwindow + 2). If you want to use the variable names in, to, or at in an expression, you must surround them with parentheses; otherwise, dbx assumes that these words are debugger keywords. |
FILE | File name. |
INT | Integer value. |
LINE | Source code line number. |
NAME | Name of a dbx command. |
PROCEDURE | Procedure name or an activation level on the stack. |
REGEXP | Regular expression string. See ed(1). |
SIGNAL | System signal. See signal(2). |
STRING | Any ASCII string. |
VAR | Valid program variable or dbx predefined variable (see Table 5-9). For machine-level debugging, VAR can also be an address. You must qualify program variables with duplicate names as described in Section 5.3.2. |
The following example illustrates the use of the uppercase words in
commands:
(dbx)
stop VAR in PROCEDURE if EXP
Enter stop, in, and if as shown. Enter the values for VAR, PROCEDURE, and EXP as defined in Table 5-1.
Note
Information on debugging multiple asynchronous processes, including extensions to the syntax of certain dbx commands to provide control of the asynchronous session, is contained in Section 5.12.
The following sections introduce the debugger and some debugging concepts. They also give suggestions about how to approach a debugging session, including where to start, how to isolate errors, and how to avoid common pitfalls. If you are an experienced programmer, you might not need to read these sections.
The dbx debugger enables you to trace problems in a program object at the source code level or at the machine code level. With dbx, you control a program's execution, monitoring program control flow, variables, and memory locations. You can also use dbx to trace the logic and flow of control to become familiar with a program written by someone else.
Activation levels define the currently active scopes (usually
procedures) on the stack. An activation stack is a list of calls that
starts with the initial program, usually
main().
The most recently called procedure or block is number 0. The next
procedure called is number 1. The last activation level is always the
main procedure (the procedure that controls the whole program).
Activation levels can also consist of blocks that define local
variables within procedures. You see activation levels in stack traces
(see the
where
and
tstack
debugger commands) and when moving around the activation stack (see the
up,
down,
and
func
debugger commands). The following example shows a stack trace produced
by a
where
command:
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04] [1] 1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac] [2] | | | | | | [3][4] [5] [6] [7] [8]
Because the dbx debugger finds only run-time errors, you should fix compiler errors before starting a debugging session. Run-time errors can cause a program to fail during execution (resulting in the creation of a core dump file) or to produce incorrect results. The approach for debugging a program that fails during execution differs from the approach for debugging a program that executes to completion but produces incorrect results. (See Section 5.1.4 for information on how to debug programs that produce incorrect results.)
If a program fails during execution, you can usually save time by using the following approach to start a debugging session instead of blindly debugging line by line:
Note
If you have not stripped symbol table information from the object file, you can get a stack trace even if the program was not compiled with the -g debug flag.
If you still cannot find the error, other dbx commands described in this chapter might be useful.
If a program executes to completion but produces incorrect values or output, take the following steps:
The debugger cannot solve all problems. For example, if your program's logic is incorrect, the debugger can only help you find the problem, not solve it. When information displayed by the debugger appears confusing or incorrect, taking the following actions might correct the situation:
Similarly, dbx will not reflect changes you make if you edit and recompile your program in one window on a workstation while running the debugger in another window. You must stop and restart dbx each time you want it to recognize changes you have made.
(dbx)
print (output)
Before invoking dbx, you need to compile the program for debugging. You might also want to create a dbx initialization file that will execute commands when the debugger is started.
To use the debugger, specify the -g flag at compilation time. With this flag set, the compiler inserts into the program symbol table information that the debugger uses to locate variables. With the -g flag set, the compiler also sets its optimization level to -O0. When you use different levels of optimizing, for example -O2, the optimizer does not alter the flow of control within a program, but it might move operations around so that the object code and source code do not correspond. These changed sequences of code can create confusion when you use the debugger.
You can do limited debugging on code compiled without the -g flag. For example, the following commands work properly without recompiling for debugging:
Although you can do limited debugging, it is usually more useful to recompile the program with -g. Note that the debugger does not warn you if an object file was compiled without the -g flag.
Complete symbol table information is available only for programs in which all modules have been compiled with the -g flag. Other programs will have symbol table information only for symbols that are either referenced by or defined in modules compiled with the -g flag.
Note
Any routines in shared library applications in which breakpoints are to be set must be compiled with the -g flag. If the -g flag is not specified, the symbol table information that dbx needs to set breakpoints is not generated and dbx will not be able to stop the application.
You can create a
dbx
initialization file that contains commands you normally issue at
the beginning of each
dbx
session. For example, the file could contain the following commands:
set $page = 5 set $lines = 20 set $prompt = "DBX> " alias du dump
The initialization file must have the name .dbxinit. Each time you invoke the debugger, dbx executes the commands in .dbxinit. The debugger looks first for .dbxinit in the current directory and then in your home directory (the directory assigned to the $HOME environment variable).
You invoke dbx from the shell command line by entering dbx and the optional parameters.
After invocation, dbx sets the current function to the first procedure of the program.
The dbx command has the following syntax:
dbx [ flags ] [ objfile [ corefile ] ]
The maximum number of arguments accepted by dbx is 1000; however, system limits on your machine might reduce this number.
Flag | Function |
-cfilename | Selects an initialization command file other than your .dbxinit file. |
-Idirname | Tells dbx to look in the specified directory for source files. To specify multiple directories, use a separate -I for each. Unless you specify this flag when you invoke dbx, the debugger looks for source files in the current directory and in the object file's directory. You can change directories with the use command (see Section 4.6.1). |
-i | Invokes dbx in interactive mode. With this flag set, dbx does not treat source lines beginning with number signs (#) as comments. |
-k | Maps memory addresses. This flag is useful for kernel debugging. (For information on kernel debugging, see krash(8) and the manual Kernel Debugging.) |
-pid process-id | Attaches dbx to a currently running process. |
-r | Immediately executes the object file that you specify on the command line. If program execution terminates with an error, dbx displays the message that describes the error. You can then either invoke the debugger or allow the program to continue exiting. The dbx debugger reads from /dev/tty when you specify the -r flag and standard input is not a terminal. If the program executes successfully, dbx prompts you for input. |
The following example invokes
dbx
with no flags. Because an object file name is not specified,
dbx
prompts for one. In this case, the user responds with
sam.
The default debugger prompt is
(dbx).
%
dbx
enter object file name (default is 'a.out'):
sam
dbx version 3.12 Type 'help' for help.
main: 23 if (argc < 2) { (dbx)
Use the quit or q command to end a debugging session. The quit command accepts no arguments.
You can enter up to 10,240 characters on an input line. Long lines can be continued with a backslash (\). If a line exceeds 10,240 characters, dbx displays an error message. The maximum string length is also 10,240.
The following sections describe scoping and the use of qualified variable names, dbx expressions and precedence, and dbx data types and constants.
Variables in
dbx
are qualified by file, procedure, block, or structure.
When using commands like
print
to display a variable's value,
dbx
indicates the scope of the variable when the scope could
be ambiguous (for example, you have a variable
by the same name in two or more procedures). If the scope
is wrong, you can specify the full scope of the variable by
separating scopes with periods. For example:
sam.main.i | | | [1][2] [3]
The dbx debugger recognizes expression operators from C; these operators can also be used for debugging any other supported language. (Note that dbx uses brackets ([ ]) for array subscripts even in Fortran, whose natural subscript delimiters are parentheses.) In addition to the standard C operators, dbx uses the number sign (#) as shown in Table 5-3.
Syntax | Description |
("FILE" #EXP) | Uses the line number specified by #EXP in the file named by FILE. |
(PROCEDURE #EXP) | Uses the relative line number specified by #EXP in the procedure named by PROCEDURE. |
(#EXP) | Returns the address for the line specified by (#EXP). |
Operators follow the C language precedence. Table 5-4 shows the language operators recognized by dbx in order of precedence from top to bottom and from left to right, with the dbx-specific number-sign operator included among the unary operators to show its place in the precedence hierarchy.
Unary: |
&,
+,
-,
*
(pointer),
#,
sizeof() |
Binary: |
<<,
>>,
",
!,
==,
!=,
<=,
>=,
<,
>,
&,
&&,
|,
||,
+,
-,
*,
/ |
Table Notes:
Table 5-5 lists the built-in data types that dbx commands can use.
Data Type | Description | Data Type | Description | |
$address | Pointer | $real | Double precision real | |
$boolean | Boolean | $short | 16-bit integer | |
$char | Character | $signed | Signed integer | |
$double | Double precision real | $uchar | Unsigned character | |
$float | Single precision real | $unsigned | Unsigned integer | |
$integer | Signed integer | $void | Empty |
You can use the built-in data types for type coercion -- for example, to display the value of a variable in a type other than the type specified in the variable's declaration. The dbx debugger understands C language data types, so that you can refer to data types without the $. The types of constants that are acceptable as input to dbx are shown in Table 5-6. Constants that are output from dbx are displayed by default as decimal values.
Constant | Description |
false | 0 |
true | Nonzero |
nil | 0 |
0xnumber | Hexadecimal |
0tnumber | Decimal |
0number | Octal |
number | Decimal |
number.[number][e|E][+|-]EXP | Float |
Notes:
The dbx debugger provides a command history, command-line editing, and symbol name completion. The dbx debugger also allows multiple commands on an input line. These features can reduce the amount of input required or allow you to repeat previously executed commands.
The debugger keeps a command history that allows you to repeat debugger commands without retyping them. You can display these commands by using the history command. The $lines variable controls the number of history lines saved. The default is 20 commands. You can use the set command to modify the $lines variable (see Section 5.5.1).
To repeat a command, use the Return key or one of the exclamation point
(!)
commands.
The history command has the following forms:
The following example displays the history list and then repeats
execution of the twelfth command in the list:
(dbx)
history
10 print x 11 print y 12 print z(dbx) !12
(!12 = print z) 123 (dbx)
The
dbx
debugger provides support for command line editing. You can edit a
command line to correct mistakes without reentering the entire command.
To enable command-line editing, set the
EDITOR,
EDITMODE,
or
LINEEDIT
environment variable before you invoke
dbx.
For example, to set
LINEEDIT
from the C shell, you would enter the following command:
%
setenv LINEEDIT
From the Bourne or Korn shells, you would enter this command:
$
export LINEEDIT
The debugger offers the following modes of command line editing:
$ + - 0 A B C D E F I R S W X ^ a b c d e f h i j k l r s w x ~ Ctrl/D Ctrl/H Ctrl/J Ctrl/L Ctrl/M Ctrl/V
See ksh(1) for more information.
Table 5-7
lists the
emacs-mode
command line editing commands.
Command | Function |
Ctrl/A | Moves the cursor to the beginning of the command line. |
Ctrl/B | Moves the cursor back one character. |
Ctrl/C | Clears the line. |
Ctrl/D | Deletes the character at the cursor. |
Ctrl/E | Moves the cursor to the end of the line. |
Ctrl/F | Moves the cursor ahead one character. |
Ctrl/H | Deletes the character immediately preceding the cursor. |
Ctrl/J | Executes the line. |
Ctrl/K | (When enabled by EDITOR or EDITMODE) Deletes from the cursor to the end of the line. If preceded by a numerical parameter whose value is less than the current cursor position, deletes from given position up to the cursor. If preceded by a numerical parameter whose value is greater than the current cursor position, deletes from cursor up to given position. |
Ctrl/K char | (When enabled by LINEEDIT) Deletes characters until the cursor rests on the next occurrence of char. |
Ctrl/L | Redisplays the current line. |
Ctrl/M | Executes the line. |
Ctrl/N | Moves to the next line in the history list. |
Ctrl/P | Moves to the previous line in the history list. |
Ctrl/R char | Searches back in the current line for the specified character. |
Ctrl/T | Interchanges the two characters immediately preceding the cursor. |
Ctrl/U | Repeats the next character four times. |
Ctrl/W | Deletes the entire line. |
Ctrl/Y | Inserts immediately before the cursor any text cut with Ctrl/K. |
Ctrl/Z | Tries to complete a file or symbol name. |
Escape | Tries to complete a file or symbol name. |
Down Arrow | Moves to the next line in the history list. |
Up Arrow | Moves to the previous line in the history list. |
Left Arrow | Moves the cursor back one character. |
Right Arrow | Moves the cursor ahead one character. |
You can enter multiple commands on the command line by using a semicolon (;) as a separator. This feature is useful when you are using the when command (see Section 5.8.4).
The following example has two commands on one command line; the first
command stops the program and the second command reruns it:
(dbx)
stop at 40; rerun
[2] stop at "sam.c":40 [2] stopped at [main:40 ,0x120000b40] i=strlen(line1.string); (dbx)
The dbx debugger provides symbol name completion. When you enter a partial symbol name and press Ctrl/Z, dbx attempts to complete the name. If a unique completion is found, dbx redisplays the input with the unique completion added; otherwise, all possible completions are shown, and you can choose one.
To enable symbol name completion, you must enable command line editing
as described in
Section 5.4.2.
The following example displays all names beginning with the
letter "i":
(dbx) i [Ctrl/Z]
The following example shows symbol name completion. In this case, the
entry supplied is unambiguous:
(dbx) print file [Ctrl/Z]
(dbx) print file_header_ptr 0x124ac (dbx)
The dbx debugger provides commands for setting and removing dbx variables, creating and removing aliases, invoking a subshell, checking and deleting items from the status list, displaying a list of object files associated with an application, and recording and playing back input.
The set command defines a dbx variable, sets an existing dbx variable to a different value, or displays a list of existing dbx predefined variables. The unset command removes a dbx variable. Use the print command to display the values of program and debugger variables. The dbx predefined variables are listed in Table 5-8. You cannot define a debugger variable with the same name as a program variable.
The set and unset commands have the following forms:
The following example illustrates the
set
and
unset
commands:
(dbx)
set [1]
$listwindow 10 $datacache 1 $main "main" $pagewindow 22 test 5 $page 1 $maxstrlen 128 $cursrcline 24more (n if no)? n
$listwindow 10 $datacache 1 $main "main" $pagewindow 22 test 12 $page 1 $maxstrlen 128 $cursrcline 24more (n if no)? n
$listwindow 10 $datacache 1 $main "main" $pagewindow 22 $page 1 $maxstrlen 128 $cursrcline 24more (n if no)? n
The predefined
dbx
variables are shown in
Table 5-8.
Each variable is labeled I for integer, B for boolean, or S for string.
Variables that you can examine but cannot modify are indicated by an R.
Type | Name | Default | Description |
S | $addrfmt | 0x%lx | Specifies the format for addresses. Can be set to anything you can format with a C language printf statement. |
B | $assignverify | 1 | Specifies whether new values are displayed when assigning a value to a variable. |
B | $asynch_interface | 0 | Controls whether dbx is, or can be, configured to control multiple asynchronous processes. Incremented by 1 when a process is attached; decremented by 1 when a process terminates or is detached. Can also be set by user. If 0 or negative, asynchronous debugging is disabled. |
B | $break_during_step | 0 | Controls whether breakpoints are checked while processing step/stepi, next/nexti, call, return, and so on. |
B | $casesense | 0 | Specifies whether source searching and variables are case sensitive. A nonzero value means case sensitive; a 0 means not case sensitive. |
I R | $curevent | 0 | Shows the last event number as reported by the status command. |
I R | $curline | 0 | Shows the current line in the source code. |
I R | $curpc | - | Shows the current address. Used with the wi and li aliases. |
I R | $cursrcline | 1 | Shows the last line listed plus 1. |
B | $datacache | 1 | Caches information from the data space so that dbx only has to check the data space once. If you are debugging the operating system, set this variable to 0; otherwise, set it to a nonzero value. |
S R | $defaultin | Null string | Shows the name of the file that dbx uses to store information when using the record input command. |
S R | $defaultout | Null string | Shows the name of the file that dbx uses to store information when using the record output command. |
B | $dispix | 0 | When set to 1, specifies display of only real instructions when debugging in pixie mode. |
B | $hexchars | Not defined | A nonzero value indicates that character values are shown in hexadecimal. |
B | $hexin | Not defined | A nonzero value indicates that input constants are hexadecimal. |
B | $hexints | Not defined | A nonzero value indicates that output constants are shown in hexadecimal; a nonzero value overrides octal. |
B | $hexstrings | Not defined | A nonzero value indicates that strings are displayed in hexadecimal; otherwise, strings are shown as characters. |
I R | $historyevent | None | Shows the current history number. |
I | $lines | 20 | Specifies the size of the dbx history list. |
I | $listwindow | $pagewindow/2 | Specifies the number of lines shown by the list command. |
S | $main | main | Specifies the name of the procedure where execution begins. The debugger starts the program at main() unless otherwise specified. |
I | $maxstrlen | 128 | Specifies the maximum number of characters in strings that dbx prints for pointers to strings. |
B | $octin | Not defined | Changes the default input constants to octal when set to a nonzero value. Hexadecimal overrides octal. |
B | $octints | Not defined | Changes the default output constants to octal when set to a nonzero value. Hexadecimal overrides octal. |
B | $page | 1 | Specifies whether to page long information. A nonzero value enables paging; a zero disables it. |
I | $pagewindow | Various | Specifies the number of lines displayed when viewing information that is longer than one screen. This variable should be set to the number of lines on the terminal. A value of 0 indicates a minimum of 1 line. The default value depends on the terminal type; for a standard video display, the default is 24. |
B | $pimode | 0 | Displays input when using the playback input command. |
I | $printdata | 0 | A nonzero value indicates that the values of registers are displayed when instructions are disassembled; otherwise, register values are not displayed. |
B | $printtargets | 1 | If set to 1, specifies that displayed disassembly listings are to include the labels of targets for jump instructions. If set to 0, disables this label display. |
B | $printwhilestep | 0 | For use with the step [n] and stepi [n] instructions. A nonzero value specifies that all n lines or instructions should be displayed. A zero value specifies that only the last line or instruction should be displayed. |
B | $printwide | 0 | Specifies wide (useful for structures or arrays) or vertical format for displaying variables. A nonzero value indicates wide format; zero indicates vertical format. |
S | $prompt | dbx) | Sets the prompt for dbx. |
B | $readtextfile | 1 | When set to a value of 1, dbx tries to read instructions from the object file instead of from the process. This variable should always be set to 0 when the process being debugged copies in code during the debugging process. However, performance is better when $readtextfile is set to 1. |
B | $regstyle | 1 | Specifies the type of register names to be used. A value of 1 specifies hardware names. A zero specifies software names as defined by the file regdefs.h. |
B | $repeatmode | 1 | Specifies whether dbx should repeat the last command when the Return key is pressed. A nonzero value indicates that the command is repeated; otherwise, it is not repeated. |
B | $rimode | 0 | Records input when using the record output command. |
S | $sigvec | sigaction | Tells dbx the name of the code called by the system to set signal handlers. |
S | $sigtramp | _sigtramp | Tells dbx the name of the code called by the system to invoke user signal handlers. |
B | $stop_all_forks | 0 | Specifies whether dbx should stop every child process that is forked (1), or ignore many of the forks generated by various system and library calls (0). If $stop_all_forks is not set, the value of $stop_on_fork determines dbx's behavior with forks. $stop_all_forks traps forks in libraries and system calls that are usually ignored by $stop_on_fork. |
B | $stop_in_main | N/A | Not used. This variable is displayed by the set command, but it presently has no effect on dbx operation. |
B | $stop_on_exec | 1 | Specifies whether dbx should detect calls to execl( ) and execv( ), and stop the newly activated images at the first line of executable code. |
B | $stop_on_fork | 1 | Specifies whether dbx should advance a new image activated by a fork( ) or vfork( ) call to its main activation point and then stop (1) or continue until stopped by a breakpoint or event (0). The dbx program tries to avoid stopping on forks from system or library calls unless $stop_all_forks is set. |
S | $tagfile | tags | Contains a file name indicating the file in which the tag command and the tagvalue macro are to search for tags. |
I | $traploops | 3 | Specifies the number of consecutive calls to a SIGTRAP handler that will be made before dbx assumes that the program has fallen into a trap-handling loop. |
The alias command defines a new alias or displays a list of all current aliases.
The alias command allows you to rename any debugger command. Enclose commands containing spaces within double or single quotation marks. You can also define a macro as part of an alias.
The dbx debugger has a group of predefined aliases. You can modify these aliases or add new aliases. You can also include aliases in your .dbxinit file for use in future debugging sessions. The unalias command removes an alias from a command. You must specify the alias to remove. The alias is removed only for the current debugging session.
The alias and unalias commands have the following forms:
The following example illustrates the
alias
and
unalias
commands:
(dbx)
alias [1]
h history si stepi Si nextiMore (n if no) ? n
.
.
.
g goto s step
[2] Stop at "sam.c":52 [4] (dbx)(dbx) unalias h [5]
si stepi Si nextiMore (n if no)? n
.
.
.
g goto s step
Use the status command to check which, if any, of the following commands are currently set:
The
status
command accepts no arguments. For example:
(dbx)
status
[2] trace i in main [3] stop in prnt [4] record output /tmp/dbxt0018898 (0 lines)(dbx)
The numbers in brackets (for example, [2]) indicate status item numbers.
To delete breakpoints and stop the recording of input and output, use the delete command. Deleting a breakpoint or stopping recording removes the pertinent items from the status list produced by the status command. To disable breakpoints without deleting them, use the disable command. The enable command reenables disabled events.
The delete command has the following forms:
The following example illustrates the use of the
delete
command:
(dbx)
status
[2] record output /tmp/dbxt0018898 (0 lines) [3] trace i in main [4] print pline at "sam.c": [5] stop in prnt(dbx) delete 4
[2] record output /tmp/dbxt0018898 (0 lines) [3] trace i in main [5] stop in prnt(dbx)
The disable and enable commands have the following forms:
The
listobj
command displays the names of all the object files that have
been loaded by
dbx,
together with their sizes and the address at which they were loaded.
These objects include the main program and all of the shared libraries
that are used in an application. The
listobj
command accepts no arguments. For example:
(dbx)
listobj
sam addr: 0x120000000 size: 0x2000 /usr/shlib/libc.so addr: 0x3ff80080000 size: 0xbc000(dbx)
To invoke an interactive subshell at the
dbx
prompt, enter
sh.
To return to
dbx
from a subshell, enter
exit
or press Ctrl/D. To invoke a subshell that performs a single command
and returns to
dbx,
enter
sh
and the desired shell command. For example:
(dbx)
sh
%
date
Tue Aug 9 17:25:15 EDT 1994
%
exit
.
.
.
(dbx)
sh date
Tue Aug 9 17:29:34 EDT 1994
(dbx)
The following sections describe how to list and edit source code, change directories, change source files, search for strings in source code, display qualified symbol names, and display type declarations.
If you did not specify the -I flag when invoking dbx, (see Section 5.2.3), the debugger looks for source files in the current directory or the object file's directory. The use command has two functions:
The command recognizes absolute and relative pathnames (for example, ./), but it does not recognize the C-shell tilde (~).
The use command has the following forms:
For example:
(dbx)
use
. [1]
(dbx)
use /usr/local/lib
(dbx)
use
/usr/local/lib [2]
(dbx)
As described in Section 5.1.2, the debugger maintains a stack of activation levels. To find the name or activation number for a specific procedure, get a stack trace with the where or tstack command. You can move through the activation stack by using the up, down, and func commands.
The where command displays a stack trace showing the current activation levels (active procedures) of the program being debugged. The tstack command displays a stack trace for all threads. See Section 5.11 for more information about debugging threads.
The where and tstack commands have the following form:
If EXP is specified, dbx displays only the top EXP levels of the stack; otherwise, the entire stack is displayed.
If a breakpoint is set in
prnt
in the sample program
sam.c,
the program runs and stops in the procedure
prnt().
If you enter
where,
the debugger's stack trace provides the information shown in the
following example:
(dbx)
stop in prnt
[1] stop in prnt
(dbx)
run
.
.
.
(dbx)
where 1
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04] | | | | | | [1][2] [3] [4] [5] [6](dbx)
The up and down commands move you directly up or down in the stack; they are useful when tracking a call from one level to another. The func command can move you up or down incrementally or to a specific activation level or procedure. The func command changes the current line, the current file, and the current procedure, thus changing the scope of the variables you can access. You can also use the func command to examine source code when a program is not executing.
The up, down, and func commands have the following forms:
The following example illustrates these commands:
(dbx)
where
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04] 1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac](dbx) up
0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04] > 1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac](dbx) down
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04] 1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac](dbx) func 1
The file command displays the current source file name or changes the current source file.
Note
Before setting a breakpoint or trace on a line number, use the func command to get the correct procedure. The file command cannot be specific enough for the debugger to access the information necessary to set a breakpoint.
The file command has the following forms:
For example:
(dbx)
file
sam.c [1]
(dbx)
file data.c
(dbx)
file
data.c [2]
(dbx)
The list command displays lines of source code. The dbx variable $listwindow defines the number of lines that dbx lists by default. The list command uses the current file, procedure, and line unless otherwise specified.
The
list
command has the following forms:
The following example specifies a 2-line list starting at line 49:
(dbx)
list 49:2
49 void prnt(pline) 50 LINETYPE *pline;
If you use the
list
command's predefined alias
w,
the output is as follows:
(dbx)
w
45 prnt(&line1); 46 } 47 } 48 49 void prnt(pline) > 50 LINETYPE *pline; 51 { * 52 fprintf(stdout,"%3d. (%3d) %s",pline->linenumber, 53 pline->length, pline->string); 54 fflush(stdout);
The right angle bracket in column 1 (>) indicates the current line, and the asterisk in column 2 (*) indicates the location of the program counter (pc) at this activation level.
The slash (/) and question mark (?) commands search for regular expressions in source code. The slash searches forward from the current line, and the question mark searches backward. Both commands wrap around at the end of the file if necessary, searching the entire file from the point of invocation back to the same point. By default, dbx does not distinguish uppercase letters from lowercase when searching. If you set the dbx variable $casesense to any nonzero value, the search is case sensitive.
The
/
and
?
commands have the following form:
(dbx)
/lines
no match
(dbx)
/line1
16 LINETYPE line1;
(dbx)
/
39 while(fgets(line1.string, sizeof(line1.string), fd) != NULL){ (dbx)
The edit command enables you to change source files from within dbx. To make the changes effective, you must quit from dbx, recompile the program, and restart dbx.
The edit command has the following forms:
The edit command loads the editor indicated by the environment variable EDITOR or, if EDITOR is not set, the vi editor. To return to dbx, exit normally from the editor.
The which and whereis commands display program variables. These commands are useful for debugging programs that have multiple variables with the same name occurring in different scopes. The commands follow the rules described in Section 5.3.1.
The which and whereis commands have the following forms:
In the following example, the user checks to see where the default
variable named
i
is and then verifies that this is the only instance of
i
in the program by observing that
whereis
shows only the one occurrence.
(dbx)
which i
sam.main.i
(dbx)
whereis i
sam.main.i
The whatis command lists the type declaration for variables and procedures in a program.
The
whatis
command has the following form:
For example:
(dbx)
whatis main
int main(argc,argv) int argc; unsigned char **argv;(dbx) whatis i
The following sections describe the dbx commands used to run a program, step through source code, return from a procedure call, start at a specified line, continue after stopping at a breakpoint, assign values to program variables, patch an executable disk file, execute a particular routine, set an environment variable, and load shared libraries.
The run and rerun commands start program execution. Each command accepts program arguments and passes those arguments to the program. If no arguments are specified for a run command, dbx runs the program with no arguments. If no arguments are specified for a rerun command, dbx defaults to the arguments used with the previous run or rerun command. You can specify arguments in advance of issuing a rerun command by using the args command. Arguments set by the args command are ignored by a subsequent run command.
You can also use these commands to redirect program input and output in a manner similar to redirection in the C shell:
Note
The redirected output differs from the output saved with the record output command (see Section 5.9.4.2), which saves debugger output, not program output.
The run, args, and rerun commands have the following forms:
For example:
(dbx) run sam.c [1]
0. (19)#include <stdio.h> 1. (14) struct line { 2. (19) char string[256];(dbx) rerun [2]
.
.
.
Program terminated normally
0. (19)#include <stdio.h> 1. (14) struct line { 2. (19) char string[256];(dbx)
.
.
.
Program terminated normally
For debugging programs written in high-level languages, the step and next commands execute a fixed number of source code lines as specified by EXP. For debugging programs written in assembly language, the stepi and nexti commands work the same as step and next except that they step by machine instructions instead of by program lines. If EXP is not specified, dbx executes one source code line or machine instruction; otherwise, dbx executes the source code lines or machine instructions as follows:
The step/stepi and next/nexti commands have the following forms:
For example:
(dbx)
rerun
[7] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",
(dbx)
step 2
0. ( 19) #include <stdio.h> [prnt:55 ,0x120000c48] }(dbx) step
The $break_during_step and $printwhilestep variables affect stepping. See Table 5-8 for more information.
The return command is used in a called procedure to execute the remaining instructions in the procedure and return to the calling procedure.
The return command has the following forms:
For example:
(dbx)
rerun
[7] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",
(dbx)
return
0. (19) #include <stdio.h> stopped at [main:45 +0xc,0x120000bb0] prnt(&line1); (dbx)
The
goto
command shifts to the specified line and continues execution. This
command is useful in a
when
statement -- for example, to skip a line known to cause problems. The
goto
command has the following form:
For example:
(dbx)
when at 40 {goto 43}
[8] start sam.c:43 at "sam.c":40 (dbx)
For debugging programs written in high-level languages, the cont command resumes program execution after a breakpoint. For debugging programs written in assembly language, the conti command works the same as cont. The cont and conti commands have the following forms:
The following example shows the
cont
command in a C program:
(dbx)
stop in prnt
[9] stop in prnt
(dbx)
rerun
[9] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",(dbx) cont
0. ( 19) #include <stdio.h> [9] stopped at [prnt:52,0x120000c04] fprintf(stdout,"%3d.(%3d) %s",(dbx)
The following example shows the
conti
command in an assembly-language program:
(dbx)
conti
0. ( 19) #include <stdio.h> [4] stopped at >*[prnt:52 ,0x120000c04] ldq r16,-32640(gp) (dbx)
The assign command changes the value of a program variable. The assign command has the following form:
For example:
(dbx)
print i
19 [1]
(dbx)
assign i = 10
10 [2]
(dbx)
assign *(int *)0x444 = 1 [3]
1
(dbx)
The patch command patches an executable disk file to correct bad data or instructions. Only 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. The patch command fails if it is issued against a program that is executing.
The patch command has the following form:
The patch is applied to the default disk file; you can use qualified
variable names to specify a patch to a file other than the default.
Applying a patch in this way also patches the in-memory image of the
file being patched.
For example:
(dbx)
patch &main = 0
(dbx)
patch var = 20
(dbx)
patch &var = 20
(dbx)
patch 0xnnnnn = 0xnnnnn
Although it is possible for you to set the current line pointer to the beginning of a procedure, place a breakpoint at the end of the procedure, and run the procedure, it is usually easier to use the call or print command to execute a procedure in your program. The call or print command executes the procedure you name on the command line. You can pass parameters to the procedure by specifying them as arguments to the call or print command.
The
call
or
print
command does not alter the flow of your program. When the procedure
returns, the program remains stopped at the point where you issued the
call
or
print
command. The
print
command displays values returned by called procedures; the
call
command does not.
The call and print commands have the following forms:
For example:
(dbx)
stop in prnt [1]
[11] stop in prnt
(dbx)
call prnt(&line1) [2]
[11] stopped at [prnt:52,0x120000c] fprintf(stdout,"%3d.(%3d) %s",(dbx) status [3]
[11] stop in prnt [12] stop at "sam.c":40 [2] record output example2 (126 lines)(dbx) delete 11,12 [4]
The
print
command allows you to include a procedure as part of an expression to
be printed. For example:
(dbx)
print sqrt(2.)+sqrt(3.)
Use the setenv command to set an environment variable. You can use this command to set the value of an existing environment variable or create a new environment variable. The environment variable is visible to both dbx and the program you are running under dbx control, but it is not visible after you exit the dbx environment; however, if you start a shell with the sh command within dbx, that shell can see dbx environment variables. To change an environment variable for a process, you must issue the setenv command before starting up the process within dbx with the run command.
The setenv command has the following form:
For example:
(dbx)
setenv TEXT "sam.c" [1]
(dbx)
run [2]
[4] stopped at [prnt:52,0x120000e34] fprintf(stdout,"%3d.(%3d) %s",(dbx) setenv TEXT "" [3]
Usage: sam filename
Program exited with code 1
A breakpoint stops program execution and lets you examine the program's state at that point. The following sections describe the dbx commands to set a breakpoint at a specific line or in a procedure and to stop for signals.
When a program stops at a breakpoint, the debugger displays an
informational message. For example, if a breakpoint is set in the
sample program
sam.c
at line 23 in the
main()
procedure, the following message is displayed:
[4] stopped at [main:40, 0x120000b18] i=strlen(line1.string); | | | | | [1] [2] [3] [4] [5]
Before setting a breakpoint in a program with multiple source files, be sure that you are setting the breakpoint in the right file. To select the right procedure, take the following steps:
For debugging programs written in high-level languages, the stop command sets breakpoints to stop at a line, when a variable changes or a specified condition is true, or in a procedure. For debugging programs written in assembly language, the stopi command works the same as stop, except that it traces by machine instructions instead of by program lines. You can also instruct dbx to stop when it enters a new image invoked by an exec( ) call by setting the $stop_on_exec predefined variable (see Table 5-8).
Use the delete command to remove breakpoints established by the stop or stopi command.
The
stop
and
stopi
commands have the following forms:
Note
Specifying both VAR and EXP causes stops anywhere in the procedure, not just at the beginning. Using this feature is time consuming because the debugger must check the condition before and after each source line is executed. (When both arguments are specified, EXP is always checked before VAR.)
The following example shows the use of
stop
in a C program:
(dbx)
stop at 52
[3] stop at "sam.c":52
(dbx)
rerun
[3] stopped at [prnt:52,0x120000fb0] fprintf(stdout,"%3d.(%3d) %s",(dbx) stop in prnt
The following example shows the use of
stopi
in an assembly-language program:
(dbx)
stopi at 0x120000c04
[4] stop at 0x120000c04
(dbx)
rerun
[7] stopped at >*[prnt:52 ,0x120000c04] ldq r16, -32640(gp)
For debugging programs written in high-level languages, the trace command lists the value of a variable while the program is executing and determines the scope of the variable being traced. For debugging programs written in assembly language, the tracei command works the same as trace, except that it traces by machine instructions instead of by program lines.
The
trace
and
tracei
commands have the following forms:
For example:
(dbx)
trace i
[5] trace i in main
(dbx)
rerun sam.c
[4] [main:25 ,0x400a50]
(dbx)
c
[5] i changed before [main: line 41]: new value = 19; [5] i changed before [main: line 41]: old value = 19; new value = 14; [5] i changed before [main: line 41]: old value = 14; new value = 19; [5] i changed before [main: line 41]: old value = 19; new value = 13; [5] i changed before [main: line 41]: old value = 13; new value = 17; [5] i changed before [main: line 41]: old value = 17; new value = 3; [5] i changed before [main: line 41]: old value = 3; new value = 1; [5] i changed before [main: line 41]: old value = 1; new value = 30;
Use the when command to control the conditions under which certain dbx commands that you specify will be executed.
The when command has the following forms:
For example:
(dbx) when in prnt {print line1.length}
19 [1] 14 19More (n if no)?
.
.
.
17 59 45 12
[7] stopped at [prnt:52,0x12000fb0] fprintf(stdout,"%3d.(%3d) %s", | [2]
The catch command either lists the signals that dbx catches or specifies a signal for dbx to catch. If the process encounters a specified signal, dbx stops the process.
The ignore command either lists the signals that dbx does not catch or specifies a signal for dbx to add to the ignore list.
The catch and ignore commands have the following forms:
For example:
(dbx) catch [1]
INT QUIT ILL TRAP ABRT EMT FPE BUS SEGV SYS PIPE TERM URG \ STOP TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2(dbx) ignore [2]
INT QUIT ILL TRAP ABRT EMT FPE KILL BUS SEGV SYS PIPE TERM URG \ STOP TTIN TTOU IO XCPU XFSZ VTALRM PROF WINCH INFO USR1 USR2(dbx) ignore
The backslashes in this example represent line continuation. The actual output from catch and ignore is a single line.
When dbx is stopped at a breakpoint, the program state can be examined to determine what might have gone wrong. The debugger provides commands for displaying stack traces, variable values, and register values. The debugger also provides commands to display information about the activation levels shown in the stack trace and to move up and down the activation levels (see Section 5.6.2).
The print command displays the values of one or more expressions.
The printf command lists information in a specified format and supports all formats of the printf() function except strings (%s). For a list of formats, see printf(3). You can use the printf command to see a variable's value in a different number base.
The default command alias list (see Section 5.5.3) provides some useful aliases for displaying the value of variables in different bases -- octal (po), decimal (pd), and hexadecimal (px). The default number base is decimal.
You can specify either the real machine register names or the software names from the include file regdef.h. A prefix before the register number specifies the type of register; the prefix can be either $f or $r, as shown in the following listing of registers:
Register Name(s) | Register Type |
$f00-$f31 | Floating point register (1 of 32) |
$r00-$r31 | Machine register (1 of 32) |
$fpcr | Floating-point control register |
$pc | Program counter value |
$ps |
Program status register |
Table Note:
You can also specify prefixed registers in the
print
command to display a register value or the program counter. The
following commands display the values of machine register 3 and the
program counter:
(dbx)
print $r3
(dbx)
print $pc
The print command has the following forms:
Note
If the expression contains a name that is the same as a dbx keyword, you must enclose the name within parentheses. For example, to print output, a keyword in the playback and record commands, specify the name as follows:
(dbx) print (output)
For example:
(dbx) print i
The printregs command displays a complete list of register values; it accepts no arguments. As with the print command, the default base for display by printregs is decimal. To display values in hexadecimal with the printregs command, set the dbx variable $hexints.
For example:
(dbx)
printregs
$vfp= 4831837712 $r0_v0=0 $r1_t0=0 $r2_t1=0 $r3_t2=18446744069416926720 $r4_t3=18446744071613142936 $r5_t4=1 $r6_t5=0
.
.
.
$f25= 0.0 $f26= 0.0 $f27= 2.3873098155006918e-314 $f28= 2.6525639909000367e-314 $f29= 9.8813129168249309e-324 $f30= 2.3872988413145664e-314 $f31= 0.0 $pc= 4831840840
The dump command displays information about activation levels, including values for all variables that are local to a specified activation level. To see what activation levels are currently active in the program, use the where command to get a stack trace.
The dump command has the following forms:
For example:
(dbx)
where
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04] 1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac](dbx) dump
> 0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04](dbx) dump main
1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac] line1 = struct { string = "#include <stdio.h>" length = 19 linenumber = 0 } fd = 0x140000158 fname = 0x11ffffe9c = "sam.c" i = 19 curlinenumber = 1
main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac] line1 = struct { string = "#include <stdio.h>" length = 19 linenumber = 0 } fd = 0x140000158 fname = 0x11ffffe9c = "sam.c" i = 19 curlinenumber = 1 (dbx)
You can display memory contents by specifying the address and the format of the display. Use the following form, with no spaces between the three parts of the command:
address /countmode
The
address
portion of the command is the address of the first item to be
displayed,
count
is the number of items to be shown, and
mode
indicates the format in which the items are to be displayed. For
example:
prnt/20i
This example displays the contents of 20 machine instructions, beginning at the address of the prnt function.
The values for mode are shown in Table 5-9.
Mode | Display Format |
b | Displays a byte in octal. |
c | Displays a byte as a character. |
D | Displays a long word (64 bits) in decimal. |
d | Displays a short word (16 bits) in decimal. |
dd | Displays a word (32 bits) in decimal. |
f | Displays a single-precision real number. |
g | Displays a double-precision real number. |
i | Displays machine instructions. |
O | Displays a long word in octal. |
o | Displays a short word in octal. |
oo | Displays a word (32 bits) in octal. |
s | Displays a string of characters that ends in a null byte. |
X | Displays a long word in hexadecimal. |
x | Displays a short word in hexadecimal. |
xx | Displays a word (32 bits) in hexadecimal. |
The following example shows the output when displaying memory addresses
as instructions:
(dbx)
&prnt/20i
[prnt:51, 0x120000bf0] ldah gp, 8193(r27) [prnt:51, 0x120000bf4] lda gp, -25616(gp) [prnt:51, 0x120000bf8] lda sp, -64(sp) [prnt:51, 0x120000bfc] stq r26, 8(sp) [prnt:51, 0x120000c00] stq r16, 16(sp) [prnt:52, 0x120000c04] ldq r16, -32640(gp) >*[prnt:52, 0x120000c08] addq r16, 0x38, r16 [prnt:52, 0x120000c0c] ldq r17, -32552(gp) [prnt:52, 0x120000c10] ldq r1, 16(sp) [prnt:52, 0x120000c14] ldl r18, 260(r1) [prnt:52, 0x120000c18] ldl r19, 256(r1) [prnt:52, 0x120000c1c] bis r1, r1, r20 [prnt:52, 0x120000c20] ldq r27, -32624(gp) [prnt:52, 0x120000c24] jsr r26, (r27), 0x4800030a0 [prnt:52, 0x120000c28] ldah gp, 8193(r26) [prnt:52, 0x120000c2c] lda gp, -25672(gp) [prnt:54, 0x120000c30] ldq r16, -32640(gp) [prnt:54, 0x120000c34] addq r16, 0x38, r16 [prnt:54, 0x120000c38] ldq r27, -32544(gp) [prnt:54, 0x120000c3c] jsr r26, (r27), 0x480003100
The dbx debugger allows you to capture and replay portions of your input to the program and also portions of its output. Recorded information is written to a file so that you can reuse or reexamine it.
Recording input can be useful for creating command files containing sequences that you want to repeat many times; you can even use recorded input to control dbx for such purposes as regression testing. Recording output is useful for capturing large volumes of information that are inconvenient to deal with on the screen, so that you can analyze them later. To look at recorded output later, you can read the saved file directly or you can play it back with dbx.
Use the record input command to record debugger input. Use the playback input command to repeat a recorded sequence. The record input and playback input commands have the following forms:
The name given to the temporary file, if used, is contained in the
debugger variable
$defaultin.
To display the temporary file name, use the
print
command:
(dbx)
print $defaultin
Use a temporary file when you need to refer to the saved output only during the current debugging session; specify a file name to save information for reuse after you end the current debugging session. Use the status command to see whether recording is active. Use the delete command to stop recording. Note that these commands will appear in the recording; if you are creating a file for future use, you will probably want to edit the file to remove commands of this type.
Use the playback input command to replay the commands recorded with the record input command. By default, playback is silent; you do not see the commands as they are played. If the dbx variable $pimode is set to 1, dbx displays commands as they are played back.
The following example records input and displays the resulting file:
(dbx)
record input [1]
[2] record input /tmp/dbxtX026963 (0 lines)
(dbx)
status
[2] record input /tmp/dbxtX026963 (1 lines)
(dbx)
stop in prnt
[3] stop in prnt
(dbx)
when i = 19 {stop}
[4] stop ifchanged i = 19
(dbx)
delete 2 [2]
(dbx)
playback input [3]
[3] stop in prnt [4] stop ifchanged i = 19 [5] stop in prnt [6] stop ifchanged i = 19 /tmp/dbxtX026963: 4: unknown event 2 [4](dbx)
The temporary file resulting from the preceding
dbx
commands contains the following text:
status stop in prnt when i = 19 {stop} delete 2
Use the
record
output
command to record
dbx
output during a debugging session. To produce a complete record of
activity by recording input along with the output, set the
dbx
variable
$rimode.
You can use the debugger's
playback
output
command to look at the recorded information, or you can use any text
editor.
The record output and playback output commands have the following forms:
The name given to the temporary file, if used, is contained in the
debugger variable
$defaultout.
To display the temporary file name, use the
print
command:
(dbx)
print $defaultout
The playback output command works the same as the cat command; a display from the record output command is identical to the contents of the recording file.
Use a temporary file when you need to refer to the saved output only during the current debugging session; specify a file name to save information for reuse after you end the current debugging session. Use the status command to see whether recording is active. Use the delete command to stop recording.
The following example shows a sample
dbx
interaction and the output recorded for this interaction in a file
named
code:
(dbx)
record output code
[3] record output code (0 lines)
(dbx)
stop at 25
[4] stop at "sam.c":25
(dbx)
run sam.c
[4] stopped at [main:25 ,0x120000a48] if (argc < 2) {
(dbx)
delete 3
(dbx)
playback output code
[3] record output code (0 lines) (dbx) [4] stop at "sam.c":25 (dbx) [4] stopped at [main:25 ,0x120000a48] if (argc < 2) {(dbx)
The
dbx
debugger can be used to debug running processes that are started
outside the
dbx
environment. It supports the debugging of such processes, both
parent and child, by using the
/proc
file system. The debugger can debug running processes only if the
/proc
file system is mounted. If
/proc
is not already mounted, the superuser can mount it with the following
command:
#
mount -t procfs /proc /proc
You can add the following entry to the
/etc/fstab
file to mount
/proc
upon booting:
/proc /proc procfs rw 0 0
The dbx debugger checks first to see if /proc is mounted, but it will still function if this is not the case.
To attach to a running process, use the dbx command attach, which has the following form:
You can also attach to a process for debugging by using the command line flag -pid process id.
To detach from a running process, use the dbx command detach, which has the following form:
To change from one process to another, use the dbx command switch, which has the following form:
The attach command first checks to see whether /proc is mounted; dbx gives a warning that tells you what to do if it is not mounted. If /proc is mounted, dbx looks for the process ID in /proc. If the process ID is in /proc, dbx attempts to open the process and issues a stop command. If the process is not there or if the permissions do not allow attaching to it, dbx reports this failure.
When the stop command takes effect, dbx reports the current position, issues a prompt, and waits for user commands. The program probably will not be stopped directly in the user code but will more likely be in a library or system call that was called by user code.
The detach command deletes all current breakpoints, sets up a "run on last close" flag, and closes ("releases") the process. The program then continues running if it has not been explicitly terminated inside dbx.
To see a summary of all the active processes under control of dbx, use the plist command, which has the following form:
The dbx debugger provides four basic commands to assist in the debugging of applications that use threads.
The tlist command displays a quick list of all threads and where they are currently positioned in the program. This command accepts no arguments.
The tset command sets the current thread. The debugger maintains one thread as the "current" thread; this thread is the one that hits a breakpoint or receives a signal that causes it to stop and relinquish control to dbx.
Using the tlist command, you can see all the threads, with their IDs, that are currently in your program. Use tset to choose a different thread as the current thread so that you can examine its state with the usual dbx commands.
Note that the selected thread remains the current thread until you enter another tset command. Note also that the continue, step, or next commands might be inappropriate for a given thread if it is blocked or waiting to join with another thread.
The tset command has the following form:
The
tstack
command lists the stacks of all the threads in your application. It is
similar to the
where
command and, like
where,
takes an optional numeric argument to limit the number of stack levels
displayed:
If EXP is specified, dbx displays only the top EXP levels of the stacks; otherwise, the entire stacks are displayed.
If the DECthreads product is installed on your system, you can gain access to the DECthreads pthread debugger by issuing a call cma_debug() command within your dbx session. The pthread debugger can provide a great deal of useful information about the threads in your program. For information on using the pthread debugger, enter a help command at its debug> prompt.
A sample threaded program,
twait.c,
is shown in
Example 12-1.
The following example shows a
dbx
session using that program. Long lines in this example have all been
folded at 72 characters to represent display on a narrow terminal.
%
dbx twait
dbx version 3.11.6 Type 'help' for help.(dbx) stop in do_tick
main: 50 pthread_t me = pthread_self(), timer_thread;
1: main thread starting up 1: exit lock initialized 1: exit lock obtained 1: exit cv initialized 1: timer_thread 2 created 1: exit lock released [2] thread 0x81c62e80 stopped at [do_tick:21 ,0x12000730c] pthread_ t me = pthread_self();(dbx) tlist
thread 0x81c623a0 stopped at [msg_receive_trap:74 +0x8,0x3ff808edf04] Source not available thread 0x81c62e80 stopped at [do_tick:21 ,0x12000730c] pthread_ t me = pthread_self();(dbx) where
> 0 do_tick(argP = (nil)) ["twait.c":21, 0x12000730c] 1 cma__thread_base(0x0, 0x0, 0x0, 0x0, 0x0) ["../../../../../src/usr/ ccs/lib/DECthreads/COMMON/cma_thread.c":1441, 0x3ff80931410](dbx) tset 0x81c623a0
thread 0x81c623a0 stopped at [msg_receive_trap:74 +0x8,0x3ff808edf04] Source not available(dbx) where
> 0 msg_receive_trap(0x3ff8087b8dc, 0x3ffc00a2480, 0x3ff8087b928, 0x181 57f0d0d, 0x3ff8087b68c) ["/usr/build/osf1/goldos.bld/export/alpha/usr/in clude/mach/syscall_sw.h":74, 0x3ff808edf00] 1 msg_receive(0x61746164782e, 0x3ffc009a420, 0x3ffc009a420, 0x3c20, 0 xe0420) ["../../../../../src/usr/ccs/lib/libmach/msg.c":95, 0x3ff808e474 4] 2 cma__vp_sleep(0x280187f578, 0x3990, 0x7, 0x3ffc1032848, 0x0) ["../. ./../../../src/usr/ccs/lib/DECthreads/COMMON/cma_vp.c":1471, 0x3ff809375 cc] 3 cma__dispatch(0x7, 0x3ffc1032848, 0x0, 0x3ffc100ee08, 0x3ff80917e3c ) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_dispatch.c":967 , 0x3ff80920e48] 4 cma__int_wait(0x11ffff228, 0x140009850, 0x3ffc040cdb0, 0x5, 0x3ffc0 014c00) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_condition .c":2202, 0x3ff80917e38] 5 cma_thread_join(0x11ffff648, 0x11ffff9f0, 0x11ffff9e8, 0x60aaec4, 0 x3ff8000cf38) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_thr ead.c":825, 0x3ff80930a58] 6 pthread_join(0x140003110, 0x40002, 0x11ffffa68, 0x3ffc040cdb0, 0x0) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_pthread.c":2193, 0x3ff809286c8] 7 main() ["twait.c":81, 0x12000788c](dbx) tlist
thread 0x81c623a0 stopped at [msg_receive_trap:74 +0x8,0x3ff808edf04] Source not available thread 0x81c62e80 stopped at [do_tick:21 ,0x12000730c] pthread_ t me = pthread_self();(dbx) tset 0x81c62e80
thread 0x81c62e80 stopped at [do_tick:21 ,0x12000730c] pthread_ t me = pthread_self();(dbx) cont
2: timer thread starting up, argP=0x0 [4] thread 0x81c62e80 stopped at [do_tick:35 ,0x120007430] printf(" %d: wait for next tick\n", THRID(&me));(dbx) cont
2: wait for next tick 2: TICK #1 [4] thread 0x81c62e80 stopped at [do_tick:35 ,0x120007430] printf(" %d: wait for next tick\n", THRID(&me));(dbx) tstack
Thread 0x81c623a0: > 0 msg_receive_trap(0x3ff8087b8dc, 0x3ffc00a2480, 0x3ff8087b928, 0x181 57f0d0d, 0x3ff8087b68c) ["/usr/build/osf1/goldos.bld/export/alpha/usr/in clude/mach/syscall_sw.h":74, 0x3ff808edf00] 1 msg_receive(0x61746164782e, 0x3ffc009a420, 0x3ffc009a420, 0x3c20, 0 xe0420) ["../../../../../src/usr/ccs/lib/libmach/msg.c":95, 0x3ff808e474 4] 2 cma__vp_sleep(0x280187f578, 0x3990, 0x7, 0x3ffc1032848, 0x0) ["../. ./../../../src/usr/ccs/lib/DECthreads/COMMON/cma_vp.c":1471, 0x3ff809375 cc] 3 cma__dispatch(0x7, 0x3ffc1032848, 0x0, 0x3ffc100ee08, 0x3ff80917e3c ) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_dispatch.c":967 , 0x3ff80920e48] 4 cma__int_wait(0x11ffff228, 0x140009850, 0x3ffc040cdb0, 0x5, 0x3ffc0 014c00) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_condition .c":2202, 0x3ff80917e38] 5 cma_thread_join(0x11ffff648, 0x11ffff9f0, 0x11ffff9e8, 0x60aaec4, 0 x3ff8000cf38) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_thr ead.c":825, 0x3ff80930a58] 6 pthread_join(0x140003110, 0x40002, 0x11ffffa68, 0x3ffc040cdb0, 0x0) ["../../../../../src/usr/ccs/lib/DECthreads/COMMON/cma_pthread.c":2193, 0x3ff809286c8] 7 main() ["twait.c":81, 0x12000788c] Thread 0x81c62e80: > 0 do_tick(argP = (nil)) ["twait.c":35, 0x120007430] 1 cma__thread_base(0x0, 0x0, 0x0, 0x0, 0x0) ["../../../../../src/usr/ ccs/lib/DECthreads/COMMON/cma_thread.c":1441, 0x3ff80931410] More (n if no)?(dbx) tstack 3
Thread 0x81c623a0: > 0 msg_receive_trap(0x3ff8087b8dc, 0x3ffc00a2480, 0x3ff8087b928, 0x181 57f0d0d, 0x3ff8087b68c) ["/usr/build/osf1/goldos.bld/export/alpha/usr/in clude/mach/syscall_sw.h":74, 0x3ff808edf00] 1 msg_receive(0x61746164782e, 0x3ffc009a420, 0x3ffc009a420, 0x3c20, 0 xe0420) ["../../../../../src/usr/ccs/lib/libmach/msg.c":95, 0x3ff808e474 4] 2 cma__vp_sleep(0x280187f578, 0x3990, 0x7, 0x3ffc1032848, 0x0) ["../. ./../../../src/usr/ccs/lib/DECthreads/COMMON/cma_vp.c":1471, 0x3ff809375 cc] Thread 0x81c62e80: > 0 do_tick(argP = (nil)) ["twait.c":35, 0x120007430] 1 cma__thread_base(0x0, 0x0, 0x0, 0x0, 0x0) ["../../../../../src/usr/ ccs/lib/DECthreads/COMMON/cma_thread.c":1441, 0x3ff80931410](dbx) cont
2: wait for next tick 2: TICK #2 [4] thread 0x81c62e80 stopped at [do_tick:35 ,0x120007430] printf(" %d: wait for next tick\n", THRID(&me));(dbx) assign ticks = 29
2: wait for next tick 2: TICK #29 [4] thread 0x81c62e80 stopped at [do_tick:35 ,0x120007430] printf(" %d: wait for next tick\n", THRID(&me));(dbx) cont
2: wait for next tick 2: TICK #30 2: exiting after #31 ticks 1: joined with timer_thread 2 [3] thread 0x81c623a0 stopped at [main:85 ,0x1200078ec] if (errn o != 0) printf("errno 7 = %d\n",errno);(dbx) tlist
thread 0x81c623a0 stopped at [main:85 ,0x1200078ec] if (errno != 0) printf("errno 7 = %d\n",errno); thread 0x81c62e80 stopped at [msg_rpc_trap:75 +0x8,0x3ff808edf10] Source not available(dbx) cont
(dbx) tlist
Program terminated normally
The dbx debugger can debug multiple simultaneous asynchronous processes. While debugging asynchronous processes, dbx can display status and accept commands asynchronously. When running asynchronously, the debugger might exhibit confusing behavior because a running process can display output on the screen while you are entering commands to examine a different process that is stopped.
The debugger automatically enters asynchronous mode in either of the following circumstances:
The debugger uses several predefined variables to define the behavior of asynchronous debugging. (See also Table 5-8.) The variable $asynch_interface can be viewed as a counter that is incremented by 1 when a new process is attached and decremented by 1 when a process terminates or is detached. The default value is 0.
When $asynch_interface has a positive nonzero value, asynchronous debugging is enabled; when the variable is 0 (zero) or negative, asynchronous debugging is disabled. To prevent dbx from entering asynchronous mode, set the $asynch_interface variable to a negative value. (Note that disabling asynchronous mode might make debugging more difficult if a parent is waiting on a child that is stopped.)
When a process executes a fork( ) or vfork( ) call, dbx attaches to the child process and automatically enters asynchronous mode (if permitted by $asynch_interface). The default behavior is to stop the child process right after the fork. You can change this default by setting the variable $stop_on_fork to 0; in this case, dbx will attach to the child process but not stop it.
The dbx debugger attempts to apply a degree of intelligence to the handling of forks by filtering out many of the fork calls made by various system and library calls. If you want to stop the process on these forks also, you can set the predefined variable $stop_all_forks to 1. This variable's default value is 0. Stopping on all forks can be particularly useful when you are debugging a library routine.
You can use the debugger's
plist
and
switch
commands to monitor and switch between processes.
Example 5-1 is the sample C program (sam.c) that is referred to in examples throughout this chapter.
#include <stdio.h> struct line { char string[256]; int length; int linenumber; };
typedef struct line LINETYPE;
void prnt();
main(argc,argv) int argc; char **argv; { LINETYPE line1; FILE *fd; extern FILE *fopen(); extern char *fgets(); extern char *getenv(); char *fname; int i; static curlinenumber=0;
if (argc < 2) { if((fname = getenv("TEXT")) == NULL || *fname == ' ') { fprintf(stderr, "Usage: sam filename\n"); exit(1); } } else fname = argv[1]; fd = fopen(fname,"r"); if (fd == NULL) { fprintf(stderr, "cannot open %s\n",fname); exit(1); } while(fgets(line1.string, sizeof(line1.string), fd) != NULL){ i=strlen(line1.string); if (i==1 && line1.string[0] == '\n') continue; line1.length = i; line1.linenumber = curlinenumber++; prnt(&line1); } } void prnt(pline) LINETYPE *pline; { fprintf(stdout,"%3d. (%3d) %s", pline->linenumber, pline->length, pline->string); fflush(stdout); }