Files
wxWidgets/src/palmos/crashrpt.cpp
Julian Smart ffecfa5aeb Committed William Osborne's wxPalmOS port
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@29996 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2004-10-19 13:40:30 +00:00

538 lines
15 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: palmos/crashrpt.cpp
// Purpose: helpers for structured exception handling (SEH)
// Author: William Osborne
// Modified by:
// Created: 10/13/04
// RCS-ID: $Id:
// Copyright: (c) William Osborne
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
/*
The code generating the crash reports in this file is heavily based on
Matt Pietrek's column from the March 2002 issue of MSDN Magazine. Note
that this code is not currently used by default, however. In any case,
all bugs are my alone.
*/
// ============================================================================
// declarations
// ============================================================================
// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_ON_FATAL_EXCEPTION
#ifndef WX_PRECOMP
#endif //WX_PRECOMP
/*
We have two possibilities here: one, a priori more interesting, is to
generate the crash report ourselves and include the values of all the
variables in the dump. Unfortunately my code to do it doesn't work in
"real life" situations i.e. it works in small examples but invariably
gets confused by something in big programs which makes quite useless.
The other possibility is to let dbghelp.dll to do the work for us and
analyze its results later using a debugger with knowledge about crash
dumps, such as (free!) WinDbg. This also has another advantage of not
needing to ship the .pdb file (containing debug info) to the user. So
this is the default now, but I keep the old code just in case, and if
you really want you can still use it.
*/
#define wxUSE_MINIDUMP 1
#if !wxUSE_MINIDUMP
#include "wx/longlong.h"
#endif // wxUSE_MINIDUMP
#include "wx/datetime.h"
#include "wx/dynload.h"
#include "wx/palmos/crashrpt.h"
#include "wx/palmos/wrapwin.h"
#include "wx/palmos/private.h"
#ifndef wxUSE_DBGHELP
#define wxUSE_DBGHELP 0
#endif
#if wxUSE_DBGHELP
// ----------------------------------------------------------------------------
// types of imagehlp.h functions
// ----------------------------------------------------------------------------
#if wxUSE_MINIDUMP
typedef BOOL (WINAPI *MiniDumpWriteDump_t)(HANDLE, DWORD, HANDLE,
MINIDUMP_TYPE,
CONST PMINIDUMP_EXCEPTION_INFORMATION,
CONST PMINIDUMP_USER_STREAM_INFORMATION,
CONST PMINIDUMP_CALLBACK_INFORMATION);
#else // !wxUSE_MINIDUMP
typedef DWORD (WINAPI *SymSetOptions_t)(DWORD);
typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME,
LPVOID, PREAD_PROCESS_MEMORY_ROUTINE,
PFUNCTION_TABLE_ACCESS_ROUTINE,
PGET_MODULE_BASE_ROUTINE,
PTRANSLATE_ADDRESS_ROUTINE);
typedef BOOL (WINAPI *SymFromAddr_t)(HANDLE, DWORD64, PDWORD64, PSYMBOL_INFO);
typedef LPVOID (WINAPI *SymFunctionTableAccess_t)(HANDLE, DWORD);
typedef DWORD (WINAPI *SymGetModuleBase_t)(HANDLE, DWORD);
typedef BOOL (WINAPI *SymGetLineFromAddr_t)(HANDLE, DWORD,
PDWORD, PIMAGEHLP_LINE);
typedef BOOL (WINAPI *SymSetContext_t)(HANDLE, PIMAGEHLP_STACK_FRAME,
PIMAGEHLP_CONTEXT);
typedef BOOL (WINAPI *SymEnumSymbols_t)(HANDLE, ULONG64, PCSTR,
PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG,
IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
#endif // wxUSE_MINIDUMP
// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------
#if !wxUSE_MINIDUMP
// Stolen from CVCONST.H in the DIA 2.0 SDK
enum BasicType
{
BASICTYPE_NOTYPE = 0,
BASICTYPE_VOID = 1,
BASICTYPE_CHAR = 2,
BASICTYPE_WCHAR = 3,
BASICTYPE_INT = 6,
BASICTYPE_UINT = 7,
BASICTYPE_FLOAT = 8,
BASICTYPE_BCD = 9,
BASICTYPE_BOOL = 10,
BASICTYPE_LONG = 13,
BASICTYPE_ULONG = 14,
BASICTYPE_CURRENCY = 25,
BASICTYPE_DATE = 26,
BASICTYPE_VARIANT = 27,
BASICTYPE_COMPLEX = 28,
BASICTYPE_BIT = 29,
BASICTYPE_BSTR = 30,
BASICTYPE_HRESULT = 31
};
// Same as above
enum SymbolTag
{
SYMBOL_TAG_NULL,
SYMBOL_TAG_FUNCTION = 5,
SYMBOL_TAG_DATA = 7,
SYMBOL_TAG_PUBLIC = 10, // appears in .DBGs
SYMBOL_TAG_UDT,
SYMBOL_TAG_ENUM,
SYMBOL_TAG_FUNCTION_TYPE,
SYMBOL_TAG_POINTER_TYPE,
SYMBOL_TAG_ARRAY_TYPE,
SYMBOL_TAG_BASE_TYPE,
SYMBOL_TAG_TYPEDEF,
SYMBOL_TAG_BASECLASS
};
#endif // wxUSE_MINIDUMP
#endif // wxUSE_DBGHELP
// ----------------------------------------------------------------------------
// classes
// ----------------------------------------------------------------------------
// low level wxBusyCursor replacement: we use Win32 API directly here instead
// of going through wxWidgets calls as this could be dangerous
class BusyCursor
{
public:
BusyCursor()
{
}
~BusyCursor()
{
}
private:
};
// the real crash report generator
class wxCrashReportImpl
{
public:
wxCrashReportImpl(const wxChar *filename);
bool Generate(int flags);
~wxCrashReportImpl()
{
if ( m_hFile != INVALID_HANDLE_VALUE )
{
::CloseHandle(m_hFile);
}
}
private:
// formatted output to m_hFile
void Output(const wxChar *format, ...);
// output end of line
void OutputEndl() { Output(_T("\r\n")); }
#if wxUSE_DBGHELP
#if !wxUSE_MINIDUMP
// translate exception code to its symbolic name
static wxString GetExceptionString(DWORD dwCode);
// return the type from "type index"
static BasicType GetBasicType(DWORD64 modBase, DWORD typeIndex);
// return the name for the type index
static wxString GetSymbolName(DWORD64 modBase, DWORD dwTypeIndex);
// return the string representation of the variable value
static wxString FormatSimpleValue(BasicType bt,
DWORD64 length,
PVOID pAddress);
// return string representation of a struct field (which may itself be a
// struct, of course)
static wxString FormatField(DWORD64 modBase,
DWORD dwTypeIndex,
void *pVariable,
unsigned level);
// show the name and value of the given symbol
static wxString FormatSymbol(PSYMBOL_INFO pSym, STACKFRAME *sf);
// show value described by SYMBOL_INFO located at pVariable
static wxString FormatAnyValue(PSYMBOL_INFO pSym, void *pVariable);
// show value of possibly complex (user-defined) type
static wxString FormatUDT(DWORD64 modBase,
DWORD dwTypeIndex,
void *pVariable,
unsigned level = 0);
// outputs information about the given symbol
void OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf);
// map address to module (and also section:offset), retunr true if ok
static bool GetLogicalAddress(PVOID addr,
PTSTR szModule,
DWORD len,
DWORD& section,
DWORD& offset);
// callback used with SymEnumSymbols() to process all variables
static BOOL CALLBACK EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo,
ULONG SymbolSize,
PVOID UserContext);
// show the general information about exception which should be always
// available
//
// returns the module of the handle where the crash occured
HANDLE OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pCtx);
// output the call stack and local variables values
void OutputStack(const CONTEXT *pCtx, int flags);
// output the global variables values
void OutputGlobals(HANDLE hModuleCrash);
// the current stack frame (may be NULL)
STACKFRAME *m_sfCurrent;
#endif // !wxUSE_MINIDUMP
// load all the functions we need from dbghelp.dll, return true if all ok
bool BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp);
// dynamically loaded dbghelp.dll functions
#define DECLARE_SYM_FUNCTION(func) static func ## _t func
#if wxUSE_MINIDUMP
DECLARE_SYM_FUNCTION(MiniDumpWriteDump);
#else // !wxUSE_MINIDUMP
DECLARE_SYM_FUNCTION(SymSetOptions);
DECLARE_SYM_FUNCTION(SymInitialize);
DECLARE_SYM_FUNCTION(StackWalk);
DECLARE_SYM_FUNCTION(SymFromAddr);
DECLARE_SYM_FUNCTION(SymFunctionTableAccess);
DECLARE_SYM_FUNCTION(SymGetModuleBase);
DECLARE_SYM_FUNCTION(SymGetLineFromAddr);
DECLARE_SYM_FUNCTION(SymSetContext);
DECLARE_SYM_FUNCTION(SymEnumSymbols);
DECLARE_SYM_FUNCTION(SymGetTypeInfo);
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
#undef DECLARE_SYM_FUNCTION
#endif // wxUSE_DBGHELP
// the handle of the report file
HANDLE m_hFile;
};
// ----------------------------------------------------------------------------
// globals
// ----------------------------------------------------------------------------
// global pointer to exception information, only valid inside OnFatalException
extern WXDLLIMPEXP_BASE EXCEPTION_POINTERS *wxGlobalSEInformation = NULL;
// flag telling us whether the application wants to handle exceptions at all
static bool gs_handleExceptions = false;
// the file name where the report about exception is written
static wxChar gs_reportFilename[MAX_PATH];
// ============================================================================
// implementation
// ============================================================================
#if wxUSE_DBGHELP
#define DEFINE_SYM_FUNCTION(func) func ## _t wxCrashReportImpl::func = 0
#if wxUSE_MINIDUMP
DEFINE_SYM_FUNCTION(MiniDumpWriteDump);
#else // !wxUSE_MINIDUMP
DEFINE_SYM_FUNCTION(SymSetOptions);
DEFINE_SYM_FUNCTION(SymInitialize);
DEFINE_SYM_FUNCTION(StackWalk);
DEFINE_SYM_FUNCTION(SymFromAddr);
DEFINE_SYM_FUNCTION(SymFunctionTableAccess);
DEFINE_SYM_FUNCTION(SymGetModuleBase);
DEFINE_SYM_FUNCTION(SymGetLineFromAddr);
DEFINE_SYM_FUNCTION(SymSetContext);
DEFINE_SYM_FUNCTION(SymEnumSymbols);
DEFINE_SYM_FUNCTION(SymGetTypeInfo);
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
#undef DEFINE_SYM_FUNCTION
#endif // wxUSE_DBGHELP
// ----------------------------------------------------------------------------
// wxCrashReportImpl
// ----------------------------------------------------------------------------
wxCrashReportImpl::wxCrashReportImpl(const wxChar *filename)
{
}
void wxCrashReportImpl::Output(const wxChar *format, ...)
{
}
#if wxUSE_DBGHELP
#if !wxUSE_MINIDUMP
bool
wxCrashReportImpl::GetLogicalAddress(PVOID addr,
PTSTR szModule,
DWORD len,
DWORD& section,
DWORD& offset)
{
return false;
}
/* static */ BasicType
wxCrashReportImpl::GetBasicType(DWORD64 modBase, DWORD typeIndex)
{
return BASICTYPE_NOTYPE;
}
/* static */ wxString
wxCrashReportImpl::FormatSimpleValue(BasicType bt,
DWORD64 length,
PVOID pAddress)
{
wxString s;
return s;
}
/* static */
wxString wxCrashReportImpl::GetSymbolName(DWORD64 modBase, DWORD dwTypeIndex)
{
wxString s;
return s;
}
// this is called for the struct members/base classes
wxString
wxCrashReportImpl::FormatField(DWORD64 modBase,
DWORD dwTypeIndex,
void *pVariable,
unsigned level)
{
wxString s;
return s;
}
// If it's a user defined type (UDT), recurse through its members until we're
// at fundamental types.
wxString
wxCrashReportImpl::FormatUDT(DWORD64 modBase,
DWORD dwTypeIndex,
void *pVariable,
unsigned level)
{
wxString s;
return s;
}
// return the string containing the symbol of the given symbol
/* static */ wxString
wxCrashReportImpl::FormatAnyValue(PSYMBOL_INFO pSym, void *pVariable)
{
wxString s;
return s;
}
// display contents and type of the given variable
/* static */ wxString
wxCrashReportImpl::FormatSymbol(PSYMBOL_INFO pSym, STACKFRAME *sf)
{
wxString s;
return s;
}
void
wxCrashReportImpl::OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf)
{
}
// callback for SymEnumSymbols()
/* static */
BOOL CALLBACK
wxCrashReportImpl::EnumerateSymbolsCallback(PSYMBOL_INFO pSymInfo,
ULONG WXUNUSED(SymbolSize),
PVOID UserContext)
{
return false;
}
HANDLE
wxCrashReportImpl::OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord,
CONTEXT *pCtx)
{
return ::GetModuleHandle(szFaultingModule);
}
void wxCrashReportImpl::OutputStack(const CONTEXT *pCtx, int flags)
{
}
void wxCrashReportImpl::OutputGlobals(HANDLE hModule)
{
}
#endif // wxUSE_MINIDUMP
bool wxCrashReportImpl::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
{
return false;
}
#if !wxUSE_MINIDUMP
/* static */
wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
{
wxString s;
return s;
}
#endif // !wxUSE_MINIDUMP
#endif // wxUSE_DBGHELP
bool wxCrashReportImpl::Generate(
#if wxUSE_DBGHELP
int flags
#else
int WXUNUSED(flags)
#endif
)
{
return false;
}
// ----------------------------------------------------------------------------
// wxCrashReport
// ----------------------------------------------------------------------------
/* static */
void wxCrashReport::SetFileName(const wxChar *filename)
{
}
/* static */
const wxChar *wxCrashReport::GetFileName()
{
return NULL;
}
/* static */
bool wxCrashReport::Generate(int flags)
{
return false;
}
// ----------------------------------------------------------------------------
// wxApp::OnFatalException() support
// ----------------------------------------------------------------------------
bool wxHandleFatalExceptions(bool doit)
{
return true;
}
extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
{
return EXCEPTION_EXECUTE_HANDLER;
}
#else // !wxUSE_ON_FATAL_EXCEPTION
bool wxHandleFatalExceptions(bool WXUNUSED(doit))
{
return false;
}
#endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION