mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Tier0: crash handler reliability improvements
* Break out of loop when we found and cached the primary graphics device. * Log total and available ram with more accuracy. * (New) log total and available disk space the game is being ran from. * Cache hardware details such as disk space, ram space and graphics device so the crash callback could also use it. * Calculate highest XMM number as unsigned so an ABS call is not needed. * Make the crash callback const. * Provide pointer to instance to the crash callback. * Fix crash callback not running properly; it should always be ran in the context of the current crash, not after. The callback is now ran after the crashmsg application has been started.
This commit is contained in:
parent
7ef0a77bb9
commit
98f4f57afe
@ -38,7 +38,7 @@ static HMODULE s_hModuleHandle = NULL;
|
|||||||
// UTILITY
|
// UTILITY
|
||||||
//#############################################################################
|
//#############################################################################
|
||||||
|
|
||||||
void Crash_Callback()
|
void Crash_Callback(const CCrashHandler* handler)
|
||||||
{
|
{
|
||||||
// Shutdown SpdLog to flush all buffers.
|
// Shutdown SpdLog to flush all buffers.
|
||||||
SpdLog_Shutdown();
|
SpdLog_Shutdown();
|
||||||
|
@ -4,6 +4,26 @@
|
|||||||
|
|
||||||
#define CRASHMESSAGE_MSG_EXECUTABLE "bin\\crashmsg.exe"
|
#define CRASHMESSAGE_MSG_EXECUTABLE "bin\\crashmsg.exe"
|
||||||
|
|
||||||
|
class CCrashHandler;
|
||||||
|
typedef void (*CrashCallback_t)(const CCrashHandler* handler);
|
||||||
|
|
||||||
|
struct CrashHardWareInfo_s
|
||||||
|
{
|
||||||
|
CrashHardWareInfo_s()
|
||||||
|
{
|
||||||
|
displayDevice = { sizeof(displayDevice), {0} };
|
||||||
|
memoryStatus = { sizeof(memoryStatus) , {0} };
|
||||||
|
availDiskSpace = 0;
|
||||||
|
totalDiskSpace = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
DISPLAY_DEVICE displayDevice;
|
||||||
|
MEMORYSTATUSEX memoryStatus;
|
||||||
|
|
||||||
|
size_t totalDiskSpace;
|
||||||
|
size_t availDiskSpace;
|
||||||
|
};
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose:
|
// Purpose:
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@ -29,6 +49,12 @@ public:
|
|||||||
|
|
||||||
inline bool IsValid() const { return m_hExceptionHandler != nullptr; };
|
inline bool IsValid() const { return m_hExceptionHandler != nullptr; };
|
||||||
|
|
||||||
|
inline bool CrashingModuleNameKnown() const { return m_CrashingModule.Length() > 0; }
|
||||||
|
inline const char* GetCrashingModuleName() const { return m_CrashingModule.String(); }
|
||||||
|
|
||||||
|
inline const EXCEPTION_POINTERS* GetExceptionPointers() const { return m_pExceptionPointers; }
|
||||||
|
inline const CrashHardWareInfo_s& GetHardwareInfo() const { return m_HardWareInfo; }
|
||||||
|
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
// Formatters:
|
// Formatters:
|
||||||
//-------------------------------------------------------------------------
|
//-------------------------------------------------------------------------
|
||||||
@ -46,13 +72,13 @@ public:
|
|||||||
const char* ExceptionToString(const DWORD nExceptionCode) const;
|
const char* ExceptionToString(const DWORD nExceptionCode) const;
|
||||||
|
|
||||||
void SetExceptionPointers(EXCEPTION_POINTERS* const pExceptionPointers) { m_pExceptionPointers = pExceptionPointers; }
|
void SetExceptionPointers(EXCEPTION_POINTERS* const pExceptionPointers) { m_pExceptionPointers = pExceptionPointers; }
|
||||||
void SetCrashCallback(PVOID pCrashCallback) { m_pCrashCallback = pCrashCallback; }
|
void SetCrashCallback(CrashCallback_t pCrashCallback) { m_pCrashCallback = pCrashCallback; }
|
||||||
|
|
||||||
void CaptureCallStack();
|
void CaptureCallStack();
|
||||||
void WriteFile();
|
void WriteFile();
|
||||||
|
|
||||||
void CreateMessageProcess();
|
void CreateMessageProcess();
|
||||||
void CrashCallback();
|
void CrashCallback() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -83,7 +109,7 @@ private:
|
|||||||
HMODULE m_ppModuleHandles[MAX_MODULE_HANDLES];
|
HMODULE m_ppModuleHandles[MAX_MODULE_HANDLES];
|
||||||
|
|
||||||
// Custom crash callback that's called after the logs have been written.
|
// Custom crash callback that's called after the logs have been written.
|
||||||
PVOID m_pCrashCallback;
|
CrashCallback_t m_pCrashCallback;
|
||||||
|
|
||||||
// Current exception handler, only kept here for tracking as we need the
|
// Current exception handler, only kept here for tracking as we need the
|
||||||
// handle if we want to remove this handler.
|
// handle if we want to remove this handler.
|
||||||
@ -109,6 +135,9 @@ private:
|
|||||||
|
|
||||||
// Set when crashmsg.exe is created to prevent recursive messages.
|
// Set when crashmsg.exe is created to prevent recursive messages.
|
||||||
bool m_bMessageCreated;
|
bool m_bMessageCreated;
|
||||||
|
|
||||||
|
// Cached hardware info this application crashed on.
|
||||||
|
CrashHardWareInfo_s m_HardWareInfo;
|
||||||
|
|
||||||
mutable RTL_SRWLOCK m_Lock;
|
mutable RTL_SRWLOCK m_Lock;
|
||||||
};
|
};
|
||||||
|
@ -171,9 +171,10 @@ void CCrashHandler::FormatSystemInfo()
|
|||||||
m_Buffer.AppendFormat("\tcpu_model = \"%s\"\n", pi.m_szProcessorBrand);
|
m_Buffer.AppendFormat("\tcpu_model = \"%s\"\n", pi.m_szProcessorBrand);
|
||||||
m_Buffer.AppendFormat("\tcpu_speed = %010lld // clock cycles\n", pi.m_Speed);
|
m_Buffer.AppendFormat("\tcpu_speed = %010lld // clock cycles\n", pi.m_Speed);
|
||||||
|
|
||||||
|
DISPLAY_DEVICE& dd = m_HardWareInfo.displayDevice;
|
||||||
|
|
||||||
for (DWORD i = 0; ; i++)
|
for (DWORD i = 0; ; i++)
|
||||||
{
|
{
|
||||||
DISPLAY_DEVICE dd = { sizeof(dd), {0} };
|
|
||||||
const BOOL f = EnumDisplayDevices(NULL, i, &dd, EDD_GET_DEVICE_INTERFACE_NAME);
|
const BOOL f = EnumDisplayDevices(NULL, i, &dd, EDD_GET_DEVICE_INTERFACE_NAME);
|
||||||
|
|
||||||
if (!f)
|
if (!f)
|
||||||
@ -185,16 +186,28 @@ void CCrashHandler::FormatSystemInfo()
|
|||||||
{
|
{
|
||||||
m_Buffer.AppendFormat("\tgpu_model = \"%s\"\n", dd.DeviceString);
|
m_Buffer.AppendFormat("\tgpu_model = \"%s\"\n", dd.DeviceString);
|
||||||
m_Buffer.AppendFormat("\tgpu_flags = 0x%08X // primary device\n", dd.StateFlags);
|
m_Buffer.AppendFormat("\tgpu_flags = 0x%08X // primary device\n", dd.StateFlags);
|
||||||
|
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MEMORYSTATUSEX statex{};
|
MEMORYSTATUSEX& statex = m_HardWareInfo.memoryStatus;
|
||||||
statex.dwLength = sizeof(statex);
|
|
||||||
|
|
||||||
if (GlobalMemoryStatusEx(&statex))
|
if (GlobalMemoryStatusEx(&statex))
|
||||||
{
|
{
|
||||||
m_Buffer.AppendFormat("\tram_total = [%010d, %010d] // physical/virtual (MiB)\n", (statex.ullTotalPhys / 1024) / 1024, (statex.ullTotalVirtual / 1024) / 1024);
|
m_Buffer.AppendFormat("\tram_total = [%.2lf, %.2lf] // physical/virtual (MiB)\n", (f64)(statex.ullTotalPhys / (1024.0 * 1024.0)), (f64)(statex.ullTotalVirtual / (1024.0 * 1024.0)));
|
||||||
m_Buffer.AppendFormat("\tram_avail = [%010d, %010d] // physical/virtual (MiB)\n", (statex.ullAvailPhys / 1024) / 1024, (statex.ullAvailVirtual / 1024) / 1024);
|
m_Buffer.AppendFormat("\tram_avail = [%.2lf, %.2lf] // physical/virtual (MiB)\n", (f64)(statex.ullAvailPhys / (1024.0 * 1024.0)), (f64)(statex.ullAvailVirtual / (1024.0 * 1024.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD sectorsPerCluster, bytesPerSector, freeClusters, totalClusters;
|
||||||
|
|
||||||
|
if (GetDiskFreeSpaceA(NULL, §orsPerCluster, &bytesPerSector, &freeClusters, &totalClusters))
|
||||||
|
{
|
||||||
|
m_HardWareInfo.totalDiskSpace = (u64)totalClusters * sectorsPerCluster * bytesPerSector;
|
||||||
|
m_HardWareInfo.availDiskSpace = (u64)freeClusters * sectorsPerCluster * bytesPerSector;
|
||||||
|
|
||||||
|
m_Buffer.AppendFormat("\tdsk_total = %.2lf // (MiB)\n", (f64)(m_HardWareInfo.totalDiskSpace / (1024.0 * 1024.0)));
|
||||||
|
m_Buffer.AppendFormat("\tdsk_avail = %.2lf // (MiB)\n", (f64)(m_HardWareInfo.availDiskSpace / (1024.0 * 1024.0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Buffer.Append("}\n");
|
m_Buffer.Append("}\n");
|
||||||
@ -366,7 +379,7 @@ void CCrashHandler::FormatFPU(const char* const pszRegister, const M128A* const
|
|||||||
*reinterpret_cast<const FLOAT*>(&nVec[2]),
|
*reinterpret_cast<const FLOAT*>(&nVec[2]),
|
||||||
*reinterpret_cast<const FLOAT*>(&nVec[3]));
|
*reinterpret_cast<const FLOAT*>(&nVec[3]));
|
||||||
|
|
||||||
const LONG nHighest = abs(LONG(*MaxElementABS(std::begin(nVec), std::end(nVec))));
|
const DWORD nHighest = *MaxElementABS(std::begin(nVec), std::end(nVec));
|
||||||
|
|
||||||
if (nHighest >= 1000000)
|
if (nHighest >= 1000000)
|
||||||
{
|
{
|
||||||
@ -531,11 +544,11 @@ void CCrashHandler::CreateMessageProcess()
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose: calls the crash callback
|
// Purpose: calls the crash callback
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
void CCrashHandler::CrashCallback()
|
void CCrashHandler::CrashCallback() const
|
||||||
{
|
{
|
||||||
if (m_pCrashCallback)
|
if (m_pCrashCallback)
|
||||||
{
|
{
|
||||||
((void(*)(void))m_pCrashCallback)();
|
m_pCrashCallback(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -548,11 +561,9 @@ long __stdcall BottomLevelExceptionFilter(EXCEPTION_POINTERS* const pExceptionIn
|
|||||||
{
|
{
|
||||||
g_CrashHandler.Start();
|
g_CrashHandler.Start();
|
||||||
|
|
||||||
// If the exception couldn't be handled, run the crash callback and
|
// If the exception couldn't be handled, terminate the process
|
||||||
// terminate the process
|
|
||||||
if (g_CrashHandler.GetExit())
|
if (g_CrashHandler.GetExit())
|
||||||
{
|
{
|
||||||
g_CrashHandler.CrashCallback();
|
|
||||||
ExitProcess(EXIT_FAILURE);
|
ExitProcess(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -590,6 +601,9 @@ long __stdcall BottomLevelExceptionFilter(EXCEPTION_POINTERS* const pExceptionIn
|
|||||||
// Display the message to the user.
|
// Display the message to the user.
|
||||||
g_CrashHandler.CreateMessageProcess();
|
g_CrashHandler.CreateMessageProcess();
|
||||||
|
|
||||||
|
// Run the crash callback
|
||||||
|
g_CrashHandler.CrashCallback();
|
||||||
|
|
||||||
// End it here, the next recursive call terminates the process.
|
// End it here, the next recursive call terminates the process.
|
||||||
g_CrashHandler.End();
|
g_CrashHandler.End();
|
||||||
|
|
||||||
@ -625,7 +639,6 @@ void CCrashHandler::Reset()
|
|||||||
m_Buffer.Clear();
|
m_Buffer.Clear();
|
||||||
m_CrashingModule.Clear();
|
m_CrashingModule.Clear();
|
||||||
m_MessageCmdLine.Clear();
|
m_MessageCmdLine.Clear();
|
||||||
|
|
||||||
m_nCrashMsgFlags = 0;
|
m_nCrashMsgFlags = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user