diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-28 19:32:48 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-28 19:32:48 -0400 |
| commit | dcf9ed1b33352a27fceef84c3cf9292424c658db (patch) | |
| tree | 8def454103387ab6c120a0513e453640a8910c82 /src/yuzu_cmd | |
| parent | e6820eacafdfd4f5afa2a5e0b4111e6100b2642c (diff) | |
eden-cli: crash handler prints the faulting stack first; log close requests
MiniDumpWithIndirectlyReferencedMemory left an empty file on Eden's
address space, so print the exception, address and stack as
module+offset before writing a smaller dump, and report a failed write.
A window close or quit request is now logged, to tell it from a crash.
Diffstat (limited to 'src/yuzu_cmd')
| -rw-r--r-- | src/yuzu_cmd/emu_window/emu_window_sdl3.cpp | 2 | ||||
| -rw-r--r-- | src/yuzu_cmd/yuzu.cpp | 40 |
2 files changed, 38 insertions, 4 deletions
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl3.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl3.cpp index d62acb36cd..174f8b5328 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl3.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl3.cpp @@ -227,6 +227,7 @@ void EmuWindow_SDL3::OnEvent(SDL_Event& event) { is_shown = true; return OnResize(); case SDL_EVENT_WINDOW_CLOSE_REQUESTED: + LOG_INFO(Frontend, "Window close requested"); is_open = false; return; case SDL_EVENT_KEY_DOWN: @@ -250,6 +251,7 @@ void EmuWindow_SDL3::OnEvent(SDL_Event& event) { case SDL_EVENT_FINGER_UP: return OnFingerUp(); case SDL_EVENT_QUIT: + LOG_INFO(Frontend, "Quit requested"); is_open = false; return; default: diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index 33909c1ec9..bf256766fb 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp @@ -11,6 +11,7 @@ #include <cstdlib> #include <chrono> #include <cstdio> +#include <cstring> #include <iostream> #include <memory> #include <mutex> @@ -72,12 +73,40 @@ __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. +// Prints a code address as module+offset (resolve with llvm-symbolizer and the module's PDB). +static void PrintCodeAddress(const char* label, const void* address) { + HMODULE module{}; + char name[MAX_PATH] = "?"; + if (GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + static_cast<LPCSTR>(address), &module)) { + GetModuleFileNameA(module, name, sizeof(name)); + } + const char* base_name = std::strrchr(name, '\\'); + std::fprintf(stderr, " %s %p %s+%#llx\n", label, address, base_name ? base_name + 1 : name, + static_cast<unsigned long long>(reinterpret_cast<uintptr_t>(address) - + reinterpret_cast<uintptr_t>(module))); +} + 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; } + // The faulting address and stack first: they survive even if the dump fails. + const EXCEPTION_RECORD& record = *exception->ExceptionRecord; + std::fprintf(stderr, "Unhandled exception %#lx on thread %lu, info %#llx %#llx\n", + record.ExceptionCode, GetCurrentThreadId(), + static_cast<unsigned long long>(record.NumberParameters > 0 ? record.ExceptionInformation[0] : 0), + static_cast<unsigned long long>(record.NumberParameters > 1 ? record.ExceptionInformation[1] : 0)); + PrintCodeAddress("at", record.ExceptionAddress); + void* frames[48]; + const USHORT count = RtlCaptureStackBackTrace(0, 48, frames, nullptr); + for (USHORT i = 0; i < count; ++i) { + PrintCodeAddress("frame", frames[i]); + } + std::fflush(stderr); struct ExceptionInformation { DWORD thread_id; EXCEPTION_POINTERS* exception_pointers; @@ -98,11 +127,14 @@ static LONG WINAPI WriteCrashDump(EXCEPTION_POINTERS* exception) { 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); + // MiniDumpWithThreadInfo; the larger MiniDumpWithIndirectlyReferencedMemory failed on + // Eden's address space and left an empty file. + const BOOL ok = write(GetCurrentProcess(), GetCurrentProcessId(), file, 0x1000, + &information, nullptr, nullptr); + const DWORD error = ok ? 0 : GetLastError(); CloseHandle(file); - std::fprintf(stderr, "Crash dump written to %s\n", path); + std::fprintf(stderr, ok ? "Crash dump written to %s\n" : "Crash dump to %s failed (%#lx)\n", + path, error); } return EXCEPTION_CONTINUE_SEARCH; } |
