]> git.saurik.com Git - wxWidgets.git/blob - include/wx/msw/debughlp.h
Make wxMSW stack walking methods work with Unicode identifiers.
[wxWidgets.git] / include / wx / msw / debughlp.h
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: wx/msw/debughlp.h
3 // Purpose: wraps dbghelp.h standard file
4 // Author: Vadim Zeitlin
5 // Modified by: Suzumizaki-kimitaka 2013-04-10
6 // Created: 2005-01-08 (extracted from msw/crashrpt.cpp)
7 // Copyright: (c) 2003-2005 Vadim Zeitlin <vadim@wxwindows.org>
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 #ifndef _WX_MSW_DEBUGHLPH_H_
12 #define _WX_MSW_DEBUGHLPH_H_
13
14 #include "wx/dynlib.h"
15
16 #include "wx/msw/wrapwin.h"
17 #ifndef __WXWINCE__
18 #include <imagehlp.h>
19 #endif // __WXWINCE__
20 #include "wx/msw/private.h"
21
22 // All known versions of imagehlp.h define API_VERSION_NUMBER but it's not
23 // documented, so deal with the possibility that it's not defined just in case.
24 #ifndef API_VERSION_NUMBER
25 #define API_VERSION_NUMBER 0
26 #endif
27
28 // wxUSE_DBGHELP is a bit special as it is not defined in wx/setup.h and we try
29 // to auto-detect whether we should be using debug help API or not ourselves
30 // below. However if the auto-detection fails, you can always predefine it as 0
31 // to avoid even trying.
32 #ifndef wxUSE_DBGHELP
33 // The version of imagehlp.h from VC6 (7) is too old and is missing some
34 // required symbols while the version from VC7 (9) is good enough. As we
35 // don't know anything about version 8, don't use it unless we can test it.
36 #if API_VERSION_NUMBER >= 9
37 #define wxUSE_DBGHELP 1
38 #else
39 #define wxUSE_DBGHELP 0
40 #endif
41 #endif
42
43 #if wxUSE_DBGHELP
44
45 /*
46
47 The table below shows which functions are exported by dbghelp.dll.
48 On 64 bit Windows, it looks no difference between 32bit dll and
49 64bit one.
50 Vista-64 and Win8-64 looks same, but in fact, "Ex" and "ExW"
51 versions are exist only in Windows 8.
52
53 Make sure SymGetLineFromAddrW and EnumerateLoadedModulesW DON'T
54 exists.
55
56 functions | Windows | XP-32 Vista-64 Win8-64
57 SymEnumSymbolsW n/a v v
58 SymFromAddrW n/a v v
59 SymInitializeW n/a v v
60
61 SymEnumSymbols v v v
62 SymFromAddr v v v
63 SymInitialize v v v
64
65 SymGetLineFromAddrW64 n/a v v
66 SymGetLineFromAddr64 v v v
67 SymGetLineFromAddrW n/a n/a n/a
68 SymGetLineFromAddr v v v
69
70 EnumerateLoadedModulesW64 n/a v v
71 EnumerateLoadedModules64 v v v
72 EnumerateLoadedModulesW n/a n/a n/a
73 EnumerateLoadedModules v v v
74
75 */
76
77 #ifdef UNICODE
78 #define wxPENUMLOADED_MODULES_CALLBACK64 PENUMLOADED_MODULES_CALLBACKW64
79 #define wxPSYMBOL_INFO PSYMBOL_INFOW
80 #define wxSYMBOL_INFO SYMBOL_INFOW
81 #define wxPIMAGEHLP_LINE PIMAGEHLP_LINEW64
82 #define wxIMAGEHLP_LINE IMAGEHLP_LINEW64
83 #define wxPSYM_ENUMERATESYMBOLS_CALLBACK PSYM_ENUMERATESYMBOLS_CALLBACKW
84 #else
85 #define wxPENUMLOADED_MODULES_CALLBACK64 PENUMLOADED_MODULES_CALLBACK64
86 #define wxPSYMBOL_INFO PSYMBOL_INFO
87 #define wxSYMBOL_INFO SYMBOL_INFO
88 #define wxPIMAGEHLP_LINE PIMAGEHLP_LINE64
89 #define wxIMAGEHLP_LINE IMAGEHLP_LINE64
90 #define wxPSYM_ENUMERATESYMBOLS_CALLBACK PSYM_ENUMERATESYMBOLS_CALLBACK
91 #endif
92
93 // ----------------------------------------------------------------------------
94 // wxDbgHelpDLL: dynamically load dbghelp.dll functions
95 // ----------------------------------------------------------------------------
96
97 // wrapper for some functions from dbghelp.dll
98 //
99 // MT note: this class is not MT safe and should be only used from a single
100 // thread at a time (this is so because dbghelp.dll is not MT-safe
101 // itself anyhow)
102 class wxDbgHelpDLL
103 {
104 public:
105 // some useful constants not present in debughlp.h (stolen from DIA SDK)
106 enum BasicType
107 {
108 BASICTYPE_NOTYPE = 0,
109 BASICTYPE_VOID = 1,
110 BASICTYPE_CHAR = 2,
111 BASICTYPE_WCHAR = 3,
112 BASICTYPE_INT = 6,
113 BASICTYPE_UINT = 7,
114 BASICTYPE_FLOAT = 8,
115 BASICTYPE_BCD = 9,
116 BASICTYPE_BOOL = 10,
117 BASICTYPE_LONG = 13,
118 BASICTYPE_ULONG = 14,
119 BASICTYPE_CURRENCY = 25,
120 BASICTYPE_DATE = 26,
121 BASICTYPE_VARIANT = 27,
122 BASICTYPE_COMPLEX = 28,
123 BASICTYPE_BIT = 29,
124 BASICTYPE_BSTR = 30,
125 BASICTYPE_HRESULT = 31,
126 BASICTYPE_MAX
127 };
128
129 enum SymbolTag
130 {
131 SYMBOL_TAG_NULL,
132 SYMBOL_TAG_EXE,
133 SYMBOL_TAG_COMPILAND,
134 SYMBOL_TAG_COMPILAND_DETAILS,
135 SYMBOL_TAG_COMPILAND_ENV,
136 SYMBOL_TAG_FUNCTION,
137 SYMBOL_TAG_BLOCK,
138 SYMBOL_TAG_DATA,
139 SYMBOL_TAG_ANNOTATION,
140 SYMBOL_TAG_LABEL,
141 SYMBOL_TAG_PUBLIC_SYMBOL,
142 SYMBOL_TAG_UDT,
143 SYMBOL_TAG_ENUM,
144 SYMBOL_TAG_FUNCTION_TYPE,
145 SYMBOL_TAG_POINTER_TYPE,
146 SYMBOL_TAG_ARRAY_TYPE,
147 SYMBOL_TAG_BASE_TYPE,
148 SYMBOL_TAG_TYPEDEF,
149 SYMBOL_TAG_BASE_CLASS,
150 SYMBOL_TAG_FRIEND,
151 SYMBOL_TAG_FUNCTION_ARG_TYPE,
152 SYMBOL_TAG_FUNC_DEBUG_START,
153 SYMBOL_TAG_FUNC_DEBUG_END,
154 SYMBOL_TAG_USING_NAMESPACE,
155 SYMBOL_TAG_VTABLE_SHAPE,
156 SYMBOL_TAG_VTABLE,
157 SYMBOL_TAG_CUSTOM,
158 SYMBOL_TAG_THUNK,
159 SYMBOL_TAG_CUSTOM_TYPE,
160 SYMBOL_TAG_MANAGED_TYPE,
161 SYMBOL_TAG_DIMENSION,
162 SYMBOL_TAG_MAX
163 };
164
165 enum DataKind
166 {
167 DATA_UNKNOWN,
168 DATA_LOCAL,
169 DATA_STATIC_LOCAL,
170 DATA_PARAM,
171 DATA_OBJECT_PTR, // "this" pointer
172 DATA_FILE_STATIC,
173 DATA_GLOBAL,
174 DATA_MEMBER,
175 DATA_STATIC_MEMBER,
176 DATA_CONSTANT,
177 DATA_MAX
178 };
179
180 enum UdtKind
181 {
182 UDT_STRUCT,
183 UDT_CLASS,
184 UDT_UNION,
185 UDT_MAX
186 };
187
188
189 // function types
190 typedef DWORD (WINAPI *SymGetOptions_t)();
191 typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
192 typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME,
193 LPVOID, PREAD_PROCESS_MEMORY_ROUTINE,
194 PFUNCTION_TABLE_ACCESS_ROUTINE,
195 PGET_MODULE_BASE_ROUTINE,
196 PTRANSLATE_ADDRESS_ROUTINE);
197 typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD_PTR);
198 typedef DWORD_PTR (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD_PTR);
199 typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME,
200 PIMAGEHLP_CONTEXT);
201 typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG,
202 IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
203 typedef BOOL (WINAPI *SymCleanup_t)(HANDLE);
204 typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
205 MINIDUMP_TYPE,
206 CONST PMINIDUMP_EXCEPTION_INFORMATION,
207 CONST PMINIDUMP_USER_STREAM_INFORMATION,
208 CONST PMINIDUMP_CALLBACK_INFORMATION);
209
210 typedef BOOL (WINAPI *EnumerateLoadedModules_t)(HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID);
211 typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD, PDWORD, PIMAGEHLP_LINE);
212
213 typedef BOOL (WINAPI *EnumerateLoadedModules64_t)(HANDLE, PENUMLOADED_MODULES_CALLBACK64, PVOID);
214 typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPCSTR, BOOL);
215 typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
216 typedef BOOL (WINAPI *SymGetLineFromAddr64_t)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINE64);
217 typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR,
218 PSYM_ENUMERATESYMBOLS_CALLBACK, const PVOID);
219
220 typedef BOOL (WINAPI *EnumerateLoadedModulesW64_t)(HANDLE, PENUMLOADED_MODULES_CALLBACKW64, PVOID);
221 typedef BOOL (WINAPI *SymInitializeW_t)(HANDLE, LPCWSTR, BOOL);
222 typedef BOOL (WINAPI *SymFromAddrW_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFOW);
223 typedef BOOL (WINAPI *SymGetLineFromAddrW64_t)(HANDLE, DWORD64, PDWORD, PIMAGEHLP_LINEW64);
224 typedef BOOL (WINAPI *SymEnumSymbolsW_t)(HANDLE, ULONG64, PCWSTR,
225 PSYM_ENUMERATESYMBOLS_CALLBACKW, const PVOID);
226
227 static BOOL EnumerateLoadedModulesT(HANDLE, wxPENUMLOADED_MODULES_CALLBACK64, PVOID);
228 static BOOL SymInitializeT(HANDLE, LPCTSTR, BOOL);
229 static BOOL SymFromAddrT(HANDLE, DWORD64, PDWORD64, wxPSYMBOL_INFO);
230 static BOOL SymGetLineFromAddrT(HANDLE, DWORD64, PDWORD, wxPIMAGEHLP_LINE);
231 static BOOL SymEnumSymbolsT(HANDLE, ULONG64, PCTSTR, wxPSYM_ENUMERATESYMBOLS_CALLBACK, const PVOID);
232
233 // The macro called by wxDO_FOR_ALL_SYM_FUNCS() below takes 2 arguments:
234 // the name of the function in the program code, which never has "64"
235 // suffix, and the name of the function in the DLL which can have "64"
236 // suffix in some cases. These 2 helper macros call the macro with the
237 // correct arguments in both cases.
238 #define wxSYM_CALL(what, name) what(name, name)
239 #if defined(_M_AMD64)
240 #define wxSYM_CALL_64(what, name) what(name, name ## 64)
241 // Also undo all the "helpful" definitions done by imagehlp.h that map 32
242 // bit functions to 64 bit ones, we don't need this as we do it ourselves.
243 #undef StackWalk
244 #undef SymFunctionTableAccess
245 #undef SymGetModuleBase
246 #undef SymGetLineFromAddr
247 #undef EnumerateLoadedModules
248 #else
249 #define wxSYM_CALL_64(what, name) what(name, name)
250 #endif
251
252 #define wxSYM_CALL_ALWAYS_W(what, name) what(name ## W, name ## W)
253
254 #define wxSYM_CALL_ALTERNATIVES(what, name) \
255 what(name, name); \
256 what(name ## 64, name ## 64); \
257 what(name ## W64, name ## W64)
258
259 #define wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PUBLIC(what) \
260 wxSYM_CALL_64(what, StackWalk); \
261 wxSYM_CALL_64(what, SymFunctionTableAccess); \
262 wxSYM_CALL_64(what, SymGetModuleBase); \
263 \
264 wxSYM_CALL(what, SymGetOptions); \
265 wxSYM_CALL(what, SymSetOptions); \
266 wxSYM_CALL(what, SymSetContext); \
267 wxSYM_CALL(what, SymGetTypeInfo); \
268 wxSYM_CALL(what, SymCleanup); \
269 wxSYM_CALL(what, MiniDumpWriteDump)
270
271 #define wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PRIVATE(what) \
272 wxSYM_CALL(what, SymInitialize); \
273 wxSYM_CALL(what, SymFromAddr); \
274 wxSYM_CALL(what, SymEnumSymbols)
275
276 #define wxDO_FOR_ALL_SYM_FUNCS_REQUIRED(what) \
277 wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PRIVATE(what); \
278 wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PUBLIC(what)
279
280 // Alternation will work when the following functions are not found,
281 // therefore they are not included in REQUIRED version.
282 #define wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(what) \
283 wxSYM_CALL_ALTERNATIVES(what, SymGetLineFromAddr); \
284 wxSYM_CALL_ALTERNATIVES(what, EnumerateLoadedModules); \
285 wxSYM_CALL_ALWAYS_W(what, SymInitialize); \
286 wxSYM_CALL_ALWAYS_W(what, SymFromAddr); \
287 wxSYM_CALL_ALWAYS_W(what, SymEnumSymbols)
288
289 #define wxDO_FOR_ALL_SYM_FUNCS(what) \
290 wxDO_FOR_ALL_SYM_FUNCS_REQUIRED(what); \
291 wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(what)
292
293 #define wxDECLARE_SYM_FUNCTION(func, name) static func ## _t func
294
295 wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PUBLIC(wxDECLARE_SYM_FUNCTION);
296
297 private:
298 wxDO_FOR_ALL_SYM_FUNCS_REQUIRED_PRIVATE(wxDECLARE_SYM_FUNCTION);
299 wxDO_FOR_ALL_SYM_FUNCS_OPTIONAL(wxDECLARE_SYM_FUNCTION);
300
301 public:
302
303 #undef wxDECLARE_SYM_FUNCTION
304
305 // load all functions from DLL, return true if ok
306 static bool Init();
307
308 // return the string with the error message explaining why Init() failed
309 static const wxString& GetErrorMessage();
310
311 // log error returned by the given function to debug output
312 static void LogError(const wxChar *func);
313
314 // return textual representation of the value of given symbol
315 static wxString DumpSymbol(wxPSYMBOL_INFO pSymInfo, void *pVariable);
316
317 // return the name of the symbol with given type index
318 static wxString GetSymbolName(wxPSYMBOL_INFO pSymInfo);
319
320 private:
321 // dereference the given symbol, i.e. return symbol which is not a
322 // pointer/reference any more
323 //
324 // if ppData != NULL, dereference the pointer as many times as we
325 // dereferenced the symbol
326 //
327 // return the tag of the dereferenced symbol
328 static SymbolTag DereferenceSymbol(wxPSYMBOL_INFO pSymInfo, void **ppData);
329
330 static wxString DumpField(wxPSYMBOL_INFO pSymInfo,
331 void *pVariable,
332 unsigned level);
333
334 static wxString DumpBaseType(BasicType bt, DWORD64 length, void *pVariable);
335
336 static wxString DumpUDT(wxPSYMBOL_INFO pSymInfo,
337 void *pVariable,
338 unsigned level = 0);
339
340 static bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp);
341 static bool DoInit();
342 };
343
344 #endif // wxUSE_DBGHELP
345
346 #endif // _WX_MSW_DEBUGHLPH_H_
347