1 /////////////////////////////////////////////////////////////////////////////
2 // Name: palmos/crashrpt.cpp
3 // Purpose: helpers for structured exception handling (SEH)
4 // Author: William Osborne
8 // Copyright: (c) William Osborne
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
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.
19 // ============================================================================
21 // ============================================================================
23 // ----------------------------------------------------------------------------
25 // ----------------------------------------------------------------------------
27 // For compilers that support precompilation, includes "wx.h".
28 #include "wx/wxprec.h"
34 #if wxUSE_ON_FATAL_EXCEPTION
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.
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.
53 #define wxUSE_MINIDUMP 1
56 #include "wx/longlong.h"
57 #endif // wxUSE_MINIDUMP
59 #include "wx/datetime.h"
61 #include "wx/dynload.h"
63 #include "wx/palmos/crashrpt.h"
65 #include "wx/palmos/wrapwin.h"
66 #include "wx/palmos/private.h"
69 #define wxUSE_DBGHELP 0
74 // ----------------------------------------------------------------------------
75 // types of imagehlp.h functions
76 // ----------------------------------------------------------------------------
80 typedef BOOL (WINAPI
*MiniDumpWriteDump_t
)(HANDLE
, DWORD
, HANDLE
,
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
,
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
106 // ----------------------------------------------------------------------------
108 // ----------------------------------------------------------------------------
112 // Stolen from CVCONST.H in the DIA 2.0 SDK
115 BASICTYPE_NOTYPE
= 0,
125 BASICTYPE_ULONG
= 14,
126 BASICTYPE_CURRENCY
= 25,
128 BASICTYPE_VARIANT
= 27,
129 BASICTYPE_COMPLEX
= 28,
132 BASICTYPE_HRESULT
= 31
139 SYMBOL_TAG_FUNCTION
= 5,
141 SYMBOL_TAG_PUBLIC
= 10, // appears in .DBGs
144 SYMBOL_TAG_FUNCTION_TYPE
,
145 SYMBOL_TAG_POINTER_TYPE
,
146 SYMBOL_TAG_ARRAY_TYPE
,
147 SYMBOL_TAG_BASE_TYPE
,
152 #endif // wxUSE_MINIDUMP
154 #endif // wxUSE_DBGHELP
156 // ----------------------------------------------------------------------------
158 // ----------------------------------------------------------------------------
160 // low level wxBusyCursor replacement: we use Win32 API directly here instead
161 // of going through wxWidgets calls as this could be dangerous
176 // the real crash report generator
177 class wxCrashReportImpl
180 wxCrashReportImpl(const wxChar
*filename
);
182 bool Generate(int flags
);
186 if ( m_hFile
!= INVALID_HANDLE_VALUE
)
188 ::CloseHandle(m_hFile
);
194 // formatted output to m_hFile
195 void Output(const wxChar
*format
, ...);
197 // output end of line
198 void OutputEndl() { Output(_T("\r\n")); }
203 // translate exception code to its symbolic name
204 static wxString
GetExceptionString(DWORD dwCode
);
206 // return the type from "type index"
207 static BasicType
GetBasicType(DWORD64 modBase
, DWORD typeIndex
);
209 // return the name for the type index
210 static wxString
GetSymbolName(DWORD64 modBase
, DWORD dwTypeIndex
);
212 // return the string representation of the variable value
213 static wxString
FormatSimpleValue(BasicType bt
,
217 // return string representation of a struct field (which may itself be a
218 // struct, of course)
219 static wxString
FormatField(DWORD64 modBase
,
224 // show the name and value of the given symbol
225 static wxString
FormatSymbol(PSYMBOL_INFO pSym
, STACKFRAME
*sf
);
227 // show value described by SYMBOL_INFO located at pVariable
228 static wxString
FormatAnyValue(PSYMBOL_INFO pSym
, void *pVariable
);
230 // show value of possibly complex (user-defined) type
231 static wxString
FormatUDT(DWORD64 modBase
,
236 // outputs information about the given symbol
237 void OutputSymbol(PSYMBOL_INFO pSymInfo
, STACKFRAME
*sf
);
239 // map address to module (and also section:offset), retunr true if ok
240 static bool GetLogicalAddress(PVOID addr
,
246 // callback used with SymEnumSymbols() to process all variables
247 static BOOL CALLBACK
EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo
,
252 // show the general information about exception which should be always
255 // returns the module of the handle where the crash occured
256 HANDLE
OutputBasicContext(EXCEPTION_RECORD
*pExceptionRecord
, CONTEXT
*pCtx
);
258 // output the call stack and local variables values
259 void OutputStack(const CONTEXT
*pCtx
, int flags
);
261 // output the global variables values
262 void OutputGlobals(HANDLE hModuleCrash
);
265 // the current stack frame (may be NULL)
266 STACKFRAME
*m_sfCurrent
;
267 #endif // !wxUSE_MINIDUMP
269 // load all the functions we need from dbghelp.dll, return true if all ok
270 bool BindDbgHelpFunctions(const wxDynamicLibrary
& dllDbgHelp
);
273 // dynamically loaded dbghelp.dll functions
274 #define DECLARE_SYM_FUNCTION(func) static func ## _t func
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
291 #undef DECLARE_SYM_FUNCTION
292 #endif // wxUSE_DBGHELP
294 // the handle of the report file
298 // ----------------------------------------------------------------------------
300 // ----------------------------------------------------------------------------
302 // global pointer to exception information, only valid inside OnFatalException
303 extern WXDLLIMPEXP_BASE EXCEPTION_POINTERS
*wxGlobalSEInformation
= NULL
;
306 // flag telling us whether the application wants to handle exceptions at all
307 static bool gs_handleExceptions
= false;
309 // the file name where the report about exception is written
310 static wxChar gs_reportFilename
[MAX_PATH
];
312 // ============================================================================
314 // ============================================================================
318 #define DEFINE_SYM_FUNCTION(func) func ## _t wxCrashReportImpl::func = 0
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
335 #undef DEFINE_SYM_FUNCTION
337 #endif // wxUSE_DBGHELP
339 // ----------------------------------------------------------------------------
341 // ----------------------------------------------------------------------------
343 wxCrashReportImpl::wxCrashReportImpl(const wxChar
*filename
)
347 void wxCrashReportImpl::Output(const wxChar
*format
, ...)
356 wxCrashReportImpl::GetLogicalAddress(PVOID addr
,
365 /* static */ BasicType
366 wxCrashReportImpl::GetBasicType(DWORD64 modBase
, DWORD typeIndex
)
368 return BASICTYPE_NOTYPE
;
371 /* static */ wxString
372 wxCrashReportImpl::FormatSimpleValue(BasicType bt
,
382 wxString
wxCrashReportImpl::GetSymbolName(DWORD64 modBase
, DWORD dwTypeIndex
)
389 // this is called for the struct members/base classes
391 wxCrashReportImpl::FormatField(DWORD64 modBase
,
401 // If it's a user defined type (UDT), recurse through its members until we're
402 // at fundamental types.
404 wxCrashReportImpl::FormatUDT(DWORD64 modBase
,
414 // return the string containing the symbol of the given symbol
415 /* static */ wxString
416 wxCrashReportImpl::FormatAnyValue(PSYMBOL_INFO pSym
, void *pVariable
)
423 // display contents and type of the given variable
424 /* static */ wxString
425 wxCrashReportImpl::FormatSymbol(PSYMBOL_INFO pSym
, STACKFRAME
*sf
)
433 wxCrashReportImpl::OutputSymbol(PSYMBOL_INFO pSymInfo
, STACKFRAME
*sf
)
437 // callback for SymEnumSymbols()
440 wxCrashReportImpl::EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo
,
441 ULONG
WXUNUSED(SymbolSize
),
448 wxCrashReportImpl::OutputBasicContext(EXCEPTION_RECORD
*pExceptionRecord
,
451 return ::GetModuleHandle(szFaultingModule
);
454 void wxCrashReportImpl::OutputStack(const CONTEXT
*pCtx
, int flags
)
458 void wxCrashReportImpl::OutputGlobals(HANDLE hModule
)
462 #endif // wxUSE_MINIDUMP
464 bool wxCrashReportImpl::BindDbgHelpFunctions(const wxDynamicLibrary
& dllDbgHelp
)
472 wxString
wxCrashReportImpl::GetExceptionString(DWORD dwCode
)
479 #endif // !wxUSE_MINIDUMP
481 #endif // wxUSE_DBGHELP
483 bool wxCrashReportImpl::Generate(
494 // ----------------------------------------------------------------------------
496 // ----------------------------------------------------------------------------
499 void wxCrashReport::SetFileName(const wxChar
*filename
)
504 const wxChar
*wxCrashReport::GetFileName()
510 bool wxCrashReport::Generate(int flags
)
515 // ----------------------------------------------------------------------------
516 // wxApp::OnFatalException() support
517 // ----------------------------------------------------------------------------
519 bool wxHandleFatalExceptions(bool doit
)
524 extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS
*pExcPtrs
)
526 return EXCEPTION_EXECUTE_HANDLER
;
529 #else // !wxUSE_ON_FATAL_EXCEPTION
531 bool wxHandleFatalExceptions(bool WXUNUSED(doit
))
536 #endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION