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一起下载(译者注:windbg是MS发布的一款调试工具,当你下载并安装的时候,相应的安装目录下会有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); }
};