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);
}
_______________________________________________
Beowulf mailing list, [email protected]
To change your subscription (digest mode or unsubscribe) visit 
http://www.beowulf.org/mailman/listinfo/beowulf

Reply via email to