How to print the stack information when the program crashes?

黄晋 icanlearn at tom.com
Sat Jun 19 06:59:42 UTC 2010


I've tried to output the data in the program stack when the program has a segmentation fault. I need to print where the program executation has been, especially the function names, in order to know what operation in the code causes the crashes.
But when I invoke dladdr() on the addresses in the registers, dladdr() just fails, returning 0.
The following is my program:

#ifndef __USE_GNU
#define __USE_GNU
#endif
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <ucontext.h>
#include <dlfcn.h>
#include <strings.h>
#include <stdlib.h>

static void signal_segv(int signum, siginfo_t *info, void *ptr)
{
    static const char *si_codes[3] = { "", "SEGV_MAP_ERR", "SEGV_ACC_ERR" };

    int i;
    int f = 0;
    ucontext_t *ucontext = (ucontext_t *)ptr;
    Dl_info dlinfo;
    void **bp = 0;
    void *ip = 0;
    FILE *fp;
    time_t cur_time;
    struct tm *tfmt;

    fp = fopen("stacktrace", "a");
    if (!fp)
    {
        printf("fopen() failed.\n");
        fclose(fp);
        return;
    }

    fprintf(fp, "info.si_signo = %d\n", signum);
    fprintf(fp, "info.si_errno = %d\n", info->si_errno);
    fprintf(fp, "info.si_code  = %d (%s)\n", info->si_code,
        (info->si_code >= 0 && info->si_code <= 2) ? si_codes[info->si_code] : "");
    fprintf(fp, "info.si_addr  = %p\n", info->si_addr);
    for (i = 0; i < NGREG; ++i)
        fprintf(fp, "reg[%02d]       = 0x%08x\n", i, ucontext->uc_mcontext.gpregs[i]);

    ip = (void *)ucontext->uc_mcontext.gpregs[CTX_S7]; // this is only one register, but I tried every generic
                                                       //  register, having the same results
    bp = (void **)ucontext->uc_mcontext.gpregs[CTX_SP];

    while (ip && bp)
    {
        if (!dladdr(ip, &dlinfo)) // the dladdr() failed here
            break;

        const char *symname = dlinfo.dli_sname;

        fprintf(fp, "% 2d: %p <%s+%lu> (%s)\n", ++f, ip, symname,
            (unsigned long)ip - (unsigned long)dlinfo.dli_saddr, dlinfo.dli_fname);

        if (dlinfo.dli_sname && !strcmp(dlinfo.dli_sname, "main"))
            break;

        ip = bp[1];
        bp = (void **)bp[0];
    }

    fclose(fp);

    exit(0);
}

static void setup_sigsegv()
{
    struct sigaction action;
    bzero(&action, sizeof(action));
    action.sa_sigaction = signal_segv;
    action.sa_flags = SA_SIGINFO;
    if (sigaction(SIGSEGV, &action, NULL) < 0)
        printf("sigaction() failed.\n");
}

int main()
{
    setup_sigsegv();
    *(int *)0x1234 = 30;
    return 0;
}

Can somebody figure out where the problem is and how should I write the tracing code?
Thanks!

 



More information about the uClibc mailing list