source: opengl-game/StackWalker.h

feature/imgui-sdl
Last change on this file was d9b6a1c, checked in by Dmitry Portnoy <dmitry.portnoy@…>, 5 years ago

Print a stack trace in the event of a crash. Currently, the code for this on Windows outputs the stack trace to stderr, not to a log file.

  • Property mode set to 100644
File size: 9.7 KB
Line 
1#ifndef __STACKWALKER_H__
2#define __STACKWALKER_H__
3
4#if defined(_MSC_VER)
5
6/**********************************************************************
7 *
8 * StackWalker.h
9 *
10 *
11 *
12 * LICENSE (http://www.opensource.org/licenses/bsd-license.php)
13 *
14 * Copyright (c) 2005-2009, Jochen Kalmbach
15 * All rights reserved.
16 *
17 * Redistribution and use in source and binary forms, with or without modification,
18 * are permitted provided that the following conditions are met:
19 *
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.
38 *
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)!
42#pragma once
43
44#include <windows.h>
45
46#if _MSC_VER >= 1900
47#pragma warning(disable : 4091)
48#endif
49
50// special defines for VC5/6 (if no actual PSDK is installed):
51#if _MSC_VER < 1300
52typedef unsigned __int64 DWORD64, *PDWORD64;
53#if defined(_WIN64)
54typedef unsigned __int64 SIZE_T, *PSIZE_T;
55#else
56typedef unsigned long SIZE_T, *PSIZE_T;
57#endif
58#endif // _MSC_VER < 1300
59
60class StackWalkerInternal; // forward
61class StackWalker
62{
63public:
64 typedef enum StackWalkOptions
65 {
66 // No addition info will be retrieved
67 // (only the address is available)
68 RetrieveNone = 0,
69
70 // Try to get the symbol-name
71 RetrieveSymbol = 1,
72
73 // Try to get the line for this symbol
74 RetrieveLine = 2,
75
76 // Try to retrieve the module-infos
77 RetrieveModuleInfo = 4,
78
79 // Also retrieve the version for the DLL/EXE
80 RetrieveFileVersion = 8,
81
82 // Contains all the above
83 RetrieveVerbose = 0xF,
84
85 // Generate a "good" symbol-search-path
86 SymBuildPath = 0x10,
87
88 // Also use the public Microsoft-Symbol-Server
89 SymUseSymSrv = 0x20,
90
91 // Contains all the above "Sym"-options
92 SymAll = 0x30,
93
94 // Contains all options (default)
95 OptionsAll = 0x3F
96 } StackWalkOptions;
97
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();
104
105 typedef BOOL(__stdcall* PReadProcessMemoryRoutine)(
106 HANDLE hProcess,
107 DWORD64 qwBaseAddress,
108 PVOID lpBuffer,
109 DWORD nSize,
110 LPDWORD lpNumberOfBytesRead,
111 LPVOID pUserData // optional data, which was passed in "ShowCallstack"
112 );
113
114 BOOL LoadModules();
115
116 BOOL 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
121 );
122
123 BOOL ShowObject(LPVOID pObject);
124
125#if _MSC_VER >= 1300
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"
128protected:
129#endif
130 enum
131 {
132 STACKWALK_MAX_NAMELEN = 1024
133 }; // max name length for found symbols
134
135protected:
136 // Entry for each Callstack-Entry
137 typedef struct CallstackEntry
138 {
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;
145 DWORD lineNumber;
146 CHAR lineFileName[STACKWALK_MAX_NAMELEN];
147 DWORD symType;
148 LPCSTR symTypeString;
149 CHAR moduleName[STACKWALK_MAX_NAMELEN];
150 DWORD64 baseOfImage;
151 CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
152 } CallstackEntry;
153
154 typedef enum CallstackEntryType
155 {
156 firstEntry,
157 nextEntry,
158 lastEntry
159 } CallstackEntryType;
160
161 virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
162 virtual void OnLoadModule(LPCSTR img,
163 LPCSTR mod,
164 DWORD64 baseAddr,
165 DWORD size,
166 DWORD result,
167 LPCSTR symType,
168 LPCSTR pdbName,
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);
173
174 StackWalkerInternal* m_sw;
175 HANDLE m_hProcess;
176 DWORD m_dwProcessId;
177 BOOL m_modulesLoaded;
178 LPSTR m_szSymPath;
179
180 int m_options;
181 int m_MaxRecursionCount;
182
183 static BOOL __stdcall myReadProcMem(HANDLE hProcess,
184 DWORD64 qwBaseAddress,
185 PVOID lpBuffer,
186 DWORD nSize,
187 LPDWORD lpNumberOfBytesRead);
188
189 friend StackWalkerInternal;
190}; // class StackWalker
191
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)
198
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)
202
203#if defined(_M_IX86)
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) \
208 do \
209 { \
210 memset(&c, 0, sizeof(CONTEXT)); \
211 EXCEPTION_POINTERS* pExp = NULL; \
212 __try \
213 { \
214 throw 0; \
215 } \
216 __except (((pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER \
217 : EXCEPTION_EXECUTE_HANDLER)) \
218 { \
219 } \
220 if (pExp != NULL) \
221 memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
222 c.ContextFlags = contextFlags; \
223 } while (0);
224#else
225// clang-format off
226// The following should be enough for walking the callstack...
227#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
228 do \
229 { \
230 memset(&c, 0, sizeof(CONTEXT)); \
231 c.ContextFlags = contextFlags; \
232 __asm call x \
233 __asm x: pop eax \
234 __asm mov c.Eip, eax \
235 __asm mov c.Ebp, ebp \
236 __asm mov c.Esp, esp \
237 } while (0)
238// clang-format on
239#endif
240
241#else
242
243// The following is defined for x86 (XP and higher), x64 and IA64:
244#define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \
245 do \
246 { \
247 memset(&c, 0, sizeof(CONTEXT)); \
248 c.ContextFlags = contextFlags; \
249 RtlCaptureContext(&c); \
250 } while (0);
251#endif
252
253#endif //defined(_MSC_VER)
254
255#endif // __STACKWALKER_H__
Note: See TracBrowser for help on using the repository browser.