mirror of
https://github.com/rei-2/Amalgam
synced 2026-10-10 12:53:10 +08:00
crash logging
This commit is contained in:
@@ -564,11 +564,11 @@
|
||||
<ClCompile Include="src\SDK\Helpers\TraceFilters\TraceFilters.cpp" />
|
||||
<ClCompile Include="src\SDK\SDK.cpp" />
|
||||
<ClCompile Include="src\Utils\ConVars\ConVars.cpp" />
|
||||
<ClCompile Include="src\Utils\CrashLog\CrashLog.cpp" />
|
||||
<ClCompile Include="src\Utils\Hooks\Hooks.cpp" />
|
||||
<ClCompile Include="src\Utils\Interfaces\Interfaces.cpp" />
|
||||
<ClCompile Include="src\Utils\KeyHandler\KeyHandler.cpp" />
|
||||
<ClCompile Include="src\Utils\Memory\Memory.cpp" />
|
||||
<ClCompile Include="src\Utils\Minidump\Minidump.cpp" />
|
||||
<ClCompile Include="src\Utils\NetVars\NetVars.cpp" />
|
||||
<ClCompile Include="src\Utils\Signatures\Signatures.cpp" />
|
||||
<ClCompile Include="src\Utils\Timer\Timer.cpp" />
|
||||
@@ -826,6 +826,7 @@
|
||||
<ClInclude Include="src\SDK\Vars.h" />
|
||||
<ClInclude Include="src\Utils\Assert\Assert.h" />
|
||||
<ClInclude Include="src\Utils\ConVars\ConVars.h" />
|
||||
<ClInclude Include="src\Utils\CrashLog\CrashLog.h" />
|
||||
<ClInclude Include="src\Utils\Feature\Feature.h" />
|
||||
<ClInclude Include="src\Utils\Hash\FNV1A.h" />
|
||||
<ClInclude Include="src\Utils\Hooks\Hooks.h" />
|
||||
@@ -833,7 +834,6 @@
|
||||
<ClInclude Include="src\Utils\KeyHandler\KeyHandler.h" />
|
||||
<ClInclude Include="src\Utils\Math\Math.h" />
|
||||
<ClInclude Include="src\Utils\Memory\Memory.h" />
|
||||
<ClInclude Include="src\Utils\Minidump\Minidump.h" />
|
||||
<ClInclude Include="src\Utils\NetVars\NetVars.h" />
|
||||
<ClInclude Include="src\Utils\Signatures\Signatures.h" />
|
||||
<ClInclude Include="src\Utils\Timer\Timer.h" />
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
<ClCompile Include="src\Utils\Interfaces\Interfaces.cpp" />
|
||||
<ClCompile Include="src\Utils\KeyHandler\KeyHandler.cpp" />
|
||||
<ClCompile Include="src\Utils\Memory\Memory.cpp" />
|
||||
<ClCompile Include="src\Utils\Minidump\Minidump.cpp" />
|
||||
<ClCompile Include="src\Utils\NetVars\NetVars.cpp" />
|
||||
<ClCompile Include="src\Utils\Signatures\Signatures.cpp" />
|
||||
<ClCompile Include="src\Utils\Timer\Timer.cpp" />
|
||||
@@ -172,6 +171,7 @@
|
||||
<ClCompile Include="src\Hooks\CTFGCClientSystem_UpdateAssignedLobby.cpp" />
|
||||
<ClCompile Include="src\Hooks\CTFBadgePanel_SetupBadge.cpp" />
|
||||
<ClCompile Include="src\Hooks\IEngineTrace_TraceRay.cpp" />
|
||||
<ClCompile Include="src\Utils\CrashLog\CrashLog.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\Utils\UtlVector\UtlVector.h" />
|
||||
@@ -301,7 +301,6 @@
|
||||
<ClInclude Include="src\Utils\KeyHandler\KeyHandler.h" />
|
||||
<ClInclude Include="src\Utils\Math\Math.h" />
|
||||
<ClInclude Include="src\Utils\Memory\Memory.h" />
|
||||
<ClInclude Include="src\Utils\Minidump\Minidump.h" />
|
||||
<ClInclude Include="src\Utils\NetVars\NetVars.h" />
|
||||
<ClInclude Include="src\Utils\Signatures\Signatures.h" />
|
||||
<ClInclude Include="src\Utils\Timer\Timer.h" />
|
||||
@@ -438,6 +437,7 @@
|
||||
<ClInclude Include="src\SDK\Definitions\Main\CCaptureFlag.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\IPanel.h" />
|
||||
<ClInclude Include="src\SDK\Definitions\Interfaces\CTFGCClientSystem.h" />
|
||||
<ClInclude Include="src\Utils\CrashLog\CrashLog.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="cpp.hint" />
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <Windows.h>
|
||||
#include "Core/Core.h"
|
||||
#include "Utils/Minidump/Minidump.h"
|
||||
#include "Utils/CrashLog/CrashLog.h"
|
||||
|
||||
DWORD WINAPI MainThread(LPVOID lpParam)
|
||||
{
|
||||
@@ -8,10 +8,6 @@ DWORD WINAPI MainThread(LPVOID lpParam)
|
||||
U::Core.Loop();
|
||||
U::Core.Unload();
|
||||
|
||||
#ifndef _DEBUG
|
||||
SetUnhandledExceptionFilter(nullptr);
|
||||
#endif
|
||||
|
||||
FreeLibraryAndExitThread(static_cast<HMODULE>(lpParam), EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@@ -20,9 +16,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
if (fdwReason == DLL_PROCESS_ATTACH)
|
||||
{
|
||||
#ifndef _DEBUG
|
||||
SetUnhandledExceptionFilter(Minidump::ExceptionFilter);
|
||||
#endif
|
||||
AddVectoredExceptionHandler(1, CrashLog::ExceptionFilter);
|
||||
|
||||
if (const auto hMainThread = CreateThread(nullptr, 0, MainThread, hinstDLL, 0, nullptr))
|
||||
CloseHandle(hMainThread);
|
||||
|
||||
@@ -108,8 +108,6 @@ namespace Vars
|
||||
SUBNAMESPACE_BEGIN(Theme)
|
||||
CVar(Accent, Color_t(255, 101, 101, 255), VISUAL)
|
||||
CVar(Background, Color_t(23, 23, 23, 250), VISUAL)
|
||||
CVar(Foreground, Color_t(11, 11, 11, 250), VISUAL)
|
||||
CVar(Foremost, Color_t(23, 23, 23, 250), VISUAL)
|
||||
CVar(Inactive, Color_t(150, 150, 150, 255), VISUAL)
|
||||
CVar(Active, Color_t(255, 255, 255, 255), VISUAL)
|
||||
SUBNAMESPACE_END(Theme)
|
||||
@@ -156,17 +154,17 @@ namespace Vars
|
||||
CVar(SplashRadius, 90.f)
|
||||
CVar(AutoRelease, 0.f)
|
||||
|
||||
CVar(GroundSamples, 66, NOSAVE) // debug
|
||||
CVar(GroundSamples, 33, NOSAVE) // debug
|
||||
CVar(GroundStraightFuzzyValue, 100.f, NOSAVE) // debug
|
||||
CVar(GroundLowMinimumSamples, 5, NOSAVE) // debug
|
||||
CVar(GroundHighMinimumSamples, 15, NOSAVE) // debug
|
||||
CVar(GroundLowMinimumSamples, 8, NOSAVE) // debug
|
||||
CVar(GroundHighMinimumSamples, 16, NOSAVE) // debug
|
||||
CVar(GroundLowMinimumDistance, 0.f, NOSAVE) // debug
|
||||
CVar(GroundHighMinimumDistance, 2500.f, NOSAVE) // debug
|
||||
|
||||
CVar(AirSamples, 66, NOSAVE) // debug
|
||||
CVar(AirSamples, 33, NOSAVE) // debug
|
||||
CVar(AirStraightFuzzyValue, 10.f, NOSAVE) // debug
|
||||
CVar(AirLowMinimumSamples, 5, NOSAVE) // debug
|
||||
CVar(AirHighMinimumSamples, 5, NOSAVE) // debug
|
||||
CVar(AirLowMinimumSamples, 3, NOSAVE) // debug
|
||||
CVar(AirHighMinimumSamples, 3, NOSAVE) // debug
|
||||
CVar(AirLowMinimumDistance, 100000.f, NOSAVE) // debug
|
||||
CVar(AirHighMinimumDistance, 100000.f, NOSAVE) // debug
|
||||
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
#include "CrashLog.h"
|
||||
|
||||
#include "../../Features/Configs/Configs.h"
|
||||
|
||||
#include <ImageHlp.h>
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
#include <format>
|
||||
#pragma comment(lib, "imagehlp.lib")
|
||||
|
||||
struct Frame
|
||||
{
|
||||
std::string m_sModule = "";
|
||||
uintptr_t m_pAddress = 0;
|
||||
std::string m_sFile = "";
|
||||
unsigned int m_uLine = 0;
|
||||
std::string m_sName = "";
|
||||
};
|
||||
|
||||
static std::deque<Frame> StackTrace(PCONTEXT context)
|
||||
{
|
||||
HANDLE hProcess = GetCurrentProcess();
|
||||
HANDLE hThread = GetCurrentThread();
|
||||
|
||||
OutputDebugStringA("StackTrace\n");
|
||||
if (!SymInitialize(hProcess, nullptr, TRUE))
|
||||
return {};
|
||||
|
||||
OutputDebugStringA("Frame\n");
|
||||
SymSetOptions(SYMOPT_LOAD_LINES);
|
||||
|
||||
STACKFRAME64 frame = {};
|
||||
frame.AddrPC.Offset = context->Rip;
|
||||
frame.AddrFrame.Offset = context->Rbp;
|
||||
frame.AddrStack.Offset = context->Rsp;
|
||||
frame.AddrPC.Mode = AddrModeFlat;
|
||||
frame.AddrFrame.Mode = AddrModeFlat;
|
||||
frame.AddrStack.Mode = AddrModeFlat;
|
||||
|
||||
std::deque<Frame> vTrace = {};
|
||||
while (StackWalk64(IMAGE_FILE_MACHINE_AMD64, hProcess, hThread, &frame, context, nullptr, SymFunctionTableAccess64, SymGetModuleBase64, nullptr))
|
||||
{
|
||||
OutputDebugStringA("StackWalk\n");
|
||||
Frame tFrame = {};
|
||||
|
||||
tFrame.m_pAddress = frame.AddrPC.Offset;
|
||||
|
||||
{
|
||||
auto base = HINSTANCE(SymGetModuleBase64(hProcess, frame.AddrPC.Offset));
|
||||
char buf[MAX_PATH];
|
||||
if (base && GetModuleFileNameA(base, buf, MAX_PATH))
|
||||
{
|
||||
tFrame.m_sModule = std::format("{}, {:#x}", buf, uintptr_t(base));
|
||||
auto find = tFrame.m_sModule.rfind("\\");
|
||||
if (find != std::string::npos)
|
||||
tFrame.m_sModule.replace(0, find + 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
DWORD offset = 0;
|
||||
IMAGEHLP_LINE64 line = {};
|
||||
line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
|
||||
if (SymGetLineFromAddr64(hProcess, frame.AddrPC.Offset, &offset, &line))
|
||||
{
|
||||
tFrame.m_sFile = line.FileName;
|
||||
tFrame.m_uLine = line.LineNumber;
|
||||
auto find = tFrame.m_sFile.rfind("\\");
|
||||
if (find != std::string::npos)
|
||||
tFrame.m_sFile.replace(0, find + 1, "");
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
uintptr_t offset = 0;
|
||||
char buf[sizeof(IMAGEHLP_SYMBOL64) + 255];
|
||||
auto symbol = PIMAGEHLP_SYMBOL64(buf);
|
||||
symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64) + 255;
|
||||
symbol->MaxNameLength = 254;
|
||||
if (SymGetSymFromAddr64(hProcess, frame.AddrPC.Offset, &offset, symbol))
|
||||
tFrame.m_sName = symbol->Name;
|
||||
}
|
||||
|
||||
vTrace.push_back(tFrame);
|
||||
}
|
||||
//if (!vTrace.empty())
|
||||
// vTrace.pop_front();
|
||||
|
||||
SymCleanup(hProcess);
|
||||
|
||||
return vTrace;
|
||||
}
|
||||
|
||||
LONG APIENTRY CrashLog::ExceptionFilter(PEXCEPTION_POINTERS Info)
|
||||
{
|
||||
if (Info->ExceptionRecord->ExceptionCode != EXCEPTION_ACCESS_VIOLATION)
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
|
||||
std::stringstream error;
|
||||
error << std::format("Error: {:#X}\n", Info->ExceptionRecord->ExceptionCode);
|
||||
error << std::format("Address: {:#X}\n\n", uintptr_t(Info->ExceptionRecord->ExceptionAddress));
|
||||
error << std::format("RIP: {:#x}\n", Info->ContextRecord->Rip);
|
||||
error << std::format("EFLAGS: {:#x}\n", Info->ContextRecord->EFlags);
|
||||
error << std::format("RAX: {:#x}\n", Info->ContextRecord->Rax);
|
||||
error << std::format("RCX: {:#x}\n", Info->ContextRecord->Rcx);
|
||||
error << std::format("RDX: {:#x}\n", Info->ContextRecord->Rdx);
|
||||
error << std::format("RBX: {:#x}\n", Info->ContextRecord->Rbx);
|
||||
error << std::format("RSP: {:#x}\n", Info->ContextRecord->Rsp);
|
||||
error << std::format("RBP: {:#x}\n", Info->ContextRecord->Rbp);
|
||||
error << std::format("RSI: {:#x}\n", Info->ContextRecord->Rsi);
|
||||
error << std::format("RDI: {:#x}\n\n", Info->ContextRecord->Rdi);
|
||||
|
||||
auto vTrace = StackTrace(Info->ContextRecord);
|
||||
if (!vTrace.empty())
|
||||
{
|
||||
for (auto& tFrame : vTrace)
|
||||
{
|
||||
error << std::format("{:#x}", tFrame.m_pAddress);
|
||||
if (!tFrame.m_sModule.empty())
|
||||
error << std::format(" ({})", tFrame.m_sModule);
|
||||
if (!tFrame.m_sFile.empty())
|
||||
error << std::format(" ({} L{})", tFrame.m_sFile, tFrame.m_uLine);
|
||||
if (!tFrame.m_sName.empty())
|
||||
error << std::format(" ({})", tFrame.m_sName);
|
||||
error << "\n";
|
||||
}
|
||||
error << "\n";
|
||||
}
|
||||
|
||||
error << "Ctrl + C to copy. Logged to Amalgam\\crash_log.txt. ";
|
||||
|
||||
MessageBox(nullptr, error.str().c_str(), "Unhandled exception", MB_OK | MB_ICONERROR);
|
||||
|
||||
error << "\n\n\n\n";
|
||||
std::ofstream file;
|
||||
file.open(F::Configs.sConfigPath + "\\crash_log.txt", std::ios_base::app);
|
||||
file << error.str();
|
||||
file.close();
|
||||
|
||||
return EXCEPTION_EXECUTE_HANDLER;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
namespace CrashLog
|
||||
{
|
||||
LONG APIENTRY ExceptionFilter(PEXCEPTION_POINTERS Info);
|
||||
}
|
||||
@@ -1,77 +0,0 @@
|
||||
#include "Minidump.h"
|
||||
|
||||
#include <dbghelp.h>
|
||||
#include <shlobj.h>
|
||||
#include <tchar.h>
|
||||
#include <ctime>
|
||||
|
||||
[[noreturn]] void ExitWithMessage(const TCHAR* msg)
|
||||
{
|
||||
MessageBox(
|
||||
nullptr,
|
||||
msg,
|
||||
_T("Unhandled exception"),
|
||||
MB_OK | MB_ICONERROR
|
||||
);
|
||||
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
LONG __stdcall Minidump::ExceptionFilter(PEXCEPTION_POINTERS exPtr)
|
||||
{
|
||||
const HMODULE hLib = LoadLibrary(_T("dbghelp"));
|
||||
if (!hLib)
|
||||
{
|
||||
ExitWithMessage(_T("Could not load dbghelp!"));
|
||||
}
|
||||
|
||||
const auto pMiniDumpWriteDump = reinterpret_cast<decltype(&MiniDumpWriteDump)>(GetProcAddress(hLib, "MiniDumpWriteDump"));
|
||||
|
||||
// Get the MiniDumpWriteDump function
|
||||
if (!pMiniDumpWriteDump)
|
||||
{
|
||||
ExitWithMessage(_T("Could not load MiniDumpWriteDump!"));
|
||||
}
|
||||
|
||||
// Get the dump folde (Desktop)
|
||||
TCHAR buf[512];
|
||||
const auto gfpResult = SHGetFolderPath(nullptr, CSIDL_DESKTOP, nullptr, SHGFP_TYPE_CURRENT, buf);
|
||||
if (FAILED(gfpResult))
|
||||
{
|
||||
ExitWithMessage(_T("Failed to get folder path!"));
|
||||
}
|
||||
|
||||
// Create a file handle
|
||||
TCHAR fileName[MAX_PATH];
|
||||
const int curTime = static_cast<int>(time(nullptr) % 100000);
|
||||
wsprintf(fileName, _T("%s\\Crash_Amalgam_%x.dmp"), buf, curTime);
|
||||
const HANDLE hFile = CreateFile(fileName, GENERIC_READ | GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
||||
|
||||
if (hFile == INVALID_HANDLE_VALUE)
|
||||
{
|
||||
wsprintf(buf, _T("Could not create minidump file!\n\n- Error: %ul\n- File: %s"), GetLastError(), fileName);
|
||||
ExitWithMessage(buf);
|
||||
}
|
||||
|
||||
// Write the minidump
|
||||
MINIDUMP_EXCEPTION_INFORMATION mdei = {
|
||||
GetCurrentThreadId(),
|
||||
exPtr,
|
||||
FALSE
|
||||
};
|
||||
|
||||
if (pMiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(), hFile, MiniDumpNormal, &mdei, nullptr, nullptr))
|
||||
{
|
||||
wsprintf(buf, _T("Minidump created.\n\n- Build: " __TIMESTAMP__ "\n- File: %s"), fileName);
|
||||
}
|
||||
else
|
||||
{
|
||||
wsprintf(buf, _T("Could not create minidump!\n- Error: %ul\n- File: %s"), GetLastError(), fileName);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
FreeLibrary(hLib);
|
||||
CloseHandle(hFile);
|
||||
|
||||
ExitWithMessage(buf);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#pragma once
|
||||
#include "../Feature/Feature.h"
|
||||
#include <Windows.h>
|
||||
|
||||
namespace Minidump
|
||||
{
|
||||
LONG WINAPI ExceptionFilter(PEXCEPTION_POINTERS exPtr);
|
||||
}
|
||||
Reference in New Issue
Block a user