【IT168技术文档】
这里,就给出一个采用内联汇编来获取App调用堆栈的例子,这个例子里面,由于调试生成的符号文件没有加载好,故而Mudule的信息不能很好的显示出来,不过这个例子很好的演示了使用内联汇编来获取Stack Frame,从而print出整个函数的调用堆栈来,同时也是一个很好的使用DbgHelp来获取调试信息的例子:
#include "stdafx.h" #include <windows.h> #include <dbghelp.h> #define INVALID_FP_RET_ADDR_VALUE 0x00000000 BOOL g_fSymInit; HANDLE g_hProcess; //address of the founction stack-call to walk. BOOL DisplaySymbolDetails(DWORD dwAddress) { DWORD64 displacement = 0; ULONG64 buffer[(sizeof(SYMBOL_INFO) + MAX_SYM_NAME*sizeof(TCHAR) + sizeof(ULONG64) - 1) / sizeof(ULONG64)]; PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; pSymbol->SizeOfStruct = sizeof(SYMBOL_INFO); pSymbol->MaxNameLen = MAX_SYM_NAME; if (SymFromAddr(g_hProcess,dwAddress,&displacement,pSymbol)) { // Try to get the Module details IMAGEHLP_MODULE64 moduleinfo; moduleinfo.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); if (SymGetModuleInfo64(g_hProcess,pSymbol->Address,&moduleinfo)) { printf("%s!",moduleinfo.ModuleName); } else { printf("<ErrorModuleInfo_%d>!", GetLastError()); } // now print the function name if (pSymbol->MaxNameLen > 0) { printf("%s",pSymbol->Name); } else { printf("<Unknown_Function>"); } } else { printf(" <Unable to get symbol details_%d>", GetLastError()); } return TRUE; } //采用内联汇编获取当前stack Frame地址和当前程序指令地址. bool WalkTheStack() { DWORD _ebp = INVALID_FP_RET_ADDR_VALUE; DWORD dwIPOfCurrentFunction = (DWORD)&WalkTheStack; // Get the current Frame pointer __asm { mov [_ebp], ebp } // We cannot walk the stack (yet!) without a frame pointer if (_ebp == INVALID_FP_RET_ADDR_VALUE) return false; printf("CurFP\t\t\tRetAddr\n"); //current Frame Pointer DWORD *pCurFP = (DWORD *)_ebp; BOOL fFirstFP = TRUE; while (pCurFP != INVALID_FP_RET_ADDR_VALUE) { // pointer arithmetic works in terms of type pointed to. Thus, // "+1" below is equivalent of 4 bytes since we are doing DWORD // math. // Find Caller,next print. DWORD pRetAddrInCaller = (*((DWORD *)(pCurFP + 1))); printf("%p\t\t%p ",pCurFP, (DWORD *)pRetAddrInCaller); if (g_fSymInit) { if (fFirstFP) { fFirstFP = FALSE; } DisplaySymbolDetails(dwIPOfCurrentFunction); // To get the name of the next function up the stack, // we use the return address of the current frame dwIPOfCurrentFunction = pRetAddrInCaller; } printf("\n"); if (pRetAddrInCaller == INVALID_FP_RET_ADDR_VALUE) { // StackWalk is over now... break; } // move up the stack to our caller DWORD pCallerFP = *((DWORD *)pCurFP); pCurFP = (DWORD *)pCallerFP; } return true; } int _tmain(int argc, _TCHAR* argv[]) { // Initialize the debugger services to retrieve detailed stack info g_fSymInit = FALSE; g_hProcess = GetCurrentProcess(); if (!SymInitialize(g_hProcess, NULL,TRUE)) { printf("Unable to initialize symbols!\n\n"); } g_fSymInit = TRUE; //SYMOPT_UNDNAME:All symbols are presented in undecorated form. //SYMOPT_INCLUDE_32BIT_MODULES: //When debugging on 64-bit Windows, include any 32-bit modules. //SYMOPT_ALLOW_ABSOLUTE_SYMBOLS: //Enables the use of symbols that are stored with absolute addresses. instead of RAVS forms. SymSetOptions(SYMOPT_UNDNAME|SYMOPT_INCLUDE_32BIT_MODULES|SYMOPT_ALLOW_ABSOLUTE_SYMBOLS); if (WalkTheStack() == false) printf("Stackwalk failed!\n"); return 0; }