当我的 C++ Linux 应用程序崩溃时,我需要转储堆栈跟踪。我使用 backtrace()
和 backtrace_symbols()
成功地做到了这一点。现在,我还想获得崩溃的行号。它是怎么做到的?
最佳答案
我得到了帮助
http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l2.html 和 http://www.linuxjournal.com/article/6391?page=0,0想出示例代码来展示如何实现这一目标。
基本上它是关于在信号处理程序中放置一个堆栈回溯,并让后者捕获您的程序可以接收的所有“坏”信号(SIGSEGV、SIGBUS、SIGILL、SIGFPE 等)。这样,如果您的程序不幸崩溃并且您没有使用调试器运行它,您可以获得堆栈跟踪并知道故障发生的位置。此技术还可用于了解您的程序在何处循环,以防它停止响应...
下面的代码运行外部程序addr2line对于跟踪中的每个地址,将其转换为文件名和行号。
下面的源代码打印所有局部函数的行号。如果调用另一个库中的函数,您可能会看到几个 ??:0 而不是文件名。
#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 %p\n", sig, ctx.cr2, ctx.eip);
else
printf("Got signal %d\n", sig);
trace_size = backtrace(trace, 16);
/* overwrite sigaction with caller's address */
trace[1] = (void *)ctx.eip;
messages = backtrace_symbols(trace, trace_size);
/* skip first stack frame (points here) */
printf("[bt] Execution path:\n");
for (i=1; i<trace_size; ++i)
{
printf("[bt] #%d %s\n", i, messages[i]);
char syscom[256];
sprintf(syscom,"addr2line %p -e sighandler", trace[i]); //last parameter is the name of this app
system(syscom);
}
exit(0);
}
int func_a(int a, char b) {
char *p = (char *)0xdeadbeef;
a = a + b;
*p = 10; /* CRASH here!! */
return 2*a;
}
int func_b() {
int res, a = 5;
res = 5 + func_a(a, 't');
return res;
}
int main() {
/* Install our signal handler */
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);
/* ... add any other signal here */
/* Do something */
printf("%d\n", 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
关于c++ - 有没有办法从 Linux 发行版二进制文件中转储带有行号的堆栈跟踪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15129089/