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