個人檔案Quake3 启示录相片部落格清單更多 ![]() | 說明 |
|
3月6日 使用dbghelp获取调用堆栈--release下的调试方法学Author : Kevin Lynx当软件作为release模式被发布给用户时,当程序崩溃时我们很难去查找原因。常见的手法是输出LOG文件,根据LOG文件分析 要获取call stack(所谓的调用堆栈),就需要查看(unwind)stack的内容。We could conceivably attempt to unwind the StackWalk64声明如下: 具体每个参数的含义可以参见MSDN。这里说下ContextRecord参数,该参数指定了CPU各个寄存器的内容。StackFrame指定了stack frame的内容。stack frame是什么,我也不知道。(= =) StackWalk64函数需要用户指定当前frame的地址,以及当前程序的指令地址。这两个信息都被填充进ContextRecord,然后传进StackWalk64函数。 那么如何获取当前的stack frame地址和当前程序指令地址呢?如前所说,你可以使用内联汇编。(对于程序指令地址,因为要获取EIP寄存器的内容,而该寄存器不能被软件访问)也可以使用GetThreadContext一次性获取当前线程当前运行情况下的CPU各个寄存器内容。补充下,当前frame地址被放在EBP寄存器里,当前程序指令地址放在EIP寄存器里。但是,如同MSDN对GetThreadContext函数的说明一样,该函数可能获取到错误的寄存器内容(You cannot get a valid context for a running thread)。 另一种获取Context(包含EBP and EIP)的方法就是使用SEH(结构化异常处理),在__except中使用GetExceptionInformation获取。 GetExceptionInformation 传回一个LPEXCEPTION_POINTERS指针,该指针指向一个EXCEPTION_POINTERS结构,该结构里包含一个Context的指针,即达到目标,可以使用StackWalk函数。 补充一下,你可以直接使用StackWalk函数,StackWalk被define为StackWalk64(windows平台相关)。 unwind栈后,可以进一步获取一个stack frame的内容,例如函数名。这里涉及到SymFromAddr函数,该函数可以根据一个地址返回符号名(函数名)。还有一个有意思的函数:SymGetLineFromAddr,可以获取函数对应的源代码的文件名和行号。 当然,这一切都依赖于VC产生的程序数据库文件(pdb),以及提供以上API函数的dbghelp.dll。 参考一段简单的代码: #include <windows.h> #pragma comment( lib, "dbghelp.lib" ) void dump_callstack( CONTEXT *context ) sf.AddrPC.Offset = context->Eip; DWORD machineType = IMAGE_FILE_MACHINE_I386; HANDLE hProcess = GetCurrentProcess(); for( ; ; ) if( sf.AddrFrame.Offset == 0 ) pSymbol->SizeOfStruct = sizeof( symbolBuffer ); DWORD64 symDisplacement = 0; IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) }; if( SymGetLineFromAddr( hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &lineInfo ) ) DWORD excep_filter( LPEXCEPTION_POINTERS lpEP ) dump_callstack( lpEP->ContextRecord ); if( SymCleanup( GetCurrentProcess() ) ) return EXCEPTION_EXECUTE_HANDLER; void func1( int i ) void func2( int i ) void func3( int i ) void test( int i ) int main() return 0; 以上代码在release模式下需要关掉优化,否则调用堆栈显示不正确(某些函数被去掉了?),同时需要pdb文件。当用户使用时可以只抛出挂掉时候的地址,然后开发者通过crashfinder这样的软件,启动拥有pdb的程序 引用通告此內容的引用通告是: http://topameng.spaces.live.com/blog/cns!F962D4854A8233D!534.trak 引述這則內容的部落格
|
|
|