This chapter describes how to set, clear, and list breakpoints and traces, and how to use watchpoints.
The chapter is organized into the following sections:
The stop, when, and trace commands are called event management commands. Event management refers to the general capability of dbx to perform certain actions when certain events take place in the program being debugged.
There are three types of breakpoint action commands:
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 breakpoints. The program halts and dbx executes one or more debugging commands, then the program continues (unless one of the commands is stop).
trace breakpoints. the program halts and an event-specific trace information line is emitted, then the program continues.
You can set a breakpoint at a line number, using the dbx stop at command:
(dbx) stop at filename: n
where n is a source code line number and filename is an optional program file name qualifier. For example
(dbx)stop at main.cc:3
If the line specified in a stop or when command is not an executable line of source code, dbx sets the breakpoint at the next executable line.
A when breakpoint command accepts other dbx commands like list, allowing you to write your own version of trace.
(dbx) when at 123 { list $lineno;} |
when operates with an implied cont command. In the example above, after listing the source code at the current line, the program continues executing.
dbx provides full debugging support for code that makes use of the programmatic interface to the run-time linker; code that calls dlopen(), dlclose() and their associated functions. The run-time linker binds and unbinds shared libraries during program execution. Debugging support for dlopen()/dlclose() allows you to step into a function or set a breakpoint in functions in a dynamically shared library just as you can in a library linked when the program is started.
There are three exceptions:
You cannot set a breakpoint in a library loaded by dlopen()before that library is loaded by dlopen().
You cannot set a breakpoint in a filter library loaded by dlopen() until the first function in it is called.
When a library is loaded by dlopen(), an initialization routine named _init() is called. This routine may call other routines in the library. dbx cannot place breakpoints in the loaded library until after this initialization is completed. You cannot have dbx stop at _init() in a library loaded by dlopen().
You may want to 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.
To set a when breakpoint, use when inmember.
For example, if the function draw is defined in several different classes, then to place a breakpoint in each function :
(dbx) stop inmember draw
To set a breakpoint in all member functions of a specific class, use the stop inclass command.
To set a when breakpoint, use when inclass.
To set a breakpoint in all member functions of the class draw:
(dbx) stop inclass draw
Breakpoints are inserted in only the class member functions defined in the class. It does not include those that it may inherit from base classes.
Due to the large number of breakpoints that may be inserted by stop inclass and other breakpoint selections, you should be sure to set your dbxenv step_events to on to speed up step and next.
To set multiple breakpoints in nonmember functions with overloaded names (same name, different type or number of arguments), use the stop infunction command.
To set a when breakpoint, use when infunction.
For example, if a C++ program has defined two versions of a function named sort(), one which passes an int type argument, the other a float, then, to place a breakpoint in both functions:
(dbx) when infunction sort {cmd;}
Set an In Object breakpoint to check the operations applied to a specific object. An In Object breakpoint suspends program execution in all nonstatic member functions of the object's class when called from the object.
To set a breakpoint in object foo:
(dbx) stop inobject foo
Tracing displays information about the line of code about to be executed or a function about to be called.
Set a trace by typing a trace command at the command line. Table 5-1 shows the command syntax for the types of traces that you can set. The information a trace provides depends on the type of event associated with it.
Table 5-1 trace Command Syntax
Command |
trace prints ... |
---|---|
trace step |
Every line in the program as it is about to be executed |
trace next -in function |
Every line while the program is in the function |
trace at line_number |
The line number and the line itself, as that line becomes the next line to be executed |
trace in function |
The name of the function that called function; line number, parameters passed in, and return value |
trace inmember member_function |
The name of the function that called member_function of any class; its line number, parameters passed in, and its return value |
trace inclass class |
The name of the function that called any member_function in class; its line number, parameters passed in, and return value |
trace infunction function |
The name of the function that called any member_function in class; its line number, parameters passed in, and return value |
trace change variable [-in function] |
The new value of variable, if it changes, and the line at which it changed |
In many programs, code execution is too fast to view the code. The dbxenv trace_speed allows you to control the delay after each trace is printed. The default delay is 0.5 seconds.
To set the interval between execution of each line of code during a trace:
dbxenv trace_speed number
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 print ID numbers in parentheses, which can then be used by other commands.
As noted, 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 prints 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:
(dbx) delete 3 5
To delete all breakpoints set in the program currently loaded in dbx:
(dbx) delete all
Watchpointing is the capability of dbx to note when the value of a variable or expression has changed.
To stop program execution when the contents of an address is written to:
(dbx) stop modify &variable
Keep these points in mind when using stop modify:
The event occurs when a variable gets written to even if it is the same value.
The event occurs before the instruction that wrote to the variable is executed, although the new contents of the memory are preset by dbx by emulating the instruction.
You cannot use addresses of stack variables, for example, auto function local variables.
To stop program execution if the value of a specified variable has changed:
(dbx) stop change variable
Keep these points in mind when using stop change:
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.
dbx implements stop change by causing automatic single stepping together with a check on the value at each step. Stepping skips over library calls. So, if control flows in the following manner:
user_routine calls library_routine, which calls user_routine2, which changes variable
dbx does not trace the nested user_ routine2 because tracing skips the library call and the nested call to user_routine2, so 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.
To stop program execution if a conditional statement evaluates to true:
(dbx) stop cond condition
A faster way of setting watchpoints is to use the modify command. Instead of automatically single-stepping the program, it uses a page protection scheme which is much faster. The speed depends on how many times the page on which the variable you are watching is modified, as well as the overall system call rate of the program being debugged.
In dbx, most of the event management commands also support an optional event filter modifier statement. The simplest filter instructs dbx to test for a condition after the program arrives at a breakpoint or trace handler, or after a watch condition occurs.
If this filter condition evaluates to true (non 0), the event command applies. If the condition evaluates to false (0), dbx continues program execution as if the event never happened.
To set a breakpoint at a line or in a function that includes a conditional filter, 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 location-based breakpoints like in or at, the scope 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 may have to use syntax to specify the scope precisely.
These two filters are not the same:
stop in foo -if a>5 stop cond a>5
The former will breakpoint at foo and test the condition. The latter automatically single-steps and tests for the condition.
This point is emphasized because 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.
(dbx) stop modify &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 to see if the new value of speed is equal to fast_enough. If it is not, the program continues on, "ignoring" the stop.
In dbx syntax, the filter is represented in the form of an [-if condition] statement at the end of the formula:
stop in function [-if condition ]
Various events have varying 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. This is because 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.
In the case of step and next, 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 step and next slows down considerably. Use the dbxenv step_events to control whether breakpoints are taken out and reinserted after each step or next.
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 watchpoints 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 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 in the cases where you suspect that the lookup() function is clobbering your variable.