Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Dbg traces

  • Loading branch information...
commit befb530d33b501adf984b8cf3f3a83c0d91a640a 1 parent c05a923
Volodymyr Shymanskyy authored
1,096 src/StackWalker/StackWalker.cpp
... ... @@ -0,0 +1,1096 @@
  1 +/**********************************************************************
  2 + *
  3 + * StackWalker.cpp
  4 + *
  5 + *
  6 + * History:
  7 + * 2005-07-27 v1 - First public release on http://www.codeproject.com/
  8 + * http://www.codeproject.com/threads/StackWalker.asp
  9 + * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack
  10 + * (to simplify the usage)
  11 + * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL
  12 + * (should also be enough)
  13 + * - Changed to compile correctly with the PSDK of VC7.0
  14 + * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:
  15 + * it uses LPSTR instead of LPCSTR as first paremeter)
  16 + * - Added declarations to support VC5/6 without using 'dbghelp.h'
  17 + * - Added a 'pUserData' member to the ShowCallstack function and the
  18 + * PReadProcessMemoryRoutine declaration (to pass some user-defined data,
  19 + * which can be used in the readMemoryFunction-callback)
  20 + * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default
  21 + * - Added example for doing an exception-callstack-walking in main.cpp
  22 + * (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)
  23 + * 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!
  24 + *
  25 + **********************************************************************/
  26 +
  27 +#include <XPlat.h>
  28 +#if defined (TARGET_OS_WINDOWS)
  29 +
  30 +#include <windows.h>
  31 +#include <tchar.h>
  32 +#include <stdio.h>
  33 +#pragma comment(lib, "version.lib") // for "VerQueryValue"
  34 +
  35 +#include "StackWalker.h"
  36 +#include <dbghelp.h>
  37 +
  38 +
  39 +// Some missing defines (for VC5/6):
  40 +#ifndef INVALID_FILE_ATTRIBUTES
  41 +#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
  42 +#endif
  43 +
  44 +
  45 +// secure-CRT_functions are only available starting with VC8
  46 +#if _MSC_VER < 1400
  47 +#define strcpy_s strcpy
  48 +#define strcat_s(dst, len, src) strcat(dst, src)
  49 +#define _snprintf_s _snprintf
  50 +#define _tcscat_s _tcscat
  51 +#endif
  52 +
  53 +// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
  54 +#define USED_CONTEXT_FLAGS CONTEXT_FULL
  55 +
  56 +
  57 +class StackWalkerInternal
  58 +{
  59 +public:
  60 + StackWalkerInternal(StackWalker *parent, HANDLE hProcess)
  61 + {
  62 + m_parent = parent;
  63 + m_hDbhHelp = NULL;
  64 + pSC = NULL;
  65 + m_hProcess = hProcess;
  66 + m_szSymPath = NULL;
  67 + pSFTA = NULL;
  68 + pSGLFA = NULL;
  69 + pSGMB = NULL;
  70 + pSGMI = NULL;
  71 + pSGO = NULL;
  72 + pSGSFA = NULL;
  73 + pSI = NULL;
  74 + pSLM = NULL;
  75 + pSSO = NULL;
  76 + pSW = NULL;
  77 + pUDSN = NULL;
  78 + pSGSP = NULL;
  79 + }
  80 + ~StackWalkerInternal()
  81 + {
  82 + if (pSC != NULL)
  83 + pSC(m_hProcess); // SymCleanup
  84 + if (m_hDbhHelp != NULL)
  85 + FreeLibrary(m_hDbhHelp);
  86 + m_hDbhHelp = NULL;
  87 + m_parent = NULL;
  88 + if(m_szSymPath != NULL)
  89 + free(m_szSymPath);
  90 + m_szSymPath = NULL;
  91 + }
  92 + BOOL Init(LPCSTR szSymPath)
  93 + {
  94 + if (m_parent == NULL)
  95 + return FALSE;
  96 + // Dynamically load the Entry-Points for dbghelp.dll:
  97 + // First try to load the newsest one from
  98 + TCHAR szTemp[4096];
  99 + // But before wqe do this, we first check if the ".local" file exists
  100 + if (GetModuleFileName(NULL, szTemp, 4096) > 0)
  101 + {
  102 + _tcscat_s(szTemp, _T(".local"));
  103 + if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)
  104 + {
  105 + // ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
  106 + if (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0)
  107 + {
  108 + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));
  109 + // now check if the file exists:
  110 + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  111 + {
  112 + m_hDbhHelp = LoadLibrary(szTemp);
  113 + }
  114 + }
  115 + // Still not found? Then try to load the 64-Bit version:
  116 + if ( (m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0) )
  117 + {
  118 + _tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));
  119 + if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
  120 + {
  121 + m_hDbhHelp = LoadLibrary(szTemp);
  122 + }
  123 + }
  124 + }
  125 + }
  126 + if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one
  127 + m_hDbhHelp = LoadLibrary( _T("dbghelp.dll") );
  128 + if (m_hDbhHelp == NULL)
  129 + return FALSE;
  130 + pSI = (tSI) GetProcAddress(m_hDbhHelp, "SymInitialize" );
  131 + pSC = (tSC) GetProcAddress(m_hDbhHelp, "SymCleanup" );
  132 +
  133 + pSW = (tSW) GetProcAddress(m_hDbhHelp, "StackWalk64" );
  134 + pSGO = (tSGO) GetProcAddress(m_hDbhHelp, "SymGetOptions" );
  135 + pSSO = (tSSO) GetProcAddress(m_hDbhHelp, "SymSetOptions" );
  136 +
  137 + pSFTA = (tSFTA) GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64" );
  138 + pSGLFA = (tSGLFA) GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64" );
  139 + pSGMB = (tSGMB) GetProcAddress(m_hDbhHelp, "SymGetModuleBase64" );
  140 + pSGMI = (tSGMI) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
  141 + //pSGMI_V3 = (tSGMI_V3) GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64" );
  142 + pSGSFA = (tSGSFA) GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64" );
  143 + pUDSN = (tUDSN) GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName" );
  144 + pSLM = (tSLM) GetProcAddress(m_hDbhHelp, "SymLoadModule64" );
  145 + pSGSP =(tSGSP) GetProcAddress(m_hDbhHelp, "SymGetSearchPath" );
  146 +
  147 + if ( pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL ||
  148 + pSGO == NULL || pSGSFA == NULL || pSI == NULL || pSSO == NULL ||
  149 + pSW == NULL || pUDSN == NULL || pSLM == NULL )
  150 + {
  151 + FreeLibrary(m_hDbhHelp);
  152 + m_hDbhHelp = NULL;
  153 + pSC = NULL;
  154 + return FALSE;
  155 + }
  156 +
  157 + // SymInitialize
  158 + if (szSymPath != NULL)
  159 + m_szSymPath = _strdup(szSymPath);
  160 + if (pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
  161 + m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
  162 +
  163 + DWORD symOptions = pSGO(); // SymGetOptions
  164 + symOptions |= SYMOPT_LOAD_LINES;
  165 + symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
  166 + //symOptions |= SYMOPT_NO_PROMPTS;
  167 + // SymSetOptions
  168 + symOptions = pSSO(symOptions);
  169 +
  170 + char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
  171 + if (pSGSP != NULL)
  172 + {
  173 + if (pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
  174 + m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
  175 + }
  176 + char szUserName[1024] = {0};
  177 + DWORD dwSize = 1024;
  178 + GetUserNameA(szUserName, &dwSize);
  179 + m_parent->OnSymInit(buf, symOptions, szUserName);
  180 +
  181 + return TRUE;
  182 + }
  183 +
  184 + StackWalker *m_parent;
  185 +
  186 + HMODULE m_hDbhHelp;
  187 + HANDLE m_hProcess;
  188 + LPSTR m_szSymPath;
  189 +
  190 +/*typedef struct IMAGEHLP_MODULE64_V3 {
  191 + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
  192 + DWORD64 BaseOfImage; // base load address of module
  193 + DWORD ImageSize; // virtual size of the loaded module
  194 + DWORD TimeDateStamp; // date/time stamp from pe header
  195 + DWORD CheckSum; // checksum from the pe header
  196 + DWORD NumSyms; // number of symbols in the symbol table
  197 + SYM_TYPE SymType; // type of symbols loaded
  198 + CHAR ModuleName[32]; // module name
  199 + CHAR ImageName[256]; // image name
  200 + // new elements: 07-Jun-2002
  201 + CHAR LoadedImageName[256]; // symbol file name
  202 + CHAR LoadedPdbName[256]; // pdb file name
  203 + DWORD CVSig; // Signature of the CV record in the debug directories
  204 + CHAR CVData[MAX_PATH * 3]; // Contents of the CV record
  205 + DWORD PdbSig; // Signature of PDB
  206 + GUID PdbSig70; // Signature of PDB (VC 7 and up)
  207 + DWORD PdbAge; // DBI age of pdb
  208 + BOOL PdbUnmatched; // loaded an unmatched pdb
  209 + BOOL DbgUnmatched; // loaded an unmatched dbg
  210 + BOOL LineNumbers; // we have line number information
  211 + BOOL GlobalSymbols; // we have internal symbol information
  212 + BOOL TypeInfo; // we have type information
  213 + // new elements: 17-Dec-2003
  214 + BOOL SourceIndexed; // pdb supports source server
  215 + BOOL Publics; // contains public symbols
  216 +};
  217 +*/
  218 +typedef struct IMAGEHLP_MODULE64_V2 {
  219 + DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
  220 + DWORD64 BaseOfImage; // base load address of module
  221 + DWORD ImageSize; // virtual size of the loaded module
  222 + DWORD TimeDateStamp; // date/time stamp from pe header
  223 + DWORD CheckSum; // checksum from the pe header
  224 + DWORD NumSyms; // number of symbols in the symbol table
  225 + SYM_TYPE SymType; // type of symbols loaded
  226 + CHAR ModuleName[32]; // module name
  227 + CHAR ImageName[256]; // image name
  228 + CHAR LoadedImageName[256]; // symbol file name
  229 +};
  230 +
  231 +
  232 + // SymCleanup()
  233 + typedef BOOL (__stdcall *tSC)( IN HANDLE hProcess );
  234 + tSC pSC;
  235 +
  236 + // SymFunctionTableAccess64()
  237 + typedef PVOID (__stdcall *tSFTA)( HANDLE hProcess, DWORD64 AddrBase );
  238 + tSFTA pSFTA;
  239 +
  240 + // SymGetLineFromAddr64()
  241 + typedef BOOL (__stdcall *tSGLFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
  242 + OUT PDWORD pdwDisplacement, OUT PIMAGEHLP_LINE64 Line );
  243 + tSGLFA pSGLFA;
  244 +
  245 + // SymGetModuleBase64()
  246 + typedef DWORD64 (__stdcall *tSGMB)( IN HANDLE hProcess, IN DWORD64 dwAddr );
  247 + tSGMB pSGMB;
  248 +
  249 + // SymGetModuleInfo64()
  250 + typedef BOOL (__stdcall *tSGMI)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V2 *ModuleInfo );
  251 + tSGMI pSGMI;
  252 +
  253 +// // SymGetModuleInfo64()
  254 +// typedef BOOL (__stdcall *tSGMI_V3)( IN HANDLE hProcess, IN DWORD64 dwAddr, OUT IMAGEHLP_MODULE64_V3 *ModuleInfo );
  255 +// tSGMI_V3 pSGMI_V3;
  256 +
  257 + // SymGetOptions()
  258 + typedef DWORD (__stdcall *tSGO)( VOID );
  259 + tSGO pSGO;
  260 +
  261 + // SymGetSymFromAddr64()
  262 + typedef BOOL (__stdcall *tSGSFA)( IN HANDLE hProcess, IN DWORD64 dwAddr,
  263 + OUT PDWORD64 pdwDisplacement, OUT PIMAGEHLP_SYMBOL64 Symbol );
  264 + tSGSFA pSGSFA;
  265 +
  266 + // SymInitialize()
  267 + typedef BOOL (__stdcall *tSI)( IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess );
  268 + tSI pSI;
  269 +
  270 + // SymLoadModule64()
  271 + typedef DWORD64 (__stdcall *tSLM)( IN HANDLE hProcess, IN HANDLE hFile,
  272 + IN PSTR ImageName, IN PSTR ModuleName, IN DWORD64 BaseOfDll, IN DWORD SizeOfDll );
  273 + tSLM pSLM;
  274 +
  275 + // SymSetOptions()
  276 + typedef DWORD (__stdcall *tSSO)( IN DWORD SymOptions );
  277 + tSSO pSSO;
  278 +
  279 + // StackWalk64()
  280 + typedef BOOL (__stdcall *tSW)(
  281 + DWORD MachineType,
  282 + HANDLE hProcess,
  283 + HANDLE hThread,
  284 + LPSTACKFRAME64 StackFrame,
  285 + PVOID ContextRecord,
  286 + PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
  287 + PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
  288 + PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
  289 + PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress );
  290 + tSW pSW;
  291 +
  292 + // UnDecorateSymbolName()
  293 + typedef DWORD (__stdcall WINAPI *tUDSN)( PCSTR DecoratedName, PSTR UnDecoratedName,
  294 + DWORD UndecoratedLength, DWORD Flags );
  295 + tUDSN pUDSN;
  296 +
  297 + typedef BOOL (__stdcall WINAPI *tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
  298 + tSGSP pSGSP;
  299 +
  300 +
  301 +private:
  302 + // **************************************** ToolHelp32 ************************
  303 + #define MAX_MODULE_NAME32 255
  304 + #define TH32CS_SNAPMODULE 0x00000008
  305 + #pragma pack( push, 8 )
  306 + typedef struct tagMODULEENTRY32
  307 + {
  308 + DWORD dwSize;
  309 + DWORD th32ModuleID; // This module
  310 + DWORD th32ProcessID; // owning process
  311 + DWORD GlblcntUsage; // Global usage count on the module
  312 + DWORD ProccntUsage; // Module usage count in th32ProcessID's context
  313 + BYTE * modBaseAddr; // Base address of module in th32ProcessID's context
  314 + DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr
  315 + HMODULE hModule; // The hModule of this module in th32ProcessID's context
  316 + char szModule[MAX_MODULE_NAME32 + 1];
  317 + char szExePath[MAX_PATH];
  318 + } MODULEENTRY32;
  319 + typedef MODULEENTRY32 * PMODULEENTRY32;
  320 + typedef MODULEENTRY32 * LPMODULEENTRY32;
  321 + #pragma pack( pop )
  322 +
  323 + BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)
  324 + {
  325 + // CreateToolhelp32Snapshot()
  326 + typedef HANDLE (__stdcall *tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
  327 + // Module32First()
  328 + typedef BOOL (__stdcall *tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
  329 + // Module32Next()
  330 + typedef BOOL (__stdcall *tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
  331 +
  332 + // try both dlls...
  333 + const TCHAR *dllname[] = { _T("kernel32.dll"), _T("tlhelp32.dll") };
  334 + HINSTANCE hToolhelp = NULL;
  335 + tCT32S pCT32S = NULL;
  336 + tM32F pM32F = NULL;
  337 + tM32N pM32N = NULL;
  338 +
  339 + HANDLE hSnap;
  340 + MODULEENTRY32 me;
  341 + me.dwSize = sizeof(me);
  342 + BOOL keepGoing;
  343 + size_t i;
  344 +
  345 + for (i = 0; i<(sizeof(dllname) / sizeof(dllname[0])); i++ )
  346 + {
  347 + hToolhelp = LoadLibrary( dllname[i] );
  348 + if (hToolhelp == NULL)
  349 + continue;
  350 + pCT32S = (tCT32S) GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
  351 + pM32F = (tM32F) GetProcAddress(hToolhelp, "Module32First");
  352 + pM32N = (tM32N) GetProcAddress(hToolhelp, "Module32Next");
  353 + if ( (pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL) )
  354 + break; // found the functions!
  355 + FreeLibrary(hToolhelp);
  356 + hToolhelp = NULL;
  357 + }
  358 +
  359 + if (hToolhelp == NULL)
  360 + return FALSE;
  361 +
  362 + hSnap = pCT32S( TH32CS_SNAPMODULE, pid );
  363 + if (hSnap == (HANDLE) -1)
  364 + return FALSE;
  365 +
  366 + keepGoing = !!pM32F( hSnap, &me );
  367 + int cnt = 0;
  368 + while (keepGoing)
  369 + {
  370 + LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64) me.modBaseAddr, me.modBaseSize);
  371 + cnt++;
  372 + keepGoing = !!pM32N( hSnap, &me );
  373 + }
  374 + CloseHandle(hSnap);
  375 + FreeLibrary(hToolhelp);
  376 + if (cnt <= 0)
  377 + return FALSE;
  378 + return TRUE;
  379 + } // GetModuleListTH32
  380 +
  381 + // **************************************** PSAPI ************************
  382 + typedef struct _MODULEINFO {
  383 + LPVOID lpBaseOfDll;
  384 + DWORD SizeOfImage;
  385 + LPVOID EntryPoint;
  386 + } MODULEINFO, *LPMODULEINFO;
  387 +
  388 + BOOL GetModuleListPSAPI(HANDLE hProcess)
  389 + {
  390 + // EnumProcessModules()
  391 + typedef BOOL (__stdcall *tEPM)(HANDLE hProcess, HMODULE *lphModule, DWORD cb, LPDWORD lpcbNeeded );
  392 + // GetModuleFileNameEx()
  393 + typedef DWORD (__stdcall *tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
  394 + // GetModuleBaseName()
  395 + typedef DWORD (__stdcall *tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename, DWORD nSize );
  396 + // GetModuleInformation()
  397 + typedef BOOL (__stdcall *tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize );
  398 +
  399 + HINSTANCE hPsapi;
  400 + tEPM pEPM;
  401 + tGMFNE pGMFNE;
  402 + tGMBN pGMBN;
  403 + tGMI pGMI;
  404 +
  405 + DWORD i;
  406 + //ModuleEntry e;
  407 + DWORD cbNeeded;
  408 + MODULEINFO mi;
  409 + HMODULE *hMods = 0;
  410 + char *tt = NULL;
  411 + char *tt2 = NULL;
  412 + const SIZE_T TTBUFLEN = 8096;
  413 + int cnt = 0;
  414 +
  415 + hPsapi = LoadLibrary( _T("psapi.dll") );
  416 + if (hPsapi == NULL)
  417 + return FALSE;
  418 +
  419 + pEPM = (tEPM) GetProcAddress( hPsapi, "EnumProcessModules" );
  420 + pGMFNE = (tGMFNE) GetProcAddress( hPsapi, "GetModuleFileNameExA" );
  421 + pGMBN = (tGMFNE) GetProcAddress( hPsapi, "GetModuleBaseNameA" );
  422 + pGMI = (tGMI) GetProcAddress( hPsapi, "GetModuleInformation" );
  423 + if ( (pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL) )
  424 + {
  425 + // we couldn�t find all functions
  426 + FreeLibrary(hPsapi);
  427 + return FALSE;
  428 + }
  429 +
  430 + hMods = (HMODULE*) malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof HMODULE));
  431 + tt = (char*) malloc(sizeof(char) * TTBUFLEN);
  432 + tt2 = (char*) malloc(sizeof(char) * TTBUFLEN);
  433 + if ( (hMods == NULL) || (tt == NULL) || (tt2 == NULL) )
  434 + goto cleanup;
  435 +
  436 + if ( ! pEPM( hProcess, hMods, TTBUFLEN, &cbNeeded ) )
  437 + {
  438 + //_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
  439 + goto cleanup;
  440 + }
  441 +
  442 + if ( cbNeeded > TTBUFLEN )
  443 + {
  444 + //_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
  445 + goto cleanup;
  446 + }
  447 +
  448 + for ( i = 0; i < cbNeeded / sizeof hMods[0]; i++ )
  449 + {
  450 + // base address, size
  451 + pGMI(hProcess, hMods[i], &mi, sizeof mi );
  452 + // image file name
  453 + tt[0] = 0;
  454 + pGMFNE(hProcess, hMods[i], tt, TTBUFLEN );
  455 + // module name
  456 + tt2[0] = 0;
  457 + pGMBN(hProcess, hMods[i], tt2, TTBUFLEN );
  458 +
  459 + DWORD dwRes = LoadModule(hProcess, tt, tt2, (DWORD64) mi.lpBaseOfDll, mi.SizeOfImage);
  460 + if (dwRes != ERROR_SUCCESS)
  461 + m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
  462 + cnt++;
  463 + }
  464 +
  465 + cleanup:
  466 + if (hPsapi != NULL) FreeLibrary(hPsapi);
  467 + if (tt2 != NULL) free(tt2);
  468 + if (tt != NULL) free(tt);
  469 + if (hMods != NULL) free(hMods);
  470 +
  471 + return cnt != 0;
  472 + } // GetModuleListPSAPI
  473 +
  474 + DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
  475 + {
  476 + CHAR *szImg = _strdup(img);
  477 + CHAR *szMod = _strdup(mod);
  478 + DWORD result = ERROR_SUCCESS;
  479 + if ( (szImg == NULL) || (szMod == NULL) )
  480 + result = ERROR_NOT_ENOUGH_MEMORY;
  481 + else
  482 + {
  483 + if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
  484 + result = GetLastError();
  485 + }
  486 + ULONGLONG fileVersion = 0;
  487 + if ( (m_parent != NULL) && (szImg != NULL) )
  488 + {
  489 + // try to retrive the file-version:
  490 + if ( (m_parent->m_options & StackWalker::RetrieveFileVersion) != 0)
  491 + {
  492 + VS_FIXEDFILEINFO *fInfo = NULL;
  493 + DWORD dwHandle;
  494 + DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
  495 + if (dwSize > 0)
  496 + {
  497 + LPVOID vData = malloc(dwSize);
  498 + if (vData != NULL)
  499 + {
  500 + if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
  501 + {
  502 + UINT len;
  503 + TCHAR szSubBlock[] = _T("\\");
  504 + if (VerQueryValue(vData, szSubBlock, (LPVOID*) &fInfo, &len) == 0)
  505 + fInfo = NULL;
  506 + else
  507 + {
  508 + fileVersion = ((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);
  509 + }
  510 + }
  511 + free(vData);
  512 + }
  513 + }
  514 + }
  515 +
  516 + // Retrive some additional-infos about the module
  517 + IMAGEHLP_MODULE64_V2 Module;
  518 + const char *szSymType = "-unknown-";
  519 + if (GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
  520 + {
  521 + switch(Module.SymType)
  522 + {
  523 + case SymNone:
  524 + szSymType = "-nosymbols-";
  525 + break;
  526 + case SymCoff:
  527 + szSymType = "COFF";
  528 + break;
  529 + case SymCv:
  530 + szSymType = "CV";
  531 + break;
  532 + case SymPdb:
  533 + szSymType = "PDB";
  534 + break;
  535 + case SymExport:
  536 + szSymType = "-exported-";
  537 + break;
  538 + case SymDeferred:
  539 + szSymType = "-deferred-";
  540 + break;
  541 + case SymSym:
  542 + szSymType = "SYM";
  543 + break;
  544 + case 8: //SymVirtual:
  545 + szSymType = "Virtual";
  546 + break;
  547 + case 9: // SymDia:
  548 + szSymType = "DIA";
  549 + break;
  550 + }
  551 + }
  552 + m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, Module.LoadedImageName, fileVersion);
  553 + }
  554 + if (szImg != NULL) free(szImg);
  555 + if (szMod != NULL) free(szMod);
  556 + return result;
  557 + }
  558 +public:
  559 + BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
  560 + {
  561 + // first try toolhelp32
  562 + if (GetModuleListTH32(hProcess, dwProcessId))
  563 + return true;
  564 + // then try psapi
  565 + return GetModuleListPSAPI(hProcess);
  566 + }
  567 +
  568 +
  569 + BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V2 *pModuleInfo)
  570 + {
  571 + if(pSGMI == NULL)
  572 + {
  573 + SetLastError(ERROR_DLL_INIT_FAILED);
  574 + return FALSE;
  575 + }
  576 + // First try to use the larger ModuleInfo-Structure
  577 +// memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
  578 +// pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
  579 +// if (pSGMI_V3 != NULL)
  580 +// {
  581 +// if (pSGMI_V3(hProcess, baseAddr, pModuleInfo) != FALSE)
  582 +// return TRUE;
  583 +// // check if the parameter was wrong (size is bad...)
  584 +// if (GetLastError() != ERROR_INVALID_PARAMETER)
  585 +// return FALSE;
  586 +// }
  587 + // could not retrive the bigger structure, try with the smaller one (as defined in VC7.1)...
  588 + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
  589 + void *pData = malloc(4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
  590 + if (pData == NULL)
  591 + {
  592 + SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  593 + return FALSE;
  594 + }
  595 + memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
  596 + if (pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V2*) pData) != FALSE)
  597 + {
  598 + // only copy as much memory as is reserved...
  599 + memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
  600 + pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
  601 + free(pData);
  602 + return TRUE;
  603 + }
  604 + free(pData);
  605 + SetLastError(ERROR_DLL_INIT_FAILED);
  606 + return FALSE;
  607 + }
  608 +};
  609 +
  610 +// #############################################################
  611 +StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
  612 +{
  613 + m_options = OptionsAll;
  614 + m_modulesLoaded = FALSE;
  615 + m_hProcess = hProcess;
  616 + m_sw = new StackWalkerInternal(this, m_hProcess);
  617 + m_dwProcessId = dwProcessId;
  618 + m_szSymPath = NULL;
  619 +}
  620 +StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
  621 +{
  622 + m_options = options;
  623 + m_modulesLoaded = FALSE;
  624 + m_hProcess = hProcess;
  625 + m_sw = new StackWalkerInternal(this, m_hProcess);
  626 + m_dwProcessId = dwProcessId;
  627 + if (szSymPath != NULL)
  628 + {
  629 + m_szSymPath = _strdup(szSymPath);
  630 + m_options |= SymBuildPath;
  631 + }
  632 + else
  633 + m_szSymPath = NULL;
  634 +}
  635 +
  636 +StackWalker::~StackWalker()
  637 +{
  638 + if (m_szSymPath != NULL)
  639 + free(m_szSymPath);
  640 + m_szSymPath = NULL;
  641 + if (m_sw != NULL)
  642 + delete m_sw;
  643 + m_sw = NULL;
  644 +}
  645 +
  646 +BOOL StackWalker::LoadModules()
  647 +{
  648 + if (m_sw == NULL)
  649 + {
  650 + SetLastError(ERROR_DLL_INIT_FAILED);
  651 + return FALSE;
  652 + }
  653 + if (m_modulesLoaded != FALSE)
  654 + return TRUE;
  655 +
  656 + // Build the sym-path:
  657 + char *szSymPath = NULL;
  658 + if ( (m_options & SymBuildPath) != 0)
  659 + {
  660 + const size_t nSymPathLen = 4096;
  661 + szSymPath = (char*) malloc(nSymPathLen);
  662 + if (szSymPath == NULL)
  663 + {
  664 + SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  665 + return FALSE;
  666 + }
  667 + szSymPath[0] = 0;
  668 + // Now first add the (optional) provided sympath:
  669 + if (m_szSymPath != NULL)
  670 + {
  671 + strcat_s(szSymPath, nSymPathLen, m_szSymPath);
  672 + strcat_s(szSymPath, nSymPathLen, ";");
  673 + }
  674 +
  675 + strcat_s(szSymPath, nSymPathLen, ".;");
  676 +
  677 + const size_t nTempLen = 1024;
  678 + char szTemp[nTempLen];
  679 + // Now add the current directory:
  680 + if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
  681 + {
  682 + szTemp[nTempLen-1] = 0;
  683 + strcat_s(szSymPath, nSymPathLen, szTemp);
  684 + strcat_s(szSymPath, nSymPathLen, ";");
  685 + }
  686 +
  687 + // Now add the path for the main-module:
  688 + if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
  689 + {
  690 + szTemp[nTempLen-1] = 0;
  691 + for (char *p = (szTemp+strlen(szTemp)-1); p >= szTemp; --p)
  692 + {
  693 + // locate the rightmost path separator
  694 + if ( (*p == '\\') || (*p == '/') || (*p == ':') )
  695 + {
  696 + *p = 0;
  697 + break;
  698 + }
  699 + } // for (search for path separator...)
  700 + if (strlen(szTemp) > 0)
  701 + {
  702 + strcat_s(szSymPath, nSymPathLen, szTemp);
  703 + strcat_s(szSymPath, nSymPathLen, ";");
  704 + }
  705 + }
  706 + if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
  707 + {
  708 + szTemp[nTempLen-1] = 0;
  709 + strcat_s(szSymPath, nSymPathLen, szTemp);
  710 + strcat_s(szSymPath, nSymPathLen, ";");
  711 + }
  712 + if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
  713 + {
  714 + szTemp[nTempLen-1] = 0;
  715 + strcat_s(szSymPath, nSymPathLen, szTemp);
  716 + strcat_s(szSymPath, nSymPathLen, ";");
  717 + }
  718 + if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
  719 + {
  720 + szTemp[nTempLen-1] = 0;
  721 + strcat_s(szSymPath, nSymPathLen, szTemp);
  722 + strcat_s(szSymPath, nSymPathLen, ";");
  723 + // also add the "system32"-directory:
  724 + strcat_s(szTemp, nTempLen, "\\system32");
  725 + strcat_s(szSymPath, nSymPathLen, szTemp);
  726 + strcat_s(szSymPath, nSymPathLen, ";");
  727 + }
  728 +
  729 + if ( (m_options & SymBuildPath) != 0)
  730 + {
  731 + if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
  732 + {
  733 + szTemp[nTempLen-1] = 0;
  734 + strcat_s(szSymPath, nSymPathLen, "SRV*");
  735 + strcat_s(szSymPath, nSymPathLen, szTemp);
  736 + strcat_s(szSymPath, nSymPathLen, "\\websymbols");
  737 + strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");
  738 + }
  739 + else
  740 + strcat_s(szSymPath, nSymPathLen, "SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");
  741 + }
  742 + }
  743 +
  744 + // First Init the whole stuff...
  745 + BOOL bRet = m_sw->Init(szSymPath);
  746 + if (szSymPath != NULL) free(szSymPath); szSymPath = NULL;
  747 + if (bRet == FALSE)
  748 + {
  749 + OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
  750 + SetLastError(ERROR_DLL_INIT_FAILED);
  751 + return FALSE;
  752 + }
  753 +
  754 + bRet = m_sw->LoadModules(m_hProcess, m_dwProcessId);
  755 + if (bRet != FALSE)
  756 + m_modulesLoaded = TRUE;
  757 + return bRet;
  758 +}
  759 +
  760 +
  761 +// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
  762 +// This has to be done due to a problem with the "hProcess"-parameter in x64...
  763 +// Because this class is in no case multi-threading-enabled (because of the limitations
  764 +// of dbghelp.dll) it is "safe" to use a static-variable
  765 +static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
  766 +static LPVOID s_readMemoryFunction_UserData = NULL;
  767 +
  768 +BOOL StackWalker::ShowCallstack(HANDLE hThread, const CONTEXT *context, PReadProcessMemoryRoutine readMemoryFunction, LPVOID pUserData)
  769 +{
  770 + CONTEXT c;;
  771 + CallstackEntry csEntry;
  772 + IMAGEHLP_SYMBOL64 *pSym = NULL;
  773 + StackWalkerInternal::IMAGEHLP_MODULE64_V2 Module;
  774 + IMAGEHLP_LINE64 Line;
  775 + int frameNum;
  776 +
  777 + if (m_modulesLoaded == FALSE)
  778 + LoadModules(); // ignore the result...
  779 +
  780 + if (m_sw->m_hDbhHelp == NULL)
  781 + {
  782 + SetLastError(ERROR_DLL_INIT_FAILED);
  783 + return FALSE;
  784 + }
  785 +
  786 + s_readMemoryFunction = readMemoryFunction;
  787 + s_readMemoryFunction_UserData = pUserData;
  788 +
  789 + if (context == NULL)
  790 + {
  791 + // If no context is provided, capture the context
  792 + if (hThread == GetCurrentThread())
  793 + {
  794 + GET_CURRENT_CONTEXT(c, USED_CONTEXT_FLAGS);
  795 + }
  796 + else
  797 + {
  798 + SuspendThread(hThread);
  799 + memset(&c, 0, sizeof(CONTEXT));
  800 + c.ContextFlags = USED_CONTEXT_FLAGS;
  801 + if (GetThreadContext(hThread, &c) == FALSE)
  802 + {
  803 + ResumeThread(hThread);
  804 + return FALSE;
  805 + }
  806 + }
  807 + }
  808 + else
  809 + c = *context;
  810 +
  811 + // init STACKFRAME for first call
  812 + STACKFRAME64 s; // in/out stackframe
  813 + memset(&s, 0, sizeof(s));
  814 + DWORD imageType;
  815 +#ifdef _M_IX86
  816 + // normally, call ImageNtHeader() and use machine info from PE header
  817 + imageType = IMAGE_FILE_MACHINE_I386;
  818 + s.AddrPC.Offset = c.Eip;
  819 + s.AddrPC.Mode = AddrModeFlat;
  820 + s.AddrFrame.Offset = c.Ebp;
  821 + s.AddrFrame.Mode = AddrModeFlat;
  822 + s.AddrStack.Offset = c.Esp;
  823 + s.AddrStack.Mode = AddrModeFlat;
  824 +#elif _M_X64
  825 + imageType = IMAGE_FILE_MACHINE_AMD64;
  826 + s.AddrPC.Offset = c.Rip;
  827 + s.AddrPC.Mode = AddrModeFlat;
  828 + s.AddrFrame.Offset = c.Rsp;
  829 + s.AddrFrame.Mode = AddrModeFlat;
  830 + s.AddrStack.Offset = c.Rsp;
  831 + s.AddrStack.Mode = AddrModeFlat;
  832 +#elif _M_IA64
  833 + imageType = IMAGE_FILE_MACHINE_IA64;
  834 + s.AddrPC.Offset = c.StIIP;
  835 + s.AddrPC.Mode = AddrModeFlat;
  836 + s.AddrFrame.Offset = c.IntSp;
  837 + s.AddrFrame.Mode = AddrModeFlat;
  838 + s.AddrBStore.Offset = c.RsBSP;
  839 + s.AddrBStore.Mode = AddrModeFlat;
  840 + s.AddrStack.Offset = c.IntSp;
  841 + s.AddrStack.Mode = AddrModeFlat;
  842 +#else
  843 +#error "Platform not supported!"
  844 +#endif
  845 +
  846 + pSym = (IMAGEHLP_SYMBOL64 *) malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
  847 + if (!pSym) goto cleanup; // not enough memory...
  848 + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
  849 + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
  850 + pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
  851 +
  852 + memset(&Line, 0, sizeof(Line));
  853 + Line.SizeOfStruct = sizeof(Line);
  854 +
  855 + memset(&Module, 0, sizeof(Module));
  856 + Module.SizeOfStruct = sizeof(Module);
  857 +
  858 + for (frameNum = 0; ; ++frameNum )
  859 + {
  860 + // get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
  861 + // if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
  862 + // assume that either you are done, or that the stack is so hosed that the next
  863 + // deeper frame could not be found.
  864 + // CONTEXT need not to be suplied if imageTyp is IMAGE_FILE_MACHINE_I386!
  865 + if ( ! m_sw->pSW(imageType, m_hProcess, hThread, &s, &c, myReadProcMem, m_sw->pSFTA, m_sw->pSGMB, NULL) )
  866 + {
  867 + OnDbgHelpErr("StackWalk64", GetLastError(), s.AddrPC.Offset);
  868 + break;
  869 + }
  870 +
  871 + csEntry.offset = s.AddrPC.Offset;
  872 + csEntry.name[0] = 0;
  873 + csEntry.undName[0] = 0;
  874 + csEntry.undFullName[0] = 0;
  875 + csEntry.offsetFromSmybol = 0;
  876 + csEntry.offsetFromLine = 0;
  877 + csEntry.lineFileName[0] = 0;
  878 + csEntry.lineNumber = 0;
  879 + csEntry.loadedImageName[0] = 0;
  880 + csEntry.moduleName[0] = 0;
  881 + if (s.AddrPC.Offset == s.AddrReturn.Offset)
  882 + {
  883 + OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
  884 + break;
  885 + }
  886 + if (s.AddrPC.Offset != 0)
  887 + {
  888 + // we seem to have a valid PC
  889 + // show procedure info (SymGetSymFromAddr64())
  890 + if (m_sw->pSGSFA(m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol), pSym) != FALSE)
  891 + {
  892 + // TODO: Mache dies sicher...!
  893 + strcpy_s(csEntry.name, pSym->Name);
  894 + // UnDecorateSymbolName()
  895 + m_sw->pUDSN( pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY );
  896 + m_sw->pUDSN( pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE );
  897 + }
  898 + else
  899 + {
  900 + OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
  901 + }
  902 +
  903 + // show line number info, NT5.0-method (SymGetLineFromAddr64())
  904 + if (m_sw->pSGLFA != NULL )
  905 + { // yes, we have SymGetLineFromAddr64()
  906 + if (m_sw->pSGLFA(m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine), &Line) != FALSE)
  907 + {
  908 + csEntry.lineNumber = Line.LineNumber;
  909 + // TODO: Mache dies sicher...!
  910 + strcpy_s(csEntry.lineFileName, Line.FileName);
  911 + }
  912 + else
  913 + {
  914 + OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
  915 + }
  916 + } // yes, we have SymGetLineFromAddr64()
  917 +
  918 + // show module info (SymGetModuleInfo64())
  919 + if (m_sw->GetModuleInfo(m_hProcess, s.AddrPC.Offset, &Module ) != FALSE)
  920 + { // got module info OK
  921 + switch ( Module.SymType )
  922 + {
  923 + case SymNone:
  924 + csEntry.symTypeString = "-nosymbols-";
  925 + break;
  926 + case SymCoff:
  927 + csEntry.symTypeString = "COFF";
  928 + break;
  929 + case SymCv:
  930 + csEntry.symTypeString = "CV";
  931 + break;
  932 + case SymPdb:
  933 + csEntry.symTypeString = "PDB";
  934 + break;
  935 + case SymExport:
  936 + csEntry.symTypeString = "-exported-";
  937 + break;
  938 + case SymDeferred:
  939 + csEntry.symTypeString = "-deferred-";
  940 + break;
  941 + case SymSym:
  942 + csEntry.symTypeString = "SYM";
  943 + break;
  944 +#if API_VERSION_NUMBER >= 9
  945 + case SymDia:
  946 + csEntry.symTypeString = "DIA";
  947 + break;
  948 +#endif
  949 + case 8: //SymVirtual:
  950 + csEntry.symTypeString = "Virtual";
  951 + break;
  952 + default:
  953 + //_snprintf( ty, sizeof ty, "symtype=%ld", (long) Module.SymType );
  954 + csEntry.symTypeString = NULL;
  955 + break;
  956 + }
  957 +
  958 + // TODO: Mache dies sicher...!
  959 + strcpy_s(csEntry.moduleName, Module.ModuleName);
  960 + csEntry.baseOfImage = Module.BaseOfImage;
  961 + strcpy_s(csEntry.loadedImageName, Module.LoadedImageName);
  962 + } // got module info OK
  963 + else
  964 + {
  965 + OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
  966 + }
  967 + } // we seem to have a valid PC
  968 +
  969 + CallstackEntryType et = nextEntry;
  970 + if (frameNum == 0)
  971 + et = firstEntry;
  972 + OnCallstackEntry(et, csEntry);
  973 +
  974 + if (s.AddrReturn.Offset == 0)
  975 + {
  976 + OnCallstackEntry(lastEntry, csEntry);
  977 + SetLastError(ERROR_SUCCESS);
  978 + break;
  979 + }
  980 + } // for ( frameNum )
  981 +
  982 + cleanup:
  983 + if (pSym) free( pSym );
  984 +
  985 + if (context == NULL)
  986 + ResumeThread(hThread);
  987 +
  988 + return TRUE;
  989 +}
  990 +
  991 +BOOL __stdcall StackWalker::myReadProcMem(
  992 + HANDLE hProcess,
  993 + DWORD64 qwBaseAddress,
  994 + PVOID lpBuffer,
  995 + DWORD nSize,
  996 + LPDWORD lpNumberOfBytesRead
  997 + )
  998 +{
  999 + if (s_readMemoryFunction == NULL)
  1000 + {
  1001 + SIZE_T st;
  1002 + BOOL bRet = ReadProcessMemory(hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, &st);
  1003 + *lpNumberOfBytesRead = (DWORD) st;
  1004 + //printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
  1005 + return bRet;
  1006 + }
  1007 + else
  1008 + {
  1009 + return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead, s_readMemoryFunction_UserData);
  1010 + }
  1011 +}
  1012 +
  1013 +void StackWalker::OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
  1014 +{
  1015 + CHAR buffer[STACKWALK_MAX_NAMELEN];
  1016 + if (fileVersion == 0)
  1017 + _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);
  1018 + else
  1019 + {
  1020 + DWORD v4 = (DWORD) fileVersion & 0xFFFF;
  1021 + DWORD v3 = (DWORD) (fileVersion>>16) & 0xFFFF;
  1022 + DWORD v2 = (DWORD) (fileVersion>>32) & 0xFFFF;
  1023 + DWORD v1 = (DWORD) (fileVersion>>48) & 0xFFFF;
  1024 + _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);
  1025 + }
  1026 + OnOutput(buffer);
  1027 +}
  1028 +
  1029 +void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
  1030 +{
  1031 + CHAR buffer[STACKWALK_MAX_NAMELEN];
  1032 + if ( (eType != lastEntry) && (entry.offset != 0) )
  1033 + {
  1034 + if (entry.name[0] == 0)
  1035 + strcpy_s(entry.name, "(function-name not available)");
  1036 + if (entry.undName[0] != 0)
  1037 + strcpy_s(entry.name, entry.undName);
  1038 + if (entry.undFullName[0] != 0)
  1039 + strcpy_s(entry.name, entry.undFullName);
  1040 + if (entry.lineFileName[0] == 0)
  1041 + {
  1042 + strcpy_s(entry.lineFileName, "(filename not available)");
  1043 + if (entry.moduleName[0] == 0)
  1044 + strcpy_s(entry.moduleName, "(module-name not available)");
  1045 + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%p (%s): %s: %s\n", (LPVOID) entry.offset, entry.moduleName, entry.lineFileName, entry.name);
  1046 + }
  1047 + else
  1048 + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber, entry.name);
  1049 + OnOutput(buffer);
  1050 + }
  1051 +}
  1052 +
  1053 +void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
  1054 +{
  1055 + CHAR buffer[STACKWALK_MAX_NAMELEN];
  1056 + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle, (LPVOID) addr);
  1057 + OnOutput(buffer);
  1058 +}
  1059 +
  1060 +void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
  1061 +{
  1062 + CHAR buffer[STACKWALK_MAX_NAMELEN];
  1063 + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n", szSearchPath, symOptions, szUserName);
  1064 + OnOutput(buffer);
  1065 + // Also display the OS-version
  1066 +#if _MSC_VER <= 1200
  1067 + OSVERSIONINFOA ver;
  1068 + ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
  1069 + ver.dwOSVersionInfoSize = sizeof(ver);
  1070 + if (GetVersionExA(&ver) != FALSE)
  1071 + {
  1072 + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n",
  1073 + ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
  1074 + ver.szCSDVersion);
  1075 + OnOutput(buffer);
  1076 + }
  1077 +#else
  1078 + OSVERSIONINFOEXA ver;
  1079 + ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
  1080 + ver.dwOSVersionInfoSize = sizeof(ver);
  1081 + if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE)
  1082 + {
  1083 + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n",
  1084 + ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber,
  1085 + ver.szCSDVersion, ver.wSuiteMask, ver.wProductType);
  1086 + OnOutput(buffer);
  1087 + }
  1088 +#endif
  1089 +}
  1090 +
  1091 +void StackWalker::OnOutput(LPCSTR buffer)
  1092 +{
  1093 + OutputDebugStringA(buffer);
  1094 +}
  1095 +
  1096 +#endif // TARGET_OS_WINDOWS
189 src/StackWalker/StackWalker.h
... ... @@ -0,0 +1,189 @@
  1 +/**********************************************************************
  2 + *
  3 + * StackWalker.h
  4 + *
  5 + *
  6 + * History:
  7 + * 2005-07-27 v1 - First public release on http://www.codeproject.com/
  8 + * (for additional changes see History in 'StackWalker.cpp'!
  9 + *
  10 + **********************************************************************/
  11 +// #pragma once is supported starting with _MCS_VER 1000,
  12 +// so we need not to check the version (because we only support _MSC_VER >= 1100)!
  13 +#pragma once
  14 +
  15 +#include <windows.h>
  16 +
  17 +// special defines for VC5/6 (if no actual PSDK is installed):
  18 +#if _MSC_VER < 1300
  19 +typedef unsigned __int64 DWORD64, *PDWORD64;
  20 +#if defined(_WIN64)
  21 +typedef unsigned __int64 SIZE_T, *PSIZE_T;
  22 +#else
  23 +typedef unsigned long SIZE_T, *PSIZE_T;
  24 +#endif
  25 +#endif // _MSC_VER < 1300
  26 +
  27 +class StackWalkerInternal; // forward
  28 +class StackWalker
  29 +{
  30 +public:
  31 + typedef enum StackWalkOptions
  32 + {
  33 + // No addition info will be retrived
  34 + // (only the address is available)
  35 + RetrieveNone = 0,
  36 +
  37 + // Try to get the symbol-name
  38 + RetrieveSymbol = 1,
  39 +
  40 + // Try to get the line for this symbol
  41 + RetrieveLine = 2,
  42 +
  43 + // Try to retrieve the module-infos
  44 + RetrieveModuleInfo = 4,
  45 +
  46 + // Also retrieve the version for the DLL/EXE
  47 + RetrieveFileVersion = 8,
  48 +
  49 + // Contains all the abouve
  50 + RetrieveVerbose = 0xF,
  51 +
  52 + // Generate a "good" symbol-search-path
  53 + SymBuildPath = 0x10,
  54 +
  55 + // Also use the public Microsoft-Symbol-Server
  56 + SymUseSymSrv = 0x20,
  57 +
  58 + // Contains all the abouve "Sym"-options
  59 + SymAll = 0x30,
  60 +
  61 + // Contains all options (default)
  62 + OptionsAll = 0x3F
  63 + } StackWalkOptions;
  64 +
  65 + StackWalker(
  66 + int options = OptionsAll, // 'int' is by design, to combine the enum-flags
  67 + LPCSTR szSymPath = NULL,
  68 + DWORD dwProcessId = GetCurrentProcessId(),
  69 + HANDLE hProcess = GetCurrentProcess()
  70 + );
  71 + StackWalker(DWORD dwProcessId, HANDLE hProcess);
  72 + virtual ~StackWalker();
  73 +
  74 + typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
  75 + HANDLE hProcess,
  76 + DWORD64 qwBaseAddress,
  77 + PVOID lpBuffer,
  78 + DWORD nSize,