快速捕获调用堆栈

时间:2011-12-09 23:59:33

标签: c++ windows visual-studio-2010

我正在尝试尽快捕获调用堆栈。现在这就是我所拥有的:

void* addrs[10] = {};
DWORD hash;
RtlCaptureStackBackTrace(0, 10, addrs, &hash);

for( size_t i = 0; i <10; ++i )
{
    std::cout << addrs[i] << '\n';
}

这适用于内存跟踪系统,所以如果以后(在某些用户驱动的事件中)可以将其转换为人类可读的内容,我最终会得到一个地址数组。

  • 如何将addrs变成人类可读的东西?(见下面的编辑)
  • 有什么比RtlCaptureStackBackTrace更快
  • 是否有跨平台方式来捕获调用堆栈?

修改

我使用SymFromAddrSymGetLineFromAddr64将地址转换为人类可读的信息。但是,使用new的{​​{1}}版本比原始版本长约30倍,几乎所有时间都是因为堆栈跟踪。我还在寻找更快的解决方案!

2 个答案:

答案 0 :(得分:2)

  

是否有跨平台方式来捕获调用堆栈?

快速回答是,不幸的是,这是不可能的。不同的编译器和平台将以不同的方式组织堆栈,如果没有编译器的“帮助”,您将无法准确地追溯堆栈...您可以在使用堆栈的平台上做的最多 - frame base-pointer将使用EBPRBP中的值向上移动堆栈,甚至取决于您运行的是32位x86可执行文件还是x86_64可执行文件。此外,管理UNIX应用程序二进制接口(ABI)和Windows ABI的规则完全不同。所以一般来说,你最终必须支持至少四种不同的可能性:

  1. Unix 32位ABI
  2. Unix 64位ABI
  3. Windows 32位ABI
  4. Windows 64位ABI
  5. 请记住,UNIX 64位ABI允许编译器选择是否支持堆栈帧基指针...因此无法保证使用基指针;编译器可以简单地选择在不使用单独的基指针的情况下针对堆栈指针本身引用所有堆栈变量。这仍然被认为符合UNIX 64位ABI。

    正如您所看到的,通过所有这些可能的变化,您将很难制作出可靠的跨平台堆栈跟踪器。您最好选择使用可用于您所针对的平台的工具。如果您需要支持多个平台,那么不幸的是,当您使用特定于平台的工具来帮助您可靠地执行堆栈跟踪时,会出现一定程度的代码重复。

答案 1 :(得分:0)

没有跨平台的方式,但有跨平台的库可以解决这个问题。 It's a common requirement for garbage collectors

不幸的是,我对这些库的推荐不够了解。 MMgc有嵌入的东西(在上面的链接中解释)。我相信Hans Boehm的垃圾收集器有另一个。

这些库通常依赖于特定于平台的调用,例如Windows上的RtlCaptureStackBacktrace。如果任何这样的库比特定于平台的调用更快,我会感到惊讶;但是如果任何这样的库变得非常慢,我也会感到惊讶。唯一的问题 - 对我来说 - 是你更喜欢直接调用Windows API调用还是通过另一个库来调用该调用。