Path: blob/main_old/util/windows/third_party/StackWalker/src/StackWalker.cpp
1695 views
/**********************************************************************1*2* StackWalker.cpp3* https://github.com/JochenKalmbach/StackWalker4*5* Old location: http://stackwalker.codeplex.com/6*7*8* History:9* 2005-07-27 v1 - First public release on http://www.codeproject.com/10* http://www.codeproject.com/threads/StackWalker.asp11* 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack12* (to simplify the usage)13* 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL14* (should also be enough)15* - Changed to compile correctly with the PSDK of VC7.016* (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:17* it uses LPSTR instead of LPCSTR as first parameter)18* - Added declarations to support VC5/6 without using 'dbghelp.h'19* - Added a 'pUserData' member to the ShowCallstack function and the20* PReadProcessMemoryRoutine declaration (to pass some user-defined data,21* which can be used in the readMemoryFunction-callback)22* 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default23* - Added example for doing an exception-callstack-walking in main.cpp24* (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)25* 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!26* 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag27* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx28* Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN"29* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx30* Fixed Bug: Compiling with "/Wall"31* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx32* Fixed Bug: Now checking SymUseSymSrv33* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx34* Fixed Bug: Support for recursive function calls35* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx36* Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32"37* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx38* Fixed Bug: SymDia is number 7, not 9!39* 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8!40* Thanks to Teajay which reported the bug...41* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx42* 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory43* Thanks to Luiz Salamon which reported this "bug"...44* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx45* 2009-04-10 v9 License slightly corrected (<ORGANIZATION> replaced)46* 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/47* 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available48* 2010-04-15 v12 Added support for VS2010 RTM49* 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon:50* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx51* 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed:52* http://stackwalker.codeplex.com/workitem/1051153*54*55* LICENSE (http://www.opensource.org/licenses/bsd-license.php)56*57* Copyright (c) 2005-2013, Jochen Kalmbach58* All rights reserved.59*60* Redistribution and use in source and binary forms, with or without modification,61* are permitted provided that the following conditions are met:62*63* Redistributions of source code must retain the above copyright notice,64* this list of conditions and the following disclaimer.65* Redistributions in binary form must reproduce the above copyright notice,66* this list of conditions and the following disclaimer in the documentation67* and/or other materials provided with the distribution.68* Neither the name of Jochen Kalmbach nor the names of its contributors may be69* used to endorse or promote products derived from this software without70* specific prior written permission.71* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"72* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,73* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE74* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE75* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES76* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;77* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND78* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT79* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS80* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.81*82**********************************************************************/8384#include "StackWalker.h"8586#include <stdio.h>87#include <stdlib.h>88#include <tchar.h>89#include <windows.h>90#pragma comment(lib, "version.lib") // for "VerQueryValue"91#pragma warning(disable : 4826)929394// If VC7 and later, then use the shipped 'dbghelp.h'-file95#pragma pack(push, 8)96#if _MSC_VER >= 130097#include <dbghelp.h>98#else99// inline the important dbghelp.h-declarations...100typedef enum101{102SymNone = 0,103SymCoff,104SymCv,105SymPdb,106SymExport,107SymDeferred,108SymSym,109SymDia,110SymVirtual,111NumSymTypes112} SYM_TYPE;113typedef struct _IMAGEHLP_LINE64114{115DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64)116PVOID Key; // internal117DWORD LineNumber; // line number in file118PCHAR FileName; // full filename119DWORD64 Address; // first instruction of line120} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;121typedef struct _IMAGEHLP_MODULE64122{123DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)124DWORD64 BaseOfImage; // base load address of module125DWORD ImageSize; // virtual size of the loaded module126DWORD TimeDateStamp; // date/time stamp from pe header127DWORD CheckSum; // checksum from the pe header128DWORD NumSyms; // number of symbols in the symbol table129SYM_TYPE SymType; // type of symbols loaded130CHAR ModuleName[32]; // module name131CHAR ImageName[256]; // image name132CHAR LoadedImageName[256]; // symbol file name133} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;134typedef struct _IMAGEHLP_SYMBOL64135{136DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64)137DWORD64 Address; // virtual address including dll base address138DWORD Size; // estimated size of symbol, can be zero139DWORD Flags; // info about the symbols, see the SYMF defines140DWORD MaxNameLength; // maximum size of symbol name in 'Name'141CHAR Name[1]; // symbol name (null terminated string)142} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;143typedef enum144{145AddrMode1616,146AddrMode1632,147AddrModeReal,148AddrModeFlat149} ADDRESS_MODE;150typedef struct _tagADDRESS64151{152DWORD64 Offset;153WORD Segment;154ADDRESS_MODE Mode;155} ADDRESS64, *LPADDRESS64;156typedef struct _KDHELP64157{158DWORD64 Thread;159DWORD ThCallbackStack;160DWORD ThCallbackBStore;161DWORD NextCallback;162DWORD FramePointer;163DWORD64 KiCallUserMode;164DWORD64 KeUserCallbackDispatcher;165DWORD64 SystemRangeStart;166DWORD64 Reserved[8];167} KDHELP64, *PKDHELP64;168typedef struct _tagSTACKFRAME64169{170ADDRESS64 AddrPC; // program counter171ADDRESS64 AddrReturn; // return address172ADDRESS64 AddrFrame; // frame pointer173ADDRESS64 AddrStack; // stack pointer174ADDRESS64 AddrBStore; // backing store pointer175PVOID FuncTableEntry; // pointer to pdata/fpo or NULL176DWORD64 Params[4]; // possible arguments to the function177BOOL Far; // WOW far call178BOOL Virtual; // is this a virtual frame?179DWORD64 Reserved[3];180KDHELP64 KdHelp;181} STACKFRAME64, *LPSTACKFRAME64;182typedef BOOL(__stdcall* PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,183DWORD64 qwBaseAddress,184PVOID lpBuffer,185DWORD nSize,186LPDWORD lpNumberOfBytesRead);187typedef PVOID(__stdcall* PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE hProcess, DWORD64 AddrBase);188typedef DWORD64(__stdcall* PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address);189typedef DWORD64(__stdcall* PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,190HANDLE hThread,191LPADDRESS64 lpaddr);192193// clang-format off194#define SYMOPT_CASE_INSENSITIVE 0x00000001195#define SYMOPT_UNDNAME 0x00000002196#define SYMOPT_DEFERRED_LOADS 0x00000004197#define SYMOPT_NO_CPP 0x00000008198#define SYMOPT_LOAD_LINES 0x00000010199#define SYMOPT_OMAP_FIND_NEAREST 0x00000020200#define SYMOPT_LOAD_ANYTHING 0x00000040201#define SYMOPT_IGNORE_CVREC 0x00000080202#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100203#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200204#define SYMOPT_EXACT_SYMBOLS 0x00000400205#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800206#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000207#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000208#define SYMOPT_PUBLICS_ONLY 0x00004000209#define SYMOPT_NO_PUBLICS 0x00008000210#define SYMOPT_AUTO_PUBLICS 0x00010000211#define SYMOPT_NO_IMAGE_SEARCH 0x00020000212#define SYMOPT_SECURE 0x00040000213#define SYMOPT_DEBUG 0x80000000214#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration215#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration;216// clang-format on217218#endif // _MSC_VER < 1300219#pragma pack(pop)220221// Some missing defines (for VC5/6):222#ifndef INVALID_FILE_ATTRIBUTES223#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)224#endif225226// secure-CRT_functions are only available starting with VC8227#if _MSC_VER < 1400228#define strcpy_s(dst, len, src) strcpy(dst, src)229#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)230#define strcat_s(dst, len, src) strcat(dst, src)231#define _snprintf_s _snprintf232#define _tcscat_s _tcscat233#endif234235static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)236{237if (nMaxDestSize <= 0)238return;239strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);240// INFO: _TRUNCATE will ensure that it is null-terminated;241// but with older compilers (<1400) it uses "strncpy" and this does not!)242szDest[nMaxDestSize - 1] = 0;243} // MyStrCpy244245// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')246#define USED_CONTEXT_FLAGS CONTEXT_FULL247248class StackWalkerInternal249{250public:251StackWalkerInternal(StackWalker* parent, HANDLE hProcess)252{253m_parent = parent;254m_hDbhHelp = NULL;255pSC = NULL;256m_hProcess = hProcess;257m_szSymPath = NULL;258pSFTA = NULL;259pSGLFA = NULL;260pSGMB = NULL;261pSGMI = NULL;262pSGO = NULL;263pSGSFA = NULL;264pSI = NULL;265pSLM = NULL;266pSSO = NULL;267pSW = NULL;268pUDSN = NULL;269pSGSP = NULL;270}271~StackWalkerInternal()272{273if (pSC != NULL)274pSC(m_hProcess); // SymCleanup275if (m_hDbhHelp != NULL)276FreeLibrary(m_hDbhHelp);277m_hDbhHelp = NULL;278m_parent = NULL;279if (m_szSymPath != NULL)280free(m_szSymPath);281m_szSymPath = NULL;282}283BOOL Init(LPCSTR szSymPath)284{285if (m_parent == NULL)286return FALSE;287// Dynamically load the Entry-Points for dbghelp.dll:288// First try to load the newest one from289TCHAR szTemp[4096];290// But before we do this, we first check if the ".local" file exists291if (GetModuleFileName(NULL, szTemp, 4096) > 0)292{293_tcscat_s(szTemp, _T(".local"));294if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)295{296// ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"297// Ok, first try the new path according to the architecture:298#ifdef _M_IX86299if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))300{301_tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll"));302// now check if the file exists:303if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)304{305m_hDbhHelp = LoadLibrary(szTemp);306}307}308#elif _M_X64309if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))310{311_tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll"));312// now check if the file exists:313if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)314{315m_hDbhHelp = LoadLibrary(szTemp);316}317}318#elif _M_IA64319if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))320{321_tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll"));322// now check if the file exists:323if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)324{325m_hDbhHelp = LoadLibrary(szTemp);326}327}328#endif329// If still not found, try the old directories...330if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))331{332_tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));333// now check if the file exists:334if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)335{336m_hDbhHelp = LoadLibrary(szTemp);337}338}339#if defined _M_X64 || defined _M_IA64340// Still not found? Then try to load the (old) 64-Bit version:341if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))342{343_tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));344if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)345{346m_hDbhHelp = LoadLibrary(szTemp);347}348}349#endif350}351}352if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one353m_hDbhHelp = LoadLibrary(_T("dbghelp.dll"));354if (m_hDbhHelp == NULL)355return FALSE;356pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize");357pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup");358359pSW = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64");360pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions");361pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions");362363pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64");364pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64");365pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64");366pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64");367pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64");368pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName");369pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64");370pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath");371372if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL ||373pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL ||374pSLM == NULL)375{376FreeLibrary(m_hDbhHelp);377m_hDbhHelp = NULL;378pSC = NULL;379return FALSE;380}381382// SymInitialize383if (szSymPath != NULL)384m_szSymPath = _strdup(szSymPath);385if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)386this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);387388DWORD symOptions = this->pSGO(); // SymGetOptions389symOptions |= SYMOPT_LOAD_LINES;390symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;391//symOptions |= SYMOPT_NO_PROMPTS;392// SymSetOptions393symOptions = this->pSSO(symOptions);394395char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};396if (this->pSGSP != NULL)397{398if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)399this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);400}401char szUserName[1024] = {0};402DWORD dwSize = 1024;403GetUserNameA(szUserName, &dwSize);404this->m_parent->OnSymInit(buf, symOptions, szUserName);405406return TRUE;407}408409StackWalker* m_parent;410411HMODULE m_hDbhHelp;412HANDLE m_hProcess;413LPSTR m_szSymPath;414415#pragma pack(push, 8)416typedef struct IMAGEHLP_MODULE64_V3417{418DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)419DWORD64 BaseOfImage; // base load address of module420DWORD ImageSize; // virtual size of the loaded module421DWORD TimeDateStamp; // date/time stamp from pe header422DWORD CheckSum; // checksum from the pe header423DWORD NumSyms; // number of symbols in the symbol table424SYM_TYPE SymType; // type of symbols loaded425CHAR ModuleName[32]; // module name426CHAR ImageName[256]; // image name427CHAR LoadedImageName[256]; // symbol file name428// new elements: 07-Jun-2002429CHAR LoadedPdbName[256]; // pdb file name430DWORD CVSig; // Signature of the CV record in the debug directories431CHAR CVData[MAX_PATH * 3]; // Contents of the CV record432DWORD PdbSig; // Signature of PDB433GUID PdbSig70; // Signature of PDB (VC 7 and up)434DWORD PdbAge; // DBI age of pdb435BOOL PdbUnmatched; // loaded an unmatched pdb436BOOL DbgUnmatched; // loaded an unmatched dbg437BOOL LineNumbers; // we have line number information438BOOL GlobalSymbols; // we have internal symbol information439BOOL TypeInfo; // we have type information440// new elements: 17-Dec-2003441BOOL SourceIndexed; // pdb supports source server442BOOL Publics; // contains public symbols443};444445typedef struct IMAGEHLP_MODULE64_V2446{447DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)448DWORD64 BaseOfImage; // base load address of module449DWORD ImageSize; // virtual size of the loaded module450DWORD TimeDateStamp; // date/time stamp from pe header451DWORD CheckSum; // checksum from the pe header452DWORD NumSyms; // number of symbols in the symbol table453SYM_TYPE SymType; // type of symbols loaded454CHAR ModuleName[32]; // module name455CHAR ImageName[256]; // image name456CHAR LoadedImageName[256]; // symbol file name457};458#pragma pack(pop)459460// SymCleanup()461typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess);462tSC pSC;463464// SymFunctionTableAccess64()465typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase);466tSFTA pSFTA;467468// SymGetLineFromAddr64()469typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess,470IN DWORD64 dwAddr,471OUT PDWORD pdwDisplacement,472OUT PIMAGEHLP_LINE64 Line);473tSGLFA pSGLFA;474475// SymGetModuleBase64()476typedef DWORD64(__stdcall* tSGMB)(IN HANDLE hProcess, IN DWORD64 dwAddr);477tSGMB pSGMB;478479// SymGetModuleInfo64()480typedef BOOL(__stdcall* tSGMI)(IN HANDLE hProcess,481IN DWORD64 dwAddr,482OUT IMAGEHLP_MODULE64_V3* ModuleInfo);483tSGMI pSGMI;484485// SymGetOptions()486typedef DWORD(__stdcall* tSGO)(VOID);487tSGO pSGO;488489// SymGetSymFromAddr64()490typedef BOOL(__stdcall* tSGSFA)(IN HANDLE hProcess,491IN DWORD64 dwAddr,492OUT PDWORD64 pdwDisplacement,493OUT PIMAGEHLP_SYMBOL64 Symbol);494tSGSFA pSGSFA;495496// SymInitialize()497typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);498tSI pSI;499500// SymLoadModule64()501typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess,502IN HANDLE hFile,503IN PSTR ImageName,504IN PSTR ModuleName,505IN DWORD64 BaseOfDll,506IN DWORD SizeOfDll);507tSLM pSLM;508509// SymSetOptions()510typedef DWORD(__stdcall* tSSO)(IN DWORD SymOptions);511tSSO pSSO;512513// StackWalk64()514typedef BOOL(__stdcall* tSW)(DWORD MachineType,515HANDLE hProcess,516HANDLE hThread,517LPSTACKFRAME64 StackFrame,518PVOID ContextRecord,519PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,520PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,521PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,522PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);523tSW pSW;524525// UnDecorateSymbolName()526typedef DWORD(__stdcall WINAPI* tUDSN)(PCSTR DecoratedName,527PSTR UnDecoratedName,528DWORD UndecoratedLength,529DWORD Flags);530tUDSN pUDSN;531532typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);533tSGSP pSGSP;534535private:536// **************************************** ToolHelp32 ************************537#define MAX_MODULE_NAME32 255538#define TH32CS_SNAPMODULE 0x00000008539#pragma pack(push, 8)540typedef struct tagMODULEENTRY32541{542DWORD dwSize;543DWORD th32ModuleID; // This module544DWORD th32ProcessID; // owning process545DWORD GlblcntUsage; // Global usage count on the module546DWORD ProccntUsage; // Module usage count in th32ProcessID's context547BYTE* modBaseAddr; // Base address of module in th32ProcessID's context548DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr549HMODULE hModule; // The hModule of this module in th32ProcessID's context550char szModule[MAX_MODULE_NAME32 + 1];551char szExePath[MAX_PATH];552} MODULEENTRY32;553typedef MODULEENTRY32* PMODULEENTRY32;554typedef MODULEENTRY32* LPMODULEENTRY32;555#pragma pack(pop)556557BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)558{559// CreateToolhelp32Snapshot()560typedef HANDLE(__stdcall * tCT32S)(DWORD dwFlags, DWORD th32ProcessID);561// Module32First()562typedef BOOL(__stdcall * tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);563// Module32Next()564typedef BOOL(__stdcall * tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);565566// try both dlls...567const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")};568HINSTANCE hToolhelp = NULL;569tCT32S pCT32S = NULL;570tM32F pM32F = NULL;571tM32N pM32N = NULL;572573HANDLE hSnap;574MODULEENTRY32 me;575me.dwSize = sizeof(me);576BOOL keepGoing;577size_t i;578579for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)580{581hToolhelp = LoadLibrary(dllname[i]);582if (hToolhelp == NULL)583continue;584pCT32S = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");585pM32F = (tM32F)GetProcAddress(hToolhelp, "Module32First");586pM32N = (tM32N)GetProcAddress(hToolhelp, "Module32Next");587if ((pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL))588break; // found the functions!589FreeLibrary(hToolhelp);590hToolhelp = NULL;591}592593if (hToolhelp == NULL)594return FALSE;595596hSnap = pCT32S(TH32CS_SNAPMODULE, pid);597if (hSnap == (HANDLE)-1)598{599FreeLibrary(hToolhelp);600return FALSE;601}602603keepGoing = !!pM32F(hSnap, &me);604int cnt = 0;605while (keepGoing)606{607this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr,608me.modBaseSize);609cnt++;610keepGoing = !!pM32N(hSnap, &me);611}612CloseHandle(hSnap);613FreeLibrary(hToolhelp);614if (cnt <= 0)615return FALSE;616return TRUE;617} // GetModuleListTH32618619// **************************************** PSAPI ************************620typedef struct _MODULEINFO621{622LPVOID lpBaseOfDll;623DWORD SizeOfImage;624LPVOID EntryPoint;625} MODULEINFO, *LPMODULEINFO;626627BOOL GetModuleListPSAPI(HANDLE hProcess)628{629// EnumProcessModules()630typedef BOOL(__stdcall * tEPM)(HANDLE hProcess, HMODULE * lphModule, DWORD cb,631LPDWORD lpcbNeeded);632// GetModuleFileNameEx()633typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,634DWORD nSize);635// GetModuleBaseName()636typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,637DWORD nSize);638// GetModuleInformation()639typedef BOOL(__stdcall * tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize);640641HINSTANCE hPsapi;642tEPM pEPM;643tGMFNE pGMFNE;644tGMBN pGMBN;645tGMI pGMI;646647DWORD i;648//ModuleEntry e;649DWORD cbNeeded;650MODULEINFO mi;651HMODULE* hMods = 0;652char* tt = NULL;653char* tt2 = NULL;654const SIZE_T TTBUFLEN = 8096;655int cnt = 0;656657hPsapi = LoadLibrary(_T("psapi.dll"));658if (hPsapi == NULL)659return FALSE;660661pEPM = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules");662pGMFNE = (tGMFNE)GetProcAddress(hPsapi, "GetModuleFileNameExA");663pGMBN = (tGMFNE)GetProcAddress(hPsapi, "GetModuleBaseNameA");664pGMI = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation");665if ((pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL))666{667// we couldn't find all functions668FreeLibrary(hPsapi);669return FALSE;670}671672hMods = (HMODULE*)malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));673tt = (char*)malloc(sizeof(char) * TTBUFLEN);674tt2 = (char*)malloc(sizeof(char) * TTBUFLEN);675if ((hMods == NULL) || (tt == NULL) || (tt2 == NULL))676goto cleanup;677678if (!pEPM(hProcess, hMods, TTBUFLEN, &cbNeeded))679{680//_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );681goto cleanup;682}683684if (cbNeeded > TTBUFLEN)685{686//_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );687goto cleanup;688}689690for (i = 0; i < cbNeeded / sizeof(hMods[0]); i++)691{692// base address, size693pGMI(hProcess, hMods[i], &mi, sizeof(mi));694// image file name695tt[0] = 0;696pGMFNE(hProcess, hMods[i], tt, TTBUFLEN);697// module name698tt2[0] = 0;699pGMBN(hProcess, hMods[i], tt2, TTBUFLEN);700701DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64)mi.lpBaseOfDll, mi.SizeOfImage);702if (dwRes != ERROR_SUCCESS)703this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);704cnt++;705}706707cleanup:708if (hPsapi != NULL)709FreeLibrary(hPsapi);710if (tt2 != NULL)711free(tt2);712if (tt != NULL)713free(tt);714if (hMods != NULL)715free(hMods);716717return cnt != 0;718} // GetModuleListPSAPI719720DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)721{722CHAR* szImg = _strdup(img);723CHAR* szMod = _strdup(mod);724DWORD result = ERROR_SUCCESS;725if ((szImg == NULL) || (szMod == NULL))726result = ERROR_NOT_ENOUGH_MEMORY;727else728{729if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)730result = GetLastError();731}732ULONGLONG fileVersion = 0;733if ((m_parent != NULL) && (szImg != NULL))734{735// try to retrieve the file-version:736if ((this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0)737{738VS_FIXEDFILEINFO* fInfo = NULL;739DWORD dwHandle;740DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);741if (dwSize > 0)742{743LPVOID vData = malloc(dwSize);744if (vData != NULL)745{746if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)747{748UINT len;749TCHAR szSubBlock[] = _T("\\");750if (VerQueryValue(vData, szSubBlock, (LPVOID*)&fInfo, &len) == 0)751fInfo = NULL;752else753{754fileVersion =755((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);756}757}758free(vData);759}760}761}762763// Retrieve some additional-infos about the module764IMAGEHLP_MODULE64_V3 Module;765const char* szSymType = "-unknown-";766if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)767{768switch (Module.SymType)769{770case SymNone:771szSymType = "-nosymbols-";772break;773case SymCoff: // 1774szSymType = "COFF";775break;776case SymCv: // 2777szSymType = "CV";778break;779case SymPdb: // 3780szSymType = "PDB";781break;782case SymExport: // 4783szSymType = "-exported-";784break;785case SymDeferred: // 5786szSymType = "-deferred-";787break;788case SymSym: // 6789szSymType = "SYM";790break;791case 7: // SymDia:792szSymType = "DIA";793break;794case 8: //SymVirtual:795szSymType = "Virtual";796break;797}798}799LPCSTR pdbName = Module.LoadedImageName;800if (Module.LoadedPdbName[0] != 0)801pdbName = Module.LoadedPdbName;802this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName,803fileVersion);804}805if (szImg != NULL)806free(szImg);807if (szMod != NULL)808free(szMod);809return result;810}811812public:813BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)814{815// first try toolhelp32816if (GetModuleListTH32(hProcess, dwProcessId))817return true;818// then try psapi819return GetModuleListPSAPI(hProcess);820}821822BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3* pModuleInfo)823{824memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));825if (this->pSGMI == NULL)826{827SetLastError(ERROR_DLL_INIT_FAILED);828return FALSE;829}830// First try to use the larger ModuleInfo-Structure831pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);832void* pData = malloc(8334096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...834if (pData == NULL)835{836SetLastError(ERROR_NOT_ENOUGH_MEMORY);837return FALSE;838}839memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3));840static bool s_useV3Version = true;841if (s_useV3Version)842{843if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)844{845// only copy as much memory as is reserved...846memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));847pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);848free(pData);849return TRUE;850}851s_useV3Version = false; // to prevent unnecessary calls with the larger struct...852}853854// could not retrieve the bigger structure, try with the smaller one (as defined in VC7.1)...855pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);856memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));857if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)858{859// only copy as much memory as is reserved...860memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));861pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);862free(pData);863return TRUE;864}865free(pData);866SetLastError(ERROR_DLL_INIT_FAILED);867return FALSE;868}869};870871// #############################################################872StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)873{874this->m_options = OptionsAll;875this->m_modulesLoaded = FALSE;876this->m_hProcess = hProcess;877this->m_sw = new StackWalkerInternal(this, this->m_hProcess);878this->m_dwProcessId = dwProcessId;879this->m_szSymPath = NULL;880this->m_MaxRecursionCount = 1000;881}882StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)883{884this->m_options = options;885this->m_modulesLoaded = FALSE;886this->m_hProcess = hProcess;887this->m_sw = new StackWalkerInternal(this, this->m_hProcess);888this->m_dwProcessId = dwProcessId;889if (szSymPath != NULL)890{891this->m_szSymPath = _strdup(szSymPath);892this->m_options |= SymBuildPath;893}894else895this->m_szSymPath = NULL;896this->m_MaxRecursionCount = 1000;897}898899StackWalker::~StackWalker()900{901if (m_szSymPath != NULL)902free(m_szSymPath);903m_szSymPath = NULL;904if (this->m_sw != NULL)905delete this->m_sw;906this->m_sw = NULL;907}908909BOOL StackWalker::LoadModules()910{911if (this->m_sw == NULL)912{913SetLastError(ERROR_DLL_INIT_FAILED);914return FALSE;915}916if (m_modulesLoaded != FALSE)917return TRUE;918919// Build the sym-path:920char* szSymPath = NULL;921if ((this->m_options & SymBuildPath) != 0)922{923const size_t nSymPathLen = 4096;924szSymPath = (char*)malloc(nSymPathLen);925if (szSymPath == NULL)926{927SetLastError(ERROR_NOT_ENOUGH_MEMORY);928return FALSE;929}930szSymPath[0] = 0;931// Now first add the (optional) provided sympath:932if (this->m_szSymPath != NULL)933{934strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);935strcat_s(szSymPath, nSymPathLen, ";");936}937938strcat_s(szSymPath, nSymPathLen, ".;");939940const size_t nTempLen = 1024;941char szTemp[nTempLen];942// Now add the current directory:943if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)944{945szTemp[nTempLen - 1] = 0;946strcat_s(szSymPath, nSymPathLen, szTemp);947strcat_s(szSymPath, nSymPathLen, ";");948}949950// Now add the path for the main-module:951if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)952{953szTemp[nTempLen - 1] = 0;954for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p)955{956// locate the rightmost path separator957if ((*p == '\\') || (*p == '/') || (*p == ':'))958{959*p = 0;960break;961}962} // for (search for path separator...)963if (strlen(szTemp) > 0)964{965strcat_s(szSymPath, nSymPathLen, szTemp);966strcat_s(szSymPath, nSymPathLen, ";");967}968}969if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)970{971szTemp[nTempLen - 1] = 0;972strcat_s(szSymPath, nSymPathLen, szTemp);973strcat_s(szSymPath, nSymPathLen, ";");974}975if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)976{977szTemp[nTempLen - 1] = 0;978strcat_s(szSymPath, nSymPathLen, szTemp);979strcat_s(szSymPath, nSymPathLen, ";");980}981if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)982{983szTemp[nTempLen - 1] = 0;984strcat_s(szSymPath, nSymPathLen, szTemp);985strcat_s(szSymPath, nSymPathLen, ";");986// also add the "system32"-directory:987strcat_s(szTemp, nTempLen, "\\system32");988strcat_s(szSymPath, nSymPathLen, szTemp);989strcat_s(szSymPath, nSymPathLen, ";");990}991992if ((this->m_options & SymUseSymSrv) != 0)993{994if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)995{996szTemp[nTempLen - 1] = 0;997strcat_s(szSymPath, nSymPathLen, "SRV*");998strcat_s(szSymPath, nSymPathLen, szTemp);999strcat_s(szSymPath, nSymPathLen, "\\websymbols");1000strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");1001}1002else1003strcat_s(szSymPath, nSymPathLen,1004"SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");1005}1006} // if SymBuildPath10071008// First Init the whole stuff...1009BOOL bRet = this->m_sw->Init(szSymPath);1010if (szSymPath != NULL)1011free(szSymPath);1012szSymPath = NULL;1013if (bRet == FALSE)1014{1015this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);1016SetLastError(ERROR_DLL_INIT_FAILED);1017return FALSE;1018}10191020bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);1021if (bRet != FALSE)1022m_modulesLoaded = TRUE;1023return bRet;1024}10251026// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction1027// This has to be done due to a problem with the "hProcess"-parameter in x64...1028// Because this class is in no case multi-threading-enabled (because of the limitations1029// of dbghelp.dll) it is "safe" to use a static-variable1030static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;1031static LPVOID s_readMemoryFunction_UserData = NULL;10321033BOOL StackWalker::ShowCallstack(HANDLE hThread,1034const CONTEXT* context,1035PReadProcessMemoryRoutine readMemoryFunction,1036LPVOID pUserData)1037{1038CONTEXT c;1039CallstackEntry csEntry;1040IMAGEHLP_SYMBOL64* pSym = NULL;1041StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module;1042IMAGEHLP_LINE64 Line;1043int frameNum;1044bool bLastEntryCalled = true;1045int curRecursionCount = 0;10461047if (m_modulesLoaded == FALSE)1048this->LoadModules(); // ignore the result...10491050if (this->m_sw->m_hDbhHelp == NULL)1051{1052SetLastError(ERROR_DLL_INIT_FAILED);1053return FALSE;1054}10551056s_readMemoryFunction = readMemoryFunction;1057s_readMemoryFunction_UserData = pUserData;10581059if (context == NULL)1060{1061// If no context is provided, capture the context1062// See: https://stackwalker.codeplex.com/discussions/4469581063#if _WIN32_WINNT <= 0x05011064// If we need to support XP, we need to use the "old way", because "GetThreadId" is not available!1065if (hThread == GetCurrentThread())1066#else1067if (GetThreadId(hThread) == GetCurrentThreadId())1068#endif1069{1070GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);1071}1072else1073{1074SuspendThread(hThread);1075memset(&c, 0, sizeof(CONTEXT));1076c.ContextFlags = USED_CONTEXT_FLAGS;10771078// TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture...1079// This does only work if we are x64 and the target process is x64 or x86;1080// It cannot work, if this process is x64 and the target process is x64... this is not supported...1081// See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html1082if (GetThreadContext(hThread, &c) == FALSE)1083{1084ResumeThread(hThread);1085return FALSE;1086}1087}1088}1089else1090c = *context;10911092// init STACKFRAME for first call1093STACKFRAME64 s; // in/out stackframe1094memset(&s, 0, sizeof(s));1095DWORD imageType;1096#ifdef _M_IX861097// normally, call ImageNtHeader() and use machine info from PE header1098imageType = IMAGE_FILE_MACHINE_I386;1099s.AddrPC.Offset = c.Eip;1100s.AddrPC.Mode = AddrModeFlat;1101s.AddrFrame.Offset = c.Ebp;1102s.AddrFrame.Mode = AddrModeFlat;1103s.AddrStack.Offset = c.Esp;1104s.AddrStack.Mode = AddrModeFlat;1105#elif _M_X641106imageType = IMAGE_FILE_MACHINE_AMD64;1107s.AddrPC.Offset = c.Rip;1108s.AddrPC.Mode = AddrModeFlat;1109s.AddrFrame.Offset = c.Rsp;1110s.AddrFrame.Mode = AddrModeFlat;1111s.AddrStack.Offset = c.Rsp;1112s.AddrStack.Mode = AddrModeFlat;1113#elif _M_IA641114imageType = IMAGE_FILE_MACHINE_IA64;1115s.AddrPC.Offset = c.StIIP;1116s.AddrPC.Mode = AddrModeFlat;1117s.AddrFrame.Offset = c.IntSp;1118s.AddrFrame.Mode = AddrModeFlat;1119s.AddrBStore.Offset = c.RsBSP;1120s.AddrBStore.Mode = AddrModeFlat;1121s.AddrStack.Offset = c.IntSp;1122s.AddrStack.Mode = AddrModeFlat;1123#elif _M_ARM641124imageType = IMAGE_FILE_MACHINE_ARM64;1125s.AddrPC.Offset = c.Pc;1126s.AddrPC.Mode = AddrModeFlat;1127s.AddrFrame.Offset = c.Fp;1128s.AddrFrame.Mode = AddrModeFlat;1129s.AddrStack.Offset = c.Sp;1130s.AddrStack.Mode = AddrModeFlat;1131#else1132#error "Platform not supported!"1133#endif11341135pSym = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);1136if (!pSym)1137goto cleanup; // not enough memory...1138memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);1139pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);1140pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;11411142memset(&Line, 0, sizeof(Line));1143Line.SizeOfStruct = sizeof(Line);11441145memset(&Module, 0, sizeof(Module));1146Module.SizeOfStruct = sizeof(Module);11471148for (frameNum = 0;; ++frameNum)1149{1150// get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())1151// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can1152// assume that either you are done, or that the stack is so hosed that the next1153// deeper frame could not be found.1154// CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386!1155if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem,1156this->m_sw->pSFTA, this->m_sw->pSGMB, NULL))1157{1158// INFO: "StackWalk64" does not set "GetLastError"...1159this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);1160break;1161}11621163csEntry.offset = s.AddrPC.Offset;1164csEntry.name[0] = 0;1165csEntry.undName[0] = 0;1166csEntry.undFullName[0] = 0;1167csEntry.offsetFromSmybol = 0;1168csEntry.offsetFromLine = 0;1169csEntry.lineFileName[0] = 0;1170csEntry.lineNumber = 0;1171csEntry.loadedImageName[0] = 0;1172csEntry.moduleName[0] = 0;1173if (s.AddrPC.Offset == s.AddrReturn.Offset)1174{1175if ((this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount))1176{1177this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);1178break;1179}1180curRecursionCount++;1181}1182else1183curRecursionCount = 0;1184if (s.AddrPC.Offset != 0)1185{1186// we seem to have a valid PC1187// show procedure info (SymGetSymFromAddr64())1188if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol),1189pSym) != FALSE)1190{1191MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name);1192// UnDecorateSymbolName()1193this->m_sw->pUDSN(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);1194this->m_sw->pUDSN(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);1195}1196else1197{1198this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);1199}12001201// show line number info, NT5.0-method (SymGetLineFromAddr64())1202if (this->m_sw->pSGLFA != NULL)1203{ // yes, we have SymGetLineFromAddr64()1204if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine),1205&Line) != FALSE)1206{1207csEntry.lineNumber = Line.LineNumber;1208MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName);1209}1210else1211{1212this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);1213}1214} // yes, we have SymGetLineFromAddr64()12151216// show module info (SymGetModuleInfo64())1217if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module) != FALSE)1218{ // got module info OK1219switch (Module.SymType)1220{1221case SymNone:1222csEntry.symTypeString = "-nosymbols-";1223break;1224case SymCoff:1225csEntry.symTypeString = "COFF";1226break;1227case SymCv:1228csEntry.symTypeString = "CV";1229break;1230case SymPdb:1231csEntry.symTypeString = "PDB";1232break;1233case SymExport:1234csEntry.symTypeString = "-exported-";1235break;1236case SymDeferred:1237csEntry.symTypeString = "-deferred-";1238break;1239case SymSym:1240csEntry.symTypeString = "SYM";1241break;1242#if API_VERSION_NUMBER >= 91243case SymDia:1244csEntry.symTypeString = "DIA";1245break;1246#endif1247case 8: //SymVirtual:1248csEntry.symTypeString = "Virtual";1249break;1250default:1251//_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType );1252csEntry.symTypeString = NULL;1253break;1254}12551256MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName);1257csEntry.baseOfImage = Module.BaseOfImage;1258MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName);1259} // got module info OK1260else1261{1262this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);1263}1264} // we seem to have a valid PC12651266CallstackEntryType et = nextEntry;1267if (frameNum == 0)1268et = firstEntry;1269bLastEntryCalled = false;1270this->OnCallstackEntry(et, csEntry);12711272if (s.AddrReturn.Offset == 0)1273{1274bLastEntryCalled = true;1275this->OnCallstackEntry(lastEntry, csEntry);1276SetLastError(ERROR_SUCCESS);1277break;1278}1279} // for ( frameNum )12801281cleanup:1282if (pSym)1283free(pSym);12841285if (bLastEntryCalled == false)1286this->OnCallstackEntry(lastEntry, csEntry);12871288if (context == NULL)1289ResumeThread(hThread);12901291return TRUE;1292}12931294BOOL StackWalker::ShowObject(LPVOID pObject)1295{1296// Load modules if not done yet1297if (m_modulesLoaded == FALSE)1298this->LoadModules(); // ignore the result...12991300// Verify that the DebugHelp.dll was actually found1301if (this->m_sw->m_hDbhHelp == NULL)1302{1303SetLastError(ERROR_DLL_INIT_FAILED);1304return FALSE;1305}13061307// SymGetSymFromAddr64() is required1308if (this->m_sw->pSGSFA == NULL)1309return FALSE;13101311// Show object info (SymGetSymFromAddr64())1312DWORD64 dwAddress = DWORD64(pObject);1313DWORD64 dwDisplacement = 0;1314IMAGEHLP_SYMBOL64* pSym =1315(IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);1316memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);1317pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);1318pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;1319if (this->m_sw->pSGSFA(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE)1320{1321this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), dwAddress);1322return FALSE;1323}1324// Object name output1325this->OnOutput(pSym->Name);13261327free(pSym);1328return TRUE;1329};13301331BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess,1332DWORD64 qwBaseAddress,1333PVOID lpBuffer,1334DWORD nSize,1335LPDWORD lpNumberOfBytesRead)1336{1337if (s_readMemoryFunction == NULL)1338{1339SIZE_T st;1340BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st);1341*lpNumberOfBytesRead = (DWORD)st;1342//printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);1343return bRet;1344}1345else1346{1347return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead,1348s_readMemoryFunction_UserData);1349}1350}13511352void StackWalker::OnLoadModule(LPCSTR img,1353LPCSTR mod,1354DWORD64 baseAddr,1355DWORD size,1356DWORD result,1357LPCSTR symType,1358LPCSTR pdbName,1359ULONGLONG fileVersion)1360{1361CHAR buffer[STACKWALK_MAX_NAMELEN];1362size_t maxLen = STACKWALK_MAX_NAMELEN;1363#if _MSC_VER >= 14001364maxLen = _TRUNCATE;1365#endif1366if (fileVersion == 0)1367_snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n",1368img, mod, (LPVOID)baseAddr, size, result, symType, pdbName);1369else1370{1371DWORD v4 = (DWORD)(fileVersion & 0xFFFF);1372DWORD v3 = (DWORD)((fileVersion >> 16) & 0xFFFF);1373DWORD v2 = (DWORD)((fileVersion >> 32) & 0xFFFF);1374DWORD v1 = (DWORD)((fileVersion >> 48) & 0xFFFF);1375_snprintf_s(1376buffer, maxLen,1377"%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n",1378img, mod, (LPVOID)baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);1379}1380buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NULL terminated1381OnOutput(buffer);1382}13831384void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry)1385{1386CHAR buffer[STACKWALK_MAX_NAMELEN];1387size_t maxLen = STACKWALK_MAX_NAMELEN;1388#if _MSC_VER >= 14001389maxLen = _TRUNCATE;1390#endif1391if ((eType != lastEntry) && (entry.offset != 0))1392{1393if (entry.name[0] == 0)1394MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)");1395if (entry.undName[0] != 0)1396MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);1397if (entry.undFullName[0] != 0)1398MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);1399if (entry.lineFileName[0] == 0)1400{1401MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");1402if (entry.moduleName[0] == 0)1403MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");1404_snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID)entry.offset, entry.moduleName,1405entry.lineFileName, entry.name);1406}1407else1408_snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber,1409entry.name);1410buffer[STACKWALK_MAX_NAMELEN - 1] = 0;1411OnOutput(buffer);1412}1413}14141415void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)1416{1417CHAR buffer[STACKWALK_MAX_NAMELEN];1418size_t maxLen = STACKWALK_MAX_NAMELEN;1419#if _MSC_VER >= 14001420maxLen = _TRUNCATE;1421#endif1422_snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle,1423(LPVOID)addr);1424buffer[STACKWALK_MAX_NAMELEN - 1] = 0;1425OnOutput(buffer);1426}14271428void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)1429{1430CHAR buffer[STACKWALK_MAX_NAMELEN];1431size_t maxLen = STACKWALK_MAX_NAMELEN;1432#if _MSC_VER >= 14001433maxLen = _TRUNCATE;1434#endif1435_snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n",1436szSearchPath, symOptions, szUserName);1437buffer[STACKWALK_MAX_NAMELEN - 1] = 0;1438OnOutput(buffer);1439// Also display the OS-version1440#if _MSC_VER <= 12001441OSVERSIONINFOA ver;1442ZeroMemory(&ver, sizeof(OSVERSIONINFOA));1443ver.dwOSVersionInfoSize = sizeof(ver);1444if (GetVersionExA(&ver) != FALSE)1445{1446_snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion,1447ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion);1448buffer[STACKWALK_MAX_NAMELEN - 1] = 0;1449OnOutput(buffer);1450}1451#else1452OSVERSIONINFOEXA ver;1453ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));1454ver.dwOSVersionInfoSize = sizeof(ver);1455#if _MSC_VER >= 19001456#pragma warning(push)1457#pragma warning(disable : 4996)1458#endif1459if (GetVersionExA((OSVERSIONINFOA*)&ver) != FALSE)1460{1461_snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion,1462ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask,1463ver.wProductType);1464buffer[STACKWALK_MAX_NAMELEN - 1] = 0;1465OnOutput(buffer);1466}1467#if _MSC_VER >= 19001468#pragma warning(pop)1469#endif1470#endif1471}14721473void StackWalker::OnOutput(LPCSTR buffer)1474{1475OutputDebugStringA(buffer);1476}147714781479