[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In some applications, it is not feasible for the debugger to interrupt the program's execution long enough for the developer to learn anything helpful about its behavior. If the program's correctness depends on its real-time behavior, delays introduced by a debugger might cause the program to change its behavior drastically, or perhaps fail, even when the code itself is correct. It is useful to be able to observe the program's behavior without interrupting it.
Using GDB's trace
and collect
commands, you can
specify locations in the program, called tracepoints, and
arbitrary expressions to evaluate when those tracepoints are reached.
Later, using the tfind
command, you can examine the values
those expressions had when the program hit the tracepoints. The
expressions may also denote objects in memory--structures or arrays,
for example--whose values GDB should record; while visiting
a particular tracepoint, you may inspect those objects as if they were
in memory at that moment. However, because GDB records these
values without interacting with you, it can do so quickly and
unobtrusively, hopefully not disturbing the program's behavior.
The tracepoint facility is currently available only for remote targets. See section 16. Specifying a Debugging Target. In addition, your remote target must know how to collect trace data. This functionality is implemented in the remote stub; however, none of the stubs distributed with GDB support tracepoints as of this writing.
This chapter describes the tracepoint commands and features.
10.1 Commands to Set Tracepoints 10.2 Using the collected data 10.3 Convenience Variables for Tracepoints
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Before running such a trace experiment, an arbitrary number of tracepoints can be set. Like a breakpoint (see section 5.1.1 Setting breakpoints), a tracepoint has a number assigned to it by GDB. Like with breakpoints, tracepoint numbers are successive integers starting from one. Many of the commands associated with tracepoints take the tracepoint number as their argument, to identify which tracepoint to work on.
For each tracepoint, you can specify, in advance, some arbitrary set of data that you want the target to collect in the trace buffer when it hits that tracepoint. The collected data can include registers, local variables, or global data. Later, you can use GDB commands to examine the values these data had at the time the tracepoint was hit.
This section describes commands to set tracepoints and associated conditions and actions.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
trace
trace
command is very similar to the break
command.
Its argument can be a source line, a function name, or an address in
the target program. See section 5.1.1 Setting breakpoints. The trace
command
defines a tracepoint, which is a point in the target program where the
debugger will briefly stop, collect some data, and then allow the
program to continue. Setting a tracepoint or changing its commands
doesn't take effect until the next tstart
command; thus, you
cannot change the tracepoint attributes once a trace experiment is
running.
Here are some examples of using the trace
command:
(gdb) trace foo.c:121 // a source file and line number (gdb) trace +2 // 2 lines forward (gdb) trace my_function // first source line of function (gdb) trace *my_function // EXACT start address of function (gdb) trace *0x2117c4 // an address |
You can abbreviate trace
as tr
.
The convenience variable $tpnum
records the tracepoint number
of the most recently set tracepoint.
delete tracepoint [num]
Examples:
(gdb) delete trace 1 2 3 // remove three tracepoints (gdb) delete trace // remove all tracepoints |
You can abbreviate this command as del tr
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
disable tracepoint [num]
enable tracepoint
command.
enable tracepoint [num]
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
passcount [n [num]]
passcount
command sets the
passcount of the most recently defined tracepoint. If no passcount is
given, the trace experiment will run until stopped explicitly by the
user.
Examples:
(gdb) passcount 5 2 // Stop on the 5th execution of |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
actions [num]
actions
without bothering about its number). You specify the
actions themselves on the following lines, one action at a time, and
terminate the actions list with a line containing just end
. So
far, the only defined actions are collect
and
while-stepping
.
To remove all actions from a tracepoint, type `actions num' and follow it immediately with `end'.
(gdb) collect data // collect some data (gdb) while-stepping 5 // single-step 5 times, collect data (gdb) end // signals the end of actions. |
In the following example, the action list begins with collect
commands indicating the things to be collected when the tracepoint is
hit. Then, in order to single-step and collect additional data
following the tracepoint, a while-stepping
command is used,
followed by the list of things to be collected while stepping. The
while-stepping
command is terminated by its own separate
end
command. Lastly, the action list is terminated by an
end
command.
(gdb) trace foo (gdb) actions Enter actions for tracepoint 1, one per line: > collect bar,baz > collect $regs > while-stepping 12 > collect $fp, $sp > end end |
collect expr1, expr2, ...
$regs
$args
$locals
You can give several consecutive collect
commands, each one
with a single argument, or one collect
command with several
arguments separated by commas: the effect is the same.
The command info scope
(see section info scope) is
particularly useful for figuring out what data to collect.
while-stepping n
while-stepping
command is
followed by the list of what to collect while stepping (followed by
its own end
command):
> while-stepping 12 > collect $regs, myglobal > end > |
You may abbreviate while-stepping
as ws
or
stepping
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
info tracepoints [num]
passcount n
command
while-stepping n
command
actions
command
(gdb) info trace Num Enb Address PassC StepC What 1 y 0x002117c4 0 0 <gdb_asm> 2 y 0x0020dc64 0 0 in g_test at g_test.c:1375 3 y 0x0020b1f4 0 0 in get_data at ../foo.c:41 (gdb) |
This command can be abbreviated info tp
.
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
tstart
tstop
Note: a trace experiment and data collection may stop automatically if any tracepoint's passcount is reached (see section 10.1.3 Tracepoint Passcounts), or if the trace buffer becomes full.
tstatus
Here is an example of the commands we described so far:
(gdb) trace gdb_c_test (gdb) actions Enter actions for tracepoint #1, one per line. > collect $regs,$locals,$args > while-stepping 11 > collect $regs > end > end (gdb) tstart [time passes ...] (gdb) tstop |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
After the tracepoint experiment ends, you use GDB commands
for examining the trace data. The basic idea is that each tracepoint
collects a trace snapshot every time it is hit and another
snapshot every time it single-steps. All these snapshots are
consecutively numbered from zero and go into a buffer, and you can
examine them later. The way you examine them is to focus on a
specific trace snapshot. When the remote stub is focused on a trace
snapshot, it will respond to all GDB requests for memory and
registers by reading from the buffer which belongs to that snapshot,
rather than from real memory or registers of the program being
debugged. This means that all GDB commands
(print
, info registers
, backtrace
, etc.) will
behave as if we were currently debugging the program state as it was
when the tracepoint occurred. Any requests for data that are not in
the buffer will fail.
10.2.1 tfind n
How to select a trace snapshot 10.2.2 tdump
How to display all data for a snapshot 10.2.3 save-tracepoints filename
How to save tracepoints for a future run
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
tfind n
The basic command for selecting a trace snapshot from the buffer is
tfind n
, which finds trace snapshot number n,
counting from zero. If no argument n is given, the next
snapshot is selected.
Here are the various forms of using the tfind
command.
tfind start
tfind 0
(since 0 is the number of the first snapshot).
tfind none
tfind end
tfind
tfind -
tfind tracepoint num
tfind pc addr
tfind outside addr1, addr2
tfind range addr1, addr2
tfind line [file:]n
tfind line
repeatedly can appear to have the same effect as
stepping from line to line in a live debugging session.
The default arguments for the tfind
commands are specifically
designed to make it easy to scan through the trace buffer. For
instance, tfind
with no argument selects the next trace
snapshot, and tfind -
with no argument selects the previous
trace snapshot. So, by giving one tfind
command, and then
simply hitting RET repeatedly you can examine all the trace
snapshots in order. Or, by saying tfind -
and then hitting
RET repeatedly you can examine the snapshots in reverse order.
The tfind line
command with no argument selects the snapshot
for the next source line executed. The tfind pc
command with
no argument selects the next snapshot with the same program counter
(PC) as the current frame. The tfind tracepoint
command with
no argument selects the next trace snapshot collected by the same
tracepoint as the current one.
In addition to letting you scan through the trace buffer manually, these commands make it easy to construct GDB scripts that scan through the trace buffer and print out whatever collected data you are interested in. Thus, if we want to examine the PC, FP, and SP registers from each trace frame in the buffer, we can say this:
(gdb) tfind start (gdb) while ($trace_frame != -1) > printf "Frame %d, PC = %08X, SP = %08X, FP = %08X\n", \ $trace_frame, $pc, $sp, $fp > tfind > end Frame 0, PC = 0020DC64, SP = 0030BF3C, FP = 0030BF44 Frame 1, PC = 0020DC6C, SP = 0030BF38, FP = 0030BF44 Frame 2, PC = 0020DC70, SP = 0030BF34, FP = 0030BF44 Frame 3, PC = 0020DC74, SP = 0030BF30, FP = 0030BF44 Frame 4, PC = 0020DC78, SP = 0030BF2C, FP = 0030BF44 Frame 5, PC = 0020DC7C, SP = 0030BF28, FP = 0030BF44 Frame 6, PC = 0020DC80, SP = 0030BF24, FP = 0030BF44 Frame 7, PC = 0020DC84, SP = 0030BF20, FP = 0030BF44 Frame 8, PC = 0020DC88, SP = 0030BF1C, FP = 0030BF44 Frame 9, PC = 0020DC8E, SP = 0030BF18, FP = 0030BF44 Frame 10, PC = 00203F6C, SP = 0030BE3C, FP = 0030BF14 |
Or, if we want to examine the variable X
at each source line in
the buffer:
(gdb) tfind start (gdb) while ($trace_frame != -1) > printf "Frame %d, X == %d\n", $trace_frame, X > tfind line > end Frame 0, X = 1 Frame 7, X = 2 Frame 13, X = 255 |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
tdump
This command takes no arguments. It prints all the data collected at the current trace snapshot.
(gdb) trace 444 (gdb) actions Enter actions for tracepoint #2, one per line: > collect $regs, $locals, $args, gdb_long_test > end (gdb) tstart (gdb) tfind line 444 #0 gdb_test (p1=0x11, p2=0x22, p3=0x33, p4=0x44, p5=0x55, p6=0x66) at gdb_test.c:444 444 printp( "%s: arguments = 0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n", ) (gdb) tdump Data collected at tracepoint 2, trace frame 1: d0 0xc4aa0085 -995491707 d1 0x18 24 d2 0x80 128 d3 0x33 51 d4 0x71aea3d 119204413 d5 0x22 34 d6 0xe0 224 d7 0x380035 3670069 a0 0x19e24a 1696330 a1 0x3000668 50333288 a2 0x100 256 a3 0x322000 3284992 a4 0x3000698 50333336 a5 0x1ad3cc 1758156 fp 0x30bf3c 0x30bf3c sp 0x30bf34 0x30bf34 ps 0x0 0 pc 0x20b2c8 0x20b2c8 fpcontrol 0x0 0 fpstatus 0x0 0 fpiaddr 0x0 0 p = 0x20e5b4 "gdb-test" p1 = (void *) 0x11 p2 = (void *) 0x22 p3 = (void *) 0x33 p4 = (void *) 0x44 p5 = (void *) 0x55 p6 = (void *) 0x66 gdb_long_test = 17 '\021' (gdb) |
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
save-tracepoints filename
This command saves all current tracepoint definitions together with
their actions and passcounts, into a file `filename'
suitable for use in a later debugging session. To read the saved
tracepoint definitions, use the source
command (see section 20.3 Command files).
[ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
(int) $trace_frame
(int) $tracepoint
(int) $trace_line
(char []) $trace_file
(char []) $trace_func
$tracepoint
.
Note: $trace_file
is not suitable for use in printf
,
use output
instead.
Here's a simple example of using these convenience variables for stepping through all the trace snapshots and printing some of their data.
(gdb) tfind start (gdb) while $trace_frame != -1 > output $trace_file > printf ", line %d (tracepoint #%d)\n", $trace_line, $tracepoint > tfind > end |
[ << ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |