wheatyexceptionreport.cpp
来自「一个FTP下载的源代码。代码质量非常高」· C++ 代码 · 共 1,021 行 · 第 1/3 页
CPP
1,021 行
CloseHandle( m_hReportFile );
m_hReportFile = 0;
}
END_CATCH_ALL
#endif
}
else
nError=GetLastError();
if (nError)
{
TCHAR tmp[1000];
_stprintf(tmp, _T("Unable to create exception report, error code %d."), nError);
MessageBox(0, tmp, _T("FileZilla - Unhandled eception"), MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
}
else
{
sendMail();
TCHAR tmp[1000];
_stprintf(tmp, _T("The exception report has been saved to \"%s\" and \"%s\".\n\
Please make sure that you are using the latest version of FileZilla.\n\
You can download the latest version from http://sourceforge.net/projects/filezilla/.\n\
If you do use the latest version, please send the exception report to Tim.Kosse@gmx.de along with a brief explanation what you did before FileZilla crashed."), m_szLogFileName, m_szDmpFileName);
MessageBox(0, tmp, _T("FileZilla - Unhandled eception"), MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
int *x=0;
*x=0;
FreeLibrary(hDll);
return EXCEPTION_EXECUTE_HANDLER;
}
}
FreeLibrary(hDll);
if ( m_previousFilter )
return m_previousFilter( pExceptionInfo );
else
return EXCEPTION_CONTINUE_SEARCH;
}
//===========================================================================
// Open the report file, and write the desired information to it. Called by
// WheatyUnhandledExceptionFilter
//===========================================================================
void WheatyExceptionReport::GenerateExceptionReport(
PEXCEPTION_POINTERS pExceptionInfo )
{
// Start out with a banner
_tprintf(_T("//=====================================================\r\n"));
_tprintf(_T("Exception report created by %s\r\n\r\n"), (LPCTSTR)GetVersionString());
_tprintf(_T("System details:\r\n"));
TCHAR buffer[200];
if (DisplaySystemVersion(buffer))
_tprintf(_T("%s\r\n"), buffer);
CProcessorInfo pi;
CMemoryInfo mi;
_tprintf(_T("%s\r\n"), (LPCTSTR)pi.GetProcessorName());
_tprintf(_T("%s\r\n\r\n"), (LPCTSTR)mi.GetMemoryInfo());
PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
// First print information about the type of fault
_tprintf( _T("Exception code: %08X %s\r\n"),
pExceptionRecord->ExceptionCode,
GetExceptionString(pExceptionRecord->ExceptionCode) );
// Now print information about where the fault occured
TCHAR szFaultingModule[MAX_PATH];
DWORD section, offset;
GetLogicalAddress( pExceptionRecord->ExceptionAddress,
szFaultingModule,
sizeof( szFaultingModule ),
section, offset );
_tprintf( _T("Fault address: %08X %02X:%08X %s\r\n"),
pExceptionRecord->ExceptionAddress,
section, offset, szFaultingModule );
PCONTEXT pCtx = pExceptionInfo->ContextRecord;
// Show the registers
#ifdef _M_IX86 // X86 Only!
_tprintf( _T("\r\nRegisters:\r\n") );
_tprintf(_T("EAX:%08X\r\nEBX:%08X\r\nECX:%08X\r\nEDX:%08X\r\nESI:%08X\r\nEDI:%08X\r\n")
,pCtx->Eax, pCtx->Ebx, pCtx->Ecx, pCtx->Edx,
pCtx->Esi, pCtx->Edi );
_tprintf( _T("CS:EIP:%04X:%08X\r\n"), pCtx->SegCs, pCtx->Eip );
_tprintf( _T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
pCtx->SegSs, pCtx->Esp, pCtx->Ebp );
_tprintf( _T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
pCtx->SegDs, pCtx->SegEs, pCtx->SegFs, pCtx->SegGs );
_tprintf( _T("Flags:%08X\r\n"), pCtx->EFlags );
#endif
// Set up the symbol engine.
DWORD dwOpts = pSymGetOptions() ;
// Turn on line loading and deferred loading.
pSymSetOptions( dwOpts |
SYMOPT_DEFERRED_LOADS |
SYMOPT_LOAD_LINES ) ;
// Initialize DbgHelp
if ( !pSymInitialize( GetCurrentProcess(), 0, TRUE ) )
return;
CONTEXT trashableContext = *pCtx;
WriteStackDetails( &trashableContext, false );
#ifdef _M_IX86 // X86 Only!
_tprintf( _T("========================\r\n") );
_tprintf( _T("Local Variables And Parameters\r\n") );
trashableContext = *pCtx;
WriteStackDetails( &trashableContext, true );
/*_tprintf( _T("========================\r\n") );
_tprintf( _T("Global Variables\r\n") );
SymEnumSymbols( GetCurrentProcess(),
(DWORD64)GetModuleHandle(szFaultingModule),
0, EnumerateSymbolsCallback, 0 );
*/
#endif // X86 Only!
pSymCleanup( GetCurrentProcess() );
_tprintf( _T("\r\n") );
}
//======================================================================
// Given an exception code, returns a pointer to a static string with a
// description of the exception
//======================================================================
LPTSTR WheatyExceptionReport::GetExceptionString( DWORD dwCode )
{
#define EXCEPTION( x ) case EXCEPTION_##x: return _T(#x);
switch ( dwCode )
{
EXCEPTION( ACCESS_VIOLATION )
EXCEPTION( DATATYPE_MISALIGNMENT )
EXCEPTION( BREAKPOINT )
EXCEPTION( SINGLE_STEP )
EXCEPTION( ARRAY_BOUNDS_EXCEEDED )
EXCEPTION( FLT_DENORMAL_OPERAND )
EXCEPTION( FLT_DIVIDE_BY_ZERO )
EXCEPTION( FLT_INEXACT_RESULT )
EXCEPTION( FLT_INVALID_OPERATION )
EXCEPTION( FLT_OVERFLOW )
EXCEPTION( FLT_STACK_CHECK )
EXCEPTION( FLT_UNDERFLOW )
EXCEPTION( INT_DIVIDE_BY_ZERO )
EXCEPTION( INT_OVERFLOW )
EXCEPTION( PRIV_INSTRUCTION )
EXCEPTION( IN_PAGE_ERROR )
EXCEPTION( ILLEGAL_INSTRUCTION )
EXCEPTION( NONCONTINUABLE_EXCEPTION )
EXCEPTION( STACK_OVERFLOW )
EXCEPTION( INVALID_DISPOSITION )
EXCEPTION( GUARD_PAGE )
EXCEPTION( INVALID_HANDLE )
}
// If not one of the "known" exceptions, try to get the string
// from NTDLL.DLL's message table.
static TCHAR szBuffer[512] = { 0 };
FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle( _T("NTDLL.DLL") ),
dwCode, 0, szBuffer, sizeof( szBuffer ), 0 );
return szBuffer;
}
//=============================================================================
// Given a linear address, locates the module, section, and offset containing
// that address.
//
// Note: the szModule paramater buffer is an output buffer of length specified
// by the len parameter (in characters!)
//=============================================================================
BOOL WheatyExceptionReport::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.
for ( unsigned i = 0;
i < pNtHdr->FileHeader.NumberOfSections;
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;
}
}
return FALSE; // Should never get here!
}
//============================================================
// Walks the stack, and writes the results to the report file
//============================================================
void WheatyExceptionReport::WriteStackDetails(
PCONTEXT pContext,
bool bWriteVariables ) // true if local/params should be output
{
USES_CONVERSION;
_tprintf( _T("\r\nCall stack:\r\n") );
_tprintf( _T("Address Frame Function SourceFile\r\n") );
DWORD dwMachineType = 0;
// Could use SymSetOptions here to add the SYMOPT_DEFERRED_LOADS flag
STACKFRAME sf;
memset( &sf, 0, sizeof(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 = pContext->Eip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Offset = pContext->Esp;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Offset = pContext->Ebp;
sf.AddrFrame.Mode = AddrModeFlat;
dwMachineType = IMAGE_FILE_MACHINE_I386;
#endif
while ( 1 )
{
// Get the next stack frame
if ( ! pStackWalk( dwMachineType,
m_hProcess,
GetCurrentThread(),
&sf,
pContext,
0,
pSymFunctionTableAccess,
pSymGetModuleBase,
0 ) )
break;
if ( 0 == sf.AddrFrame.Offset ) // Basic sanity check to make sure
break; // the frame is OK. Bail if not.
_tprintf( _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 ( pSymFromAddr(m_hProcess,sf.AddrPC.Offset,&symDisplacement,pSymbol))
{
_tprintf( _T("%hs+%I64X"), pSymbol->Name, symDisplacement );
}
else // No symbol found. Print out the logical address instead.
{
TCHAR szModule[MAX_PATH] = _T("");
DWORD section = 0, offset = 0;
GetLogicalAddress( (PVOID)sf.AddrPC.Offset,
szModule, sizeof(szModule), section, offset );
_tprintf( _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 ( pSymGetLineFromAddr( m_hProcess, sf.AddrPC.Offset,
&dwLineDisplacement, &lineInfo ) )
{
_tprintf(_T(" %s line %u"), A2T(lineInfo.FileName), lineInfo.LineNumber);
}
_tprintf( _T("\r\n") );
// Write out the variables, if desired
if ( bWriteVariables )
{
// Use SymSetContext to get just the locals/params for this frame
IMAGEHLP_STACK_FRAME imagehlpStackFrame;
imagehlpStackFrame.InstructionOffset = sf.AddrPC.Offset;
pSymSetContext( m_hProcess, &imagehlpStackFrame, 0 );
// Enumerate the locals/parameters
pSymEnumSymbols( m_hProcess, 0, 0, EnumerateSymbolsCallback, &sf );
_tprintf( _T("\r\n") );
}
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?