程序崩潰時如何自動記錄調用棧

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);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章