正在从信号处理程序打印堆栈跟踪

Printing stack trace from a signal handler

本文关键字:打印 堆栈 跟踪 程序 信号处理      更新时间:2023-10-16

我需要从Linux上运行的64位多线程C++应用程序的信号处理程序打印堆栈跟踪。尽管我发现了几个代码示例,但没有一个可以编译。我的阻塞点是从ucontext_t结构中获取调用者的地址(生成信号的点)。我能找到的所有信息都指向EIP寄存器,它们要么是ucontext.gregs[REG_EIP],要么是ucntext.EIP。看起来它们都是x86特定的。我需要适用于英特尔和AMD CPU的64位兼容代码。有人能帮忙吗?

有一个glibc函数backtrace。手册页列出了呼叫的示例:

#define SIZE 100
void myfunc3(void) {
       int j, nptrs;
       void *buffer[100];
       char **strings;
       nptrs = backtrace(buffer, SIZE);
       printf("backtrace() returned %d addressesn", nptrs);
       /* The call backtrace_symbols_fd(buffer, nptrs, STDOUT_FILENO)
          would produce similar output to the following: */
       strings = backtrace_symbols(buffer, nptrs);
       if (strings == NULL) {
           perror("backtrace_symbols");
           exit(EXIT_FAILURE);
       }
       for (j = 0; j < nptrs; j++)
           printf("%sn", strings[j]);
       free(strings);
   }

有关更多上下文,请参阅手册页。

很难判断这是否真的能从信号处理程序中保证工作,因为posix只列出了几个保证工作的可重入函数。记住:当进程的其余部分正处于malloc调用的中间时,可能会调用信号处理程序。

我的猜测是,这通常有效,但可能会不时失败。对于调试来说,这可能已经足够好了。

获取堆栈跟踪的常用方法是获取本地变量,然后添加一些幻数,具体取决于编译器生成代码(可能取决于优化选项用于编译代码),然后从那里返回。非常系统依赖,但如果你知道自己在做什么,这是可行的。

这在信号处理程序中是否有效是另一个问题。我没有了解您所描述的平台,但许多系统都安装了信号处理程序的单独堆栈,没有返回到用户可访问内存中的中断堆栈。