📄 excepthandler.cpp
字号:
}
if (pExceptionInfo->ExceptionRecord->NumberParameters > 1)
Log(_T("Access Violation Address: 0x%08X\r\n"), pExceptionInfo->ExceptionRecord->ExceptionInformation[1]);
}
//Is the exception continuable
if (pExceptionInfo->ExceptionRecord->ExceptionFlags == 0)
Log(_T("Exception is continuable\r\n"));
else
Log(_T("Exception is noncontinuable\r\n"));
//Log where the fault occurred
DWORD dwOffset;
char pszSectionName[IMAGE_SIZEOF_SHORT_NAME+1];
if (GetAddressDetails(pExceptionInfo->ExceptionRecord->ExceptionAddress, m_szTempFileName, dwOffset, pszSectionName))
Log(_T("Exception Address Details: 0x%08X [%hs]:0x%08X %s\r\n"), pExceptionInfo->ExceptionRecord->ExceptionAddress, pszSectionName, dwOffset, m_szTempFileName);
else
{
//Fall back to just reporting the linear faulting address, rather than the additional details
Log(_T("Exception Address Details: 0x%08X [UNKNOWN]\r\n"), pExceptionInfo->ExceptionRecord->ExceptionAddress);
}
//Write out the full path to the process which is affected
GetModuleFileName(NULL, m_szTempFileName, _MAX_PATH);
Log(_T("Process Path: %s\r\n"), m_szTempFileName);
//Get the current working directory
GetCurrentDirectory(_MAX_PATH, m_szTempFileName);
Log(_T("Current Directory: %s\r\n"), m_szTempFileName);
//Get the current working directory
Log(_T("Command Line: %s\r\n"), GetCommandLine());
//Write out the Process and Thread ID
DWORD dwProcessID = GetCurrentProcessId();
Log(_T("Process ID: 0x%08X\r\n"), dwProcessID);
Log(_T("Thread ID where exception has occurred: 0x%08X\r\n"), GetCurrentThreadId());
//Initialize DBGHELP
HANDLE hProcess = GetCurrentProcess();
BOOL bInitDBGHelp = SymInitialize(hProcess, NULL, TRUE);
if (!bInitDBGHelp)
Log(_T(" Failed to initialize Debug Help Library, Error:%d\r\n"), GetLastError());
SymSetOptions(SYMOPT_DEFERRED_LOADS);
//Log details on each module in this process
HANDLE hToolHelp32Snap = INVALID_HANDLE_VALUE;
if (_ExceptionLoggerData.m_lpfnCreateToolhelp32Snapshot)
{
hToolHelp32Snap = _ExceptionLoggerData.m_lpfnCreateToolhelp32Snapshot(TH32CS_SNAPALL, 0);
if (hToolHelp32Snap != INVALID_HANDLE_VALUE)
{
//Log all the threads in the current process
Log(_T("\r\nThreads:\r\n"));
//Fill in the size of the structure before using it.
THREADENTRY32 te32;;
te32.dwSize = sizeof(THREADENTRY32);
//Walk the thread snapshot to find all threads of the process.
//If the thread belongs to the process, add its information
//to the display list.
if (_ExceptionLoggerData.m_lpfnThread32First(hToolHelp32Snap, &te32))
{
do
{
if (te32.th32OwnerProcessID == dwProcessID)
{
Log(_T(" Thread ID: 0x%08X\r\n"), te32.th32ThreadID);
Log(_T(" Priority Level: %d\r\n"), te32.tpBasePri);
Log(_T(" Delta Priority: %d\r\n"), te32.tpDeltaPri);
Log(_T(" References: %d\r\n"), te32.cntUsage);
//Write out some detailed info on each thread (over and above what ToolHelp32 gives you)
HANDLE hThread = _ExceptionLoggerData.m_lpfnOpenThread ? _ExceptionLoggerData.m_lpfnOpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID) : NULL;
if (hThread)
{
FILETIME ct;
FILETIME et;
FILETIME kt;
FILETIME ut;
if (GetThreadTimes(hThread, &ct, &et, &kt, &ut))
{
SYSTEMTIME st;
FileTimeToSystemTime(&ct, &st);
Log(_T(" Creation Time: %02d:%02d:%02d.%03d %d/%d/%d (D/M/Y)\r\n"), st.wHour, st.wMinute, st.wSecond, st.wMilliseconds, st.wDay, st.wMonth, st.wYear);
unsigned __int64 TimeTaken;
TimeTaken = (((unsigned __int64)kt.dwHighDateTime) << 32);
TimeTaken += kt.dwLowDateTime;
Log(_T(" Kernel Time (Seconds): %I64u\r\n"), TimeTaken/10000000);
TimeTaken = (((unsigned __int64)ut.dwHighDateTime) << 32);
TimeTaken += ut.dwLowDateTime;
Log(_T(" User Time: (Seconds) %I64u\r\n"), TimeTaken/10000000);
}
CloseHandle(hThread);
}
Log(_T("\r\n"));
}
}
while (_ExceptionLoggerData.m_lpfnThread32Next(hToolHelp32Snap, &te32));
}
else
Log(_T(" Failed in call to Thread32First, Error:%d\r\n"), GetLastError());
//Log all the modules in the current process
Log(_T("Modules:\r\n"));
//Fill in the size of the structure before using it.
MODULEENTRY32 me32;
me32.dwSize = sizeof(MODULEENTRY32);
//Walk the thread snapshot to find all threads of the process.
//If the thread belongs to the process, add its information
//to the display list.
if (_ExceptionLoggerData.m_lpfnModule32First(hToolHelp32Snap, &me32))
{
do
{
if (me32.th32ProcessID == dwProcessID)
{
Log(_T(" Name: %s\r\n"), me32.szModule);
Log(_T(" Path: %s\r\n"), me32.szExePath);
Log(_T(" Global Usage Count: %d\r\n"), me32.GlblcntUsage);
Log(_T(" Process Usage Count: %d\r\n"), me32.ProccntUsage);
Log(_T(" HMODULE: %08X\r\n"), me32.modBaseAddr);
Log(_T(" Size: %d\r\n"), me32.modBaseSize);
//Also display all the symbols for this module
if (bInitDBGHelp)
{
//display all the global variables
Log(_T("Variables for this Module\r\n"));
SymEnumSymbols(hProcess, (ULONG64)me32.modBaseAddr, 0, EnumSymbols, 0);
Log(_T("\r\n"));
}
}
}
while (_ExceptionLoggerData.m_lpfnModule32Next(hToolHelp32Snap, &me32));
}
else
Log(_T(" Failed in call to Module32First, Error:%d\r\n"), GetLastError());
//close the handle now that we are finished with it
CloseHandle(hToolHelp32Snap);
}
else
Log(_T(" Failed in call to CreateToolhelp32Snapshot, Error:%d\r\n"), GetLastError());
}
else
Log(_T("Threads / Modules: ToolHelp32 dll not availble, Cannot enumerate threads or modules\r\n"));
//Next thing to log is the i86 Registers
Log(_T("\r\nRegisters:\r\n EAX %08X\r\n"), pExceptionInfo->ContextRecord->Eax);
Log(_T(" EBX %08X\r\n"), pExceptionInfo->ContextRecord->Ebx);
Log(_T(" ECX %08X\r\n"), pExceptionInfo->ContextRecord->Ecx);
Log(_T(" EDX %08X\r\n"), pExceptionInfo->ContextRecord->Edx);
Log(_T(" ESI %08X\r\n"), pExceptionInfo->ContextRecord->Esi);
Log(_T(" EDI %08X\r\n"), pExceptionInfo->ContextRecord->Edi);
Log(_T(" CS:EIP %08X:%08X\r\n"), pExceptionInfo->ContextRecord->SegCs, pExceptionInfo->ContextRecord->Eip);
Log(_T(" SS:ESP %08X:%08X\r\n"), pExceptionInfo->ContextRecord->SegSs, pExceptionInfo->ContextRecord->Esp);
Log(_T(" EBP %08X\r\n"), pExceptionInfo->ContextRecord->SegSs, pExceptionInfo->ContextRecord->Ebp);
Log(_T(" DS %08X\r\n"), pExceptionInfo->ContextRecord->SegDs);
Log(_T(" ES %08X\r\n"), pExceptionInfo->ContextRecord->SegEs);
Log(_T(" FS %08X\r\n"), pExceptionInfo->ContextRecord->SegFs);
Log(_T(" GS %08X\r\n"), pExceptionInfo->ContextRecord->SegGs);
Log(_T(" Flags %08X\r\n"), pExceptionInfo->ContextRecord->EFlags);
//Next do the call stack
Log(_T("\r\nCall Stack:\r\n"));
LogStack(pExceptionInfo->ContextRecord, hProcess);
//Cleanup our usage of DBGHELP
SymCleanup(hProcess);
}
//A Helper function to allow use to do sprintf style logging to the crash log file.
//Please note that the file will be Unicode if you build using UNICODE.
int CExceptionLogger::Log(const TCHAR* format, ...)
{
//Generate the line
va_list args;
va_start(args, format);
int nLen = _vstprintf(m_szTempLogLine, format, args); //Note that we are using the C runtime here!!
va_end(args);
//write the line to disk
DWORD dwWritten = 0;
WriteFile(m_hLogFile, m_szTempLogLine, nLen*sizeof(TCHAR), &dwWritten, NULL);
return nLen;
}
//Coverts a linear address to a module, section, offset, name of section
BOOL CExceptionLogger::GetAddressDetails(void* pAddress, LPTSTR pszModule, DWORD& dwOffset, char* pszSectionName)
{
//First thing to do is we need to get the base address in memory (i.e. a HINSTANCE) from pAddress
MEMORY_BASIC_INFORMATION MemInfo;
if (!VirtualQuery(pAddress, &MemInfo, sizeof(MEMORY_BASIC_INFORMATION)))
return FALSE;
//From the HINSTANCE we can get the module name
HMODULE hModule = (HMODULE) MemInfo.AllocationBase;
if (!GetModuleFileName(hModule, pszModule, _MAX_PATH))
return FALSE;
//Now do our in memory traversal of the PE image to loop across the sections in that image
PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER) hModule;
PIMAGE_NT_HEADERS pNTHeader = (PIMAGE_NT_HEADERS) (((BYTE*)pDosHeader) + pDosHeader->e_lfanew);
PIMAGE_SECTION_HEADER pSection = IMAGE_FIRST_SECTION(pNTHeader);
//Express the "pAddress" parameter as an "RVA"
DWORD dwRVAAddress = (DWORD) ((BYTE*)pAddress - (BYTE*)MemInfo.AllocationBase);
//Loop across the sections to find the one which contains our faulting address
for (WORD i=0; i<pNTHeader->FileHeader.NumberOfSections; i++, pSection++)
{
DWORD dwSectionStart = pSection->VirtualAddress;
DWORD dwSectionEnd = dwSectionStart + max(pSection->SizeOfRawData, pSection->Misc.VirtualSize);
//Is the "pAddress" parameter (expressed as a RVA) inside this section?
if ((dwRVAAddress >= dwSectionStart) && (dwRVAAddress <= dwSectionEnd))
{
dwOffset = dwRVAAddress - dwSectionStart;
CopyMemory(pszSectionName, pSection->Name, IMAGE_SIZEOF_SHORT_NAME);
pszSectionName[IMAGE_SIZEOF_SHORT_NAME] = NULL; //Don't forget to NULL terminate the Section name
return TRUE;
}
}
//Got here, then return failure
return FALSE;
}
void CExceptionLogger::LogStack(CONTEXT* pContext, HANDLE hProcess)
{
//Variables required inside the loop
HANDLE hThread = GetCurrentThread();
//Initialize the STACKFRAME variable to start walking the stack from
STACKFRAME sf;
ZeroMemory(&sf, sizeof(STACKFRAME));
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;
//Now let's walk the walk
BOOL bContinue = TRUE;
while (bContinue)
{
if (StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &sf,
pContext, NULL, SymFunctionTableAccess, SymGetModuleBase, NULL))
{
DWORD dwOffset;
char pszSectionName[IMAGE_SIZEOF_SHORT_NAME+1];
if (GetAddressDetails((PVOID)sf.AddrPC.Offset, m_szTempFileName, dwOffset, pszSectionName))
Log(_T(" 0x%08X [%hs]:0x%08X %s"), sf.AddrPC.Offset, pszSectionName, dwOffset, m_szTempFileName);
else
{
//Fall back to just reporting the linear faulting address, rather than the additional details
Log(_T(" 0x%08X [UNKNOWN]"), sf.AddrPC.Offset);
}
//Get the Symbol Info for the offending address
SYMBOL_INFO* pSymbolInfo = (SYMBOL_INFO*) m_bySymbolInfo;
pSymbolInfo->SizeOfStruct = sizeof(m_bySymbolInfo);
pSymbolInfo->MaxNameLen = 1024;
DWORD64 SymbolOffset;
if (SymFromAddr(hProcess, sf.AddrPC.Offset, &SymbolOffset, pSymbolInfo))
Log(_T(" %hs+%I64X"), pSymbolInfo->Name, SymbolOffset);
//Get the source line if we can
IMAGEHLP_LINE LineInfo;
LineInfo.SizeOfStruct = sizeof(IMAGEHLP_LINE);
DWORD dwLineDisplacement;
if (SymGetLineFromAddr(hProcess, sf.AddrPC.Offset, &dwLineDisplacement, &LineInfo))
Log(_T(" %hs line %u"), LineInfo.FileName, LineInfo.LineNumber);
//Write out the variables at this stack frame
Log(_T("\r\n Variables\r\n"));
IMAGEHLP_STACK_FRAME imageHelpStackFrame;
imageHelpStackFrame.InstructionOffset = sf.AddrPC.Offset;
SymSetContext(hProcess, &imageHelpStackFrame, 0);
SymEnumSymbols(hProcess, 0, 0, EnumSymbols, &sf);
//Start the next stack frame log on a new line
Log(_T("\r\n"));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -