首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

Linux 程式崩潰時自動列印堆疊追蹤日誌

     編輯:關於C

背景動機

GNU/Linux 程式因記憶體存取錯誤崩潰時,通常依賴 core dump 檔案除錯。但無法在現場除錯時,若日誌中包含崩潰瞬間的堆疊呼叫資訊,將大幅加速定位問題。本文示範如何使用 backtrace 與 addr2line 在訊號處理器中自動產生可讀的堆疊日誌。

關鍵編譯選項

g++ -g -rdynamic -o mytest main.cpp
  • -g:編入除錯符號,addr2line 才能顯示行號。
  • -rdynamic:將所有符號加入動態符號表,backtrace_symbols 才能解析函數名稱。

核心實作:dump_stack 函數

void dump_stack(FILE *log) {
    void *bufs[100];
    int n = backtrace(bufs, 100);
    char **infos = backtrace_symbols(bufs, n);
    if (!infos) exit(1);

    fprintf(log, "==================\nFrame info:\n");
    for (int i = 0; i < n; ++i)
        fprintf(log, "%s\n", infos[i]);

    // 建立 addr2line 指令
    char cmd[512];
    int len = snprintf(cmd, sizeof(cmd), "addr2line -ifC -e ./mytest");
    char *p = cmd + len;
    size_t s = sizeof(cmd) - len;
    for (int i = 0; i < n; ++i) {
        if (s > 0) {
            len = snprintf(p, s, " %p", bufs[i]);
            p += len; s -= len;
        }
    }

    fprintf(log, "src info:\n");
    FILE *fp = popen(cmd, "r");
    if (fp) {
        char buf[128];
        while (fgets(buf, sizeof(buf), fp))
            fprintf(log, "%s", buf);
        pclose(fp);
    }
    fprintf(log, "==================\n");
    free(infos);
}

訊號處理器安裝

void segv_handle(int s) {
    dump_stack(stdout);
    exit(127 + s);
}

int main() {
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = segv_handle;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGSEGV, &sa, 0) < 0) { perror("sigaction"); exit(1); }

    foo(7); // 觸發遞迴最終導致 SIGSEGV
    return 0;
}

實際輸出範例

Frame info:
./mytest(_Z10dump_stackP8_IO_FILE+0x1f) [0x8048abb]
./mytest(_Z11segv_handlei+0x13) [0x8048cba]
[0x709400]
/lib/libc.so.6(memcpy+0x5a) [0x1c22ba]
./mytest(_Z5foo_1i+0x3e) [0x8048a95]
...

src info:
dump_stack(_IO_FILE*) /home/shuheng/temp_blog/main.cpp:59
segv_handle(int)    /home/shuheng/temp_blog/main.cpp:99
??                  ??:0
foo_1(int)          /home/shuheng/temp_blog/main.cpp:53
foo                 /home/shuheng/temp_blog/main.cpp:44
main                /home/shuheng/temp_blog/main.cpp:38
...

注意事項

  • C++ 程式行號可能偏移一行,C 程式則正常。
  • 若最佳化等級過高或缺少幀指標,堆疊可能不完整,此時仍需 core dump 配合 gdb 分析。
  • 訊號處理器中僅呼叫 async-signal-safe 函數;本範例為示範簡單化,生產環境需謹慎處理 (如寫入預先開啟的檔案描述符)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved