打印windows程序调用栈

来源:互联网 发布:猴子头像是什么软件 编辑:程序博客网 时间:2024/06/03 19:51

原文地址:http://www.codeproject.com/Articles/11132/Walking-the-callstack


源代码

/*********************************************************************** * StackWalker.h*** History:*  2005-07-27   v1    - First public release on http://www.codeproject.com/*  (for additional changes see History in 'StackWalker.cpp'!***********************************************************************/// #pragma once is supported starting with _MCS_VER 1000, // so we need not to check the version (because we only support _MSC_VER >= 1100)!#pragma once#include <windows.h>// special defines for VC5/6 (if no actual PSDK is installed):#if _MSC_VER < 1300typedef unsigned __int64 DWORD64, *PDWORD64;#if defined(_WIN64)typedef unsigned __int64 SIZE_T, *PSIZE_T;#elsetypedef unsigned long SIZE_T, *PSIZE_T;#endif#endif  // _MSC_VER < 1300class StackWalkerInternal;  // forwardclass StackWalker{public:typedef enum StackWalkOptions{// No addition info will be retrived // (only the address is available)RetrieveNone = 0,// Try to get the symbol-nameRetrieveSymbol = 1,// Try to get the line for this symbolRetrieveLine = 2,// Try to retrieve the module-infosRetrieveModuleInfo = 4,// Also retrieve the version for the DLL/EXERetrieveFileVersion = 8,// Contains all the abouveRetrieveVerbose = 0xF,// Generate a "good" symbol-search-pathSymBuildPath = 0x10,// Also use the public Microsoft-Symbol-ServerSymUseSymSrv = 0x20,// Contains all the abouve "Sym"-optionsSymAll = 0x30,// Contains all options (default)OptionsAll = 0x3F} StackWalkOptions;StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flagsLPCSTR szSymPath = NULL, DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess());StackWalker(DWORD dwProcessId, HANDLE hProcess);virtual ~StackWalker();typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(HANDLE      hProcess,DWORD64     qwBaseAddress,PVOID       lpBuffer,DWORD       nSize,LPDWORD     lpNumberOfBytesRead,LPVOID      pUserData  // optional data, which was passed in "ShowCallstack");BOOL LoadModules();BOOL ShowCallstack(HANDLE hThread = GetCurrentThread(), const CONTEXT *context = NULL, PReadProcessMemoryRoutine readMemoryFunction = NULL,LPVOID pUserData = NULL  // optional to identify some data in the 'readMemoryFunction'-callback);#if _MSC_VER >= 1300// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" // in older compilers in order to use it... starting with VC7 we can declare it as "protected"protected:#endifenum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbolsprotected:// Entry for each Callstack-Entrytypedef struct CallstackEntry{DWORD64 offset;  // if 0, we have no valid entryCHAR name[STACKWALK_MAX_NAMELEN];CHAR undName[STACKWALK_MAX_NAMELEN];CHAR undFullName[STACKWALK_MAX_NAMELEN];DWORD64 offsetFromSmybol;DWORD offsetFromLine;DWORD lineNumber;CHAR lineFileName[STACKWALK_MAX_NAMELEN];DWORD symType;LPCSTR symTypeString;CHAR moduleName[STACKWALK_MAX_NAMELEN];DWORD64 baseOfImage;CHAR loadedImageName[STACKWALK_MAX_NAMELEN];} CallstackEntry;typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);virtual void OnOutput(LPCSTR szText);StackWalkerInternal *m_sw;HANDLE m_hProcess;DWORD m_dwProcessId;BOOL m_modulesLoaded;LPSTR m_szSymPath;int m_options;static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);friend StackWalkerInternal;};// The "ugly" assembler-implementation is needed for systems before XP// If you have a new PSDK and you only compile for XP and later, then you can use // the "RtlCaptureContext"// Currently there is no define which determines the PSDK-Version... // So we just use the compiler-version (and assumes that the PSDK is // the one which was installed by the VS-IDE)// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...//       But I currently use it in x64/IA64 environments...//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)#if defined(_M_IX86)#ifdef CURRENT_THREAD_VIA_EXCEPTION// TODO: The following is not a "good" implementation, // because the callstack is only valid in the "__except" block...#define GET_CURRENT_CONTEXT(c, contextFlags) \do { \memset(&c, 0, sizeof(CONTEXT)); \EXCEPTION_POINTERS *pExp = NULL; \__try { \throw 0; \} __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \if (pExp != NULL) \memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \c.ContextFlags = contextFlags; \} while(0);#else// The following should be enough for walking the callstack...#define GET_CURRENT_CONTEXT(c, contextFlags) \do { \memset(&c, 0, sizeof(CONTEXT)); \c.ContextFlags = contextFlags; \__asm    call x \__asm x: pop eax \__asm    mov c.Eip, eax \__asm    mov c.Ebp, ebp \__asm    mov c.Esp, esp \} while(0);#endif#else// The following is defined for x86 (XP and higher), x64 and IA64:#define GET_CURRENT_CONTEXT(c, contextFlags) \do { \memset(&c, 0, sizeof(CONTEXT)); \c.ContextFlags = contextFlags; \RtlCaptureContext(&c); \} while(0);#endif

/*********************************************************************** * StackWalker.cpp*** History:*  2005-07-27   v1    - First public release on http://www.codeproject.com/*                       http://www.codeproject.com/threads/StackWalker.asp*  2005-07-28   v2    - Changed the params of the constructor and ShowCallstack*                       (to simplify the usage)*  2005-08-01   v3    - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL *                       (should also be enough)*                     - Changed to compile correctly with the PSDK of VC7.0*                       (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:*                        it uses LPSTR instead of LPCSTR as first paremeter)*                     - Added declarations to support VC5/6 without using 'dbghelp.h'*                     - Added a 'pUserData' member to the ShowCallstack function and the *                       PReadProcessMemoryRoutine declaration (to pass some user-defined data, *                       which can be used in the readMemoryFunction-callback)*  2005-08-02   v4    - OnSymInit now also outputs the OS-Version by default*                     - Added example for doing an exception-callstack-walking in main.cpp*                       (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)*  2005-08-05   v5    - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!***********************************************************************/#include <windows.h>#include <tchar.h>#include <stdio.h>#pragma comment(lib, "version.lib")  // for "VerQueryValue"#include "StackWalker.h"// If VC7 and later, then use the shipped 'dbghelp.h'-file#if _MSC_VER >= 1300#include <dbghelp.h>#else// inline the important dbghelp.h-declarations...typedef enum {SymNone = 0,SymCoff,SymCv,SymPdb,SymExport,SymDeferred,SymSym,SymDia,SymVirtual,NumSymTypes} SYM_TYPE;typedef struct _IMAGEHLP_LINE64 {DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_LINE64)PVOID                       Key;                    // internalDWORD                       LineNumber;             // line number in filePCHAR                       FileName;               // full filenameDWORD64                     Address;                // first instruction of line} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;typedef struct _IMAGEHLP_MODULE64 {DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)DWORD64                     BaseOfImage;            // base load address of moduleDWORD                       ImageSize;              // virtual size of the loaded moduleDWORD                       TimeDateStamp;          // date/time stamp from pe headerDWORD                       CheckSum;               // checksum from the pe headerDWORD                       NumSyms;                // number of symbols in the symbol tableSYM_TYPE                    SymType;                // type of symbols loadedCHAR                        ModuleName[32];         // module nameCHAR                        ImageName[256];         // image nameCHAR                        LoadedImageName[256];   // symbol file name} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;typedef struct _IMAGEHLP_SYMBOL64 {DWORD                       SizeOfStruct;           // set to sizeof(IMAGEHLP_SYMBOL64)DWORD64                     Address;                // virtual address including dll base addressDWORD                       Size;                   // estimated size of symbol, can be zeroDWORD                       Flags;                  // info about the symbols, see the SYMF definesDWORD                       MaxNameLength;          // maximum size of symbol name in 'Name'CHAR                        Name[1];                // symbol name (null terminated string)} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;typedef enum {AddrMode1616,AddrMode1632,AddrModeReal,AddrModeFlat} ADDRESS_MODE;typedef struct _tagADDRESS64 {DWORD64       Offset;WORD          Segment;ADDRESS_MODE  Mode;} ADDRESS64, *LPADDRESS64;typedef struct _KDHELP64 {DWORD64   Thread;DWORD   ThCallbackStack;DWORD   ThCallbackBStore;DWORD   NextCallback;DWORD   FramePointer;DWORD64   KiCallUserMode;DWORD64   KeUserCallbackDispatcher;DWORD64   SystemRangeStart;DWORD64  Reserved[8];} KDHELP64, *PKDHELP64;typedef struct _tagSTACKFRAME64 {ADDRESS64   AddrPC;               // program counterADDRESS64   AddrReturn;           // return addressADDRESS64   AddrFrame;            // frame pointerADDRESS64   AddrStack;            // stack pointerADDRESS64   AddrBStore;           // backing store pointerPVOID       FuncTableEntry;       // pointer to pdata/fpo or NULLDWORD64     Params[4];            // possible arguments to the functionBOOL        Far;                  // WOW far callBOOL        Virtual;              // is this a virtual frame?DWORD64     Reserved[3];KDHELP64    KdHelp;} STACKFRAME64, *LPSTACKFRAME64;typedefBOOL(__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE      hProcess,DWORD64     qwBaseAddress,PVOID       lpBuffer,DWORD       nSize,LPDWORD     lpNumberOfBytesRead);typedefPVOID(__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE  hProcess,DWORD64 AddrBase);typedefDWORD64(__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE  hProcess,DWORD64 Address);typedefDWORD64(__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE    hProcess,HANDLE    hThread,LPADDRESS64 lpaddr);#define SYMOPT_CASE_INSENSITIVE         0x00000001#define SYMOPT_UNDNAME                  0x00000002#define SYMOPT_DEFERRED_LOADS           0x00000004#define SYMOPT_NO_CPP                   0x00000008#define SYMOPT_LOAD_LINES               0x00000010#define SYMOPT_OMAP_FIND_NEAREST        0x00000020#define SYMOPT_LOAD_ANYTHING            0x00000040#define SYMOPT_IGNORE_CVREC             0x00000080#define SYMOPT_NO_UNQUALIFIED_LOADS     0x00000100#define SYMOPT_FAIL_CRITICAL_ERRORS     0x00000200#define SYMOPT_EXACT_SYMBOLS            0x00000400#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS   0x00000800#define SYMOPT_IGNORE_NT_SYMPATH        0x00001000#define SYMOPT_INCLUDE_32BIT_MODULES    0x00002000#define SYMOPT_PUBLICS_ONLY             0x00004000#define SYMOPT_NO_PUBLICS               0x00008000#define SYMOPT_AUTO_PUBLICS             0x00010000#define SYMOPT_NO_IMAGE_SEARCH          0x00020000#define SYMOPT_SECURE                   0x00040000#define SYMOPT_DEBUG                    0x80000000#define UNDNAME_COMPLETE                 (0x0000)  // Enable full undecoration#define UNDNAME_NAME_ONLY                (0x1000)  // Crack only the name for primary declaration;#endif  // _MSC_VER < 1300// Some missing defines (for VC5/6):#ifndef INVALID_FILE_ATTRIBUTES#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)#endif  // secure-CRT_functions are only available starting with VC8#if _MSC_VER < 1400#define strcpy_s strcpy#define strcat_s(dst, len, src) strcat(dst, src)#define _snprintf_s _snprintf#define _tcscat_s _tcscat#endif// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')#define USED_CONTEXT_FLAGS CONTEXT_FULLclass StackWalkerInternal{public:StackWalkerInternal(StackWalker *parent, HANDLE hProcess){m_parent = parent;m_hDbhHelp = NULL;pSC = NULL;m_hProcess = hProcess;m_szSymPath = NULL;pSFTA = NULL;pSGLFA = NULL;pSGMB = NULL;pSGMI = NULL;pSGO = NULL;pSGSFA = NULL;pSI = NULL;pSLM = NULL;pSSO = NULL;pSW = NULL;pUDSN = NULL;pSGSP = NULL;}~StackWalkerInternal(){if (pSC != NULL)pSC(m_hProcess);  // SymCleanupif (m_hDbhHelp != NULL)FreeLibrary(m_hDbhHelp);m_hDbhHelp = NULL;m_parent = NULL;if(m_szSymPath != NULL)free(m_szSymPath);m_szSymPath = NULL;}BOOL Init(LPCSTR szSymPath){if (m_parent == NULL)return FALSE;// Dynamically load the Entry-Points for dbghelp.dll:// First try to load the newsest one fromTCHAR szTemp[4096];// But before wqe do this, we first check if the ".local" file existsif (GetModuleFileName(NULL, szTemp, 4096) > 0){_tcscat_s(szTemp, _T(".local"));if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES){// ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"if (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0){_tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));// now check if the file exists:if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES){m_hDbhHelp = LoadLibrary(szTemp);}}// Still not found? Then try to load the 64-Bit version:if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) ){_tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES){m_hDbhHelp = LoadLibrary(szTemp);}}}}if (m_hDbhHelp == NULL)  // if not already loaded, try to load a default-onem_hDbhHelp = LoadLibrary( _T("dbghelp.dll") );if (m_hDbhHelp == NULL)return FALSE;pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" );pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" );pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" );pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" );pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" );pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );//pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" );pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" );if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||pSW == NULL || pUDSN == NULL || pSLM == NULL ){FreeLibrary(m_hDbhHelp);m_hDbhHelp = NULL;pSC = NULL;return FALSE;}// SymInitializeif (szSymPath != NULL)m_szSymPath = _strdup(szSymPath);if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);DWORD symOptions = this->pSGO();  // SymGetOptionssymOptions |= SYMOPT_LOAD_LINES;symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;//symOptions |= SYMOPT_NO_PROMPTS;// SymSetOptionssymOptions = this->pSSO(symOptions);char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};if (this->pSGSP != NULL){if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);}char szUserName[1024] = {0};DWORD dwSize = 1024;GetUserNameA(szUserName, &dwSize);this->m_parent->OnSymInit(buf, symOptions, szUserName);return TRUE;}StackWalker *m_parent;HMODULE m_hDbhHelp;HANDLE m_hProcess;LPSTR m_szSymPath;/*typedef struct IMAGEHLP_MODULE64_V3 {DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)DWORD64  BaseOfImage;            // base load address of moduleDWORD    ImageSize;              // virtual size of the loaded moduleDWORD    TimeDateStamp;          // date/time stamp from pe headerDWORD    CheckSum;               // checksum from the pe headerDWORD    NumSyms;                // number of symbols in the symbol tableSYM_TYPE SymType;                // type of symbols loadedCHAR     ModuleName[32];         // module nameCHAR     ImageName[256];         // image name// new elements: 07-Jun-2002CHAR     LoadedImageName[256];   // symbol file nameCHAR     LoadedPdbName[256];     // pdb file nameDWORD    CVSig;                  // Signature of the CV record in the debug directoriesCHAR         CVData[MAX_PATH * 3];   // Contents of the CV recordDWORD    PdbSig;                 // Signature of PDBGUID     PdbSig70;               // Signature of PDB (VC 7 and up)DWORD    PdbAge;                 // DBI age of pdbBOOL     PdbUnmatched;           // loaded an unmatched pdbBOOL     DbgUnmatched;           // loaded an unmatched dbgBOOL     LineNumbers;            // we have line number informationBOOL     GlobalSymbols;          // we have internal symbol informationBOOL     TypeInfo;               // we have type information// new elements: 17-Dec-2003BOOL     SourceIndexed;          // pdb supports source serverBOOL     Publics;                // contains public symbols};*/typedef struct IMAGEHLP_MODULE64_V2 {DWORD    SizeOfStruct;           // set to sizeof(IMAGEHLP_MODULE64)DWORD64  BaseOfImage;            // base load address of moduleDWORD    ImageSize;              // virtual size of the loaded moduleDWORD    TimeDateStamp;          // date/time stamp from pe headerDWORD    CheckSum;               // checksum from the pe headerDWORD    NumSyms;                // number of symbols in the symbol tableSYM_TYPE SymType;                // type of symbols loadedCHAR     ModuleName[32];         // module nameCHAR     ImageName[256];         // image nameCHAR     LoadedImageName[256];   // symbol file name};// SymCleanup()typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );tSC pSC;// SymFunctionTableAccess64()typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );tSFTA pSFTA;// SymGetLineFromAddr64()typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );tSGLFA pSGLFA;// SymGetModuleBase64()typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );tSGMB pSGMB;// SymGetModuleInfo64()typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo );tSGMI pSGMI;//  // SymGetModuleInfo64()//  typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );//  tSGMI_V3 pSGMI_V3;// SymGetOptions()typedef DWORD (__stdcall *tSGO)( VOID );tSGO pSGO;// SymGetSymFromAddr64()typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );tSGSFA pSGSFA;// SymInitialize()typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );tSI pSI;// SymLoadModule64()typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );tSLM pSLM;// SymSetOptions()typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );tSSO pSSO;// StackWalk64()typedef BOOL (__stdcall *tSW)( DWORD MachineType, HANDLE hProcess,HANDLE hThread, LPSTACKFRAME64 StackFrame, PVOID ContextRecord,PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );tSW pSW;// UnDecorateSymbolName()typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,DWORD UndecoratedLength, DWORD Flags );tUDSN pUDSN;typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);tSGSP pSGSP;private:// **************************************** ToolHelp32 ************************#define MAX_MODULE_NAME32 255#define TH32CS_SNAPMODULE   0x00000008#pragma pack( push, 8 )typedef struct tagMODULEENTRY32{DWORD   dwSize;DWORD   th32ModuleID;       // This moduleDWORD   th32ProcessID;      // owning processDWORD   GlblcntUsage;       // Global usage count on the moduleDWORD   ProccntUsage;       // Module usage count in th32ProcessID's contextBYTE  * modBaseAddr;        // Base address of module in th32ProcessID's contextDWORD   modBaseSize;        // Size in bytes of module starting at modBaseAddrHMODULE hModule;            // The hModule of this module in th32ProcessID's contextchar    szModule[MAX_MODULE_NAME32 + 1];char    szExePath[MAX_PATH];} MODULEENTRY32;typedef MODULEENTRY32 *  PMODULEENTRY32;typedef MODULEENTRY32 *  LPMODULEENTRY32;#pragma pack( pop )BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid){// CreateToolhelp32Snapshot()typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);// Module32First()typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);// Module32Next()typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);// try both dlls...const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };HINSTANCE hToolhelp = NULL;tCT32S pCT32S = NULL;tM32F pM32F = NULL;tM32N pM32N = NULL;HANDLE hSnap;MODULEENTRY32 me;me.dwSize = sizeof(me);BOOL keepGoing;size_t i;for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ ){hToolhelp = LoadLibrary( dllname[i] );if (hToolhelp == NULL)continue;pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) )break; // found the functions!FreeLibrary(hToolhelp);hToolhelp = NULL;}if (hToolhelp == NULL)return FALSE;hSnap = pCT32S( TH32CS_SNAPMODULE, pid );if (hSnap == (HANDLE) -1)return FALSE;keepGoing = !!pM32F( hSnap, &me );int cnt = 0;while (keepGoing){this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize);cnt++;keepGoing = !!pM32N( hSnap, &me );}CloseHandle(hSnap);FreeLibrary(hToolhelp);if (cnt <= 0)return FALSE;return TRUE;}  // GetModuleListTH32// **************************************** PSAPI ************************typedef struct _MODULEINFO {LPVOID lpBaseOfDll;DWORD SizeOfImage;LPVOID EntryPoint;} MODULEINFO, *LPMODULEINFO;BOOL GetModuleListPSAPI(HANDLE hProcess){// EnumProcessModules()typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );// GetModuleFileNameEx()typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );// GetModuleBaseName()typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );// GetModuleInformation()typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );HINSTANCE hPsapi;tEPM pEPM;tGMFNE pGMFNE;tGMBN pGMBN;tGMI pGMI;DWORD i;//ModuleEntry e;DWORD cbNeeded;MODULEINFO mi;HMODULE *hMods = 0;char *tt = NULL;char *tt2 = NULL;const SIZE_T TTBUFLEN = 8096;int cnt = 0;hPsapi = LoadLibrary( _T("psapi.dll") );if (hPsapi == NULL)return FALSE;pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) ){// we couldn�t find all functionsFreeLibrary(hPsapi);return FALSE;}hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));tt = (char*) malloc(sizeof(char) * TTBUFLEN);tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )goto cleanup;if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) ){//_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );goto cleanup;}if ( cbNeeded > TTBUFLEN ){//_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );goto cleanup;}for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ ){// base address, sizepGMI(hProcess, hMods[i], &mi, sizeof mi );// image file namett[0] = 0;pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );// module namett2[0] = 0;pGMBN(hProcess, hMods[i], tt2, TTBUFLEN );DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage);if (dwRes != ERROR_SUCCESS)this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);cnt++;}cleanup:if (hPsapi != NULL) FreeLibrary(hPsapi);if (tt2 != NULL) free(tt2);if (tt != NULL) free(tt);if (hMods != NULL) free(hMods);return cnt != 0;}  // GetModuleListPSAPIDWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size){CHAR *szImg = _strdup(img);CHAR *szMod = _strdup(mod);DWORD result = ERROR_SUCCESS;if ( (szImg == NULL) || (szMod == NULL) )result = ERROR_NOT_ENOUGH_MEMORY;else{if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)result = GetLastError();}ULONGLONG fileVersion = 0;if ( (m_parent != NULL) && (szImg != NULL) ){// try to retrive the file-version:if ( (this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0){VS_FIXEDFILEINFO *fInfo = NULL;DWORD dwHandle;DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);if (dwSize > 0){LPVOID vData = malloc(dwSize);if (vData != NULL){if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0){UINT len;TCHAR szSubBlock[] = _T("\\");if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0)fInfo = NULL;else{fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);}}free(vData);}}}// Retrive some additional-infos about the moduleIMAGEHLP_MODULE64_V2 Module;const char *szSymType = "-unknown-";if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE){switch(Module.SymType){case SymNone:szSymType = "-nosymbols-";break;case SymCoff:szSymType = "COFF";break;case SymCv:szSymType = "CV";break;case SymPdb:szSymType = "PDB";break;case SymExport:szSymType = "-exported-";break;case SymDeferred:szSymType = "-deferred-";break;case SymSym:szSymType = "SYM";break;case 8: //SymVirtual:szSymType = "Virtual";break;case 9: // SymDia:szSymType = "DIA";break;}}this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, Module.LoadedImageName, fileVersion);}if (szImg != NULL) free(szImg);if (szMod != NULL) free(szMod);return result;}public:BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId){// first try toolhelp32if (GetModuleListTH32(hProcess, dwProcessId))return true;// then try psapireturn GetModuleListPSAPI(hProcess);}BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V2 *pModuleInfo){if(this->pSGMI == NULL){SetLastError(ERROR_DLL_INIT_FAILED);return FALSE;}// First try to use the larger ModuleInfo-Structure//    memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));//    pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);//    if (this->pSGMI_V3 != NULL)//    {//      if (this->pSGMI_V3(hProcess, baseAddr, pModuleInfo) != FALSE)//        return TRUE;//      // check if the parameter was wrong (size is bad...)//      if (GetLastError() != ERROR_INVALID_PARAMETER)//        return FALSE;//    }// could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...if (pData == NULL){SetLastError(ERROR_NOT_ENOUGH_MEMORY);return FALSE;}memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V2*) pData) != FALSE){// only copy as much memory as is reserved...memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);free(pData);return TRUE;}free(pData);SetLastError(ERROR_DLL_INIT_FAILED);return FALSE;}};// #############################################################StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess){this->m_options = OptionsAll;this->m_modulesLoaded = FALSE;this->m_hProcess = hProcess;this->m_sw = new StackWalkerInternal(this, this->m_hProcess);this->m_dwProcessId = dwProcessId;this->m_szSymPath = NULL;}StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess){this->m_options = options;this->m_modulesLoaded = FALSE;this->m_hProcess = hProcess;this->m_sw = new StackWalkerInternal(this, this->m_hProcess);this->m_dwProcessId = dwProcessId;if (szSymPath != NULL){this->m_szSymPath = _strdup(szSymPath);this->m_options |= SymBuildPath;}elsethis->m_szSymPath = NULL;}StackWalker::~StackWalker(){if (m_szSymPath != NULL)free(m_szSymPath);m_szSymPath = NULL;if (this->m_sw != NULL)delete this->m_sw;this->m_sw = NULL;}BOOL StackWalker::LoadModules(){if (this->m_sw == NULL){SetLastError(ERROR_DLL_INIT_FAILED);return FALSE;}if (m_modulesLoaded != FALSE)return TRUE;// Build the sym-path:char *szSymPath = NULL;if ( (this->m_options & SymBuildPath) != 0){const size_t nSymPathLen = 4096;szSymPath = (char*) malloc(nSymPathLen);if (szSymPath == NULL){SetLastError(ERROR_NOT_ENOUGH_MEMORY);return FALSE;}szSymPath[0] = 0;// Now first add the (optional) provided sympath:if (this->m_szSymPath != NULL){strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);strcat_s(szSymPath, nSymPathLen, ";");}strcat_s(szSymPath, nSymPathLen, ".;");const size_t nTempLen = 1024;char szTemp[nTempLen];// Now add the current directory:if (GetCurrentDirectoryA(nTempLen, szTemp) > 0){szTemp[nTempLen-1] = 0;strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, ";");}// Now add the path for the main-module:if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0){szTemp[nTempLen-1] = 0;for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p){// locate the rightmost path separatorif ( (*p == '\\') || (*p == '/') || (*p == ':') ){*p = 0;break;}}  // for (search for path separator...)if (strlen(szTemp) > 0){strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, ";");}}if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0){szTemp[nTempLen-1] = 0;strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, ";");}if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0){szTemp[nTempLen-1] = 0;strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, ";");}if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0){szTemp[nTempLen-1] = 0;strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, ";");// also add the "system32"-directory:strcat_s(szTemp, nTempLen, "\\system32");strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, ";");}if ( (this->m_options & SymBuildPath) != 0){if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0){szTemp[nTempLen-1] = 0;strcat_s(szSymPath, nSymPathLen, "SRV*");strcat_s(szSymPath, nSymPathLen, szTemp);strcat_s(szSymPath, nSymPathLen, "\\websymbols");strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");}elsestrcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");}}// First Init the whole stuff...BOOL bRet = this->m_sw->Init(szSymPath);if (szSymPath != NULL) free(szSymPath); szSymPath = NULL;if (bRet == FALSE){this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);SetLastError(ERROR_DLL_INIT_FAILED);return FALSE;}bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);if (bRet != FALSE)m_modulesLoaded = TRUE;return bRet;}// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction// This has to be done due to a problem with the "hProcess"-parameter in x64...// Because this class is in no case multi-threading-enabled (because of the limitations // of dbghelp.dll) it is "safe" to use a static-variablestatic StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;static LPVOID s_readMemoryFunction_UserData = NULL;BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData){CONTEXT c;;CallstackEntry csEntry;IMAGEHLP_SYMBOL64 *pSym = NULL;StackWalkerInternal::IMAGEHLP_MODULE64_V2 Module;IMAGEHLP_LINE64 Line;int frameNum;if (m_modulesLoaded == FALSE)this->LoadModules();  // ignore the result...if (this->m_sw->m_hDbhHelp == NULL){SetLastError(ERROR_DLL_INIT_FAILED);return FALSE;}s_readMemoryFunction = readMemoryFunction;s_readMemoryFunction_UserData = pUserData;if (context == NULL){// If no context is provided, capture the contextif (hThread == GetCurrentThread()){GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);}else{SuspendThread(hThread);memset(&c, 0, sizeof(CONTEXT));c.ContextFlags = USED_CONTEXT_FLAGS;if (GetThreadContext(hThread, &c) == FALSE){ResumeThread(hThread);return FALSE;}}}elsec = *context;// init STACKFRAME for first callSTACKFRAME64 s; // in/out stackframememset(&s, 0, sizeof(s));DWORD imageType;#ifdef _M_IX86// normally, call ImageNtHeader() and use machine info from PE headerimageType = IMAGE_FILE_MACHINE_I386;s.AddrPC.Offset = c.Eip;s.AddrPC.Mode = AddrModeFlat;s.AddrFrame.Offset = c.Ebp;s.AddrFrame.Mode = AddrModeFlat;s.AddrStack.Offset = c.Esp;s.AddrStack.Mode = AddrModeFlat;#elif _M_X64imageType = IMAGE_FILE_MACHINE_AMD64;s.AddrPC.Offset = c.Rip;s.AddrPC.Mode = AddrModeFlat;s.AddrFrame.Offset = c.Rsp;s.AddrFrame.Mode = AddrModeFlat;s.AddrStack.Offset = c.Rsp;s.AddrStack.Mode = AddrModeFlat;#elif _M_IA64imageType = IMAGE_FILE_MACHINE_IA64;s.AddrPC.Offset = c.StIIP;s.AddrPC.Mode = AddrModeFlat;s.AddrFrame.Offset = c.IntSp;s.AddrFrame.Mode = AddrModeFlat;s.AddrBStore.Offset = c.RsBSP;s.AddrBStore.Mode = AddrModeFlat;s.AddrStack.Offset = c.IntSp;s.AddrStack.Mode = AddrModeFlat;#else#error "Platform not supported!"#endifpSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);if (!pSym) goto cleanup;  // not enough memory...memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;memset(&Line, 0, sizeof(Line));Line.SizeOfStruct = sizeof(Line);memset(&Module, 0, sizeof(Module));Module.SizeOfStruct = sizeof(Module);for (frameNum = 0; ; ++frameNum ){// get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can// assume that either you are done, or that the stack is so hosed that the next// deeper frame could not be found.// CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!if ( ! this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem, this->m_sw->pSFTA, this->m_sw->pSGMB, NULL) ){this->OnDbgHelpErr("StackWalk64", GetLastError(), s.AddrPC.Offset);break;}csEntry.offset = s.AddrPC.Offset;csEntry.name[0] = 0;csEntry.undName[0] = 0;csEntry.undFullName[0] = 0;csEntry.offsetFromSmybol = 0;csEntry.offsetFromLine = 0;csEntry.lineFileName[0] = 0;csEntry.lineNumber = 0;csEntry.loadedImageName[0] = 0;csEntry.moduleName[0] = 0;if (s.AddrPC.Offset == s.AddrReturn.Offset){this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);break;}if (s.AddrPC.Offset != 0){// we seem to have a valid PC// show procedure info (SymGetSymFromAddr64())if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE){// TODO: Mache dies sicher...!strcpy_s(csEntry.name, pSym->Name);// UnDecorateSymbolName()this->m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );this->m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );}else{this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);}// show line number info, NT5.0-method (SymGetLineFromAddr64())if (this->m_sw->pSGLFA != NULL ){ // yes, we have SymGetLineFromAddr64()if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE){csEntry.lineNumber = Line.LineNumber;// TODO: Mache dies sicher...!strcpy_s(csEntry.lineFileName, Line.FileName);}else{this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);}} // yes, we have SymGetLineFromAddr64()// show module info (SymGetModuleInfo64())if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module ) != FALSE){ // got module info OKswitch ( Module.SymType ){case SymNone:csEntry.symTypeString = "-nosymbols-";break;case SymCoff:csEntry.symTypeString = "COFF";break;case SymCv:csEntry.symTypeString = "CV";break;case SymPdb:csEntry.symTypeString = "PDB";break;case SymExport:csEntry.symTypeString = "-exported-";break;case SymDeferred:csEntry.symTypeString = "-deferred-";break;case SymSym:csEntry.symTypeString = "SYM";break;#if API_VERSION_NUMBER >= 9case SymDia:csEntry.symTypeString = "DIA";break;#endifcase 8: //SymVirtual:csEntry.symTypeString = "Virtual";break;default://_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );csEntry.symTypeString = NULL;break;}// TODO: Mache dies sicher...!strcpy_s(csEntry.moduleName, Module.ModuleName);csEntry.baseOfImage = Module.BaseOfImage;strcpy_s(csEntry.loadedImageName, Module.LoadedImageName);} // got module info OKelse{this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);}} // we seem to have a valid PCCallstackEntryType et = nextEntry;if (frameNum == 0)et = firstEntry;this->OnCallstackEntry(et, csEntry);if (s.AddrReturn.Offset == 0){this->OnCallstackEntry(lastEntry, csEntry);SetLastError(ERROR_SUCCESS);break;}} // for ( frameNum )cleanup:if (pSym) free( pSym );if (context == NULL)ResumeThread(hThread);return TRUE;}BOOL __stdcall StackWalker::myReadProcMem(HANDLE      hProcess,DWORD64     qwBaseAddress,PVOID       lpBuffer,DWORD       nSize,LPDWORD     lpNumberOfBytesRead){if (s_readMemoryFunction == NULL){SIZE_T st;BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);*lpNumberOfBytesRead = (DWORD) st;//printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);return bRet;}else{return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);}}void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion){CHAR buffer[STACKWALK_MAX_NAMELEN];if (fileVersion == 0)_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName);else{DWORD v4 = (DWORD) fileVersion & 0xFFFF;DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF;DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF;DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF;_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n", img, mod, (LPVOID) baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);}OnOutput(buffer);}void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry){CHAR buffer[STACKWALK_MAX_NAMELEN];if ( (eType != lastEntry) && (entry.offset != 0) ){if (entry.name[0] == 0)strcpy_s(entry.name, "(function-name not available)");if (entry.undName[0] != 0)strcpy_s(entry.name, entry.undName);if (entry.undFullName[0] != 0)strcpy_s(entry.name, entry.undFullName);if (entry.lineFileName[0] == 0){strcpy_s(entry.lineFileName, "(filename not available)");if (entry.moduleName[0] == 0)strcpy_s(entry.moduleName, "(module-name not available)");_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);}else_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);OnOutput(buffer);}}void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr){CHAR buffer[STACKWALK_MAX_NAMELEN];_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);OnOutput(buffer);}void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName){CHAR buffer[STACKWALK_MAX_NAMELEN];_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);OnOutput(buffer);// Also display the OS-version#if _MSC_VER <= 1200OSVERSIONINFOA ver;ZeroMemory(&ver, sizeof(OSVERSIONINFOA));ver.dwOSVersionInfoSize = sizeof(ver);if (GetVersionExA(&ver) != FALSE){_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,ver.szCSDVersion);OnOutput(buffer);}#elseOSVERSIONINFOEXA ver;ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));ver.dwOSVersionInfoSize = sizeof(ver);if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE){_snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);OnOutput(buffer);}#endif}void StackWalker::OnOutput(LPCSTR buffer){OutputDebugStringA(buffer);}

测试结果

StackWalker sw;sw.ShowCallstack();


输出:

SymInit: Symbol-SearchPath: '.;d:\cifs\test\localsvn\peer;d:\cifs\test\localsvn\bin\release;C:\Windows;C:\Windows\system32;SRV*C:\websymbols*http://msdl.microsoft.com/download/symbols;', symOptions: 530, UserName: 'Administrator'OS-Version: 6.1.7601 (Service Pack 1) 0x100-0x1d:\cifs\test\localsvn\bin\release\peer.exe:peer.exe (00160000), size: 40960 (result: 0), SymType: 'PDB', PDB: 'd:\cifs\test\localsvn\bin\release\peer.exe'C:\Windows\SysWOW64\ntdll.dll:ntdll.dll (779B0000), size: 1572864 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\SysWOW64\ntdll.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\kernel32.dll:kernel32.dll (75740000), size: 1114112 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\kernel32.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\KERNELBASE.dll:KERNELBASE.dll (75D30000), size: 286720 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\KERNELBASE.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\ADVAPI32.dll:ADVAPI32.dll (77120000), size: 655360 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\ADVAPI32.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\msvcrt.dll:msvcrt.dll (76E00000), size: 704512 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\msvcrt.dll', fileVersion: 7.0.7600.16385C:\Windows\SysWOW64\sechost.dll:sechost.dll (75DD0000), size: 102400 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\SysWOW64\sechost.dll', fileVersion: 6.1.7600.16385C:\Windows\syswow64\RPCRT4.dll:RPCRT4.dll (75B70000), size: 983040 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\RPCRT4.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\SspiCli.dll:SspiCli.dll (75510000), size: 393216 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\SspiCli.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\CRYPTBASE.dll:CRYPTBASE.dll (75500000), size: 49152 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\CRYPTBASE.dll', fileVersion: 6.1.7600.16385d:\cifs\test\localsvn\bin\release\libtvup.dll:libtvup.dll (5DD90000), size: 458752 (result: 0), SymType: 'PDB', PDB: 'd:\cifs\test\localsvn\bin\release\libtvup.dll'C:\Windows\syswow64\WS2_32.dll:WS2_32.dll (76D60000), size: 217088 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\WS2_32.dll', fileVersion: 6.1.7601.17514C:\Windows\syswow64\NSI.dll:NSI.dll (772C0000), size: 24576 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\syswow64\NSI.dll', fileVersion: 6.1.7600.16385C:\Windows\system32\IPHLPAPI.DLL:IPHLPAPI.DLL (73E80000), size: 114688 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\system32\IPHLPAPI.DLL', fileVersion: 6.1.7601.17514C:\Windows\system32\WINNSI.DLL:WINNSI.DLL (73E70000), size: 28672 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\system32\WINNSI.DLL', fileVersion: 6.1.7600.16385C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4940_none_50916076bcb9a742\MSVCR90.dll:MSVCR90.dll (74020000), size: 667648 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\WinSxS\x86_microsoft.vc90.crt_1fc8b3b9a1e18e3b_9.0.30729.4940_none_50916076bcb9a742\MSVCR90.dll', fileVersion: 9.0.30729.4940C:\Windows\system32\VERSION.dll:VERSION.dll (73EA0000), size: 36864 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\system32\VERSION.dll', fileVersion: 6.1.7600.16385C:\Windows\system32\dbghelp.dll:dbghelp.dll (73D80000), size: 962560 (result: 0), SymType: '-exported-', PDB: 'C:\Windows\system32\dbghelp.dll', fileVersion: 6.1.7601.17514d:\cifs\test\localsvn\peer\stackwalker.cpp (920): StackWalker::ShowCallstackd:\cifs\test\localsvn\peer\peer.cc (298): mainf:\dd\vctools\crt_bld\self_x86\crt\src\crtexe.c (582): __tmainCRTStartupERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 757533CA)757533CA (kernel32): (filename not available): BaseThreadInitThunkERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 779E9ED2)779E9ED2 (ntdll): (filename not available): RtlInitializeExceptionChainERROR: SymGetLineFromAddr64, GetLastError: 487 (Address: 779E9EA5)779E9EA5 (ntdll): (filename not available): RtlInitializeExceptionChain