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:
Vadim Zeitlin
2003-09-21 00:15:08 +00:00
parent 0b98a2524e
commit 2bbc1b2855

View File

@@ -10,8 +10,10 @@
///////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////
/* /*
The code in this file is heavily based on Matt Pietrek's column from The code generating the crash reports in this file is heavily based on
the March 2002 issue of MSDN Magazine. 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 #ifndef WX_PRECOMP
#endif //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/datetime.h"
#include "wx/dynload.h" #include "wx/dynload.h"
#include "wx/msw/crashrpt.h" #include "wx/msw/crashrpt.h"
@@ -68,6 +90,14 @@
// types of imagehlp.h functions // 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 DWORD (WINAPI *SymSetOptions_t)(DWORD);
typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL); typedef BOOL (WINAPI *SymInitialize_t)(HANDLE, LPSTR, BOOL);
typedef BOOL (WINAPI *StackWalk_t)(DWORD, HANDLE, HANDLE, LPSTACKFRAME, 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); PSYM_ENUMERATESYMBOLS_CALLBACK, PVOID);
typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG, typedef BOOL (WINAPI *SymGetTypeInfo_t)(HANDLE, DWORD64, ULONG,
IMAGEHLP_SYMBOL_TYPE_INFO, PVOID); IMAGEHLP_SYMBOL_TYPE_INFO, PVOID);
#endif // wxUSE_MINIDUMP
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// constant // constants
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
#if !wxUSE_MINIDUMP
// Stolen from CVCONST.H in the DIA 2.0 SDK // Stolen from CVCONST.H in the DIA 2.0 SDK
enum BasicType enum BasicType
{ {
@@ -131,6 +164,8 @@ enum SymbolTag
SYMBOL_TAG_BASECLASS SYMBOL_TAG_BASECLASS
}; };
#endif // wxUSE_MINIDUMP
#endif // wxUSE_DBGHELP #endif // wxUSE_DBGHELP
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@@ -154,6 +189,7 @@ public:
} }
private: private:
// formatted output to m_hFile // formatted output to m_hFile
void Output(const wxChar *format, ...); void Output(const wxChar *format, ...);
@@ -161,6 +197,8 @@ private:
void OutputEndl() { Output(_T("\r\n")); } void OutputEndl() { Output(_T("\r\n")); }
#if wxUSE_DBGHELP #if wxUSE_DBGHELP
#if !wxUSE_MINIDUMP
// translate exception code to its symbolic name // translate exception code to its symbolic name
static wxString GetExceptionString(DWORD dwCode); static wxString GetExceptionString(DWORD dwCode);
@@ -197,9 +235,6 @@ private:
// outputs information about the given symbol // outputs information about the given symbol
void OutputSymbol(PSYMBOL_INFO pSymInfo, STACKFRAME *sf); 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 // map address to module (and also section:offset), retunr true if ok
static bool GetLogicalAddress(PVOID addr, static bool GetLogicalAddress(PVOID addr,
PTSTR szModule, PTSTR szModule,
@@ -228,11 +263,18 @@ private:
// the current stack frame (may be NULL) // the current stack frame (may be NULL)
STACKFRAME *m_sfCurrent; 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 // dynamically loaded dbghelp.dll functions
#define DECLARE_SYM_FUNCTION(func) static func ## _t func #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(SymSetOptions);
DECLARE_SYM_FUNCTION(SymInitialize); DECLARE_SYM_FUNCTION(SymInitialize);
DECLARE_SYM_FUNCTION(StackWalk); DECLARE_SYM_FUNCTION(StackWalk);
@@ -243,6 +285,9 @@ private:
DECLARE_SYM_FUNCTION(SymSetContext); DECLARE_SYM_FUNCTION(SymSetContext);
DECLARE_SYM_FUNCTION(SymEnumSymbols); DECLARE_SYM_FUNCTION(SymEnumSymbols);
DECLARE_SYM_FUNCTION(SymGetTypeInfo); DECLARE_SYM_FUNCTION(SymGetTypeInfo);
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
#undef DECLARE_SYM_FUNCTION
#endif // wxUSE_DBGHELP #endif // wxUSE_DBGHELP
// the handle of the report file // 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 #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(SymSetOptions);
DEFINE_SYM_FUNCTION(SymInitialize); DEFINE_SYM_FUNCTION(SymInitialize);
DEFINE_SYM_FUNCTION(StackWalk); DEFINE_SYM_FUNCTION(StackWalk);
@@ -281,6 +329,7 @@ DEFINE_SYM_FUNCTION(SymGetLineFromAddr);
DEFINE_SYM_FUNCTION(SymSetContext); DEFINE_SYM_FUNCTION(SymSetContext);
DEFINE_SYM_FUNCTION(SymEnumSymbols); DEFINE_SYM_FUNCTION(SymEnumSymbols);
DEFINE_SYM_FUNCTION(SymGetTypeInfo); DEFINE_SYM_FUNCTION(SymGetTypeInfo);
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
#undef DEFINE_SYM_FUNCTION #undef DEFINE_SYM_FUNCTION
@@ -292,7 +341,7 @@ DEFINE_SYM_FUNCTION(SymGetTypeInfo);
wxCrashReportImpl::wxCrashReportImpl(const wxChar *filename) wxCrashReportImpl::wxCrashReportImpl(const wxChar *filename)
{ {
#if wxUSE_DBGHELP #if wxUSE_DBGHELP && !wxUSE_MINIDUMP
m_sfCurrent = NULL; m_sfCurrent = NULL;
#endif // wxUSE_DBGHELP #endif // wxUSE_DBGHELP
@@ -323,6 +372,8 @@ void wxCrashReportImpl::Output(const wxChar *format, ...)
#if wxUSE_DBGHELP #if wxUSE_DBGHELP
#if !wxUSE_MINIDUMP
bool bool
wxCrashReportImpl::GetLogicalAddress(PVOID addr, wxCrashReportImpl::GetLogicalAddress(PVOID addr,
PTSTR szModule, PTSTR szModule,
@@ -921,7 +972,9 @@ void wxCrashReportImpl::OutputGlobals(HANDLE hModule)
#endif // _M_IX86 #endif // _M_IX86
} }
bool wxCrashReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp) #endif // wxUSE_MINIDUMP
bool wxCrashReportImpl::BindDbgHelpFunctions(const wxDynamicLibrary& dllDbgHelp)
{ {
#define LOAD_SYM_FUNCTION(name) \ #define LOAD_SYM_FUNCTION(name) \
name = (name ## _t) dllDbgHelp.GetSymbol(_T(#name)); \ name = (name ## _t) dllDbgHelp.GetSymbol(_T(#name)); \
@@ -932,6 +985,9 @@ bool wxCrashReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
return false; \ return false; \
} }
#if wxUSE_MINIDUMP
LOAD_SYM_FUNCTION(MiniDumpWriteDump);
#else // !wxUSE_MINIDUMP
LOAD_SYM_FUNCTION(SymSetOptions); LOAD_SYM_FUNCTION(SymSetOptions);
LOAD_SYM_FUNCTION(SymInitialize); LOAD_SYM_FUNCTION(SymInitialize);
LOAD_SYM_FUNCTION(StackWalk); LOAD_SYM_FUNCTION(StackWalk);
@@ -942,12 +998,15 @@ bool wxCrashReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
LOAD_SYM_FUNCTION(SymSetContext); LOAD_SYM_FUNCTION(SymSetContext);
LOAD_SYM_FUNCTION(SymEnumSymbols); LOAD_SYM_FUNCTION(SymEnumSymbols);
LOAD_SYM_FUNCTION(SymGetTypeInfo); LOAD_SYM_FUNCTION(SymGetTypeInfo);
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
#undef LOAD_SYM_FUNCTION #undef LOAD_SYM_FUNCTION
return true; return true;
} }
#if !wxUSE_MINIDUMP
/* static */ /* static */
wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode) wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
{ {
@@ -1003,16 +1062,18 @@ wxString wxCrashReportImpl::GetExceptionString(DWORD dwCode)
return s; return s;
} }
#endif // !wxUSE_MINIDUMP
#endif // wxUSE_DBGHELP #endif // wxUSE_DBGHELP
// Remove warning // Remove warning
#if wxUSE_DBGHELP #if wxUSE_DBGHELP && !wxUSE_MINIDUMP
#define _WXUNUSED(x) x #define WXUNUSED_LOCAL(x) x
#else #else
#define _WXUNUSED WXUNUSED #define WXUNUSED_LOCAL WXUNUSED
#endif #endif
bool wxCrashReportImpl::Generate(int _WXUNUSED(flags)) bool wxCrashReportImpl::Generate(int WXUNUSED_LOCAL(flags))
{ {
if ( m_hFile == INVALID_HANDLE_VALUE ) if ( m_hFile == INVALID_HANDLE_VALUE )
return false; return false;
@@ -1021,6 +1082,7 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
if ( !wxGlobalSEInformation ) if ( !wxGlobalSEInformation )
return false; return false;
#if !wxUSE_MINIDUMP
PEXCEPTION_RECORD pExceptionRecord = wxGlobalSEInformation->ExceptionRecord; PEXCEPTION_RECORD pExceptionRecord = wxGlobalSEInformation->ExceptionRecord;
PCONTEXT pCtx = wxGlobalSEInformation->ContextRecord; PCONTEXT pCtx = wxGlobalSEInformation->ContextRecord;
@@ -1028,13 +1090,41 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
return false; return false;
HANDLE hModuleCrash = OutputBasicContext(pExceptionRecord, pCtx); HANDLE hModuleCrash = OutputBasicContext(pExceptionRecord, pCtx);
#endif // !wxUSE_MINIDUMP
// for everything else we need dbghelp.dll // for everything else we need dbghelp.dll
wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM); wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
if ( dllDbgHelp.IsLoaded() ) 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); SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_UNDNAME);
// Initialize DbgHelp // Initialize DbgHelp
@@ -1049,14 +1139,17 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
return true; return true;
} }
#endif // !wxUSE_MINIDUMP
} }
else else
{ {
Output(_T("Please update your dbghelp.dll version, ") Output(_T("\r\nPlease update your dbghelp.dll version, ")
_T("at least version 5.1 is needed!\r\n")); _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 ") Output(_T("Please install dbghelp.dll available free of charge ")
_T("from Microsoft to get more detailed crash information!")); _T("from Microsoft to get more detailed crash information!"));
@@ -1070,7 +1163,7 @@ bool wxCrashReportImpl::Generate(int _WXUNUSED(flags))
_T("in this wxWindows version.")); _T("in this wxWindows version."));
#endif // wxUSE_DBGHELP/!wxUSE_DBGHELP #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 // use PID and date to make the report file name more unique
wxString fname = wxString::Format wxString fname = wxString::Format
( (
#if wxUSE_MINIDUMP
_T("%s_%s_%lu.dmp"),
#else // !wxUSE_MINIDUMP
_T("%s_%s_%lu.rpt"), _T("%s_%s_%lu.rpt"),
#endif // wxUSE_MINIDUMP/!wxUSE_MINIDUMP
wxTheApp ? wxTheApp->GetAppName().c_str() wxTheApp ? wxTheApp->GetAppName().c_str()
: _T("wxwindows"), : _T("wxwindows"),
wxDateTime::Now().Format(_T("%Y%m%d")).c_str(), wxDateTime::Now().Format(_T("%Y%m%d")).c_str(),