When an event occurs, dbx allows you to stop a process, execute arbitrary commands, or print information. The simplest example of an event is a breakpoint. Examples of other events are faults, signals, system calls, calls to dlopen(), and data changes.
A trace displays information about an event in your program, such as a change in the value of a variable. Although a trace’s behavior is different from that of a breakpoint, traces and breakpoints share similar event handlers (see Event Handlers).
This chapter describes how to set, clear, and list breakpoints and traces. For complete information on the event specifications you can use in setting breakpoints and traces, see Setting Event Specifications.
This chapter is organized into the following sections:
In dbx, you can use three commands to set breakpoints:
stop breakpoints. If the program arrives at a breakpoint created with a stop command, the program halts. The program cannot resume until you issue another debugging command, such as cont, step, or next.
when breakpoint. If the program arrives at a breakpoint created with a when command, the program halts and dbx executes one or more debugging commands, then the program continues (unless one of the executed commands is stop).
trace breakpoints. If a program arrives at a breakpoint created with a trace command, the program halts and an event-specific trace information line is emitted, then the program continues.
The stop, when, and trace commands all take as an argument an event specification, which describes the event on which the breakpoint is based. Event specifications are discussed in detail in Setting Event Specifications.
To set machine-level breakpoints, use the stopi, wheni, and tracei commands (see Chapter 18, Debugging at the Machine-Instruction Level).
When debugging an application that is a mixture of JavaTM code and C JNI (Java Native Interface) code or C++ JNI code, you may want to set breakpoints in code that has not yet been loaded. For information on setting breakpoints on such code, see Setting Breakpoints in Native (JNI) Code.
You can set a breakpoint at a line number, using the stop at command, where n is a source code line number and filename is an optional program file name qualifier.
(dbx) stop at filename:n |
For example
(dbx) stop at main.cc:3 |
If the line specified is not an executable line of source code, dbx sets the breakpoint at the next executable line. If there is no executable line, dbx issues an error.
You can determine the line at which you wish to stop by using the file command to set the current file and the list command to list the function in which you wish to stop. Then use the stop at command to set the breakpoint on the source line:
(dbx) file t.c (dbx) list main 10 main(int argc, char *argv[]) 11 { 12 char *msg = "hello world\n"; 13 printit(msg); 14 } (dbx) stop at 13 |
For more information on specifying at an location event, see at [filename:]line_number.
You can set a breakpoint in a function, using the stop in command:
(dbx) stop in function |
An In Function breakpoint suspends program execution at the beginning of the first source line in a procedure or function.
dbx should be able to determine which function you are referring to except when:
You reference an overloaded function by name only.
You reference a function with a leading `.
Consider the following set of declarations:
int foo(double); int foo(int); int bar(); class x { int bar(); }; |
To stop at a non-member function, you can type:
stop in foo(int) |
to set a breakpoint at the global foo(int).
To set a breakpoint at the member function you can use the command:
stop in x::bar() |
If you type:
stop in foo |
dbx cannot determine whether you mean the global function foo(int) or the global function foo(double) and may be forced to display an overloaded menu for clarification.
If you type:
stop in `bar |
dbx cannot determine whether you mean the global function bar() or the member function bar() and displays an overload menu.
For more information on specifying an in function event, see in function.
You can check for problems related to calls to members of different classes, calls to any members of a given class, or calls to overloaded top-level functions. You can use a keyword, inmember, inclass, infunction, or inobject, with a stop, when, or trace command to set multiple breaks in C++ code.
To set a breakpoint in each of the object-specific variants of a particular member function (same member function name, different classes), use stop inmember.
For example, if the function draw is defined in several different classes, then to place a breakpoint in each function, type:
(dbx) stop inmember draw |
For more information on specifying an inmember or inmethod event, see inmember function inmethod function.
To set a breakpoint in all member functions of a specific class, use the stop inclass command.
By default, breakpoints are inserted only in the class member functions defined in the class, not those that it might inherit from its base classes. To insert breakpoints in the functions inherited from the base classes also, specify the -recurse option.
To set a breakpoint in all member functions defined in the class shape, type:
(dbx) stop inclass shape |
To set a breakpoint in all member functions defined in the class shape, and also in functions inherited from the class, type:
(dbx) stop inclass shape -recurse |
For more information on specifying an inclass event, see inclass classname [-recurse | -norecurse] and stop Command.
Due to the large number of breakpoints that may be inserted by stop inclass and other breakpoint selections, you should be sure to set the dbx environment variable step_events to on to speed up the step and next commands (see Efficiency Considerations).
To set multiple breakpoints in nonmember functions with overloaded names (same name, different type or number of arguments), use the stop infunction command.
For example, if a C++ program has defined two versions of a function named sort()(one that passes an int type argument and the other a float) then, to place a breakpoint in both functions, type:
(dbx) stop infunction sort |
For more information on specifying an infunction event, see infunction function.
Set an In Object breakpoint to check the operations applied to a specific object instance.
By default, an In Object breakpoint suspends program execution in all nonstatic member functions of the object’s class, including inherited ones, when called from the object. To set a breakpoint to suspend program execution in only nonstatic member functions defined in the object’s class and not inherited classes, specify the -norecurse option.
To set a breakpoint in all nonstatic member functions defined in the base class of object foo, and in all nonstatic member functions defined in inherited classes of object foo, type:
(dbx) stop inobject &foo |
To set a breakpoint in all nonstatic member functions defined in the class of object foo, but not those defined in inherited classes of object foo, type:
(dbx) stop inobject &foo -norecurse |
For more information on specifying an inobject event, see inobject object-expression [-recurse | -norecurse] and stop Command
You can use data change breakpoints in dbx to note when the value of a variable or expression has changed.
To stop execution when a memory address has been accessed, type:
(dbx) stop access mode address-expression [, byte-size-expression] |
mode specifies how the memory was accessed. It can be composed of one or all of the letters:
The memory at the specified address has been read.
The memory has been written to.
The memory has been executed.
mode can also contain either of the following:
Stops the process after the access (default).
Stops the process before the access.
In both cases the program counter will point at the accessing instruction. The “before” and “after” refer to the side effect.
address-expression is any expression that can be evaluated to produce an address. If you give a symbolic expression, the size of the region to be watched is automatically deduced; you can override it by specifying byte-size-expression. You can also use nonsymbolic, typeless address expressions; in which case, the size is mandatory.
In the following example, execution will stop execution after any of the four bytes after the memory address 0x4762 has been read
(dbx) stop access r 0x4762, 4 |
In this example, execution will stop before the variable speed has be written to:
(dbx) stop access wb &speed |
Keep these points in mind when using the stop access command:
The event occurs when a variable is written to even if it is the same value.
By default, the event occurs after execution of the instruction that wrote to the variable. You can indicate that you want the event to occur before the instruction is executed by specifying the mode as b.
For more information on specifying an access event, see access mode address-expression [, byte-size-expression] and stop Command.
To stop program execution if the value of a specified variable has changed, type:
(dbx) stop change variable |
Keep these points in mind when using the stop change command:
dbx stops the program at the line after the line that caused a change in the value of the specified variable.
If variable is local to a function, the variable is considered to have changed when the function is first entered and storage for variable is allocated. The same is true with respect to parameters.
The command does not work with multithreaded applications.
For more information on specifying a change event, see change variable and stop Command.
dbx implements stop change by causing automatic single stepping together with a check on the value at each step. Stepping skips over library calls if the library was not compiled with the -g option. So, if control flows in the following manner, dbx does not trace the nested user_routine2 because tracing skips the library call and the nested call to user_routine2.
user_routine calls library_routine, which calls user_routine2, which changes variable |
The change in the value of variable appears to have occurred after the return from the library call, not in the middle of user_routine2.
dbx cannot set a breakpoint for a change in a block local variable, a variable nested in {}. If you try to set a breakpoint or trace in a block local “nested” variable, dbx issues an error informing you that it cannot perform this operation.
It is faster to watch data changes using the access event than the change event. Instead of automatically single-stepping the program, the access event uses hardware or OS services that are much faster.
To stop program execution if a conditional statement evaluates to true, type:
(dbx) stop cond condition |
The program stops executing when the condition occurs.
Keep these points in mind when using the stop cond command:
dbx stops the program at the line after the line that caused the condition to evaluate to true.
The command does not work with multithreaded applications.
For more information on specifying a condition event, see cond condition-expression and stop Command.
In dbx, most of the event management commands also support an optional event filter modifier. The simplest filter instructs dbx to test for a condition after the program arrives at a breakpoint or trace handler, or after a data change breakpoint occurs.
If this filter condition evaluates to true (non 0), the event command applies and program execution stops at the breakpoint. If the condition evaluates to false (0), dbx continues program execution as if the event had never happened.
To set a breakpoint that includes a filter at a line or in a function, add an optional- if condition modifier statement to the end of a stop or trace command.
The condition can be any valid expression, including function calls, returning Boolean or integer in the language current at the time the command is entered.
With a location-based breakpoint like in or at, the scope for parsing the condition is that of the breakpoint location. Otherwise, the scope of the condition is the scope at the time of entry, not at the time of the event. You might have to use the backquote operator (see Backquote Operator) to specify the scope precisely.
These two filters are not the same:
stop in foo -if a>5 stop cond a>5 |
The former breaks at foo and tests the condition. The latter automatically single steps and tests for the condition.
You can use a function call as a breakpoint filter. In this example, if the value in the string str is abcde, then execution stops in function foo():
(dbx) stop in foo -if !strcmp(“abcde”,str) |
Filters can be convenient when you are placing a data change breakpoint on a local variable. In the following example, the current scope is in function foo()(), while index, the variable of interest, is in function bar()().
(dbx) stop access w &bar`index -in bar |
bar`index ensures that the index variable in function bar()() is picked up, instead of the index variable in function foo() or a global variable named index.
-in bar implies the following:
The breakpoint is automatically enables when function bar() is entered.
The breakpoint remains enabled for the duration of bar()() including any functions it calls.
The breakpoint is automatically disabled upon return from bar()().
The stack location corresponding to index might be reused by some other local variable of some other function. -in ensures that the breakpoint is triggered only when bar`index is accessed.
New users sometimes confuse setting a conditional event command (a watch-type command) with using filters. Conceptually, “watching” creates a precondition that must be checked before each line of code executes (within the scope of the watch). But even a breakpoint command with a conditional trigger can also have a filter attached to it.
Consider this example:
(dbx) stop access w &speed -if speed==fast_enough |
This command instructs dbx to monitor the variable, speed; if the variable speed is written to (the “watch” part), then the -if filter goes into effect. dbx checks whether the new value of speed is equal to fast_enough. If it is not, the program continues, “ignoring” the stop command.
In dbx syntax, the filter is represented in the form of an [-if condition] statement at the end of the command.
stop in function [-if condition] |
If you set a breakpoint with a filter that contains function calls in a multithreaded program, dbx stops execution of all threads when it hits the breakpoint, and then evaluates the condition. If the condition is met and the function is called, dbx resumes all threads for the duration of the call.
For example, you might set the following breakpoint in a multithreaded application where many threads call lookup():
(dbx) stop in lookup -if strcmp(name, “troublesome”) == 0 |
dbx stops when thread t@1 calls lookup(), evaluates the condition, and calls strcmp() resuming all threads. If dbx hits the breakpoint in another thread during the function call, it issues a warning such as one of the following:
event infinite loop causes missed events in the following handlers: ... |
Event reentrancy first event BPT(VID 6m TID 6, PC echo+0x8) second event BPT*VID 10, TID 10, PC echo+0x8) the following handlers will miss events: ... |
In such a case, if you can ascertain that the function called in the conditional expression will not grab a mutex, you can use the -resumeone event specification modifier to force dbx to resume only the first thread in which it hit the breakpoint. For example, you might set the following breakpoint:
(dbx) stop in lookup -resumeone -if strcmp(name, “troublesome”) == 0 |
The -resumeone modifier does not prevent problems in all cases. For example, it would not help if:
The second breakpoint on lookup() occurs in the same thread as the first because the condition recursively calls lookup().
The thread on which the condition runs relinquishes control to another thread.
For detailed information on event modifiers, see Event Specification Modifiers.
Tracing collects information about what is happening in your program and displays it. If a program arrives at a breakpoint created with a trace command, the program halts and an event-specific trace information line is emitted, then the program continues.
A trace displays each line of source code as it is about to be executed. In all but the simplest programs, this trace produces volumes of output.
A more useful trace applies a filter to display information about events in your program. For example, you can trace each call to a function, every member function of a given name, every function in a class, or each exit from a function. You can also trace changes to a variable.
Set a trace by typing a trace command at the command line. The basic syntax of the trace command is:
trace event-specification [ modifier ] |
For the complete syntax of the trace command, see trace Command.
The information a trace provides depends on the type of event associated with it (see Setting Event Specifications).
Often trace output goes by too quickly. The dbx environment variable trace_speed lets you control the delay after each trace is printed. The default delay is 0.5 seconds.
To set the interval in seconds between execution of each line of code during a trace, type:
dbxenv trace_speed number |
You can direct the output of a trace to a file using the -file filename option. For example, the following command direct trace output to the file trace1:
(dbx) trace -file trace1 |
To revert trace output to standard output use - for filename. Trace output is always appended to filename. It is flushed whenever dbx prompts and when the application has exited. The filename is always re-opened on a new run or resumption after an attach.
A when breakpoint command accepts other dbx commands such as list, letting you write your own version of trace.
(dbx) when at 123 {list $lineno;} |
The when command operates with an implied cont command. In the example above, after listing the source code at the current line, the program continues executing. If you included a stop command after the list command, the program would not continue executing.
For the complete syntax of the when command, see when Command. For detailed information on event modifiers, see Event Specification Modifiers.
dbx interacts with the following types of shared libraries:
Libraries that are implicitly loaded at the beginning of a program's execution.
Libraries that are explicitly (dynamically) loaded using dlopen(2)(). The names in such libraries are known only after the library has been loaded during a run, so you cannot place breakpoints in them after starting a debugging session with a debug or attach command.
Filter libraries that are explicitly loaded using dlopen(2)(). The names in such libraries are know only after the library has been loaded and the first function in it has been called.
You can set breakpoints in explicitly (dynamically) loaded libraries in two ways:
If you have a library, for example, mylibrary.so, which contains a function myfunc()(), you could preload the library's symbol tale into dbx and set a breakpoint on the function as follows:
(dbx) loadobject -load fullpathto/mylibrary.so (dbx) stop in myfunc |
Alternatively, a much easier way is to run your program under dbx to completion. dbx records and remembers all shared libraries that are loaded with dlopen(2)(), even if they are closed with dlclose()(). So after the first run of the program, you will be able to set breakpoints successfully:
(dbx) run execution completed, exit code is 0 (dbx) loadobject -list u myprogram (primary) u /lib/libc.so.1 u p /platform/sun4u-us3/lib/libc_psr.so.1 u fullpathto/mylibrary.so (dbx) stop in myfunc |
Often, you set more than one breakpoint or trace handler during a debugging session. dbx supports commands for listing and clearing them.
To display a list of all active breakpoints, use the status command to display ID numbers in parentheses, which can then be used by other commands.
dbx reports multiple breakpoints set with the inmember, inclass, and infunction keywords as a single set of breakpoints with one status ID number.
When you list breakpoints using the status command, dbx displays the ID number assigned to each breakpoint when it was created. Using the delete command, you can remove breakpoints by ID number, or use the keyword all to remove all breakpoints currently set anywhere in the program.
To delete breakpoints by ID number (in this case 3 and 5), type:
(dbx) delete 3 5 |
To delete all breakpoints set in the program currently loaded in dbx, type:
(dbx) delete all |
For more information, see delete Command.
Each event management command (stop, trace, when) that you use to set a breakpoint creates an event handler (see Event Handlers). Each of these commands returns a number known as the handler ID (hid). You can use the handler ID as an argument to the handler command (see handler Command) to enable or disable the breakpoint.
Various events have different degrees of overhead in respect to the execution time of the program being debugged. Some events, like the simplest breakpoints, have practically no overhead. Events based on a single breakpoint have minimal overhead.
Multiple breakpoints such as inclass, that might result in hundreds of breakpoints, have an overhead only during creation time. dbx uses permanent breakpoints; the breakpoints are retained in the process at all times and are not taken out on every stoppage and put in on every cont command.
In the case of the step command and next command, by default all breakpoints are taken out before the process is resumed and reinserted once the step completes. If you are using many breakpoints or multiple breakpoints on prolific classes, the speed of the step command and next command slows down considerably. Use the dbx step_events environment variable to control whether breakpoints are taken out and reinserted after each step command or next command.
The slowest events are those that utilize automatic single stepping. This might be explicit and obvious as in the trace step command, which single steps through every source line. Other events, like the stop change expression or trace cond variable not only single step automatically but also have to evaluate an expression or a variable at each step.
These events are very slow, but you can often overcome the slowness by bounding the event with a function using the -in modifier. For example:
trace next -in mumble stop change clobbered_variable -in lookup |
Do not use trace -in main because the trace is effective in the functions called by main as well. Do use it in the cases where you suspect that the lookup() function is clobbering your variable.