exceptionreport.cpp
来自「一个支持FTP,SFTP的客户端程序」· C++ 代码 · 共 703 行 · 第 1/2 页
CPP
703 行
// Print fault type
AddToReport("\r\nException Details:\r\n------------------\r\n\r\nException code: ");
AddToReportHex(pExceptionRecord->ExceptionCode, 8);
AddToReport(" ");
AddToReport(GetExceptionString(pExceptionRecord->ExceptionCode));
// Add fault address and module
TCHAR szModule[MAX_PATH];
memset(szModule, 0, MAX_PATH);
DWORD dwSection, dwOffset;
GetAddrDetails(pExceptionRecord->ExceptionAddress,
szModule,
sizeof(szModule),
dwSection, dwOffset);
AddToReport("\r\nFault address: ");
AddToReportHex((int)pExceptionRecord->ExceptionAddress, 8);
AddToReport(" ");
AddToReportHex(dwSection, 2);
AddToReport(":");
AddToReportHex(dwOffset, 8);
AddToReport(" ");
AddToReport(szModule);
AddToReport("\r\n");
// Set up the symbol engine.
DWORD dwOptions = pSymGetOptions() ;
// Turn on line loading and deferred loading.
pSymSetOptions(dwOptions | SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
PCONTEXT pContext = pExceptionInfo->ContextRecord;
// Initialize DbgHelp
if (!pSymInitialize(GetCurrentProcess(), 0, TRUE))
return;
StackWalk(*pContext);
pSymCleanup(GetCurrentProcess());
}
LPTSTR CExceptionReport::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)
}
// Try to get descripbion of unknown exceptions
static TCHAR buffer[512] = {0};
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
GetModuleHandle(_T("NTDLL.DLL")),
dwCode, 0, buffer, sizeof(buffer), 0);
return buffer;
}
void CExceptionReport::StackWalk(CONTEXT Context)
{
USES_CONVERSION;
AddToReport("\r\nCall stack:\r\n-----------\r\n\r\n");
AddToReport("Address Frame Function SourceFile\r\n");
DWORD dwMachineType = 0;
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 = Context.Eip;
sf.AddrPC.Mode = AddrModeFlat;
sf.AddrStack.Offset = Context.Esp;
sf.AddrStack.Mode = AddrModeFlat;
sf.AddrFrame.Offset = Context.Ebp;
sf.AddrFrame.Mode = AddrModeFlat;
dwMachineType = IMAGE_FILE_MACHINE_I386;
#endif
#ifdef _M_IX86
while (TRUE)
{
// Get next stack frame
if (!pStackWalk(dwMachineType, GetCurrentProcess(), GetCurrentThread(),
&sf, &Context, 0,
pSymFunctionTableAccess, pSymGetModuleBase, 0))
break;
if (!sf.AddrFrame.Offset)
break; //Invalid frame
AddToReportHex(sf.AddrPC.Offset, 8);
AddToReport(" ");
AddToReportHex(sf.AddrFrame.Offset, 8);
AddToReport(" ");
// Get function name for 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(GetCurrentProcess(), sf.AddrPC.Offset, &symDisplacement, pSymbol))
{
AddToReport(pSymbol->Name);
AddToReport("+");
AddToReportHex(symDisplacement);
}
else // No symbol found. Print out the logical address instead.
{
TCHAR szModule[MAX_PATH] = _T("");
DWORD section = 0, offset = 0;
GetAddrDetails((PVOID)sf.AddrPC.Offset,
szModule, sizeof(szModule), section, offset);
AddToReportHex(section, 4);
AddToReport(":");
AddToReportHex(offset, 8);
AddToReport(" ");
AddToReport(szModule);
}
// Get the source line for this stack frame entry
IMAGEHLP_LINE lineInfo = { sizeof(IMAGEHLP_LINE) };
DWORD dwLineDisplacement;
if (pSymGetLineFromAddr(GetCurrentProcess(), sf.AddrPC.Offset,
&dwLineDisplacement, &lineInfo))
{
AddToReport(" ");
AddToReport(lineInfo.FileName);
AddToReport(" line ");
AddToReport(lineInfo.LineNumber);
}
AddToReport("\r\n");
}
#else
AddToReport("Cannot dump stack yet on non-x86 systems!\r\n");
#endif
}
bool CExceptionReport::writeMiniDump(PEXCEPTION_POINTERS pExceptionInfo)
{
// Write the minidump to the file
MINIDUMP_EXCEPTION_INFORMATION eInfo;
eInfo.ThreadId = GetCurrentThreadId();
eInfo.ExceptionPointers = pExceptionInfo;
eInfo.ClientPointers = FALSE;
MINIDUMP_CALLBACK_INFORMATION cbMiniDump;
cbMiniDump.CallbackRoutine = 0;
cbMiniDump.CallbackParam = 0;
pMiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
m_hDumpFile,
MiniDumpNormal,
pExceptionInfo ? &eInfo : NULL,
NULL,
&cbMiniDump);
// Close file
CloseHandle(m_hDumpFile);
return true;
}
int CExceptionReport::sendMail()
{
CMailMsg mail;
mail.SetTo(_T("tim.kosse@gmx.de"), _T("Tim Kosse"));
TCHAR str[4096];
_stprintf(str, _T("Exception report created by %s\r\n\r\n"), (LPCTSTR)GetVersionString());
mail.SetSubject(str);
mail.SetMessage(_T("Enter your comments here, what did you do with FileZilla before it crashed?"));
mail.AddAttachment(m_pLogFileName, _T("FileZilla.rpt"));
mail.AddAttachment(m_pDmpFileName, _T("FileZilla.dmp"));
return mail.Send();
}
void CExceptionReport::SuspendThreads()
{
// Try to get OpenThread and Thread32* function from kernel32.dll, since it's not available on Win95/98
typedef HANDLE (WINAPI *tOpenThread) (DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId);
typedef BOOL (WINAPI *tThread32First) (HANDLE hSnapshot, LPTHREADENTRY32 lpte);
typedef BOOL (WINAPI *tThread32Next) (HANDLE hSnapshot, LPTHREADENTRY32 lpte);
typedef HANDLE (WINAPI *tCreateToolhelp32Snapshot) (DWORD dwFlags, DWORD th32ProcessID);
HMODULE hKernel32Dll = LoadLibrary(_T("kernel32.dll"));
if (!hKernel32Dll)
return;
tOpenThread pOpenThread = (tOpenThread) GetProcAddress(hKernel32Dll, "OpenThread");
tThread32First pThread32First = (tThread32First) GetProcAddress(hKernel32Dll, "Thread32First");
tThread32Next pThread32Next = (tThread32Next) GetProcAddress(hKernel32Dll, "Thread32Next");
tCreateToolhelp32Snapshot pCreateToolhelp32Snapshot = (tCreateToolhelp32Snapshot) GetProcAddress(hKernel32Dll, "CreateToolhelp32Snapshot");
if (!pOpenThread ||
!pThread32First ||
!pThread32Next ||
!pCreateToolhelp32Snapshot)
{
CloseHandle(hKernel32Dll);
return;
}
HANDLE hSnapshot = pCreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
// Get information about own process/thread
DWORD ownProcessId = GetCurrentProcessId();
DWORD ownThreadId = GetCurrentThreadId();
// Enumerate threads
THREADENTRY32 entry;
entry.dwSize = sizeof(THREADENTRY32);
BOOL bNext = pThread32First(hSnapshot, &entry);
while (bNext)
{
if (entry.th32OwnerProcessID == ownProcessId &&
entry.th32ThreadID != ownThreadId)
{
// Suspen threads of own process
HANDLE hThread = pOpenThread(THREAD_SUSPEND_RESUME, FALSE, entry.th32ThreadID);
if (hThread)
SuspendThread(hThread);
}
bNext = pThread32Next(hSnapshot, &entry);
}
CloseHandle(hKernel32Dll);
}
void CExceptionReport::AddToReport(const char * pText)
{
DWORD bytesWritten = 0;
WriteFile(m_hReportFile, pText, strlen(pText), &bytesWritten, 0);
}
void CExceptionReport::AddToReport(const WCHAR * pText)
{
USES_CONVERSION;
AddToReport(W2A(pText));
}
void CExceptionReport::AddToReport(int number)
{
char buffer[sizeof(int) * 4];
sprintf(buffer, "%d", number);
AddToReport(buffer);
}
void CExceptionReport::AddToReportHex(_int64 number, int minDigits /*=0*/)
{
char buffer[sizeof(_int64) * 2 + 1];
if (!minDigits)
sprintf(buffer, "%I64X", number);
else
{
char fmt[10];
sprintf(fmt, "%%0%dI64X", minDigits);
sprintf(buffer, fmt, number);
}
AddToReport(buffer);
}
BOOL CExceptionReport::GetAddrDetails(PVOID addr, PTSTR szModule, DWORD len, DWORD& section, DWORD& offset)
{
// Get details about an address: Module name, section and offet
// Get information about the provided address
MEMORY_BASIC_INFORMATION mbi;
if (!VirtualQuery(addr, &mbi, sizeof(mbi)))
return FALSE;
// Get module
DWORD hMod = (DWORD)mbi.AllocationBase;
if (!GetModuleFileName((HMODULE)hMod, szModule, len))
return FALSE;
// Get DOS header of module
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hMod;
// Advance to PE header and get the section information
PIMAGE_NT_HEADERS pNtHeader = (PIMAGE_NT_HEADERS)(hMod + pDosHeader->e_lfanew);
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNtHeader);
// Get module load address
DWORD lAddr = (DWORD)addr - hMod;
// Search for a section which contains the address
for (unsigned int i = 0; i < pNtHeader->FileHeader.NumberOfSections; i++)
{
// Calculate section start and end addresses
DWORD startAddr = pSection->VirtualAddress;
DWORD endAddr = startAddr;
if (pSection->SizeOfRawData > pSection->Misc.VirtualSize)
endAddr += pSection->SizeOfRawData;
else
pSection->Misc.VirtualSize;
// Look if provided address is between startAddr and endAddr
if (lAddr >= startAddr && lAddr <= endAddr)
{
// We've found the section, set section index and offset
section = i+1;
offset = lAddr - startAddr;
return TRUE;
}
pSection++;
}
// Section not found, very strange
return FALSE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?