diff --git a/config/os/linux/os.mk b/config/os/linux/os.mk
index f875e822..ee225a6f 100644
--- a/config/os/linux/os.mk
+++ b/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/config/os/macos/os.mk b/config/os/macos/os.mk
index 6d185126..f6e4e1af 100644
--- a/config/os/macos/os.mk
+++ b/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/config/os/windows/os.mk b/config/os/windows/os.mk
index 7ef43a25..c63a7d8d 100644
--- a/config/os/windows/os.mk
+++ b/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/config/templates/stratosphere.mk b/config/templates/stratosphere.mk
index a052c927..63b90af9 100644
--- a/config/templates/stratosphere.mk
+++ b/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/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc b/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc
index 2f37cd3c..845d3575 100644
--- a/libexosphere/include/exosphere/diag/diag_detailed_assertion_impl.inc
+++ b/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/libexosphere/source/impl/ams_impl_unexpected_default.cpp b/libexosphere/source/impl/ams_impl_unexpected_default.cpp
new file mode 100644
index 00000000..3b397ad5
--- /dev/null
+++ b/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/libmesosphere/include/mesosphere/kern_panic.hpp b/libmesosphere/include/mesosphere/kern_panic.hpp
index bb1dfa7e..047a6576 100644
--- a/libmesosphere/include/mesosphere/kern_panic.hpp
+++ b/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/libstratosphere/include/stratosphere/diag.hpp b/libstratosphere/include/stratosphere/diag.hpp
index 0a51073c..a8f9c0e2 100644
--- a/libstratosphere/include/stratosphere/diag.hpp
+++ b/libstratosphere/include/stratosphere/diag.hpp
@@ -20,6 +20,10 @@
#include
#include
#include
+#include
+#include
#include
+#include
+#include
diff --git a/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp b/libstratosphere/include/stratosphere/diag/diag_abort_observer.hpp
new file mode 100644
index 00000000..52a4605b
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp b/libstratosphere/include/stratosphere/diag/diag_assertion_failure_handler.hpp
new file mode 100644
index 00000000..b1466a18
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp b/libstratosphere/include/stratosphere/diag/diag_backtrace.hpp
new file mode 100644
index 00000000..de8bbe89
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/diag_symbol.hpp b/libstratosphere/include/stratosphere/diag/diag_symbol.hpp
new file mode 100644
index 00000000..d4354094
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp b/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp
new file mode 100644
index 00000000..1500b147
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp b/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp
new file mode 100644
index 00000000..23e1e40a
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp b/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp
new file mode 100644
index 00000000..23e1e40a
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp b/libstratosphere/include/stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp
new file mode 100644
index 00000000..23e1e40a
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/os.hpp b/libstratosphere/include/stratosphere/os.hpp
index 3c4e84b2..7133512c 100644
--- a/libstratosphere/include/stratosphere/os.hpp
+++ b/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/libstratosphere/include/stratosphere/os/os_debug.hpp b/libstratosphere/include/stratosphere/os/os_debug.hpp
new file mode 100644
index 00000000..1e31b0e2
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/os/os_debug_api.hpp b/libstratosphere/include/stratosphere/os/os_debug_api.hpp
new file mode 100644
index 00000000..6a1fd3d1
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/os/os_debug_types.hpp b/libstratosphere/include/stratosphere/os/os_debug_types.hpp
new file mode 100644
index 00000000..c9e05965
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp b/libstratosphere/include/stratosphere/os/os_sdk_thread_info.hpp
new file mode 100644
index 00000000..933c0120
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp b/libstratosphere/include/stratosphere/os/os_sdk_thread_info_api.hpp
new file mode 100644
index 00000000..375ba73b
--- /dev/null
+++ b/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/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp b/libstratosphere/include/stratosphere/os/os_sdk_thread_info_types.hpp
new file mode 100644
index 00000000..dafc5150
--- /dev/null
+++ b/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/libstratosphere/libstratosphere.mk b/libstratosphere/libstratosphere.mk
index 83a24366..e646ea02 100644
--- a/libstratosphere/libstratosphere.mk
+++ b/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/libstratosphere/source/diag/diag_abort_observer.cpp b/libstratosphere/source/diag/diag_abort_observer.cpp
new file mode 100644
index 00000000..183822b0
--- /dev/null
+++ b/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/libstratosphere/source/diag/diag_assertion_impl.cpp b/libstratosphere/source/diag/diag_assertion_impl.cpp
index 537ccedd..ad0472de 100644
--- a/libstratosphere/source/diag/diag_assertion_impl.cpp
+++ b/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/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s b/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s
index e29c989f..c22914cb 100644
--- a/libstratosphere/source/diag/diag_assertion_impl_for_nx_asm.board.nintendo_nx.s
+++ b/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/libstratosphere/source/diag/diag_backtrace.cpp b/libstratosphere/source/diag/diag_backtrace.cpp
new file mode 100644
index 00000000..f8eaedf6
--- /dev/null
+++ b/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/libstratosphere/source/diag/diag_log.cpp b/libstratosphere/source/diag/diag_log.cpp
index 5870e0c9..fc7980e8 100644
--- a/libstratosphere/source/diag/diag_log.cpp
+++ b/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/libstratosphere/source/diag/diag_symbol.cpp b/libstratosphere/source/diag/diag_symbol.cpp
new file mode 100644
index 00000000..a9a5b496
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp b/libstratosphere/source/diag/impl/diag_abort_observer_manager.cpp
new file mode 100644
index 00000000..ed8c6698
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp b/libstratosphere/source/diag/impl/diag_abort_observer_manager.hpp
new file mode 100644
index 00000000..e2bc6f1d
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp b/libstratosphere/source/diag/impl/diag_backtrace_impl.os.generic.cpp
new file mode 100644
index 00000000..9cd49070
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp b/libstratosphere/source/diag/impl/diag_backtrace_impl.os.horizon.cpp
new file mode 100644
index 00000000..b1f05c93
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp b/libstratosphere/source/diag/impl/diag_default_abort_observer.cpp
new file mode 100644
index 00000000..4c022480
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp b/libstratosphere/source/diag/impl/diag_dump_stack_trace.hpp
new file mode 100644
index 00000000..295b2c89
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp b/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.generic.cpp
new file mode 100644
index 00000000..560b53a4
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp b/libstratosphere/source/diag/impl/diag_dump_stack_trace.os.horizon.cpp
new file mode 100644
index 00000000..971bc538
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp b/libstratosphere/source/diag/impl/diag_get_all_backtrace.cpp
new file mode 100644
index 00000000..a96f8c5e
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp b/libstratosphere/source/diag/impl/diag_get_all_backtrace.hpp
new file mode 100644
index 00000000..1a5a7636
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_invoke_abort.hpp b/libstratosphere/source/diag/impl/diag_invoke_abort.hpp
new file mode 100644
index 00000000..513bd0ab
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp b/libstratosphere/source/diag/impl/diag_invoke_abort.os.generic.cpp
new file mode 100644
index 00000000..33812ab3
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp b/libstratosphere/source/diag/impl/diag_invoke_abort.os.horizon.cpp
new file mode 100644
index 00000000..33812ab3
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_symbol_impl.hpp b/libstratosphere/source/diag/impl/diag_symbol_impl.hpp
new file mode 100644
index 00000000..cdaebf89
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp b/libstratosphere/source/diag/impl/diag_symbol_impl.os.generic.cpp
new file mode 100644
index 00000000..888fc7a5
--- /dev/null
+++ b/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/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp b/libstratosphere/source/diag/impl/diag_symbol_impl.os.horizon.cpp
new file mode 100644
index 00000000..28e74a78
--- /dev/null
+++ b/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/libstratosphere/source/fs/fs_access_log.cpp b/libstratosphere/source/fs/fs_access_log.cpp
index 9006a921..3da798fd 100644
--- a/libstratosphere/source/fs/fs_access_log.cpp
+++ b/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/libstratosphere/source/os/impl/os_cache_impl.hpp b/libstratosphere/source/os/impl/os_cache_impl.hpp
index 7d3a23f2..663f51bb 100644
--- a/libstratosphere/source/os/impl/os_cache_impl.hpp
+++ b/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/libstratosphere/source/os/impl/os_debug_impl.hpp b/libstratosphere/source/os/impl/os_debug_impl.hpp
new file mode 100644
index 00000000..d8001d30
--- /dev/null
+++ b/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/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp b/libstratosphere/source/os/impl/os_debug_impl.os.horizon.hpp
new file mode 100644
index 00000000..e35a6092
--- /dev/null
+++ b/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/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp b/libstratosphere/source/os/impl/os_debug_impl.os.linux.hpp
new file mode 100644
index 00000000..52f09170
--- /dev/null
+++ b/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/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp b/libstratosphere/source/os/impl/os_debug_impl.os.macos.hpp
new file mode 100644
index 00000000..637460a1
--- /dev/null
+++ b/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/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp b/libstratosphere/source/os/impl/os_debug_impl.os.windows.hpp
new file mode 100644
index 00000000..7e596f36
--- /dev/null
+++ b/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/libstratosphere/source/os/os_debug.cpp b/libstratosphere/source/os/os_debug.cpp
new file mode 100644
index 00000000..57bb08ee
--- /dev/null
+++ b/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/libstratosphere/source/result/result_on_assertion.cpp b/libstratosphere/source/result/result_on_assertion.cpp
deleted file mode 100644
index f9eb49d9..00000000
--- a/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/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp b/libstratosphere/source/sf/hipc/sf_hipc_api.os.generic.cpp
new file mode 100644
index 00000000..a6fd71d3
--- /dev/null
+++ b/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/libvapours/include/vapours/assert.hpp b/libvapours/include/vapours/assert.hpp
index 83601343..d901f2d9 100644
--- a/libvapours/include/vapours/assert.hpp
+++ b/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/libvapours/include/vapours/results/cal_results.hpp b/libvapours/include/vapours/results/cal_results.hpp
index 2d99fef2..cb770ef5 100644
--- a/libvapours/include/vapours/results/cal_results.hpp
+++ b/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/libvapours/include/vapours/results/capsrv_results.hpp b/libvapours/include/vapours/results/capsrv_results.hpp
index 965d7f9d..d353ab93 100644
--- a/libvapours/include/vapours/results/capsrv_results.hpp
+++ b/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/libvapours/include/vapours/results/creport_results.hpp b/libvapours/include/vapours/results/creport_results.hpp
index a3b4d7a6..f7d424e6 100644
--- a/libvapours/include/vapours/results/creport_results.hpp
+++ b/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/libvapours/include/vapours/results/cs_results.hpp b/libvapours/include/vapours/results/cs_results.hpp
index b1e63802..8ff32ac7 100644
--- a/libvapours/include/vapours/results/cs_results.hpp
+++ b/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/libvapours/include/vapours/results/dd_results.hpp b/libvapours/include/vapours/results/dd_results.hpp
index 648fb6b6..dd1f042b 100644
--- a/libvapours/include/vapours/results/dd_results.hpp
+++ b/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/libvapours/include/vapours/results/ddsf_results.hpp b/libvapours/include/vapours/results/ddsf_results.hpp
index 73378d4e..35725429 100644
--- a/libvapours/include/vapours/results/ddsf_results.hpp
+++ b/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/libvapours/include/vapours/results/debug_results.hpp b/libvapours/include/vapours/results/debug_results.hpp
index d93cff64..6db0d722 100644
--- a/libvapours/include/vapours/results/debug_results.hpp
+++ b/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/libvapours/include/vapours/results/dmnt_results.hpp b/libvapours/include/vapours/results/dmnt_results.hpp
index 29323d32..f6203c9b 100644
--- a/libvapours/include/vapours/results/dmnt_results.hpp
+++ b/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/libvapours/include/vapours/results/erpt_results.hpp b/libvapours/include/vapours/results/erpt_results.hpp
index 3df7473e..10c1b9aa 100644
--- a/libvapours/include/vapours/results/erpt_results.hpp
+++ b/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/libvapours/include/vapours/results/err_results.hpp b/libvapours/include/vapours/results/err_results.hpp
index 88003f65..6dd43c88 100644
--- a/libvapours/include/vapours/results/err_results.hpp
+++ b/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/libvapours/include/vapours/results/exosphere_results.hpp b/libvapours/include/vapours/results/exosphere_results.hpp
index 128cac07..be02b877 100644
--- a/libvapours/include/vapours/results/exosphere_results.hpp
+++ b/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/libvapours/include/vapours/results/fatal_results.hpp b/libvapours/include/vapours/results/fatal_results.hpp
index 68ff8940..23d75720 100644
--- a/libvapours/include/vapours/results/fatal_results.hpp
+++ b/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/libvapours/include/vapours/results/fs_results.hpp b/libvapours/include/vapours/results/fs_results.hpp
index d3384d52..1b9ed605 100644
--- a/libvapours/include/vapours/results/fs_results.hpp
+++ b/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/libvapours/include/vapours/results/gpio_results.hpp b/libvapours/include/vapours/results/gpio_results.hpp
index 88e75baa..a228c812 100644
--- a/libvapours/include/vapours/results/gpio_results.hpp
+++ b/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/libvapours/include/vapours/results/hipc_results.hpp b/libvapours/include/vapours/results/hipc_results.hpp
index 99fd5644..8e557b5a 100644
--- a/libvapours/include/vapours/results/hipc_results.hpp
+++ b/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/libvapours/include/vapours/results/htc_results.hpp b/libvapours/include/vapours/results/htc_results.hpp
index 8d92196f..ba3a8741 100644
--- a/libvapours/include/vapours/results/htc_results.hpp
+++ b/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/libvapours/include/vapours/results/htcfs_results.hpp b/libvapours/include/vapours/results/htcfs_results.hpp
index 5549d5d8..cf96274e 100644
--- a/libvapours/include/vapours/results/htcfs_results.hpp
+++ b/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/libvapours/include/vapours/results/htclow_results.hpp b/libvapours/include/vapours/results/htclow_results.hpp
index 0d288c14..9f6dfa52 100644
--- a/libvapours/include/vapours/results/htclow_results.hpp
+++ b/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/libvapours/include/vapours/results/htcs_results.hpp b/libvapours/include/vapours/results/htcs_results.hpp
index 6e5dba0d..0f782d52 100644
--- a/libvapours/include/vapours/results/htcs_results.hpp
+++ b/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/libvapours/include/vapours/results/i2c_results.hpp b/libvapours/include/vapours/results/i2c_results.hpp
index 1704009e..2a0e0602 100644
--- a/libvapours/include/vapours/results/i2c_results.hpp
+++ b/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/libvapours/include/vapours/results/kvdb_results.hpp b/libvapours/include/vapours/results/kvdb_results.hpp
index 254d89e3..109a81bb 100644
--- a/libvapours/include/vapours/results/kvdb_results.hpp
+++ b/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/libvapours/include/vapours/results/loader_results.hpp b/libvapours/include/vapours/results/loader_results.hpp
index 691acbd4..825be378 100644
--- a/libvapours/include/vapours/results/loader_results.hpp
+++ b/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/libvapours/include/vapours/results/lr_results.hpp b/libvapours/include/vapours/results/lr_results.hpp
index fd18d022..faad916d 100644
--- a/libvapours/include/vapours/results/lr_results.hpp
+++ b/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/libvapours/include/vapours/results/ncm_results.hpp b/libvapours/include/vapours/results/ncm_results.hpp
index 8c4a2aea..a3b4fb80 100644
--- a/libvapours/include/vapours/results/ncm_results.hpp
+++ b/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/libvapours/include/vapours/results/nim_results.hpp b/libvapours/include/vapours/results/nim_results.hpp
index 967bfd3e..a006b4a4 100644
--- a/libvapours/include/vapours/results/nim_results.hpp
+++ b/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/libvapours/include/vapours/results/ns_results.hpp b/libvapours/include/vapours/results/ns_results.hpp
index 29d386f9..34bf8309 100644
--- a/libvapours/include/vapours/results/ns_results.hpp
+++ b/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/libvapours/include/vapours/results/os_results.hpp b/libvapours/include/vapours/results/os_results.hpp
index 62a6344c..b83389e8 100644
--- a/libvapours/include/vapours/results/os_results.hpp
+++ b/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/libvapours/include/vapours/results/osdbg_results.hpp b/libvapours/include/vapours/results/osdbg_results.hpp
index 952c0730..0ced0875 100644
--- a/libvapours/include/vapours/results/osdbg_results.hpp
+++ b/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/libvapours/include/vapours/results/pcv_results.hpp b/libvapours/include/vapours/results/pcv_results.hpp
index eed8e316..daf05f28 100644
--- a/libvapours/include/vapours/results/pcv_results.hpp
+++ b/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/libvapours/include/vapours/results/pgl_results.hpp b/libvapours/include/vapours/results/pgl_results.hpp
index c909aa66..af4176de 100644
--- a/libvapours/include/vapours/results/pgl_results.hpp
+++ b/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/libvapours/include/vapours/results/pm_results.hpp b/libvapours/include/vapours/results/pm_results.hpp
index 1bb18e02..4c9e51ad 100644
--- a/libvapours/include/vapours/results/pm_results.hpp
+++ b/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/libvapours/include/vapours/results/powctl_results.hpp b/libvapours/include/vapours/results/powctl_results.hpp
index 7a9d6d7f..98413f67 100644
--- a/libvapours/include/vapours/results/powctl_results.hpp
+++ b/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/libvapours/include/vapours/results/psc_results.hpp b/libvapours/include/vapours/results/psc_results.hpp
index 019925ac..16d8e307 100644
--- a/libvapours/include/vapours/results/psc_results.hpp
+++ b/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/libvapours/include/vapours/results/pwm_results.hpp b/libvapours/include/vapours/results/pwm_results.hpp
index ed5a8ded..247a5f31 100644
--- a/libvapours/include/vapours/results/pwm_results.hpp
+++ b/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/libvapours/include/vapours/results/results_common.hpp b/libvapours/include/vapours/results/results_common.hpp
index ec03e67d..2ddbf37d 100644
--- a/libvapours/include/vapours/results/results_common.hpp
+++ b/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/libvapours/include/vapours/results/ro_results.hpp b/libvapours/include/vapours/results/ro_results.hpp
index 076b3455..c187749d 100644
--- a/libvapours/include/vapours/results/ro_results.hpp
+++ b/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/libvapours/include/vapours/results/scs_results.hpp b/libvapours/include/vapours/results/scs_results.hpp
index 1446b0ef..59dcfe81 100644
--- a/libvapours/include/vapours/results/scs_results.hpp
+++ b/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/libvapours/include/vapours/results/sdmmc_results.hpp b/libvapours/include/vapours/results/sdmmc_results.hpp
index 25d4aa1e..3477907c 100644
--- a/libvapours/include/vapours/results/sdmmc_results.hpp
+++ b/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/libvapours/include/vapours/results/settings_results.hpp b/libvapours/include/vapours/results/settings_results.hpp
index 0155b00f..828b489b 100644
--- a/libvapours/include/vapours/results/settings_results.hpp
+++ b/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/libvapours/include/vapours/results/sf_results.hpp b/libvapours/include/vapours/results/sf_results.hpp
index add2cd5b..825ac175 100644
--- a/libvapours/include/vapours/results/sf_results.hpp
+++ b/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/libvapours/include/vapours/results/sm_results.hpp b/libvapours/include/vapours/results/sm_results.hpp
index 28119b7c..7b29894b 100644
--- a/libvapours/include/vapours/results/sm_results.hpp
+++ b/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/libvapours/include/vapours/results/socket_results.hpp b/libvapours/include/vapours/results/socket_results.hpp
index 58915c1d..f83cbaee 100644
--- a/libvapours/include/vapours/results/socket_results.hpp
+++ b/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/libvapours/include/vapours/results/spl_results.hpp b/libvapours/include/vapours/results/spl_results.hpp
index c15e5cd3..12c1199b 100644
--- a/libvapours/include/vapours/results/spl_results.hpp
+++ b/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/libvapours/include/vapours/results/sprofile_results.hpp b/libvapours/include/vapours/results/sprofile_results.hpp
index 8772bdb0..4000bd8f 100644
--- a/libvapours/include/vapours/results/sprofile_results.hpp
+++ b/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/libvapours/include/vapours/results/svc_results.hpp b/libvapours/include/vapours/results/svc_results.hpp
index 6128b6b2..7a01b569 100644
--- a/libvapours/include/vapours/results/svc_results.hpp
+++ b/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/libvapours/include/vapours/results/time_results.hpp b/libvapours/include/vapours/results/time_results.hpp
index 863ac47c..c83941fe 100644
--- a/libvapours/include/vapours/results/time_results.hpp
+++ b/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/libvapours/include/vapours/results/tipc_results.hpp b/libvapours/include/vapours/results/tipc_results.hpp
index b537bd38..c381c87e 100644
--- a/libvapours/include/vapours/results/tipc_results.hpp
+++ b/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/libvapours/include/vapours/results/tma_results.hpp b/libvapours/include/vapours/results/tma_results.hpp
index 55a1068b..ce464687 100644
--- a/libvapours/include/vapours/results/tma_results.hpp
+++ b/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/libvapours/include/vapours/results/updater_results.hpp b/libvapours/include/vapours/results/updater_results.hpp
index 7e86e435..0ff0e135 100644
--- a/libvapours/include/vapours/results/updater_results.hpp
+++ b/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/libvapours/include/vapours/results/usb_results.hpp b/libvapours/include/vapours/results/usb_results.hpp
index a56efe78..a4185b16 100644
--- a/libvapours/include/vapours/results/usb_results.hpp
+++ b/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/libvapours/include/vapours/results/vi_results.hpp b/libvapours/include/vapours/results/vi_results.hpp
index 2012bd16..3df6c3fc 100644
--- a/libvapours/include/vapours/results/vi_results.hpp
+++ b/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/libvapours/source/result/result_get_name.cpp b/libvapours/source/result/result_get_name.cpp
new file mode 100644
index 00000000..4595d0b1
--- /dev/null
+++ b/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/libvapours/source/util/util_format_string.cpp b/libvapours/source/util/util_format_string.cpp
index 312d0906..9ef0bb7a 100644
--- a/libvapours/source/util/util_format_string.cpp
+++ b/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;