RCFProto

- Main Page
- Classes
- Files

- File List

All Classes Functions Typedefs
StackWalker.h
1 /**********************************************************************
2 *
3 * StackWalker.h
4 *
5 *
6 * History:
7 * 2005-07-27 v1 - First public release on http://www.codeproject.com/
8 * (for additional changes see History in 'StackWalker.cpp'!
9 *
10 **********************************************************************/
11 // #pragma once is supported starting with _MCS_VER 1000,
12 // so we need not to check the version (because we only support _MSC_VER >= 1100)!
13 #pragma once
14
15 #include <windows.h>
16
17 // special defines for VC5/6 (if no actual PSDK is installed):
18 #if _MSC_VER < 1300
19 typedef unsigned __int64 DWORD64, *PDWORD64;
20 #if defined(_WIN64)
21 typedef unsigned __int64 SIZE_T, *PSIZE_T;
22 #else
23 typedef unsigned long SIZE_T, *PSIZE_T;
24 #endif
25 #endif // _MSC_VER < 1300
26
27 class StackWalkerInternal; // forward
28 class StackWalker
29 {
30 public:
31 typedef enum StackWalkOptions
32 {
33 // No addition info will be retrived
34 // (only the address is available)
35 RetrieveNone = 0,
36
37 // Try to get the symbol-name
38 RetrieveSymbol = 1,
39
40 // Try to get the line for this symbol
41 RetrieveLine = 2,
42
43 // Try to retrieve the module-infos
44 RetrieveModuleInfo = 4,
45
46 // Also retrieve the version for the DLL/EXE
47 RetrieveFileVersion = 8,
48
49 // Contains all the abouve
50 RetrieveVerbose = 0xF,
51
52 // Generate a "good" symbol-search-path
53 SymBuildPath = 0x10,
54
55 // Also use the public Microsoft-Symbol-Server
56 SymUseSymSrv = 0x20,
57
58 // Contains all the abouve "Sym"-options
59 SymAll = 0x30,
60
61 // Contains all options (default)
62 OptionsAll = 0x3F
63 } StackWalkOptions;
64
65 StackWalker(
66 int options = OptionsAll, // 'int' is by design, to combine the enum-flags
67 LPCSTR szSymPath = NULL,
68 DWORD dwProcessId = GetCurrentProcessId(),
69 HANDLE hProcess = GetCurrentProcess()
70 );
71 StackWalker(DWORD dwProcessId, HANDLE hProcess);
72 virtual ~StackWalker();
73
74 typedef BOOL (__stdcall *PReadProcessMemoryRoutine)(
75 HANDLE hProcess,
76 DWORD64 qwBaseAddress,
77 PVOID lpBuffer,
78 DWORD nSize,
79 LPDWORD lpNumberOfBytesRead,
80 LPVOID pUserData // optional data, which was passed in "ShowCallstack"
81 );
82
83 BOOL LoadModules();
84
85 BOOL ShowCallstack(
86 HANDLE hThread = GetCurrentThread(),
87 const CONTEXT *context = NULL,
88 PReadProcessMemoryRoutine readMemoryFunction = NULL,
89 LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback
90 );
91
92 #if _MSC_VER >= 1300
93 // due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public"
94 // in older compilers in order to use it... starting with VC7 we can declare it as "protected"
95 protected:
96 #endif
97 enum { STACKWALK_MAX_NAMELEN = 1024 }; // max name length for found symbols
98
99 protected:
100 // Entry for each Callstack-Entry
101 typedef struct CallstackEntry
102 {
103 DWORD64 offset; // if 0, we have no valid entry
104 CHAR name[STACKWALK_MAX_NAMELEN];
105 CHAR undName[STACKWALK_MAX_NAMELEN];
106 CHAR undFullName[STACKWALK_MAX_NAMELEN];
107 DWORD64 offsetFromSmybol;
108 DWORD offsetFromLine;
109 DWORD lineNumber;
110 CHAR lineFileName[STACKWALK_MAX_NAMELEN];
111 DWORD symType;
112 LPCSTR symTypeString;
113 CHAR moduleName[STACKWALK_MAX_NAMELEN];
114 DWORD64 baseOfImage;
115 CHAR loadedImageName[STACKWALK_MAX_NAMELEN];
116 } CallstackEntry;
117
118 typedef enum CallstackEntryType {firstEntry, nextEntry, lastEntry};
119
120 virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName);
121 virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size, DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion);
122 virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry);
123 virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr);
124 virtual void OnOutput(LPCSTR szText);
125
126 StackWalkerInternal *m_sw;
127 HANDLE m_hProcess;
128 DWORD m_dwProcessId;
129 BOOL m_modulesLoaded;
130 LPSTR m_szSymPath;
131
132 int m_options;
133
134 static BOOL __stdcall myReadProcMem(HANDLE hProcess, DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, LPDWORD lpNumberOfBytesRead);
135
136 friend StackWalkerInternal;
137 };
138
139
140 // The "ugly" assembler-implementation is needed for systems before XP
141 // If you have a new PSDK and you only compile for XP and later, then you can use
142 // the "RtlCaptureContext"
143 // Currently there is no define which determines the PSDK-Version...
144 // So we just use the compiler-version (and assumes that the PSDK is
145 // the one which was installed by the VS-IDE)
146
147 // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later...
148 // But I currently use it in x64/IA64 environments...
149 //#if defined(_M_IX86) && (_WIN32_WINNT <= 0x0500) && (_MSC_VER < 1400)
150
151 #if defined(_M_IX86)
152 #ifdef CURRENT_THREAD_VIA_EXCEPTION
153 // TODO: The following is not a "good" implementation,
154 // because the callstack is only valid in the "__except" block...
155 #define GET_CURRENT_CONTEXT(c, contextFlags) \
156 do { \
157 memset(&c, 0, sizeof(CONTEXT)); \
158 EXCEPTION_POINTERS *pExp = NULL; \
159 __try { \
160 throw 0; \
161 } __except( ( (pExp = GetExceptionInformation()) ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_EXECUTE_HANDLER)) {} \
162 if (pExp != NULL) \
163 memcpy(&c, pExp->ContextRecord, sizeof(CONTEXT)); \
164 c.ContextFlags = contextFlags; \
165 } while(0);
166 #else
167 // The following should be enough for walking the callstack...
168 #define GET_CURRENT_CONTEXT(c, contextFlags) \
169 do { \
170 memset(&c, 0, sizeof(CONTEXT)); \
171 c.ContextFlags = contextFlags; \
172 __asm call x \
173 __asm x: pop eax \
174 __asm mov c.Eip, eax \
175 __asm mov c.Ebp, ebp \
176 __asm mov c.Esp, esp \
177 } while(0);
178 #endif
179
180 #else
181
182 // The following is defined for x86 (XP and higher), x64 and IA64:
183 #define GET_CURRENT_CONTEXT(c, contextFlags) \
184 do { \
185 memset(&c, 0, sizeof(CONTEXT)); \
186 c.ContextFlags = contextFlags; \
187 RtlCaptureContext(&c); \
188 } while(0);
189 #endif
190
191 class StackTrace : public StackWalker
192 {
193 public:
194 StackTrace() : StackWalker()
195 {
196 ShowCallstack();
197 }
198
199 const std::string & toString() const
200 {
201 return mOutput;
202 }
203
204 protected:
205 virtual void OnOutput(LPCSTR szText)
206 {
207 mOutput += szText;
208 }
209
210 virtual void OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUserName)
211 {
212 }
213
214 virtual void OnLoadModule(LPCSTR img, LPCSTR mod, DWORD64 baseAddr, DWORD size,
215 DWORD result, LPCSTR symType, LPCSTR pdbName, ULONGLONG fileVersion)
216 {
217 }
218
219 //virtual void OnCallstackEntry(CallstackEntryType eType, CallstackEntry &entry)
220 //{
221 // mOutput += entry.;
222 //}
223
224 virtual void OnDbgHelpErr(LPCSTR szFuncName, DWORD gle, DWORD64 addr)
225 {
226 }
227
228 std::string mOutput;
229 };