Monday, December 29, 2008

Backtrace and g++

Looking for printstack like option on other platforms(Linux), I came across the backtrace call in libc.

It works similar to the Solaris printstack call..

libc backtrace manual


#include < execinfo.h >
#include < stdio.h >
#include < stdlib.h >

/* Obtain a backtrace and print it to stdout. */
void print_trace ()
{
void *array[10];
size_t size;
char **strings;
size_t i;

size = backtrace (array, 10);
strings = backtrace_symbols (array, size);

printf ("Obtained %d stack frames.\n", size);

for (i = 0; i < size; i++)
printf ("%s\n", strings[i]);

free (strings);
}

/* A dummy function to make the backtrace more interesting. */
void dummy_function()
{
print_trace ();
}

int main()
{
dummy_function ();
return 0;
}



We may have to pass special linker flags like -rdynamic to the gcc linker to get the correct symbol names. Its also better if we have a debug build of the executable.

$g++ -rdynamic temp.cpp
$./a.out
Obtained 5 stack frames.
./a.out(print_trace__Fv+0x14) [0x8048ca4]
./a.out(dummy_function__Fv+0xb) [0x8048d3f]
./a.out(main+0xb) [0x8048d53]
/lib/tls/libc.so.6(__libc_start_main+0xda) [0xd7079a]
./a.out(backtrace_symbols+0x3d) [0x8048bc1]


A more useful scenario will be to use backtrace and printstack inside a signal handler. It is a good way to gracefully handle the various signals rather than let the system core when it gets some signals. For a basic Backtrace Handler, the first thing we need to do is take hold of the signals. Some of the common ones are SIGSEGV, SIGILL and SIGBUS. abort() is usually called in the case of an assertion generates a SIGABRT.

When a signal occurs, we need to save or display our backtrace.


void signal_handler(int signo)
{
void *stack[20];
int count, i;

printf("Caught signal %d\n");

count = backtrace(stack, 20);
for (i=0; i < count; i++) {
printf("Frame %2d: %p\n", i+1, stack[i]);
}
}

int main()
{
signal(SIGBUS, signal_handler);

signal(SIGILL, signal_handler);
signal(SIGSEGV, signal_handler);
signal(SIGABRT, signal_handler);
}


It will be easy to implement a c++ class which should work for all the platforms. If we need a stack trace, simply create an object of it. This should produce the stack trace easily..

No comments: