2022-12-23 02:56:40 +01:00
|
|
|
//=============================================================================//
|
|
|
|
//
|
2022-12-26 20:11:37 +01:00
|
|
|
// Purpose: Crash handler (overrides the game's implementation!)
|
2022-12-23 02:56:40 +01:00
|
|
|
//
|
|
|
|
//=============================================================================//
|
2023-05-10 00:05:38 +02:00
|
|
|
#include "tier0/binstream.h"
|
2022-12-27 02:28:43 +01:00
|
|
|
#include "tier0/cpu.h"
|
2023-01-31 22:13:40 +01:00
|
|
|
#include "tier0/crashhandler.h"
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-28 21:38:47 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::Start()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
AcquireSRWLockExclusive(&m_Lock);
|
2022-12-28 21:38:47 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::End()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
ReleaseSRWLockExclusive(&m_Lock);
|
2022-12-28 21:38:47 +01:00
|
|
|
}
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-26 20:33:09 +01:00
|
|
|
// Purpose: formats the crasher (module, address and exception)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatCrash()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("crash:\n{\n");
|
2022-12-26 20:33:09 +01:00
|
|
|
|
|
|
|
FormatExceptionAddress();
|
|
|
|
FormatExceptionCode();
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("}\n");
|
2022-12-26 20:33:09 +01:00
|
|
|
}
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-26 20:33:09 +01:00
|
|
|
// Purpose: formats the captured callstack
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatCallstack()
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("callstack:\n{\n");
|
2022-12-27 13:19:57 +01:00
|
|
|
|
|
|
|
if (m_nCapturedFrames)
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
const PEXCEPTION_RECORD pExceptionRecord = m_pExceptionPointers->ExceptionRecord;
|
|
|
|
|
2022-12-27 13:19:57 +01:00
|
|
|
if (m_ppStackTrace[m_nCapturedFrames - 1] == pExceptionRecord->ExceptionAddress)
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
const PCONTEXT pContextRecord = m_pExceptionPointers->ContextRecord;
|
2022-12-27 13:19:57 +01:00
|
|
|
MEMORY_BASIC_INFORMATION mbi = { 0 };
|
2024-02-04 00:55:07 +01:00
|
|
|
|
|
|
|
const SIZE_T t = VirtualQuery((LPCVOID)pContextRecord->Rsp, &mbi, sizeof(LPCVOID));
|
2022-12-27 13:19:57 +01:00
|
|
|
|
|
|
|
if (t >= sizeof(mbi)
|
|
|
|
&& !(mbi.Protect & PAGE_NOACCESS)
|
2024-02-04 00:55:07 +01:00
|
|
|
&& (mbi.Protect & (PAGE_READONLY | PAGE_READWRITE))
|
2022-12-27 13:19:57 +01:00
|
|
|
&& (mbi.State & MEM_COMMIT))
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("\t// call stack ended; possible return address?\n");
|
2022-12-27 13:19:57 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2022-12-26 20:33:09 +01:00
|
|
|
for (WORD i = 0; i < m_nCapturedFrames; i++)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2022-12-26 20:33:09 +01:00
|
|
|
FormatExceptionAddress(reinterpret_cast<LPCSTR>(m_ppStackTrace[i]));
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
2022-12-27 13:19:57 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("}\n");
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-26 20:33:09 +01:00
|
|
|
// Purpose: formats all the registers and their contents
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatRegisters()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("registers:\n{\n");
|
|
|
|
const PCONTEXT pContextRecord = m_pExceptionPointers->ContextRecord;
|
2022-12-27 13:19:57 +01:00
|
|
|
|
2023-01-04 14:55:58 +01:00
|
|
|
FormatALU("rax", pContextRecord->Rax);
|
|
|
|
FormatALU("rbx", pContextRecord->Rbx);
|
|
|
|
FormatALU("rcx", pContextRecord->Rcx);
|
|
|
|
FormatALU("rdx", pContextRecord->Rdx);
|
|
|
|
FormatALU("rsp", pContextRecord->Rsp);
|
|
|
|
FormatALU("rbp", pContextRecord->Rbp);
|
|
|
|
FormatALU("rsi", pContextRecord->Rsi);
|
|
|
|
FormatALU("rdi", pContextRecord->Rdi);
|
|
|
|
FormatALU("r8 ", pContextRecord->R8);
|
|
|
|
FormatALU("r9 ", pContextRecord->R9);
|
|
|
|
FormatALU("r10", pContextRecord->R10);
|
|
|
|
FormatALU("r11", pContextRecord->R11);
|
|
|
|
FormatALU("r12", pContextRecord->R12);
|
|
|
|
FormatALU("r13", pContextRecord->R13);
|
|
|
|
FormatALU("r14", pContextRecord->R14);
|
|
|
|
FormatALU("r15", pContextRecord->R15);
|
|
|
|
FormatALU("rip", pContextRecord->Rip);
|
2022-12-27 13:19:57 +01:00
|
|
|
|
2022-12-26 20:33:09 +01:00
|
|
|
FormatFPU("xmm0 ", &pContextRecord->Xmm0);
|
|
|
|
FormatFPU("xmm1 ", &pContextRecord->Xmm1);
|
|
|
|
FormatFPU("xmm2 ", &pContextRecord->Xmm2);
|
|
|
|
FormatFPU("xmm3 ", &pContextRecord->Xmm3);
|
|
|
|
FormatFPU("xmm4 ", &pContextRecord->Xmm4);
|
|
|
|
FormatFPU("xmm5 ", &pContextRecord->Xmm5);
|
|
|
|
FormatFPU("xmm6 ", &pContextRecord->Xmm6);
|
|
|
|
FormatFPU("xmm7 ", &pContextRecord->Xmm7);
|
|
|
|
FormatFPU("xmm8 ", &pContextRecord->Xmm8);
|
|
|
|
FormatFPU("xmm9 ", &pContextRecord->Xmm9);
|
|
|
|
FormatFPU("xmm10", &pContextRecord->Xmm10);
|
|
|
|
FormatFPU("xmm11", &pContextRecord->Xmm11);
|
|
|
|
FormatFPU("xmm12", &pContextRecord->Xmm12);
|
|
|
|
FormatFPU("xmm13", &pContextRecord->Xmm13);
|
|
|
|
FormatFPU("xmm14", &pContextRecord->Xmm14);
|
|
|
|
FormatFPU("xmm15", &pContextRecord->Xmm15);
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("}\n");
|
2022-12-26 20:33:09 +01:00
|
|
|
}
|
|
|
|
|
2022-12-27 14:12:46 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: formats all loaded modules (verbose)
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatModules()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("modules:\n{\n");
|
|
|
|
|
|
|
|
const HANDLE hProcess = GetCurrentProcess();
|
2022-12-27 14:12:46 +01:00
|
|
|
|
|
|
|
DWORD cbNeeded;
|
2024-02-04 00:55:07 +01:00
|
|
|
const BOOL result = K32EnumProcessModulesEx(hProcess, m_ppModuleHandles, MAX_MODULE_HANDLES, &cbNeeded, LIST_MODULES_ALL);
|
2022-12-27 14:12:46 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
if (result && cbNeeded <= MAX_MODULE_HANDLES && cbNeeded >> 3)
|
2022-12-27 14:12:46 +01:00
|
|
|
{
|
2023-07-08 02:44:33 +02:00
|
|
|
CHAR szModuleName[MAX_FILEPATH];
|
2022-12-28 15:38:18 +01:00
|
|
|
LPSTR pszModuleName;
|
2022-12-27 14:12:46 +01:00
|
|
|
MODULEINFO modInfo;
|
|
|
|
|
2022-12-28 15:38:18 +01:00
|
|
|
for (DWORD i = 0, j = cbNeeded >> 3; j; i++, j--)
|
2022-12-27 14:12:46 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
const DWORD m = GetModuleFileNameA(m_ppModuleHandles[i], szModuleName, sizeof(szModuleName));
|
|
|
|
|
2022-12-27 14:12:46 +01:00
|
|
|
if ((m - 1) > (sizeof(szModuleName) - 2)) // Too small for buffer.
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
snprintf(szModuleName, sizeof(szModuleName), "module@%p", m_ppModuleHandles[i]);
|
2022-12-27 14:12:46 +01:00
|
|
|
pszModuleName = szModuleName;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pszModuleName = strrchr(szModuleName, '\\') + 1;
|
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
K32GetModuleInformation(hProcess, m_ppModuleHandles[i], &modInfo, sizeof(modInfo));
|
2022-12-27 14:12:46 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%-15s: [%p, %p]\n",
|
|
|
|
pszModuleName, modInfo.lpBaseOfDll, (reinterpret_cast<uintptr_t>(modInfo.lpBaseOfDll) + modInfo.SizeOfImage));
|
2022-12-27 14:12:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("}\n");
|
2022-12-27 14:12:46 +01:00
|
|
|
}
|
|
|
|
|
2022-12-26 22:00:38 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: formats the system information
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatSystemInfo()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("system:\n{\n");
|
2022-12-26 22:00:38 +01:00
|
|
|
|
|
|
|
const CPUInformation& pi = GetCPUInformation();
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\tcpu_model = \"%s\"\n", pi.m_szProcessorBrand);
|
|
|
|
m_Buffer.AppendFormat("\tcpu_speed = %010lld // clock cycles\n", pi.m_Speed);
|
2022-12-26 22:00:38 +01:00
|
|
|
|
2022-12-28 15:38:18 +01:00
|
|
|
for (DWORD i = 0; ; i++)
|
2022-12-26 22:00:38 +01:00
|
|
|
{
|
2023-04-08 10:50:32 +02:00
|
|
|
DISPLAY_DEVICE dd = { sizeof(dd), {0} };
|
2024-02-04 00:55:07 +01:00
|
|
|
const BOOL f = EnumDisplayDevices(NULL, i, &dd, EDD_GET_DEVICE_INTERFACE_NAME);
|
|
|
|
|
2022-12-26 22:00:38 +01:00
|
|
|
if (!f)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dd.StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE) // The primary device is the only relevant device.
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\tgpu_model = \"%s\"\n", dd.DeviceString);
|
|
|
|
m_Buffer.AppendFormat("\tgpu_flags = 0x%08X // primary device\n", dd.StateFlags);
|
2022-12-26 22:00:38 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEMORYSTATUSEX statex{};
|
|
|
|
statex.dwLength = sizeof(statex);
|
|
|
|
|
|
|
|
if (GlobalMemoryStatusEx(&statex))
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\tram_total = [%010d, %010d] // physical/virtual (MiB)\n", (statex.ullTotalPhys / 1024) / 1024, (statex.ullTotalVirtual / 1024) / 1024);
|
|
|
|
m_Buffer.AppendFormat("\tram_avail = [%010d, %010d] // physical/virtual (MiB)\n", (statex.ullAvailPhys / 1024) / 1024, (statex.ullAvailVirtual / 1024) / 1024);
|
2022-12-26 22:00:38 +01:00
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.Append("}\n");
|
2022-12-26 22:00:38 +01:00
|
|
|
}
|
|
|
|
|
2022-12-26 23:35:41 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: formats the build information
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatBuildInfo()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("build_id: %u\n", g_SDKDll.GetNTHeaders()->FileHeader.TimeDateStamp);
|
2022-12-26 23:35:41 +01:00
|
|
|
}
|
|
|
|
|
2022-12-27 23:08:59 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: formats the module, address and exception
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatExceptionAddress()
|
|
|
|
{
|
|
|
|
FormatExceptionAddress(static_cast<LPCSTR>(m_pExceptionPointers->ExceptionRecord->ExceptionAddress));
|
|
|
|
}
|
|
|
|
|
2022-12-26 20:33:09 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: formats the module, address and exception
|
|
|
|
// Input : pExceptionAddress -
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-04 00:55:07 +01:00
|
|
|
void CCrashHandler::FormatExceptionAddress(const LPCSTR pExceptionAddress)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2022-12-26 20:11:37 +01:00
|
|
|
HMODULE hCrashedModule;
|
|
|
|
if (!GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, pExceptionAddress, &hCrashedModule))
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t!!!unknown-module!!!: %p\n", pExceptionAddress);
|
2022-12-27 02:28:43 +01:00
|
|
|
m_nCrashMsgFlags = 0; // Display the "unknown DLL or EXE" message.
|
2022-12-26 20:11:37 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
const LPCSTR pModuleBase = reinterpret_cast<LPCSTR>(pExceptionAddress - reinterpret_cast<LPCSTR>(hCrashedModule));
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
CHAR szCrashedModuleFullName[MAX_PATH];
|
2022-12-26 20:11:37 +01:00
|
|
|
if (GetModuleFileNameExA(GetCurrentProcess(), hCrashedModule, szCrashedModuleFullName, sizeof(szCrashedModuleFullName)) - 1 > 0x1FE)
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\tmodule@%p: %p\n", (void*)hCrashedModule, pModuleBase);
|
2022-12-27 14:23:54 +01:00
|
|
|
m_nCrashMsgFlags = 2; // Display the "Apex crashed" message without additional information regarding the module.
|
2022-12-26 20:11:37 +01:00
|
|
|
return;
|
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
// NOTE: original implementation strips the extension as well, but we keep
|
|
|
|
// this in as its useful for when additional modules are loaded that aren't
|
|
|
|
// part of the OS or game
|
|
|
|
const char* const szCrashedModuleName = strrchr(szCrashedModuleFullName, '\\') + 1;
|
|
|
|
|
|
|
|
m_Buffer.AppendFormat("\t%-15s: %p\n", szCrashedModuleName, pModuleBase);
|
2022-12-27 02:28:43 +01:00
|
|
|
m_nCrashMsgFlags = 1; // Display the "Apex crashed in <module>" message.
|
|
|
|
|
2023-06-19 01:18:27 +02:00
|
|
|
// Only set it once to the crashing module,
|
|
|
|
// empty strings get treated as "unknown
|
|
|
|
// DLL or EXE" in the crashmsg executable.
|
2024-02-04 00:55:07 +01:00
|
|
|
if (!m_CrashingModule.Length())
|
2022-12-27 02:28:43 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_CrashingModule.Append(szCrashedModuleName);
|
2022-12-27 02:28:43 +01:00
|
|
|
}
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-26 20:33:09 +01:00
|
|
|
// Purpose: formats the exception code
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::FormatExceptionCode()
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
const DWORD nExceptionCode = m_pExceptionPointers->ExceptionRecord->ExceptionCode;
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
if (nExceptionCode > EXCEPTION_IN_PAGE_ERROR)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat(ExceptionToString(), nExceptionCode);
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
|
|
|
else if (nExceptionCode >= EXCEPTION_ACCESS_VIOLATION)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2022-12-28 16:36:52 +01:00
|
|
|
const CHAR* pszException = "EXCEPTION_IN_PAGE_ERROR";
|
2024-02-04 00:55:07 +01:00
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
if (nExceptionCode == EXCEPTION_ACCESS_VIOLATION)
|
|
|
|
{
|
|
|
|
pszException = "EXCEPTION_ACCESS_VIOLATION";
|
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
const ULONG_PTR uExceptionInfo0 = m_pExceptionPointers->ExceptionRecord->ExceptionInformation[0];
|
|
|
|
const ULONG_PTR uExceptionInfo1 = m_pExceptionPointers->ExceptionRecord->ExceptionInformation[1];
|
2022-12-26 20:11:37 +01:00
|
|
|
|
|
|
|
if (uExceptionInfo0)
|
|
|
|
{
|
|
|
|
if (uExceptionInfo0 == 1)
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s(write): %p\n", pszException, uExceptionInfo1);
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
|
|
|
else if (uExceptionInfo0 == 8)
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s(execute): %p\n", pszException, uExceptionInfo1);
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s(unknown): %p\n", pszException, uExceptionInfo1);
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
else
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s(read): %p\n", pszException, uExceptionInfo1);
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
if (uExceptionInfo0 != 8)
|
|
|
|
{
|
|
|
|
if (IsPageAccessible())
|
|
|
|
{
|
|
|
|
FormatExceptionAddress();
|
|
|
|
}
|
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
2022-12-26 20:11:37 +01:00
|
|
|
else
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat(ExceptionToString(), nExceptionCode);
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2023-01-04 14:55:58 +01:00
|
|
|
// Purpose: formats the arithmetic logic register and its content
|
2022-12-26 22:00:38 +01:00
|
|
|
// Input : *pszRegister -
|
|
|
|
// nContent -
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-04 00:55:07 +01:00
|
|
|
void CCrashHandler::FormatALU(const char* const pszRegister, const DWORD64 nContent)
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2023-01-16 15:28:39 +01:00
|
|
|
if (nContent >= 1000000)
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2022-12-28 20:30:33 +01:00
|
|
|
if (nContent > UINT_MAX)
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2023-06-19 01:18:27 +02:00
|
|
|
// Print the full 64bits of the register.
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s = 0x%016llX\n", pszRegister, nContent);
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
|
|
|
else
|
2022-12-24 16:40:04 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s = 0x%08X\n", pszRegister, nContent);
|
2022-12-24 16:40:04 +01:00
|
|
|
}
|
|
|
|
}
|
2023-06-19 01:18:27 +02:00
|
|
|
else if (nContent >= 10)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2023-06-19 01:18:27 +02:00
|
|
|
// Print as decimal with a hexadecimal comment.
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s = %-6i // 0x%08X\n", pszRegister, nContent, nContent);
|
2023-06-19 01:18:27 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Print as decimal only.
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s = %-10i\n", pszRegister, nContent);
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-26 20:33:09 +01:00
|
|
|
// Purpose: formats the floating point register and its content
|
2022-12-26 22:00:38 +01:00
|
|
|
// Input : *pszRegister -
|
|
|
|
// *pxContent -
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-04 00:55:07 +01:00
|
|
|
void CCrashHandler::FormatFPU(const char* const pszRegister, const M128A* const pxContent)
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
const DWORD nVec[4] =
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2023-03-18 16:45:43 +01:00
|
|
|
static_cast<DWORD>(pxContent->Low & UINT_MAX),
|
|
|
|
static_cast<DWORD>(pxContent->Low >> 32),
|
|
|
|
static_cast<DWORD>(pxContent->High & UINT_MAX),
|
|
|
|
static_cast<DWORD>(pxContent->High >> 32),
|
2022-12-26 20:11:37 +01:00
|
|
|
};
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat("\t%s = [ [%.8g, %.8g, %.8g, %.8g]", pszRegister,
|
|
|
|
*reinterpret_cast<const FLOAT*>(&nVec[0]),
|
|
|
|
*reinterpret_cast<const FLOAT*>(&nVec[1]),
|
|
|
|
*reinterpret_cast<const FLOAT*>(&nVec[2]),
|
|
|
|
*reinterpret_cast<const FLOAT*>(&nVec[3]));
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2023-04-08 13:34:31 +02:00
|
|
|
const LONG nHighest = abs(LONG(*MaxElementABS(std::begin(nVec), std::end(nVec))));
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2023-04-08 13:34:31 +02:00
|
|
|
if (nHighest >= 1000000)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat(", [0x%08X, 0x%08X, 0x%08X, 0x%08X] ]\n",
|
|
|
|
nVec[0], nVec[1], nVec[2], nVec[3]);
|
2022-12-28 15:38:18 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_Buffer.AppendFormat(", [%i, %i, %i, %i] ]\n",
|
2022-12-28 15:38:18 +01:00
|
|
|
static_cast<LONG>(nVec[0]), static_cast<LONG>(nVec[1]),
|
2024-02-04 00:55:07 +01:00
|
|
|
static_cast<LONG>(nVec[2]), static_cast<LONG>(nVec[3]));
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-26 20:33:09 +01:00
|
|
|
// Purpose: returns the current exception code as string
|
2022-12-28 16:36:52 +01:00
|
|
|
// Output : exception code, "UNKNOWN_EXCEPTION" if exception code doesn't exist in this context
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-04 00:55:07 +01:00
|
|
|
const char* CCrashHandler::ExceptionToString(const DWORD nExceptionCode) const
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2022-12-27 02:28:43 +01:00
|
|
|
switch (nExceptionCode)
|
2022-12-26 20:33:09 +01:00
|
|
|
{
|
2023-04-08 10:50:32 +02:00
|
|
|
case EXCEPTION_BREAKPOINT: { return "\tEXCEPTION_BREAKPOINT" ": %08X\n"; };
|
|
|
|
case EXCEPTION_SINGLE_STEP: { return "\tEXCEPTION_SINGLE_STEP" ": %08X\n"; };
|
|
|
|
case EXCEPTION_ACCESS_VIOLATION: { return "\tEXCEPTION_ACCESS_VIOLATION" ": %08X\n"; };
|
|
|
|
case EXCEPTION_IN_PAGE_ERROR: { return "\tEXCEPTION_IN_PAGE_ERROR" ": %08X\n"; };
|
|
|
|
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: { return "\tEXCEPTION_ARRAY_BOUNDS_EXCEEDED" ": %08X\n"; };
|
|
|
|
case EXCEPTION_ILLEGAL_INSTRUCTION: { return "\tEXCEPTION_ILLEGAL_INSTRUCTION" ": %08X\n"; };
|
|
|
|
case EXCEPTION_INVALID_DISPOSITION: { return "\tEXCEPTION_INVALID_DISPOSITION" ": %08X\n"; };
|
|
|
|
case EXCEPTION_NONCONTINUABLE_EXCEPTION: { return "\tEXCEPTION_NONCONTINUABLE_EXCEPTION" ": %08X\n"; };
|
|
|
|
case EXCEPTION_PRIV_INSTRUCTION: { return "\tEXCEPTION_PRIV_INSTRUCTION" ": %08X\n"; };
|
|
|
|
case EXCEPTION_STACK_OVERFLOW: { return "\tEXCEPTION_STACK_OVERFLOW" ": %08X\n"; };
|
|
|
|
case EXCEPTION_DATATYPE_MISALIGNMENT: { return "\tEXCEPTION_DATATYPE_MISALIGNMENT" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_DENORMAL_OPERAND: { return "\tEXCEPTION_FLT_DENORMAL_OPERAND" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_DIVIDE_BY_ZERO: { return "\tEXCEPTION_FLT_DIVIDE_BY_ZERO" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_INEXACT_RESULT: { return "\tEXCEPTION_FLT_INEXACT_RESULT" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_INVALID_OPERATION: { return "\tEXCEPTION_FLT_INVALID_OPERATION" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_OVERFLOW: { return "\tEXCEPTION_FLT_OVERFLOW" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_STACK_CHECK: { return "\tEXCEPTION_FLT_STACK_CHECK" ": %08X\n"; };
|
|
|
|
case EXCEPTION_FLT_UNDERFLOW: { return "\tEXCEPTION_FLT_UNDERFLOW" ": %08X\n"; };
|
|
|
|
case EXCEPTION_INT_DIVIDE_BY_ZERO: { return "\tEXCEPTION_INT_DIVIDE_BY_ZERO" ": %08X\n"; };
|
|
|
|
case EXCEPTION_INT_OVERFLOW: { return "\tEXCEPTION_INT_OVERFLOW" ": %08X\n"; };
|
|
|
|
default: { return "\tUNKNOWN_EXCEPTION" ": %08X\n"; };
|
2022-12-26 20:33:09 +01:00
|
|
|
}
|
|
|
|
}
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2022-12-27 02:28:43 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: returns the current exception code as string
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
const char* CCrashHandler::ExceptionToString() const
|
|
|
|
{
|
|
|
|
return ExceptionToString(m_pExceptionPointers->ExceptionRecord->ExceptionCode);
|
|
|
|
}
|
|
|
|
|
2022-12-26 20:33:09 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: tests if memory page is accessible
|
2022-12-28 16:36:52 +01:00
|
|
|
// Output : true if accessible, false otherwise
|
2022-12-26 20:33:09 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
bool CCrashHandler::IsPageAccessible() const
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
const PCONTEXT pContextRecord = m_pExceptionPointers->ContextRecord;
|
2022-12-26 20:33:09 +01:00
|
|
|
MEMORY_BASIC_INFORMATION mbi = { 0 };
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
const SIZE_T t = VirtualQuery((LPCVOID)pContextRecord->Rsp, &mbi, sizeof(LPCVOID));
|
2023-04-08 10:50:32 +02:00
|
|
|
if (t < sizeof(mbi) || (mbi.Protect & PAGE_NOACCESS) || !((mbi.Protect & PAGE_NOACCESS) | PAGE_READWRITE))
|
2022-12-26 20:33:09 +01:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return !(mbi.State & MEM_COMMIT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: captures the callstack
|
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-04 00:55:07 +01:00
|
|
|
void CCrashHandler::CaptureCallStack()
|
2022-12-26 20:33:09 +01:00
|
|
|
{
|
2022-12-27 13:19:57 +01:00
|
|
|
m_nCapturedFrames = RtlCaptureStackBackTrace(2, NUM_FRAMES_TO_CAPTURE, m_ppStackTrace, NULL);
|
2022-12-26 20:33:09 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
2023-04-08 16:09:23 +02:00
|
|
|
// Purpose: writes the stack trace and minidump to the disk
|
2022-12-26 20:33:09 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::WriteFile()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
CFmtStrQuietTruncationN<256> outFile;
|
|
|
|
|
|
|
|
outFile.Format("%s/%s.txt", g_LogSessionDirectory.c_str(), "apex_crash");
|
|
|
|
HANDLE hTxtFile = CreateFile(outFile.String(), GENERIC_WRITE, 0, 0, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
|
2022-12-26 20:33:09 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
if (hTxtFile != INVALID_HANDLE_VALUE)
|
2023-04-08 16:09:23 +02:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
::WriteFile(hTxtFile, m_Buffer.String(), (DWORD)m_Buffer.Length(), NULL, NULL);
|
|
|
|
CloseHandle(hTxtFile);
|
2023-04-08 16:09:23 +02:00
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
outFile.Format("%s/%s.dmp", g_LogSessionDirectory.c_str(), "minidump");
|
|
|
|
HANDLE hDmpFile = CreateFile(outFile.String(), GENERIC_WRITE, 0, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
|
2023-04-08 16:09:23 +02:00
|
|
|
|
|
|
|
if (hDmpFile != INVALID_HANDLE_VALUE)
|
|
|
|
{
|
|
|
|
MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo;
|
|
|
|
dumpExceptionInfo.ThreadId = GetCurrentThreadId();
|
|
|
|
dumpExceptionInfo.ExceptionPointers = m_pExceptionPointers;
|
|
|
|
dumpExceptionInfo.ClientPointers = false;
|
|
|
|
|
|
|
|
MiniDumpWriteDump(
|
|
|
|
GetCurrentProcess(),
|
|
|
|
GetCurrentProcessId(),
|
|
|
|
hDmpFile, MiniDumpNormal,
|
|
|
|
&dumpExceptionInfo, NULL, NULL);
|
|
|
|
|
|
|
|
CloseHandle(hDmpFile);
|
|
|
|
}
|
2022-12-26 20:11:37 +01:00
|
|
|
}
|
2022-12-23 02:56:40 +01:00
|
|
|
|
2022-12-27 02:28:43 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: creates the crashmsg process displaying the error to the user
|
|
|
|
// the process has to be separate as the current process is getting killed
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::CreateMessageProcess()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
if (m_bMessageCreated)
|
2022-12-27 02:28:43 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
// Crash message already displayed.
|
|
|
|
return;
|
2022-12-27 02:28:43 +01:00
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
m_bMessageCreated = true;
|
|
|
|
|
|
|
|
const PEXCEPTION_RECORD pExceptionRecord = m_pExceptionPointers->ExceptionRecord;
|
|
|
|
const PCONTEXT pContextRecord = m_pExceptionPointers->ContextRecord;
|
2022-12-27 02:28:43 +01:00
|
|
|
|
2023-02-04 01:04:06 +01:00
|
|
|
if (pExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION &&
|
2022-12-27 02:28:43 +01:00
|
|
|
pExceptionRecord->ExceptionInformation[0] == 8 &&
|
|
|
|
pExceptionRecord->ExceptionInformation[1] != pContextRecord->Rip)
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_MessageCmdLine.Clear();
|
|
|
|
m_MessageCmdLine.Append(CRASHMESSAGE_MSG_EXECUTABLE" overclock");
|
2022-12-27 02:28:43 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
m_MessageCmdLine.Format(CRASHMESSAGE_MSG_EXECUTABLE" crash %hhu \"%s\"",
|
|
|
|
m_nCrashMsgFlags, m_CrashingModule.String());
|
2022-12-27 02:28:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
STARTUPINFOA startupInfo = { 0 };
|
2024-02-04 00:55:07 +01:00
|
|
|
PROCESS_INFORMATION processInfo;
|
2022-12-27 02:28:43 +01:00
|
|
|
|
|
|
|
startupInfo.cb = sizeof(STARTUPINFOA);
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
if (CreateProcessA(NULL, (LPSTR)m_MessageCmdLine.String(),
|
|
|
|
NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo))
|
2022-12-27 02:28:43 +01:00
|
|
|
{
|
|
|
|
CloseHandle(processInfo.hProcess);
|
|
|
|
CloseHandle(processInfo.hThread);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-10 00:05:38 +02:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose: calls the crash callback
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::CrashCallback()
|
|
|
|
{
|
|
|
|
if (m_pCrashCallback)
|
|
|
|
{
|
|
|
|
((void(*)(void))m_pCrashCallback)();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
2022-12-28 16:36:52 +01:00
|
|
|
// Input :
|
|
|
|
// Output :
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
2024-02-04 00:55:07 +01:00
|
|
|
long __stdcall BottomLevelExceptionFilter(EXCEPTION_POINTERS* const pExceptionInfo)
|
2022-12-26 20:11:37 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.Start();
|
2022-12-28 21:38:47 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
// If the exception couldn't be handled, run the crash callback and
|
|
|
|
// terminate the process
|
|
|
|
if (g_CrashHandler.GetExit())
|
2022-12-27 02:28:43 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.CrashCallback();
|
|
|
|
ExitProcess(EXIT_FAILURE);
|
2022-12-27 02:28:43 +01:00
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.Reset();
|
|
|
|
g_CrashHandler.SetExceptionPointers(pExceptionInfo);
|
|
|
|
|
|
|
|
// Let the higher level exception handlers deal with this particular
|
|
|
|
// exception.
|
|
|
|
if (g_CrashHandler.ExceptionToString() == g_CrashHandler.ExceptionToString(0xFFFFFFFF))
|
2022-12-27 02:28:43 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.End();
|
2022-12-27 02:28:43 +01:00
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
// Don't run when a debugger is present.
|
|
|
|
if (IsDebuggerPresent())
|
2022-12-27 23:08:59 +01:00
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.End();
|
2022-12-27 23:08:59 +01:00
|
|
|
return EXCEPTION_CONTINUE_SEARCH;
|
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.SetExit(true);
|
|
|
|
|
|
|
|
g_CrashHandler.CaptureCallStack();
|
2023-03-18 14:10:29 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.FormatCrash();
|
|
|
|
g_CrashHandler.FormatCallstack();
|
|
|
|
g_CrashHandler.FormatRegisters();
|
|
|
|
g_CrashHandler.FormatModules();
|
|
|
|
g_CrashHandler.FormatSystemInfo();
|
|
|
|
g_CrashHandler.FormatBuildInfo();
|
2022-12-24 16:40:04 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
g_CrashHandler.WriteFile();
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
// Display the message to the user.
|
|
|
|
g_CrashHandler.CreateMessageProcess();
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
// End it here, the next recursive call terminates the process.
|
|
|
|
g_CrashHandler.End();
|
2022-12-26 20:11:37 +01:00
|
|
|
|
2022-12-23 02:56:40 +01:00
|
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
|
|
}
|
|
|
|
|
2023-01-31 21:48:42 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::Init()
|
|
|
|
{
|
2024-02-04 00:55:07 +01:00
|
|
|
InitializeSRWLock(&m_Lock);
|
2023-01-31 21:48:42 +01:00
|
|
|
m_hExceptionHandler = AddVectoredExceptionHandler(TRUE, BottomLevelExceptionFilter);
|
|
|
|
}
|
|
|
|
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::Shutdown()
|
|
|
|
{
|
|
|
|
if (m_hExceptionHandler)
|
|
|
|
{
|
|
|
|
RemoveVectoredExceptionHandler(m_hExceptionHandler);
|
|
|
|
m_hExceptionHandler = nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCrashHandler::Reset()
|
|
|
|
{
|
|
|
|
m_Buffer.Clear();
|
|
|
|
m_CrashingModule.Clear();
|
|
|
|
m_MessageCmdLine.Clear();
|
|
|
|
|
|
|
|
m_nCrashMsgFlags = 0;
|
|
|
|
}
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-23 02:56:40 +01:00
|
|
|
CCrashHandler::CCrashHandler()
|
2022-12-26 20:11:37 +01:00
|
|
|
: m_ppStackTrace()
|
2024-02-04 00:55:07 +01:00
|
|
|
, m_nCapturedFrames(0)
|
|
|
|
, m_ppModuleHandles()
|
2023-05-10 00:05:38 +02:00
|
|
|
, m_pCrashCallback(nullptr)
|
|
|
|
, m_hExceptionHandler(nullptr)
|
2022-12-27 02:28:43 +01:00
|
|
|
, m_pExceptionPointers(nullptr)
|
|
|
|
, m_nCrashMsgFlags(0)
|
2024-02-04 00:55:07 +01:00
|
|
|
, m_bExit(false)
|
|
|
|
, m_bMessageCreated(false)
|
2022-12-23 02:56:40 +01:00
|
|
|
{
|
2023-01-31 21:48:42 +01:00
|
|
|
Init();
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
|
|
|
|
2022-12-26 20:11:37 +01:00
|
|
|
//-----------------------------------------------------------------------------
|
|
|
|
// Purpose:
|
|
|
|
//-----------------------------------------------------------------------------
|
2022-12-23 02:56:40 +01:00
|
|
|
CCrashHandler::~CCrashHandler()
|
|
|
|
{
|
2023-01-31 21:48:42 +01:00
|
|
|
Shutdown();
|
2022-12-23 02:56:40 +01:00
|
|
|
}
|
|
|
|
|
2024-02-04 00:55:07 +01:00
|
|
|
CCrashHandler g_CrashHandler;
|