诸暨麻将添加redis
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1222 lines
43 KiB

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