Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/angle
Path: blob/main_old/util/windows/third_party/StackWalker/src/StackWalker.cpp
1695 views
1
/**********************************************************************
2
*
3
* StackWalker.cpp
4
* https://github.com/JochenKalmbach/StackWalker
5
*
6
* Old location: http://stackwalker.codeplex.com/
7
*
8
*
9
* History:
10
* 2005-07-27 v1 - First public release on http://www.codeproject.com/
11
* http://www.codeproject.com/threads/StackWalker.asp
12
* 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack
13
* (to simplify the usage)
14
* 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL
15
* (should also be enough)
16
* - Changed to compile correctly with the PSDK of VC7.0
17
* (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined:
18
* it uses LPSTR instead of LPCSTR as first parameter)
19
* - Added declarations to support VC5/6 without using 'dbghelp.h'
20
* - Added a 'pUserData' member to the ShowCallstack function and the
21
* PReadProcessMemoryRoutine declaration (to pass some user-defined data,
22
* which can be used in the readMemoryFunction-callback)
23
* 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default
24
* - Added example for doing an exception-callstack-walking in main.cpp
25
* (thanks to owillebo: http://www.codeproject.com/script/profile/whos_who.asp?id=536268)
26
* 2005-08-05 v5 - Removed most Lint (http://www.gimpel.com/) errors... thanks to Okko Willeboordse!
27
* 2008-08-04 v6 - Fixed Bug: Missing LEAK-end-tag
28
* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2502890#xx2502890xx
29
* Fixed Bug: Compiled with "WIN32_LEAN_AND_MEAN"
30
* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=1824718#xx1824718xx
31
* Fixed Bug: Compiling with "/Wall"
32
* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2638243#xx2638243xx
33
* Fixed Bug: Now checking SymUseSymSrv
34
* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1388979#xx1388979xx
35
* Fixed Bug: Support for recursive function calls
36
* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1434538#xx1434538xx
37
* Fixed Bug: Missing FreeLibrary call in "GetModuleListTH32"
38
* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=1326923#xx1326923xx
39
* Fixed Bug: SymDia is number 7, not 9!
40
* 2008-09-11 v7 For some (undocumented) reason, dbhelp.h is needing a packing of 8!
41
* Thanks to Teajay which reported the bug...
42
* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=2718933#xx2718933xx
43
* 2008-11-27 v8 Debugging Tools for Windows are now stored in a different directory
44
* Thanks to Luiz Salamon which reported this "bug"...
45
* http://www.codeproject.com/KB/threads/StackWalker.aspx?msg=2822736#xx2822736xx
46
* 2009-04-10 v9 License slightly corrected (<ORGANIZATION> replaced)
47
* 2009-11-01 v10 Moved to http://stackwalker.codeplex.com/
48
* 2009-11-02 v11 Now try to use IMAGEHLP_MODULE64_V3 if available
49
* 2010-04-15 v12 Added support for VS2010 RTM
50
* 2010-05-25 v13 Now using secure MyStrcCpy. Thanks to luke.simon:
51
* http://www.codeproject.com/KB/applications/leakfinder.aspx?msg=3477467#xx3477467xx
52
* 2013-01-07 v14 Runtime Check Error VS2010 Debug Builds fixed:
53
* http://stackwalker.codeplex.com/workitem/10511
54
*
55
*
56
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
57
*
58
* Copyright (c) 2005-2013, Jochen Kalmbach
59
* All rights reserved.
60
*
61
* Redistribution and use in source and binary forms, with or without modification,
62
* are permitted provided that the following conditions are met:
63
*
64
* Redistributions of source code must retain the above copyright notice,
65
* this list of conditions and the following disclaimer.
66
* Redistributions in binary form must reproduce the above copyright notice,
67
* this list of conditions and the following disclaimer in the documentation
68
* and/or other materials provided with the distribution.
69
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
70
* used to endorse or promote products derived from this software without
71
* specific prior written permission.
72
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
73
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
74
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
75
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
76
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
77
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
78
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
79
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
80
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
81
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
82
*
83
**********************************************************************/
84
85
#include "StackWalker.h"
86
87
#include <stdio.h>
88
#include <stdlib.h>
89
#include <tchar.h>
90
#include <windows.h>
91
#pragma comment(lib, "version.lib") // for "VerQueryValue"
92
#pragma warning(disable : 4826)
93
94
95
// If VC7 and later, then use the shipped 'dbghelp.h'-file
96
#pragma pack(push, 8)
97
#if _MSC_VER >= 1300
98
#include <dbghelp.h>
99
#else
100
// inline the important dbghelp.h-declarations...
101
typedef enum
102
{
103
SymNone = 0,
104
SymCoff,
105
SymCv,
106
SymPdb,
107
SymExport,
108
SymDeferred,
109
SymSym,
110
SymDia,
111
SymVirtual,
112
NumSymTypes
113
} SYM_TYPE;
114
typedef struct _IMAGEHLP_LINE64
115
{
116
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_LINE64)
117
PVOID Key; // internal
118
DWORD LineNumber; // line number in file
119
PCHAR FileName; // full filename
120
DWORD64 Address; // first instruction of line
121
} IMAGEHLP_LINE64, *PIMAGEHLP_LINE64;
122
typedef struct _IMAGEHLP_MODULE64
123
{
124
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
125
DWORD64 BaseOfImage; // base load address of module
126
DWORD ImageSize; // virtual size of the loaded module
127
DWORD TimeDateStamp; // date/time stamp from pe header
128
DWORD CheckSum; // checksum from the pe header
129
DWORD NumSyms; // number of symbols in the symbol table
130
SYM_TYPE SymType; // type of symbols loaded
131
CHAR ModuleName[32]; // module name
132
CHAR ImageName[256]; // image name
133
CHAR LoadedImageName[256]; // symbol file name
134
} IMAGEHLP_MODULE64, *PIMAGEHLP_MODULE64;
135
typedef struct _IMAGEHLP_SYMBOL64
136
{
137
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_SYMBOL64)
138
DWORD64 Address; // virtual address including dll base address
139
DWORD Size; // estimated size of symbol, can be zero
140
DWORD Flags; // info about the symbols, see the SYMF defines
141
DWORD MaxNameLength; // maximum size of symbol name in 'Name'
142
CHAR Name[1]; // symbol name (null terminated string)
143
} IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64;
144
typedef enum
145
{
146
AddrMode1616,
147
AddrMode1632,
148
AddrModeReal,
149
AddrModeFlat
150
} ADDRESS_MODE;
151
typedef struct _tagADDRESS64
152
{
153
DWORD64 Offset;
154
WORD Segment;
155
ADDRESS_MODE Mode;
156
} ADDRESS64, *LPADDRESS64;
157
typedef struct _KDHELP64
158
{
159
DWORD64 Thread;
160
DWORD ThCallbackStack;
161
DWORD ThCallbackBStore;
162
DWORD NextCallback;
163
DWORD FramePointer;
164
DWORD64 KiCallUserMode;
165
DWORD64 KeUserCallbackDispatcher;
166
DWORD64 SystemRangeStart;
167
DWORD64 Reserved[8];
168
} KDHELP64, *PKDHELP64;
169
typedef struct _tagSTACKFRAME64
170
{
171
ADDRESS64 AddrPC; // program counter
172
ADDRESS64 AddrReturn; // return address
173
ADDRESS64 AddrFrame; // frame pointer
174
ADDRESS64 AddrStack; // stack pointer
175
ADDRESS64 AddrBStore; // backing store pointer
176
PVOID FuncTableEntry; // pointer to pdata/fpo or NULL
177
DWORD64 Params[4]; // possible arguments to the function
178
BOOL Far; // WOW far call
179
BOOL Virtual; // is this a virtual frame?
180
DWORD64 Reserved[3];
181
KDHELP64 KdHelp;
182
} STACKFRAME64, *LPSTACKFRAME64;
183
typedef BOOL(__stdcall* PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess,
184
DWORD64 qwBaseAddress,
185
PVOID lpBuffer,
186
DWORD nSize,
187
LPDWORD lpNumberOfBytesRead);
188
typedef PVOID(__stdcall* PFUNCTION_TABLE_ACCESS_ROUTINE64)(HANDLE hProcess, DWORD64 AddrBase);
189
typedef DWORD64(__stdcall* PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, DWORD64 Address);
190
typedef DWORD64(__stdcall* PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess,
191
HANDLE hThread,
192
LPADDRESS64 lpaddr);
193
194
// clang-format off
195
#define SYMOPT_CASE_INSENSITIVE 0x00000001
196
#define SYMOPT_UNDNAME 0x00000002
197
#define SYMOPT_DEFERRED_LOADS 0x00000004
198
#define SYMOPT_NO_CPP 0x00000008
199
#define SYMOPT_LOAD_LINES 0x00000010
200
#define SYMOPT_OMAP_FIND_NEAREST 0x00000020
201
#define SYMOPT_LOAD_ANYTHING 0x00000040
202
#define SYMOPT_IGNORE_CVREC 0x00000080
203
#define SYMOPT_NO_UNQUALIFIED_LOADS 0x00000100
204
#define SYMOPT_FAIL_CRITICAL_ERRORS 0x00000200
205
#define SYMOPT_EXACT_SYMBOLS 0x00000400
206
#define SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 0x00000800
207
#define SYMOPT_IGNORE_NT_SYMPATH 0x00001000
208
#define SYMOPT_INCLUDE_32BIT_MODULES 0x00002000
209
#define SYMOPT_PUBLICS_ONLY 0x00004000
210
#define SYMOPT_NO_PUBLICS 0x00008000
211
#define SYMOPT_AUTO_PUBLICS 0x00010000
212
#define SYMOPT_NO_IMAGE_SEARCH 0x00020000
213
#define SYMOPT_SECURE 0x00040000
214
#define SYMOPT_DEBUG 0x80000000
215
#define UNDNAME_COMPLETE (0x0000) // Enable full undecoration
216
#define UNDNAME_NAME_ONLY (0x1000) // Crack only the name for primary declaration;
217
// clang-format on
218
219
#endif // _MSC_VER < 1300
220
#pragma pack(pop)
221
222
// Some missing defines (for VC5/6):
223
#ifndef INVALID_FILE_ATTRIBUTES
224
#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
225
#endif
226
227
// secure-CRT_functions are only available starting with VC8
228
#if _MSC_VER < 1400
229
#define strcpy_s(dst, len, src) strcpy(dst, src)
230
#define strncpy_s(dst, len, src, maxLen) strncpy(dst, len, src)
231
#define strcat_s(dst, len, src) strcat(dst, src)
232
#define _snprintf_s _snprintf
233
#define _tcscat_s _tcscat
234
#endif
235
236
static void MyStrCpy(char* szDest, size_t nMaxDestSize, const char* szSrc)
237
{
238
if (nMaxDestSize <= 0)
239
return;
240
strncpy_s(szDest, nMaxDestSize, szSrc, _TRUNCATE);
241
// INFO: _TRUNCATE will ensure that it is null-terminated;
242
// but with older compilers (<1400) it uses "strncpy" and this does not!)
243
szDest[nMaxDestSize - 1] = 0;
244
} // MyStrCpy
245
246
// Normally it should be enough to use 'CONTEXT_FULL' (better would be 'CONTEXT_ALL')
247
#define USED_CONTEXT_FLAGS CONTEXT_FULL
248
249
class StackWalkerInternal
250
{
251
public:
252
StackWalkerInternal(StackWalker* parent, HANDLE hProcess)
253
{
254
m_parent = parent;
255
m_hDbhHelp = NULL;
256
pSC = NULL;
257
m_hProcess = hProcess;
258
m_szSymPath = NULL;
259
pSFTA = NULL;
260
pSGLFA = NULL;
261
pSGMB = NULL;
262
pSGMI = NULL;
263
pSGO = NULL;
264
pSGSFA = NULL;
265
pSI = NULL;
266
pSLM = NULL;
267
pSSO = NULL;
268
pSW = NULL;
269
pUDSN = NULL;
270
pSGSP = NULL;
271
}
272
~StackWalkerInternal()
273
{
274
if (pSC != NULL)
275
pSC(m_hProcess); // SymCleanup
276
if (m_hDbhHelp != NULL)
277
FreeLibrary(m_hDbhHelp);
278
m_hDbhHelp = NULL;
279
m_parent = NULL;
280
if (m_szSymPath != NULL)
281
free(m_szSymPath);
282
m_szSymPath = NULL;
283
}
284
BOOL Init(LPCSTR szSymPath)
285
{
286
if (m_parent == NULL)
287
return FALSE;
288
// Dynamically load the Entry-Points for dbghelp.dll:
289
// First try to load the newest one from
290
TCHAR szTemp[4096];
291
// But before we do this, we first check if the ".local" file exists
292
if (GetModuleFileName(NULL, szTemp, 4096) > 0)
293
{
294
_tcscat_s(szTemp, _T(".local"));
295
if (GetFileAttributes(szTemp) == INVALID_FILE_ATTRIBUTES)
296
{
297
// ".local" file does not exist, so we can try to load the dbghelp.dll from the "Debugging Tools for Windows"
298
// Ok, first try the new path according to the architecture:
299
#ifdef _M_IX86
300
if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
301
{
302
_tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x86)\\dbghelp.dll"));
303
// now check if the file exists:
304
if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
305
{
306
m_hDbhHelp = LoadLibrary(szTemp);
307
}
308
}
309
#elif _M_X64
310
if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
311
{
312
_tcscat_s(szTemp, _T("\\Debugging Tools for Windows (x64)\\dbghelp.dll"));
313
// now check if the file exists:
314
if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
315
{
316
m_hDbhHelp = LoadLibrary(szTemp);
317
}
318
}
319
#elif _M_IA64
320
if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
321
{
322
_tcscat_s(szTemp, _T("\\Debugging Tools for Windows (ia64)\\dbghelp.dll"));
323
// now check if the file exists:
324
if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
325
{
326
m_hDbhHelp = LoadLibrary(szTemp);
327
}
328
}
329
#endif
330
// If still not found, try the old directories...
331
if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
332
{
333
_tcscat_s(szTemp, _T("\\Debugging Tools for Windows\\dbghelp.dll"));
334
// now check if the file exists:
335
if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
336
{
337
m_hDbhHelp = LoadLibrary(szTemp);
338
}
339
}
340
#if defined _M_X64 || defined _M_IA64
341
// Still not found? Then try to load the (old) 64-Bit version:
342
if ((m_hDbhHelp == NULL) && (GetEnvironmentVariable(_T("ProgramFiles"), szTemp, 4096) > 0))
343
{
344
_tcscat_s(szTemp, _T("\\Debugging Tools for Windows 64-Bit\\dbghelp.dll"));
345
if (GetFileAttributes(szTemp) != INVALID_FILE_ATTRIBUTES)
346
{
347
m_hDbhHelp = LoadLibrary(szTemp);
348
}
349
}
350
#endif
351
}
352
}
353
if (m_hDbhHelp == NULL) // if not already loaded, try to load a default-one
354
m_hDbhHelp = LoadLibrary(_T("dbghelp.dll"));
355
if (m_hDbhHelp == NULL)
356
return FALSE;
357
pSI = (tSI)GetProcAddress(m_hDbhHelp, "SymInitialize");
358
pSC = (tSC)GetProcAddress(m_hDbhHelp, "SymCleanup");
359
360
pSW = (tSW)GetProcAddress(m_hDbhHelp, "StackWalk64");
361
pSGO = (tSGO)GetProcAddress(m_hDbhHelp, "SymGetOptions");
362
pSSO = (tSSO)GetProcAddress(m_hDbhHelp, "SymSetOptions");
363
364
pSFTA = (tSFTA)GetProcAddress(m_hDbhHelp, "SymFunctionTableAccess64");
365
pSGLFA = (tSGLFA)GetProcAddress(m_hDbhHelp, "SymGetLineFromAddr64");
366
pSGMB = (tSGMB)GetProcAddress(m_hDbhHelp, "SymGetModuleBase64");
367
pSGMI = (tSGMI)GetProcAddress(m_hDbhHelp, "SymGetModuleInfo64");
368
pSGSFA = (tSGSFA)GetProcAddress(m_hDbhHelp, "SymGetSymFromAddr64");
369
pUDSN = (tUDSN)GetProcAddress(m_hDbhHelp, "UnDecorateSymbolName");
370
pSLM = (tSLM)GetProcAddress(m_hDbhHelp, "SymLoadModule64");
371
pSGSP = (tSGSP)GetProcAddress(m_hDbhHelp, "SymGetSearchPath");
372
373
if (pSC == NULL || pSFTA == NULL || pSGMB == NULL || pSGMI == NULL || pSGO == NULL ||
374
pSGSFA == NULL || pSI == NULL || pSSO == NULL || pSW == NULL || pUDSN == NULL ||
375
pSLM == NULL)
376
{
377
FreeLibrary(m_hDbhHelp);
378
m_hDbhHelp = NULL;
379
pSC = NULL;
380
return FALSE;
381
}
382
383
// SymInitialize
384
if (szSymPath != NULL)
385
m_szSymPath = _strdup(szSymPath);
386
if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE)
387
this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0);
388
389
DWORD symOptions = this->pSGO(); // SymGetOptions
390
symOptions |= SYMOPT_LOAD_LINES;
391
symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS;
392
//symOptions |= SYMOPT_NO_PROMPTS;
393
// SymSetOptions
394
symOptions = this->pSSO(symOptions);
395
396
char buf[StackWalker::STACKWALK_MAX_NAMELEN] = {0};
397
if (this->pSGSP != NULL)
398
{
399
if (this->pSGSP(m_hProcess, buf, StackWalker::STACKWALK_MAX_NAMELEN) == FALSE)
400
this->m_parent->OnDbgHelpErr("SymGetSearchPath", GetLastError(), 0);
401
}
402
char szUserName[1024] = {0};
403
DWORD dwSize = 1024;
404
GetUserNameA(szUserName, &dwSize);
405
this->m_parent->OnSymInit(buf, symOptions, szUserName);
406
407
return TRUE;
408
}
409
410
StackWalker* m_parent;
411
412
HMODULE m_hDbhHelp;
413
HANDLE m_hProcess;
414
LPSTR m_szSymPath;
415
416
#pragma pack(push, 8)
417
typedef struct IMAGEHLP_MODULE64_V3
418
{
419
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
420
DWORD64 BaseOfImage; // base load address of module
421
DWORD ImageSize; // virtual size of the loaded module
422
DWORD TimeDateStamp; // date/time stamp from pe header
423
DWORD CheckSum; // checksum from the pe header
424
DWORD NumSyms; // number of symbols in the symbol table
425
SYM_TYPE SymType; // type of symbols loaded
426
CHAR ModuleName[32]; // module name
427
CHAR ImageName[256]; // image name
428
CHAR LoadedImageName[256]; // symbol file name
429
// new elements: 07-Jun-2002
430
CHAR LoadedPdbName[256]; // pdb file name
431
DWORD CVSig; // Signature of the CV record in the debug directories
432
CHAR CVData[MAX_PATH * 3]; // Contents of the CV record
433
DWORD PdbSig; // Signature of PDB
434
GUID PdbSig70; // Signature of PDB (VC 7 and up)
435
DWORD PdbAge; // DBI age of pdb
436
BOOL PdbUnmatched; // loaded an unmatched pdb
437
BOOL DbgUnmatched; // loaded an unmatched dbg
438
BOOL LineNumbers; // we have line number information
439
BOOL GlobalSymbols; // we have internal symbol information
440
BOOL TypeInfo; // we have type information
441
// new elements: 17-Dec-2003
442
BOOL SourceIndexed; // pdb supports source server
443
BOOL Publics; // contains public symbols
444
};
445
446
typedef struct IMAGEHLP_MODULE64_V2
447
{
448
DWORD SizeOfStruct; // set to sizeof(IMAGEHLP_MODULE64)
449
DWORD64 BaseOfImage; // base load address of module
450
DWORD ImageSize; // virtual size of the loaded module
451
DWORD TimeDateStamp; // date/time stamp from pe header
452
DWORD CheckSum; // checksum from the pe header
453
DWORD NumSyms; // number of symbols in the symbol table
454
SYM_TYPE SymType; // type of symbols loaded
455
CHAR ModuleName[32]; // module name
456
CHAR ImageName[256]; // image name
457
CHAR LoadedImageName[256]; // symbol file name
458
};
459
#pragma pack(pop)
460
461
// SymCleanup()
462
typedef BOOL(__stdcall* tSC)(IN HANDLE hProcess);
463
tSC pSC;
464
465
// SymFunctionTableAccess64()
466
typedef PVOID(__stdcall* tSFTA)(HANDLE hProcess, DWORD64 AddrBase);
467
tSFTA pSFTA;
468
469
// SymGetLineFromAddr64()
470
typedef BOOL(__stdcall* tSGLFA)(IN HANDLE hProcess,
471
IN DWORD64 dwAddr,
472
OUT PDWORD pdwDisplacement,
473
OUT PIMAGEHLP_LINE64 Line);
474
tSGLFA pSGLFA;
475
476
// SymGetModuleBase64()
477
typedef DWORD64(__stdcall* tSGMB)(IN HANDLE hProcess, IN DWORD64 dwAddr);
478
tSGMB pSGMB;
479
480
// SymGetModuleInfo64()
481
typedef BOOL(__stdcall* tSGMI)(IN HANDLE hProcess,
482
IN DWORD64 dwAddr,
483
OUT IMAGEHLP_MODULE64_V3* ModuleInfo);
484
tSGMI pSGMI;
485
486
// SymGetOptions()
487
typedef DWORD(__stdcall* tSGO)(VOID);
488
tSGO pSGO;
489
490
// SymGetSymFromAddr64()
491
typedef BOOL(__stdcall* tSGSFA)(IN HANDLE hProcess,
492
IN DWORD64 dwAddr,
493
OUT PDWORD64 pdwDisplacement,
494
OUT PIMAGEHLP_SYMBOL64 Symbol);
495
tSGSFA pSGSFA;
496
497
// SymInitialize()
498
typedef BOOL(__stdcall* tSI)(IN HANDLE hProcess, IN PSTR UserSearchPath, IN BOOL fInvadeProcess);
499
tSI pSI;
500
501
// SymLoadModule64()
502
typedef DWORD64(__stdcall* tSLM)(IN HANDLE hProcess,
503
IN HANDLE hFile,
504
IN PSTR ImageName,
505
IN PSTR ModuleName,
506
IN DWORD64 BaseOfDll,
507
IN DWORD SizeOfDll);
508
tSLM pSLM;
509
510
// SymSetOptions()
511
typedef DWORD(__stdcall* tSSO)(IN DWORD SymOptions);
512
tSSO pSSO;
513
514
// StackWalk64()
515
typedef BOOL(__stdcall* tSW)(DWORD MachineType,
516
HANDLE hProcess,
517
HANDLE hThread,
518
LPSTACKFRAME64 StackFrame,
519
PVOID ContextRecord,
520
PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine,
521
PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine,
522
PGET_MODULE_BASE_ROUTINE64 GetModuleBaseRoutine,
523
PTRANSLATE_ADDRESS_ROUTINE64 TranslateAddress);
524
tSW pSW;
525
526
// UnDecorateSymbolName()
527
typedef DWORD(__stdcall WINAPI* tUDSN)(PCSTR DecoratedName,
528
PSTR UnDecoratedName,
529
DWORD UndecoratedLength,
530
DWORD Flags);
531
tUDSN pUDSN;
532
533
typedef BOOL(__stdcall WINAPI* tSGSP)(HANDLE hProcess, PSTR SearchPath, DWORD SearchPathLength);
534
tSGSP pSGSP;
535
536
private:
537
// **************************************** ToolHelp32 ************************
538
#define MAX_MODULE_NAME32 255
539
#define TH32CS_SNAPMODULE 0x00000008
540
#pragma pack(push, 8)
541
typedef struct tagMODULEENTRY32
542
{
543
DWORD dwSize;
544
DWORD th32ModuleID; // This module
545
DWORD th32ProcessID; // owning process
546
DWORD GlblcntUsage; // Global usage count on the module
547
DWORD ProccntUsage; // Module usage count in th32ProcessID's context
548
BYTE* modBaseAddr; // Base address of module in th32ProcessID's context
549
DWORD modBaseSize; // Size in bytes of module starting at modBaseAddr
550
HMODULE hModule; // The hModule of this module in th32ProcessID's context
551
char szModule[MAX_MODULE_NAME32 + 1];
552
char szExePath[MAX_PATH];
553
} MODULEENTRY32;
554
typedef MODULEENTRY32* PMODULEENTRY32;
555
typedef MODULEENTRY32* LPMODULEENTRY32;
556
#pragma pack(pop)
557
558
BOOL GetModuleListTH32(HANDLE hProcess, DWORD pid)
559
{
560
// CreateToolhelp32Snapshot()
561
typedef HANDLE(__stdcall * tCT32S)(DWORD dwFlags, DWORD th32ProcessID);
562
// Module32First()
563
typedef BOOL(__stdcall * tM32F)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
564
// Module32Next()
565
typedef BOOL(__stdcall * tM32N)(HANDLE hSnapshot, LPMODULEENTRY32 lpme);
566
567
// try both dlls...
568
const TCHAR* dllname[] = {_T("kernel32.dll"), _T("tlhelp32.dll")};
569
HINSTANCE hToolhelp = NULL;
570
tCT32S pCT32S = NULL;
571
tM32F pM32F = NULL;
572
tM32N pM32N = NULL;
573
574
HANDLE hSnap;
575
MODULEENTRY32 me;
576
me.dwSize = sizeof(me);
577
BOOL keepGoing;
578
size_t i;
579
580
for (i = 0; i < (sizeof(dllname) / sizeof(dllname[0])); i++)
581
{
582
hToolhelp = LoadLibrary(dllname[i]);
583
if (hToolhelp == NULL)
584
continue;
585
pCT32S = (tCT32S)GetProcAddress(hToolhelp, "CreateToolhelp32Snapshot");
586
pM32F = (tM32F)GetProcAddress(hToolhelp, "Module32First");
587
pM32N = (tM32N)GetProcAddress(hToolhelp, "Module32Next");
588
if ((pCT32S != NULL) && (pM32F != NULL) && (pM32N != NULL))
589
break; // found the functions!
590
FreeLibrary(hToolhelp);
591
hToolhelp = NULL;
592
}
593
594
if (hToolhelp == NULL)
595
return FALSE;
596
597
hSnap = pCT32S(TH32CS_SNAPMODULE, pid);
598
if (hSnap == (HANDLE)-1)
599
{
600
FreeLibrary(hToolhelp);
601
return FALSE;
602
}
603
604
keepGoing = !!pM32F(hSnap, &me);
605
int cnt = 0;
606
while (keepGoing)
607
{
608
this->LoadModule(hProcess, me.szExePath, me.szModule, (DWORD64)me.modBaseAddr,
609
me.modBaseSize);
610
cnt++;
611
keepGoing = !!pM32N(hSnap, &me);
612
}
613
CloseHandle(hSnap);
614
FreeLibrary(hToolhelp);
615
if (cnt <= 0)
616
return FALSE;
617
return TRUE;
618
} // GetModuleListTH32
619
620
// **************************************** PSAPI ************************
621
typedef struct _MODULEINFO
622
{
623
LPVOID lpBaseOfDll;
624
DWORD SizeOfImage;
625
LPVOID EntryPoint;
626
} MODULEINFO, *LPMODULEINFO;
627
628
BOOL GetModuleListPSAPI(HANDLE hProcess)
629
{
630
// EnumProcessModules()
631
typedef BOOL(__stdcall * tEPM)(HANDLE hProcess, HMODULE * lphModule, DWORD cb,
632
LPDWORD lpcbNeeded);
633
// GetModuleFileNameEx()
634
typedef DWORD(__stdcall * tGMFNE)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,
635
DWORD nSize);
636
// GetModuleBaseName()
637
typedef DWORD(__stdcall * tGMBN)(HANDLE hProcess, HMODULE hModule, LPSTR lpFilename,
638
DWORD nSize);
639
// GetModuleInformation()
640
typedef BOOL(__stdcall * tGMI)(HANDLE hProcess, HMODULE hModule, LPMODULEINFO pmi, DWORD nSize);
641
642
HINSTANCE hPsapi;
643
tEPM pEPM;
644
tGMFNE pGMFNE;
645
tGMBN pGMBN;
646
tGMI pGMI;
647
648
DWORD i;
649
//ModuleEntry e;
650
DWORD cbNeeded;
651
MODULEINFO mi;
652
HMODULE* hMods = 0;
653
char* tt = NULL;
654
char* tt2 = NULL;
655
const SIZE_T TTBUFLEN = 8096;
656
int cnt = 0;
657
658
hPsapi = LoadLibrary(_T("psapi.dll"));
659
if (hPsapi == NULL)
660
return FALSE;
661
662
pEPM = (tEPM)GetProcAddress(hPsapi, "EnumProcessModules");
663
pGMFNE = (tGMFNE)GetProcAddress(hPsapi, "GetModuleFileNameExA");
664
pGMBN = (tGMFNE)GetProcAddress(hPsapi, "GetModuleBaseNameA");
665
pGMI = (tGMI)GetProcAddress(hPsapi, "GetModuleInformation");
666
if ((pEPM == NULL) || (pGMFNE == NULL) || (pGMBN == NULL) || (pGMI == NULL))
667
{
668
// we couldn't find all functions
669
FreeLibrary(hPsapi);
670
return FALSE;
671
}
672
673
hMods = (HMODULE*)malloc(sizeof(HMODULE) * (TTBUFLEN / sizeof(HMODULE)));
674
tt = (char*)malloc(sizeof(char) * TTBUFLEN);
675
tt2 = (char*)malloc(sizeof(char) * TTBUFLEN);
676
if ((hMods == NULL) || (tt == NULL) || (tt2 == NULL))
677
goto cleanup;
678
679
if (!pEPM(hProcess, hMods, TTBUFLEN, &cbNeeded))
680
{
681
//_ftprintf(fLogFile, _T("%lu: EPM failed, GetLastError = %lu\n"), g_dwShowCount, gle );
682
goto cleanup;
683
}
684
685
if (cbNeeded > TTBUFLEN)
686
{
687
//_ftprintf(fLogFile, _T("%lu: More than %lu module handles. Huh?\n"), g_dwShowCount, lenof( hMods ) );
688
goto cleanup;
689
}
690
691
for (i = 0; i < cbNeeded / sizeof(hMods[0]); i++)
692
{
693
// base address, size
694
pGMI(hProcess, hMods[i], &mi, sizeof(mi));
695
// image file name
696
tt[0] = 0;
697
pGMFNE(hProcess, hMods[i], tt, TTBUFLEN);
698
// module name
699
tt2[0] = 0;
700
pGMBN(hProcess, hMods[i], tt2, TTBUFLEN);
701
702
DWORD dwRes = this->LoadModule(hProcess, tt, tt2, (DWORD64)mi.lpBaseOfDll, mi.SizeOfImage);
703
if (dwRes != ERROR_SUCCESS)
704
this->m_parent->OnDbgHelpErr("LoadModule", dwRes, 0);
705
cnt++;
706
}
707
708
cleanup:
709
if (hPsapi != NULL)
710
FreeLibrary(hPsapi);
711
if (tt2 != NULL)
712
free(tt2);
713
if (tt != NULL)
714
free(tt);
715
if (hMods != NULL)
716
free(hMods);
717
718
return cnt != 0;
719
} // GetModuleListPSAPI
720
721
DWORD LoadModule(HANDLE hProcess, LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size)
722
{
723
CHAR* szImg = _strdup(img);
724
CHAR* szMod = _strdup(mod);
725
DWORD result = ERROR_SUCCESS;
726
if ((szImg == NULL) || (szMod == NULL))
727
result = ERROR_NOT_ENOUGH_MEMORY;
728
else
729
{
730
if (pSLM(hProcess, 0, szImg, szMod, baseAddr, size) == 0)
731
result = GetLastError();
732
}
733
ULONGLONG fileVersion = 0;
734
if ((m_parent != NULL) && (szImg != NULL))
735
{
736
// try to retrieve the file-version:
737
if ((this->m_parent->m_options & StackWalker::RetrieveFileVersion) != 0)
738
{
739
VS_FIXEDFILEINFO* fInfo = NULL;
740
DWORD dwHandle;
741
DWORD dwSize = GetFileVersionInfoSizeA(szImg, &dwHandle);
742
if (dwSize > 0)
743
{
744
LPVOID vData = malloc(dwSize);
745
if (vData != NULL)
746
{
747
if (GetFileVersionInfoA(szImg, dwHandle, dwSize, vData) != 0)
748
{
749
UINT len;
750
TCHAR szSubBlock[] = _T("\\");
751
if (VerQueryValue(vData, szSubBlock, (LPVOID*)&fInfo, &len) == 0)
752
fInfo = NULL;
753
else
754
{
755
fileVersion =
756
((ULONGLONG)fInfo->dwFileVersionLS) + ((ULONGLONG)fInfo->dwFileVersionMS << 32);
757
}
758
}
759
free(vData);
760
}
761
}
762
}
763
764
// Retrieve some additional-infos about the module
765
IMAGEHLP_MODULE64_V3 Module;
766
const char* szSymType = "-unknown-";
767
if (this->GetModuleInfo(hProcess, baseAddr, &Module) != FALSE)
768
{
769
switch (Module.SymType)
770
{
771
case SymNone:
772
szSymType = "-nosymbols-";
773
break;
774
case SymCoff: // 1
775
szSymType = "COFF";
776
break;
777
case SymCv: // 2
778
szSymType = "CV";
779
break;
780
case SymPdb: // 3
781
szSymType = "PDB";
782
break;
783
case SymExport: // 4
784
szSymType = "-exported-";
785
break;
786
case SymDeferred: // 5
787
szSymType = "-deferred-";
788
break;
789
case SymSym: // 6
790
szSymType = "SYM";
791
break;
792
case 7: // SymDia:
793
szSymType = "DIA";
794
break;
795
case 8: //SymVirtual:
796
szSymType = "Virtual";
797
break;
798
}
799
}
800
LPCSTR pdbName = Module.LoadedImageName;
801
if (Module.LoadedPdbName[0] != 0)
802
pdbName = Module.LoadedPdbName;
803
this->m_parent->OnLoadModule(img, mod, baseAddr, size, result, szSymType, pdbName,
804
fileVersion);
805
}
806
if (szImg != NULL)
807
free(szImg);
808
if (szMod != NULL)
809
free(szMod);
810
return result;
811
}
812
813
public:
814
BOOL LoadModules(HANDLE hProcess, DWORD dwProcessId)
815
{
816
// first try toolhelp32
817
if (GetModuleListTH32(hProcess, dwProcessId))
818
return true;
819
// then try psapi
820
return GetModuleListPSAPI(hProcess);
821
}
822
823
BOOL GetModuleInfo(HANDLE hProcess, DWORD64 baseAddr, IMAGEHLP_MODULE64_V3* pModuleInfo)
824
{
825
memset(pModuleInfo, 0, sizeof(IMAGEHLP_MODULE64_V3));
826
if (this->pSGMI == NULL)
827
{
828
SetLastError(ERROR_DLL_INIT_FAILED);
829
return FALSE;
830
}
831
// First try to use the larger ModuleInfo-Structure
832
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
833
void* pData = malloc(
834
4096); // reserve enough memory, so the bug in v6.3.5.1 does not lead to memory-overwrites...
835
if (pData == NULL)
836
{
837
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
838
return FALSE;
839
}
840
memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V3));
841
static bool s_useV3Version = true;
842
if (s_useV3Version)
843
{
844
if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
845
{
846
// only copy as much memory as is reserved...
847
memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V3));
848
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V3);
849
free(pData);
850
return TRUE;
851
}
852
s_useV3Version = false; // to prevent unnecessary calls with the larger struct...
853
}
854
855
// could not retrieve the bigger structure, try with the smaller one (as defined in VC7.1)...
856
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
857
memcpy(pData, pModuleInfo, sizeof(IMAGEHLP_MODULE64_V2));
858
if (this->pSGMI(hProcess, baseAddr, (IMAGEHLP_MODULE64_V3*)pData) != FALSE)
859
{
860
// only copy as much memory as is reserved...
861
memcpy(pModuleInfo, pData, sizeof(IMAGEHLP_MODULE64_V2));
862
pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64_V2);
863
free(pData);
864
return TRUE;
865
}
866
free(pData);
867
SetLastError(ERROR_DLL_INIT_FAILED);
868
return FALSE;
869
}
870
};
871
872
// #############################################################
873
StackWalker::StackWalker(DWORD dwProcessId, HANDLE hProcess)
874
{
875
this->m_options = OptionsAll;
876
this->m_modulesLoaded = FALSE;
877
this->m_hProcess = hProcess;
878
this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
879
this->m_dwProcessId = dwProcessId;
880
this->m_szSymPath = NULL;
881
this->m_MaxRecursionCount = 1000;
882
}
883
StackWalker::StackWalker(int options, LPCSTR szSymPath, DWORD dwProcessId, HANDLE hProcess)
884
{
885
this->m_options = options;
886
this->m_modulesLoaded = FALSE;
887
this->m_hProcess = hProcess;
888
this->m_sw = new StackWalkerInternal(this, this->m_hProcess);
889
this->m_dwProcessId = dwProcessId;
890
if (szSymPath != NULL)
891
{
892
this->m_szSymPath = _strdup(szSymPath);
893
this->m_options |= SymBuildPath;
894
}
895
else
896
this->m_szSymPath = NULL;
897
this->m_MaxRecursionCount = 1000;
898
}
899
900
StackWalker::~StackWalker()
901
{
902
if (m_szSymPath != NULL)
903
free(m_szSymPath);
904
m_szSymPath = NULL;
905
if (this->m_sw != NULL)
906
delete this->m_sw;
907
this->m_sw = NULL;
908
}
909
910
BOOL StackWalker::LoadModules()
911
{
912
if (this->m_sw == NULL)
913
{
914
SetLastError(ERROR_DLL_INIT_FAILED);
915
return FALSE;
916
}
917
if (m_modulesLoaded != FALSE)
918
return TRUE;
919
920
// Build the sym-path:
921
char* szSymPath = NULL;
922
if ((this->m_options & SymBuildPath) != 0)
923
{
924
const size_t nSymPathLen = 4096;
925
szSymPath = (char*)malloc(nSymPathLen);
926
if (szSymPath == NULL)
927
{
928
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
929
return FALSE;
930
}
931
szSymPath[0] = 0;
932
// Now first add the (optional) provided sympath:
933
if (this->m_szSymPath != NULL)
934
{
935
strcat_s(szSymPath, nSymPathLen, this->m_szSymPath);
936
strcat_s(szSymPath, nSymPathLen, ";");
937
}
938
939
strcat_s(szSymPath, nSymPathLen, ".;");
940
941
const size_t nTempLen = 1024;
942
char szTemp[nTempLen];
943
// Now add the current directory:
944
if (GetCurrentDirectoryA(nTempLen, szTemp) > 0)
945
{
946
szTemp[nTempLen - 1] = 0;
947
strcat_s(szSymPath, nSymPathLen, szTemp);
948
strcat_s(szSymPath, nSymPathLen, ";");
949
}
950
951
// Now add the path for the main-module:
952
if (GetModuleFileNameA(NULL, szTemp, nTempLen) > 0)
953
{
954
szTemp[nTempLen - 1] = 0;
955
for (char* p = (szTemp + strlen(szTemp) - 1); p >= szTemp; --p)
956
{
957
// locate the rightmost path separator
958
if ((*p == '\\') || (*p == '/') || (*p == ':'))
959
{
960
*p = 0;
961
break;
962
}
963
} // for (search for path separator...)
964
if (strlen(szTemp) > 0)
965
{
966
strcat_s(szSymPath, nSymPathLen, szTemp);
967
strcat_s(szSymPath, nSymPathLen, ";");
968
}
969
}
970
if (GetEnvironmentVariableA("_NT_SYMBOL_PATH", szTemp, nTempLen) > 0)
971
{
972
szTemp[nTempLen - 1] = 0;
973
strcat_s(szSymPath, nSymPathLen, szTemp);
974
strcat_s(szSymPath, nSymPathLen, ";");
975
}
976
if (GetEnvironmentVariableA("_NT_ALTERNATE_SYMBOL_PATH", szTemp, nTempLen) > 0)
977
{
978
szTemp[nTempLen - 1] = 0;
979
strcat_s(szSymPath, nSymPathLen, szTemp);
980
strcat_s(szSymPath, nSymPathLen, ";");
981
}
982
if (GetEnvironmentVariableA("SYSTEMROOT", szTemp, nTempLen) > 0)
983
{
984
szTemp[nTempLen - 1] = 0;
985
strcat_s(szSymPath, nSymPathLen, szTemp);
986
strcat_s(szSymPath, nSymPathLen, ";");
987
// also add the "system32"-directory:
988
strcat_s(szTemp, nTempLen, "\\system32");
989
strcat_s(szSymPath, nSymPathLen, szTemp);
990
strcat_s(szSymPath, nSymPathLen, ";");
991
}
992
993
if ((this->m_options & SymUseSymSrv) != 0)
994
{
995
if (GetEnvironmentVariableA("SYSTEMDRIVE", szTemp, nTempLen) > 0)
996
{
997
szTemp[nTempLen - 1] = 0;
998
strcat_s(szSymPath, nSymPathLen, "SRV*");
999
strcat_s(szSymPath, nSymPathLen, szTemp);
1000
strcat_s(szSymPath, nSymPathLen, "\\websymbols");
1001
strcat_s(szSymPath, nSymPathLen, "*http://msdl.microsoft.com/download/symbols;");
1002
}
1003
else
1004
strcat_s(szSymPath, nSymPathLen,
1005
"SRV*c:\\websymbols*http://msdl.microsoft.com/download/symbols;");
1006
}
1007
} // if SymBuildPath
1008
1009
// First Init the whole stuff...
1010
BOOL bRet = this->m_sw->Init(szSymPath);
1011
if (szSymPath != NULL)
1012
free(szSymPath);
1013
szSymPath = NULL;
1014
if (bRet == FALSE)
1015
{
1016
this->OnDbgHelpErr("Error while initializing dbghelp.dll", 0, 0);
1017
SetLastError(ERROR_DLL_INIT_FAILED);
1018
return FALSE;
1019
}
1020
1021
bRet = this->m_sw->LoadModules(this->m_hProcess, this->m_dwProcessId);
1022
if (bRet != FALSE)
1023
m_modulesLoaded = TRUE;
1024
return bRet;
1025
}
1026
1027
// The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction
1028
// This has to be done due to a problem with the "hProcess"-parameter in x64...
1029
// Because this class is in no case multi-threading-enabled (because of the limitations
1030
// of dbghelp.dll) it is "safe" to use a static-variable
1031
static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL;
1032
static LPVOID s_readMemoryFunction_UserData = NULL;
1033
1034
BOOL StackWalker::ShowCallstack(HANDLE hThread,
1035
const CONTEXT* context,
1036
PReadProcessMemoryRoutine readMemoryFunction,
1037
LPVOID pUserData)
1038
{
1039
CONTEXT c;
1040
CallstackEntry csEntry;
1041
IMAGEHLP_SYMBOL64* pSym = NULL;
1042
StackWalkerInternal::IMAGEHLP_MODULE64_V3 Module;
1043
IMAGEHLP_LINE64 Line;
1044
int frameNum;
1045
bool bLastEntryCalled = true;
1046
int curRecursionCount = 0;
1047
1048
if (m_modulesLoaded == FALSE)
1049
this->LoadModules(); // ignore the result...
1050
1051
if (this->m_sw->m_hDbhHelp == NULL)
1052
{
1053
SetLastError(ERROR_DLL_INIT_FAILED);
1054
return FALSE;
1055
}
1056
1057
s_readMemoryFunction = readMemoryFunction;
1058
s_readMemoryFunction_UserData = pUserData;
1059
1060
if (context == NULL)
1061
{
1062
// If no context is provided, capture the context
1063
// See: https://stackwalker.codeplex.com/discussions/446958
1064
#if _WIN32_WINNT <= 0x0501
1065
// If we need to support XP, we need to use the "old way", because "GetThreadId" is not available!
1066
if (hThread == GetCurrentThread())
1067
#else
1068
if (GetThreadId(hThread) == GetCurrentThreadId())
1069
#endif
1070
{
1071
GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, USED_CONTEXT_FLAGS);
1072
}
1073
else
1074
{
1075
SuspendThread(hThread);
1076
memset(&c, 0, sizeof(CONTEXT));
1077
c.ContextFlags = USED_CONTEXT_FLAGS;
1078
1079
// TODO: Detect if you want to get a thread context of a different process, which is running a different processor architecture...
1080
// This does only work if we are x64 and the target process is x64 or x86;
1081
// It cannot work, if this process is x64 and the target process is x64... this is not supported...
1082
// See also: http://www.howzatt.demon.co.uk/articles/DebuggingInWin64.html
1083
if (GetThreadContext(hThread, &c) == FALSE)
1084
{
1085
ResumeThread(hThread);
1086
return FALSE;
1087
}
1088
}
1089
}
1090
else
1091
c = *context;
1092
1093
// init STACKFRAME for first call
1094
STACKFRAME64 s; // in/out stackframe
1095
memset(&s, 0, sizeof(s));
1096
DWORD imageType;
1097
#ifdef _M_IX86
1098
// normally, call ImageNtHeader() and use machine info from PE header
1099
imageType = IMAGE_FILE_MACHINE_I386;
1100
s.AddrPC.Offset = c.Eip;
1101
s.AddrPC.Mode = AddrModeFlat;
1102
s.AddrFrame.Offset = c.Ebp;
1103
s.AddrFrame.Mode = AddrModeFlat;
1104
s.AddrStack.Offset = c.Esp;
1105
s.AddrStack.Mode = AddrModeFlat;
1106
#elif _M_X64
1107
imageType = IMAGE_FILE_MACHINE_AMD64;
1108
s.AddrPC.Offset = c.Rip;
1109
s.AddrPC.Mode = AddrModeFlat;
1110
s.AddrFrame.Offset = c.Rsp;
1111
s.AddrFrame.Mode = AddrModeFlat;
1112
s.AddrStack.Offset = c.Rsp;
1113
s.AddrStack.Mode = AddrModeFlat;
1114
#elif _M_IA64
1115
imageType = IMAGE_FILE_MACHINE_IA64;
1116
s.AddrPC.Offset = c.StIIP;
1117
s.AddrPC.Mode = AddrModeFlat;
1118
s.AddrFrame.Offset = c.IntSp;
1119
s.AddrFrame.Mode = AddrModeFlat;
1120
s.AddrBStore.Offset = c.RsBSP;
1121
s.AddrBStore.Mode = AddrModeFlat;
1122
s.AddrStack.Offset = c.IntSp;
1123
s.AddrStack.Mode = AddrModeFlat;
1124
#elif _M_ARM64
1125
imageType = IMAGE_FILE_MACHINE_ARM64;
1126
s.AddrPC.Offset = c.Pc;
1127
s.AddrPC.Mode = AddrModeFlat;
1128
s.AddrFrame.Offset = c.Fp;
1129
s.AddrFrame.Mode = AddrModeFlat;
1130
s.AddrStack.Offset = c.Sp;
1131
s.AddrStack.Mode = AddrModeFlat;
1132
#else
1133
#error "Platform not supported!"
1134
#endif
1135
1136
pSym = (IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
1137
if (!pSym)
1138
goto cleanup; // not enough memory...
1139
memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
1140
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
1141
pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
1142
1143
memset(&Line, 0, sizeof(Line));
1144
Line.SizeOfStruct = sizeof(Line);
1145
1146
memset(&Module, 0, sizeof(Module));
1147
Module.SizeOfStruct = sizeof(Module);
1148
1149
for (frameNum = 0;; ++frameNum)
1150
{
1151
// get next stack frame (StackWalk64(), SymFunctionTableAccess64(), SymGetModuleBase64())
1152
// if this returns ERROR_INVALID_ADDRESS (487) or ERROR_NOACCESS (998), you can
1153
// assume that either you are done, or that the stack is so hosed that the next
1154
// deeper frame could not be found.
1155
// CONTEXT need not to be supplied if imageTyp is IMAGE_FILE_MACHINE_I386!
1156
if (!this->m_sw->pSW(imageType, this->m_hProcess, hThread, &s, &c, myReadProcMem,
1157
this->m_sw->pSFTA, this->m_sw->pSGMB, NULL))
1158
{
1159
// INFO: "StackWalk64" does not set "GetLastError"...
1160
this->OnDbgHelpErr("StackWalk64", 0, s.AddrPC.Offset);
1161
break;
1162
}
1163
1164
csEntry.offset = s.AddrPC.Offset;
1165
csEntry.name[0] = 0;
1166
csEntry.undName[0] = 0;
1167
csEntry.undFullName[0] = 0;
1168
csEntry.offsetFromSmybol = 0;
1169
csEntry.offsetFromLine = 0;
1170
csEntry.lineFileName[0] = 0;
1171
csEntry.lineNumber = 0;
1172
csEntry.loadedImageName[0] = 0;
1173
csEntry.moduleName[0] = 0;
1174
if (s.AddrPC.Offset == s.AddrReturn.Offset)
1175
{
1176
if ((this->m_MaxRecursionCount > 0) && (curRecursionCount > m_MaxRecursionCount))
1177
{
1178
this->OnDbgHelpErr("StackWalk64-Endless-Callstack!", 0, s.AddrPC.Offset);
1179
break;
1180
}
1181
curRecursionCount++;
1182
}
1183
else
1184
curRecursionCount = 0;
1185
if (s.AddrPC.Offset != 0)
1186
{
1187
// we seem to have a valid PC
1188
// show procedure info (SymGetSymFromAddr64())
1189
if (this->m_sw->pSGSFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromSmybol),
1190
pSym) != FALSE)
1191
{
1192
MyStrCpy(csEntry.name, STACKWALK_MAX_NAMELEN, pSym->Name);
1193
// UnDecorateSymbolName()
1194
this->m_sw->pUDSN(pSym->Name, csEntry.undName, STACKWALK_MAX_NAMELEN, UNDNAME_NAME_ONLY);
1195
this->m_sw->pUDSN(pSym->Name, csEntry.undFullName, STACKWALK_MAX_NAMELEN, UNDNAME_COMPLETE);
1196
}
1197
else
1198
{
1199
this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), s.AddrPC.Offset);
1200
}
1201
1202
// show line number info, NT5.0-method (SymGetLineFromAddr64())
1203
if (this->m_sw->pSGLFA != NULL)
1204
{ // yes, we have SymGetLineFromAddr64()
1205
if (this->m_sw->pSGLFA(this->m_hProcess, s.AddrPC.Offset, &(csEntry.offsetFromLine),
1206
&Line) != FALSE)
1207
{
1208
csEntry.lineNumber = Line.LineNumber;
1209
MyStrCpy(csEntry.lineFileName, STACKWALK_MAX_NAMELEN, Line.FileName);
1210
}
1211
else
1212
{
1213
this->OnDbgHelpErr("SymGetLineFromAddr64", GetLastError(), s.AddrPC.Offset);
1214
}
1215
} // yes, we have SymGetLineFromAddr64()
1216
1217
// show module info (SymGetModuleInfo64())
1218
if (this->m_sw->GetModuleInfo(this->m_hProcess, s.AddrPC.Offset, &Module) != FALSE)
1219
{ // got module info OK
1220
switch (Module.SymType)
1221
{
1222
case SymNone:
1223
csEntry.symTypeString = "-nosymbols-";
1224
break;
1225
case SymCoff:
1226
csEntry.symTypeString = "COFF";
1227
break;
1228
case SymCv:
1229
csEntry.symTypeString = "CV";
1230
break;
1231
case SymPdb:
1232
csEntry.symTypeString = "PDB";
1233
break;
1234
case SymExport:
1235
csEntry.symTypeString = "-exported-";
1236
break;
1237
case SymDeferred:
1238
csEntry.symTypeString = "-deferred-";
1239
break;
1240
case SymSym:
1241
csEntry.symTypeString = "SYM";
1242
break;
1243
#if API_VERSION_NUMBER >= 9
1244
case SymDia:
1245
csEntry.symTypeString = "DIA";
1246
break;
1247
#endif
1248
case 8: //SymVirtual:
1249
csEntry.symTypeString = "Virtual";
1250
break;
1251
default:
1252
//_snprintf( ty, sizeof(ty), "symtype=%ld", (long) Module.SymType );
1253
csEntry.symTypeString = NULL;
1254
break;
1255
}
1256
1257
MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName);
1258
csEntry.baseOfImage = Module.BaseOfImage;
1259
MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName);
1260
} // got module info OK
1261
else
1262
{
1263
this->OnDbgHelpErr("SymGetModuleInfo64", GetLastError(), s.AddrPC.Offset);
1264
}
1265
} // we seem to have a valid PC
1266
1267
CallstackEntryType et = nextEntry;
1268
if (frameNum == 0)
1269
et = firstEntry;
1270
bLastEntryCalled = false;
1271
this->OnCallstackEntry(et, csEntry);
1272
1273
if (s.AddrReturn.Offset == 0)
1274
{
1275
bLastEntryCalled = true;
1276
this->OnCallstackEntry(lastEntry, csEntry);
1277
SetLastError(ERROR_SUCCESS);
1278
break;
1279
}
1280
} // for ( frameNum )
1281
1282
cleanup:
1283
if (pSym)
1284
free(pSym);
1285
1286
if (bLastEntryCalled == false)
1287
this->OnCallstackEntry(lastEntry, csEntry);
1288
1289
if (context == NULL)
1290
ResumeThread(hThread);
1291
1292
return TRUE;
1293
}
1294
1295
BOOL StackWalker::ShowObject(LPVOID pObject)
1296
{
1297
// Load modules if not done yet
1298
if (m_modulesLoaded == FALSE)
1299
this->LoadModules(); // ignore the result...
1300
1301
// Verify that the DebugHelp.dll was actually found
1302
if (this->m_sw->m_hDbhHelp == NULL)
1303
{
1304
SetLastError(ERROR_DLL_INIT_FAILED);
1305
return FALSE;
1306
}
1307
1308
// SymGetSymFromAddr64() is required
1309
if (this->m_sw->pSGSFA == NULL)
1310
return FALSE;
1311
1312
// Show object info (SymGetSymFromAddr64())
1313
DWORD64 dwAddress = DWORD64(pObject);
1314
DWORD64 dwDisplacement = 0;
1315
IMAGEHLP_SYMBOL64* pSym =
1316
(IMAGEHLP_SYMBOL64*)malloc(sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
1317
memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STACKWALK_MAX_NAMELEN);
1318
pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
1319
pSym->MaxNameLength = STACKWALK_MAX_NAMELEN;
1320
if (this->m_sw->pSGSFA(this->m_hProcess, dwAddress, &dwDisplacement, pSym) == FALSE)
1321
{
1322
this->OnDbgHelpErr("SymGetSymFromAddr64", GetLastError(), dwAddress);
1323
return FALSE;
1324
}
1325
// Object name output
1326
this->OnOutput(pSym->Name);
1327
1328
free(pSym);
1329
return TRUE;
1330
};
1331
1332
BOOL __stdcall StackWalker::myReadProcMem(HANDLE hProcess,
1333
DWORD64 qwBaseAddress,
1334
PVOID lpBuffer,
1335
DWORD nSize,
1336
LPDWORD lpNumberOfBytesRead)
1337
{
1338
if (s_readMemoryFunction == NULL)
1339
{
1340
SIZE_T st;
1341
BOOL bRet = ReadProcessMemory(hProcess, (LPVOID)qwBaseAddress, lpBuffer, nSize, &st);
1342
*lpNumberOfBytesRead = (DWORD)st;
1343
//printf("ReadMemory: hProcess: %p, baseAddr: %p, buffer: %p, size: %d, read: %d, result: %d\n", hProcess, (LPVOID) qwBaseAddress, lpBuffer, nSize, (DWORD) st, (DWORD) bRet);
1344
return bRet;
1345
}
1346
else
1347
{
1348
return s_readMemoryFunction(hProcess, qwBaseAddress, lpBuffer, nSize, lpNumberOfBytesRead,
1349
s_readMemoryFunction_UserData);
1350
}
1351
}
1352
1353
void StackWalker::OnLoadModule(LPCSTR img,
1354
LPCSTR mod,
1355
DWORD64 baseAddr,
1356
DWORD size,
1357
DWORD result,
1358
LPCSTR symType,
1359
LPCSTR pdbName,
1360
ULONGLONG fileVersion)
1361
{
1362
CHAR buffer[STACKWALK_MAX_NAMELEN];
1363
size_t maxLen = STACKWALK_MAX_NAMELEN;
1364
#if _MSC_VER >= 1400
1365
maxLen = _TRUNCATE;
1366
#endif
1367
if (fileVersion == 0)
1368
_snprintf_s(buffer, maxLen, "%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s'\n",
1369
img, mod, (LPVOID)baseAddr, size, result, symType, pdbName);
1370
else
1371
{
1372
DWORD v4 = (DWORD)(fileVersion & 0xFFFF);
1373
DWORD v3 = (DWORD)((fileVersion >> 16) & 0xFFFF);
1374
DWORD v2 = (DWORD)((fileVersion >> 32) & 0xFFFF);
1375
DWORD v1 = (DWORD)((fileVersion >> 48) & 0xFFFF);
1376
_snprintf_s(
1377
buffer, maxLen,
1378
"%s:%s (%p), size: %d (result: %d), SymType: '%s', PDB: '%s', fileVersion: %d.%d.%d.%d\n",
1379
img, mod, (LPVOID)baseAddr, size, result, symType, pdbName, v1, v2, v3, v4);
1380
}
1381
buffer[STACKWALK_MAX_NAMELEN - 1] = 0; // be sure it is NULL terminated
1382
OnOutput(buffer);
1383
}
1384
1385
void StackWalker::OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry)
1386
{
1387
CHAR buffer[STACKWALK_MAX_NAMELEN];
1388
size_t maxLen = STACKWALK_MAX_NAMELEN;
1389
#if _MSC_VER >= 1400
1390
maxLen = _TRUNCATE;
1391
#endif
1392
if ((eType != lastEntry) && (entry.offset != 0))
1393
{
1394
if (entry.name[0] == 0)
1395
MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, "(function-name not available)");
1396
if (entry.undName[0] != 0)
1397
MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undName);
1398
if (entry.undFullName[0] != 0)
1399
MyStrCpy(entry.name, STACKWALK_MAX_NAMELEN, entry.undFullName);
1400
if (entry.lineFileName[0] == 0)
1401
{
1402
MyStrCpy(entry.lineFileName, STACKWALK_MAX_NAMELEN, "(filename not available)");
1403
if (entry.moduleName[0] == 0)
1404
MyStrCpy(entry.moduleName, STACKWALK_MAX_NAMELEN, "(module-name not available)");
1405
_snprintf_s(buffer, maxLen, "%p (%s): %s: %s\n", (LPVOID)entry.offset, entry.moduleName,
1406
entry.lineFileName, entry.name);
1407
}
1408
else
1409
_snprintf_s(buffer, maxLen, "%s (%d): %s\n", entry.lineFileName, entry.lineNumber,
1410
entry.name);
1411
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
1412
OnOutput(buffer);
1413
}
1414
}
1415
1416
void StackWalker::OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
1417
{
1418
CHAR buffer[STACKWALK_MAX_NAMELEN];
1419
size_t maxLen = STACKWALK_MAX_NAMELEN;
1420
#if _MSC_VER >= 1400
1421
maxLen = _TRUNCATE;
1422
#endif
1423
_snprintf_s(buffer, maxLen, "ERROR: %s, GetLastError: %d (Address: %p)\n", szFuncName, gle,
1424
(LPVOID)addr);
1425
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
1426
OnOutput(buffer);
1427
}
1428
1429
void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
1430
{
1431
CHAR buffer[STACKWALK_MAX_NAMELEN];
1432
size_t maxLen = STACKWALK_MAX_NAMELEN;
1433
#if _MSC_VER >= 1400
1434
maxLen = _TRUNCATE;
1435
#endif
1436
_snprintf_s(buffer, maxLen, "SymInit: Symbol-SearchPath: '%s', symOptions: %d, UserName: '%s'\n",
1437
szSearchPath, symOptions, szUserName);
1438
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
1439
OnOutput(buffer);
1440
// Also display the OS-version
1441
#if _MSC_VER <= 1200
1442
OSVERSIONINFOA ver;
1443
ZeroMemory(&ver, sizeof(OSVERSIONINFOA));
1444
ver.dwOSVersionInfoSize = sizeof(ver);
1445
if (GetVersionExA(&ver) != FALSE)
1446
{
1447
_snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion,
1448
ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion);
1449
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
1450
OnOutput(buffer);
1451
}
1452
#else
1453
OSVERSIONINFOEXA ver;
1454
ZeroMemory(&ver, sizeof(OSVERSIONINFOEXA));
1455
ver.dwOSVersionInfoSize = sizeof(ver);
1456
#if _MSC_VER >= 1900
1457
#pragma warning(push)
1458
#pragma warning(disable : 4996)
1459
#endif
1460
if (GetVersionExA((OSVERSIONINFOA*)&ver) != FALSE)
1461
{
1462
_snprintf_s(buffer, maxLen, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion,
1463
ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask,
1464
ver.wProductType);
1465
buffer[STACKWALK_MAX_NAMELEN - 1] = 0;
1466
OnOutput(buffer);
1467
}
1468
#if _MSC_VER >= 1900
1469
#pragma warning(pop)
1470
#endif
1471
#endif
1472
}
1473
1474
void StackWalker::OnOutput(LPCSTR buffer)
1475
{
1476
OutputDebugStringA(buffer);
1477
}
1478
1479