当前位置: 代码迷 >> 综合 >> Walking the callstack
  详细解决方案

Walking the callstack

热度:61   发布时间:2024-01-16 03:01:43.0

Walking the callstack

作者:Jochen Kalmbach

翻译:Hefe

原文出处:www.codeproject.com

关键字:callstack, StackWalker

简介

有些情况下,我们需要显示当前线程的callstack,或是显示其他我们感兴趣的进程或线程的callstack,为此,我专门写了这篇文章阐述如何获得callstack

我写这篇文章的主要目的如下:

1, 提供一些简单的接口来生成callstack

2, 基于CPP的特性提供一些方法来用于重载

3, 隐藏具体API的实现

4, Callstack信息默认输出在debug模式窗口(可以自己定制输出方式)

5, 支持用户提供的内存只读函数

6, 编译器支持VC5-VC8

7, 提供最便利的callstack生成方案

背景

目前MS已经提供API(StackWalker64)用来遍历callstack。从win9x/w2k开始,这个接口就被包含在dbghelp.dll的库中(NT上,取而代之的是imagehelp.dll),只是这个接口(StackWalk64)w2k之后被改名字了,在w2k之前叫StackWalk,没有尾巴的64。这个工程只支持最新的Xxx64接口,如果你想在比较旧的平台上运行,你可以去下载支持相关的平台dll

最新版本的dbghelp.dll可以和windbg一起下载(译者注:windbgMS发布的一款调试工具,当你下载并安装的时候,相应的安装目录下会有dbghelp.dll文件)。同时也包含了symsrv.dll文件,这个文件主要用来激活MS的公共符号服务(这个服务主要用来获取系统文件的调试信息)

如何使用代码

StackWalker这个类的使用非常简单。比如:如果你想获得当前线程的callstack,你只需要初始化一个StackWalk的实例,然后调用ShowCallStack即可。(译者注:一般我们需要继承StackWalker这个类,然后声明并初始化这个子类的实例)。

代码演示1

#include <windows.h>
#include "StackWalker.h"
 
void Func5() { StackWalker sw; sw.ShowCallstack(); }
void Func4() { Func5(); }
void Func3() { Func4(); }
void Func2() { Func3(); }
void Func1() { Func2(); }
 
int main()
{
     
 Func1();
 return 0;
}

debug-output窗口生成相应的输出如下:

[...] (output stripped)
d:/privat/Articles/stackwalker/stackwalker.cpp (736): StackWalker::ShowCallstack
d:/privat/Articles/stackwalker/main.cpp (4): Func5
d:/privat/Articles/stackwalker/main.cpp (5): Func4
d:/privat/Articles/stackwalker/main.cpp (6): Func3
d:/privat/Articles/stackwalker/main.cpp (7): Func2
d:/privat/Articles/stackwalker/main.cpp (8): Func1
d:/privat/Articles/stackwalker/main.cpp (13): main
f:/vs70builds/3077/vc/crtbld/crt/src/crt0.c (259): mainCRTStartup
77E614C7 (kernel32): (filename not available): _BaseProcessStart@4

你现在可以双击任意一行,VS会自动的跳转到你想到的文件并定位到具体行。

定制你自己的输出结构

如果你想直接把callstack输出到文件或是使用其他的输出结构(译者注:比如英雄岛项目中就是ITrace*),你只需要继承StackWalker类即可。你有两种选择来实现自己的输出结构:1,重写OnOutput方法。2,重写所有的OnXXX函数。当然从OO的思想来说,第一种方法是推荐的,符合KISS的原则。

演示代码2
class MyStackWalker : public StackWalker
{
    
public:
 MyStackWalker() : StackWalker() {}
protected:
 virtual void OnOutput(LPCSTR szText)
    { printf(szText); StackWalker::OnOutput(szText); }
};