从另一个线程打印堆栈跟踪

Kar*_*arl 7 iphone objective-c stack-trace

我知道我可以使用backtrace()或[NSThread callStackSymbols]来获取当前线程的堆栈跟踪,但是如何获得DIFFERENT线程的堆栈跟踪(假设它已被冻结)?

Kar*_*arl 14

编辑:我的原始答案不会从任意线程打印.我已经在我的崩溃处理程序项目中编写了一个正确的实现:https://github.com/kstenerud/KSCrash

具体来说,这些文件:

在以下帮助下:

你做的是:

  • 创建一个新的机器上下文结构(_STRUCT_MCONTEXT)
  • 使用thread_get_state()填充其堆栈状态
  • 获取程序计数器(第一个堆栈跟踪条目)和帧指针(所有其余的)
  • 逐步通过帧指针指向的堆栈帧,并将所有指令地址存储在缓冲区中供以后使用.

请注意,您应该在执行此操作之前暂停线程,否则您可能会得到不可预测的结果.

堆栈框架填充了包含两个指针的结构:

  • 指向堆栈上一级的指针
  • 指令地址

所以你需要在走框架时考虑到这一点,以填写你的堆栈跟踪.还有可能堆栈损坏,导致指针坏,这会导致程序崩溃.您可以通过使用vm_read_overwrite()复制内存来解决这个问题,vm_read_overwrite()会首先询问内核是否可以访问内存,因此它不会崩溃.

一旦你有了堆栈跟踪,就可以像往常一样在它上面调用backtrace()(崩溃处理程序必须是异步安全的,所以它实现了自己的backtrace方法,但在正常情况下,backtrace()就可以了).


Alb*_*ert 5

这是从另一个线程获取调用堆栈的一些更安全的方法:实现一些背景信息。它使用信号处理并在目标线程中生成信号处理程序。它还具有比您的解决方案更具跨平台性的优点,即它应该可以在您拥有的任何地方<signal.h>工作<execinfo.h>任何地方工作。

对于打印,您可以backtrace_symbols按照自己的建议进行使用。但您可能对此处实现的扩展版本感兴趣。它使用 libbfd (来自binutils;最新版本也主要适用于 MacOSX,请参阅此处了解可能与您无关的小限制)来读取调试信息并添加行号和其他信息(它也回退到dladdr如果一切都失败了;这就是正在backtrace_symbols做的)。