[Beowulf] backtraces

Mark Hahn hahn at mcmaster.ca
Mon Jun 11 12:43:12 PDT 2007


>> It's highly dependant to implement but I should imagine most people who
>> need backtraces use a debugger,

suppose your program is running on a hundred nodes for a week 
before you hit the event you want the backtrace for...
yes, debugger+coredump can be used, but for obvious reasons,
we normally recommend users _not_ have them enabled.

>> the libc backtrace() function or
>> libbacktrace which can be use from either inside or outside the target
>> process, these tend to be platform independent.

I started with the libc backtrace function, but wanted something 
better than its backtrace_symbols() companion.

> libbacktrace is AFAICT also gcc specific. Or do you any pointers to some more 
> platform-info on libbacktrace ?

I believe it's binutils/libc-specific, not compiler-specific.  at least 
"pathcc -O3 -fno-inline-functions -g" gave me a meaningful backtrace on 
an mpi tester.

anyway, appended is my current version of backtrace.c - 
I think it's interesting and potentially useful, 
especially considering that it's not really complex:

/* print a backtrace.
    written by Mark Hahn, SHARCnet, 2007.

gcc -fPIC backtrace.c /usr/lib64/libbfd-2.15.92.0.2.so -shared -o backtrace.so

using -lbfd chokes on a symbol addressing issue with (static) libbfd.a on 
my system.  your libbfd version number may differ.

LD_PRELOAD=./backtrace.so ./tester
signal(11)
Obtained 9 stack frames.
file: /home/hahn/private/tester.c, line: 10, func dosegv
file: /home/hahn/private/tester.c, line: 14, func bar
file: /home/hahn/private/tester.c, line: 17, func foo
file: /home/hahn/private/tester.c, line: 29, func main

all symbols (globals and functions) are static to avoid contamination.

you need -g on the target program, and potentially something like
-fno-inline-functions to dissuade the compiler from disappearing 
some functions.
*/

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <signal.h>
#include <bfd.h>
#include <unistd.h>

#define MAX_FRAMES (20)

/* globals retained across calls to resolve. */
static bfd* abfd = 0;
static asymbol **syms = 0;
static asection *text = 0;

static void resolve(char *address) {
     if (!abfd) {
 	char ename[1024];
 	int l = readlink("/proc/self/exe",ename,sizeof(ename));
 	if (l == -1) {
 	    perror("failed to find executable\n");
 	    return;
 	}
 	ename[l] = 0;

 	bfd_init();

 	abfd = bfd_openr(ename, 0);
 	if (!abfd) {
 	    perror("bfd_openr failed: ");
 	    return;
 	}
 	/* oddly, this is required for it to work... */
 	bfd_check_format(abfd,bfd_object);

 	unsigned storage_needed = bfd_get_symtab_upper_bound(abfd);
 	syms = (asymbol **) malloc(storage_needed);
 	unsigned cSymbols = bfd_canonicalize_symtab(abfd, syms);

 	text = bfd_get_section_by_name(abfd, ".text");
     }
     long offset = ((long)address) - text->vma;
     if (offset > 0) {
         const char *file;
         const char *func;
         unsigned line;
         if (bfd_find_nearest_line(abfd, text, syms, offset, &file, &func, &line) && file)
             printf("file: %s, line: %u, func %s\n",file,line,func);
     }
}

static void print_trace() {
     void *array[MAX_FRAMES];
     size_t size;
     size_t i;
     void *approx_text_end = (void*) ((128+100) * 2<<20);

     size = backtrace (array, MAX_FRAMES);
     printf ("Obtained %zd stack frames.\n", size);
     for (i = 0; i < size; i++) {
 	if (array[i] < approx_text_end) {
 	    resolve(array[i]);
 	}
     }
}

static void handler(int sig) {
     printf("signal(%d)\n",sig);
     print_trace();
     _exit(1);
}

static void __attribute__((constructor)) init() {
     static struct sigaction sa;
     sa.sa_handler = handler;
     sigaction(SIGABRT, &sa, 0);
     sigaction(SIGFPE, &sa, 0);
     sigaction(SIGSEGV, &sa, 0);
}



More information about the Beowulf mailing list