1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        wx/msw/debughlp.h
3 // Purpose:     wraps dbghelp.h standard file
4 // Author:      Vadim Zeitlin
5 // Modified by:
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 #ifdef __VISUALC__
19     // Disable a warning that we can do nothing about: we get it at least for
20     // imagehlp.h from 8.1 Windows kit when using VC14.
21     #pragma warning(push)
22 
23     // 'typedef ': ignored on left of '' when no variable is declared
24     #pragma warning(disable:4091)
25 #endif
26 
27 #include <imagehlp.h>
28 
29 #ifdef __VISUALC__
30   #pragma warning(pop)
31 #endif
32 #endif // __WXWINCE__
33 #include "wx/msw/private.h"
34 
35 // All known versions of imagehlp.h define API_VERSION_NUMBER but it's not
36 // documented, so deal with the possibility that it's not defined just in case.
37 #ifndef API_VERSION_NUMBER
38     #define API_VERSION_NUMBER 0
39 #endif
40 
41 // wxUSE_DBGHELP is a bit special as it is not defined in wx/setup.h and we try
42 // to auto-detect whether we should be using debug help API or not ourselves
43 // below. However if the auto-detection fails, you can always predefine it as 0
44 // to avoid even trying.
45 #ifndef wxUSE_DBGHELP
46     // The version of imagehlp.h from VC6 (7) is too old and is missing some
47     // required symbols while the version from VC7 (9) is good enough. As we
48     // don't know anything about version 8, don't use it unless we can test it.
49     #if API_VERSION_NUMBER >= 9
50         #define wxUSE_DBGHELP 1
51     #else
52         #define wxUSE_DBGHELP 0
53     #endif
54 #endif
55 
56 #if wxUSE_DBGHELP
57 
58 // ----------------------------------------------------------------------------
59 // wxDbgHelpDLL: dynamically load dbghelp.dll functions
60 // ----------------------------------------------------------------------------
61 
62 // wrapper for some functions from dbghelp.dll
63 //
64 // MT note: this class is not MT safe and should be only used from a single
65 //          thread at a time (this is so because dbghelp.dll is not MT-safe
66 //          itself anyhow)
67 class wxDbgHelpDLL
68 {
69 public:
70     // some useful constants not present in debughlp.h (stolen from DIA SDK)
71     enum BasicType
72     {
73         BASICTYPE_NOTYPE = 0,
74         BASICTYPE_VOID = 1,
75         BASICTYPE_CHAR = 2,
76         BASICTYPE_WCHAR = 3,
77         BASICTYPE_INT = 6,
78         BASICTYPE_UINT = 7,
79         BASICTYPE_FLOAT = 8,
80         BASICTYPE_BCD = 9,
81         BASICTYPE_BOOL = 10,
82         BASICTYPE_LONG = 13,
83         BASICTYPE_ULONG = 14,
84         BASICTYPE_CURRENCY = 25,
85         BASICTYPE_DATE = 26,
86         BASICTYPE_VARIANT = 27,
87         BASICTYPE_COMPLEX = 28,
88         BASICTYPE_BIT = 29,
89         BASICTYPE_BSTR = 30,
90         BASICTYPE_HRESULT = 31,
91         BASICTYPE_MAX
92     };
93 
94     enum SymbolTag
95     {
96         SYMBOL_TAG_NULL,
97         SYMBOL_TAG_EXE,
98         SYMBOL_TAG_COMPILAND,
99         SYMBOL_TAG_COMPILAND_DETAILS,
100         SYMBOL_TAG_COMPILAND_ENV,
101         SYMBOL_TAG_FUNCTION,
102         SYMBOL_TAG_BLOCK,
103         SYMBOL_TAG_DATA,
104         SYMBOL_TAG_ANNOTATION,
105         SYMBOL_TAG_LABEL,
106         SYMBOL_TAG_PUBLIC_SYMBOL,
107         SYMBOL_TAG_UDT,
108         SYMBOL_TAG_ENUM,
109         SYMBOL_TAG_FUNCTION_TYPE,
110         SYMBOL_TAG_POINTER_TYPE,
111         SYMBOL_TAG_ARRAY_TYPE,
112         SYMBOL_TAG_BASE_TYPE,
113         SYMBOL_TAG_TYPEDEF,
114         SYMBOL_TAG_BASE_CLASS,
115         SYMBOL_TAG_FRIEND,
116         SYMBOL_TAG_FUNCTION_ARG_TYPE,
117         SYMBOL_TAG_FUNC_DEBUG_START,
118         SYMBOL_TAG_FUNC_DEBUG_END,
119         SYMBOL_TAG_USING_NAMESPACE,
120         SYMBOL_TAG_VTABLE_SHAPE,
121         SYMBOL_TAG_VTABLE,
122         SYMBOL_TAG_CUSTOM,
123         SYMBOL_TAG_THUNK,
124         SYMBOL_TAG_CUSTOM_TYPE,
125         SYMBOL_TAG_MANAGED_TYPE,
126         SYMBOL_TAG_DIMENSION,
127         SYMBOL_TAG_MAX
128     };
129 
130     enum DataKind
131     {
132         DATA_UNKNOWN,
133         DATA_LOCAL,
134         DATA_STATIC_LOCAL,
135         DATA_PARAM,
136         DATA_OBJECT_PTR,                    // "this" pointer
137         DATA_FILE_STATIC,
138         DATA_GLOBAL,
139         DATA_MEMBER,
140         DATA_STATIC_MEMBER,
141         DATA_CONSTANT,
142         DATA_MAX
143     };
144 
145     enum UdtKind
146     {
147         UDT_STRUCT,
148         UDT_CLASS,
149         UDT_UNION,
150         UDT_MAX
151     };
152 
153 
154     // function types
155     typedef DWORD (WINAPI *SymGetOptions_t)();
156     typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
157     typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
158     typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME,
159                                        LPVOID, PREAD_PROCESS_MEMORY_ROUTINE,
160                                        PFUNCTION_TABLE_ACCESS_ROUTINE,
161                                        PGET_MODULE_BASE_ROUTINE,
162                                        PTRANSLATE_ADDRESS_ROUTINE);
163     typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
164     typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD_PTR);
165     typedef DWORD_PTR (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD_PTR);
166     typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD_PTR,
167                                                 PDWORD, PIMAGEHLP_LINE);
168     typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME,
169                                            PIMAGEHLP_CONTEXT);
170     typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR,
171                                             PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
172     typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG,
173                                             IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
174     typedef BOOL (WINAPI *SymCleanup_t)(HANDLE);
175     typedef BOOL (WINAPI *EnumerateLoadedModules_t)(HANDLE, PENUMLOADED_MODULES_CALLBACK, PVOID);
176     typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
177                                                MINIDUMP_TYPE,
178                                                CONST PMINIDUMP_EXCEPTION_INFORMATION,
179                                                CONST PMINIDUMP_USER_STREAM_INFORMATION,
180                                                CONST PMINIDUMP_CALLBACK_INFORMATION);
181 
182     // The macro called by wxDO_FOR_ALL_SYM_FUNCS() below takes 2 arguments:
183     // the name of the function in the program code, which never has "64"
184     // suffix, and the name of the function in the DLL which can have "64"
185     // suffix in some cases. These 2 helper macros call the macro with the
186     // correct arguments in both cases.
187     #define wxSYM_CALL(what, name)  what(name, name)
188 #if defined(_M_AMD64)
189     #define wxSYM_CALL_64(what, name)  what(name, name ## 64)
190 
191     // Also undo all the "helpful" definitions done by imagehlp.h that map 32
192     // bit functions to 64 bit ones, we don't need this as we do it ourselves.
193     #undef StackWalk
194     #undef SymFunctionTableAccess
195     #undef SymGetModuleBase
196     #undef SymGetLineFromAddr
197     #undef EnumerateLoadedModules
198 #else
199     #define wxSYM_CALL_64(what, name)  what(name, name)
200 #endif
201 
202     #define wxDO_FOR_ALL_SYM_FUNCS(what)                                      \
203         wxSYM_CALL_64(what, StackWalk);                                       \
204         wxSYM_CALL_64(what, SymFunctionTableAccess);                          \
205         wxSYM_CALL_64(what, SymGetModuleBase);                                \
206         wxSYM_CALL_64(what, SymGetLineFromAddr);                              \
207         wxSYM_CALL_64(what, EnumerateLoadedModules);                          \
208                                                                               \
209         wxSYM_CALL(what, SymGetOptions);                                      \
210         wxSYM_CALL(what, SymSetOptions);                                      \
211         wxSYM_CALL(what, SymInitialize);                                      \
212         wxSYM_CALL(what, SymFromAddr);                                        \
213         wxSYM_CALL(what, SymSetContext);                                      \
214         wxSYM_CALL(what, SymEnumSymbols);                                     \
215         wxSYM_CALL(what, SymGetTypeInfo);                                     \
216         wxSYM_CALL(what, SymCleanup);                                         \
217         wxSYM_CALL(what, MiniDumpWriteDump)
218 
219     #define wxDECLARE_SYM_FUNCTION(func, name) static func ## _t func
220 
221     wxDO_FOR_ALL_SYM_FUNCS(wxDECLARE_SYM_FUNCTION);
222 
223     #undef wxDECLARE_SYM_FUNCTION
224 
225     // load all functions from DLL, return true if ok
226     static bool Init();
227 
228     // return the string with the error message explaining why Init() failed
229     static const wxString& GetErrorMessage();
230 
231     // log error returned by the given function to debug output
232     static void LogError(const wxChar *func);
233 
234     // return textual representation of the value of given symbol
235     static wxString DumpSymbol(PSYMBOL_INFO pSymInfo, void *pVariable);
236 
237     // return the name of the symbol with given type index
238     static wxString GetSymbolName(PSYMBOL_INFO pSymInfo);
239 
240 private:
241     // dereference the given symbol, i.e. return symbol which is not a
242     // pointer/reference any more
243     //
244     // if ppData != NULL, dereference the pointer as many times as we
245     // dereferenced the symbol
246     //
247     // return the tag of the dereferenced symbol
248     static SymbolTag DereferenceSymbol(PSYMBOL_INFO pSymInfo, void **ppData);
249 
250     static wxString DumpField(PSYMBOL_INFO pSymInfo,
251                               void *pVariable,
252                               unsigned level);
253 
254     static wxString DumpBaseType(BasicType bt, DWORD64 length, void *pVariable);
255 
256     static wxString DumpUDT(PSYMBOL_INFO pSymInfo,
257                             void *pVariable,
258                             unsigned level = 0);
259 };
260 
261 #endif // wxUSE_DBGHELP
262 
263 #endif // _WX_MSW_DEBUGHLPH_H_
264 
265