寫起來,免得忘記。
在程式Crash前直接呼叫gdb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| void dump(int signo) { char buf[1024]; char 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)) 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);
exit(0); } signal(SIGSEGV, &dump);
|
沒有gdb的情況下,使用backtrace和objdump / addr2line 進行分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| #include <execinfo.h> // Important void dump(int signo) { void *array[10]; size_t size; char **strings; size_t i;
size = backtrace(array, 10); strings = backtrace_symbols(array, size);
printf("Obtained %zd stack frames.\n", size);
for (i = 0; i < size; i++) printf ("%s\n", strings[i]);
free(strings);
exit(0); }
|
在編譯的時候記得加上-rdynamic
選項,這樣會有比較多的資訊產出。執行結果
1 2 3 4 5 6 7 8
| Obtained 6 stack frames. ./a(dump+0x1c) [0x4009c9] /lib/x86_64-linux-gnu/libc.so.6(+0x36ff0) [0x7fdbdcad7ff0] ./a(dummy_function+0x10) [0x400a5a] ./a(main+0x18) [0x400a77] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf5) [0x7fdbdcac2ec5] ./a() [0x4008e9]
|
透過 objdump 可以找到可能出錯得地方
1 2 3 4 5 6 7 8 9 10 11
| $ objdump -d a 0000000000400a4a <dummy_function>: 400a4a: 55 push %rbp 400a4b: 48 89 e5 mov %rsp,%rbp 400a4e: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp) 400a55: 00 400a56: 48 8b 45 f8 mov -0x8(%rbp),%rax 400a5a: c6 00 00 movb $0x0,(%rax) <------ Here 400a5d: 5d pop %rbp 400a5e: c3 retq
|
或者是用Binary Hacks上寫的方法
1 2 3 4
| $ gcc a.c -o a -rdynamic -g $ addr2line -f -e a 0x400a5a dummy_function /home/hm/a.c:30
|