[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


5    Debugging Programs with dbx

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.

Table 5-1: Keywords Used in Command Syntax Descriptions

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.


[Return to Library] [Contents] [Previous Chapter] [Next Section] [Next Chapter] [Index] [Help]


5.1    General Debugging Considerations

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.1.1    Why Use a Source-Level Debugger?

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.1.2    What Are Activation Levels?

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]

  1. The most recently called procedure is prnt. The activation level of prnt is 0; this function is at the top of the stack. [Return to example]

  2. The main program is main. [Return to example]

  3. Activation level number. The angle bracket (>) indicates the activation level that is currently under examination. [Return to example]

  4. Procedure name. [Return to example]

  5. Procedure's arguments. [Return to example]

  6. Source file name. [Return to example]

  7. Current line number. [Return to example]

  8. Current program counter. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.1.3    Isolating Program Execution Failures

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:

  1. Invoke the program under dbx, specifying any appropriate flags and the names of the executable file and the core dump file on the dbx command line.

  2. Get a stack trace using the where command to locate the point of failure.

    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.

  3. Set breakpoints to isolate the error using the stop or stopi commands.

  4. Display the values of variables using the print command to see where a variable might have been assigned an incorrect value.

If you still cannot find the error, other dbx commands described in this chapter might be useful.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.1.4    Diagnosing Incorrect Output Results

If a program executes to completion but produces incorrect values or output, take the following steps:

  1. Set a breakpoint where you think the problem is happening -- for example, the code that generates the value or output.

  2. Run the program.

  3. Get a stack trace using the where command.

  4. Display the values for the variables that might be causing the problem using the print command.

  5. Repeat this procedure until the problem is found.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.1.5    Avoiding Pitfalls

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:


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.2    Running dbx

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.2.1    Compiling a Program for Debugging

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.2.2    Creating a dbx Initialization File

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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.2.3    Invoking and Terminating dbx

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

flags
Several of the most important flags supported by the dbx command line are shown in Table 5-2.

objfile
The name of the executable file of the program that you want to debug. If objfile is not specified, dbx uses a.out by default.

corefile
Name of a core dump file. If you specify corefile, dbx lists the point of program failure. The dump file holds an image of memory at the time the program failed. Use dbx commands to get a stack trace and look at the core file code. The debugger displays information from the core file, not from memory as it usually does.

The maximum number of arguments accepted by dbx is 1000; however, system limits on your machine might reduce this number.

Table 5-2: dbx Command Flags

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.3    Using dbx Commands

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.3.1    Qualifying Variable Names

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]

  1. Current file [Return to example]

  2. Procedure name [Return to example]

  3. Variable name [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.3.2    dbx Expressions and Their Precedence

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.

Table 5-3: The dbx Number-Sign Expression Operator

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.

Table 5-4: Expression Operator Precedence

Unary: &, +, -, * (pointer), #, sizeof()[Table Note 1], ~, /, (type), (type *)
Binary: <<, >>, ", !, ==, !=, <=, >=, <, >, &, &&, |, ||, +, -, *, /[Table Note 2], %, [], ->

Table Notes:

  1. The sizeof operator specifies the number of bytes retrieved to get an element, not (number-of-bits+7)/8.

  2. For backward compatibility, dbx also accepts two slashes (//) as a division operator.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.3.3    dbx Data Types and Constants

Table 5-5 lists the built-in data types that dbx commands can use.

Table 5-5: Built-in Data Types

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.

Table 5-6: Input Constants

Constant Description
false 0
true Nonzero
nil 0
0xnumber Hexadecimal
0tnumber Decimal
0number Octal
number Decimal
number.[number][e|E][+|-]EXP Float


Notes:


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.4    Working with the dbx Monitor

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.4.1    Repeating dbx 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:

history
Displays the commands in the history list.

Return key
Repeats the last command that you entered. You can disable this feature by setting the $repeatmode variable to 0 (see Section 5.5.1).

!string
Repeats the most recent command that starts with the specified string.

!integer
Repeats the command associated with the specified integer.

!-integer
Repeats the command that occurred the specified number of commands (integer) before the most recent command.

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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.4.2    Editing the dbx Command Line

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:

Table 5-7 lists the emacs-mode command line editing commands.

Table 5-7: Command-Line Editing Commands in emacs mode

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.4.3    Entering Multiple Commands

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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.4.4    Completing Symbol Names

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]

ioctl.ioctl .ioctl isatty.isatty .isatty i int [1]
(dbx) i                                        [2]


  1. The display might include data types and library symbols. [Return to example]

  2. After listing all names beginning with the partial name, dbx prompts again with the previously specified string, giving you an opportunity to specify additional characters and repeat the search. [Return to example]

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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.1    Setting and Removing Variables

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:

set
Displays a list of dbx predefined variables.

set VAR = EXP
Assigns a new value to a variable or defines a new variable.

unset VAR
Unsets the value of a dbx variable.

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      24
more (n if no)?  n
(dbx)  set test = 12    [2]
.nr C# 1 (dbx)  set

$listwindow      10
$datacache        1
$main        "main"
$pagewindow      22
test             12
$page             1
$maxstrlen      128
$cursrcline      24
more (n if no)?  n
.nr C# 3 (dbx)  unset test       [3]
.nr C# 1 (dbx)  set

$listwindow      10
$datacache        1
$main        "main"
$pagewindow      22
$page             1
$maxstrlen      128
$cursrcline      24
more (n if no)?  n
(dbx) 

  1. Display a list of dbx predefined variables. [Return to example]

  2. Assign a new value to a variable. [Return to example]

  3. Remove a variable. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.2    Predefined dbx Variables

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.

Table 5-8: Predefined dbx Variables

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.3    Defining and Removing Aliases

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:

alias
Displays a list of all aliases.

alias NAME1[(ARG1,...,ARGN)] "NAME2"
Defines a new alias. NAME1 is the new name. NAME2 is the command to string to rename. ARG1,...,ARGN are the command arguments.

unalias NAME
Removes an alias from a command, where NAME is the alias name.

The following example illustrates the alias and unalias commands:

(dbx)  alias                        [1]

h       history
si      stepi
Si      nexti

.
.
.
g goto s step
More (n if no) ? n
(dbx)  alias ok(x) "stop at x"    [2]
(dbx)  ok(52)                       [3]

[2] Stop at "sam.c":52      [4]
(dbx)
(dbx)  unalias h                    [5]
(dbx)  alias

si      stepi
Si      nexti

.
.
.
g goto s step
More (n if no)?  n
(dbx) 

  1. Display aliases. [Return to example]

  2. Define an alias for setting a breakpoint. [Return to example]

  3. Set a breakpoint at line 52. [Return to example]

  4. Debugger acknowledges breakpoint set at line 52. [Return to example]

  5. Remove the h alias. (Notice that it disappears from the alias list.) [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.4    Monitoring Debugging Session Status

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.5    Deleting and Disabling Breakpoints

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:

delete EXP1[,...,EXPN]
Deletes the specified status items.

delete all
delete *
Deletes all status items.


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
(dbx)  status

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

disable EVENT1[,EVENT2,...]
enable EVENT1[,EVENT2,...]
Disables or enables the specified events.

disable all
enable all
Disables or enables all events.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.6    Displaying the Names of Loaded Object Files

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) 


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.5.7    Invoking a Subshell from Within 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) 


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6    Examining Source Programs

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.1    Specifying the Locations of Source Files

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:

use
Lists the current directories.

use DIR1 ... DIRN
Replaces the current list of directories with a new set.

For example:

(dbx)  use
.                            [1]
(dbx)  use /usr/local/lib
(dbx)  use
/usr/local/lib               [2]
(dbx) 

  1. Current directory [Return to example]

  2. New directory [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.2    Moving Up or Down in the Activation Stack

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.2.1    Using the where and tstack 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:

where [EXP]
tstack [EXP]
Displays a stack trace.

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) 

  1. Activation level [Return to example]

  2. Procedure name [Return to example]

  3. Current value of the argument pline [Return to example]

  4. Source file name [Return to example]

  5. Line number [Return to example]

  6. Program counter [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.2.2    Using the up and down and func Commands

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:

up [EXP]
Moves up the specified number of activation levels in the stack. The default is one level.

down [EXP]
Moves down the specified number of activation levels in the stack. The default is one level.

func
Displays the current activation levels.

func PROCEDURE
Moves to the activation level specified by PROCEDURE.

func EXP
Moves to the activation level specified by the expression.

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
main:  45  prnt(&line1);                                   [1]
(dbx)  where

   0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
>  1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac]
(dbx)  down
prnt:  52  fprintf(stdout,"%3d.  (%3d) %s",              [2]
(dbx)  where

>  0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
   1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac]
(dbx)  func 1
main 47        prnt(&line1)                                [3]
(dbx) 

  1. Move up one level. [Return to example]

  2. Move down one level. [Return to example]

  3. Move directly to main. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.3    Changing the Current Source File

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:

file
Displays the name of the file currently in use.

file FILE
Changes the current file to the specified file.

For example:

(dbx)  file
sam.c               [1]
(dbx)  file data.c
(dbx)  file
data.c              [2]
(dbx) 

  1. Current file [Return to example]

  2. New file [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.4    Listing Source Code

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:

list
Lists the number of lines specified by $listwindow, starting at the current line.

list EXP
Lists the number of lines specified by EXP, starting at the current line.

list EXP1,EXP2
List lines from EXP1 to EXP2.

list EXP:INT
Starting at the specified line (EXP), lists the specified number of lines (INT), overriding $listwindow.

list PROCEDURE
Lists the specified procedure for $listwindow lines.

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.5    Searching for Text in Source Files

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:

/[REGEXP]
Searches forward for the specified regular expression or, if no expression is specified, for the regular expression associated with the last previous search command.

?[REGEXP]
Searches backward in the same manner as the slash command's forward search.


(dbx)  /lines
no match
(dbx)  /line1
  16  LINETYPE line1;
(dbx)  /

  39  while(fgets(line1.string, sizeof(line1.string), fd) != NULL){
(dbx)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.6    Editing Source Files from Within 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:

edit
Invokes an editor on the current file.

edit FILE
Invokes an editor on the specified file.

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.7    identifying Variables That Share the Same Name

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:

which VAR
Displays the default version of the specified variable.

whereis VAR
Displays all versions of the specified variable.

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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.6.8    Examining Variable and Procedure Types

The whatis command lists the type declaration for variables and procedures in a program.

The whatis command has the following form:

whatis VAR
Displays the type declaration for the specified variable or procedure.

For example:

(dbx)  whatis main

int main(argc,argv)
int argc;
unsigned char **argv;
(dbx)  whatis i
int i;
(dbx) 


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7    Controlling the Program

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.1    Running and Rerunning the Program

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:

run ARGN][ARG1... [<FILE1] [>FILE2]
run ARGN][ARG1... [<FILE1] [>&FILE2]
Runs the program with the specified arguments and redirections.

args ARGN][ARG1... [<FILE1] [>FILE2]
args ARGN][ARG1... [<FILE1] [>&FILE2]
Sets the specified arguments and redirections for use by subsequent commands; the specified values remain in effect until explicitly altered by new values given with a run or rerun command.

rerun ARGN][ARG1... [<FILE1] [>FILE2]
rerun ARGN][ARG1... [<FILE1] [>&FILE2]
Reruns the program with the specified arguments and redirections.


For example:



(dbx) 
run sam.c                [1]

0.  (19)#include <stdio.h>
1.  (14) struct line {
2.  (19) char string[256];

.
.
.
Program terminated normally
(dbx)  rerun                    [2]
0.  (19)#include <stdio.h>
1.  (14) struct line {
2.  (19) char string[256];

.
.
.
Program terminated normally
(dbx) 

  1. The argument is sam.c. [Return to example]

  2. Reruns the program with the previously specified arguments. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.2    Executing the Program Step by Step

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:

step [EXP]
stepi [EXP]
Executes the specified number of lines or instructions in both the current procedure and any called procedures. The default is 1.

next [EXP]
nexti [EXP]
Executes the specified number of source code lines or machine instructions in only the current procedure, regardless of the number of lines executed in any called procedures. The default is 1.

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
  [main:40 ,0x120000b40]        i=strlen(line1.string);
(dbx) 

The $break_during_step and $printwhilestep variables affect stepping. See Table 5-8 for more information.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.3    Using the return Command

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:

return
Executes the rest of the current procedure and stops ready to execute the next sequential line in the calling procedure.

return PROCEDURE
Executes the rest of the current procedure and any calling procedures intervening between the current procedure and the procedure named by PROCEDURE. Stops ready to execute the next sequential line in the named procedure.

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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.4    Going to a Specific Place in the Code

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:

goto LINE
Goes to the specified source line when you continue execution.

For example:

(dbx)  when at 40 {goto 43}

[8] start sam.c:43 at "sam.c":40
(dbx)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.5    Resuming Execution After a Breakpoint

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:

cont
conti
Continues from the current source code line or machine address.

cont to LINE
conti to ADDRESS
Continues until the specified source code line or machine address.

cont in PROCEDURE
conti in PROCEDURE
Continues until the specified procedure.


cont SIGNAL
conti SIGNAL
Continues from the current line or machine instruction after receiving the specified signal.

cont SIGNAL to LINE
conti SIGNAL to ADDRESS
Continues until the specified line or address after receiving the specified signal.

cont SIGNAL in PROCEDURE
conti SIGNAL in PROCEDURE
Continues until the specified procedure and sends the specified signal.

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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.6    Changing the Values of Program Variables

The assign command changes the value of a program variable. The assign command has the following form:

assign VAR = EXP
assign EXP1 = EXP2
Assigns a new value to the program variable named by VAR or the address represented by the resolution of EXP1.

For example:

(dbx)  print i
19                              [1]
(dbx)  assign i = 10
10                              [2]
(dbx)  assign *(int *)0x444 = 1        [3]
 1
(dbx) 

  1. The value of i. [Return to example]

  2. The new value of i. [Return to example]

  3. Coerce the address to be an integer and assign a value of 1 to it. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.7    Patching Executable Disk Files

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:

patch VAR = EXP
patch EXP1 = EXP2
Assigns a new value to the program variable named by VAR or the address represented by the resolution of EXP1.


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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.8    Running a Specific Procedure

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:

call PROCEDURE([parameters])
print PROCEDURE([parameters])
Executes the object code associated with the named procedure or function. Specified parameters are passed to the procedure or function.

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]
(dbx) 

  1. The stop command sets a breakpoint in the prnt() function. [Return to example]

  2. The call command begins executing the object code associated with prnt(). The line1 argument passes a string by reference to prnt. [Return to example]

  3. The status command displays the currently active breakpoints. [Return to example]

  4. The delete command deletes the breakpoints at lines 52 and 40. [Return to example]

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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.7.9    Setting Environment Variables

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:

setenv VAR "STRING"
Changes the value of an existing environment variable or create a new one. To reset an environment variable, specify a null string.


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]
(dbx)  run                                      [4]

Usage: sam filename

 
Program exited with code 1

  1. The setenv command sets the environment variable TEXT to the value sam.c. [Return to example]

  2. The run command executes the program from the beginning. The program reads input from the file named in the the environment variable TEXT. Program execution stops at the breakpoint at line 52. [Return to example]

  3. The setenv command sets the environment variable TEXT to null. [Return to example]

  4. The run command executes the program. Because the TEXT environment variable contains a null value, the program must get input. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.8    Setting Breakpoints

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.8.1    Overview

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]

  1. Breakpoint status number. [Return to example]

  2. Procedure name. [Return to example]

  3. Line number. [Return to example]

  4. Current program counter. Use this number to display the assembly language instructions from this point. (See Section 5.7.5 for more information.) [Return to example]

  5. Source line. [Return to example]

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:

  1. Use the file command to select the source file.

  2. Use the func command to specify a procedure name.

  3. List the lines of the file or procedure using the list command (see Section 5.6.4).

  4. Use a stop at command to set a breakpoint at the desired line.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.8.2    Setting Breakpoints

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:

stop VAR
stopi VAR
Stops when VAR changes.


stop VAR at LINE
stopi VAR at ADDRESS
Stops when VAR changes at a specified source code line or address.

stop VAR at LINE if EXP
stopi VAR at ADDRESS if EXP
Stops when VAR changes at a specified line or address only if the expression is true.

stop if EXP
stopi if EXP
Stops if EXP is true.

stop VAR if EXP
stopi VAR if EXP
Stops when VAR changes if EXP is true.


stop in PROCEDURE
stopi in PROCEDURE
Stops at the beginning of the procedure.

stop VAR in PROCEDURE
Stops in the specified procedure when VAR changes.

stop VAR in PROCEDURE if EXP
stopi VAR in PROCEDURE if EXP
Stops when VAR changes in the specified procedure if EXP is true.

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
[15] stop in prnt
(dbx) 

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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.8.3    Tracing Variables During Execution

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:

trace LINE
Lists the specified source line each time it is executed.

trace VAR
tracei VAR
Lists the specified variable after each source line or machine instruction is executed.

trace [VAR] at LINE
tracei [VAR] at ADDRESS
Lists the specified variable at the specified line or instruction.

trace [VAR] in PROCEDURE
tracei [VAR] in PROCEDURE
Lists the specified variable in the specified procedure.

trace [VAR] at LINE if EXP
tracei [VAR] at ADDRESS if EXP
Lists the variable at the specified source code line or machine address when the expression is true and the value of the variable has changed. (EXP is checked before VAR.)

trace [VAR] in PROCEDURE if EXP
tracei [VAR] in PROCEDURE if EXP
Lists the variable in the specified procedure when the expression is true and the value of the variable has changed. (EXP is checked before VAR.)

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;


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.8.4    Writing Conditional Code in dbx

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:

when VAR [if EXP] {COMMAND_LIST}
Executes the command list when EXP is true and VAR changes.

when [VAR] at LINE [if EXP] {COMMAND_LIST}
Executes the command list when EXP is true, VAR changes, and the debugger encounters LINE.

when in PROCEDURE {COMMAND_LIST}
Executes the command list upon entering PROCEDURE.

when [VAR] in PROCEDURE [if EXP] {COMMAND_LIST}
Executes the specified commands on each line of PROCEDURE when EXP is true and VAR changes. (EXP is checked before VAR.)


For example:



(dbx) 
when in prnt {print line1.length}

[6] print line1.length in prnt
(dbx)  rerun

19                                 [1]
14
19

.
.
.
17 59 45 12
More (n if no)?
(dbx)  delete 6
(dbx)  when in prnt {stop}
[7] stop in prnt
(dbx)  rerun

[7] stopped at [prnt:52,0x12000fb0] fprintf(stdout,"%3d.(%3d) %s",
    |
   [2]

  1. Value of line1.length. [Return to example]

  2. Stops in the procedure prnt. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.8.5    Catching and Ignoring Signals

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:

catch
Displays a list of all signals that dbx catches.


catch SIGNAL
Adds a signal to the catch list.

ignore
Displays a list of all signals that dbx does not catch.


ignore SIGNAL
Removes a signal from the catch list and adds it to the ignore list.

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]
HUP KILL ALRM TSTP CONT CHLD
(dbx)  catch kill                               [3]
(dbx)  catch

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
HUP ALRM TSTP CONT CHLD
(dbx) 

The backslashes in this example represent line continuation. The actual output from catch and ignore is a single line.

  1. Displays the catch list. [Return to example]

  2. Displays the ignore list. [Return to example]

  3. Adds KILL to the catch list and removes KILL from the ignore list. [Return to example]


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9    Examining Program State

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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9.1    Printing the Values of Variables and Expressions

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

Table Note:

  1. The program status register is useful only for kernel debugging. For user-level programs, its value is always 8.

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:

print EXP1,...,EXPN
Displays the value of the specified expressions.

printf "STRING", EXP1,...,EXPN
Displays the value of the specified expressions in the format specified by the string.

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

14            [1]
(dbx)  po i
016           [2]
(dbx)  px i
0xe           [3]
(dbx)  pd i
14            [4]
(dbx) 


  1. Decimal [Return to example]

  2. Octal [Return to example]

  3. Hexadecimal [Return to example]

  4. Decimal [Return to example]

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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9.2    Displaying Activation-Level Information with the dump Command

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:

dump
Displays information about the current activation level.

dump .
Displays information about all activation levels.

dump PROCEDURE
Displays information about the specified procedure (activation level).


For example:

(dbx)  where

>  0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
   1 main(argc = 2, argv = 0x11ffffe08) ["sam.c":45, 0x120000bac]
(dbx)  dump
prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]
(dbx)  dump .

>  0 prnt(pline = 0x11ffffcb8) ["sam.c":52, 0x120000c04]

 
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)  dump main
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)


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9.3    Displaying the Contents of Memory

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.

Table 5-9: Modes for Displaying Memory Addresses

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


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9.4    Recording and Playing Back Portions of a dbx Session

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9.4.1    Recording and Playing Back Input

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:

record input [FILE]
Begins recording dbx commands in the specified file or, if no file is specified, in a file placed in /tmp and given a generated name.


playback input [FILE]
source [FILE]
Executes the commands from the specified file or, if no file is specified, from the temporary file. The two forms are identical in function.

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) 

  1. Start recording. [Return to example]

  2. Stop recording. [Return to example]

  3. Play back the recorded input. As events 3 and 4 are played, they create duplicates of themselves, numbered 5 and 6, respectively. [Return to example]

  4. The debugger displays this error message because event 2, the command to begin recording, was deleted when recording was stopped. [Return to example]

The temporary file resulting from the preceding dbx commands contains the following text:

status
stop in prnt
when i = 19 {stop}
delete 2


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.9.4.2    Recording and Playing Back Output

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:

record output [FILE]
Begins recording dbx output in the specified file or, if no file is specified, in a file placed in /tmp and given a generated name.

playback output [FILE]
Displays recorded output from the specified file or, if no file is specified, from the temporary file.

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) 



[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.10    Debugging a Running Process

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:

attach process-id
The process-id argument is the process ID of the process you want to attach to.

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:

detach [process-id]
The optional process-id argument is the process ID of the process you want to detach from. If no argument is given, dbx detaches from the current process.

To change from one process to another, use the dbx command switch, which has the following form:

switch process-id
The process-id argument is the process ID of the process you want to switch to. You must already have attached to a process before you can switch to it. You can use the alias sw for the switch command.

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:

plist
Displays a list of active processes and their status. Indicates the current process with a marker: -->


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.11    Debugging Multithreaded Applications

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:

tset [EXP]
Choose a thread to be the current thread. The EXP argument is the hexadecimal ID of the desired thread.


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:

tstack [EXP]
Display stack traces for all threads.

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.

 
main: 50 pthread_t me = pthread_self(), timer_thread;
(dbx)  stop in do_tick
[2] stop in do_tick
(dbx)  stop at 85
[3] stop at "twait.c":85
(dbx)  stop at 35
[4] stop at "twait.c":35
(dbx)  run

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
29
(dbx)  cont

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

 
Program terminated normally
 
(dbx)  tlist
(dbx)  quit


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Section] [Next Chapter] [Index] [Help]


5.12    Debugging Multiple Asynchronous Processes

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.


[Return to Library] [Contents] [Previous Chapter] [Previous Section] [Next Chapter] [Index] [Help]


5.13    Sample Program

Example 5-1 is the sample C program (sam.c) that is referred to in examples throughout this chapter.

Example 5-1: Sample Program Used in dbx Examples

#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); }