如何使用带有行号信息的gcc获取C ++的堆栈跟踪?

我们在专有的assert宏(如宏)中使用堆栈跟踪来捕获开发人员的错误-发现错误时,将打印堆栈跟踪。

我发现gcc的对backtrace()/ backtrace_symbols()方法不足:

  1. 名称混乱
  2. 没有行信息

第一个问题可以通过abi :: __

cxa_demangle解决。

但是第二个问题更加棘手。我找到了backtrace_symbols()的替代品。这比gcc的backtrace_symbols()更好,因为它可以检索行号(如果使用-

g编译),并且您不需要使用-rdynamic进行编译。

悬停代码是GNU许可的,所以恕我直言,我不能在商业代码中使用它。

有什么建议吗?

gdb能够打印出传递给函数的参数。可能要求太多了:)

回答:

不久之前,我回答了类似的问题to-print-its-stacktrace/4611112#4611112)。您应该看一下方法#4上可用的源代码,该方法还会打印行号和文件名。

我对方法3进行了一点改进,以打印行号。也可以将其复制以使用方法2。

基本上,它使用 将地址转换为文件名和行号。

下面的源代码显示所有本地功能的行号。如果调用了另一个库中的函数,则可能会看到几个??: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 %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]);

/* find first occurence of '(' or ' ' in message[i] and assume

* everything before that is the file name. (Don't go beyond 0 though

* (string terminator)*/

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; /* 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

以上是 如何使用带有行号信息的gcc获取C ++的堆栈跟踪? 的全部内容, 来源链接: utcz.com/qa/423812.html

回到顶部