(This article is an adaptation of this thing in Spanish I wrote in 2008. It’s nothing groundbreaking but a good friend of mine suggested a few days ago that it was still useful to him, so I decided to put it here. The new title is a reference to the poor man’s profiler, which you will probably like if you like this post)
Everyone of us has resorted at some point to printf-based debugging. Traces can be very useful, either because you want to see at a glance how a given value is changing over time or because stopping a thread at a breakpoint to examine some values can vanish the same race condition you are trying to debug. Nevertheless, inserting printf statements is a boring task, which makes you recompile everytime you want to change the set of values you want to see.
Ideally we could use tracepoints in our favorite debugger to collect some values and later dump them to a log, and gdb supports them but as the documentation points out:
The tracepoint facility is currently available only for remote targets. See Targets. 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.
So, if our platform doesn’t support tracepoints… are we stuck with printf()? Well, yes and no. It turns out gdb allows us to specify actions to be executed at a breakpoint, so you can tell it to, every time it passes by some point in your program, print whatever you want and continue running. It’s not as good as the real deal, because a tracepoint would be more lightweight, but it can be helpful nonetheless.
Let’s see how to do it. Consider the following C program:
1
2
3
4
5
6
7
8
9
10
| #include <stdio.h>
int main()
{
int i;
double x=2.0f;
for (i=0; i<64; i++)
x*=2;
return 0;
} |
#include <stdio.h>
int main()
{
int i;
double x=2.0f;
for (i=0; i<64; i++)
x*=2;
return 0;
}
if we compile it with debug info and launch it on gdb, we can log the values of x doing this:
(gdb) break 8
Breakpoint 1 at 0x400463: file a.c, line 8.
(gdb) commands 1
Type commands for when breakpoint 1 is hit, one per line.
End with a line saying just "end".
>silent
>printf "x=%g\n",x
>cont
>end
(gdb) r
Starting program: /home/slack/a.out
x=2
x=4
x=8
The “silent” keyword as first action means that gdb shouldn’t print the info about the current stack frame it usually prints when stopping at a breakpoint, and the rest should be pretty self-explaining. In addition to gdb’s printf function you can also use more complex gdb expresions so you could, for instance, traverse a list and log its values or stuff like that :)
Happy coding!