程序崩溃时如何自动记录调用栈

Linux系统应用程序发生异常时,系统一般会发出相应的信号,因此在收到信号后打印调用栈即可实现相应功能。

引起程序退出的信号主要有:

    signal(SIGABRT, dump_backtrace);
    signal(SIGBUS,  dump_backtrace);
    signal(SIGFPE,  dump_backtrace);
    signal(SIGILL,  dump_backtrace);
    signal(SIGSEGV, dump_backtrace);
  • 打印调用栈可以使用gcc自带的 backtrace 函数:
void dump_backtrace(int sig)
{
    int tracefd = 0;
    void *array[50];
    size_t size;

    tracefd = open(BACKTRACE_FILE, O_CREAT | O_APPEND | O_WRONLY, 0666);
    if (tracefd < 0) {
        fprintf(stderr, "unable to open backtrace file '%s': %s\n", BACKTRACE_FILE, strerror(errno));
        exit(0);
    }

    size = backtrace(array, 50);
    backtrace_symbols_fd(array, size, tracefd);
    close(tracefd);

    exit(0);
}
  • 或者使用libunwind等第三方库实现:
static void dump_backtrace(int sig) {
    unw_cursor_t cursor;
    unw_context_t context;
    unw_word_t ip;
    unw_word_t offset;
    int tracefd = 0;
    ssize_t r;
    char fname[128] = {0};
    char stac[128 * 3] = {0};
    int len = 0;

    tracefd = open(BACKTRACE_FILE, O_CREAT | O_APPEND | O_WRONLY, 0666);
    if (tracefd < 0) {
        fprintf(stderr, "unable to open backtrace file '%s': %s\n", BACKTRACE_FILE, strerror(errno));
        exit(0);
    }

    unw_getcontext(&context);
    unw_init_local(&cursor, &context);

    while (unw_step(&cursor) > 0) {
        memset(fname, 0, sizeof(fname));
        unw_get_reg(&cursor, UNW_REG_IP, &ip);
        unw_get_proc_name(&cursor, fname, sizeof(fname), &offset);

        len = snprintf(stac, sizeof(stac), "0x%016lx: %s+0x%lx\n", ip, fname, offset);
        r = write(tracefd, stac, len);
        if (r < 0) {
            close(tracefd);
            exit(0);
        }
    }
    close(tracefd);

    exit(0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章