Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2338,6 +2338,8 @@ if(CLIENT)
checksum.h
client.cpp
client.h
crash_handler.cpp
crash_handler.h
demoedit.cpp
demoedit.h
discord.cpp
Expand Down
7 changes: 7 additions & 0 deletions src/engine/client/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
#include "friends.h"
#include "notifications.h"
#include "serverbrowser.h"
#include "crash_handler.h"

#if defined(CONF_VIDEORECORDER)
#include "video.h"
Expand Down Expand Up @@ -4932,6 +4933,12 @@ int main(int argc, const char **argv)
}
g_Config.m_ClConfigVersion = 1;

#if defined(CONF_FAMILY_WINDOWS)
if (g_Config.m_ClWriteCrashDump > 0) {
InitCrashHandler(g_Config.m_ClWriteCrashDump == 2);
}
#endif

// parse the command line arguments
pConsole->SetUnknownCommandCallback(UnknownArgumentCallback, pClient);
pConsole->ParseArguments(argc - 1, &argv[1]);
Expand Down
99 changes: 99 additions & 0 deletions src/engine/client/crash_handler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#include "crash_handler.h"

#include <base/detect.h>

#if defined(CONF_FAMILY_WINDOWS)
#include <windows.h>
#include <dbghelp.h>
#include <tchar.h>
#include <iostream>
#include <sstream>
#include <iomanip>
#include <string>

#pragma comment(lib, "dbghelp.lib")
#endif

namespace
{
bool g_useFullMemoryDump = false;
}

#if defined(CONF_FAMILY_WINDOWS)
static LPTOP_LEVEL_EXCEPTION_FILTER g_prevExceptionFilter = nullptr;

std::wstring getExecutableName()
{
wchar_t path[MAX_PATH];
GetModuleFileNameW(NULL, path, MAX_PATH);
std::wstring fullPath(path);
size_t pos = fullPath.find_last_of(L"\\/");
return (pos != std::wstring::npos) ? fullPath.substr(pos + 1) : fullPath;
}

std::wstring GenerateDumpFilename()
{
SYSTEMTIME st;
GetLocalTime(&st);

std::wostringstream oss;
oss << getExecutableName()
<< L"_"
<< st.wYear << L"-"
<< std::setw(2) << std::setfill(L'0') << st.wMonth << L"-"
<< std::setw(2) << std::setfill(L'0') << st.wDay << L"_"
<< std::setw(2) << std::setfill(L'0') << st.wHour << L"-"
<< std::setw(2) << std::setfill(L'0') << st.wMinute << L"-"
<< std::setw(2) << std::setfill(L'0') << st.wSecond;

if (g_useFullMemoryDump)
oss << L"_full";

oss << L".dmp";

return oss.str();
}

LONG WINAPI UnhandledExceptionHandler(EXCEPTION_POINTERS* pExceptionPointers)
{
std::wstring dumpFilename = GenerateDumpFilename();

HANDLE hFile = CreateFileW(dumpFilename.c_str(), GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);

if (hFile != INVALID_HANDLE_VALUE) {
MINIDUMP_EXCEPTION_INFORMATION mdei;
mdei.ThreadId = GetCurrentThreadId();
mdei.ExceptionPointers = pExceptionPointers;
mdei.ClientPointers = FALSE;

MINIDUMP_TYPE dumpType = g_useFullMemoryDump
? MiniDumpWithFullMemory
: MiniDumpNormal;

BOOL result = MiniDumpWriteDump(
GetCurrentProcess(),
GetCurrentProcessId(),
hFile,
dumpType,
&mdei,
nullptr,
nullptr
);

CloseHandle(hFile);
}

if (g_prevExceptionFilter)
return g_prevExceptionFilter(pExceptionPointers);

return EXCEPTION_EXECUTE_HANDLER;
}

void InitCrashHandler(bool full)
{
g_useFullMemoryDump = full;
g_prevExceptionFilter = SetUnhandledExceptionFilter(UnhandledExceptionHandler);
}
#else
void InitCrashHandler(bool full) {}
#endif
6 changes: 6 additions & 0 deletions src/engine/client/crash_handler.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef ENGINE_CLIENT_CRASH_HANDLER_H
#define ENGINE_CLIENT_CRASH_HANDLER_H

void InitCrashHandler(bool full);

#endif
4 changes: 4 additions & 0 deletions src/engine/shared/config_variables_tclient.h
Original file line number Diff line number Diff line change
Expand Up @@ -238,3 +238,7 @@ MACRO_CONFIG_INT(ClTClientSettingsTabs, tc_tclient_settings_tabs, 0, 0, 65536, C
// Mod
MACRO_CONFIG_INT(ClShowPlayerHitBoxes, tc_show_player_hit_boxes, 0, 0, 2, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show player hit boxes (1 = predicted, 2 = predicted and unpredicted)")
MACRO_CONFIG_INT(ClHideChatBubbles, tc_hide_chat_bubbles, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Hide your own chat bubbles, only works when authed in remote console")

#if defined(CONF_FAMILY_WINDOWS)
MACRO_CONFIG_INT(ClWriteCrashDump, tc_write_crash_dump, 0, 0, 2, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Whether to write a crash dump on crash (0 = off, 1 = on/normal, 2 = full")
#endif
Loading