如何在没有pstack和gdb的情况下获取线程堆栈信息

3

在一些非常小的Linux环境中,如果无法插入任何日志并且没有pstack和gdb,是否有一种获取程序挂起原因的方法?


可能是不使用GDB附加程序获取所有线程的堆栈跟踪的重复问题。 - user6448640
不是重复的问题,因为我特别询问没有gdb或pstack的情况。 - YotKay
1个回答

1
我的建议是执行以下操作:
  1. 能够在您自己的程序中检索、操作和打印堆栈跟踪
  2. 为您的进程安装一个信号处理程序(例如,对于SIGUSR1),该处理程序将执行此操作
  3. 当程序被卡住时向其发送信号-控制将移动到信号处理程序(假设您没有屏蔽信号)。

现在(2.)和(3.)非常简单。对于(3.),它是kill -USR1 1234(对于ID为1234的进程)。对于(2.),它是:

#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t sigset(int sig, sighandler_t disp);

(详情请参阅man sigset)。

至于(1.),这曾经相当困难和棘手,但现在已经基本解决:

Boost StackTrace代码 | 文档

它将尽可能获取尽可能多的堆栈跟踪信息。以下是一个简单的使用示例:

#include <iostream>
#include <boost/stacktrace.hpp>

// ... somewhere inside the `bar(int)` function that is called recursively:
std::cout << boost::stacktrace::stacktrace();

可能会产生以下输出:
0# bar(int) at /path/to/source/file.cpp:70
1# bar(int) at /path/to/source/file.cpp:70
2# bar(int) at /path/to/source/file.cpp:70
3# bar(int) at /path/to/source/file.cpp:70
4# main at /path/to/main.cpp:93
5# __libc_start_main in /lib/x86_64-linux-gnu/libc.so.6
6# _start

注意: StackTrace是Boost的一个非常新的补充(截至2017年8月);如果您的Boost版本不够新,您可能需要单独获取它。


但是为了使用它,我必须修改源代码。我不知道我的程序在哪里挂起。我应该把这段代码放在哪里?到处都要吗? - YotKay
@YotKay:你应该阅读文档,有几个选项可供选择。其中一个是为分段违规设置信号处理程序。另一个是抛出包含堆栈跟踪的异常,并在一个(或几个)地方捕获它们。 - einpoklum
我肯定应该阅读文档,我承认。但我认为我们彼此之间存在误解。我的程序在某个地方挂起,这并不意味着它会崩溃。它在等待某些条件变量或类似的东西。我需要找出它在哪里。你的解决方案对我没有帮助,因为我不知道在哪里抛出你提到的异常等。 - YotKay
@YotKay:好吧,发送一个信号并使用堆栈跟踪库为其设置信号处理程序。 - einpoklum
糟糕...看起来我的boost版本太旧了 :-/ 我需要1.65版的 :-/ - YotKay

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接