我使用GCC编译器在Linux上工作。当我的c++程序崩溃时,我希望它自动生成一个堆栈跟踪。

我的程序由许多不同的用户运行,它也可以在Linux、Windows和Macintosh上运行(所有版本都使用gcc编译)。

我希望我的程序能够在崩溃时生成堆栈跟踪,下次用户运行它时,它会问他们是否可以将堆栈跟踪发送给我,这样我就可以跟踪到问题。我可以处理发送信息给我,但我不知道如何生成跟踪字符串。什么好主意吗?


当前回答

我研究这个问题有一段时间了。

深埋在谷歌性能工具README

http://code.google.com/p/google-perftools/source/browse/trunk/README

谈到libunwind

http://www.nongnu.org/libunwind/

很乐意听听对这个图书馆的意见。

使用-rdynamic的问题是,在某些情况下,它会相对显著地增加二进制文件的大小

其他回答

看:

男人3回溯

And:

#include <exeinfo.h>
int backtrace(void **buffer, int size);

这些是GNU扩展。

我研究这个问题有一段时间了。

深埋在谷歌性能工具README

http://code.google.com/p/google-perftools/source/browse/trunk/README

谈到libunwind

http://www.nongnu.org/libunwind/

很乐意听听对这个图书馆的意见。

使用-rdynamic的问题是,在某些情况下,它会相对显著地增加二进制文件的大小

我可以帮助Linux版本:函数backtrace, backtrace_symbols和backtrace_symbols_fd可以使用。请参见相应的手册。

在Linux/unix/MacOSX上使用核心文件(您可以通过ulimit或兼容的系统调用启用它们)。在Windows上使用Microsoft错误报告(您可以成为合作伙伴并访问您的应用程序崩溃数据)。

对于Linux和Mac OS X,如果使用gcc或任何使用glibc的编译器,可以使用execinfo.h中的backtrace()函数打印堆栈跟踪,并在出现分段错误时优雅地退出。文档可以在libc手册中找到。

下面是一个示例程序,它安装了一个SIGSEGV处理程序,并在发生段错误时将堆栈跟踪输出到stderr。这里的baz()函数会导致触发处理程序的段错误:

#include <stdio.h>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>


void handler(int sig) {
  void *array[10];
  size_t size;

  // get void*'s for all entries on the stack
  size = backtrace(array, 10);

  // print out all the frames to stderr
  fprintf(stderr, "Error: signal %d:\n", sig);
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  exit(1);
}

void baz() {
 int *foo = (int*)-1; // make a bad pointer
  printf("%d\n", *foo);       // causes segfault
}

void bar() { baz(); }
void foo() { bar(); }


int main(int argc, char **argv) {
  signal(SIGSEGV, handler);   // install our handler
  foo(); // this will call foo, bar, and baz.  baz segfaults.
}

使用-g -rdynamic编译可以在输出中获得符号信息,glibc可以使用它来创建一个漂亮的stacktrace:

$ gcc -g -rdynamic ./test.c -o test

执行此命令将得到以下输出:

$ ./test
Error: signal 11:
./test(handler+0x19)[0x400911]
/lib64/tls/libc.so.6[0x3a9b92e380]
./test(baz+0x14)[0x400962]
./test(bar+0xe)[0x400983]
./test(foo+0xe)[0x400993]
./test(main+0x28)[0x4009bd]
/lib64/tls/libc.so.6(__libc_start_main+0xdb)[0x3a9b91c4bb]
./test[0x40086a]

这显示了堆栈中每个帧的加载模块、偏移量和函数。在这里,您可以看到信号处理程序位于堆栈顶部,除了main、foo、bar和baz之外,还在main之前有libc函数。