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