diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-28 18:36:20 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-28 18:36:20 -0400 |
| commit | 395de452330f717917d5aa468e50ea3b001c12ef (patch) | |
| tree | b04f326176c6c93f47b94868fc1055bdaf8fca6b /src | |
| parent | 915132e82b7fe9d33e12dbee719c280b2e87aec9 (diff) | |
eden-cli: EDEN_NX2_CRASH_DUMP writes a minidump on unhandled exceptions
A debugger changes the timing enough to hide some crashes; this catches
them at full speed. dbghelp.dll is loaded only when a dump is written.
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 42 |
1 files changed, 42 insertions, 0 deletions
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index f44916a2e3..33909c1ec9 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -4,6 +4,7 @@ // SPDX-FileCopyrightText: 2014 Citra Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <atomic> #include <iterator> #include <fstream> #include <vector> @@ -67,6 +68,44 @@ extern "C" { __declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; } + +// EDEN_NX2_CRASH_DUMP=<dir>: on an unhandled exception (a real crash; fastmem faults are handled +// before this), write <dir>/eden-crash-<pid>.dmp. A debugger changes the timing enough to hide +// some crashes, so this catches them at full speed. dbghelp.dll is loaded only then. +static LONG WINAPI WriteCrashDump(EXCEPTION_POINTERS* exception) { + static std::atomic<bool> written{}; + const char* directory = std::getenv("EDEN_NX2_CRASH_DUMP"); + if (directory == nullptr || written.exchange(true)) { + return EXCEPTION_CONTINUE_SEARCH; + } + struct ExceptionInformation { + DWORD thread_id; + EXCEPTION_POINTERS* exception_pointers; + BOOL client_pointers; + }; + using MiniDumpWriteDumpFn = BOOL(WINAPI*)(HANDLE, DWORD, HANDLE, int, const ExceptionInformation*, + const void*, const void*); + const HMODULE dbghelp = LoadLibraryA("dbghelp.dll"); + const auto write = dbghelp ? reinterpret_cast<MiniDumpWriteDumpFn>( + GetProcAddress(dbghelp, "MiniDumpWriteDump")) + : nullptr; + if (write == nullptr) { + return EXCEPTION_CONTINUE_SEARCH; + } + char path[MAX_PATH]; + std::snprintf(path, sizeof(path), "%s\\eden-crash-%lu.dmp", directory, GetCurrentProcessId()); + const HANDLE file = CreateFileA(path, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, nullptr); + if (file != INVALID_HANDLE_VALUE) { + const ExceptionInformation information{GetCurrentThreadId(), exception, FALSE}; + // MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithThreadInfo + write(GetCurrentProcess(), GetCurrentProcessId(), file, 0x40 | 0x1000, &information, + nullptr, nullptr); + CloseHandle(file); + std::fprintf(stderr, "Crash dump written to %s\n", path); + } + return EXCEPTION_CONTINUE_SEARCH; +} #endif static void OnStateChanged(const Network::RoomMember::State& state) { @@ -172,6 +211,9 @@ struct SdlState { }; extern "C" SDL_AppResult SDL_AppInit(void **appstate, int argc, char **argv) { +#ifdef _WIN32 + SetUnhandledExceptionFilter(WriteCrashDump); +#endif // SDL calls SDL_AppIterate back to back by default, which kept a host core at 100% polling // input; 240 Hz is plenty for input and the key script. SDL_SetHint(SDL_HINT_MAIN_CALLBACK_RATE, "240"); |
