diff --git a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp index 4f19c19a6..ed0cf547a 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_debug_log.hpp @@ -28,6 +28,8 @@ namespace ams::kern { static NOINLINE void Printf(const char *format, ...) __attribute__((format(printf, 1, 2))); static NOINLINE void VPrintf(const char *format, ::std::va_list vl); + static NOINLINE void LogException(const char *str); + static NOINLINE Result PrintUserString(ams::kern::svc::KUserPointer user_str, size_t len); /* Functionality for preserving across sleep. */ @@ -49,6 +51,8 @@ namespace ams::kern { #endif +#define MESOSPHERE_EXCEPTION_LOG(str) ::ams::kern::KDebugLog::LogException(str) + #define MESOSPHERE_RELEASE_LOG(fmt, ...) ::ams::kern::KDebugLog::Printf((fmt), ## __VA_ARGS__) #define MESOSPHERE_RELEASE_VLOG(fmt, vl) ::ams::kern::KDebugLog::VPrintf((fmt), (vl)) diff --git a/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp b/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp index b54815e23..da2b0666e 100644 --- a/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp +++ b/libraries/libmesosphere/source/arch/arm64/kern_exception_handlers.cpp @@ -308,7 +308,7 @@ namespace ams::kern::arch::arm64 { { if (ec != EsrEc_SoftwareStepEl0) { /* If the exception wasn't single-step, print details. */ - MESOSPHERE_RELEASE_LOG("Exception occurred. %016lx\n", GetCurrentProcess().GetProgramId()); + MESOSPHERE_EXCEPTION_LOG("Exception occurred. "); { /* Print the current thread's registers. */ @@ -327,7 +327,7 @@ namespace ams::kern::arch::arm64 { #else { /* Print that an exception occurred. */ - MESOSPHERE_RELEASE_LOG("Exception occurred. %016lx\n", GetCurrentProcess().GetProgramId()); + MESOSPHERE_EXCEPTION_LOG("Exception occurred. "); { /* Print the current thread's registers. */ @@ -496,7 +496,7 @@ namespace ams::kern::arch::arm64 { } /* Print that an exception occurred. */ - MESOSPHERE_RELEASE_LOG("Exception occurred. %016lx\n", GetCurrentProcess().GetProgramId()); + MESOSPHERE_EXCEPTION_LOG("Exception occurred. "); /* Exit the current process. */ GetCurrentProcess().Exit(); diff --git a/libraries/libmesosphere/source/kern_debug_log.cpp b/libraries/libmesosphere/source/kern_debug_log.cpp index 9a14405bd..94211b0ee 100644 --- a/libraries/libmesosphere/source/kern_debug_log.cpp +++ b/libraries/libmesosphere/source/kern_debug_log.cpp @@ -20,15 +20,15 @@ namespace ams::kern { namespace { - KSpinLock g_debug_log_lock; - bool g_initialized_impl; + constinit KSpinLock g_debug_log_lock; + constinit bool g_initialized_impl; /* NOTE: Nintendo's print buffer is size 0x100. */ - char g_print_buffer[0x400]; + constinit char g_print_buffer[0x400]; void PutString(const char *str) { /* Only print if the implementation is initialized. */ - if (!g_initialized_impl) { + if (AMS_UNLIKELY(!g_initialized_impl)) { return; } @@ -73,6 +73,20 @@ namespace ams::kern { #endif + ALWAYS_INLINE void FormatU64(char * const dst, u64 value) { + /* Adjust, so that we can print the value backwards. */ + char *cur = dst + 2 * sizeof(value); + + /* Format the value in (as %016lx) */ + while (cur > dst) { + /* Extract the digit. */ + const auto digit = value & 0xF; + value >>= 4; + + *(--cur) = (digit <= 9) ? ('0' + digit) : ('a' + digit - 10); + } + } + } void KDebugLog::Initialize() { @@ -109,6 +123,33 @@ namespace ams::kern { ::ams::util::TVSNPrintf(dst, dst_size, format, vl); } + void KDebugLog::LogException(const char *str) { + if (KTargetSystem::IsDebugLoggingEnabled()) { + /* Get the current program ID. */ + /* NOTE: Nintendo does this after printing the string, */ + /* but it seems wise to avoid holding the lock/disabling interrupts */ + /* for longer than is strictly necessary. */ + char suffix[18]; + if (const auto *cur_process = GetCurrentProcessPointer(); AMS_LIKELY(cur_process != nullptr)) { + FormatU64(suffix, cur_process->GetProgramId()); + suffix[16] = '\n'; + suffix[17] = '\x00'; + } else { + suffix[0] = '\n'; + suffix[1] = '\x00'; + } + + KScopedInterruptDisable di; + KScopedSpinLock lk(g_debug_log_lock); + + /* Log the string. */ + PutString(str); + + /* Log the program id (and newline) suffix. */ + PutString(suffix); + } + } + Result KDebugLog::PrintUserString(ams::kern::svc::KUserPointer user_str, size_t len) { /* If printing is enabled, print the user string. */ #if defined(MESOSPHERE_ENABLE_DEBUG_PRINT) diff --git a/libraries/libmesosphere/source/svc/kern_svc_exception.cpp b/libraries/libmesosphere/source/svc/kern_svc_exception.cpp index 3f9940008..5a379e8bd 100644 --- a/libraries/libmesosphere/source/svc/kern_svc_exception.cpp +++ b/libraries/libmesosphere/source/svc/kern_svc_exception.cpp @@ -60,7 +60,7 @@ namespace ams::kern::svc { } /* Print that break was called. */ - MESOSPHERE_RELEASE_LOG("Break() called. %016lx\n", GetCurrentProcess().GetProgramId()); + MESOSPHERE_EXCEPTION_LOG("Break() called. "); /* Try to enter JIT debug state. */ if (GetCurrentProcess().EnterJitDebug(ams::svc::DebugEvent_Exception, ams::svc::DebugException_UserBreak, KDebug::GetProgramCounter(GetCurrentThread()), break_reason, address, size)) {