如何在Windows上获取堆栈跟踪而不使用dbghelp.dll?

7

如何在Windows上获取地址的堆栈跟踪而不使用dbghelp.dll?

我不需要知道与地址相关的符号或函数名称,我只想要地址列表--类似于 *nix系统的回溯

谢谢!


你为什么要在没有 DbgHelp.dll 的情况下这样做呢?DbgHelp.dll 自 Windows 2000 起已内置于 Windows 中。此外,还可以查看 Jochen Kalmbach 的 Stackwalker:http://www.codeproject.com/KB/threads/StackWalker.aspx - Cheeso
3个回答

9

请查看位于Kernel32.dll中的CaptureStackBackTrace()函数,它可以捕获堆栈回溯信息。这个函数可以满足你的所有需求。

通过遍历堆栈并记录每个帧的信息,来捕获堆栈回溯信息。

USHORT WINAPI CaptureStackBackTrace(
  __in       ULONG FramesToSkip,
  __in       ULONG FramesToCapture,
  __out      PVOID *BackTrace,
  __out_opt  PULONG BackTraceHash
);

1
看起来不错。但是我正在使用VS 2005,而CaptureStackBackTrace没有在winbase.h中定义RtlCaptureBackTrace。我将尝试手动包含RtlCaptureBackTrace(...)的函数原型,并查看是否适用于我。谢谢! - Uhall
太酷了!我至少写过三次堆栈跟踪代码,但不知道这个存在。谢谢! - shoosh
@Uhall:您可以尝试安装更新的Windows SDK。最低支持的客户端列为Windows XP,尽管MSDN页面确实列出它是从Windows Vista开始包含在Windows SDK中的。 - Kris Kumler

2

如果你想要进行这个极其不可移植的操作,你可以直接读取EBP寄存器并手动遍历栈。这种方法只适用于x86架构,并且假定你使用的C运行时在调用第一个函数之前正确地将EBP初始化为0。

uint32_t read_ebp(void)
{
    uint32_t my_ebp;
    __asm
    {
        mov ebp, my_ebp
    }

    return my_ebp;
}

void backtrace(void)
{
    uint32_t ebp = read_ebp();

    printf("backtrace:\n");

    while(ebp != 0)
    {
        printf("0x%08x\n", ebp);
        ebp = ((uint32_t *)ebp)[1];
    }
}

使用发布版本,您只会得到前几帧。要使其真正可靠地工作,您需要设置“Omit Frame Pointers”= No。 - shoosh
目标先行,所以你需要将 my_ebp 移动到 ebp。除此之外,它非常酷。 - Daniel Sloof

1

之前的变体对我不起作用(msvc 6),所以:

unsigned long prev;
unsigned long addr;
__asm { mov prev, ebp }
while(addr!=0) { 
  addr = ((unsigned long *)prev)[1]; 
  printf("0x%08x\n", addr); 
  prev = ((unsigned long *)prev)[0]; 
}
Adam, thanks for highlighting the way!


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