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