有没有办法使用Linux版本二进制文件中的行号来转储堆栈跟踪? [英] Is there a way to dump stack trace with line number from a Linux release binary?

查看:371
本文介绍了有没有办法使用Linux版本二进制文件中的行号来转储堆栈跟踪?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个要求,当我的c + + linux应用程序崩溃时转储堆栈跟踪。我成功地能够做到这一点使用backtrace()和backtrace_symbols()。现在,另外我想得到崩溃的行号。

I have a requirement of dumping stack traces when my c++ linux application crashes. I was successfully able to do this using backtrace() and backtrace_symbols(). Now, additionally I would like to get the line numbers of the crash. How do it do it?

推荐答案

http://www.linuxjournal.com/files /linuxjournal.com/linuxjournal/articles/063/6391/6391l2.html
and http://www.linuxjournal.com/article/6391?page=0,0 提供示例代码,显示如何实现这一点。

http://www.linuxjournal.com/files/linuxjournal.com/linuxjournal/articles/063/6391/6391l2.html and http://www.linuxjournal.com/article/6391?page=0,0 to come up with sample code which shows how you can achieve this.

基本上,它是关于把一个堆栈回溯到信号处理程序内,让后者捕获你的程序可以接收的所有坏信号(SIGSEGV,SIGBUS,SIGILL,SIGFPE等)。这样,如果你的程序不幸崩溃,你不是用调试器运行它,你可以得到一个堆栈跟踪,知道故障发生在哪里。

Basically it is about putting a stack backtrace inside a signal handler and having the latter catch all the "bad" signals your program can receive (SIGSEGV, SIGBUS, SIGILL, SIGFPE and the like). This way, if your program unfortunately crashes and you were not running it with a debugger, you can get a stack trace and know where the fault happened. This technique also can be used to understand where your program is looping in case it stops responding...

下面的代码运行外部程序 addr2line ,以将其转换为文件名和行号。

Below code runs the external program addr2line for every address in the trace to convert it into a file name and a line number.

下面的源代码显示所有局部函数的行号。如果调用来自另一个库的函数,您可能会看到几个??:0而不是文件名。

The source code below prints line numbers for all local functions. If a function from another library is called, you might see a couple of ??:0 instead of file names.

#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

This code should be compiled as: 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

这篇关于有没有办法使用Linux版本二进制文件中的行号来转储堆栈跟踪?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆