您想要一个打印堆栈跟踪的独立函数,具有所有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);
execl("/usr/bin/gdb", "gdb", "--batch", "-n", "-ex", "thread", "-ex", "bt", name_buf, pid_buf, NULL);
abort();
} else {
waitpid(child_pid,NULL,0);
}
}
正如引用的问题所示,gdb提供了一些其他选项可供使用。例如,使用"bt full"而不是"bt"将产生更详细的报告(输出中包括局部变量)。 gdb的man页面有点简单,但完整的文档在这里提供。
由于它基于gdb,因此输出包括解码后的名称、行号、函数参数,甚至可选的局部变量。此外,gdb具有线程感知功能,因此您应该能够提取一些特定于线程的元数据。
以下是我使用此方法看到的堆栈跟踪类型的示例。
0x00007f97e1fc2925 in waitpid () from /lib/libc.so.6
[Current thread is 0 (process 15573)]
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”实例)。