From 87764613f29047f58ec3daa722453d5a25fe32b6 Mon Sep 17 00:00:00 2001 From: Michael Scire Date: Thu, 10 Mar 2022 01:15:45 -0800 Subject: [PATCH] abort/error: print backtrace, abuse templates, overhaul result/diag (macos not done yet) --- .../source/secmon_loader_error.cpp | 8 +- .../mariko_fatal/source/fatal_abort_impl.cpp | 2 +- .../source/rebootstub_power_off.cpp | 2 +- exosphere/program/sc7fw/source/sc7fw_main.cpp | 2 +- exosphere/program/source/secmon_error.cpp | 2 +- exosphere/warmboot/source/warmboot_main.cpp | 2 +- .../loader_stub/source/fusee_loader_error.cpp | 10 +- .../source/fusee_exception_handler.cpp | 50 +-- libraries/config/os/linux/os.mk | 2 +- libraries/config/os/macos/os.mk | 2 +- libraries/config/os/windows/os.mk | 2 +- libraries/config/templates/stratosphere.mk | 4 +- .../diag/diag_detailed_assertion_impl.inc | 44 ++- .../impl/ams_impl_unexpected_default.cpp | 24 ++ .../include/mesosphere/kern_panic.hpp | 6 +- .../include/stratosphere/diag.hpp | 4 + .../stratosphere/diag/diag_abort_observer.hpp | 55 ++++ .../diag/diag_assertion_failure_handler.hpp | 31 ++ .../stratosphere/diag/diag_backtrace.hpp | 60 ++++ .../include/stratosphere/diag/diag_symbol.hpp | 23 ++ .../impl/diag_backtrace_impl.os.horizon.hpp | 50 +++ .../impl/diag_backtrace_impl.os.linux.hpp | 38 +++ .../impl/diag_backtrace_impl.os.macos.hpp | 38 +++ .../impl/diag_backtrace_impl.os.windows.hpp | 38 +++ .../include/stratosphere/os.hpp | 2 + .../include/stratosphere/os/os_debug.hpp | 20 ++ .../include/stratosphere/os/os_debug_api.hpp | 32 ++ .../stratosphere/os/os_debug_types.hpp | 31 ++ .../stratosphere/os/os_sdk_thread_info.hpp | 19 ++ .../os/os_sdk_thread_info_api.hpp | 25 ++ .../os/os_sdk_thread_info_types.hpp | 25 ++ libraries/libstratosphere/libstratosphere.mk | 8 +- .../source/diag/diag_abort_observer.cpp | 66 ++++ .../source/diag/diag_assertion_impl.cpp | 266 ++++++++++------ ...ertion_impl_for_nx_asm.board.nintendo_nx.s | 18 +- .../source/diag/diag_backtrace.cpp | 50 +++ .../libstratosphere/source/diag/diag_log.cpp | 15 + .../source/diag/diag_symbol.cpp | 35 +++ .../diag/impl/diag_abort_observer_manager.cpp | 33 ++ .../diag/impl/diag_abort_observer_manager.hpp | 28 ++ .../impl/diag_backtrace_impl.os.generic.cpp | 133 ++++++++ .../impl/diag_backtrace_impl.os.horizon.cpp | 217 +++++++++++++ .../diag/impl/diag_default_abort_observer.cpp | 84 +++++ .../diag/impl/diag_dump_stack_trace.hpp | 23 ++ .../impl/diag_dump_stack_trace.os.generic.cpp | 42 +++ .../impl/diag_dump_stack_trace.os.horizon.cpp | 25 ++ .../diag/impl/diag_get_all_backtrace.cpp | 50 +++ .../diag/impl/diag_get_all_backtrace.hpp | 25 ++ .../source/diag/impl/diag_invoke_abort.hpp | 24 ++ .../impl/diag_invoke_abort.os.generic.cpp | 38 +++ .../impl/diag_invoke_abort.os.horizon.cpp | 38 +++ .../source/diag/impl/diag_symbol_impl.hpp | 24 ++ .../diag/impl/diag_symbol_impl.os.generic.cpp | 289 ++++++++++++++++++ .../diag/impl/diag_symbol_impl.os.horizon.cpp | 31 ++ .../source/fs/fs_access_log.cpp | 8 + .../source/os/impl/os_cache_impl.hpp | 2 +- .../source/os/impl/os_debug_impl.hpp | 29 ++ .../os/impl/os_debug_impl.os.horizon.hpp | 89 ++++++ .../source/os/impl/os_debug_impl.os.linux.hpp | 66 ++++ .../source/os/impl/os_debug_impl.os.macos.hpp | 66 ++++ .../os/impl/os_debug_impl.os.windows.hpp | 55 ++++ .../libstratosphere/source/os/os_debug.cpp | 53 ++++ .../source/result/result_on_assertion.cpp | 40 --- .../source/sf/hipc/sf_hipc_api.os.generic.cpp | 44 +++ .../libvapours/include/vapours/assert.hpp | 87 +++++- .../include/vapours/results/cal_results.hpp | 5 +- .../vapours/results/capsrv_results.hpp | 5 +- .../vapours/results/creport_results.hpp | 4 +- .../include/vapours/results/cs_results.hpp | 4 +- .../include/vapours/results/dd_results.hpp | 4 +- .../include/vapours/results/ddsf_results.hpp | 4 +- .../include/vapours/results/debug_results.hpp | 4 +- .../include/vapours/results/dmnt_results.hpp | 38 +-- .../include/vapours/results/erpt_results.hpp | 4 +- .../include/vapours/results/err_results.hpp | 4 +- .../vapours/results/exosphere_results.hpp | 7 +- .../include/vapours/results/fatal_results.hpp | 4 +- .../include/vapours/results/fs_results.hpp | 6 +- .../include/vapours/results/gpio_results.hpp | 4 +- .../include/vapours/results/hipc_results.hpp | 4 +- .../include/vapours/results/htc_results.hpp | 4 +- .../include/vapours/results/htcfs_results.hpp | 4 +- .../vapours/results/htclow_results.hpp | 6 +- .../include/vapours/results/htcs_results.hpp | 4 +- .../include/vapours/results/i2c_results.hpp | 4 +- .../include/vapours/results/kvdb_results.hpp | 4 +- .../vapours/results/loader_results.hpp | 4 +- .../include/vapours/results/lr_results.hpp | 4 +- .../include/vapours/results/ncm_results.hpp | 4 +- .../include/vapours/results/nim_results.hpp | 4 +- .../include/vapours/results/ns_results.hpp | 4 +- .../include/vapours/results/os_results.hpp | 4 +- .../include/vapours/results/osdbg_results.hpp | 4 +- .../include/vapours/results/pcv_results.hpp | 4 +- .../include/vapours/results/pgl_results.hpp | 4 +- .../include/vapours/results/pm_results.hpp | 4 +- .../vapours/results/powctl_results.hpp | 6 +- .../include/vapours/results/psc_results.hpp | 4 +- .../include/vapours/results/pwm_results.hpp | 4 +- .../vapours/results/results_common.hpp | 91 +++++- .../include/vapours/results/ro_results.hpp | 4 +- .../include/vapours/results/scs_results.hpp | 9 +- .../include/vapours/results/sdmmc_results.hpp | 4 +- .../vapours/results/settings_results.hpp | 4 +- .../include/vapours/results/sf_results.hpp | 36 +-- .../include/vapours/results/sm_results.hpp | 12 +- .../vapours/results/socket_results.hpp | 4 +- .../include/vapours/results/spl_results.hpp | 4 +- .../vapours/results/sprofile_results.hpp | 4 +- .../include/vapours/results/svc_results.hpp | 4 +- .../include/vapours/results/time_results.hpp | 4 +- .../include/vapours/results/tipc_results.hpp | 4 +- .../include/vapours/results/tma_results.hpp | 4 +- .../vapours/results/updater_results.hpp | 4 +- .../include/vapours/results/usb_results.hpp | 4 +- .../include/vapours/results/vi_results.hpp | 4 +- .../source/result/result_get_name.cpp | 73 +++++ .../source/util/util_format_string.cpp | 4 +- 118 files changed, 2843 insertions(+), 369 deletions(-) create mode 100644 libraries/libexosphere/source/impl/ams_impl_unexpected_default.cpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/diag_symbol.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_debug.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_debug_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_debug_types.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp create mode 100644 libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp create mode 100644 libraries/libstratosphere/source/diag/diag_abort_observer.cpp create mode 100644 libraries/libstratosphere/source/diag/diag_backtrace.cpp create mode 100644 libraries/libstratosphere/source/diag/diag_symbol.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_invoke_abort.hpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_symbol_impl.hpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp create mode 100644 libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp create mode 100644 libraries/libstratosphere/source/os/impl/os_debug_impl.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp create mode 100644 libraries/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp create mode 100644 libraries/libstratosphere/source/os/os_debug.cpp delete mode 100644 libraries/libstratosphere/source/result/result_on_assertion.cpp create mode 100644 libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp create mode 100644 libraries/libvapours/source/result/result_get_name.cpp diff --git a/exosphere/loader_stub/source/secmon_loader_error.cpp b/exosphere/loader_stub/source/secmon_loader_error.cpp index c59cc3777..ba2bef587 100644 --- a/exosphere/loader_stub/source/secmon_loader_error.cpp +++ b/exosphere/loader_stub/source/secmon_loader_error.cpp @@ -18,13 +18,13 @@ namespace ams::diag { - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - AMS_UNUSED(file, line, func, expr, value, format); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { + AMS_UNUSED(expr, func, line, file); ams::secmon::loader::ErrorReboot(); } - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - AMS_UNUSED(file, line, func, expr, value); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { + AMS_UNUSED(expr, func, line, file, format); ams::secmon::loader::ErrorReboot(); } diff --git a/exosphere/mariko_fatal/source/fatal_abort_impl.cpp b/exosphere/mariko_fatal/source/fatal_abort_impl.cpp index f764148b3..a049cdc0a 100644 --- a/exosphere/mariko_fatal/source/fatal_abort_impl.cpp +++ b/exosphere/mariko_fatal/source/fatal_abort_impl.cpp @@ -17,7 +17,7 @@ namespace ams::diag { - void AbortImpl() { + NORETURN void AbortImpl() { AMS_SECMON_LOG("AbortImpl was called\n"); AMS_LOG_FLUSH(); reg::Write(0x4, 0xAAAAAAAA); diff --git a/exosphere/program/rebootstub/source/rebootstub_power_off.cpp b/exosphere/program/rebootstub/source/rebootstub_power_off.cpp index 4998f80e3..e71c3627f 100644 --- a/exosphere/program/rebootstub/source/rebootstub_power_off.cpp +++ b/exosphere/program/rebootstub/source/rebootstub_power_off.cpp @@ -50,7 +50,7 @@ namespace ams::rebootstub { namespace ams::diag { - void AbortImpl() { + NORETURN void AbortImpl() { /* Halt the bpmp. */ rebootstub::Halt(); diff --git a/exosphere/program/sc7fw/source/sc7fw_main.cpp b/exosphere/program/sc7fw/source/sc7fw_main.cpp index 7bcc4b910..99c883540 100644 --- a/exosphere/program/sc7fw/source/sc7fw_main.cpp +++ b/exosphere/program/sc7fw/source/sc7fw_main.cpp @@ -111,7 +111,7 @@ namespace ams::sc7fw { namespace ams::diag { - void AbortImpl() { + NORETURN void AbortImpl() { sc7fw::ExceptionHandler(); } diff --git a/exosphere/program/source/secmon_error.cpp b/exosphere/program/source/secmon_error.cpp index e5bdab56b..a8d17bc2d 100644 --- a/exosphere/program/source/secmon_error.cpp +++ b/exosphere/program/source/secmon_error.cpp @@ -50,7 +50,7 @@ namespace ams::diag { } - void AbortImpl() { + NORETURN void AbortImpl() { /* Perform any necessary (typically none) debugging. */ if constexpr (SaveSystemStateForDebug) { SaveSystemStateForDebugAbort(); diff --git a/exosphere/warmboot/source/warmboot_main.cpp b/exosphere/warmboot/source/warmboot_main.cpp index 40212976f..d9527a9c0 100644 --- a/exosphere/warmboot/source/warmboot_main.cpp +++ b/exosphere/warmboot/source/warmboot_main.cpp @@ -98,7 +98,7 @@ namespace ams::warmboot { namespace ams::diag { - void AbortImpl() { + NORETURN void AbortImpl() { warmboot::ExceptionHandler(); } diff --git a/fusee/loader_stub/source/fusee_loader_error.cpp b/fusee/loader_stub/source/fusee_loader_error.cpp index dad352275..690a54b35 100644 --- a/fusee/loader_stub/source/fusee_loader_error.cpp +++ b/fusee/loader_stub/source/fusee_loader_error.cpp @@ -18,13 +18,15 @@ namespace ams::diag { - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - AMS_UNUSED(file, line, func, expr, value, format); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { + AMS_UNUSED(expr, func, line, file); + ams::nxboot::loader::ErrorStop(); } - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - AMS_UNUSED(file, line, func, expr, value); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { + AMS_UNUSED(expr, func, line, file, format); + ams::nxboot::loader::ErrorStop(); } diff --git a/fusee/program/source/fusee_exception_handler.cpp b/fusee/program/source/fusee_exception_handler.cpp index eaff48a0a..64f6cbc22 100644 --- a/fusee/program/source/fusee_exception_handler.cpp +++ b/fusee/program/source/fusee_exception_handler.cpp @@ -27,20 +27,36 @@ namespace ams::nxboot { namespace ams::diag { - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - AMS_UNUSED(file, line, func, expr, format); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { + AMS_UNUSED(expr, func, line, file); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); - nxboot::ShowFatalError("Abort called, lr=%p, value=%" PRIx64 "\n", reinterpret_cast(lr), value); + nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast(lr)); } - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - AMS_UNUSED(file, line, func, expr); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { + AMS_UNUSED(expr, func, line, file, format); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); - nxboot::ShowFatalError("Abort called, lr=%p, value=%" PRIx64 "\n", reinterpret_cast(lr), value); + nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast(lr)); + } + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) { + AMS_UNUSED(expr, func, line, file, result, format); + + u32 lr; + __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); + nxboot::ShowFatalError("Abort called, lr=%p, result=0x%08" PRIX32 "\n", reinterpret_cast(lr), result != nullptr ? result->GetValue() : 0); + } + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exception_info, const char *format, ...) { + AMS_UNUSED(expr, func, line, file, result, exception_info, format); + + u32 lr; + __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); + nxboot::ShowFatalError("Abort called, lr=%p, result=0x%08" PRIX32 "\n", reinterpret_cast(lr), result != nullptr ? result->GetValue() : 0); } NORETURN void AbortImpl() { @@ -49,16 +65,16 @@ namespace ams::diag { nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast(lr)); } - NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - AMS_UNUSED(file, line, func, expr, value); + NORETURN void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { + AMS_UNUSED(type, expr, func, file, line); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); nxboot::ShowFatalError("Assert called, lr=%p\n", reinterpret_cast(lr)); } - NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - AMS_UNUSED(file, line, func, expr, value, format); + NORETURN void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) { + AMS_UNUSED(type, expr, func, file, line, format); u32 lr; __asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory"); @@ -66,17 +82,3 @@ namespace ams::diag { } } - -namespace ams::result::impl { - - NORETURN void OnResultAbort(const char *file, int line, const char *func, const char *expr, Result result) { - ::ams::diag::AbortImpl(file, line, func, expr, result.GetValue(), "Result Abort: 2%03" PRId32 "-%04" PRId32 "", result.GetModule(), result.GetDescription()); - AMS_INFINITE_LOOP(); - __builtin_unreachable(); - } - - NORETURN void OnResultAbort(Result result) { - OnResultAbort("", 0, "", "", result); - } - -} \ No newline at end of file diff --git a/libraries/config/os/linux/os.mk b/libraries/config/os/linux/os.mk index f875e822b..ee225a6f1 100644 --- a/libraries/config/os/linux/os.mk +++ b/libraries/config/os/linux/os.mk @@ -1,5 +1,5 @@ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_LINUX -export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += diff --git a/libraries/config/os/macos/os.mk b/libraries/config/os/macos/os.mk index 6d185126c..f6e4e1afd 100644 --- a/libraries/config/os/macos/os.mk +++ b/libraries/config/os/macos/os.mk @@ -1,5 +1,5 @@ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_MACOS -export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += diff --git a/libraries/config/os/windows/os.mk b/libraries/config/os/windows/os.mk index 7ef43a255..c63a7d8d5 100644 --- a/libraries/config/os/windows/os.mk +++ b/libraries/config/os/windows/os.mk @@ -1,5 +1,5 @@ export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS -export ATMOSPHERE_SETTINGS += +export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer export ATMOSPHERE_CFLAGS += export ATMOSPHERE_CXXFLAGS += export ATMOSPHERE_ASFLAGS += diff --git a/libraries/config/templates/stratosphere.mk b/libraries/config/templates/stratosphere.mk index a052c9272..63b90af9e 100644 --- a/libraries/config/templates/stratosphere.mk +++ b/libraries/config/templates/stratosphere.mk @@ -80,9 +80,9 @@ endif ifeq ($(ATMOSPHERE_BOARD),nx-hac-001) export LIBS := -lstratosphere -lnx else ifeq ($(ATMOSPHERE_BOARD),generic_windows) -export LIBS := -lstratosphere -lwinmm -lws2_32 -lbcrypt +export LIBS := -lstratosphere -lwinmm -lws2_32 -lbcrypt -lbfd -liberty -lintl -lz else ifeq ($(ATMOSPHERE_BOARD),generic_linux) -export LIBS := -lstratosphere -pthread +export LIBS := -lstratosphere -pthread -lbfd -liberty -ldl else ifeq ($(ATMOSPHERE_BOARD),generic_macos) export LIBS := -lstratosphere -pthread else diff --git a/libraries/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc b/libraries/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc index 2f37cd3c9..845d35757 100644 --- a/libraries/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc +++ b/libraries/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc @@ -14,23 +14,22 @@ * along with this program. If not, see . */ -void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { +void AbortImpl(const char *expr, const char *func, const char *file, int line) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Abort Called\n"); AMS_LOG(" Location: %s:%d\n", file, line); AMS_LOG(" Function: %s\n", func); AMS_LOG(" Expression: %s\n", expr); - AMS_LOG(" Value: %016" PRIx64 "\n", value); AMS_LOG("\n"); } #else - AMS_UNUSED(file, line, func, expr, value); + AMS_UNUSED(file, line, func, expr); #endif AbortImpl(); } -void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { +void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Abort Called\n"); @@ -48,12 +47,35 @@ void AbortImpl(const char *file, int line, const char *func, const char *expr, u } } #else - AMS_UNUSED(file, line, func, expr, value, format); + AMS_UNUSED(file, line, func, expr, format); #endif AbortImpl(); } -void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { +void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) { + #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) + { + AMS_LOG("Abort Called\n"); + AMS_LOG(" Location: %s:%d\n", file, line); + AMS_LOG(" Function: %s\n", func); + AMS_LOG(" Expression: %s\n", expr); + AMS_LOG(" Result: 0x%08" PRIx32 "\n", result->GetValue()); + AMS_LOG("\n"); + { + ::std::va_list vl; + va_start(vl, format); + AMS_VLOG(format, vl); + va_end(vl); + AMS_LOG("\n"); + } + } + #else + AMS_UNUSED(file, line, func, expr, result, format); + #endif + AbortImpl(); +} + +void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Assertion Failure\n"); @@ -62,14 +84,16 @@ void AssertionFailureImpl(const char *file, int line, const char *func, const ch AMS_LOG(" Expression: %s\n", expr); AMS_LOG(" Value: %016" PRIx64 "\n", value); AMS_LOG("\n"); + + AMS_UNUSED(type); } #else - AMS_UNUSED(file, line, func, expr, value); + AMS_UNUSED(type, expr, func, file, line); #endif AbortImpl(); } -void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { +void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) { #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) { AMS_LOG("Assertion Failure\n"); @@ -85,9 +109,11 @@ void AssertionFailureImpl(const char *file, int line, const char *func, const ch va_end(vl); AMS_LOG("\n"); } + + AMS_UNUSED(type); } #else - AMS_UNUSED(file, line, func, expr, value, format); + AMS_UNUSED(type, expr, func, file, line, format); #endif AbortImpl(); } diff --git a/libraries/libexosphere/source/impl/ams_impl_unexpected_default.cpp b/libraries/libexosphere/source/impl/ams_impl_unexpected_default.cpp new file mode 100644 index 000000000..3b397ad59 --- /dev/null +++ b/libraries/libexosphere/source/impl/ams_impl_unexpected_default.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::impl { + + NORETURN void UnexpectedDefaultImpl(const char *func, const char *file, int line) { + ::ams::diag::AbortImpl("", func, file, line); + } + +} \ No newline at end of file diff --git a/libraries/libmesosphere/include/mesosphere/kern_panic.hpp b/libraries/libmesosphere/include/mesosphere/kern_panic.hpp index bb1dfa7ea..047a65763 100644 --- a/libraries/libmesosphere/include/mesosphere/kern_panic.hpp +++ b/libraries/libmesosphere/include/mesosphere/kern_panic.hpp @@ -26,12 +26,12 @@ namespace ams::kern { namespace ams::diag { - NORETURN ALWAYS_INLINE void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { + NORETURN ALWAYS_INLINE void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { #if defined(MESOSPHERE_ENABLE_DEBUG_PRINT) - ::ams::kern::Panic(file, line, "ams::diag::AssertionFailureImpl: %s:%s 0x%016" PRIx64 "", func, expr, value); + ::ams::kern::Panic(file, line, "ams::diag::OnAssertionFailure: %d %s:%s", (type == AssertionType_Audit), func, expr); #else ::ams::kern::Panic(); - AMS_UNUSED(file, line, func, expr, value); + AMS_UNUSED(type, expr, func, file, line); #endif } diff --git a/libraries/libstratosphere/include/stratosphere/diag.hpp b/libraries/libstratosphere/include/stratosphere/diag.hpp index 0a51073cc..a8f9c0e2e 100644 --- a/libraries/libstratosphere/include/stratosphere/diag.hpp +++ b/libraries/libstratosphere/include/stratosphere/diag.hpp @@ -20,6 +20,10 @@ #include #include #include +#include +#include #include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp b/libraries/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp new file mode 100644 index 000000000..52a4605b4 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::diag { + + using AbortObserver = void (*)(const AbortInfo &); + + struct AbortObserverHolder { + AbortObserver observer; + AbortObserverHolder *next; + bool is_registered; + }; + + void InitializeAbortObserverHolder(AbortObserverHolder *holder, AbortObserver observer); + + void RegisterAbortObserver(AbortObserverHolder *holder); + void UnregisterAbortObserver(AbortObserverHolder *holder); + void EnableDefaultAbortObserver(bool en); + + struct SdkAbortInfo { + AbortInfo abort_info; + Result result; + const ::ams::os::UserExceptionInfo *exc_info; + }; + + using SdkAbortObserver = void (*)(const SdkAbortInfo &); + + struct SdkAbortObserverHolder { + SdkAbortObserver observer; + SdkAbortObserverHolder *next; + bool is_registered; + }; + + void InitializeSdkAbortObserverHolder(SdkAbortObserverHolder *holder, SdkAbortObserver observer); + + void RegisterSdkAbortObserver(SdkAbortObserverHolder *holder); + void UnregisterSdkAbortObserver(SdkAbortObserverHolder *holder); + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp b/libraries/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp new file mode 100644 index 000000000..b1466a187 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include + +namespace ams::diag { + + enum AssertionFailureOperation { + AssertionFailureOperation_Abort, + AssertionFailureOperation_Continue, + }; + + using AssertionFailureHandler = AssertionFailureOperation (*)(const AssertionInfo &info); + + void SetAssertionFailureHandler(AssertionFailureHandler handler); + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp b/libraries/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp new file mode 100644 index 000000000..de8bbe890 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#if defined(ATMOSPHERE_OS_HORIZON) + #include +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include +#elif defined(ATMOSPHERE_OS_LINUX) + #include +#elif defined(ATMOSPHERE_OS_MACOS) + #include +#else + #error "Unknown OS for diag::Backtrace" +#endif + +namespace ams::diag { + + size_t GetBacktrace(uintptr_t *out, size_t out_size); + + #if defined(ATMOSPHERE_OS_HORIZON) + size_t GetBacktace(uintptr_t *out, size_t out_size, uintptr_t fp, uintptr_t sp, uintptr_t pc); + #endif + + class Backtrace { + private: + impl::Backtrace m_impl; + public: + NOINLINE Backtrace() { + m_impl.Initialize(); + m_impl.Step(); + } + + #if defined(ATMOSPHERE_OS_HORIZON) + Backtrace(uintptr_t fp, uintptr_t sp, uintptr_t pc) { + m_impl.Initialize(fp, sp, pc); + } + #endif + + bool Step() { return m_impl.Step(); } + + uintptr_t GetStackPointer() const { return m_impl.GetStackPointer(); } + uintptr_t GetReturnAddress() const { return m_impl.GetReturnAddress(); } + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/diag_symbol.hpp b/libraries/libstratosphere/include/stratosphere/diag/diag_symbol.hpp new file mode 100644 index 000000000..d43540949 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/diag_symbol.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +namespace ams::diag { + + uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address); + size_t GetSymbolSize(uintptr_t address); + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp new file mode 100644 index 000000000..1500b1476 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + class Backtrace { + private: + static constexpr size_t MemoryInfoBufferSize = 5; + public: + struct StackInfo { + uintptr_t stack_top; + uintptr_t stack_bottom; + }; + private: + s64 m_memory_info_buffer[MemoryInfoBufferSize]{}; + StackInfo *m_current_stack_info = nullptr; + StackInfo m_exception_stack_info{}; + StackInfo m_normal_stack_info{}; + uintptr_t m_fp = 0; + uintptr_t m_prev_fp = 0; + uintptr_t m_lr = 0; + public: + Backtrace() = default; + + void Initialize(); + void Initialize(uintptr_t fp, uintptr_t sp, uintptr_t pc); + + bool Step(); + uintptr_t GetStackPointer() const; + uintptr_t GetReturnAddress() const; + private: + void SetStackInfo(uintptr_t fp, uintptr_t sp); + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp new file mode 100644 index 000000000..23e1e40a1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + class Backtrace { + private: + static constexpr size_t BacktraceEntryCountMax = 0x80; + private: + void *m_backtrace_addresses[BacktraceEntryCountMax]; + size_t m_index = 0; + size_t m_size = 0; + public: + Backtrace() = default; + + void Initialize(); + + bool Step(); + uintptr_t GetStackPointer() const; + uintptr_t GetReturnAddress() const; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp new file mode 100644 index 000000000..23e1e40a1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + class Backtrace { + private: + static constexpr size_t BacktraceEntryCountMax = 0x80; + private: + void *m_backtrace_addresses[BacktraceEntryCountMax]; + size_t m_index = 0; + size_t m_size = 0; + public: + Backtrace() = default; + + void Initialize(); + + bool Step(); + uintptr_t GetStackPointer() const; + uintptr_t GetReturnAddress() const; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp new file mode 100644 index 000000000..23e1e40a1 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + class Backtrace { + private: + static constexpr size_t BacktraceEntryCountMax = 0x80; + private: + void *m_backtrace_addresses[BacktraceEntryCountMax]; + size_t m_index = 0; + size_t m_size = 0; + public: + Backtrace() = default; + + void Initialize(); + + bool Step(); + uintptr_t GetStackPointer() const; + uintptr_t GetReturnAddress() const; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os.hpp b/libraries/libstratosphere/include/stratosphere/os.hpp index 3c4e84b27..7133512cb 100644 --- a/libraries/libstratosphere/include/stratosphere/os.hpp +++ b/libraries/libstratosphere/include/stratosphere/os.hpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -55,3 +56,4 @@ #include #include #include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_debug.hpp b/libraries/libstratosphere/include/stratosphere/os/os_debug.hpp new file mode 100644 index 000000000..1e31b0e27 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_debug.hpp @@ -0,0 +1,20 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_debug_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_debug_api.hpp new file mode 100644 index 000000000..6a1fd3d11 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_debug_api.hpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include +#include + +namespace ams::os { + + void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size); + + void QueryMemoryInfo(MemoryInfo *out); + + Tick GetIdleTickCount(); + + int GetFreeThreadCount(); + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_debug_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_debug_types.hpp new file mode 100644 index 000000000..c9e05965f --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_debug_types.hpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os { + + struct MemoryInfo { + u64 total_available_memory_size; + size_t total_used_memory_size; + size_t total_memory_heap_size; + size_t allocated_memory_heap_size; + size_t program_size; + size_t total_thread_stack_size; + int thread_count; + }; + +} diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp new file mode 100644 index 000000000..933c01206 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp @@ -0,0 +1,19 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp new file mode 100644 index 000000000..375ba73ba --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once +#include +#include + +namespace ams::os { + + void GetThreadStackInfo(uintptr_t *out_stack_top, size_t *out_stack_size, const ThreadType *thread); + +} \ No newline at end of file diff --git a/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp new file mode 100644 index 000000000..dafc51503 --- /dev/null +++ b/libraries/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os { + + enum SdkLastThreadInfoFlag : u32 { + SdkLastThreadInfoFlag_ThreadInSystemCall = (1u << 0), + }; + +} diff --git a/libraries/libstratosphere/libstratosphere.mk b/libraries/libstratosphere/libstratosphere.mk index 83a243660..e646ea02f 100644 --- a/libraries/libstratosphere/libstratosphere.mk +++ b/libraries/libstratosphere/libstratosphere.mk @@ -132,9 +132,9 @@ DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp. #--------------------------------------------------------------------------------- # main targets #--------------------------------------------------------------------------------- -$(OUTPUT) : $(OFILES) +$(OUTPUT) : result_get_name.o $(filter-out result_get_name.o, $(OFILES)) -$(OFILES) : $(GCH_FILES) +$(filter-out result_get_name.o, $(OFILES)) : $(GCH_FILES) $(OFILES_SRC) : $(HFILES_BIN) @@ -146,12 +146,16 @@ hos_stratosphere_api.o: CXXFLAGS += -fno-lto init_operator_new.o: CXXFLAGS += -fno-lto init_libnx_shim.os.horizon.o: CXXFLAGS += -fno-lto +result_get_name.o: CXXFLAGS += -fno-lto + spl_secure_monitor_api.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include fs_id_string_impl.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include ifeq ($(ATMOSPHERE_OS_NAME),windows) os_%.o: CXXFLAGS += -fno-lto fssystem_%.o: CXXFLAGS += -fno-lto +fssrv_%.o: CXXFLAGS += -fno-lto +fs_%.o: CXXFLAGS += -fno-lto endif #--------------------------------------------------------------------------------- diff --git a/libraries/libstratosphere/source/diag/diag_abort_observer.cpp b/libraries/libstratosphere/source/diag/diag_abort_observer.cpp new file mode 100644 index 000000000..183822b08 --- /dev/null +++ b/libraries/libstratosphere/source/diag/diag_abort_observer.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/diag_abort_observer_manager.hpp" + +namespace ams::diag { + + namespace impl { + + constinit bool g_enable_default_abort_observer = true; + + } + + namespace { + + template + void InitializeAbortObserverHolderImpl(Holder *holder, Observer observer) { + holder->observer = observer; + holder->next = nullptr; + holder->is_registered = false; + } + + } + + void InitializeAbortObserverHolder(AbortObserverHolder *holder, AbortObserver observer) { + InitializeAbortObserverHolderImpl(holder, observer); + } + + void RegisterAbortObserver(AbortObserverHolder *holder) { + impl::GetAbortObserverManager()->RegisterObserver(holder); + } + + void UnregisterAbortObserver(AbortObserverHolder *holder) { + impl::GetAbortObserverManager()->UnregisterObserver(holder); + } + + void EnableDefaultAbortObserver(bool en) { + ::ams::diag::impl::g_enable_default_abort_observer = en; + } + + void InitializeSdkAbortObserverHolder(SdkAbortObserverHolder *holder, SdkAbortObserver observer) { + InitializeAbortObserverHolderImpl(holder, observer); + } + + void RegisterSdkAbortObserver(SdkAbortObserverHolder *holder) { + impl::GetSdkAbortObserverManager()->RegisterObserver(holder); + } + + void UnregisterSdkAbortObserver(SdkAbortObserverHolder *holder) { + impl::GetSdkAbortObserverManager()->UnregisterObserver(holder); + } + +} diff --git a/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp b/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp index 537ccedd7..ad0472dea 100644 --- a/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp +++ b/libraries/libstratosphere/source/diag/diag_assertion_impl.cpp @@ -14,7 +14,7 @@ * along with this program. If not, see . */ #include -#include "impl/diag_print_debug_string.hpp" +#include "impl/diag_invoke_abort.hpp" namespace ams::diag { @@ -41,119 +41,193 @@ namespace ams::diag { __builtin_unreachable(); } - inline void DebugLog(const char *format, ...) __attribute__((format(printf, 1, 2))); + constinit os::SdkMutex g_assert_mutex; + constinit os::SdkMutex g_abort_mutex; -#ifdef AMS_ENABLE_DETAILED_ASSERTIONS - constinit os::SdkRecursiveMutex g_debug_log_lock; - constinit char g_debug_buffer[0x400]; + void PrepareAbort() { + #if defined(ATMOSPHERE_OS_HORIZON) + { + /* Get the thread local region. */ + auto * const tlr = svc::GetThreadLocalRegion(); - void DebugLogImpl(const char *format, ::std::va_list vl) { - std::scoped_lock lk(g_debug_log_lock); + /* Clear disable count. */ + tlr->disable_count = 0; - util::VSNPrintf(g_debug_buffer, sizeof(g_debug_buffer), format, vl); - - diag::impl::PrintDebugString(g_debug_buffer, strlen(g_debug_buffer)); + /* If we need to, unpin. */ + if (tlr->interrupt_flag) { + svc::SynchronizePreemptionState(); + } + } + #endif } - void DebugLog(const char *format, ...) { - ::std::va_list vl; - va_start(vl, format); - DebugLogImpl(format, vl); - va_end(vl); + AbortReason ToAbortReason(AssertionType type) { + switch (type) { + case AssertionType_Audit: return AbortReason_Audit; + case AssertionType_Assert: return AbortReason_Assert; + default: + return AbortReason_Abort; + } } -#else - void DebugLog(const char *format, ...) { AMS_UNUSED(format); } -#endif - - } - - NORETURN NOINLINE WEAK_SYMBOL void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - #if defined(ATMOSPHERE_OS_HORIZON) - DebugLog("%016" PRIx64 ": Assertion Failure\n", os::GetCurrentProgramId().value); - #else - DebugLog("0100000000000000: Assertion Failure\n"); - #endif - DebugLog(" Location: %s:%d\n", file, line); - DebugLog(" Function: %s\n", func); - DebugLog(" Expression: %s\n", expr); - DebugLog(" Value: %016" PRIx64 "\n", value); - DebugLog("\n"); -#ifdef AMS_ENABLE_DETAILED_ASSERTIONS - { - ::std::va_list vl; - va_start(vl, format); - DebugLogImpl(format, vl); - va_end(vl); + AssertionFailureOperation DefaultAssertionFailureHandler(const AssertionInfo &) { + return AssertionFailureOperation_Abort; } -#else - AMS_UNUSED(format); -#endif - DebugLog("\n"); - AbortWithValue(value); - } + constinit AssertionFailureHandler g_assertion_failure_handler = &DefaultAssertionFailureHandler; - NORETURN NOINLINE WEAK_SYMBOL void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - #if defined(ATMOSPHERE_OS_HORIZON) - DebugLog("%016" PRIx64 ": Assertion Failure\n", os::GetCurrentProgramId().value); - #else - DebugLog("0100000000000000: Assertion Failure\n"); - #endif - DebugLog(" Location: %s:%d\n", file, line); - DebugLog(" Function: %s\n", func); - DebugLog(" Expression: %s\n", expr); - DebugLog(" Value: %016" PRIx64 "\n", value); - DebugLog("\n"); - DebugLog("\n"); + void ExecuteAssertionFailureOperation(AssertionFailureOperation operation, const AssertionInfo &info) { + switch (operation) { + case AssertionFailureOperation_Continue: + break; + case AssertionFailureOperation_Abort: + { + const AbortInfo abort_info = { + ToAbortReason(info.type), + info.message, + info.expr, + info.func, + info.file, + info.line, + }; - AbortWithValue(value); - } - - NORETURN NOINLINE WEAK_SYMBOL void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) { - #if defined(ATMOSPHERE_OS_HORIZON) - DebugLog("%016" PRIx64 ": Abort Called\n", os::GetCurrentProgramId().value); - #else - DebugLog("0100000000000000: Abort Called\n"); - #endif - DebugLog(" Location: %s:%d\n", file, line); - DebugLog(" Function: %s\n", func); - DebugLog(" Expression: %s\n", expr); - DebugLog(" Value: %016" PRIx64 "\n", value); - DebugLog("\n"); -#ifdef AMS_ENABLE_DETAILED_ASSERTIONS - { - ::std::va_list vl; - va_start(vl, format); - DebugLogImpl(format, vl); - va_end(vl); + ::ams::diag::impl::InvokeAbortObserver(abort_info); + AbortWithValue(0); + } + break; + AMS_UNREACHABLE_DEFAULT_CASE(); + } } -#else - AMS_UNUSED(format); -#endif - DebugLog("\n"); - AbortWithValue(value); + void InvokeAssertionFailureHandler(const AssertionInfo &info) { + const auto operation = g_assertion_failure_handler(info); + ExecuteAssertionFailureOperation(operation, info); + } + + } - NORETURN NOINLINE WEAK_SYMBOL void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) { - #if defined(ATMOSPHERE_OS_HORIZON) - DebugLog("%016" PRIx64 ": Abort Called\n", os::GetCurrentProgramId().value); - #else - DebugLog("0100000000000000: Abort Called\n"); - #endif - DebugLog(" Location: %s:%d\n", file, line); - DebugLog(" Function: %s\n", func); - DebugLog(" Expression: %s\n", expr); - DebugLog(" Value: %016" PRIx64 "\n", value); - DebugLog("\n"); - DebugLog("\n"); + NOINLINE void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) { + /* Prepare to abort. */ + PrepareAbort(); - AbortWithValue(value); + /* Acquire exclusive assert rights. */ + if (g_assert_mutex.IsLockedByCurrentThread()) { + AbortWithValue(0); + } + + std::scoped_lock lk(g_assert_mutex); + + /* Create the assertion info. */ + std::va_list vl; + va_start(vl, format); + + const ::ams::diag::LogMessage message = { format, std::addressof(vl) }; + + const AssertionInfo info = { + type, + std::addressof(message), + expr, + func, + file, + line, + }; + + InvokeAssertionFailureHandler(info); + va_end(vl); } - NORETURN NOINLINE WEAK_SYMBOL void AbortImpl() { - AbortWithValue(0); + void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) { + return OnAssertionFailure(type, expr, func, file, line, ""); + } + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) { + const Result res = ResultSuccess(); + + std::va_list vl{}; + VAbortImpl(expr, func, file, line, std::addressof(res), nullptr, "", vl); + } + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *fmt, ...) { + const Result res = ResultSuccess(); + + std::va_list vl; + va_start(vl, fmt); + VAbortImpl(expr, func, file, line, std::addressof(res), nullptr, fmt, vl); + } + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *fmt, ...) { + std::va_list vl; + va_start(vl, fmt); + VAbortImpl(expr, func, file, line, result, nullptr, fmt, vl); + } + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exc_info, const char *fmt, ...) { + std::va_list vl; + va_start(vl, fmt); + VAbortImpl(expr, func, file, line, result, exc_info, fmt, vl); + } + + NORETURN NOINLINE void VAbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exc_info, const char *fmt, std::va_list vl) { + /* Prepare to abort. */ + PrepareAbort(); + + /* Acquire exclusive abort rights. */ + if (g_abort_mutex.IsLockedByCurrentThread()) { + AbortWithValue(result->GetValue()); + } + + std::scoped_lock lk(g_abort_mutex); + + /* Create abort info. */ + std::va_list cvl; + va_copy(cvl, vl); + const diag::LogMessage message = { fmt, std::addressof(cvl) }; + + const AbortInfo abort_info = { + AbortReason_Abort, + std::addressof(message), + expr, + func, + file, + line, + }; + const SdkAbortInfo sdk_abort_info = { + abort_info, + *result, + exc_info + }; + + /* Invoke observers. */ + ::ams::diag::impl::InvokeAbortObserver(abort_info); + ::ams::diag::impl::InvokeSdkAbortObserver(sdk_abort_info); + + /* Abort. */ + AbortWithValue(result->GetValue()); + } + +} + +namespace ams::impl { + + NORETURN NOINLINE void UnexpectedDefaultImpl(const char *func, const char *file, int line) { + /* Create abort info. */ + std::va_list vl{}; + const ::ams::diag::LogMessage message = { "" , std::addressof(vl) }; + const ::ams::diag::AbortInfo abort_info = { + ::ams::diag::AbortReason_UnexpectedDefault, + std::addressof(message), + "", + func, + file, + line, + }; + + /* Invoke observers. */ + ::ams::diag::impl::InvokeAbortObserver(abort_info); + + /* Abort. */ + ::ams::diag::AbortWithValue(0); } } diff --git a/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s b/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s index e29c989fe..c22914cbf 100644 --- a/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s +++ b/libraries/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s @@ -21,7 +21,19 @@ .balign 0x10 _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE: /* Save x27/x28. */ - stp x27, x28, [sp, #0x10] + stp x27, x28, [sp, #-0x10]! + stp x0, xzr, [sp, #-0x10]! + + /* Inline ams::diag::impl::PrepareAbort() */ + mrs x27, tpidrro_el0 + strh wzr, [x27, #0x100] + ldrh w27, [x27, #0x102] + cbz w27, 0f + svc #0x36 + +0: /* Restore the value from stack. */ + ldr x0, [sp] + add sp, sp, #0x10 /* Put magic std::abort values into x27/x28. */ mov x28, #0xcafe @@ -31,7 +43,7 @@ _ZN3ams4diag4impl23FatalErrorByResultForNxENS_6ResultE: mov x27, #8 /* Abort */ -0: +1: str x28, [x27] nop - b 0b + b 1b diff --git a/libraries/libstratosphere/source/diag/diag_backtrace.cpp b/libraries/libstratosphere/source/diag/diag_backtrace.cpp new file mode 100644 index 000000000..f8eaedf63 --- /dev/null +++ b/libraries/libstratosphere/source/diag/diag_backtrace.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/diag_get_all_backtrace.hpp" + +namespace ams::diag { + + size_t GetBacktrace(uintptr_t *out, size_t out_size) { + /* Validate pre-conditions. */ + AMS_ASSERT(out != nullptr); + AMS_ASSERT(out_size > 0); + + /* Create the backtrace object. */ + ::ams::diag::Backtrace bt{}; + bt.Step(); + + /* Get the backtrace. */ + return ::ams::diag::impl::GetAllBacktrace(out, out_size, bt); + } + + #if defined(ATMOSPHERE_OS_HORIZON) + size_t GetBacktace(uintptr_t *out, size_t out_size, uintptr_t fp, uintptr_t sp, uintptr_t pc) { + /* Validate pre-conditions. */ + AMS_ASSERT(out != nullptr); + AMS_ASSERT(out_size > 0); + + /* Create the backtrace object. */ + ::ams::diag::Backtrace bt{fp, sp, pc}; + bt.Step(); + + /* Get the backtrace. */ + return ::ams::diag::impl::GetAllBacktrace(out, out_size, bt); + } + #endif + + +} diff --git a/libraries/libstratosphere/source/diag/diag_log.cpp b/libraries/libstratosphere/source/diag/diag_log.cpp index 5870e0c98..fc7980e8e 100644 --- a/libraries/libstratosphere/source/diag/diag_log.cpp +++ b/libraries/libstratosphere/source/diag/diag_log.cpp @@ -45,11 +45,26 @@ namespace ams::diag::impl { } void VLogImpl(const LogMetaData &meta, const char *fmt, std::va_list vl) { + #if defined(ATMOSPHERE_OS_HORIZON) /* Print to stack buffer. */ char msg_buffer[DebugPrintBufferLength]; /* TODO: VFormatString using utf-8 printer. */ const size_t len = util::VSNPrintf(msg_buffer, sizeof(msg_buffer), fmt, vl); + #else + /* Print to allocated buffer. */ + std::va_list cvl; + va_copy(cvl, vl); + const auto out_len = util::TVSNPrintf(nullptr, 0, fmt, cvl) + 1; + va_end(cvl); + + char *msg_buffer = static_cast(std::malloc(out_len)); + AMS_ABORT_UNLESS(msg_buffer != nullptr); + ON_SCOPE_EXIT { std::free(msg_buffer); }; + + /* TODO: VFormatString using utf-8 printer. */ + const size_t len = util::TVSNPrintf(msg_buffer, out_len, fmt, vl); + #endif /* Call log observer. */ CallPrintDebugString()(meta, msg_buffer, len, true, true); diff --git a/libraries/libstratosphere/source/diag/diag_symbol.cpp b/libraries/libstratosphere/source/diag/diag_symbol.cpp new file mode 100644 index 000000000..a9a5b496a --- /dev/null +++ b/libraries/libstratosphere/source/diag/diag_symbol.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/diag_symbol_impl.hpp" + +namespace ams::diag { + + uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address) { + AMS_ASSERT(dst != nullptr); + AMS_ASSERT(dst_size > 0); + AMS_ASSERT(address > 0); + + return ::ams::diag::impl::GetSymbolNameImpl(dst, dst_size, address); + } + + size_t GetSymbolSize(uintptr_t address) { + AMS_ASSERT(address > 0); + + return ::ams::diag::impl::GetSymbolSizeImpl(address); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp b/libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp new file mode 100644 index 000000000..ed8c6698b --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_abort_observer_manager.hpp" + +namespace ams::diag::impl { + + AbortObserverManager *GetAbortObserverManager() { + AMS_FUNCTION_LOCAL_STATIC(AbortObserverManager, s_manager); + + return std::addressof(s_manager); + } + + SdkAbortObserverManager *GetSdkAbortObserverManager() { + AMS_FUNCTION_LOCAL_STATIC(SdkAbortObserverManager, s_manager); + + return std::addressof(s_manager); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp b/libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp new file mode 100644 index 000000000..e2bc6f1d2 --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "diag_observer_manager.hpp" + +namespace ams::diag::impl { + + using AbortObserverManager = ObserverManager; + using SdkAbortObserverManager = ObserverManager; + + AbortObserverManager *GetAbortObserverManager(); + SdkAbortObserverManager *GetSdkAbortObserverManager(); + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp b/libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp new file mode 100644 index 000000000..9cd49070a --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +#if defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) +#include +#include +#endif + +namespace ams::diag::impl { + + namespace { + + #if defined(ATMOSPHERE_ARCH_X64) + struct StackFrame { + u64 fp; /* rbp */ + u64 lr; /* rip */ + }; + #elif defined(ATMOSPHERE_ARCH_X86) + struct StackFrame { + u32 fp; /* ebp */ + u32 lr; /* eip */ + } + #elif defined(ATMOSPHERE_ARCH_ARM64) + struct StackFrame { + u64 fp; + u64 lr; + }; + #elif defined(ATMOSPHERE_ARCH_ARM) + struct StackFrame { + u32 fp; + u32 lr; + } + #else + #error "Unknown architecture for generic backtrace." + #endif + + bool TryRead(os::NativeHandle native_handle, void *dst, size_t size, const void *address) { + #if defined(ATMOSPHERE_OS_WINDOWS) + return ::ReadProcessMemory(native_handle, address, dst, size, nullptr); + #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + s32 ret; + do { + ret = ::write(native_handle, address, size); + } while (ret < 0 && errno == EINTR); + + if (ret < 0) { + return false; + } + + std::memcpy(dst, address, size); + return true; + #else + #error "Unknown OS for Backtrace native handle" + #endif + } + + } + + NOINLINE void Backtrace::Initialize() { + /* Clear our size. */ + m_index = 0; + m_size = 0; + + /* Get the base frame pointer. */ + const void *cur_fp = __builtin_frame_address(0); + + /* Try to read stack frames, until we run out. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + const os::NativeHandle native_handle = ::GetCurrentProcess(); + #elif defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS) + os::NativeHandle pipe_handles[2]; + s32 nret; + do { nret = ::pipe(pipe_handles); } while (nret < 0 && errno == EINTR); + if (nret < 0) { return; } + do { nret = ::fcntl(pipe_handles[0], F_SETFL, O_NONBLOCK); } while (nret < 0 && errno == EINTR); + if (nret < 0) { return; } + do { nret = ::fcntl(pipe_handles[1], F_SETFL, O_NONBLOCK); } while (nret < 0 && errno == EINTR); + if (nret < 0) { return; } + ON_SCOPE_EXIT { + do { nret = ::close(pipe_handles[0]); } while (nret < 0 && errno == EINTR); + do { nret = ::close(pipe_handles[1]); } while (nret < 0 && errno == EINTR); + }; + const os::NativeHandle native_handle = pipe_handles[1]; + if (native_handle < 0) { return; } + #else + #error "Unknown OS for Backtrace native handle" + #endif + + StackFrame frame; + while (m_size < BacktraceEntryCountMax) { + /* Clear the frame. */ + frame = {}; + + /* Read the next frame. */ + if (!TryRead(native_handle, std::addressof(frame), sizeof(frame), cur_fp)) { + break; + } + + /* Add the return address. */ + m_backtrace_addresses[m_size++] = reinterpret_cast(frame.lr); + + /* Set the next fp. */ + cur_fp = reinterpret_cast(frame.fp); + } + } + + bool Backtrace::Step() { + return (++m_index) < m_size; + } + + uintptr_t Backtrace::GetStackPointer() const { + return 0; + } + + uintptr_t Backtrace::GetReturnAddress() const { + return reinterpret_cast(m_backtrace_addresses[m_index]); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp b/libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp new file mode 100644 index 000000000..b1f05c93f --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp @@ -0,0 +1,217 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::diag::impl { + + namespace { + + uintptr_t GetAddressValue(uintptr_t address) { + if (address == 0) { + return 0; + } + + if (!util::IsAligned(address, alignof(uintptr_t))) { + return 0; + } + + return *reinterpret_cast(address); + } + + template + svc::MemoryInfo *GetMemoryInfoPointer(T (&arr)[N]) { + /* Check that there's enough space. */ + static_assert(sizeof(T) * N <= sizeof(svc::MemoryInfo)); + static_assert(alignof(T) >= alignof(svc::MemoryInfo)); + return reinterpret_cast(std::addressof(arr[0])); + } + + bool IsValidLinkRegisterValue(uintptr_t lr, svc::MemoryInfo *info) { + /* Ensure the memory info is valid. */ + Result query_res; + + if (!(info->base_address <= lr && lr < info->base_address + info->size) && ({ svc::PageInfo page_info; query_res = svc::QueryMemory(info, std::addressof(page_info), lr); R_FAILED(query_res); })) { + AMS_SDK_LOG("Failed to get backtrace. Query memory failed. (lr: %p, result: %03d-%04d)\n", reinterpret_cast(lr), query_res.GetModule(), query_res.GetDescription()); + return false; + } + + /* Check that lr is valid. */ + if (lr == 0) { + return false; + } + + if (!util::IsAligned(lr, sizeof(u32))) { + AMS_SDK_LOG("Failed to get backtrace. The link register alignment is invalid. (lr: %p)\n", reinterpret_cast(lr)); + return false; + } + + /* Check that the lr points to code. */ + if (info->permission != svc::MemoryPermission_ReadExecute) { + AMS_SDK_LOG("Failed to get backtrace. The link register points out of the code. (lr: %p)\n", reinterpret_cast(lr)); + return false; + } + + return true; + } + + void GetNormalStackInfo(Backtrace::StackInfo *out) { + if (void * const fiber = nullptr /* TODO: os::GetCurrentFiber() */; fiber == nullptr) { + /* Get thread. */ + auto * const thread = os::GetCurrentThread(); + out->stack_top = reinterpret_cast(thread->stack); + out->stack_bottom = reinterpret_cast(thread->stack) + thread->stack_size; + } else { + /* TODO: Fiber. */ + } + } + + bool GetExceptionStackInfo(Backtrace::StackInfo *out, uintptr_t sp) { + /* Get the current stack info. */ + uintptr_t cur_stack = 0; + size_t cur_stack_size = 0; + os::GetCurrentStackInfo(std::addressof(cur_stack), std::addressof(cur_stack_size)); + + /* Get the thread's stack info. */ + uintptr_t thread_stack = 0; + size_t thread_stack_size = 0; + os::GetThreadStackInfo(std::addressof(thread_stack), std::addressof(thread_stack_size), os::GetCurrentThread()); + + /* If the current stack is the thread stack, exception stack isn't being used. */ + if (cur_stack == thread_stack) { + AMS_ASSERT(cur_stack_size == thread_stack_size); + return false; + } + + /* Check if the stack pointer is contained in the current stack. */ + if (!(cur_stack <= sp && sp < cur_stack + cur_stack_size)) { + return false; + } + + /* Set the output. */ + out->stack_top = cur_stack; + out->stack_bottom = cur_stack + cur_stack_size; + return true; + } + + } + + + NOINLINE void Backtrace::Initialize() { + /* Get the stack pointer/frame pointer. */ + uintptr_t fp, sp; + + __asm__ __volatile__( + #if defined(ATMOSPHERE_ARCH_ARM64) + "mov %[fp], fp\n" + "mov %[sp], sp\n" + #elif defined(ATMOSPHERE_ARCH_ARM) + "mov %[fp], x29\n" + "mov %[sp], sp\n" + #else + #error "Unknown architecture for Horizon fp/sp retrieval." + #endif + : [fp]"=&r"(fp), [sp]"=&r"(sp) + : + : "memory" + ); + + /* Set our stack info. */ + this->SetStackInfo(fp, sp); + + /* Step, to get our first lr. */ + this->Step(); + } + + void Backtrace::Initialize(uintptr_t fp, uintptr_t sp, uintptr_t pc) { + /* Set our initial lr. */ + m_lr = pc; + + /* Set our stack info. */ + this->SetStackInfo(fp, sp); + } + + bool Backtrace::Step() { + /* We can't step without a frame pointer. */ + if (m_fp == 0) { + if (m_current_stack_info != std::addressof(m_normal_stack_info)) { + AMS_SDK_LOG("Failed to get backtrace. The frame pointer is null.\n"); + } + return false; + } + + /* The frame pointer needs to be aligned. */ + if (!util::IsAligned(m_fp, sizeof(uintptr_t))) { + AMS_SDK_LOG("Failed to get backtrace. The frame pointer alignment is invalid. (fp: %p)\n", reinterpret_cast(m_fp)); + return false; + } + + /* Ensure our current stack info is good. */ + if (!(m_current_stack_info->stack_top <= m_fp && m_fp < m_current_stack_info->stack_bottom)) { + if (m_current_stack_info != std::addressof(m_exception_stack_info) || !(m_normal_stack_info.stack_top <= m_fp && m_fp < m_normal_stack_info.stack_bottom)) { + AMS_SDK_LOG("Failed to get backtrace. The frame pointer points out of the stack. (fp: %p, stack: %p-%p)\n", reinterpret_cast(m_fp), reinterpret_cast(m_current_stack_info->stack_top), reinterpret_cast(m_current_stack_info->stack_bottom)); + return false; + } + + m_current_stack_info = std::addressof(m_normal_stack_info); + } else if (m_fp <= m_prev_fp) { + AMS_SDK_LOG("Failed to get backtrace. The frame pointer is rewinding. (fp: %p, prev fp: %p, stack: %p-%p)\n", reinterpret_cast(m_fp), reinterpret_cast(m_prev_fp), reinterpret_cast(m_current_stack_info->stack_top), reinterpret_cast(m_current_stack_info->stack_bottom)); + return false; + } + + /* Update our previous fp. */ + m_prev_fp = m_fp; + + /* Read lr/fp. */ + m_lr = GetAddressValue(m_fp + sizeof(m_fp)); + m_fp = GetAddressValue(m_fp); + + /* Check that lr is valid. */ + if (IsValidLinkRegisterValue(m_lr, GetMemoryInfoPointer(m_memory_info_buffer))) { + return true; + } else { + m_lr = 0; + return false; + } + } + + uintptr_t Backtrace::GetStackPointer() const { + if (m_fp != 0) { + return m_fp - sizeof(m_fp); + } else { + return m_current_stack_info->stack_bottom - sizeof(m_fp); + } + } + + uintptr_t Backtrace::GetReturnAddress() const { + return m_lr; + } + + void Backtrace::SetStackInfo(uintptr_t fp, uintptr_t sp) { + /* Get the normal stack info. */ + GetNormalStackInfo(std::addressof(m_normal_stack_info)); + + /* Get the exception stack info. */ + if (GetExceptionStackInfo(std::addressof(m_exception_stack_info), sp)) { + m_current_stack_info = std::addressof(m_exception_stack_info); + } else { + m_current_stack_info = std::addressof(m_normal_stack_info); + } + + /* Set our frame pointer. */ + m_fp = fp; + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp b/libraries/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp new file mode 100644 index 000000000..4c0224808 --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_dump_stack_trace.hpp" + +namespace ams::diag::impl { + + #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_DEBUGGING) + namespace { + + constexpr const char *ToString(AbortReason reason) { + switch (reason) { + case AbortReason_Audit: + return "Auditing Assertion Failure"; + case AbortReason_Assert: + return "Assertion Failure"; + case AbortReason_UnexpectedDefault: + return "Unexpected Default"; + case AbortReason_Abort: + default: + return "Abort"; + } + } + + void DefaultPrinter(const AbortInfo &info) { + /* Get the thread name. */ + const char *thread_name; + if (auto *cur_thread = os::GetCurrentThread(); cur_thread != nullptr) { + thread_name = os::GetThreadNamePointer(cur_thread); + } else { + thread_name = "unknown"; + } + + #if defined(ATMOSPHERE_OS_HORIZON) + { + u64 process_id = 0; + u64 thread_id = 0; + svc::GetProcessId(std::addressof(process_id), svc::PseudoHandle::CurrentProcess); + svc::GetThreadId(std::addressof(thread_id), svc::PseudoHandle::CurrentThread); + AMS_SDK_LOG("%s: '%s' in %s, process=0x%02" PRIX64 ", thread=%" PRIu64 " (%s)\n%s:%d\n", ToString(info.reason), info.expr, info.func, process_id, thread_id, thread_name, info.file, info.line); + } + #elif defined(ATMOSPHERE_OS_WINDOWS) + { + DWORD process_id = ::GetCurrentProcessId(); + DWORD thread_id = ::GetCurrentThreadId(); + AMS_SDK_LOG("%s: '%s' in %s, process=0x%" PRIX64 ", thread=%" PRIu64 " (%s)\n%s:%d\n", ToString(info.reason), info.expr, info.func, static_cast(process_id), static_cast(thread_id), thread_name, info.file, info.line); + } + #else + { + AMS_SDK_LOG("%s: '%s' in %s, thread=%s\n%s:%d\n", ToString(info.reason), info.expr, info.func, thread_name, info.file, info.line); + } + #endif + + AMS_SDK_VLOG(info.message->fmt, *(info.message->vl)); + AMS_SDK_LOG("\n"); + + TentativeDumpStackTrace(); + } + + } + #endif + + void DefaultAbortObserver(const AbortInfo &info) { + #if defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING) + DefaultPrinter(info); + #else + AMS_UNUSED(info); + #endif + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp b/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp new file mode 100644 index 000000000..295b2c89b --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp @@ -0,0 +1,23 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + void TentativeDumpStackTrace(); + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp b/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp new file mode 100644 index 000000000..560b53a4c --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_dump_stack_trace.hpp" + +namespace ams::diag::impl { + + void TentativeDumpStackTrace() { + AMS_SDK_LOG("----------------Stack Trace----------------\n"); + { + /* Get the backtrace. */ + constexpr size_t MaxBackTraceSize = 0x40; + uintptr_t backtrace[MaxBackTraceSize]; + const size_t num_items = ::ams::diag::GetBacktrace(backtrace, MaxBackTraceSize); + + /* Print each item. */ + for (size_t i = 0; i < num_items; ++i) { + char symbol_name[0x200]; + if (const uintptr_t symbol_base = ::ams::diag::GetSymbolName(symbol_name, sizeof(symbol_name), backtrace[i] - 1); symbol_base != 0) { + AMS_SDK_LOG("0x%016" PRIX64 " [ %s+0x%" PRIX64 " ]\n", static_cast(backtrace[i]), symbol_name, static_cast(backtrace[i] - (symbol_base + 1))); + } else { + AMS_SDK_LOG("0x%016" PRIX64 " [ unknown ]\n", static_cast(backtrace[i])); + } + } + } + AMS_SDK_LOG("-------------------------------------------\n"); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp b/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp new file mode 100644 index 000000000..971bc538c --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_dump_stack_trace.hpp" + +namespace ams::diag::impl { + + void TentativeDumpStackTrace() { + /* TODO */ + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp b/libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp new file mode 100644 index 000000000..a96f8c5e4 --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::diag::impl { + + namespace { + + constinit uintptr_t g_abort_impl_return_address = std::numeric_limits::max(); + + } + + size_t GetAllBacktrace(uintptr_t *out, size_t out_size, ::ams::diag::Backtrace &bt) { + size_t count = 0; + do { + /* Check that we can write another return address. */ + if (count >= out_size) { + break; + } + + /* Get the current return address. */ + const uintptr_t ret_addr = bt.GetReturnAddress(); + + /* If it's abort impl, reset the trace we're writing. */ + if (ret_addr == g_abort_impl_return_address) { + count = 0; + } + + /* Set the output pointer. */ + out[count++] = ret_addr; + } while (bt.Step()); + + /* Return the number of addresses written. */ + return count; + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp b/libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp new file mode 100644 index 000000000..1a5a7636f --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + void SetAbortImplAddress(uintptr_t address); + + size_t GetAllBacktrace(uintptr_t *out, size_t out_size, ::ams::diag::Backtrace &bt); + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.hpp b/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.hpp new file mode 100644 index 000000000..513bd0abc --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + void InvokeAbortObserver(const AbortInfo &info); + void InvokeSdkAbortObserver(const SdkAbortInfo &info); + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp b/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp new file mode 100644 index 000000000..33812ab3a --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_abort_observer_manager.hpp" +#include "diag_invoke_abort.hpp" + +namespace ams::diag::impl { + + extern bool g_enable_default_abort_observer; + + void DefaultAbortObserver(const AbortInfo &info); + + void InvokeAbortObserver(const AbortInfo &info) { + if (g_enable_default_abort_observer) { + DefaultAbortObserver(info); + } + + GetAbortObserverManager()->InvokeAllObserver(info); + } + + void InvokeSdkAbortObserver(const SdkAbortInfo &info) { + GetSdkAbortObserverManager()->InvokeAllObserver(info); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp b/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp new file mode 100644 index 000000000..33812ab3a --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_abort_observer_manager.hpp" +#include "diag_invoke_abort.hpp" + +namespace ams::diag::impl { + + extern bool g_enable_default_abort_observer; + + void DefaultAbortObserver(const AbortInfo &info); + + void InvokeAbortObserver(const AbortInfo &info) { + if (g_enable_default_abort_observer) { + DefaultAbortObserver(info); + } + + GetAbortObserverManager()->InvokeAllObserver(info); + } + + void InvokeSdkAbortObserver(const SdkAbortInfo &info) { + GetSdkAbortObserverManager()->InvokeAllObserver(info); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.hpp b/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.hpp new file mode 100644 index 000000000..cdaebf89e --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.hpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::diag::impl { + + uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address); + size_t GetSymbolSizeImpl(uintptr_t address); + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp b/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp new file mode 100644 index 000000000..888fc7a5a --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp @@ -0,0 +1,289 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_symbol_impl.hpp" + +#define PACKAGE "stratosphere" +#define PACKAGE_VERSION STRINGIFY(ATMOSPHERE_RELEASE_VERSION_MAJOR.ATMOSPHERE_RELEASE_VERSION_MINOR.ATMOSPHERE_RELEASE_VERSION_MICRO) + +/* msys2 mingw64 puts headers inside binutils/ */ +#if defined(ATMOSPHERE_OS_WINDOWS) +#include +#include +#else +#include +#endif + +#if defined(ATMOSPHERE_OS_LINUX) +#include +#include +#include + +extern "C" char __init_array_start; +#endif + +#define HAVE_DECL_BASENAME 1 +#include + +namespace ams::diag::impl { + + namespace { + + class BfdHelper { + private: + bfd *m_handle; + asymbol **m_symbol; + size_t m_num_symbol; + size_t m_num_func_symbol; + const char *m_module_name; + uintptr_t m_module_address; + size_t m_module_size; + private: + BfdHelper() : m_handle(nullptr), m_symbol(nullptr), m_module_name(nullptr) { + /* Get the current executable name. */ + char exe_path[4_KB] = {}; + GetExecutablePath(exe_path, sizeof(exe_path)); + + /* Open bfd. */ + bfd *b = ::bfd_openr(exe_path, 0); + if (b == nullptr) { + return; + } + auto bfd_guard = SCOPE_GUARD { ::bfd_close(b); }; + + /* Check the format. */ + if (!::bfd_check_format(b, bfd_object)) { + return; + } + + /* Verify the file has symbols. */ + if ((bfd_get_file_flags(b) & HAS_SYMS) == 0) { + return; + } + + /* Read the symbols. */ + unsigned int _; + void *symbol_table; + s64 num_symbols = bfd_read_minisymbols(b, false, std::addressof(symbol_table), std::addressof(_)); + if (num_symbols == 0) { + num_symbols = bfd_read_minisymbols(b, true, std::addressof(symbol_table), std::addressof(_)); + if (num_symbols < 0) { + return; + } + } + + /* We successfully got the symbol table. */ + bfd_guard.Cancel(); + + m_handle = b; + m_symbol = reinterpret_cast(symbol_table); + m_num_symbol = static_cast(num_symbols); + + /* Sort the symbol table. */ + std::sort(m_symbol + 0, m_symbol + m_num_symbol, [] (asymbol *lhs, asymbol *rhs) { + const bool l_func = (lhs->flags & BSF_FUNCTION); + const bool r_func = (rhs->flags & BSF_FUNCTION); + if (l_func == r_func) { + return bfd_asymbol_value(lhs) < bfd_asymbol_value(rhs); + } else { + return l_func; + } + }); + + /* Determine number of function symbols. */ + m_num_func_symbol = 0; + for (size_t i = 0; i < m_num_symbol; ++i) { + if ((m_symbol[i]->flags & BSF_FUNCTION) == 0) { + m_num_func_symbol = i; + break; + } + } + + for (int i = std::strlen(exe_path) - 1; i >= 0; --i) { + if (exe_path[i] == '/' || exe_path[i] == '\\') { + m_module_name = strdup(exe_path + i + 1); + break; + } + } + + /* Get our module base/size. */ + #if defined(ATMOSPHERE_OS_WINDOWS) + { + MODULEINFO module_info; + if (::GetModuleInformation(::GetCurrentProcess(), ::GetModuleHandleA(nullptr), std::addressof(module_info), sizeof(module_info))) { + m_module_address = reinterpret_cast(module_info.lpBaseOfDll); + m_module_size = static_cast(module_info.SizeOfImage); + } + } + #elif defined(ATMOSPHERE_OS_LINUX) + { + m_module_address = _r_debug.r_map->l_addr; + + m_module_size = reinterpret_cast(std::addressof(__init_array_start)) - m_module_address; + } + #endif + } + + ~BfdHelper() { + if (m_symbol != nullptr) { + std::free(m_symbol); + } + if (m_handle != nullptr) { + ::bfd_close(m_handle); + } + } + public: + static BfdHelper &GetInstance() { + AMS_FUNCTION_LOCAL_STATIC(BfdHelper, s_bfd_helper_instance); + return s_bfd_helper_instance; + } + private: + size_t GetSymbolSizeImpl(asymbol **symbol) const { + /* Do our best to guess. */ + const auto vma = bfd_asymbol_value(*symbol); + if (symbol != m_symbol + m_num_func_symbol - 1) { + return bfd_asymbol_value(*(symbol + 1)) - vma; + } else { + const auto *sec = (*symbol)->section; + return (sec->vma + sec->size) - vma; + } + } + + std::ptrdiff_t GetSymbolAddressDisplacement(uintptr_t address) const { + std::ptrdiff_t displacement = 0; + + if (m_module_address <= address && address < m_module_address + m_module_size) { + displacement = m_module_address; + + #if defined(ATMOSPHERE_OS_WINDOWS) + { + #if defined(__MINGW64__) + displacement -= UINT64_C(0x140000000); + #elif defined(__MINGW32__) + displacement -= UINT64_C(0x400000); + #else + #error "Unknown build context for windows module base!" + #endif + } + #endif + } + + return displacement; + } + + asymbol **GetBestSymbol(uintptr_t address) const { + /* Adjust the symbol address. */ + address -= this->GetSymbolAddressDisplacement(address); + + asymbol **best_symbol = std::lower_bound(m_symbol + 0, m_symbol + m_num_func_symbol, address, [](asymbol *lhs, uintptr_t rhs) { + return bfd_asymbol_value(lhs) < rhs; + }); + + if (best_symbol == m_symbol + m_num_func_symbol) { + return nullptr; + } + + if (bfd_asymbol_value(*best_symbol) != address && best_symbol > m_symbol) { + --best_symbol; + } + + const auto vma = bfd_asymbol_value(*best_symbol); + const auto end = vma + this->GetSymbolSizeImpl(best_symbol); + + if (vma <= address && address < end) { + return best_symbol; + } else { + return nullptr; + } + } + public: + uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address) const { + /* Get the symbol. */ + auto **symbol = this->GetBestSymbol(address); + if (symbol == nullptr) { + return 0; + } + + /* Print the symbol. */ + const char *name = bfd_asymbol_name(*symbol); + if (auto *demangled = bfd_demangle(m_handle, name, DMGL_ANSI | DMGL_PARAMS); demangled != nullptr) { + util::TSNPrintf(dst, dst_size, "%s", demangled); + std::free(demangled); + } else { + util::TSNPrintf(dst, dst_size, "%s", name); + } + + return bfd_asymbol_value(*symbol) + this->GetSymbolAddressDisplacement(address); + } + + size_t GetSymbolSize(uintptr_t address) const { + /* Get the symbol. */ + auto **symbol = this->GetBestSymbol(address); + if (symbol == nullptr) { + return 0; + } + + return this->GetSymbolSizeImpl(symbol); + } + private: + static void GetExecutablePath(char *dst, size_t dst_size) { + #if defined(ATMOSPHERE_OS_WINDOWS) + { + /* Get the module file name. */ + wchar_t module_file_name[0x1000]; + if (::GetModuleFileNameW(0, module_file_name, util::size(module_file_name)) == 0) { + dst[0] = 0; + return; + } + + /* Convert to utf-8. */ + const auto res = ::WideCharToMultiByte(CP_UTF8, 0, module_file_name, -1, dst, dst_size, nullptr, nullptr); + if (res == 0) { + dst[0] = 0; + return; + } + } + #elif defined(ATMOSPHERE_OS_LINUX) + { + if (::readlink("/proc/self/exe", dst, dst_size) == -1) { + dst[0] = 0; + return; + } + } + #elif defined(ATMOSPHERE_OS_MACOS) + { + if (_NSGetExecutablePath(dst, dst_size) != 0) { + dst[0] = 0; + return; + } + } + #else + #error "Unknown OS for BfdHelper GetExecutablePath" + #endif + } + }; + + } + + uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address) { + return BfdHelper::GetInstance().GetSymbolName(dst, dst_size, address); + } + + size_t GetSymbolSizeImpl(uintptr_t address) { + return BfdHelper::GetInstance().GetSymbolSize(address); + } + +} diff --git a/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp b/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp new file mode 100644 index 000000000..28e74a785 --- /dev/null +++ b/libraries/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "diag_symbol_impl.hpp" + +namespace ams::diag::impl { + + uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address) { + AMS_UNUSED(dst, dst_size, address); + AMS_ABORT("TODO"); + } + + size_t GetSymbolSizeImpl(uintptr_t address) { + AMS_UNUSED(address); + AMS_ABORT("TODO"); + } + +} diff --git a/libraries/libstratosphere/source/fs/fs_access_log.cpp b/libraries/libstratosphere/source/fs/fs_access_log.cpp index 9006a921f..3da798fd9 100644 --- a/libraries/libstratosphere/source/fs/fs_access_log.cpp +++ b/libraries/libstratosphere/source/fs/fs_access_log.cpp @@ -144,6 +144,14 @@ namespace ams::fs::impl { } } + template<> const char *IdString::ToString(fs::MountHostOption id) { + if (id == MountHostOption::PseudoCaseSensitive) { + return "MountHostOptionFlag_PseudoCaseSensitive"; + } else { + return ToValueString(static_cast(id._value)); + } + } + template<> const char *IdString::ToString(fs::BisPartitionId id) { switch (id) { using enum fs::BisPartitionId; diff --git a/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp b/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp index 7d3a23f21..663f51bbc 100644 --- a/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp +++ b/libraries/libstratosphere/source/os/impl/os_cache_impl.hpp @@ -23,7 +23,7 @@ #elif defined(ATMOSPHERE_OS_LINUX) #include "os_cache_impl.os.linux.hpp" #elif defined(ATMOSPHERE_OS_MACOS) - #include "os_cache_impl.os.linux.hpp" + #include "os_cache_impl.os.macos.hpp" #else #error "Unknown OS for CacheImpl" #endif diff --git a/libraries/libstratosphere/source/os/impl/os_debug_impl.hpp b/libraries/libstratosphere/source/os/impl/os_debug_impl.hpp new file mode 100644 index 000000000..d8001d308 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_debug_impl.hpp @@ -0,0 +1,29 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +#if defined(ATMOSPHERE_OS_HORIZON) + #include "os_debug_impl.os.horizon.hpp" +#elif defined(ATMOSPHERE_OS_WINDOWS) + #include "os_debug_impl.os.windows.hpp" +#elif defined(ATMOSPHERE_OS_LINUX) + #include "os_debug_impl.os.linux.hpp" +#elif defined(ATMOSPHERE_OS_MACOS) + #include "os_debug_impl.os.macos.hpp" +#else + #error "Unknown OS for DebugImpl" +#endif diff --git a/libraries/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp new file mode 100644 index 000000000..e35a6092b --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include +#include "os_thread_manager.hpp" + +namespace ams::os::impl { + + class DebugHorizonImpl { + public: + static uintptr_t GetCurrentStackPointer() { + uintptr_t v; + __asm__ __volatile__("mov %[v], sp" : [v]"=&r"(v) :: "memory"); + return v; + } + + static void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size) { + /* Check pre-conditions. */ + AMS_ASSERT(out_stack != nullptr); + AMS_ASSERT(out_size != nullptr); + + /* Get the current thread. */ + auto *cur_thread = os::impl::GetCurrentThread(); + auto *cur_fiber = cur_thread->current_fiber; + + /* Get the current stack pointer. */ + uintptr_t cur_sp = GetCurrentStackPointer(); + + /* Determine current stack extents, TODO Fiber */ + uintptr_t stack_top = reinterpret_cast(cur_fiber == nullptr ? cur_thread->stack : /* TODO: cur_fiber->stack */ nullptr); + size_t stack_size = reinterpret_cast(cur_fiber == nullptr ? cur_thread->stack_size : /* TODO: cur_fiber->stack_size */ 0); + + uintptr_t stack_bottom = stack_top + stack_size; + + /* TODO: User exception handler, check if stack is out of range and use exception stack. */ + + /* Check that the stack pointer is in bounds. */ + AMS_ABORT_UNLESS((stack_top <= cur_sp) && (cur_sp < stack_bottom)); + + /* Set the output. */ + *out_stack = stack_top; + *out_size = stack_size; + } + + static void QueryMemoryInfo(os::MemoryInfo *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO: Horizon QueryMemoryInfo"); + } + + static Tick GetIdleTickCount() { + u64 value; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), svc::InfoType_IdleTickCount, svc::InvalidHandle, static_cast(-1))); + + return os::Tick(value); + } + + static Tick GetThreadTickCount() { + u64 value; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), svc::InfoType_ThreadTickCount, svc::PseudoHandle::CurrentThread, static_cast(-1))); + + return os::Tick(value); + } + + static int GetFreeThreadCount() { + u64 value; + R_ABORT_UNLESS(svc::GetInfo(std::addressof(value), svc::InfoType_FreeThreadCount, svc::PseudoHandle::CurrentProcess, 0)); + + AMS_ASSERT(value <= static_cast(std::numeric_limits::max())); + + return static_cast(value); + } + }; + + using DebugImpl = DebugHorizonImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp new file mode 100644 index 000000000..52f091700 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class DebugLinuxImpl { + public: + static void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size) { + /* Check pre-conditions. */ + AMS_ASSERT(out_stack != nullptr); + AMS_ASSERT(out_size != nullptr); + + /* Get the current stack by pthread */ + pthread_attr_t attr; + pthread_attr_init(std::addressof(attr)); + ON_SCOPE_EXIT { pthread_attr_destroy(std::addressof(attr)); }; + + const auto getattr_res = pthread_getattr_np(pthread_self(), std::addressof(attr)); + AMS_ABORT_UNLESS(getattr_res == 0); + + /* Get the thread satck. */ + void *base = nullptr; + size_t size = 0; + const auto getstack_res = pthread_getattr_np(pthread_self(), std::addressof(attr)); + AMS_ABORT_UNLESS(getstack_res == 0); + + *out_stack = reinterpret_cast(base); + *out_size = size; + } + + static void QueryMemoryInfo(os::MemoryInfo *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO: Linux QueryMemoryInfo"); + } + + static Tick GetIdleTickCount() { + return os::Tick(0); + } + + static Tick GetThreadTickCount() { + return os::Tick(0); + } + + static int GetFreeThreadCount() { + return 0; + } + }; + + using DebugImpl = DebugLinuxImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp new file mode 100644 index 000000000..637460a11 --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class DebugMacosImpl { + public: + static void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size) { + /* Check pre-conditions. */ + AMS_ASSERT(out_stack != nullptr); + AMS_ASSERT(out_size != nullptr); + + /* Get the current stack by pthread */ + pthread_attr_t attr; + pthread_attr_init(std::addressof(attr)); + ON_SCOPE_EXIT { pthread_attr_destroy(std::addressof(attr)); }; + + const auto getattr_res = pthread_getattr_np(pthread_self(), std::addressof(attr)); + AMS_ABORT_UNLESS(getattr_res == 0); + + /* Get the thread satck. */ + void *base = nullptr; + size_t size = 0; + const auto getstack_res = pthread_getattr_np(pthread_self(), std::addressof(attr)); + AMS_ABORT_UNLESS(getstack_res == 0); + + *out_stack = reinterpret_cast(base); + *out_size = size; + } + + static void QueryMemoryInfo(os::MemoryInfo *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO: macOS QueryMemoryInfo"); + } + + static Tick GetIdleTickCount() { + return os::Tick(0); + } + + static Tick GetThreadTickCount() { + return os::Tick(0); + } + + static int GetFreeThreadCount() { + return 0; + } + }; + + using DebugImpl = DebugMacosImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp new file mode 100644 index 000000000..7e596f36d --- /dev/null +++ b/libraries/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#pragma once +#include + +namespace ams::os::impl { + + class DebugWindowsImpl { + public: + static void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size) { + /* Check pre-conditions. */ + AMS_ASSERT(out_stack != nullptr); + AMS_ASSERT(out_size != nullptr); + + /* Get the current stack by NT_TIB */ + auto *tib = reinterpret_cast(::NtCurrentTeb()); + + *out_stack = reinterpret_cast(tib->StackLimit); + *out_size = reinterpret_cast(tib->StackBase) - reinterpret_cast(tib->StackLimit); + } + + static void QueryMemoryInfo(os::MemoryInfo *out) { + AMS_UNUSED(out); + AMS_ABORT("TODO: Windows QueryMemoryInfo"); + } + + static Tick GetIdleTickCount() { + return os::Tick(0); + } + + static Tick GetThreadTickCount() { + return os::Tick(0); + } + + static int GetFreeThreadCount() { + return 0; + } + }; + + using DebugImpl = DebugWindowsImpl; + +} \ No newline at end of file diff --git a/libraries/libstratosphere/source/os/os_debug.cpp b/libraries/libstratosphere/source/os/os_debug.cpp new file mode 100644 index 000000000..57bb08ee9 --- /dev/null +++ b/libraries/libstratosphere/source/os/os_debug.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include "impl/os_debug_impl.hpp" + +namespace ams::os { + + void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size) { + /* Get the current stack info. */ + uintptr_t stack_top = 0; + size_t stack_size = 0; + impl::DebugImpl::GetCurrentStackInfo(std::addressof(stack_top), std::addressof(stack_size)); + + /* Basic sanity check. */ + uintptr_t sp = reinterpret_cast(std::addressof(stack_top)); + AMS_ASSERT((stack_top <= sp) && (sp < (stack_top + stack_size))); + AMS_UNUSED(sp); + + /* Set the output. */ + if (out_stack != nullptr) { + *out_stack = stack_top; + } + if (out_size != nullptr) { + *out_size = stack_size; + } + } + + void QueryMemoryInfo(MemoryInfo *out) { + return impl::DebugImpl::QueryMemoryInfo(out); + } + + Tick GetIdleTickCount() { + return impl::DebugImpl::GetIdleTickCount(); + } + + int GetFreeThreadCount() { + return impl::DebugImpl::GetFreeThreadCount(); + } + +} diff --git a/libraries/libstratosphere/source/result/result_on_assertion.cpp b/libraries/libstratosphere/source/result/result_on_assertion.cpp deleted file mode 100644 index f9eb49d9c..000000000 --- a/libraries/libstratosphere/source/result/result_on_assertion.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) Atmosphère-NX - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -#include - -namespace ams::result::impl { - - NORETURN WEAK_SYMBOL void OnResultAbort(const char *file, int line, const char *func, const char *expr, Result result) { - ::ams::diag::AbortImpl(file, line, func, expr, result.GetValue(), "Result Abort: 2%03d-%04d", result.GetModule(), result.GetDescription()); - AMS_INFINITE_LOOP(); - __builtin_unreachable(); - } - - NORETURN WEAK_SYMBOL void OnResultAbort(Result result) { - OnResultAbort("", 0, "", "", result); - } - - NORETURN WEAK_SYMBOL void OnResultAssertion(const char *file, int line, const char *func, const char *expr, Result result) { - ::ams::diag::AssertionFailureImpl(file, line, func, expr, result.GetValue(), "Result Assertion: 2%03d-%04d", result.GetModule(), result.GetDescription()); - AMS_INFINITE_LOOP(); - __builtin_unreachable(); - } - - NORETURN WEAK_SYMBOL void OnResultAssertion(Result result) { - OnResultAssertion("", 0, "", "", result); - } - -} \ No newline at end of file diff --git a/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp b/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp new file mode 100644 index 000000000..a6fd71d34 --- /dev/null +++ b/libraries/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include + +namespace ams::sf::hipc { + + void AttachMultiWaitHolderForAccept(os::MultiWaitHolderType *, os::NativeHandle) { + AMS_ABORT("TODO: Generic ams::sf::hipc::AttachMultiWaitHolderForAccept"); + } + + void AttachMultiWaitHolderForReply(os::MultiWaitHolderType *, os::NativeHandle) { + AMS_ABORT("TODO: Generic ams::sf::hipc::AttachMultiWaitHolderForAccept"); + } + + Result Receive(ReceiveResult *, os::NativeHandle, const cmif::PointerAndSize &) { + AMS_ABORT("TODO: Generic ams::sf::hipc::Receive(ReceiveResult *, os::NativeHandle, const cmif::PointerAndSize &)"); + } + + Result Receive(bool *, os::NativeHandle, const cmif::PointerAndSize &) { + AMS_ABORT("TODO: Generic ams::sf::hipc::Receive(bool *, os::NativeHandle, const cmif::PointerAndSize &)"); + } + + Result Reply(os::NativeHandle, const cmif::PointerAndSize &) { + AMS_ABORT("TODO: Generic ams::sf::hipc::Reply"); + } + + Result CreateSession(os::NativeHandle *, os::NativeHandle *) { + AMS_ABORT("TODO: Generic ams::sf::hipc::CreateSession"); + } + +} diff --git a/libraries/libvapours/include/vapours/assert.hpp b/libraries/libvapours/include/vapours/assert.hpp index 836013437..d901f2d9b 100644 --- a/libraries/libvapours/include/vapours/assert.hpp +++ b/libraries/libvapours/include/vapours/assert.hpp @@ -16,48 +16,103 @@ #pragma once #include +namespace ams { + + class Result; + + namespace os { + + struct UserExceptionInfo; + + } + + namespace impl { + + NORETURN void UnexpectedDefaultImpl(const char *func, const char *file, int line); + + } + +} + namespace ams::diag { - NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); - NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value); + enum AssertionType { + AssertionType_Audit, + AssertionType_Assert, + }; - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) __attribute__((format(printf, 6, 7))); - NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value); - NORETURN void AbortImpl(); + struct LogMessage; + + struct AssertionInfo { + AssertionType type; + const LogMessage *message; + const char *expr; + const char *func; + const char *file; + int line; + }; + + enum AbortReason { + AbortReason_Audit, + AbortReason_Assert, + AbortReason_Abort, + AbortReason_UnexpectedDefault, + }; + + struct AbortInfo { + AbortReason reason; + const LogMessage *message; + const char *expr; + const char *func; + const char *file; + int line; + }; + + void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) __attribute__((format(printf, 6, 7))); + void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line); + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) __attribute__((format(printf, 5, 6))); + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) __attribute__((format(printf, 6, 7))); + + NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exception_info, const char *fmt, ...) __attribute__((format(printf, 7, 8))); + + NORETURN void VAbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exception_info, const char *fmt, std::va_list vl); } #ifdef AMS_ENABLE_DETAILED_ASSERTIONS -#define AMS_CALL_ASSERT_FAIL_IMPL(cond, ...) ::ams::diag::AssertionFailureImpl(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, 0, ## __VA_ARGS__) -#define AMS_CALL_ABORT_IMPL(cond, ...) ::ams::diag::AbortImpl(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, 0, ## __VA_ARGS__) +#define AMS_CALL_ASSERT_FAIL_IMPL(type, expr, ...) ::ams::diag::OnAssertionFailure(type, expr, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## __VA_ARGS__) +#define AMS_CALL_ABORT_IMPL(expr, ...) ::ams::diag::AbortImpl(expr, __PRETTY_FUNCTION__, __FILE__, __LINE__, ## __VA_ARGS__) +#define AMS_UNREACHABLE_DEFAULT_CASE() default: ::ams::impl::UnexpectedDefaultImpl(__PRETTY_FUNCTION__, __FILE__, __LINE__) #else -#define AMS_CALL_ASSERT_FAIL_IMPL(cond, ...) ::ams::diag::AssertionFailureImpl("", 0, "", "", 0) -#define AMS_CALL_ABORT_IMPL(cond, ...) ::ams::diag::AbortImpl(); AMS_UNUSED(cond, ## __VA_ARGS__) +#define AMS_CALL_ASSERT_FAIL_IMPL(type, expr, ...) ::ams::diag::OnAssertionFailure(type, "", "", "", 0) +#define AMS_CALL_ABORT_IMPL(expr, ...) ::ams::diag::AbortImpl("", "", "", 0); AMS_UNUSED(expr, ## __VA_ARGS__) +#define AMS_UNREACHABLE_DEFAULT_CASE() default: ::ams::impl::UnexpectedDefaultImpl("", "", 0) #endif #ifdef AMS_ENABLE_ASSERTIONS -#define AMS_ASSERT_IMPL(expr, ...) \ +#define AMS_ASSERT_IMPL(type, expr, ...) \ { \ if (std::is_constant_evaluated()) { \ AMS_ASSUME(static_cast(expr)); \ } else { \ if (const bool __tmp_ams_assert_val = static_cast(expr); (!__tmp_ams_assert_val)) { \ - AMS_CALL_ASSERT_FAIL_IMPL(#expr, ## __VA_ARGS__); \ + AMS_CALL_ASSERT_FAIL_IMPL(type, #expr, ## __VA_ARGS__); \ } \ } \ } #elif defined(AMS_PRESERVE_ASSERTION_EXPRESSIONS) -#define AMS_ASSERT_IMPL(expr, ...) AMS_UNUSED(expr, ## __VA_ARGS__) +#define AMS_ASSERT_IMPL(type, expr, ...) AMS_UNUSED(expr, ## __VA_ARGS__) #else -#define AMS_ASSERT_IMPL(expr, ...) static_cast(0) +#define AMS_ASSERT_IMPL(type, expr, ...) static_cast(0) #endif -#define AMS_ASSERT(expr, ...) AMS_ASSERT_IMPL(expr, ## __VA_ARGS__) +#define AMS_ASSERT(expr, ...) AMS_ASSERT_IMPL(::ams::diag::AssertionType_Assert, expr, ## __VA_ARGS__) -#define AMS_UNREACHABLE_DEFAULT_CASE() default: AMS_CALL_ABORT_IMPL("Unreachable default case entered") #ifdef AMS_BUILD_FOR_AUDITING -#define AMS_AUDIT(expr, ...) AMS_ASSERT(expr, ## __VA_ARGS__) +#define AMS_AUDIT(expr, ...) AMS_ASSERT_IMPL(::ams::diag::AssertionType_Audit, expr, ## __VA_ARGS__) #elif defined(AMS_PRESERVE_AUDIT_EXPRESSIONS) #define AMS_AUDIT(expr, ...) AMS_UNUSED(expr, ## __VA_ARGS__) #else diff --git a/libraries/libvapours/include/vapours/results/cal_results.hpp b/libraries/libvapours/include/vapours/results/cal_results.hpp index 2d99fef2a..cb770ef55 100644 --- a/libraries/libvapours/include/vapours/results/cal_results.hpp +++ b/libraries/libvapours/include/vapours/results/cal_results.hpp @@ -16,11 +16,10 @@ #pragma once #include +#include namespace ams::cal { - R_DEFINE_NAMESPACE_RESULT_MODULE(198); - - R_DEFINE_ERROR_RESULT(CalibrationDataCrcError, 101); + using powctl::ResultCalibrationDataCrcError; } diff --git a/libraries/libvapours/include/vapours/results/capsrv_results.hpp b/libraries/libvapours/include/vapours/results/capsrv_results.hpp index 965d7f9d9..d353ab93f 100644 --- a/libraries/libvapours/include/vapours/results/capsrv_results.hpp +++ b/libraries/libvapours/include/vapours/results/capsrv_results.hpp @@ -16,9 +16,10 @@ #pragma once #include -namespace ams::capsrv { - R_DEFINE_NAMESPACE_RESULT_MODULE(206); +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::capsrv, 206); + +namespace ams::capsrv { R_DEFINE_ERROR_RANGE(AlbumError, 2, 99); R_DEFINE_ERROR_RESULT(AlbumWorkMemoryError, 3); diff --git a/libraries/libvapours/include/vapours/results/creport_results.hpp b/libraries/libvapours/include/vapours/results/creport_results.hpp index a3b4d7a62..f7d424e6e 100644 --- a/libraries/libvapours/include/vapours/results/creport_results.hpp +++ b/libraries/libvapours/include/vapours/results/creport_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::creport { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::creport, 168); - R_DEFINE_NAMESPACE_RESULT_MODULE(168); +namespace ams::creport { R_DEFINE_ERROR_RESULT(UndefinedInstruction, 0); R_DEFINE_ERROR_RESULT(InstructionAbort, 1); diff --git a/libraries/libvapours/include/vapours/results/cs_results.hpp b/libraries/libvapours/include/vapours/results/cs_results.hpp index b1e63802f..8ff32ac73 100644 --- a/libraries/libvapours/include/vapours/results/cs_results.hpp +++ b/libraries/libvapours/include/vapours/results/cs_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::cs { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::cs, 204); - R_DEFINE_NAMESPACE_RESULT_MODULE(204); +namespace ams::cs { R_DEFINE_ERROR_RESULT(UnknownCommand, 2); R_DEFINE_ERROR_RESULT(OutOfResource, 4); diff --git a/libraries/libvapours/include/vapours/results/dd_results.hpp b/libraries/libvapours/include/vapours/results/dd_results.hpp index 648fb6b67..dd1f042b0 100644 --- a/libraries/libvapours/include/vapours/results/dd_results.hpp +++ b/libraries/libvapours/include/vapours/results/dd_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::dd { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::dd, 6); - R_DEFINE_NAMESPACE_RESULT_MODULE(6); +namespace ams::dd { R_DEFINE_ERROR_RESULT(EndOfQuery, 1); R_DEFINE_ERROR_RESULT(InvalidCurrentMemory, 2); diff --git a/libraries/libvapours/include/vapours/results/ddsf_results.hpp b/libraries/libvapours/include/vapours/results/ddsf_results.hpp index 73378d4e8..357254291 100644 --- a/libraries/libvapours/include/vapours/results/ddsf_results.hpp +++ b/libraries/libvapours/include/vapours/results/ddsf_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::ddsf { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::ddsf, 30); - R_DEFINE_NAMESPACE_RESULT_MODULE(30); +namespace ams::ddsf { R_DEFINE_ERROR_RESULT(OutOfResource, 1); R_DEFINE_ERROR_RESULT(NotSupported, 2); diff --git a/libraries/libvapours/include/vapours/results/debug_results.hpp b/libraries/libvapours/include/vapours/results/debug_results.hpp index d93cff64f..6db0d7223 100644 --- a/libraries/libvapours/include/vapours/results/debug_results.hpp +++ b/libraries/libvapours/include/vapours/results/debug_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::dbg { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::dbg, 183); - R_DEFINE_NAMESPACE_RESULT_MODULE(183); +namespace ams::dbg { R_DEFINE_ERROR_RESULT(CannotDebug, 1); R_DEFINE_ERROR_RESULT(AlreadyAttached, 2); diff --git a/libraries/libvapours/include/vapours/results/dmnt_results.hpp b/libraries/libvapours/include/vapours/results/dmnt_results.hpp index 29323d327..f6203c9b4 100644 --- a/libraries/libvapours/include/vapours/results/dmnt_results.hpp +++ b/libraries/libvapours/include/vapours/results/dmnt_results.hpp @@ -17,34 +17,34 @@ #pragma once #include -namespace ams::dmnt { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::dmnt, 13); - R_DEFINE_NAMESPACE_RESULT_MODULE(13); +namespace ams::dmnt { R_DEFINE_ERROR_RESULT(Unknown, 1); R_DEFINE_ERROR_RESULT(DebuggingDisabled, 2); /* Atmosphere extension. */ - namespace cheat { + // namespace cheat { - R_DEFINE_ABSTRACT_ERROR_RANGE(CheatError, 6500, 6599); - R_DEFINE_ERROR_RESULT(CheatNotAttached, 6500); - R_DEFINE_ERROR_RESULT(CheatNullBuffer, 6501); - R_DEFINE_ERROR_RESULT(CheatInvalidBuffer, 6502); - R_DEFINE_ERROR_RESULT(CheatUnknownId, 6503); - R_DEFINE_ERROR_RESULT(CheatOutOfResource, 6504); - R_DEFINE_ERROR_RESULT(CheatInvalid, 6505); - R_DEFINE_ERROR_RESULT(CheatCannotDisable, 6506); + R_DEFINE_ABSTRACT_ERROR_RANGE_NS(cheat, CheatError, 6500, 6599); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatNotAttached, 6500); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatNullBuffer, 6501); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatInvalidBuffer, 6502); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatUnknownId, 6503); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatOutOfResource, 6504); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatInvalid, 6505); + R_DEFINE_ERROR_RESULT_NS(cheat, CheatCannotDisable, 6506); - R_DEFINE_ABSTRACT_ERROR_RANGE(FrozenAddressError, 6600, 6699); - R_DEFINE_ERROR_RESULT(FrozenAddressInvalidWidth, 6600); - R_DEFINE_ERROR_RESULT(FrozenAddressAlreadyExists, 6601); - R_DEFINE_ERROR_RESULT(FrozenAddressNotFound, 6602); - R_DEFINE_ERROR_RESULT(FrozenAddressOutOfResource, 6603); + R_DEFINE_ABSTRACT_ERROR_RANGE_NS(cheat, FrozenAddressError, 6600, 6699); + R_DEFINE_ERROR_RESULT_NS(cheat, FrozenAddressInvalidWidth, 6600); + R_DEFINE_ERROR_RESULT_NS(cheat, FrozenAddressAlreadyExists, 6601); + R_DEFINE_ERROR_RESULT_NS(cheat, FrozenAddressNotFound, 6602); + R_DEFINE_ERROR_RESULT_NS(cheat, FrozenAddressOutOfResource, 6603); - R_DEFINE_ABSTRACT_ERROR_RANGE(VirtualMachineError, 6700, 6799); - R_DEFINE_ERROR_RESULT(VirtualMachineInvalidConditionDepth, 6700); + R_DEFINE_ABSTRACT_ERROR_RANGE_NS(cheat, VirtualMachineError, 6700, 6799); + R_DEFINE_ERROR_RESULT_NS(cheat, VirtualMachineInvalidConditionDepth, 6700); - } + // } } diff --git a/libraries/libvapours/include/vapours/results/erpt_results.hpp b/libraries/libvapours/include/vapours/results/erpt_results.hpp index 3df7473e6..10c1b9aa9 100644 --- a/libraries/libvapours/include/vapours/results/erpt_results.hpp +++ b/libraries/libvapours/include/vapours/results/erpt_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::erpt { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::erpt, 147); - R_DEFINE_NAMESPACE_RESULT_MODULE(147); +namespace ams::erpt { R_DEFINE_ERROR_RESULT(NotInitialized, 1); R_DEFINE_ERROR_RESULT(AlreadyInitialized, 2); diff --git a/libraries/libvapours/include/vapours/results/err_results.hpp b/libraries/libvapours/include/vapours/results/err_results.hpp index 88003f656..6dd43c88f 100644 --- a/libraries/libvapours/include/vapours/results/err_results.hpp +++ b/libraries/libvapours/include/vapours/results/err_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::err { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::err, 162); - R_DEFINE_NAMESPACE_RESULT_MODULE(162); +namespace ams::err { R_DEFINE_ERROR_RESULT(ApplicationAbort, 1); R_DEFINE_ERROR_RESULT(SystemProgramAbort, 2); diff --git a/libraries/libvapours/include/vapours/results/exosphere_results.hpp b/libraries/libvapours/include/vapours/results/exosphere_results.hpp index 128cac072..be02b8779 100644 --- a/libraries/libvapours/include/vapours/results/exosphere_results.hpp +++ b/libraries/libvapours/include/vapours/results/exosphere_results.hpp @@ -17,12 +17,11 @@ #pragma once #include +/* Please note: These results are all custom, and not official. */ +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::exosphere, 444); + namespace ams::exosphere { - /* Please note: These results are all custom, and not official. */ - R_DEFINE_NAMESPACE_RESULT_MODULE(444); - - /* Result 1-1000 reserved for Atmosphere. */ R_DEFINE_ERROR_RESULT(NotPresent, 1); R_DEFINE_ERROR_RESULT(VersionMismatch, 2); diff --git a/libraries/libvapours/include/vapours/results/fatal_results.hpp b/libraries/libvapours/include/vapours/results/fatal_results.hpp index 68ff89405..23d757204 100644 --- a/libraries/libvapours/include/vapours/results/fatal_results.hpp +++ b/libraries/libvapours/include/vapours/results/fatal_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::fatal { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::fatal, 163); - R_DEFINE_NAMESPACE_RESULT_MODULE(163); +namespace ams::fatal { R_DEFINE_ERROR_RESULT(AllocationFailed, 1); R_DEFINE_ERROR_RESULT(NullGraphicsBuffer, 2); diff --git a/libraries/libvapours/include/vapours/results/fs_results.hpp b/libraries/libvapours/include/vapours/results/fs_results.hpp index d3384d52a..1b9ed6057 100644 --- a/libraries/libvapours/include/vapours/results/fs_results.hpp +++ b/libraries/libvapours/include/vapours/results/fs_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::fs { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::fs, 2); - R_DEFINE_NAMESPACE_RESULT_MODULE(2); +namespace ams::fs { R_DEFINE_ERROR_RANGE(HandledByAllProcess, 0, 999); R_DEFINE_ERROR_RESULT(PathNotFound, 1); @@ -217,7 +217,7 @@ namespace ams::fs { R_DEFINE_ERROR_RESULT(NcaBaseStorageOutOfRangeC, 4510); R_DEFINE_ERROR_RESULT(NcaBaseStorageOutOfRangeD, 4511); - R_DEFINE_ERROR_RANGE(NcaFileSystemCorrupted, 4512, 4529); + R_DEFINE_ERROR_RESULT_CLASS_IMPL(NcaFileSystemCorrupted, 4512, 4529); R_DEFINE_ERROR_RESULT(InvalidNcaFileSystemType, 4512); R_DEFINE_ERROR_RESULT(InvalidAcidFileSize, 4513); R_DEFINE_ERROR_RESULT(InvalidAcidSize, 4514); diff --git a/libraries/libvapours/include/vapours/results/gpio_results.hpp b/libraries/libvapours/include/vapours/results/gpio_results.hpp index 88e75baa6..a228c8129 100644 --- a/libraries/libvapours/include/vapours/results/gpio_results.hpp +++ b/libraries/libvapours/include/vapours/results/gpio_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::gpio { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::gpio, 102); - R_DEFINE_NAMESPACE_RESULT_MODULE(102); +namespace ams::gpio { R_DEFINE_ERROR_RESULT(AlreadyBound, 1); R_DEFINE_ERROR_RESULT(AlreadyOpen, 2); diff --git a/libraries/libvapours/include/vapours/results/hipc_results.hpp b/libraries/libvapours/include/vapours/results/hipc_results.hpp index 99fd56447..8e557b5aa 100644 --- a/libraries/libvapours/include/vapours/results/hipc_results.hpp +++ b/libraries/libvapours/include/vapours/results/hipc_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::sf::hipc { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::sf::hipc, 11); - R_DEFINE_NAMESPACE_RESULT_MODULE(11); +namespace ams::sf::hipc { R_DEFINE_ABSTRACT_ERROR_RANGE(OutOfResource, 100, 299); R_DEFINE_ERROR_RESULT(OutOfSessionMemory, 102); diff --git a/libraries/libvapours/include/vapours/results/htc_results.hpp b/libraries/libvapours/include/vapours/results/htc_results.hpp index 8d92196f7..ba3a87414 100644 --- a/libraries/libvapours/include/vapours/results/htc_results.hpp +++ b/libraries/libvapours/include/vapours/results/htc_results.hpp @@ -16,9 +16,9 @@ #pragma once #include -namespace ams::htc { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::htc, 18); - R_DEFINE_NAMESPACE_RESULT_MODULE(18); +namespace ams::htc { R_DEFINE_ERROR_RESULT(ConnectionFailure, 1); R_DEFINE_ERROR_RESULT(NotFound, 2); diff --git a/libraries/libvapours/include/vapours/results/htcfs_results.hpp b/libraries/libvapours/include/vapours/results/htcfs_results.hpp index 5549d5d88..cf96274e7 100644 --- a/libraries/libvapours/include/vapours/results/htcfs_results.hpp +++ b/libraries/libvapours/include/vapours/results/htcfs_results.hpp @@ -16,9 +16,9 @@ #pragma once #include -namespace ams::htcfs { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::htcfs, 31); - R_DEFINE_NAMESPACE_RESULT_MODULE(31); +namespace ams::htcfs { R_DEFINE_ERROR_RESULT(InvalidArgument, 3); diff --git a/libraries/libvapours/include/vapours/results/htclow_results.hpp b/libraries/libvapours/include/vapours/results/htclow_results.hpp index 0d288c141..9f6dfa52d 100644 --- a/libraries/libvapours/include/vapours/results/htclow_results.hpp +++ b/libraries/libvapours/include/vapours/results/htclow_results.hpp @@ -16,9 +16,9 @@ #pragma once #include -namespace ams::htclow { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::htclow, 29); - R_DEFINE_NAMESPACE_RESULT_MODULE(29); +namespace ams::htclow { R_DEFINE_ERROR_RESULT(ConnectionFailure, 1); R_DEFINE_ERROR_RESULT(UnknownDriverType, 3); @@ -28,7 +28,7 @@ namespace ams::htclow { R_DEFINE_ERROR_RESULT(ChannelNotExist, 10); R_DEFINE_ERROR_RESULT(OutOfChannel, 151); - R_DEFINE_ERROR_RESULT(OutOfTask, 151); + R_DEFINE_ERROR_RESULT(OutOfTask, 152); R_DEFINE_ERROR_RESULT(InvalidChannelState, 200); R_DEFINE_ERROR_RESULT(InvalidChannelStateDisconnected, 201); diff --git a/libraries/libvapours/include/vapours/results/htcs_results.hpp b/libraries/libvapours/include/vapours/results/htcs_results.hpp index 6e5dba0d1..0f782d529 100644 --- a/libraries/libvapours/include/vapours/results/htcs_results.hpp +++ b/libraries/libvapours/include/vapours/results/htcs_results.hpp @@ -16,9 +16,9 @@ #pragma once #include -namespace ams::htcs { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::htcs, 4); - R_DEFINE_NAMESPACE_RESULT_MODULE(4); +namespace ams::htcs { R_DEFINE_ERROR_RESULT(InvalidHandle, 9); diff --git a/libraries/libvapours/include/vapours/results/i2c_results.hpp b/libraries/libvapours/include/vapours/results/i2c_results.hpp index 1704009ee..2a0e06022 100644 --- a/libraries/libvapours/include/vapours/results/i2c_results.hpp +++ b/libraries/libvapours/include/vapours/results/i2c_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::i2c { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::i2c, 101); - R_DEFINE_NAMESPACE_RESULT_MODULE(101); +namespace ams::i2c { R_DEFINE_ERROR_RESULT(NoAck, 1); R_DEFINE_ERROR_RESULT(BusBusy, 2); diff --git a/libraries/libvapours/include/vapours/results/kvdb_results.hpp b/libraries/libvapours/include/vapours/results/kvdb_results.hpp index 254d89e33..109a81bb3 100644 --- a/libraries/libvapours/include/vapours/results/kvdb_results.hpp +++ b/libraries/libvapours/include/vapours/results/kvdb_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::kvdb { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::kvdb, 20); - R_DEFINE_NAMESPACE_RESULT_MODULE(20); +namespace ams::kvdb { R_DEFINE_ERROR_RESULT(OutOfKeyResource, 1); R_DEFINE_ERROR_RESULT(KeyNotFound, 2); diff --git a/libraries/libvapours/include/vapours/results/loader_results.hpp b/libraries/libvapours/include/vapours/results/loader_results.hpp index 691acbd44..825be3784 100644 --- a/libraries/libvapours/include/vapours/results/loader_results.hpp +++ b/libraries/libvapours/include/vapours/results/loader_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::ldr { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::ldr, 9); - R_DEFINE_NAMESPACE_RESULT_MODULE(9); +namespace ams::ldr { R_DEFINE_ERROR_RESULT(ArgumentOverflow, 1); R_DEFINE_ERROR_RESULT(ArgumentCountOverflow, 2); diff --git a/libraries/libvapours/include/vapours/results/lr_results.hpp b/libraries/libvapours/include/vapours/results/lr_results.hpp index fd18d0228..faad916d3 100644 --- a/libraries/libvapours/include/vapours/results/lr_results.hpp +++ b/libraries/libvapours/include/vapours/results/lr_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::lr { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::lr, 8); - R_DEFINE_NAMESPACE_RESULT_MODULE(8); +namespace ams::lr { R_DEFINE_ERROR_RESULT(ProgramNotFound, 2); R_DEFINE_ERROR_RESULT(DataNotFound, 3); diff --git a/libraries/libvapours/include/vapours/results/ncm_results.hpp b/libraries/libvapours/include/vapours/results/ncm_results.hpp index 8c4a2aea7..a3b4fb80e 100644 --- a/libraries/libvapours/include/vapours/results/ncm_results.hpp +++ b/libraries/libvapours/include/vapours/results/ncm_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::ncm { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::ncm, 5); - R_DEFINE_NAMESPACE_RESULT_MODULE(5); +namespace ams::ncm { R_DEFINE_ERROR_RESULT(InvalidContentStorageBase, 1); R_DEFINE_ERROR_RESULT(PlaceHolderAlreadyExists, 2); diff --git a/libraries/libvapours/include/vapours/results/nim_results.hpp b/libraries/libvapours/include/vapours/results/nim_results.hpp index 967bfd3e9..a006b4a4d 100644 --- a/libraries/libvapours/include/vapours/results/nim_results.hpp +++ b/libraries/libvapours/include/vapours/results/nim_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::nim { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::nim, 137); - R_DEFINE_NAMESPACE_RESULT_MODULE(137); +namespace ams::nim { R_DEFINE_ERROR_RESULT(HttpConnectionCanceled, 70); diff --git a/libraries/libvapours/include/vapours/results/ns_results.hpp b/libraries/libvapours/include/vapours/results/ns_results.hpp index 29d386f9d..34bf8309a 100644 --- a/libraries/libvapours/include/vapours/results/ns_results.hpp +++ b/libraries/libvapours/include/vapours/results/ns_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::ns { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::ns, 16); - R_DEFINE_NAMESPACE_RESULT_MODULE(16); +namespace ams::ns { R_DEFINE_ERROR_RESULT(Canceled, 90); R_DEFINE_ERROR_RESULT(OutOfMaxRunningTask, 110); diff --git a/libraries/libvapours/include/vapours/results/os_results.hpp b/libraries/libvapours/include/vapours/results/os_results.hpp index 62a6344c6..b83389e84 100644 --- a/libraries/libvapours/include/vapours/results/os_results.hpp +++ b/libraries/libvapours/include/vapours/results/os_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::os { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::os, 3); - R_DEFINE_NAMESPACE_RESULT_MODULE(3); +namespace ams::os { R_DEFINE_ERROR_RESULT(Busy, 4); diff --git a/libraries/libvapours/include/vapours/results/osdbg_results.hpp b/libraries/libvapours/include/vapours/results/osdbg_results.hpp index 952c07307..0ced08755 100644 --- a/libraries/libvapours/include/vapours/results/osdbg_results.hpp +++ b/libraries/libvapours/include/vapours/results/osdbg_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::osdbg { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::osdbg, 7); - R_DEFINE_NAMESPACE_RESULT_MODULE(7); +namespace ams::osdbg { R_DEFINE_ERROR_RESULT(CannotGetThreadInfo, 1); R_DEFINE_ERROR_RESULT(UnsupportedThreadVersion, 2); diff --git a/libraries/libvapours/include/vapours/results/pcv_results.hpp b/libraries/libvapours/include/vapours/results/pcv_results.hpp index eed8e316e..daf05f28c 100644 --- a/libraries/libvapours/include/vapours/results/pcv_results.hpp +++ b/libraries/libvapours/include/vapours/results/pcv_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::pcv { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::pcv, 133); - R_DEFINE_NAMESPACE_RESULT_MODULE(133); +namespace ams::pcv { R_DEFINE_ERROR_RESULT(IllegalRequest, 16); diff --git a/libraries/libvapours/include/vapours/results/pgl_results.hpp b/libraries/libvapours/include/vapours/results/pgl_results.hpp index c909aa667..af4176de1 100644 --- a/libraries/libvapours/include/vapours/results/pgl_results.hpp +++ b/libraries/libvapours/include/vapours/results/pgl_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::pgl { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::pgl, 228); - R_DEFINE_NAMESPACE_RESULT_MODULE(228); +namespace ams::pgl { R_DEFINE_ERROR_RESULT(NotImplemented, 1); R_DEFINE_ERROR_RESULT(NotAvailable, 2); diff --git a/libraries/libvapours/include/vapours/results/pm_results.hpp b/libraries/libvapours/include/vapours/results/pm_results.hpp index 1bb18e02c..4c9e51ad5 100644 --- a/libraries/libvapours/include/vapours/results/pm_results.hpp +++ b/libraries/libvapours/include/vapours/results/pm_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::pm { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::pm, 15); - R_DEFINE_NAMESPACE_RESULT_MODULE(15); +namespace ams::pm { R_DEFINE_ERROR_RESULT(ProcessNotFound, 1); R_DEFINE_ERROR_RESULT(AlreadyStarted, 2); diff --git a/libraries/libvapours/include/vapours/results/powctl_results.hpp b/libraries/libvapours/include/vapours/results/powctl_results.hpp index 7a9d6d7fc..98413f677 100644 --- a/libraries/libvapours/include/vapours/results/powctl_results.hpp +++ b/libraries/libvapours/include/vapours/results/powctl_results.hpp @@ -17,12 +17,14 @@ #pragma once #include -namespace ams::powctl { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::powctl, 198); - R_DEFINE_NAMESPACE_RESULT_MODULE(198); +namespace ams::powctl { R_DEFINE_ERROR_RESULT(NotSupported, 1); R_DEFINE_ERROR_RESULT(InvalidArgument, 2); R_DEFINE_ERROR_RESULT(NotAvailable, 3); + R_DEFINE_ERROR_RESULT(CalibrationDataCrcError, 101); + } diff --git a/libraries/libvapours/include/vapours/results/psc_results.hpp b/libraries/libvapours/include/vapours/results/psc_results.hpp index 019925acf..16d8e3074 100644 --- a/libraries/libvapours/include/vapours/results/psc_results.hpp +++ b/libraries/libvapours/include/vapours/results/psc_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::psc { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::psc, 138); - R_DEFINE_NAMESPACE_RESULT_MODULE(138); +namespace ams::psc { R_DEFINE_ERROR_RESULT(AlreadyInitialized, 2); R_DEFINE_ERROR_RESULT(NotInitialized, 3); diff --git a/libraries/libvapours/include/vapours/results/pwm_results.hpp b/libraries/libvapours/include/vapours/results/pwm_results.hpp index ed5a8ded7..247a5f317 100644 --- a/libraries/libvapours/include/vapours/results/pwm_results.hpp +++ b/libraries/libvapours/include/vapours/results/pwm_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::pwm { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::pwm, 189); - R_DEFINE_NAMESPACE_RESULT_MODULE(189); +namespace ams::pwm { R_DEFINE_ERROR_RESULT(InvalidArgument, 2); diff --git a/libraries/libvapours/include/vapours/results/results_common.hpp b/libraries/libvapours/include/vapours/results/results_common.hpp index ec03e67d6..2ddbf37dd 100644 --- a/libraries/libvapours/include/vapours/results/results_common.hpp +++ b/libraries/libvapours/include/vapours/results/results_common.hpp @@ -20,8 +20,25 @@ namespace ams { + const char *GetResultName(int module, int description); + namespace result::impl { + #if defined(AMS_AUTO_GENERATE_RESULT_NAMES) + struct DummyNameHolder { + static constexpr bool Exists = false; + static constexpr const char *Name = "unknown"; + }; + + template + struct ResultNameSpaceExistsImpl { + static constexpr bool Exists = false; + + template + using NameHolder = DummyNameHolder; + }; + #endif + class ResultTraits { public: using BaseType = u32; @@ -113,6 +130,10 @@ namespace ams { static_assert(sizeof(Result) == sizeof(Result::Base::BaseType), "sizeof(Result) == sizeof(Result::Base::BaseType)"); static_assert(std::is_trivially_destructible::value, "std::is_trivially_destructible::value"); + ALWAYS_INLINE const char *GetResultName(const Result &result) { + return GetResultName(result.GetModule(), result.GetDescription()); + } + namespace result::impl { class ResultInternalAccessor { @@ -230,25 +251,75 @@ namespace ams { } /* Macros for defining new results. */ -#define R_DEFINE_NAMESPACE_RESULT_MODULE(value) namespace impl::result { static constexpr inline ::ams::result::impl::ResultTraits::BaseType ResultModuleId = value; } -#define R_CURRENT_NAMESPACE_RESULT_MODULE impl::result::ResultModuleId +#if defined(AMS_AUTO_GENERATE_RESULT_NAMES) +#define R_DEFINE_NAMESPACE_RESULT_MODULE(nmspc, value) \ + namespace nmspc { \ + \ + namespace result_impl { \ + static constexpr inline ::ams::result::impl::ResultTraits::BaseType ResultModuleId = value; \ + \ + template \ + struct ResultNameHolderImpl { static constexpr bool Exists = false; }; \ + } \ + \ + } \ + \ + namespace ams::result::impl { \ + \ + template<> struct ResultNameSpaceExistsImpl { \ + static constexpr bool Exists = true; \ + \ + template \ + using NameHolder = nmspc::result_impl::ResultNameHolderImpl; \ + }; \ + \ + } +#else +#define R_DEFINE_NAMESPACE_RESULT_MODULE(nmspc, value) \ + namespace nmspc { \ + \ + namespace result_impl { \ + static constexpr inline ::ams::result::impl::ResultTraits::BaseType ResultModuleId = value; \ + } \ + \ + } +#endif + +#define R_CURRENT_NAMESPACE_RESULT_MODULE result_impl::ResultModuleId #define R_NAMESPACE_MODULE_ID(nmspc) nmspc::R_CURRENT_NAMESPACE_RESULT_MODULE #define R_MAKE_NAMESPACE_RESULT(nmspc, desc) static_cast<::ams::Result>(::ams::result::impl::ResultTraits::MakeValue(R_NAMESPACE_MODULE_ID(nmspc), desc)) -#define R_DEFINE_ERROR_RESULT_IMPL(name, desc_start, desc_end) \ +#if defined(AMS_AUTO_GENERATE_RESULT_NAMES) +#define R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc_start, desc_end) \ + template<> struct result_impl::ResultNameHolderImpl { static constexpr bool Exists = true; static constexpr const char *Name = #name; }; +#else +#define R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc_start, desc_end) +#endif + +#define R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, desc_start, desc_end) \ class Result##name final : public ::ams::result::impl::ResultErrorBase, public ::ams::result::impl::ResultErrorRangeBase {} +#define R_DEFINE_ERROR_RESULT_IMPL(name, desc_start, desc_end) \ + R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc_start, desc_end) \ + R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, desc_start, desc_end) + #define R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, desc_start, desc_end) \ class Result##name final : public ::ams::result::impl::ResultErrorRangeBase {} - #define R_DEFINE_ERROR_RESULT(name, desc) R_DEFINE_ERROR_RESULT_IMPL(name, desc, desc) #define R_DEFINE_ERROR_RANGE(name, start, end) R_DEFINE_ERROR_RESULT_IMPL(name, start, end) #define R_DEFINE_ABSTRACT_ERROR_RESULT(name, desc) R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, desc, desc) #define R_DEFINE_ABSTRACT_ERROR_RANGE(name, start, end) R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, start, end) + +#define R_DEFINE_ERROR_RESULT_NS(ns, name, desc) namespace ns { R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, desc, desc); } R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, desc, desc) +#define R_DEFINE_ERROR_RANGE_NS(ns, name, start, end) namespace ns { R_DEFINE_ERROR_RESULT_CLASS_IMPL(name, start, end); } R_DEFINE_ERROR_RESULT_NAME_HOLDER_IMPL(name, start, end) + +#define R_DEFINE_ABSTRACT_ERROR_RESULT_NS(ns, name, desc) namespace ns { R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, desc, desc); } +#define R_DEFINE_ABSTRACT_ERROR_RANGE_NS(ns, name, start, end) namespace ns { R_DEFINE_ABSTRACT_ERROR_RESULT_IMPL(name, start, end); } + /* Remove libnx macros, replace with our own. */ #ifndef R_SUCCEEDED #error "R_SUCCEEDED not defined." @@ -384,14 +455,12 @@ namespace ams::result::impl { #if defined(ATMOSPHERE_BOARD_NINTENDO_NX) && defined(ATMOSPHERE_IS_STRATOSPHERE) && !defined(AMS_ENABLE_DETAILED_ASSERTIONS) && !defined(AMS_BUILD_FOR_DEBUGGING) && !defined(AMS_BUILD_FOR_AUDITING) #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false) #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false) +#elif defined(ATMOSPHERE_OS_HORIZON) + #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue()) + #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue()) #else - #if defined(AMS_ENABLE_DETAILED_ASSERTIONS) - #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) ::ams::result::impl::OnResultAssertion(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, val) - #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) ::ams::result::impl::OnResultAbort(__FILE__, __LINE__, __PRETTY_FUNCTION__, cond, val) - #else - #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) ::ams::result::impl::OnResultAssertion("", 0, "", "", val) - #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) ::ams::result::impl::OnResultAbort("", 0, "", "", val) - #endif + #define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(val)) + #define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(val)) #endif /// Evaluates an expression that returns a result, and asserts the result if it would fail. diff --git a/libraries/libvapours/include/vapours/results/ro_results.hpp b/libraries/libvapours/include/vapours/results/ro_results.hpp index 076b34551..c187749dc 100644 --- a/libraries/libvapours/include/vapours/results/ro_results.hpp +++ b/libraries/libvapours/include/vapours/results/ro_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::ro { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::ro, 22); - R_DEFINE_NAMESPACE_RESULT_MODULE(22); +namespace ams::ro { R_DEFINE_ERROR_RANGE(RoError, 1, 1023); R_DEFINE_ERROR_RESULT(OutOfAddressSpace, 2); diff --git a/libraries/libvapours/include/vapours/results/scs_results.hpp b/libraries/libvapours/include/vapours/results/scs_results.hpp index 1446b0efc..59dcfe815 100644 --- a/libraries/libvapours/include/vapours/results/scs_results.hpp +++ b/libraries/libvapours/include/vapours/results/scs_results.hpp @@ -16,13 +16,12 @@ #pragma once #include +#include namespace ams::scs { - R_DEFINE_NAMESPACE_RESULT_MODULE(204); - - R_DEFINE_ERROR_RESULT(UnknownCommand, 2); - R_DEFINE_ERROR_RESULT(OutOfResource, 4); - R_DEFINE_ERROR_RESULT(NoSocket, 7); + using ams::cs::ResultUnknownCommand; + using ams::cs::ResultOutOfResource; + using ams::cs::ResultNoSocket; } diff --git a/libraries/libvapours/include/vapours/results/sdmmc_results.hpp b/libraries/libvapours/include/vapours/results/sdmmc_results.hpp index 25d4aa1e1..3477907ce 100644 --- a/libraries/libvapours/include/vapours/results/sdmmc_results.hpp +++ b/libraries/libvapours/include/vapours/results/sdmmc_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::sdmmc { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::sdmmc, 24); - R_DEFINE_NAMESPACE_RESULT_MODULE(24); +namespace ams::sdmmc { R_DEFINE_ERROR_RESULT(NoDevice, 1); R_DEFINE_ERROR_RESULT(NotActivated, 2); diff --git a/libraries/libvapours/include/vapours/results/settings_results.hpp b/libraries/libvapours/include/vapours/results/settings_results.hpp index 0155b00f3..828b489b0 100644 --- a/libraries/libvapours/include/vapours/results/settings_results.hpp +++ b/libraries/libvapours/include/vapours/results/settings_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::settings { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::settings, 105); - R_DEFINE_NAMESPACE_RESULT_MODULE(105); +namespace ams::settings { R_DEFINE_ERROR_RESULT(SettingsItemNotFound, 11); R_DEFINE_ERROR_RESULT(StopIteration, 21); diff --git a/libraries/libvapours/include/vapours/results/sf_results.hpp b/libraries/libvapours/include/vapours/results/sf_results.hpp index add2cd5bc..825ac175a 100644 --- a/libraries/libvapours/include/vapours/results/sf_results.hpp +++ b/libraries/libvapours/include/vapours/results/sf_results.hpp @@ -17,36 +17,36 @@ #pragma once #include -namespace ams::sf { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::sf, 10); - R_DEFINE_NAMESPACE_RESULT_MODULE(10); +namespace ams::sf { R_DEFINE_ERROR_RESULT(NotSupported, 1); R_DEFINE_ERROR_RESULT(PreconditionViolation, 3); - namespace cmif { + //namespace cmif { - R_DEFINE_ERROR_RESULT(InvalidHeaderSize, 202); - R_DEFINE_ERROR_RESULT(InvalidInHeader, 211); - R_DEFINE_ERROR_RESULT(UnknownCommandId, 221); - R_DEFINE_ERROR_RESULT(InvalidOutRawSize, 232); - R_DEFINE_ERROR_RESULT(InvalidNumInObjects, 235); - R_DEFINE_ERROR_RESULT(InvalidNumOutObjects, 236); - R_DEFINE_ERROR_RESULT(InvalidInObject, 239); + R_DEFINE_ERROR_RESULT_NS(cmif, InvalidHeaderSize, 202); + R_DEFINE_ERROR_RESULT_NS(cmif, InvalidInHeader, 211); + R_DEFINE_ERROR_RESULT_NS(cmif, UnknownCommandId, 221); + R_DEFINE_ERROR_RESULT_NS(cmif, InvalidOutRawSize, 232); + R_DEFINE_ERROR_RESULT_NS(cmif, InvalidNumInObjects, 235); + R_DEFINE_ERROR_RESULT_NS(cmif, InvalidNumOutObjects, 236); + R_DEFINE_ERROR_RESULT_NS(cmif, InvalidInObject, 239); - R_DEFINE_ERROR_RESULT(TargetNotFound, 261); + R_DEFINE_ERROR_RESULT_NS(cmif, TargetNotFound, 261); - R_DEFINE_ERROR_RESULT(OutOfDomainEntries, 301); + R_DEFINE_ERROR_RESULT_NS(cmif, OutOfDomainEntries, 301); - } + //} - namespace impl { + //namespace impl { - R_DEFINE_ABSTRACT_ERROR_RANGE(RequestContextChanged, 800, 899); - R_DEFINE_ABSTRACT_ERROR_RANGE(RequestInvalidated, 801, 809); - R_DEFINE_ERROR_RESULT(RequestInvalidatedByUser, 802); + R_DEFINE_ABSTRACT_ERROR_RANGE_NS(impl, RequestContextChanged, 800, 899); + R_DEFINE_ABSTRACT_ERROR_RANGE_NS(impl, RequestInvalidated, 801, 809); + R_DEFINE_ERROR_RESULT_NS(impl, RequestInvalidatedByUser, 802); - } + //} R_DEFINE_ABSTRACT_ERROR_RANGE(RequestDeferred, 811, 819); R_DEFINE_ERROR_RESULT(RequestDeferredByUser, 812); diff --git a/libraries/libvapours/include/vapours/results/sm_results.hpp b/libraries/libvapours/include/vapours/results/sm_results.hpp index 28119b7cc..7b29894bb 100644 --- a/libraries/libvapours/include/vapours/results/sm_results.hpp +++ b/libraries/libvapours/include/vapours/results/sm_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::sm { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::sm, 21); - R_DEFINE_NAMESPACE_RESULT_MODULE(21); +namespace ams::sm { R_DEFINE_ERROR_RESULT(OutOfProcesses, 1); R_DEFINE_ERROR_RESULT(InvalidClient, 2); @@ -32,11 +32,11 @@ namespace ams::sm { R_DEFINE_ERROR_RESULT(TooLargeAccessControl, 9); /* Results 1000-2000 used as extension for Atmosphere Mitm. */ - namespace mitm { + //namespace mitm { - R_DEFINE_ERROR_RESULT(ShouldForwardToSession, 1000); - R_DEFINE_ERROR_RESULT(ProcessNotAssociated, 1100); + R_DEFINE_ERROR_RESULT_NS(mitm, ShouldForwardToSession, 1000); + R_DEFINE_ERROR_RESULT_NS(mitm, ProcessNotAssociated, 1100); - } + //} } diff --git a/libraries/libvapours/include/vapours/results/socket_results.hpp b/libraries/libvapours/include/vapours/results/socket_results.hpp index 58915c1de..f83cbaee8 100644 --- a/libraries/libvapours/include/vapours/results/socket_results.hpp +++ b/libraries/libvapours/include/vapours/results/socket_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::socket { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::socket, 27); - R_DEFINE_NAMESPACE_RESULT_MODULE(27); +namespace ams::socket { R_DEFINE_ERROR_RESULT(InsufficientProvidedMemory, 1); diff --git a/libraries/libvapours/include/vapours/results/spl_results.hpp b/libraries/libvapours/include/vapours/results/spl_results.hpp index c15e5cd3c..12c1199b4 100644 --- a/libraries/libvapours/include/vapours/results/spl_results.hpp +++ b/libraries/libvapours/include/vapours/results/spl_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::spl { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::spl, 26); - R_DEFINE_NAMESPACE_RESULT_MODULE(26); +namespace ams::spl { R_DEFINE_ERROR_RANGE(SecureMonitorError, 0, 99); R_DEFINE_ERROR_RESULT(SecureMonitorNotSupported, 1); diff --git a/libraries/libvapours/include/vapours/results/sprofile_results.hpp b/libraries/libvapours/include/vapours/results/sprofile_results.hpp index 8772bdb0c..4000bd8f1 100644 --- a/libraries/libvapours/include/vapours/results/sprofile_results.hpp +++ b/libraries/libvapours/include/vapours/results/sprofile_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::sprofile { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::sprofile, 246); - R_DEFINE_NAMESPACE_RESULT_MODULE(246); +namespace ams::sprofile { R_DEFINE_ERROR_RESULT(InvalidArgument, 100); R_DEFINE_ERROR_RESULT(InvalidState, 101); diff --git a/libraries/libvapours/include/vapours/results/svc_results.hpp b/libraries/libvapours/include/vapours/results/svc_results.hpp index 6128b6b25..7a01b5699 100644 --- a/libraries/libvapours/include/vapours/results/svc_results.hpp +++ b/libraries/libvapours/include/vapours/results/svc_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::svc { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::svc, 1); - R_DEFINE_NAMESPACE_RESULT_MODULE(1); +namespace ams::svc { R_DEFINE_ERROR_RESULT(OutOfSessions, 7); diff --git a/libraries/libvapours/include/vapours/results/time_results.hpp b/libraries/libvapours/include/vapours/results/time_results.hpp index 863ac47c6..c83941fee 100644 --- a/libraries/libvapours/include/vapours/results/time_results.hpp +++ b/libraries/libvapours/include/vapours/results/time_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::time { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::time, 116); - R_DEFINE_NAMESPACE_RESULT_MODULE(116); +namespace ams::time { R_DEFINE_ERROR_RESULT(NotInitialized, 0); diff --git a/libraries/libvapours/include/vapours/results/tipc_results.hpp b/libraries/libvapours/include/vapours/results/tipc_results.hpp index b537bd389..c381c87eb 100644 --- a/libraries/libvapours/include/vapours/results/tipc_results.hpp +++ b/libraries/libvapours/include/vapours/results/tipc_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::tipc { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::tipc, 35); - R_DEFINE_NAMESPACE_RESULT_MODULE(35); +namespace ams::tipc { R_DEFINE_ERROR_RESULT(InvalidMethod, 10); R_DEFINE_ERROR_RESULT(InvalidMessageFormat, 15); diff --git a/libraries/libvapours/include/vapours/results/tma_results.hpp b/libraries/libvapours/include/vapours/results/tma_results.hpp index 55a1068b2..ce464687a 100644 --- a/libraries/libvapours/include/vapours/results/tma_results.hpp +++ b/libraries/libvapours/include/vapours/results/tma_results.hpp @@ -16,9 +16,9 @@ #pragma once #include -namespace ams::tma { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::tma, 12); - R_DEFINE_NAMESPACE_RESULT_MODULE(12); +namespace ams::tma { R_DEFINE_ERROR_RESULT(Unknown, 1); diff --git a/libraries/libvapours/include/vapours/results/updater_results.hpp b/libraries/libvapours/include/vapours/results/updater_results.hpp index 7e86e435b..0ff0e135a 100644 --- a/libraries/libvapours/include/vapours/results/updater_results.hpp +++ b/libraries/libvapours/include/vapours/results/updater_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::updater { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::updater, 158); - R_DEFINE_NAMESPACE_RESULT_MODULE(158); +namespace ams::updater { R_DEFINE_ERROR_RESULT(BootImagePackageNotFound, 2); R_DEFINE_ERROR_RESULT(InvalidBootImagePackage, 3); diff --git a/libraries/libvapours/include/vapours/results/usb_results.hpp b/libraries/libvapours/include/vapours/results/usb_results.hpp index a56efe782..a4185b16d 100644 --- a/libraries/libvapours/include/vapours/results/usb_results.hpp +++ b/libraries/libvapours/include/vapours/results/usb_results.hpp @@ -16,9 +16,9 @@ #pragma once #include -namespace ams::usb { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::usb, 140); - R_DEFINE_NAMESPACE_RESULT_MODULE(140); +namespace ams::usb { R_DEFINE_ERROR_RESULT(NotInitialized, 0); R_DEFINE_ERROR_RESULT(AlreadyInitialized, 1); diff --git a/libraries/libvapours/include/vapours/results/vi_results.hpp b/libraries/libvapours/include/vapours/results/vi_results.hpp index 2012bd162..3df6c3fc7 100644 --- a/libraries/libvapours/include/vapours/results/vi_results.hpp +++ b/libraries/libvapours/include/vapours/results/vi_results.hpp @@ -17,9 +17,9 @@ #pragma once #include -namespace ams::vi { +R_DEFINE_NAMESPACE_RESULT_MODULE(ams::vi, 114); - R_DEFINE_NAMESPACE_RESULT_MODULE(114); +namespace ams::vi { R_DEFINE_ERROR_RESULT(OperationFailed, 1); R_DEFINE_ERROR_RESULT(NotSupported, 6); diff --git a/libraries/libvapours/source/result/result_get_name.cpp b/libraries/libvapours/source/result/result_get_name.cpp new file mode 100644 index 000000000..4595d0b19 --- /dev/null +++ b/libraries/libvapours/source/result/result_get_name.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) Atmosphère-NX + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#if !defined(ATMOSPHERE_OS_HORIZON) && (defined(AMS_BUILD_FOR_DEBUGGING) || defined(AMS_BUILD_FOR_AUDITING)) + #define AMS_AUTO_GENERATE_RESULT_NAMES +#endif + +#include + +namespace ams { + + #if defined(AMS_AUTO_GENERATE_RESULT_NAMES) + + #define AMS_INVOKE_MACRO_01(EXPR, n) EXPR(n); EXPR(n + (1 << 0)); + + #define AMS_INVOKE_MACRO_02(EXPR, n) AMS_INVOKE_MACRO_01(EXPR, n); AMS_INVOKE_MACRO_01(EXPR, n + (1 << 1)); + #define AMS_INVOKE_MACRO_03(EXPR, n) AMS_INVOKE_MACRO_02(EXPR, n); AMS_INVOKE_MACRO_02(EXPR, n + (1 << 2)); + #define AMS_INVOKE_MACRO_04(EXPR, n) AMS_INVOKE_MACRO_03(EXPR, n); AMS_INVOKE_MACRO_03(EXPR, n + (1 << 3)); + #define AMS_INVOKE_MACRO_05(EXPR, n) AMS_INVOKE_MACRO_04(EXPR, n); AMS_INVOKE_MACRO_04(EXPR, n + (1 << 4)); + #define AMS_INVOKE_MACRO_06(EXPR, n) AMS_INVOKE_MACRO_05(EXPR, n); AMS_INVOKE_MACRO_05(EXPR, n + (1 << 5)); + #define AMS_INVOKE_MACRO_07(EXPR, n) AMS_INVOKE_MACRO_06(EXPR, n); AMS_INVOKE_MACRO_06(EXPR, n + (1 << 6)); + #define AMS_INVOKE_MACRO_08(EXPR, n) AMS_INVOKE_MACRO_07(EXPR, n); AMS_INVOKE_MACRO_07(EXPR, n + (1 << 7)); + #define AMS_INVOKE_MACRO_09(EXPR, n) AMS_INVOKE_MACRO_08(EXPR, n); AMS_INVOKE_MACRO_08(EXPR, n + (1 << 8)); + #define AMS_INVOKE_MACRO_10(EXPR, n) AMS_INVOKE_MACRO_09(EXPR, n); AMS_INVOKE_MACRO_09(EXPR, n + (1 << 9)); + #define AMS_INVOKE_MACRO_11(EXPR, n) AMS_INVOKE_MACRO_10(EXPR, n); AMS_INVOKE_MACRO_10(EXPR, n + (1 << 10)); + #define AMS_INVOKE_MACRO_12(EXPR, n) AMS_INVOKE_MACRO_11(EXPR, n); AMS_INVOKE_MACRO_11(EXPR, n + (1 << 11)); + #define AMS_INVOKE_MACRO_13(EXPR, n) AMS_INVOKE_MACRO_12(EXPR, n); AMS_INVOKE_MACRO_12(EXPR, n + (1 << 12)); + + namespace { + + template + constexpr const char *GetResultNameByModuleAndDescription() { + return ::ams::result::impl::ResultNameSpaceExistsImpl::template NameHolder::Name; + } + + template + constexpr const char *GetResultNameByModule(int description) { + #define AMS_TEST_RESULT_DESCRIPTION_DEFINED(n) if constexpr (::ams::result::impl::ResultNameSpaceExistsImpl::template NameHolder::Exists) { if (description == n) { return GetResultNameByModuleAndDescription(); } } + + AMS_INVOKE_MACRO_13(AMS_TEST_RESULT_DESCRIPTION_DEFINED, 0) + + return "Unknown"; + } + + } + + const char *GetResultName(int module, int description) { + #define AMS_TEST_RESULT_MODULE_DEFINED(n) if constexpr (::ams::result::impl::ResultNameSpaceExistsImpl::Exists) { if (module == n) { return GetResultNameByModule(description); } } + + AMS_INVOKE_MACRO_08(AMS_TEST_RESULT_MODULE_DEFINED, 0) + + return "Unknown"; + } + + #else + const char *GetResultName(int, int) { + return "Unknown"; + } + #endif + +} diff --git a/libraries/libvapours/source/util/util_format_string.cpp b/libraries/libvapours/source/util/util_format_string.cpp index 312d09062..9ef0bb7a6 100644 --- a/libraries/libvapours/source/util/util_format_string.cpp +++ b/libraries/libvapours/source/util/util_format_string.cpp @@ -394,7 +394,9 @@ namespace ams::util { /* Ensure null termination. */ WriteCharacter('\0'); - dst[dst_size - 1] = '\0'; + if (dst_size > 0) { + dst[dst_size - 1] = '\0'; + } /* Return number of characters that would have been printed sans the null terminator. */ return static_cast(dst_index) - 1;