diff --git a/src/core/dllmain.cpp b/src/core/dllmain.cpp index 673940e2..e680bd62 100644 --- a/src/core/dllmain.cpp +++ b/src/core/dllmain.cpp @@ -7,6 +7,7 @@ #include "tier0/basetypes.h" #include "tier0/crashhandler.h" #include "tier0/commandline.h" +#include "tier2/crashreporter.h" /*****************************************************************************/ #ifndef DEDICATED #include "windows/id3dx.h" @@ -40,10 +41,8 @@ static HMODULE s_hModuleHandle = NULL; void Crash_Callback(const CCrashHandler* handler) { - // Shutdown SpdLog to flush all buffers. - SpdLog_Shutdown(); - - // TODO[ AMOS ]: This is where we want to call backtrace from. + CrashReporter_SubmitToCollector(handler); + SpdLog_Shutdown(); // Shutdown SpdLog to flush all buffers. } void Show_Emblem() diff --git a/src/public/tier2/crashreporter.h b/src/public/tier2/crashreporter.h new file mode 100644 index 00000000..892c11b2 --- /dev/null +++ b/src/public/tier2/crashreporter.h @@ -0,0 +1,11 @@ +//=============================================================================// +// +// Purpose: Post-mortem crash reporter +// +//=============================================================================// +#ifndef TIER2_CRASHREPORTER_H +#define TIER2_CRASHREPORTER_H + +extern void CrashReporter_SubmitToCollector(const CCrashHandler* const handler); + +#endif // TIER2_CRASHREPORTER_H diff --git a/src/tier2/CMakeLists.txt b/src/tier2/CMakeLists.txt index 2cca1d97..2c3b4b0b 100644 --- a/src/tier2/CMakeLists.txt +++ b/src/tier2/CMakeLists.txt @@ -4,6 +4,7 @@ add_module( "lib" "tier2" "vpc" ${FOLDER_CONTEXT} TRUE TRUE ) start_sources() add_sources( SOURCE_GROUP "Utility" + "crashreporter.cpp" "cryptutils.cpp" "curlutils.cpp" "fileutils.cpp" diff --git a/src/tier2/crashreporter.cpp b/src/tier2/crashreporter.cpp new file mode 100644 index 00000000..81a9b338 --- /dev/null +++ b/src/tier2/crashreporter.cpp @@ -0,0 +1,61 @@ +//=============================================================================// +// +// Purpose: Post-mortem crash reporter +// +//=============================================================================// +#include "tier0/crashhandler.h" +#include "tier0/cpu.h" +#include "tier2/curlutils.h" +#include "tier2/crashreporter.h" + +static ConVar backtrace_enabled("backtrace_enabled", "1", FCVAR_RELEASE, "Whether to report fatal errors to the collection server"); +static ConVar backtrace_hostname("backtrace_hostname", "submit.backtrace.io", FCVAR_RELEASE, "Holds the error collection server hostname"); +static ConVar backtrace_universe("backtrace_universe", "r5reloaded", FCVAR_RELEASE, "Holds the error collection server hosted instance"); +static ConVar backtrace_token("backtrace_token", "f178fd48d89c8fec7f8b6404ae6dae591c330fd3e2599cab888788033944ec98", FCVAR_RELEASE, "Holds the error collection server submission token"); + +static inline string CrashReporter_FormatAttributes(const CCrashHandler* const handler) +{ + const CPUInformation& pi = GetCPUInformation(); + const CrashHardWareInfo_s& hi = handler->GetHardwareInfo(); + + const char* const format = "uuid=%s&" "build_id=%lld&" + "cpu_model=%s&" "cpu_speed=%lf GHz&" "gpu_model=%s&" "gpu_flags=%lu&" + "ram_phys_total=%.2lf MiB&" "ram_phys_avail=%.2lf MiB&" + "ram_virt_total=%.2lf MiB&" "ram_virt_avail=%.2lf MiB&" + "disk_total=%.2lf MiB&" "disk_avail=%.2lf MiB"; + + const DISPLAY_DEVICE& dd = hi.displayDevice; + const MEMORYSTATUSEX& ms = hi.memoryStatus; + + return Format(format, g_LogSessionUUID.c_str(), g_SDKDll.GetNTHeaders()->FileHeader.TimeDateStamp, + pi.m_szProcessorBrand, (f64)(pi.m_Speed / 1000000000.0), dd.DeviceString, dd.StateFlags, + (f64)(ms.ullTotalPhys / (1024.0*1024.0)), (f64)(ms.ullAvailPhys / (1024.0*1024.0)), + (f64)(ms.ullTotalVirtual / (1024.0*1024.0)), (f64)(ms.ullAvailVirtual / (1024.0*1024.0)), + (f64)(hi.totalDiskSpace / (1024.0*1024.0)), (f64)(hi.availDiskSpace / (1024.0*1024.0))); +} + +void CrashReporter_SubmitToCollector(const CCrashHandler* const handler) +{ + if (!backtrace_enabled.GetBool()) + return; + + curl_slist* slist = nullptr; + slist = CURLSlistAppend(slist, "Expect:"); + + if (!slist) + return; // failure. + + const string attributes = CrashReporter_FormatAttributes(handler); + const string hostName = Format("%s%s/%s/%s/%s&%s", + "https://", backtrace_hostname.GetString(), backtrace_universe.GetString(), backtrace_token.GetString(), "minidump", attributes.c_str()); + const string miniDumpPath = Format("%s/%s.dmp", g_LogSessionDirectory.c_str(), "minidump"); + + CURLParams params; + params.readFunction = &CURLReadFileCallback; + params.writeFunction = &CURLWriteStringCallback; + params.timeout = curl_timeout.GetInt(); + params.verifyPeer = ssl_verify_peer.GetBool(); + params.verbose = curl_debug.GetBool(); + + CURLUploadFile(hostName.c_str(), miniDumpPath.c_str(), "rb", nullptr, true, slist, params); +}