2008-08-14

How to generate breakpoints from the source code ?

In order to ease debugging an issue, it may be wise to introduce breakpoints in your code directly at the source code level.

On POSIX compliant systems raising the SIGTRAP signal does the job. It is my preferred approach since it is portable across different OSes implementing signals, but also across architectures. I already used it successfully on Linux/x86, Linux/x86_64, Linux/ia64, Solaris/Sparc and AIX/PowerPC.
Another popular approach according to my google searches is to trigger interrupt 3 on x86 architecture (i.e. asm("int $3")). However it is not as portable as the previous method.

Example (view source repository):
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

int main(
int argc __attribute__((unused)),
char **args __attribute__((unused))
){
puts("Something really wrong happend,"
"break here to help investigation.");
raise(SIGTRAP); /* Software Breakpoint */
puts("This sentence is after the breakpoint.");

return EXIT_SUCCESS;
}


As you can see in this example it is as easy as adding raise(SIGTRAP); where you would like to break.

Now if you run the resulting program your program will stop were you raise the SIGTRAP signal. If you are running the program standalone it will just stop there with a message like this:
Something really wrong happend, break here to help investigation.
Trace/breakpoint trap


If you have core dumps allowed on your system (see man ulimit especially the -c option for more details), you will see the following:
Something really wrong happend, break here to help investigation.
Trace/breakpoint trap (core dumped)

At that point you have a core dump with all the debugging information you need to investigate your issue. Now you can run gdb yourExecutable core to investigate:
(gdb) bt
#0  0xb7f89410 in __kernel_vsyscall ()
#1  0xb7e65101 in raise () from /lib/libc.so.6
#2  0x0804840d in main () at main.c:29
[...]

This proves very useful if you have difficulties identifying an issue with a live debugging session, but you know you can trigger it in "production" conditions.

Last but not least, you can start your executable directly in gdb. Your breakpoint will then be caught by gdb:
(gdb) run
Starting program: /home/julien/Projects/juliensexperiments/generate_software_breakpoint/generate_software_breakpoint
Something really wrong happend, break here to help investigation.

Program received signal SIGTRAP, Trace/breakpoint trap.
0xb7f67410 in __kernel_vsyscall ()
(gdb) c
Continuing.
This sentence is after the breakpoint.

Program exited normally.

As you can see I was able to continue behind the breakpoint, the same way you would with standard gdb breakpoints.

To sum-up the SIGTRAP signal allows source level breakpoints interpreted as such by debuggers, and allows core generation for off-production investigation.

The example code is available through subversion:
svn checkout http://juliensexperiments.googlecode.com/svn/trunk/generate_software_breakpoint generate_software_breakpoint
Just type scons to compile it.

No comments: