From 6e526fa6b95f3abe8dae721f784615b5eb83f1de Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 14:14:20 +0000 Subject: [PATCH] Log the faulting host thread, pc and backtrace of a native crash on Linux A SIGSEGV on the Steam Frame logged only the guest state and 'Host stack trace unavailable on this platform'. With glibc the handler now names the faulting thread, its pc and lr, and a backtrace, each as module + offset for addr2line. The Dawn provider also says when a local package (--dawn-package) replaces the download instead of printing the URL it does not fetch. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_019HBRGKTE1GnN2ah8gcZKr3 --- aurora-main/cmake/AuroraDawnProvider.cmake | 6 ++- runtime/src/main.cpp | 54 ++++++++++++++++++++++ 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/aurora-main/cmake/AuroraDawnProvider.cmake b/aurora-main/cmake/AuroraDawnProvider.cmake index 35214a0..6503cf6 100644 --- a/aurora-main/cmake/AuroraDawnProvider.cmake +++ b/aurora-main/cmake/AuroraDawnProvider.cmake @@ -185,7 +185,11 @@ elseif (_aurora_dawn_provider STREQUAL "package") endif () endif () endif () - message(STATUS "aurora: Fetching prebuilt Dawn package from ${AURORA_DAWN_PACKAGE_URL}") + if (FETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT) + message(STATUS "aurora: Using the local Dawn package ${FETCHCONTENT_SOURCE_DIR_DAWN_PREBUILT}") + else () + message(STATUS "aurora: Fetching prebuilt Dawn package from ${AURORA_DAWN_PACKAGE_URL}") + endif () set(_dawn_prebuilt_hash_argument "") if (AURORA_DAWN_PACKAGE_URL_HASH) diff --git a/runtime/src/main.cpp b/runtime/src/main.cpp index 5a61273..abc2e9b 100644 --- a/runtime/src/main.cpp +++ b/runtime/src/main.cpp @@ -49,6 +49,14 @@ #include #endif #include +#if defined(__GLIBC__) +// The host side of a native crash on desktop Linux: the faulting thread, its pc and lr, and a +// backtrace, each as module + offset for addr2line against the unstripped executable. +#include +#include +#include +#include +#endif #endif #include "abi_bridge.h" @@ -766,6 +774,23 @@ void SetRuntimeExitCodeImpl(int code) { namespace { +#if defined(__GLIBC__) +// One host code address as module + offset (what `addr2line -f -C -e ` takes), +// with the nearest exported symbol when there is one. +void LogHostAddress(const char* label, int index, const void* address) { + Dl_info info{}; + if (address != nullptr && dladdr(address, &info) != 0 && info.dli_fname != nullptr) { + const char* slash = std::strrchr(info.dli_fname, '/'); + const char* module = slash != nullptr ? slash + 1 : info.dli_fname; + const auto offset = reinterpret_cast(address) - reinterpret_cast(info.dli_fbase); + RT_LOGF(RT_TAG_RUNTIME, "%s%d %p %s+0x%zx%s%s\n", label, index, address, module, static_cast(offset), + info.dli_sname != nullptr ? " " : "", info.dli_sname != nullptr ? info.dli_sname : ""); + } else { + RT_LOGF(RT_TAG_RUNTIME, "%s%d %p\n", label, index, address); + } +} +#endif + void DumpHostStackTrace() { #if defined(_WIN32) static std::atomic_flag s_inProgress = ATOMIC_FLAG_INIT; @@ -776,6 +801,19 @@ void DumpHostStackTrace() { std::fputs(trace.c_str(), stderr); std::fflush(stderr); s_inProgress.clear(); +#elif defined(__GLIBC__) + static std::atomic_flag s_inProgress = ATOMIC_FLAG_INIT; + if (s_inProgress.test_and_set()) { + return; + } + std::array frames{}; + const int count = backtrace(frames.data(), static_cast(frames.size())); + RT_LOGF(RT_TAG_RUNTIME, "Host stack trace (%d frames):\n", count); + for (int i = 0; i < count; ++i) { + LogHostAddress(" #", i, frames[static_cast(i)]); + } + std::fflush(stderr); + s_inProgress.clear(); #else RT_LOGF(RT_TAG_RUNTIME, "Host stack trace unavailable on this platform\n"); std::fflush(stderr); @@ -1231,6 +1269,22 @@ void PosixMemoryFaultHandler(int sig, siginfo_t* info, void* ucontextVoid) { popupDetails << ".\n\nThe process transcript and crash log contain the full CPU and stack " "diagnostics."; ShowRuntimeFatalPopup("a native crash occurred", popupDetails.str()); +#if defined(__GLIBC__) + { + char threadName[32] = "?"; + pthread_getname_np(pthread_self(), threadName, sizeof(threadName)); + RT_LOGF(RT_TAG_RUNTIME, "Faulting host thread: '%s' (tid %ld)\n", threadName, static_cast(gettid())); + if (ucontextVoid != nullptr) { + const auto* uc = static_cast(ucontextVoid); +#if defined(__aarch64__) + LogHostAddress("Faulting pc #", 0, reinterpret_cast(uc->uc_mcontext.pc)); + LogHostAddress("Faulting lr #", 0, reinterpret_cast(uc->uc_mcontext.regs[30])); +#elif defined(__x86_64__) + LogHostAddress("Faulting pc #", 0, reinterpret_cast(uc->uc_mcontext.gregs[REG_RIP])); +#endif + } + } +#endif DumpHostStackTrace(); WriteFatalLogImpl(sig == SIGBUS ? "sigbus" : "sigsegv");