Skyscraper 2.0
stackwalker.h
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * StackWalker.h
4 *
5 *
6 *
7 * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
8 *
9 * Copyright (c) 2005-2009, Jochen Kalmbach
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without modification,
13 * are permitted provided that the following conditions are met:
14 *
15 * Redistributions of source code must retain the above copyright notice,
16 * this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright notice,
18 * this list of conditions and the following disclaimer in the documentation
19 * and/or other materials provided with the distribution.
20 * Neither the name of Jochen Kalmbach nor the names of its contributors may be
21 * used to endorse or promote products derived from this software without
22 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
25 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 * **********************************************************************/
35// #pragma once is supported starting with _MCS_VER 1000,
36// so we need not to check the version (because we only support _MSC_VER >= 1100)!
37#pragma once
38
39#include <windows.h>
40
41// special defines for VC5/6 (if no actual PSDK is installed):
42#if _MSC_VER < 1300
43typedef unsigned __int64 DWORD64, *PDWORD64;
44#if defined(_WIN64)
45typedef unsigned __int64 SIZE_T, *PSIZE_T;
46#else
47typedef unsigned long SIZE_T, *PSIZE_T;
48#endif
49#endif // _MSC_VER < 1300
50
51class StackWalkerInternal; // forward
53{
54public:
55 typedef enum StackWalkOptions
56 {
57 // No addition info will be retrived
58 // (only the address is available)
60
61 // Try to get the symbol-name
63
64 // Try to get the line for this symbol
66
67 // Try to retrieve the module-infos
69
70 // Also retrieve the version for the DLL/EXE
72
73 // Contains all the abouve
75
76 // Generate a "good" symbol-search-path
78
79 // Also use the public Microsoft-Symbol-Server
81
82 // Contains all the abouve "Sym"-options
83 SymAll = 0x30,
84
85 // Contains all options (default)
86 OptionsAll = 0x3F
88
90 //int options = OptionsAll, // 'int' is by design, to combine the enum-flags
91 int options = RetrieveNone, // 'int' is by design, to combine the enum-flags
92 LPCSTR szSymPath = NULL,
93 DWORD dwProcessId = GetCurrentProcessId(),
94 HANDLE hProcess = GetCurrentProcess()
95 );
96 StackWalker(DWORD dwProcessId, HANDLE hProcess);
97 virtual ~StackWalker();
98
99 typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
100 HANDLE hProcess,
101 DWORD64 qwBaseAddress,
102 PVOID lpBuffer,
103 DWORD nSize,
104 LPDWORD lpNumberOfBytesRead,
105 LPVOID pUserData // optional data, which was passed in "ShowCallstack"
106 );
107
109
111 HANDLE hThread = GetCurrentThread(),
112 const CONTEXT *context = NULL,
113 PReadProcessMemoryRoutine readMemoryFunction = NULL,
114 LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
115 );
116
117#if _MSC_VER >= 1300
118// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
119// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
120protected:
121#endif
122 enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
123
124protected:
125 // Entry for each Callstack-Entry
142
144
145 virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
146 virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
148 virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
149 virtual void OnOutput(LPCSTR szText);
150
156
159
160 static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
161
163}; // class StackWalker
164
165
166// The "ugly" assembler-implementation is needed for systems before XP
167// If you have a new PSDK and you only compile for XP and later, then you can use
168// the "RtlCaptureContext"
169// Currently there is no define which determines the PSDK-Version...
170// So we just use the compiler-version (and assumes that the PSDK is
171// the one which was installed by the VS-IDE)
172
173// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
174// But I currently use it in x64/IA64 environments...
175//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
176
177#if defined(_M_IX86)
178#ifdef CURRENT_THREAD_VIA_EXCEPTION
179// TODO: The following is not a "good" implementation,
180// because the callstack is only valid in the "__except" block...
181#define GET_CURRENT_CONTEXT(c, contextFlags) \
182 do { \
183 memset(&c, 0, sizeof(CONTEXT)); \
184 EXCEPTION_POINTERS *pExp = NULL; \
185 __try { \
186 throw 0; \
187 } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
188 if (pExp != NULL) \
189 memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
190 c.ContextFlags = contextFlags; \
191 } while(0);
192#else
193// The following should be enough for walking the callstack...
194#define GET_CURRENT_CONTEXT(c, contextFlags) \
195 do { \
196 memset(&c, 0, sizeof(CONTEXT)); \
197 c.ContextFlags = contextFlags; \
198 __asm call x \
199 __asm x: pop eax \
200 __asm mov c.Eip, eax \
201 __asm mov c.Ebp, ebp \
202 __asm mov c.Esp, esp \
203 } while(0);
204#endif
205
206#else
207
208// The following is defined for x86 (XP and higher), x64 and IA64:
209#define GET_CURRENT_CONTEXT(c, contextFlags) \
210 do { \
211 memset(&c, 0, sizeof(CONTEXT)); \
212 c.ContextFlags = contextFlags; \
213 RtlCaptureContext(&c); \
214} while(0);
215#endif
StackWalker(int options=RetrieveNone, LPCSTR szSymPath=NULL, DWORD dwProcessId=GetCurrentProcessId(), HANDLE hProcess=GetCurrentProcess())
StackWalkerInternal * m_sw
@ STACKWALK_MAX_NAMELEN
virtual ~StackWalker()
BOOL m_modulesLoaded
BOOL ShowCallstack(HANDLE hThread=GetCurrentThread(), const CONTEXT *context=NULL, PReadProcessMemoryRoutine readMemoryFunction=NULL, LPVOID pUserData=NULL)
BOOL LoadModules()
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
struct StackWalker::CallstackEntry CallstackEntry
HANDLE m_hProcess
static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead)
virtual void OnOutput(LPCSTR szText)
@ RetrieveFileVersion
Definition stackwalker.h:71
friend StackWalkerInternal
BOOL(__stdcall * PReadProcessMemoryRoutine)(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead, LPVOID pUserData)
Definition stackwalker.h:99
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
int m_MaxRecursionCount
DWORD m_dwProcessId
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
StackWalker(DWORD dwProcessId, HANDLE hProcess)
virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
LPSTR m_szSymPath
unsigned long * PSIZE_T
Definition stackwalker.h:47
unsigned __int64 DWORD64
Definition stackwalker.h:43
unsigned long SIZE_T
Definition stackwalker.h:47
unsigned __int64 * PDWORD64
Definition stackwalker.h:43
CHAR undName[STACKWALK_MAX_NAMELEN]
CHAR loadedImageName[STACKWALK_MAX_NAMELEN]
CHAR lineFileName[STACKWALK_MAX_NAMELEN]
CHAR name[STACKWALK_MAX_NAMELEN]
CHAR moduleName[STACKWALK_MAX_NAMELEN]
CHAR undFullName[STACKWALK_MAX_NAMELEN]