generate standard mini dumps instead of writing our own text file equivalent
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@23766 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -10,8 +10,10 @@
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/*
|
||||
The code in this file is heavily based on Matt Pietrek's column from
|
||||
the March 2002 issue of MSDN Magazine.
|
||||
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.
|
||||
*/
|
||||
|
||||
// ============================================================================
|
||||
@@ -34,8 +36,28 @@
|
||||
#ifndef WX_PRECOMP
|
||||
#endif //WX_PRECOMP
|
||||
|
||||
#include "wx/longlong.h"
|
||||
/*
|
||||
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/msw/crashrpt.h"
|
||||
@@ -68,6 +90,14 @@
|
||||
// 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,
|
||||
@@ -86,11 +116,14 @@ 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
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constant
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#if !wxUSE_MINIDUMP
|
||||
|
||||
// Stolen from CVCONST.H in the DIA 2.0 SDK
|
||||
enum BasicType
|
||||
{
|
||||
@@ -131,6 +164,8 @@ enum SymbolTag
|
||||
SYMBOL_TAG_BASECLASS
|
||||
};
|
||||
|
||||
#endif // wxUSE_MINIDUMP
|
||||
|
||||
#endif // wxUSE_DBGHELP
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -154,6 +189,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
// formatted output to m_hFile
|
||||
void Output(const wxChar *format, ...);
|
||||
|
||||
@@ -161,6 +197,8 @@ private:
|
||||
void OutputEndl() { Output(_T("\r\n")); }
|
||||
|
||||
#if wxUSE_DBGHELP
|
||||
|
||||
#if !wxUSE_MINIDUMP
|
||||
// translate exception code to its symbolic name
|
||||
static wxString GetExceptionString(DWORD dwCode);
|
||||
|
||||
@@ -197,9 +235,6 @@ private:
|
||||
// outputs information about the given symbol
|
||||
void OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf);
|
||||
|
||||
// load all the functions we need from dbghelp.dll, return true if all ok
|
||||
bool ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp);
|
||||
|
||||
// map address to module (and also section:offset), retunr true if ok
|
||||
static bool GetLogicalAddress(PVOID addr,
|
||||
PTSTR szModule,
|
||||
@@ -228,11 +263,18 @@ private:
|
||||
|
||||
// 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);
|
||||
@@ -243,6 +285,9 @@ private:
|
||||
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
|
||||
@@ -271,6 +316,9 @@ static wxChar gs_reportFilename[MAX_PATH];
|
||||
|
||||
#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);
|
||||
@@ -281,6 +329,7 @@ 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
|
||||
|
||||
@@ -292,7 +341,7 @@ DEFINE_SYM_FUNCTION(SymGetTypeInfo);
|
||||
|
||||
wxCrashReportImpl::wxCrashReportImpl(const wxChar *filename)
|
||||
{
|
||||
#if wxUSE_DBGHELP
|
||||
#if wxUSE_DBGHELP && !wxUSE_MINIDUMP
|
||||
m_sfCurrent = NULL;
|
||||
#endif // wxUSE_DBGHELP
|
||||
|
||||
@@ -323,6 +372,8 @@ void wxCrashReportImpl::Output(const wxChar *format, ...)
|
||||
|
||||
#if wxUSE_DBGHELP
|
||||
|
||||
#if !wxUSE_MINIDUMP
|
||||
|
||||
bool
|
||||
wxCrashReportImpl::GetLogicalAddress(PVOID addr,
|
||||
PTSTR szModule,
|
||||
@@ -921,7 +972,9 @@ void wxCrashReportImpl::OutputGlobals(HANDLE hModule)
|
||||
#endif // _M_IX86
|
||||
}
|
||||
|
||||
bool wxCrashReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
|
||||
#endif // wxUSE_MINIDUMP
|
||||
|
||||
bool wxCrashReportImpl::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
|
||||
{
|
||||
#define LOAD_SYM_FUNCTION(name) \
|
||||
name = (name ## _t) dllDbgHelp.GetSymbol(_T(#name)); \
|
||||
@@ -932,6 +985,9 @@ bool wxCrashReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
|
||||
return false; \
|
||||
}
|
||||
|
||||
#if wxUSE_MINIDUMP
|
||||
LOAD_SYM_FUNCTION(MiniDumpWriteDump);
|
||||
#else // !wxUSE_MINIDUMP
|
||||
LOAD_SYM_FUNCTION(SymSetOptions);
|
||||
LOAD_SYM_FUNCTION(SymInitialize);
|
||||
LOAD_SYM_FUNCTION(StackWalk);
|
||||
@@ -942,12 +998,15 @@ bool wxCrashReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
|
||||
LOAD_SYM_FUNCTION(SymSetContext);
|
||||
LOAD_SYM_FUNCTION(SymEnumSymbols);
|
||||
LOAD_SYM_FUNCTION(SymGetTypeInfo);
|
||||
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
|
||||
|
||||
#undef LOAD_SYM_FUNCTION
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#if !wxUSE_MINIDUMP
|
||||
|
||||
/* static */
|
||||
wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
|
||||
{
|
||||
@@ -1003,16 +1062,18 @@ wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
|
||||
return s;
|
||||
}
|
||||
|
||||
#endif // !wxUSE_MINIDUMP
|
||||
|
||||
#endif // wxUSE_DBGHELP
|
||||
|
||||
// Remove warning
|
||||
#if wxUSE_DBGHELP
|
||||
#define _WXUNUSED(x) x
|
||||
#if wxUSE_DBGHELP && !wxUSE_MINIDUMP
|
||||
#define WXUNUSED_LOCAL(x) x
|
||||
#else
|
||||
#define _WXUNUSED WXUNUSED
|
||||
#define WXUNUSED_LOCAL WXUNUSED
|
||||
#endif
|
||||
|
||||
bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
|
||||
bool wxCrashReportImpl::Generate(int WXUNUSED_LOCAL(flags))
|
||||
{
|
||||
if ( m_hFile == INVALID_HANDLE_VALUE )
|
||||
return false;
|
||||
@@ -1021,6 +1082,7 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
|
||||
if ( !wxGlobalSEInformation )
|
||||
return false;
|
||||
|
||||
#if !wxUSE_MINIDUMP
|
||||
PEXCEPTION_RECORD pExceptionRecord = wxGlobalSEInformation->ExceptionRecord;
|
||||
PCONTEXT pCtx = wxGlobalSEInformation->ContextRecord;
|
||||
|
||||
@@ -1028,13 +1090,41 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
|
||||
return false;
|
||||
|
||||
HANDLE hModuleCrash = OutputBasicContext(pExceptionRecord, pCtx);
|
||||
#endif // !wxUSE_MINIDUMP
|
||||
|
||||
|
||||
// for everything else we need dbghelp.dll
|
||||
wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
|
||||
if ( dllDbgHelp.IsLoaded() )
|
||||
{
|
||||
if ( ResolveSymFunctions(dllDbgHelp) )
|
||||
if ( BindDbgHelpFunctions(dllDbgHelp) )
|
||||
{
|
||||
#if wxUSE_MINIDUMP
|
||||
MINIDUMP_EXCEPTION_INFORMATION minidumpExcInfo;
|
||||
|
||||
minidumpExcInfo.ThreadId = ::GetCurrentThreadId();
|
||||
minidumpExcInfo.ExceptionPointers = wxGlobalSEInformation;
|
||||
minidumpExcInfo.ClientPointers = FALSE; // in our own address space
|
||||
|
||||
// do generate the dump
|
||||
if ( !MiniDumpWriteDump
|
||||
(
|
||||
::GetCurrentProcess(),
|
||||
::GetCurrentProcessId(),
|
||||
m_hFile, // file to write to
|
||||
MiniDumpNormal, // just the minimum
|
||||
&minidumpExcInfo,
|
||||
NULL, // no extra user-defined data
|
||||
NULL // no callbacks
|
||||
) )
|
||||
{
|
||||
Output(_T("MiniDumpWriteDump() failed."));
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else // !wxUSE_MINIDUMP
|
||||
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
|
||||
|
||||
// Initialize DbgHelp
|
||||
@@ -1049,14 +1139,17 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif // !wxUSE_MINIDUMP
|
||||
}
|
||||
else
|
||||
{
|
||||
Output(_T("Please update your dbghelp.dll version, ")
|
||||
_T("at least version 5.1 is needed!\r\n"));
|
||||
Output(_T("\r\nPlease update your dbghelp.dll version, ")
|
||||
_T("at least version 5.1 is needed!\r\n")
|
||||
_T("(if you already have a new version, please ")
|
||||
_T("put it in the same directory where the program is.)\r\n"));
|
||||
}
|
||||
}
|
||||
else
|
||||
else // failed to load dbghelp.dll
|
||||
{
|
||||
Output(_T("Please install dbghelp.dll available free of charge ")
|
||||
_T("from Microsoft to get more detailed crash information!"));
|
||||
@@ -1070,7 +1163,7 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
|
||||
_T("in this wxWindows version."));
|
||||
#endif // wxUSE_DBGHELP/!wxUSE_DBGHELP
|
||||
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -1125,7 +1218,11 @@ bool wxHandleFatalExceptions(bool doit)
|
||||
// use PID and date to make the report file name more unique
|
||||
wxString fname = wxString::Format
|
||||
(
|
||||
#if wxUSE_MINIDUMP
|
||||
_T("%s_%s_%lu.dmp"),
|
||||
#else // !wxUSE_MINIDUMP
|
||||
_T("%s_%s_%lu.rpt"),
|
||||
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
|
||||
wxTheApp ? wxTheApp->GetAppName().c_str()
|
||||
: _T("wxwindows"),
|
||||
wxDateTime::Now().Format(_T("%Y%m%d")).c_str(),
|
||||
|
Reference in New Issue
Block a user