我正在使用 GCC 编译器在 Linux 上工作。当我的 C++ 程序崩溃时,我希望它自动生成堆栈跟踪。
我的程序由许多不同的用户运行,它也可以在 Linux、Windows 和 Macintosh 上运行(所有版本都使用 编译gcc)。
gcc
我希望我的程序能够在崩溃时生成堆栈跟踪,并且下次用户运行它时,它会询问他们是否可以将堆栈跟踪发送给我,以便我可以追踪问题。我可以处理向我发送信息,但我不知道如何生成跟踪字符串。有任何想法吗?
对于 Linux,我相信 Mac OS X,如果您使用 gcc 或任何使用 glibc 的编译器,您可以使用 backtrace() 函数execinfo.h打印堆栈跟踪,并在遇到分段错误时正常退出。文档可以在 libc 手册中找到。
execinfo.h
这是一个示例程序,它安装SIGSEGV处理程序并在出现段错误时打印堆栈stderr跟踪。这里的baz()函数会导致触发处理程序的段错误:
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 可以使用这些信息来制作漂亮的堆栈跟踪:
-g -rdynamic
$ 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除main、foo、bar和之外的 libc 函数baz。
main
foo
bar
baz