mirror of
https://github.com/jmarshall23/Hellfire.git
synced 2026-08-11 23:40:51 +02:00
287 lines
8.5 KiB
C++
287 lines
8.5 KiB
C++
//******************************************************************
|
|
// except.cpp
|
|
//******************************************************************
|
|
|
|
|
|
#include "diablo.h"
|
|
#pragma hdrstop
|
|
#include <tchar.h>
|
|
|
|
|
|
//******************************************************************
|
|
// private
|
|
//******************************************************************
|
|
class CExcept {
|
|
public:
|
|
CExcept();
|
|
~CExcept();
|
|
|
|
private:
|
|
// entry point where control comes on an unhandled exception
|
|
static LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo);
|
|
|
|
// variables used by the class
|
|
static TCHAR m_szLogFileName[MAX_PATH];
|
|
static LPTOP_LEVEL_EXCEPTION_FILTER m_previousFilter;
|
|
};
|
|
|
|
TCHAR CExcept::m_szLogFileName[MAX_PATH];
|
|
LPTOP_LEVEL_EXCEPTION_FILTER CExcept::m_previousFilter;
|
|
static CExcept g_CExcept;
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void __cdecl tprintf(HANDLE hFile,LPCTSTR pszFmt,...) {
|
|
va_list argptr;
|
|
DWORD cbWritten;
|
|
TCHAR szBuf[1024];
|
|
va_start(argptr,pszFmt);
|
|
int nChars = wvsprintf(szBuf,pszFmt,argptr);
|
|
WriteFile(hFile,szBuf,nChars * sizeof(TCHAR),&cbWritten,0);
|
|
va_end(argptr);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
// 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!)
|
|
//******************************************************************
|
|
static BOOL GetLogicalAddress(
|
|
PVOID addr,
|
|
PTSTR szModule,
|
|
DWORD len,
|
|
DWORD *pdwSection,
|
|
DWORD *pdwOffset
|
|
) {
|
|
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
|
|
*pdwSection = i+1;
|
|
*pdwOffset = rva - sectionStart;
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE; // Should never get here!
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void IntelStackWalk(HANDLE hFile,PCONTEXT pContext) {
|
|
tprintf(hFile,_T("\r\nCall stack:\r\n"));
|
|
tprintf(hFile,_T("Address Frame Logical addr Module\r\n"));
|
|
|
|
DWORD pc = pContext->Eip;
|
|
PDWORD pFrame,pPrevFrame;
|
|
pFrame = (PDWORD)pContext->Ebp;
|
|
while (1) {
|
|
TCHAR szModule[MAX_PATH] = _T("");
|
|
DWORD section = 0,offset = 0;
|
|
|
|
GetLogicalAddress((PVOID)pc,szModule,sizeof(szModule),§ion,&offset);
|
|
tprintf(hFile,_T("%08X %08X %04X:%08X %s\r\n"),
|
|
pc,pFrame,section,offset,szModule);
|
|
|
|
// precede to next higher frame on stack
|
|
pc = pFrame[1];
|
|
pPrevFrame = pFrame;
|
|
pFrame = (PDWORD)pFrame[0];
|
|
// Frame pointer must be aligned on a DWORD boundary
|
|
if ((DWORD)pFrame & 3) break;
|
|
if (pFrame <= pPrevFrame) break;
|
|
|
|
// Can two DWORDs be read from the supposed frame address?
|
|
if (IsBadWritePtr(pFrame,sizeof(PVOID)*2)) break;
|
|
}
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static LPTSTR 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)
|
|
}
|
|
#undef EXCEPTION
|
|
|
|
// If not one of the "known" exceptions, try to
|
|
// get the string from NTDLL.DLL's message table.
|
|
static TCHAR szBuf[512] = { 0 };
|
|
FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_HMODULE,
|
|
GetModuleHandle(_T("NTDLL.DLL")),
|
|
dwCode,0,szBuf,sizeof(szBuf),0);
|
|
return szBuf;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
static void GenerateExceptionReport(HANDLE hFile,PEXCEPTION_POINTERS pExceptionInfo) {
|
|
PEXCEPTION_RECORD pExceptionRecord = pExceptionInfo->ExceptionRecord;
|
|
|
|
// First print information about the type of fault
|
|
tprintf(hFile,_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),
|
|
§ion,&offset);
|
|
|
|
tprintf(hFile,_T("Fault address: %08X %02X:%08X %s\r\n"),
|
|
pExceptionRecord->ExceptionAddress,
|
|
section,offset,szFaultingModule);
|
|
|
|
PCONTEXT pCtx = pExceptionInfo->ContextRecord;
|
|
|
|
// Show the registers
|
|
#ifdef _M_IX86 // Intel Only!
|
|
tprintf(hFile,_T("\r\nRegisters:\r\n"));
|
|
|
|
tprintf(hFile,_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(hFile,_T("CS:EIP:%04X:%08X\r\n"),pCtx->SegCs,pCtx->Eip);
|
|
tprintf(hFile,_T("SS:ESP:%04X:%08X EBP:%08X\r\n"),
|
|
pCtx->SegSs,pCtx->Esp,pCtx->Ebp);
|
|
tprintf(hFile,_T("DS:%04X ES:%04X FS:%04X GS:%04X\r\n"),
|
|
pCtx->SegDs,pCtx->SegEs,pCtx->SegFs,pCtx->SegGs);
|
|
tprintf(hFile,_T("Flags:%08X\r\n"),pCtx->EFlags);
|
|
|
|
// Walk the stack using x86 specific code
|
|
IntelStackWalk(hFile,pCtx);
|
|
|
|
#endif
|
|
|
|
tprintf(hFile,_T("\r\n"));
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
LONG WINAPI CExcept::ExceptionFilter(PEXCEPTION_POINTERS pExceptionInfo) {
|
|
|
|
// try opening the error report file in the program directory
|
|
// if we can't open the file, it may be because the app
|
|
// is running from a CDROM drive -- try opening a file
|
|
// with the same name in c:
|
|
HANDLE hFile;
|
|
for (int i = 0; i < 2; i++) {
|
|
hFile = CreateFile(
|
|
m_szLogFileName,
|
|
GENERIC_WRITE,
|
|
0,
|
|
0,
|
|
OPEN_ALWAYS,
|
|
FILE_FLAG_WRITE_THROUGH,
|
|
0
|
|
);
|
|
if (hFile != INVALID_HANDLE_VALUE) break;
|
|
|
|
// extract the file name
|
|
LPTSTR lpFName = _tcsrchr(m_szLogFileName,_T('\\'));
|
|
if (! lpFName) break;
|
|
|
|
// create full path to file in C:
|
|
TCHAR szTemp[MAX_PATH] = _T("c:\\");
|
|
_tcscat(szTemp,lpFName);
|
|
_tcscpy(m_szLogFileName,szTemp);
|
|
}
|
|
|
|
if (hFile != INVALID_HANDLE_VALUE) {
|
|
SetFilePointer(hFile,0,0,FILE_END);
|
|
GenerateExceptionReport(hFile,pExceptionInfo);
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (m_previousFilter) return m_previousFilter(pExceptionInfo);
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
CExcept::CExcept() {
|
|
// Install the unhandled exception filter function
|
|
m_previousFilter = SetUnhandledExceptionFilter(ExceptionFilter);
|
|
|
|
// Figure out what the report file will be named,and store it away
|
|
GetModuleFileName(0,m_szLogFileName,MAX_PATH);
|
|
|
|
// replace .EXE with .ERR
|
|
PTSTR pszDot = _tcsrchr(m_szLogFileName,_T('.'));
|
|
if (pszDot) {
|
|
pszDot++;
|
|
if (_tcslen(pszDot) >= 3)
|
|
_tcscpy(pszDot,_T("ERR"));
|
|
}
|
|
|
|
// delete any old exception reports
|
|
DeleteFile(m_szLogFileName);
|
|
}
|
|
|
|
|
|
//******************************************************************
|
|
//******************************************************************
|
|
CExcept::~CExcept() {
|
|
SetUnhandledExceptionFilter(m_previousFilter);
|
|
}
|