1
#ifndef __STACKWALKER_H__
2
#define __STACKWALKER_H__
6
/**********************************************************************
12
* LICENSE (http://www.opensource.org/licenses/bsd-license.php)
14
* Copyright (c) 2005-2009, Jochen Kalmbach
15
* All rights reserved.
17
* Redistribution and use in source and binary forms, with or without modification,
18
* are permitted provided that the following conditions are met:
20
* Redistributions of source code must retain the above copyright notice,
21
* this list of conditions and the following disclaimer.
22
* Redistributions in binary form must reproduce the above copyright notice,
23
* this list of conditions and the following disclaimer in the documentation
24
* and/or other materials provided with the distribution.
25
* Neither the name of Jochen Kalmbach nor the names of its contributors may be
26
* used to endorse or promote products derived from this software without
27
* specific prior written permission.
28
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
29
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
30
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
32
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
33
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
34
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
36
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
37
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39
* **********************************************************************/
40
// #pragma once is supported starting with _MSC_VER 1000,
41
// so we need not to check the version (because we only support _MSC_VER >= 1100)!
47
#pragma warning(disable : 4091)
50
// special defines for VC5/6 (if no actual PSDK is installed):
52
typedef unsigned __int64 DWORD64, *PDWORD64;
54
typedef unsigned __int64 SIZE_T, *PSIZE_T;
56
typedef unsigned long SIZE_T, *PSIZE_T;
58
#endif // _MSC_VER < 1300
60
class StackWalkerInternal; // forward
64
typedef enum StackWalkOptions
66
// No addition info will be retrieved
67
// (only the address is available)
70
// Try to get the symbol-name
73
// Try to get the line for this symbol
76
// Try to retrieve the module-infos
77
RetrieveModuleInfo = 4,
79
// Also retrieve the version for the DLL/EXE
80
RetrieveFileVersion = 8,
82
// Contains all the above
83
RetrieveVerbose = 0xF,
85
// Generate a "good" symbol-search-path
88
// Also use the public Microsoft-Symbol-Server
91
// Contains all the above "Sym"-options
94
// Contains all options (default)
98
StackWalker(int options = OptionsAll, // 'int' is by design, to combine the enum-flags
99
LPCSTR szSymPath = NULL,
100
DWORD dwProcessId = GetCurrentProcessId(),
101
HANDLE hProcess = GetCurrentProcess());
102
StackWalker(DWORD dwProcessId, HANDLE hProcess);
103
virtual ~StackWalker();
105
typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
107
DWORD64 qwBaseAddress,
110
LPDWORD lpNumberOfBytesRead,
111
LPVOID pUserData // optional data, which was passed in "ShowCallstack"
117
HANDLE hThread = GetCurrentThread(),
118
const CONTEXT* context = NULL,
119
PReadProcessMemoryRoutine readMemoryFunction = NULL,
120
LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
123
BOOL ShowObject(LPVOID pObject);
126
// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
127
// in older compilers in order to use it... starting with VC7 we can declare it as "protected"
132
STACKWALK_MAX_NAMELEN = 1024
133
}; // max name length for found symbols
136
// Entry for each Callstack-Entry
137
typedef struct CallstackEntry
139
DWORD64 offset; // if 0, we have no valid entry
140
CHAR name[STACKWALK_MAX_NAMELEN];
141
CHAR undName[STACKWALK_MAX_NAMELEN];
142
CHAR undFullName[STACKWALK_MAX_NAMELEN];
143
DWORD64 offsetFromSmybol;
144
DWORD offsetFromLine;
146
CHAR lineFileName[STACKWALK_MAX_NAMELEN];
148
LPCSTR symTypeString;
149
CHAR moduleName[STACKWALK_MAX_NAMELEN];
151
CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
154
typedef enum CallstackEntryType
159
} CallstackEntryType;
161
virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
162
virtual void OnLoadModule(LPCSTR img,
169
ULONGLONG fileVersion);
170
virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry& entry);
171
virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
172
virtual void OnOutput(LPCSTR szText);
174
StackWalkerInternal* m_sw;
177
BOOL m_modulesLoaded;
181
int m_MaxRecursionCount;
183
static BOOL __stdcall myReadProcMem(HANDLE hProcess,
184
DWORD64 qwBaseAddress,
187
LPDWORD lpNumberOfBytesRead);
189
friend StackWalkerInternal;
190
}; // class StackWalker
192
// The "ugly" assembler-implementation is needed for systems before XP
193
// If you have a new PSDK and you only compile for XP and later, then you can use
194
// the "RtlCaptureContext"
195
// Currently there is no define which determines the PSDK-Version...
196
// So we just use the compiler-version (and assumes that the PSDK is
197
// the one which was installed by the VS-IDE)
199
// INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
200
// But I currently use it in x64/IA64 environments...
201
//#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
204
#ifdef CURRENT_THREAD_VIA_EXCEPTION
205
// TODO: The following is not a "good" implementation,
206
// because the callstack is only valid in the "__except" block...
207
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
210
memset(&c, 0, sizeof(CONTEXT)); \
211
EXCEPTION_POINTERS* pExp = NULL; \
216
__except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \
217
: EXCEPTION_EXECUTE_HANDLER)) \
221
memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
222
c.ContextFlags = contextFlags; \
226
// The following should be enough for walking the callstack...
227
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
230
memset(&c, 0, sizeof(CONTEXT)); \
231
c.ContextFlags = contextFlags; \
234
__asm mov c.Eip, eax \
235
__asm mov c.Ebp, ebp \
236
__asm mov c.Esp, esp \
243
// The following is defined for x86 (XP and higher), x64 and IA64:
244
#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
247
memset(&c, 0, sizeof(CONTEXT)); \
248
c.ContextFlags = contextFlags; \
249
RtlCaptureContext(&c); \
253
#endif //defined(_MSC_VER)
255
#endif // __STACKWALKER_H__