不久之前,我回答了类似的问题to-print-its-stacktrace/4611112#4611112)。您应该看一下方法#4上可用的源代码,该方法还会打印行号和文件名。
- 方法4:
我对方法3进行了一点改进,以打印行号。也可以将其复制以使用方法2。
基本上,它使用 addr2line 将地址转换为文件名和行号。
下面的源代码显示所有本地功能的行号。如果调用了另一个库中的函数,则可能会看到几个
??:0而不是文件名。
#include <stdio.h>#include <signal.h>#include <stdio.h>#include <signal.h>#include <execinfo.h>void bt_sighandler(int sig, struct sigcontext ctx) { void *trace[16]; char **messages = (char **)NULL; int i, trace_size = 0; if (sig == SIGSEGV) printf("Got signal %d, faulty address is %p, ""from %pn", sig, ctx.cr2, ctx.eip); else printf("Got signal %dn", sig); trace_size = backtrace(trace, 16); trace[1] = (void *)ctx.eip; messages = backtrace_symbols(trace, trace_size); printf("[bt] Execution path:n"); for (i=1; i<trace_size; ++i) { printf("[bt] #%d %sn", i, messages[i]); size_t p = 0; while(messages[i][p] != '(' && messages[i][p] != ' ' && messages[i][p] != 0) ++p; char syscom[256]; sprintf(syscom,"addr2line %p -e %.*s", trace[i], p, messages[i]); //last parameter is the file name of the symbol system(syscom); } exit(0);}int func_a(int a, char b) { char *p = (char *)0xdeadbeef; a = a + b; *p = 10; return 2*a;}int func_b() { int res, a = 5; res = 5 + func_a(a, 't'); return res;}int main() { struct sigaction sa; sa.sa_handler = (void *)bt_sighandler; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGSEGV, &sa, NULL); sigaction(SIGUSR1, &sa, NULL); printf("%dn", func_b());}此代码应编译为:
gcc sighandler.c -o sighandler -rdynamic
程序输出:
Got signal 11, faulty address is 0xdeadbeef, from 0x8048975[bt] Execution path:[bt] #1 ./sighandler(func_a+0x1d) [0x8048975]/home/karl/workspace/stacktrace/sighandler.c:44[bt] #2 ./sighandler(func_b+0x20) [0x804899f]/home/karl/workspace/stacktrace/sighandler.c:54[bt] #3 ./sighandler(main+0x6c) [0x8048a16]/home/karl/workspace/stacktrace/sighandler.c:74[bt] #4 /lib/tls/i686/cmov/libc.so.6(__libc_start_main+0xe6) [0x3fdbd6]??:0[bt] #5 ./sighandler() [0x8048781]??:0



