1. 获得当前的调用堆栈. < 请参考下面的函数实现 _printCallStark >
在当前线程去获得自己的调用堆栈, 我的做法是借助异常机制, 获得当前线程的下上文.然后通过 API 函数 StackWalk 遍历.
如果不是当前线程是否可以借助 API 函数 GetThreadContext 去获得指定线程的上下文. 不知道各位网友有没有验证过, 我觉得可行, 但还没有去验证.
< 注释:如果想了解更详细的信息, 建议直接去看 msdn >
大家都是程序员, 废话不多说, 请参考下面的样例代码:
- #include <string>
- #include <assert.h>
- #include "Windows.h"
- #include "dbghelp.h"
- #pragma comment(lib,"Dbghelp.lib")
- bool _printCallStark(DWORD MachineType, _EXCEPTION_POINTERS * lpEP)
- {
- if( ! lpEP || ! SymInitialize( GetCurrentProcess(), NULL, TRUE ) )
- {
- return false;
- }
- STACKFRAME stackFrame = { 0 };
- stackFrame.AddrPC.Mode = AddrModeFlat;
- stackFrame.AddrPC.Offset = lpEP->ContextRecord->Eip;
- stackFrame.AddrStack.Mode = AddrModeFlat;
- stackFrame.AddrStack.Offset = lpEP->ContextRecord->Esp;
- stackFrame.AddrFrame.Mode = AddrModeFlat;
- stackFrame.AddrFrame.Offset = lpEP->ContextRecord->Ebp;
-
- const static size_t MAX_DEPTH = 30;
- const static size_t MIN_INDEX = 3;
- size_t index = 0;
- while ( StackWalk (
- MachineType, GetCurrentProcess(), GetCurrentThread(),
- &stackFrame, lpEP->ContextRecord, NULL,
- SymFunctionTableAccess, SymGetModuleBase, NULL )/*StackWalk*/)
- {
- if ( index++ < MIN_INDEX ) continue ;
- if ( index > MAX_DEPTH ) break ;
- assert( stackFrame.AddrFrame.Offset != 0);
- const size_t BUF_LEN = 1024;
- unsigned char * symbolBuffer = new unsigned char[sizeof( SYMBOL_INFO ) + BUF_LEN];
- PSYMBOL_INFO pSymbol = reinterpret_cast<PSYMBOL_INFO>(symbolBuffer);
- pSymbol->SizeOfStruct = sizeof( SYMBOL_INFO );
- pSymbol->MaxNameLen = BUF_LEN;
- SymFromAddr( GetCurrentProcess(), stackFrame.AddrPC.Offset, 0, pSymbol );
-
- IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
- DWORD dwLineDisplacement;
- SymGetLineFromAddr(
- GetCurrentProcess(), stackFrame.AddrPC.Offset,
- &dwLineDisplacement, &lineInfo );
- char cstrInfo[256] = {0};
- sprintf_s(cstrInfo,"%s(%d) : [threadID=%d] [function=%s]\n",
- lineInfo.FileName, lineInfo.LineNumber,
- GetCurrentThreadId(), pSymbol->Name );
- OutputDebugStringA( cstrInfo );
- delete[]symbolBuffer; symbolBuffer = NULL;
- }
- if( ! SymCleanup( GetCurrentProcess() ) )
- {
- return false;
- }
- return true;
- }
- void printCallStark()
- {
- __try
- {
- throw "";
- }
- __except( _printCallStark(
- IMAGE_FILE_MACHINE_I386,
- GetExceptionInformation() )/*printCallStark*/)
- {
- printf( "Some exception occures.\n" );
- }
- }
简单的测试代码:
- void test_function()
- {
- printCallStark();
- }
- int main()
- {
- test_function();
- return 0;
- }
输出结果如下, 双击定位到源文件相关位置.
- d:\src-project\basictest\basictest\main.cpp(77) : [threadID=10184] [function=test_function]
- d:\src-project\basictest\basictest\main.cpp(82) : [threadID=10184] [function=main]
- f:\sp\vctools\crt_bld\self_x86\crt\src\crtexe.c(597) : [threadID=10184] [function=__tmainCRTStartup]
- f:\sp\vctools\crt_bld\self_x86\crt\src\crtexe.c(414) : [threadID=10184] [function=mainCRTStartup]
- (null)(0) : [threadID=10184] [function=BaseThreadInitThunk]
- (null)(0) : [threadID=10184] [function=RtlInitializeExceptionChain]
- (null)(0) : [threadID=10184] [function=RtlInitializeExceptionChain]
- 程序“[7272] basicTest.exe: 本机”已退出,返回值为 0 (0x0)。
阅读(1460) | 评论(0) | 转发(0) |