mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 04:11:18 +00:00
abort/error: print backtrace, abuse templates, overhaul result/diag (macos not done yet)
This commit is contained in:
parent
5c5789eadf
commit
87764613f2
118 changed files with 2843 additions and 369 deletions
|
@ -18,13 +18,13 @@
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) {
|
||||
AMS_UNUSED(file, line, func, expr, value, format);
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) {
|
||||
AMS_UNUSED(expr, func, line, file);
|
||||
ams::secmon::loader::ErrorReboot();
|
||||
}
|
||||
|
||||
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) {
|
||||
AMS_UNUSED(file, line, func, expr, value);
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) {
|
||||
AMS_UNUSED(expr, func, line, file, format);
|
||||
ams::secmon::loader::ErrorReboot();
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
NORETURN void AbortImpl() {
|
||||
AMS_SECMON_LOG("AbortImpl was called\n");
|
||||
AMS_LOG_FLUSH();
|
||||
reg::Write(0x4, 0xAAAAAAAA);
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace ams::rebootstub {
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
NORETURN void AbortImpl() {
|
||||
/* Halt the bpmp. */
|
||||
rebootstub::Halt();
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ namespace ams::sc7fw {
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
NORETURN void AbortImpl() {
|
||||
sc7fw::ExceptionHandler();
|
||||
}
|
||||
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace ams::diag {
|
|||
|
||||
}
|
||||
|
||||
void AbortImpl() {
|
||||
NORETURN void AbortImpl() {
|
||||
/* Perform any necessary (typically none) debugging. */
|
||||
if constexpr (SaveSystemStateForDebug) {
|
||||
SaveSystemStateForDebugAbort();
|
||||
|
|
|
@ -98,7 +98,7 @@ namespace ams::warmboot {
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
void AbortImpl() {
|
||||
NORETURN void AbortImpl() {
|
||||
warmboot::ExceptionHandler();
|
||||
}
|
||||
|
||||
|
|
|
@ -18,13 +18,15 @@
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) {
|
||||
AMS_UNUSED(file, line, func, expr, value, format);
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) {
|
||||
AMS_UNUSED(expr, func, line, file);
|
||||
|
||||
ams::nxboot::loader::ErrorStop();
|
||||
}
|
||||
|
||||
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) {
|
||||
AMS_UNUSED(file, line, func, expr, value);
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) {
|
||||
AMS_UNUSED(expr, func, line, file, format);
|
||||
|
||||
ams::nxboot::loader::ErrorStop();
|
||||
}
|
||||
|
||||
|
|
|
@ -27,20 +27,36 @@ namespace ams::nxboot {
|
|||
|
||||
namespace ams::diag {
|
||||
|
||||
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) {
|
||||
AMS_UNUSED(file, line, func, expr, format);
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line) {
|
||||
AMS_UNUSED(expr, func, line, file);
|
||||
|
||||
u32 lr;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
nxboot::ShowFatalError("Abort called, lr=%p, value=%" PRIx64 "\n", reinterpret_cast<void *>(lr), value);
|
||||
nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast<void *>(lr));
|
||||
}
|
||||
|
||||
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) {
|
||||
AMS_UNUSED(file, line, func, expr);
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const char *format, ...) {
|
||||
AMS_UNUSED(expr, func, line, file, format);
|
||||
|
||||
u32 lr;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
nxboot::ShowFatalError("Abort called, lr=%p, value=%" PRIx64 "\n", reinterpret_cast<void *>(lr), value);
|
||||
nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast<void *>(lr));
|
||||
}
|
||||
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const char *format, ...) {
|
||||
AMS_UNUSED(expr, func, line, file, result, format);
|
||||
|
||||
u32 lr;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
nxboot::ShowFatalError("Abort called, lr=%p, result=0x%08" PRIX32 "\n", reinterpret_cast<void *>(lr), result != nullptr ? result->GetValue() : 0);
|
||||
}
|
||||
|
||||
NORETURN void AbortImpl(const char *expr, const char *func, const char *file, int line, const ::ams::Result *result, const ::ams::os::UserExceptionInfo *exception_info, const char *format, ...) {
|
||||
AMS_UNUSED(expr, func, line, file, result, exception_info, format);
|
||||
|
||||
u32 lr;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
nxboot::ShowFatalError("Abort called, lr=%p, result=0x%08" PRIX32 "\n", reinterpret_cast<void *>(lr), result != nullptr ? result->GetValue() : 0);
|
||||
}
|
||||
|
||||
NORETURN void AbortImpl() {
|
||||
|
@ -49,16 +65,16 @@ namespace ams::diag {
|
|||
nxboot::ShowFatalError("Abort called, lr=%p\n", reinterpret_cast<void *>(lr));
|
||||
}
|
||||
|
||||
NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value) {
|
||||
AMS_UNUSED(file, line, func, expr, value);
|
||||
NORETURN void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line) {
|
||||
AMS_UNUSED(type, expr, func, file, line);
|
||||
|
||||
u32 lr;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
nxboot::ShowFatalError("Assert called, lr=%p\n", reinterpret_cast<void *>(lr));
|
||||
}
|
||||
|
||||
NORETURN void AssertionFailureImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) {
|
||||
AMS_UNUSED(file, line, func, expr, value, format);
|
||||
NORETURN void OnAssertionFailure(AssertionType type, const char *expr, const char *func, const char *file, int line, const char *format, ...) {
|
||||
AMS_UNUSED(type, expr, func, file, line, format);
|
||||
|
||||
u32 lr;
|
||||
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
|
||||
|
@ -66,17 +82,3 @@ namespace ams::diag {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ams::result::impl {
|
||||
|
||||
NORETURN void OnResultAbort(const char *file, int line, const char *func, const char *expr, Result result) {
|
||||
::ams::diag::AbortImpl(file, line, func, expr, result.GetValue(), "Result Abort: 2%03" PRId32 "-%04" PRId32 "", result.GetModule(), result.GetDescription());
|
||||
AMS_INFINITE_LOOP();
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
NORETURN void OnResultAbort(Result result) {
|
||||
OnResultAbort("", 0, "", "", result);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 +=
|
||||
|
|
|
@ -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 +=
|
||||
|
|
|
@ -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 +=
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -14,23 +14,22 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <exosphere.hpp>
|
||||
|
||||
namespace ams::impl {
|
||||
|
||||
NORETURN void UnexpectedDefaultImpl(const char *func, const char *file, int line) {
|
||||
::ams::diag::AbortImpl("", func, file, line);
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
#include <stratosphere/diag/impl/diag_impl_log.hpp>
|
||||
#include <stratosphere/diag/diag_log.hpp>
|
||||
#include <stratosphere/diag/diag_sdk_log.hpp>
|
||||
#include <stratosphere/diag/diag_abort_observer.hpp>
|
||||
#include <stratosphere/diag/diag_assertion_failure_handler.hpp>
|
||||
|
||||
#include <stratosphere/diag/impl/diag_utf8_util.hpp>
|
||||
|
||||
#include <stratosphere/diag/diag_backtrace.hpp>
|
||||
#include <stratosphere/diag/diag_symbol.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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/diag/diag_log_types.hpp>
|
||||
|
||||
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);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/diag/diag_log_types.hpp>
|
||||
|
||||
namespace ams::diag {
|
||||
|
||||
enum AssertionFailureOperation {
|
||||
AssertionFailureOperation_Abort,
|
||||
AssertionFailureOperation_Continue,
|
||||
};
|
||||
|
||||
using AssertionFailureHandler = AssertionFailureOperation (*)(const AssertionInfo &info);
|
||||
|
||||
void SetAssertionFailureHandler(AssertionFailureHandler handler);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_OS_HORIZON)
|
||||
#include <stratosphere/diag/impl/diag_backtrace_impl.os.horizon.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_WINDOWS)
|
||||
#include <stratosphere/diag/impl/diag_backtrace_impl.os.windows.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_LINUX)
|
||||
#include <stratosphere/diag/impl/diag_backtrace_impl.os.linux.hpp>
|
||||
#elif defined(ATMOSPHERE_OS_MACOS)
|
||||
#include <stratosphere/diag/impl/diag_backtrace_impl.os.macos.hpp>
|
||||
#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(); }
|
||||
};
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
namespace ams::diag {
|
||||
|
||||
uintptr_t GetSymbolName(char *dst, size_t dst_size, uintptr_t address);
|
||||
size_t GetSymbolSize(uintptr_t address);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
|
@ -46,6 +46,7 @@
|
|||
#include <stratosphere/os/os_sdk_reply_and_receive.hpp>
|
||||
#include <stratosphere/os/os_thread.hpp>
|
||||
#include <stratosphere/os/os_sdk_thread_api.hpp>
|
||||
#include <stratosphere/os/os_sdk_thread_info.hpp>
|
||||
#include <stratosphere/os/os_message_queue.hpp>
|
||||
#include <stratosphere/os/os_light_event.hpp>
|
||||
#include <stratosphere/os/os_light_message_queue.hpp>
|
||||
|
@ -55,3 +56,4 @@
|
|||
#include <stratosphere/os/os_multiple_wait.hpp>
|
||||
#include <stratosphere/os/os_argument.hpp>
|
||||
#include <stratosphere/os/os_cache.hpp>
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_debug_types.hpp>
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <stratosphere/os/os_debug_types.hpp>
|
||||
#include <stratosphere/os/os_tick.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
void GetCurrentStackInfo(uintptr_t *out_stack, size_t *out_size);
|
||||
|
||||
void QueryMemoryInfo(MemoryInfo *out);
|
||||
|
||||
Tick GetIdleTickCount();
|
||||
|
||||
int GetFreeThreadCount();
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stratosphere/os/os_sdk_thread_info_types.hpp>
|
||||
#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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <stratosphere/os/os_sdk_thread_info_types.hpp>
|
||||
#include <stratosphere/os/os_thread_types.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
void GetThreadStackInfo(uintptr_t *out_stack_top, size_t *out_stack_size, const ThreadType *thread);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere/os/os_common_types.hpp>
|
||||
|
||||
namespace ams::os {
|
||||
|
||||
enum SdkLastThreadInfoFlag : u32 {
|
||||
SdkLastThreadInfoFlag_ThreadInSystemCall = (1u << 0),
|
||||
};
|
||||
|
||||
}
|
|
@ -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
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "impl/diag_abort_observer_manager.hpp"
|
||||
|
||||
namespace ams::diag {
|
||||
|
||||
namespace impl {
|
||||
|
||||
constinit bool g_enable_default_abort_observer = true;
|
||||
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
template<typename Holder, typename Observer>
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
50
libraries/libstratosphere/source/diag/diag_backtrace.cpp
Normal file
50
libraries/libstratosphere/source/diag/diag_backtrace.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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
|
||||
|
||||
|
||||
}
|
|
@ -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<char *>(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);
|
||||
|
|
35
libraries/libstratosphere/source/diag/diag_symbol.cpp
Normal file
35
libraries/libstratosphere/source/diag/diag_symbol.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#include "diag_observer_manager.hpp"
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
using AbortObserverManager = ObserverManager<AbortObserverHolder, const AbortInfo &>;
|
||||
using SdkAbortObserverManager = ObserverManager<SdkAbortObserverHolder, const SdkAbortInfo &>;
|
||||
|
||||
AbortObserverManager *GetAbortObserverManager();
|
||||
SdkAbortObserverManager *GetSdkAbortObserverManager();
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#if defined(ATMOSPHERE_OS_LINUX) || defined(ATMOSPHERE_OS_MACOS)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#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<void *>(frame.lr);
|
||||
|
||||
/* Set the next fp. */
|
||||
cur_fp = reinterpret_cast<const void *>(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<uintptr_t>(m_backtrace_addresses[m_index]);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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<uintptr_t *>(address);
|
||||
}
|
||||
|
||||
template<typename T, size_t N>
|
||||
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<svc::MemoryInfo *>(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<void *>(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<void *>(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<void *>(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<uintptr_t>(thread->stack);
|
||||
out->stack_bottom = reinterpret_cast<uintptr_t>(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<void *>(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<void *>(m_fp), reinterpret_cast<void *>(m_current_stack_info->stack_top), reinterpret_cast<void *>(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<void *>(m_fp), reinterpret_cast<void *>(m_prev_fp), reinterpret_cast<void *>(m_current_stack_info->stack_top), reinterpret_cast<void *>(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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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<u64>(process_id), static_cast<u64>(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
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
void TentativeDumpStackTrace();
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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<u64>(backtrace[i]), symbol_name, static_cast<u64>(backtrace[i] - (symbol_base + 1)));
|
||||
} else {
|
||||
AMS_SDK_LOG("0x%016" PRIX64 " [ unknown ]\n", static_cast<u64>(backtrace[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
AMS_SDK_LOG("-------------------------------------------\n");
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#include "diag_dump_stack_trace.hpp"
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
void TentativeDumpStackTrace() {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
constinit uintptr_t g_abort_impl_return_address = std::numeric_limits<uintptr_t>::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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
void SetAbortImplAddress(uintptr_t address);
|
||||
|
||||
size_t GetAllBacktrace(uintptr_t *out, size_t out_size, ::ams::diag::Backtrace &bt);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
void InvokeAbortObserver(const AbortInfo &info);
|
||||
void InvokeSdkAbortObserver(const SdkAbortInfo &info);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
namespace ams::diag::impl {
|
||||
|
||||
uintptr_t GetSymbolNameImpl(char *dst, size_t dst_size, uintptr_t address);
|
||||
size_t GetSymbolSizeImpl(uintptr_t address);
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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 <binutils/bfd.h>
|
||||
#include <psapi.h>
|
||||
#else
|
||||
#include <bfd.h>
|
||||
#endif
|
||||
|
||||
#if defined(ATMOSPHERE_OS_LINUX)
|
||||
#include <unistd.h>
|
||||
#include <dlfcn.h>
|
||||
#include <link.h>
|
||||
|
||||
extern "C" char __init_array_start;
|
||||
#endif
|
||||
|
||||
#define HAVE_DECL_BASENAME 1
|
||||
#include <libiberty/demangle.h>
|
||||
|
||||
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<asymbol **>(symbol_table);
|
||||
m_num_symbol = static_cast<size_t>(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<uintptr_t>(module_info.lpBaseOfDll);
|
||||
m_module_size = static_cast<size_t>(module_info.SizeOfImage);
|
||||
}
|
||||
}
|
||||
#elif defined(ATMOSPHERE_OS_LINUX)
|
||||
{
|
||||
m_module_address = _r_debug.r_map->l_addr;
|
||||
|
||||
m_module_size = reinterpret_cast<uintptr_t>(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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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");
|
||||
}
|
||||
|
||||
}
|
|
@ -144,6 +144,14 @@ namespace ams::fs::impl {
|
|||
}
|
||||
}
|
||||
|
||||
template<> const char *IdString::ToString<fs::MountHostOption>(fs::MountHostOption id) {
|
||||
if (id == MountHostOption::PseudoCaseSensitive) {
|
||||
return "MountHostOptionFlag_PseudoCaseSensitive";
|
||||
} else {
|
||||
return ToValueString(static_cast<int>(id._value));
|
||||
}
|
||||
}
|
||||
|
||||
template<> const char *IdString::ToString<fs::BisPartitionId>(fs::BisPartitionId id) {
|
||||
switch (id) {
|
||||
using enum fs::BisPartitionId;
|
||||
|
|
|
@ -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
|
||||
|
|
29
libraries/libstratosphere/source/os/impl/os_debug_impl.hpp
Normal file
29
libraries/libstratosphere/source/os/impl/os_debug_impl.hpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
#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
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
#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<uintptr_t>(cur_fiber == nullptr ? cur_thread->stack : /* TODO: cur_fiber->stack */ nullptr);
|
||||
size_t stack_size = reinterpret_cast<size_t>(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<u64>(-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<u64>(-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<u64>(std::numeric_limits<int>::max()));
|
||||
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
};
|
||||
|
||||
using DebugImpl = DebugHorizonImpl;
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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<uintptr_t>(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;
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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<uintptr_t>(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;
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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<NT_TIB *>(::NtCurrentTeb());
|
||||
|
||||
*out_stack = reinterpret_cast<uintptr_t>(tib->StackLimit);
|
||||
*out_size = reinterpret_cast<uintptr_t>(tib->StackBase) - reinterpret_cast<uintptr_t>(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;
|
||||
|
||||
}
|
53
libraries/libstratosphere/source/os/os_debug.cpp
Normal file
53
libraries/libstratosphere/source/os/os_debug.cpp
Normal file
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
#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<uintptr_t>(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();
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stratosphere.hpp>
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
}
|
|
@ -16,48 +16,103 @@
|
|||
#pragma once
|
||||
#include <vapours/common.hpp>
|
||||
|
||||
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<bool>(expr)); \
|
||||
} else { \
|
||||
if (const bool __tmp_ams_assert_val = static_cast<bool>(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<void>(0)
|
||||
#define AMS_ASSERT_IMPL(type, expr, ...) static_cast<void>(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
|
||||
|
|
|
@ -16,11 +16,10 @@
|
|||
|
||||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
#include <vapours/results/powctl_results.hpp>
|
||||
|
||||
namespace ams::cal {
|
||||
|
||||
R_DEFINE_NAMESPACE_RESULT_MODULE(198);
|
||||
|
||||
R_DEFINE_ERROR_RESULT(CalibrationDataCrcError, 101);
|
||||
using powctl::ResultCalibrationDataCrcError;
|
||||
|
||||
}
|
||||
|
|
|
@ -16,9 +16,10 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,34 +17,34 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
// }
|
||||
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,12 +17,11 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
/* 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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -16,9 +16,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,12 +17,14 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
}
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
#pragma once
|
||||
#include <vapours/results/results_common.hpp>
|
||||
|
||||
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);
|
||||
|
||||
|
|
|
@ -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<int Module>
|
||||
struct ResultNameSpaceExistsImpl {
|
||||
static constexpr bool Exists = false;
|
||||
|
||||
template<int Description>
|
||||
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<Result>::value, "std::is_trivially_destructible<Result>::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<int Description> \
|
||||
struct ResultNameHolderImpl { static constexpr bool Exists = false; }; \
|
||||
} \
|
||||
\
|
||||
} \
|
||||
\
|
||||
namespace ams::result::impl { \
|
||||
\
|
||||
template<> struct ResultNameSpaceExistsImpl<value> { \
|
||||
static constexpr bool Exists = true; \
|
||||
\
|
||||
template<int Description> \
|
||||
using NameHolder = nmspc::result_impl::ResultNameHolderImpl<Description>; \
|
||||
}; \
|
||||
\
|
||||
}
|
||||
#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<desc_start> { 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<R_CURRENT_NAMESPACE_RESULT_MODULE, desc_start>, public ::ams::result::impl::ResultErrorRangeBase<R_CURRENT_NAMESPACE_RESULT_MODULE, desc_start, desc_end> {}
|
||||
|
||||
#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<R_CURRENT_NAMESPACE_RESULT_MODULE, desc_start, desc_end> {}
|
||||
|
||||
|
||||
#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.
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue