#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <string.h> #include <unistd.h>
void dump(int signo)
{
char buf[1024], cmd[1024];
FILE* fh;
snprintf(buf, sizeof(buf), "/proc/%d/cmdline", getpid());
if (!(fh = fopen(buf, "r"))) exit(0);
if (!fgets(buf, sizeof(buf), fh)) { fclose(fh); exit(0); }
fclose(fh);
if (buf[strlen(buf)-1] == '\n') buf[strlen(buf)-1] = '\0';
snprintf(cmd, sizeof(cmd), "gdb %s %d", buf, getpid());
system(cmd); // 彈出 GDB 交互調試
exit(0);
}
void dummy_function(void) {
unsigned char* ptr = 0; *ptr = 0; // 故意段錯誤
}
int main() {
signal(SIGSEGV, dump);
dummy_function();
return 0;
}
優點:進入完整 GDB 環境,可查變量、回溯、設置斷點。
缺點:需部署 GDB、終端交互、不適合無人值守服務器。
#include <execinfo.h> #include <stdio.h> #include <stdlib.h> #include <signal.h>
void dump(int signo)
{
void* array[10];
size_t size = backtrace(array, 10);
char** strings = backtrace_symbols(array, size);
printf("Obtained %zd stack frames:\n", size);
for (size_t i = 0; i < size; ++i) printf("%s\n", strings[i]);
free(strings);
exit(0);
}
void dummy_function(void) {
unsigned char* ptr = 0; *ptr = 0;
}
int main() {
signal(SIGSEGV, dump);
dummy_function();
return 0;
}
編譯需鏈接 -rdynamic(導出動態符號)且 -g(調試信息):
gcc -g -rdynamic -o test test.c
輸出示例:
Obtained 5 stack frames: ./test(dummy_function+0x15) [0x4005a5] ./test(main+0x1a) [0x4005c2] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7f...] ./test(_start+0x2a) [0x4004da]
SIGABRT, SIGBUS, SIGFPE, SIGILL 同註冊 dump。backtrace/backtrace_symbols/printf/malloc 不安全,但崩潰前「死馬當活馬醫」通常可接受。生產級應用用 libunwind 或寫入預分配緩衝區。printf 為 write(STDERR_FILENO, ...) 或寫文件,避免標準輸出重定向丟失。addr2line -e test 0x4005a5 獲取文件行號。| 場景 | 推薦方案 |
|---|---|
| 開發機/測試環境 | 方案一 |
| 生產服務器/嵌入式/無人值守 | 方案二 + 寫文件 + 定期上傳 |
| 大型項目/需聚類分析 | Breakpad/Crashpad |