]> git.saurik.com Git - wxWidgets.git/blob - src/palmos/crashrpt.cpp
added {debughlp|stackwalk}.{h|cpp}
[wxWidgets.git] / src / palmos / crashrpt.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: palmos/crashrpt.cpp
3 // Purpose: helpers for structured exception handling (SEH)
4 // Author: William Osborne
5 // Modified by:
6 // Created: 10/13/04
7 // RCS-ID: $Id:
8 // Copyright: (c) William Osborne
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 /*
13 The code generating the crash reports in this file is heavily based on
14 Matt Pietrek's column from the March 2002 issue of MSDN Magazine. Note
15 that this code is not currently used by default, however. In any case,
16 all bugs are my alone.
17 */
18
19 // ============================================================================
20 // declarations
21 // ============================================================================
22
23 // ----------------------------------------------------------------------------
24 // headers
25 // ----------------------------------------------------------------------------
26
27 // For compilers that support precompilation, includes "wx.h".
28 #include "wx/wxprec.h"
29
30 #ifdef __BORLANDC__
31 #pragma hdrstop
32 #endif
33
34 #if wxUSE_ON_FATAL_EXCEPTION
35
36 #ifndef WX_PRECOMP
37 #endif //WX_PRECOMP
38
39 /*
40 We have two possibilities here: one, a priori more interesting, is to
41 generate the crash report ourselves and include the values of all the
42 variables in the dump. Unfortunately my code to do it doesn't work in
43 "real life" situations i.e. it works in small examples but invariably
44 gets confused by something in big programs which makes quite useless.
45
46 The other possibility is to let dbghelp.dll to do the work for us and
47 analyze its results later using a debugger with knowledge about crash
48 dumps, such as (free!) WinDbg. This also has another advantage of not
49 needing to ship the .pdb file (containing debug info) to the user. So
50 this is the default now, but I keep the old code just in case, and if
51 you really want you can still use it.
52 */
53 #define wxUSE_MINIDUMP 1
54
55 #if !wxUSE_MINIDUMP
56 #include "wx/longlong.h"
57 #endif // wxUSE_MINIDUMP
58
59 #include "wx/datetime.h"
60
61 #include "wx/dynload.h"
62
63 #include "wx/palmos/crashrpt.h"
64
65 #include "wx/palmos/wrapwin.h"
66 #include "wx/palmos/private.h"
67
68 #ifndef wxUSE_DBGHELP
69 #define wxUSE_DBGHELP 0
70 #endif
71
72 #if wxUSE_DBGHELP
73
74 // ----------------------------------------------------------------------------
75 // types of imagehlp.h functions
76 // ----------------------------------------------------------------------------
77
78 #if wxUSE_MINIDUMP
79
80 typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
81 MINIDUMP_TYPE,
82 CONST PMINIDUMP_EXCEPTION_INFORMATION,
83 CONST PMINIDUMP_USER_STREAM_INFORMATION,
84 CONST PMINIDUMP_CALLBACK_INFORMATION);
85 #else // !wxUSE_MINIDUMP
86 typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
87 typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
88 typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME,
89 LPVOID, PREAD_PROCESS_MEMORY_ROUTINE,
90 PFUNCTION_TABLE_ACCESS_ROUTINE,
91 PGET_MODULE_BASE_ROUTINE,
92 PTRANSLATE_ADDRESS_ROUTINE);
93 typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
94 typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD);
95 typedef DWORD (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD);
96 typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD,
97 PDWORD, PIMAGEHLP_LINE);
98 typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME,
99 PIMAGEHLP_CONTEXT);
100 typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR,
101 PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
102 typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG,
103 IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
104 #endif // wxUSE_MINIDUMP
105
106 // ----------------------------------------------------------------------------
107 // constants
108 // ----------------------------------------------------------------------------
109
110 #if !wxUSE_MINIDUMP
111
112 // Stolen from CVCONST.H in the DIA 2.0 SDK
113 enum BasicType
114 {
115 BASICTYPE_NOTYPE = 0,
116 BASICTYPE_VOID = 1,
117 BASICTYPE_CHAR = 2,
118 BASICTYPE_WCHAR = 3,
119 BASICTYPE_INT = 6,
120 BASICTYPE_UINT = 7,
121 BASICTYPE_FLOAT = 8,
122 BASICTYPE_BCD = 9,
123 BASICTYPE_BOOL = 10,
124 BASICTYPE_LONG = 13,
125 BASICTYPE_ULONG = 14,
126 BASICTYPE_CURRENCY = 25,
127 BASICTYPE_DATE = 26,
128 BASICTYPE_VARIANT = 27,
129 BASICTYPE_COMPLEX = 28,
130 BASICTYPE_BIT = 29,
131 BASICTYPE_BSTR = 30,
132 BASICTYPE_HRESULT = 31
133 };
134
135 // Same as above
136 enum SymbolTag
137 {
138 SYMBOL_TAG_NULL,
139 SYMBOL_TAG_FUNCTION = 5,
140 SYMBOL_TAG_DATA = 7,
141 SYMBOL_TAG_PUBLIC = 10, // appears in .DBGs
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_BASECLASS
150 };
151
152 #endif // wxUSE_MINIDUMP
153
154 #endif // wxUSE_DBGHELP
155
156 // ----------------------------------------------------------------------------
157 // classes
158 // ----------------------------------------------------------------------------
159
160 // low level wxBusyCursor replacement: we use Win32 API directly here instead
161 // of going through wxWidgets calls as this could be dangerous
162 class BusyCursor
163 {
164 public:
165 BusyCursor()
166 {
167 }
168
169 ~BusyCursor()
170 {
171 }
172
173 private:
174 };
175
176 // the real crash report generator
177 class wxCrashReportImpl
178 {
179 public:
180 wxCrashReportImpl(const wxChar *filename);
181
182 bool Generate(int flags);
183
184 ~wxCrashReportImpl()
185 {
186 if ( m_hFile != INVALID_HANDLE_VALUE )
187 {
188 ::CloseHandle(m_hFile);
189 }
190 }
191
192 private:
193
194 // formatted output to m_hFile
195 void Output(const wxChar *format, ...);
196
197 // output end of line
198 void OutputEndl() { Output(_T("\r\n")); }
199
200 #if wxUSE_DBGHELP
201
202 #if !wxUSE_MINIDUMP
203 // translate exception code to its symbolic name
204 static wxString GetExceptionString(DWORD dwCode);
205
206 // return the type from "type index"
207 static BasicType GetBasicType(DWORD64 modBase, DWORD typeIndex);
208
209 // return the name for the type index
210 static wxString GetSymbolName(DWORD64 modBase, DWORD dwTypeIndex);
211
212 // return the string representation of the variable value
213 static wxString FormatSimpleValue(BasicType bt,
214 DWORD64 length,
215 PVOID pAddress);
216
217 // return string representation of a struct field (which may itself be a
218 // struct, of course)
219 static wxString FormatField(DWORD64 modBase,
220 DWORD dwTypeIndex,
221 void *pVariable,
222 unsigned level);
223
224 // show the name and value of the given symbol
225 static wxString FormatSymbol(PSYMBOL_INFO pSym, STACKFRAME *sf);
226
227 // show value described by SYMBOL_INFO located at pVariable
228 static wxString FormatAnyValue(PSYMBOL_INFO pSym, void *pVariable);
229
230 // show value of possibly complex (user-defined) type
231 static wxString FormatUDT(DWORD64 modBase,
232 DWORD dwTypeIndex,
233 void *pVariable,
234 unsigned level = 0);
235
236 // outputs information about the given symbol
237 void OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf);
238
239 // map address to module (and also section:offset), retunr true if ok
240 static bool GetLogicalAddress(PVOID addr,
241 PTSTR szModule,
242 DWORD len,
243 DWORD& section,
244 DWORD& offset);
245
246 // callback used with SymEnumSymbols() to process all variables
247 static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo,
248 ULONG SymbolSize,
249 PVOID UserContext);
250
251
252 // show the general information about exception which should be always
253 // available
254 //
255 // returns the module of the handle where the crash occured
256 HANDLE OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pCtx);
257
258 // output the call stack and local variables values
259 void OutputStack(const CONTEXT *pCtx, int flags);
260
261 // output the global variables values
262 void OutputGlobals(HANDLE hModuleCrash);
263
264
265 // the current stack frame (may be NULL)
266 STACKFRAME *m_sfCurrent;
267 #endif // !wxUSE_MINIDUMP
268
269 // load all the functions we need from dbghelp.dll, return true if all ok
270 bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp);
271
272
273 // dynamically loaded dbghelp.dll functions
274 #define DECLARE_SYM_FUNCTION(func) static func ## _t func
275
276 #if wxUSE_MINIDUMP
277 DECLARE_SYM_FUNCTION(MiniDumpWriteDump);
278 #else // !wxUSE_MINIDUMP
279 DECLARE_SYM_FUNCTION(SymSetOptions);
280 DECLARE_SYM_FUNCTION(SymInitialize);
281 DECLARE_SYM_FUNCTION(StackWalk);
282 DECLARE_SYM_FUNCTION(SymFromAddr);
283 DECLARE_SYM_FUNCTION(SymFunctionTableAccess);
284 DECLARE_SYM_FUNCTION(SymGetModuleBase);
285 DECLARE_SYM_FUNCTION(SymGetLineFromAddr);
286 DECLARE_SYM_FUNCTION(SymSetContext);
287 DECLARE_SYM_FUNCTION(SymEnumSymbols);
288 DECLARE_SYM_FUNCTION(SymGetTypeInfo);
289 #endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
290
291 #undef DECLARE_SYM_FUNCTION
292 #endif // wxUSE_DBGHELP
293
294 // the handle of the report file
295 HANDLE m_hFile;
296 };
297
298 // ----------------------------------------------------------------------------
299 // globals
300 // ----------------------------------------------------------------------------
301
302 // global pointer to exception information, only valid inside OnFatalException
303 extern WXDLLIMPEXP_BASE EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
304
305
306 // flag telling us whether the application wants to handle exceptions at all
307 static bool gs_handleExceptions = false;
308
309 // the file name where the report about exception is written
310 static wxChar gs_reportFilename[MAX_PATH];
311
312 // ============================================================================
313 // implementation
314 // ============================================================================
315
316 #if wxUSE_DBGHELP
317
318 #define DEFINE_SYM_FUNCTION(func) func ## _t wxCrashReportImpl::func = 0
319
320 #if wxUSE_MINIDUMP
321 DEFINE_SYM_FUNCTION(MiniDumpWriteDump);
322 #else // !wxUSE_MINIDUMP
323 DEFINE_SYM_FUNCTION(SymSetOptions);
324 DEFINE_SYM_FUNCTION(SymInitialize);
325 DEFINE_SYM_FUNCTION(StackWalk);
326 DEFINE_SYM_FUNCTION(SymFromAddr);
327 DEFINE_SYM_FUNCTION(SymFunctionTableAccess);
328 DEFINE_SYM_FUNCTION(SymGetModuleBase);
329 DEFINE_SYM_FUNCTION(SymGetLineFromAddr);
330 DEFINE_SYM_FUNCTION(SymSetContext);
331 DEFINE_SYM_FUNCTION(SymEnumSymbols);
332 DEFINE_SYM_FUNCTION(SymGetTypeInfo);
333 #endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
334
335 #undef DEFINE_SYM_FUNCTION
336
337 #endif // wxUSE_DBGHELP
338
339 // ----------------------------------------------------------------------------
340 // wxCrashReportImpl
341 // ----------------------------------------------------------------------------
342
343 wxCrashReportImpl::wxCrashReportImpl(const wxChar *filename)
344 {
345 }
346
347 void wxCrashReportImpl::Output(const wxChar *format, ...)
348 {
349 }
350
351 #if wxUSE_DBGHELP
352
353 #if !wxUSE_MINIDUMP
354
355 bool
356 wxCrashReportImpl::GetLogicalAddress(PVOID addr,
357 PTSTR szModule,
358 DWORD len,
359 DWORD& section,
360 DWORD& offset)
361 {
362 return false;
363 }
364
365 /* static */ BasicType
366 wxCrashReportImpl::GetBasicType(DWORD64 modBase, DWORD typeIndex)
367 {
368 return BASICTYPE_NOTYPE;
369 }
370
371 /* static */ wxString
372 wxCrashReportImpl::FormatSimpleValue(BasicType bt,
373 DWORD64 length,
374 PVOID pAddress)
375 {
376 wxString s;
377
378 return s;
379 }
380
381 /* static */
382 wxString wxCrashReportImpl::GetSymbolName(DWORD64 modBase, DWORD dwTypeIndex)
383 {
384 wxString s;
385
386 return s;
387 }
388
389 // this is called for the struct members/base classes
390 wxString
391 wxCrashReportImpl::FormatField(DWORD64 modBase,
392 DWORD dwTypeIndex,
393 void *pVariable,
394 unsigned level)
395 {
396 wxString s;
397
398 return s;
399 }
400
401 // If it's a user defined type (UDT), recurse through its members until we're
402 // at fundamental types.
403 wxString
404 wxCrashReportImpl::FormatUDT(DWORD64 modBase,
405 DWORD dwTypeIndex,
406 void *pVariable,
407 unsigned level)
408 {
409 wxString s;
410
411 return s;
412 }
413
414 // return the string containing the symbol of the given symbol
415 /* static */ wxString
416 wxCrashReportImpl::FormatAnyValue(PSYMBOL_INFO pSym, void *pVariable)
417 {
418 wxString s;
419
420 return s;
421 }
422
423 // display contents and type of the given variable
424 /* static */ wxString
425 wxCrashReportImpl::FormatSymbol(PSYMBOL_INFO pSym, STACKFRAME *sf)
426 {
427 wxString s;
428
429 return s;
430 }
431
432 void
433 wxCrashReportImpl::OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf)
434 {
435 }
436
437 // callback for SymEnumSymbols()
438 /* static */
439 BOOL CALLBACK
440 wxCrashReportImpl::EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo,
441 ULONG WXUNUSED(SymbolSize),
442 PVOID UserContext)
443 {
444 return false;
445 }
446
447 HANDLE
448 wxCrashReportImpl::OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord,
449 CONTEXT *pCtx)
450 {
451 return ::GetModuleHandle(szFaultingModule);
452 }
453
454 void wxCrashReportImpl::OutputStack(const CONTEXT *pCtx, int flags)
455 {
456 }
457
458 void wxCrashReportImpl::OutputGlobals(HANDLE hModule)
459 {
460 }
461
462 #endif // wxUSE_MINIDUMP
463
464 bool wxCrashReportImpl::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
465 {
466 return false;
467 }
468
469 #if !wxUSE_MINIDUMP
470
471 /* static */
472 wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
473 {
474 wxString s;
475
476 return s;
477 }
478
479 #endif // !wxUSE_MINIDUMP
480
481 #endif // wxUSE_DBGHELP
482
483 bool wxCrashReportImpl::Generate(
484 #if wxUSE_DBGHELP
485 int flags
486 #else
487 int WXUNUSED(flags)
488 #endif
489 )
490 {
491 return false;
492 }
493
494 // ----------------------------------------------------------------------------
495 // wxCrashReport
496 // ----------------------------------------------------------------------------
497
498 /* static */
499 void wxCrashReport::SetFileName(const wxChar *filename)
500 {
501 }
502
503 /* static */
504 const wxChar *wxCrashReport::GetFileName()
505 {
506 return NULL;
507 }
508
509 /* static */
510 bool wxCrashReport::Generate(int flags)
511 {
512 return false;
513 }
514
515 // ----------------------------------------------------------------------------
516 // wxApp::OnFatalException() support
517 // ----------------------------------------------------------------------------
518
519 bool wxHandleFatalExceptions(bool doit)
520 {
521 return true;
522 }
523
524 extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
525 {
526 return EXCEPTION_EXECUTE_HANDLER;
527 }
528
529 #else // !wxUSE_ON_FATAL_EXCEPTION
530
531 bool wxHandleFatalExceptions(bool WXUNUSED(doit))
532 {
533 return false;
534 }
535
536 #endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
537