wxSEHReport renamed to wxCrashReport enhanced and debugged; seems to work
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@21936 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
// Name: wx/msw/seh.h
|
// Name: wx/msw/crashrpt.h
|
||||||
// Purpose: helpers for the structured exception handling (SEH) under Win32
|
// Purpose: helpers for the structured exception handling (SEH) under Win32
|
||||||
// Author: Vadim Zeitlin
|
// Author: Vadim Zeitlin
|
||||||
// Modified by:
|
// Modified by:
|
||||||
@@ -17,10 +17,32 @@
|
|||||||
#if wxUSE_ON_FATAL_EXCEPTION
|
#if wxUSE_ON_FATAL_EXCEPTION
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// wxSEHReport: this class is used as a namespace for the SEH-related functions
|
// report generation flags
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct WXDLLIMPEXP_BASE wxSEHReport
|
enum
|
||||||
|
{
|
||||||
|
// we always report where the crash occured
|
||||||
|
wxCRASH_REPORT_LOCATION = 0,
|
||||||
|
|
||||||
|
// if this flag is given, the call stack is dumped
|
||||||
|
wxCRASH_REPORT_STACK = 1,
|
||||||
|
|
||||||
|
// if this flag is given, the values of the local variables are dumped
|
||||||
|
wxCRASH_REPORT_LOCALS = 2,
|
||||||
|
|
||||||
|
// if this flag is given, the values of all global variables are dumped
|
||||||
|
//
|
||||||
|
// WARNING: this may take a very long time and generate megabytes of output
|
||||||
|
// in a big program, this is why it is off by default
|
||||||
|
wxCRASH_REPORT_GLOBALS = 4
|
||||||
|
};
|
||||||
|
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
// wxCrashReport: this class is used to create crash reports
|
||||||
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct WXDLLIMPEXP_BASE wxCrashReport
|
||||||
{
|
{
|
||||||
// set the name of the file to which the report is written, it is
|
// set the name of the file to which the report is written, it is
|
||||||
// constructed from the .exe name by default
|
// constructed from the .exe name by default
|
||||||
@@ -31,7 +53,9 @@ struct WXDLLIMPEXP_BASE wxSEHReport
|
|||||||
|
|
||||||
// write the exception report to the file, return true if it could be done
|
// write the exception report to the file, return true if it could be done
|
||||||
// or false otherwise
|
// or false otherwise
|
||||||
static bool Generate();
|
static bool Generate(int flags = wxCRASH_REPORT_LOCATION |
|
||||||
|
wxCRASH_REPORT_STACK |
|
||||||
|
wxCRASH_REPORT_LOCALS);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // wxUSE_ON_FATAL_EXCEPTION
|
#endif // wxUSE_ON_FATAL_EXCEPTION
|
1116
src/msw/crashrpt.cpp
Normal file
1116
src/msw/crashrpt.cpp
Normal file
File diff suppressed because it is too large
Load Diff
585
src/msw/seh.cpp
585
src/msw/seh.cpp
@@ -1,585 +0,0 @@
|
|||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Name: msw/seh.cpp
|
|
||||||
// Purpose: helpers for structured exception handling (SEH)
|
|
||||||
// Author: Vadim Zeitlin
|
|
||||||
// Modified by:
|
|
||||||
// Created: 13.07.03
|
|
||||||
// RCS-ID: $Id$
|
|
||||||
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
|
|
||||||
// Licence: wxWindows licence
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
/*
|
|
||||||
The code in this file is heavily based on Matt Pietrek's column from
|
|
||||||
the 2002 issue of MSDN Magazine.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// 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
|
|
||||||
|
|
||||||
#include "wx/datetime.h"
|
|
||||||
#include "wx/dynload.h"
|
|
||||||
|
|
||||||
#include "wx/msw/seh.h"
|
|
||||||
|
|
||||||
#include <windows.h>
|
|
||||||
#include <imagehlp.h>
|
|
||||||
#include "wx/msw/private.h"
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// types of imagehlp.h functions
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// classes
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// the real crash report generator
|
|
||||||
class wxSEHReportImpl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
wxSEHReportImpl(const wxChar *filename);
|
|
||||||
|
|
||||||
bool Generate();
|
|
||||||
|
|
||||||
~wxSEHReportImpl()
|
|
||||||
{
|
|
||||||
if ( m_hFile != INVALID_HANDLE_VALUE )
|
|
||||||
{
|
|
||||||
::CloseHandle(m_hFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// formatted output to m_hFile
|
|
||||||
void Output(const wxChar *format, ...);
|
|
||||||
|
|
||||||
// translate exception code to its symbolic name
|
|
||||||
static wxString GetExceptionString(DWORD dwCode);
|
|
||||||
|
|
||||||
// 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,
|
|
||||||
DWORD len,
|
|
||||||
DWORD& section,
|
|
||||||
DWORD& offset);
|
|
||||||
|
|
||||||
|
|
||||||
// show the general information about exception which should be always
|
|
||||||
// available
|
|
||||||
bool OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord, CONTEXT *pCtx);
|
|
||||||
|
|
||||||
// output the call stack (pCtx may be modified, make copy before call!)
|
|
||||||
void OutputStack(CONTEXT *pCtx);
|
|
||||||
|
|
||||||
|
|
||||||
// the handle of the report file
|
|
||||||
HANDLE m_hFile;
|
|
||||||
|
|
||||||
// dynamically loaded dbghelp.dll functions
|
|
||||||
#define DECLARE_SYM_FUNCTION(func) func ## _t func
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// 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
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// wxSEHReport
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
wxSEHReportImpl::wxSEHReportImpl(const wxChar *filename)
|
|
||||||
{
|
|
||||||
m_hFile = ::CreateFile
|
|
||||||
(
|
|
||||||
filename,
|
|
||||||
GENERIC_WRITE,
|
|
||||||
0, // no sharing
|
|
||||||
NULL, // default security
|
|
||||||
CREATE_ALWAYS,
|
|
||||||
FILE_FLAG_WRITE_THROUGH,
|
|
||||||
NULL // no template file
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxSEHReportImpl::Output(const wxChar *format, ...)
|
|
||||||
{
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, format);
|
|
||||||
|
|
||||||
DWORD cbWritten;
|
|
||||||
|
|
||||||
wxString s = wxString::FormatV(format, argptr);
|
|
||||||
::WriteFile(m_hFile, s, s.length() * sizeof(wxChar), &cbWritten, 0);
|
|
||||||
|
|
||||||
va_end(argptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
wxSEHReportImpl::GetLogicalAddress(PVOID addr,
|
|
||||||
PTSTR szModule,
|
|
||||||
DWORD len,
|
|
||||||
DWORD& section,
|
|
||||||
DWORD& offset)
|
|
||||||
{
|
|
||||||
MEMORY_BASIC_INFORMATION mbi;
|
|
||||||
|
|
||||||
if ( !::VirtualQuery(addr, &mbi, sizeof(mbi)) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
DWORD hMod = (DWORD)mbi.AllocationBase;
|
|
||||||
|
|
||||||
if ( !::GetModuleFileName((HMODULE)hMod, szModule, len) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Point to the DOS header in memory
|
|
||||||
PIMAGE_DOS_HEADER pDosHdr = (PIMAGE_DOS_HEADER)hMod;
|
|
||||||
|
|
||||||
// From the DOS header, find the NT (PE) header
|
|
||||||
PIMAGE_NT_HEADERS pNtHdr = (PIMAGE_NT_HEADERS)(hMod + pDosHdr->e_lfanew);
|
|
||||||
|
|
||||||
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION( pNtHdr );
|
|
||||||
|
|
||||||
DWORD rva = (DWORD)addr - hMod; // RVA is offset from module load address
|
|
||||||
|
|
||||||
// Iterate through the section table, looking for the one that encompasses
|
|
||||||
// the linear address.
|
|
||||||
const DWORD nSections = pNtHdr->FileHeader.NumberOfSections;
|
|
||||||
for ( DWORD i = 0; i < nSections; i++, pSection++ )
|
|
||||||
{
|
|
||||||
DWORD sectionStart = pSection->VirtualAddress;
|
|
||||||
DWORD sectionEnd = sectionStart
|
|
||||||
+ max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
|
|
||||||
|
|
||||||
// Is the address in this section?
|
|
||||||
if ( (rva >= sectionStart) && (rva <= sectionEnd) )
|
|
||||||
{
|
|
||||||
// Yes, address is in the section. Calculate section and offset,
|
|
||||||
// and store in the "section" & "offset" params, which were
|
|
||||||
// passed by reference.
|
|
||||||
section = i + 1;
|
|
||||||
offset = rva - sectionStart;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// failed to map to logical address...
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
wxSEHReportImpl::OutputBasicContext(EXCEPTION_RECORD *pExceptionRecord,
|
|
||||||
CONTEXT *pCtx)
|
|
||||||
{
|
|
||||||
// First print information about the type of fault
|
|
||||||
const DWORD dwCode = pExceptionRecord->ExceptionCode;
|
|
||||||
Output(_T("Exception code: %s (%#08x)\r\n"),
|
|
||||||
GetExceptionString(dwCode).c_str(), dwCode);
|
|
||||||
|
|
||||||
// Now print information about where the fault occured
|
|
||||||
TCHAR szFaultingModule[MAX_PATH];
|
|
||||||
DWORD section,
|
|
||||||
offset;
|
|
||||||
void * const pExceptionAddress = pExceptionRecord->ExceptionAddress;
|
|
||||||
if ( !GetLogicalAddress(pExceptionAddress,
|
|
||||||
szFaultingModule,
|
|
||||||
WXSIZEOF(szFaultingModule),
|
|
||||||
section, offset) )
|
|
||||||
{
|
|
||||||
section =
|
|
||||||
offset = 0;
|
|
||||||
|
|
||||||
wxStrcpy(szFaultingModule, _T("<< unknown >>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Output(_T("Fault address: %08x %02x:%08x %s\r\n"),
|
|
||||||
pExceptionAddress, section, offset, szFaultingModule);
|
|
||||||
|
|
||||||
// Show the registers
|
|
||||||
#ifdef _M_IX86
|
|
||||||
Output( _T("\r\nRegisters:\r\n") );
|
|
||||||
|
|
||||||
Output(_T("EAX: %08x EBX: %08x ECX: %08x EDX: %08x ESI: %08x EDI: %08x\r\n"),
|
|
||||||
pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx, pCtx->Esi, pCtx->Edi);
|
|
||||||
|
|
||||||
Output(_T("CS:EIP: %04x:%08x SS:ESP: %04x:%08x EBP: %08x\r\n"),
|
|
||||||
pCtx->SegCs, pCtx->Eip, pCtx->SegSs, pCtx->Esp, pCtx->Ebp );
|
|
||||||
Output(_T("DS: %04x ES: %04x FS: %04x GS: %04x\r\n"),
|
|
||||||
pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs);
|
|
||||||
Output(_T("Flags: %08x\r\n"), pCtx->EFlags );
|
|
||||||
#endif // _M_IX86
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxSEHReportImpl::OutputStack(CONTEXT *pCtx)
|
|
||||||
{
|
|
||||||
Output(_T("\r\nCall stack:\r\n"));
|
|
||||||
|
|
||||||
Output(_T("Address Frame Function SourceFile\r\n"));
|
|
||||||
|
|
||||||
DWORD dwMachineType = 0;
|
|
||||||
|
|
||||||
STACKFRAME sf;
|
|
||||||
wxZeroMemory(sf);
|
|
||||||
|
|
||||||
#ifdef _M_IX86
|
|
||||||
// Initialize the STACKFRAME structure for the first call. This is only
|
|
||||||
// necessary for Intel CPUs, and isn't mentioned in the documentation.
|
|
||||||
sf.AddrPC.Offset = pCtx->Eip;
|
|
||||||
sf.AddrPC.Mode = AddrModeFlat;
|
|
||||||
sf.AddrStack.Offset = pCtx->Esp;
|
|
||||||
sf.AddrStack.Mode = AddrModeFlat;
|
|
||||||
sf.AddrFrame.Offset = pCtx->Ebp;
|
|
||||||
sf.AddrFrame.Mode = AddrModeFlat;
|
|
||||||
|
|
||||||
dwMachineType = IMAGE_FILE_MACHINE_I386;
|
|
||||||
#endif // _M_IX86
|
|
||||||
|
|
||||||
const HANDLE hProcess = GetCurrentProcess();
|
|
||||||
const HANDLE hThread = GetCurrentThread();
|
|
||||||
|
|
||||||
for ( ;; )
|
|
||||||
{
|
|
||||||
// Get the next stack frame
|
|
||||||
if ( !StackWalk(dwMachineType,
|
|
||||||
hProcess,
|
|
||||||
hThread,
|
|
||||||
&sf,
|
|
||||||
pCtx,
|
|
||||||
0,
|
|
||||||
SymFunctionTableAccess,
|
|
||||||
SymGetModuleBase,
|
|
||||||
0) )
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic sanity check to make sure the frame is OK.
|
|
||||||
if ( !sf.AddrFrame.Offset )
|
|
||||||
break;
|
|
||||||
|
|
||||||
Output(_T("%08x %08x "), sf.AddrPC.Offset, sf.AddrFrame.Offset);
|
|
||||||
|
|
||||||
// Get the name of the function for this stack frame entry
|
|
||||||
BYTE symbolBuffer[ sizeof(SYMBOL_INFO) + 1024 ];
|
|
||||||
PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)symbolBuffer;
|
|
||||||
pSymbol->SizeOfStruct = sizeof(symbolBuffer);
|
|
||||||
pSymbol->MaxNameLen = 1024;
|
|
||||||
DWORD64 symDisplacement = 0; // Displacement of the input address,
|
|
||||||
// relative to the start of the symbol
|
|
||||||
|
|
||||||
if ( SymFromAddr(hProcess, sf.AddrPC.Offset,
|
|
||||||
&symDisplacement,pSymbol) )
|
|
||||||
{
|
|
||||||
Output(_T("%hs() + %#08I64x"), pSymbol->Name, symDisplacement);
|
|
||||||
}
|
|
||||||
else // No symbol found. Print out the logical address instead.
|
|
||||||
{
|
|
||||||
TCHAR szModule[MAX_PATH];
|
|
||||||
DWORD section,
|
|
||||||
offset;
|
|
||||||
|
|
||||||
if ( !GetLogicalAddress((PVOID)sf.AddrPC.Offset,
|
|
||||||
szModule, sizeof(szModule),
|
|
||||||
section, offset) )
|
|
||||||
{
|
|
||||||
szModule[0] = _T('\0');
|
|
||||||
section =
|
|
||||||
offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Output(_T("%04x:%08x %s"), section, offset, szModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the source line for this stack frame entry
|
|
||||||
IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
|
|
||||||
DWORD dwLineDisplacement;
|
|
||||||
if ( SymGetLineFromAddr(hProcess, sf.AddrPC.Offset,
|
|
||||||
&dwLineDisplacement, &lineInfo ))
|
|
||||||
{
|
|
||||||
Output(_T(" %s line %u"), lineInfo.FileName, lineInfo.LineNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
Output(_T("\r\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wxSEHReportImpl::ResolveSymFunctions(const wxDynamicLibrary& dllDbgHelp)
|
|
||||||
{
|
|
||||||
#define LOAD_SYM_FUNCTION(name) \
|
|
||||||
name = (name ## _t) dllDbgHelp.GetSymbol(#name); \
|
|
||||||
if ( !name ) \
|
|
||||||
{ \
|
|
||||||
Output(_T("\r\nFunction ") __XFILE__(#name) \
|
|
||||||
_T("() not found.\r\n")); \
|
|
||||||
return false; \
|
|
||||||
}
|
|
||||||
|
|
||||||
LOAD_SYM_FUNCTION(SymSetOptions);
|
|
||||||
LOAD_SYM_FUNCTION(SymInitialize);
|
|
||||||
LOAD_SYM_FUNCTION(StackWalk);
|
|
||||||
LOAD_SYM_FUNCTION(SymFromAddr);
|
|
||||||
LOAD_SYM_FUNCTION(SymFunctionTableAccess);
|
|
||||||
LOAD_SYM_FUNCTION(SymGetModuleBase);
|
|
||||||
LOAD_SYM_FUNCTION(SymGetLineFromAddr);
|
|
||||||
|
|
||||||
#undef LOAD_SYM_FUNCTION
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool wxSEHReportImpl::Generate()
|
|
||||||
{
|
|
||||||
if ( m_hFile == INVALID_HANDLE_VALUE )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
PEXCEPTION_RECORD pExceptionRecord = wxGlobalSEInformation->ExceptionRecord;
|
|
||||||
PCONTEXT pCtx = wxGlobalSEInformation->ContextRecord;
|
|
||||||
|
|
||||||
if ( !OutputBasicContext(pExceptionRecord, pCtx) )
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// for everything else we need dbghelp.dll
|
|
||||||
wxDynamicLibrary dllDbgHelp(_T("dbghelp.dll"), wxDL_VERBATIM);
|
|
||||||
if ( dllDbgHelp.IsLoaded() )
|
|
||||||
{
|
|
||||||
if ( ResolveSymFunctions(dllDbgHelp) )
|
|
||||||
{
|
|
||||||
SymSetOptions(SYMOPT_DEFERRED_LOADS);
|
|
||||||
|
|
||||||
// Initialize DbgHelp
|
|
||||||
if ( SymInitialize(GetCurrentProcess(), NULL, TRUE /* invade */) )
|
|
||||||
{
|
|
||||||
CONTEXT ctxCopy = *pCtx;
|
|
||||||
|
|
||||||
OutputStack(&ctxCopy);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Output(_T("Please update your dbghelp.dll version, "
|
|
||||||
"at least version 6.0 is needed!\r\n"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Output(_T("Please install dbghelp.dll available free of charge ")
|
|
||||||
_T("from Microsoft to get more detailed crash information!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
Output(_T("\r\nLatest dbghelp.dll is available at "
|
|
||||||
"http://www.microsoft.com/whdc/ddk/debugging/\r\n"));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
wxString wxSEHReportImpl::GetExceptionString(DWORD dwCode)
|
|
||||||
{
|
|
||||||
wxString s;
|
|
||||||
|
|
||||||
#define CASE_EXCEPTION( x ) case EXCEPTION_##x: s = _T(#x); break
|
|
||||||
|
|
||||||
switch ( dwCode )
|
|
||||||
{
|
|
||||||
CASE_EXCEPTION(ACCESS_VIOLATION);
|
|
||||||
CASE_EXCEPTION(DATATYPE_MISALIGNMENT);
|
|
||||||
CASE_EXCEPTION(BREAKPOINT);
|
|
||||||
CASE_EXCEPTION(SINGLE_STEP);
|
|
||||||
CASE_EXCEPTION(ARRAY_BOUNDS_EXCEEDED);
|
|
||||||
CASE_EXCEPTION(FLT_DENORMAL_OPERAND);
|
|
||||||
CASE_EXCEPTION(FLT_DIVIDE_BY_ZERO);
|
|
||||||
CASE_EXCEPTION(FLT_INEXACT_RESULT);
|
|
||||||
CASE_EXCEPTION(FLT_INVALID_OPERATION);
|
|
||||||
CASE_EXCEPTION(FLT_OVERFLOW);
|
|
||||||
CASE_EXCEPTION(FLT_STACK_CHECK);
|
|
||||||
CASE_EXCEPTION(FLT_UNDERFLOW);
|
|
||||||
CASE_EXCEPTION(INT_DIVIDE_BY_ZERO);
|
|
||||||
CASE_EXCEPTION(INT_OVERFLOW);
|
|
||||||
CASE_EXCEPTION(PRIV_INSTRUCTION);
|
|
||||||
CASE_EXCEPTION(IN_PAGE_ERROR);
|
|
||||||
CASE_EXCEPTION(ILLEGAL_INSTRUCTION);
|
|
||||||
CASE_EXCEPTION(NONCONTINUABLE_EXCEPTION);
|
|
||||||
CASE_EXCEPTION(STACK_OVERFLOW);
|
|
||||||
CASE_EXCEPTION(INVALID_DISPOSITION);
|
|
||||||
CASE_EXCEPTION(GUARD_PAGE);
|
|
||||||
CASE_EXCEPTION(INVALID_HANDLE);
|
|
||||||
|
|
||||||
default:
|
|
||||||
// unknown exception, ask NTDLL for the name
|
|
||||||
if ( !::FormatMessage
|
|
||||||
(
|
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS |
|
|
||||||
FORMAT_MESSAGE_FROM_HMODULE,
|
|
||||||
::GetModuleHandle(_T("NTDLL.DLL")),
|
|
||||||
dwCode,
|
|
||||||
0,
|
|
||||||
wxStringBuffer(s, 1024),
|
|
||||||
1024,
|
|
||||||
0
|
|
||||||
) )
|
|
||||||
{
|
|
||||||
s = _T("UNKNOWN_EXCEPTION");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef CASE_EXCEPTION
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// wxSEHReport
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
void wxSEHReport::SetFileName(const wxChar *filename)
|
|
||||||
{
|
|
||||||
wxStrncpy(gs_reportFilename, filename, WXSIZEOF(gs_reportFilename) - 1);
|
|
||||||
gs_reportFilename[WXSIZEOF(gs_reportFilename) - 1] = _T('\0');
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
const wxChar *wxSEHReport::GetFileName()
|
|
||||||
{
|
|
||||||
return gs_reportFilename;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* static */
|
|
||||||
bool wxSEHReport::Generate()
|
|
||||||
{
|
|
||||||
wxSEHReportImpl impl(gs_reportFilename);
|
|
||||||
|
|
||||||
return impl.Generate();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// wxApp::OnFatalException() support
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
bool wxHandleFatalExceptions(bool doit)
|
|
||||||
{
|
|
||||||
// assume this can only be called from the main thread
|
|
||||||
gs_handleExceptions = doit;
|
|
||||||
|
|
||||||
if ( doit )
|
|
||||||
{
|
|
||||||
// try to find a place where we can put out report file later
|
|
||||||
if ( !::GetTempPath
|
|
||||||
(
|
|
||||||
WXSIZEOF(gs_reportFilename),
|
|
||||||
gs_reportFilename
|
|
||||||
) )
|
|
||||||
{
|
|
||||||
wxLogLastError(_T("GetTempPath"));
|
|
||||||
|
|
||||||
// when all else fails...
|
|
||||||
wxStrcpy(gs_reportFilename, _T("c:\\"));
|
|
||||||
}
|
|
||||||
|
|
||||||
// use PID and date to make the report file name more unique
|
|
||||||
wxString fname = wxString::Format
|
|
||||||
(
|
|
||||||
_T("%s_%s_%lu.rpt"),
|
|
||||||
wxTheApp ? wxTheApp->GetAppName().c_str()
|
|
||||||
: _T("wxwindows"),
|
|
||||||
wxDateTime::Now().Format(_T("%Y%m%d")).c_str(),
|
|
||||||
::GetCurrentProcessId()
|
|
||||||
);
|
|
||||||
|
|
||||||
wxStrncat(gs_reportFilename, fname,
|
|
||||||
WXSIZEOF(gs_reportFilename) - strlen(gs_reportFilename) - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
extern unsigned long wxGlobalSEHandler(EXCEPTION_POINTERS *pExcPtrs)
|
|
||||||
{
|
|
||||||
if ( gs_handleExceptions && wxTheApp )
|
|
||||||
{
|
|
||||||
// store the pointer to exception info
|
|
||||||
wxGlobalSEInformation = pExcPtrs;
|
|
||||||
|
|
||||||
// give the user a chance to do something special about this
|
|
||||||
wxTheApp->OnFatalException();
|
|
||||||
|
|
||||||
wxGlobalSEInformation = NULL;
|
|
||||||
|
|
||||||
// this will execute our handler and terminate the process
|
|
||||||
return EXCEPTION_EXECUTE_HANDLER;
|
|
||||||
}
|
|
||||||
|
|
||||||
return EXCEPTION_CONTINUE_SEARCH;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else // !wxUSE_ON_FATAL_EXCEPTION
|
|
||||||
|
|
||||||
bool wxHandleFatalExceptions(bool WXUNUSED(doit))
|
|
||||||
{
|
|
||||||
wxFAIL_MSG(_T("set wxUSE_ON_FATAL_EXCEPTION to 1 to use this function"));
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // wxUSE_ON_FATAL_EXCEPTION/!wxUSE_ON_FATAL_EXCEPTION
|
|
||||||
|
|
Reference in New Issue
Block a user