]> git.saurik.com Git - wxWidgets.git/blame - src/palmos/crashrpt.cpp
reverted Robert's over-optimisation, correct fix coming soon
[wxWidgets.git] / src / palmos / crashrpt.cpp
CommitLineData
ffecfa5a
JS
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
80typedef 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
86typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
87typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
88typedef 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);
93typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
94typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD);
95typedef DWORD (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD);
96typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD,
97 PDWORD, PIMAGEHLP_LINE);
98typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME,
99 PIMAGEHLP_CONTEXT);
100typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR,
101 PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
102typedef 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
113enum 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
136enum 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
162class BusyCursor
163{
164public:
165 BusyCursor()
166 {
167 }
168
169 ~BusyCursor()
170 {
171 }
172
173private:
174};
175
176// the real crash report generator
177class wxCrashReportImpl
178{
179public:
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
192private:
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
303extern WXDLLIMPEXP_BASE EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
304
305
306// flag telling us whether the application wants to handle exceptions at all
307static bool gs_handleExceptions = false;
308
309// the file name where the report about exception is written
310static 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
321DEFINE_SYM_FUNCTION(MiniDumpWriteDump);
322#else // !wxUSE_MINIDUMP
323DEFINE_SYM_FUNCTION(SymSetOptions);
324DEFINE_SYM_FUNCTION(SymInitialize);
325DEFINE_SYM_FUNCTION(StackWalk);
326DEFINE_SYM_FUNCTION(SymFromAddr);
327DEFINE_SYM_FUNCTION(SymFunctionTableAccess);
328DEFINE_SYM_FUNCTION(SymGetModuleBase);
329DEFINE_SYM_FUNCTION(SymGetLineFromAddr);
330DEFINE_SYM_FUNCTION(SymSetContext);
331DEFINE_SYM_FUNCTION(SymEnumSymbols);
332DEFINE_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
343wxCrashReportImpl::wxCrashReportImpl(const wxChar *filename)
344{
345}
346
347void wxCrashReportImpl::Output(const wxChar *format, ...)
348{
349}
350
351#if wxUSE_DBGHELP
352
353#if !wxUSE_MINIDUMP
354
355bool
356wxCrashReportImpl::GetLogicalAddress(PVOID addr,
357 PTSTR szModule,
358 DWORD len,
359 DWORD& section,
360 DWORD& offset)
361{
362 return false;
363}
364
365/* static */ BasicType
366wxCrashReportImpl::GetBasicType(DWORD64 modBase, DWORD typeIndex)
367{
368 return BASICTYPE_NOTYPE;
369}
370
371/* static */ wxString
372wxCrashReportImpl::FormatSimpleValue(BasicType bt,
373 DWORD64 length,
374 PVOID pAddress)
375{
376 wxString s;
377
378 return s;
379}
380
381/* static */
382wxString 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
390wxString
391wxCrashReportImpl::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.
403wxString
404wxCrashReportImpl::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
416wxCrashReportImpl::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
425wxCrashReportImpl::FormatSymbol(PSYMBOL_INFO pSym, STACKFRAME *sf)
426{
427 wxString s;
428
429 return s;
430}
431
432void
433wxCrashReportImpl::OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf)
434{
435}
436
437// callback for SymEnumSymbols()
438/* static */
439BOOL CALLBACK
440wxCrashReportImpl::EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo,
441 ULONG WXUNUSED(SymbolSize),
442 PVOID UserContext)
443{
444 return false;
445}
446
447HANDLE
448wxCrashReportImpl::OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord,
449 CONTEXT *pCtx)
450{
451 return ::GetModuleHandle(szFaultingModule);
452}
453
454void wxCrashReportImpl::OutputStack(const CONTEXT *pCtx, int flags)
455{
456}
457
458void wxCrashReportImpl::OutputGlobals(HANDLE hModule)
459{
460}
461
462#endif // wxUSE_MINIDUMP
463
464bool wxCrashReportImpl::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
465{
466 return false;
467}
468
469#if !wxUSE_MINIDUMP
470
471/* static */
472wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
473{
474 wxString s;
475
476 return s;
477}
478
479#endif // !wxUSE_MINIDUMP
480
481#endif // wxUSE_DBGHELP
482
483bool 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 */
499void wxCrashReport::SetFileName(const wxChar *filename)
500{
501}
502
503/* static */
504const wxChar *wxCrashReport::GetFileName()
505{
506 return NULL;
507}
508
509/* static */
510bool wxCrashReport::Generate(int flags)
511{
512 return false;
513}
514
515// ----------------------------------------------------------------------------
516// wxApp::OnFatalException() support
517// ----------------------------------------------------------------------------
518
519bool wxHandleFatalExceptions(bool doit)
520{
521 return true;
522}
523
524extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
525{
526 return EXCEPTION_EXECUTE_HANDLER;
527}
528
529#else // !wxUSE_ON_FATAL_EXCEPTION
530
531bool wxHandleFatalExceptions(bool WXUNUSED(doit))
532{
533 return false;
534}
535
536#endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
537