aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 19:32:48 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-28 19:32:48 -0400
commitdcf9ed1b33352a27fceef84c3cf9292424c658db (patch)
tree8def454103387ab6c120a0513e453640a8910c82 /src
parente6820eacafdfd4f5afa2a5e0b4111e6100b2642c (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')
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl3.cpp2
-rw-r--r--src/yuzu_cmd/yuzu.cpp40
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;
}