代码改变世界

Stack Walk with DIA SDK

2007-03-26 21:05  atempcode  阅读(2623)  评论(0编辑  收藏  举报

DIA SDK (Debug Interface Access SDK) 是微软随Visual Studio发布的一套解析PDB的SDK. 如何用它分析PDB文件, MS有一个sample程序叫DIA2dump, 在x:\Program Files\Microsoft Visual Studio 8\DIA SDK\Samples\DIA2Dump\目录下. 这个sample没有涉及到的是Stack Walk, 微软这方面的文档也很少. 理论上自己写一个Stack walk应该也可以, 但是考虑到各种call convention, 32bit/64-bit, 本地变量, 还有FPO, oh my, 还是老老实实用DIA的实现吧, 一套code, 32位, 64位通用.

跟stack walk有关的两个interfaces是IDiaStackWalker和IDiaStackWalkHelper. 先讲IDiaStackWalker. 跟x86平台有关的只有一个function:

HRESULT getEnumFrames(
IDiaStackWalkHelper*   pHelper,
IDiaEnumStackFrames**  ppEnum
);

就这麽简单. CoCreate一个实例:

IDiaStackWalker* pStackWalker;
HRESULT hr = CoCreateInstance(CLSID_DiaStackWalker,
NULL,
CLSCTX_INPROC_SERVER,
IID_IDiaStackWalker,
(void**) &pStackWalker);

一个call就可以得到IDiaEnumStackFrames*, enum里的每个stack frame也是唾手可得. 它的奥妙全在IDiaStackWalkHelper里了.

IDiaStackWalkHelper这个interface全部要用户来实现. 一堆接口函数.

get_registerValue和put_registerValue是和register有关. 想要stack walk, 一些寄存器象esp, ebp的值是必须要知道;

searchForReturnAddress和searchForReturnAddressStart以我的经验可以不实现, 直接返回E_NOTIMPL就可以了;

readMemory必须实现. DIA会用这个函数去读stack里的内容, code section的内容, 以及一些特殊寄存器的值所指向的内存.

剩下的都可以在DIA的其他接口和函数来实现了:

frameForVA:

	IDiaSession::getEnumTables
HRESULT getEnumTables (
IDiaEnumTables** ppEnumTables
);
IDiaEnumFrameData::frameByVA
HRESULT frameByVA(
ULONGLONG       virtualAddress,
IDiaFrameData** frame
);

symbolForVA:

	IDiaSession::findSymbolByVA
HRESULT findSymbolByVA (
ULONGLONG    va,
SymTagEnum   symtag,
IDiaSymbol** ppSymbol
);

imageForVA:

	IDiaSession::get_loadAddress
HRESULT get_loadAddress (
ULONGLONG* pRetVal
);

pdataForVA:

我们debugger的目标程序中没有exception handle, 所以偷个懒, 返回E_NOTIMPL, 呵呵.