所以你想要一个打印堆栈跟踪的独立函数具有 gdb 堆栈跟踪所具有的所有功能,并且不会终止您的应用程序。答案是以非交互模式自动启动 gdb 以执行您想要的任务。
这是通过在子进程中执行 gdb、使用 fork() 并编写脚本来在应用程序等待其完成时显示堆栈跟踪来完成的。这可以在不使用核心转储且不中止应用程序的情况下执行。我通过查看这个问题学会了如何做到这一点:从程序中调用 gdb 来打印它的堆栈跟踪如何更好?
与该问题一起发布的示例并不完全按照所写的那样对我起作用,所以这是我的“固定”版本(我在 Ubuntu 9.04 上运行了这个)。
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/prctl.h>
void print_trace() {
char pid_buf[30];
sprintf(pid_buf, "%d", getpid());
char name_buf[512];
name_buf[readlink("/proc/self/exe", name_buf, 511)]=0;
prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
int child_pid = fork();
if (!child_pid) {
dup2(2,1); // redirect output to stderr - edit: unnecessary?
execl("/usr/bin/gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
abort(); /* If gdb failed to start */
} else {
waitpid(child_pid,NULL,0);
}
}
如引用的问题所示,gdb 提供了您可以使用的其他选项。例如,使用“bt full”而不是“bt”会生成更详细的报告(局部变量包含在输出中)。 gdb 的联机帮助页比较简单,但提供了完整的文档here.
由于这是基于 gdb 的,因此输出包括分解的名字, 行号, 函数参数,并且可选地甚至局部变量。此外,gdb 是线程感知的,因此您应该能够提取一些特定于线程的元数据。
这是我使用此方法看到的堆栈跟踪类型的示例。
0x00007f97e1fc2925 in waitpid () from /lib/libc.so.6
[Current thread is 0 (process 15573)]
#0 0x00007f97e1fc2925 in waitpid () from /lib/libc.so.6
#1 0x0000000000400bd5 in print_trace () at ./demo3b.cpp:496
2 0x0000000000400c09 in recursive (i=2) at ./demo3b.cpp:636
3 0x0000000000400c1a in recursive (i=1) at ./demo3b.cpp:646
4 0x0000000000400c1a in recursive (i=0) at ./demo3b.cpp:646
5 0x0000000000400c46 in main (argc=1, argv=0x7fffe3b2b5b8) at ./demo3b.cpp:70
注意:我发现这与使用不兼容valgrind(可能是由于 Valgrind 使用虚拟机)。当您在 gdb 会话内运行程序时,它也不起作用(无法将“ptrace”的第二个实例应用于进程)。