diff --git a/app/src/main/cpp/skyline/nce.cpp b/app/src/main/cpp/skyline/nce.cpp index 6800a6a2..8ee56652 100644 --- a/app/src/main/cpp/skyline/nce.cpp +++ b/app/src/main/cpp/skyline/nce.cpp @@ -107,37 +107,46 @@ namespace skyline::nce { *tls = nullptr; } else { // If TLS wasn't restored then this occurred in host code - if (signal == SIGSEGV) { - bool runningUnderDebugger{[]() { - static std::ifstream status("/proc/self/status"); - status.seekg(0); - - constexpr std::string_view TracerPidTag{"TracerPid:"}; - for (std::string line; std::getline(status, line);) { - if (line.starts_with(TracerPidTag)) { - line = line.substr(TracerPidTag.size()); - - for (char character : line) - if (std::isspace(character)) - continue; - else - return character != '0'; - - return false; - } - } - - return false; - }()}; - - if (runningUnderDebugger) - raise(SIGTRAP); // Notify the debugger if we've got a SIGSEGV as the debugger doesn't catch them by default as they might be hooked - } - - signal::ExceptionalSignalHandler(signal, info, ctx); //!< Delegate throwing a host exception to the exceptional signal handler + HostSignalHandler(signal, info, ctx); } } + static NCE* staticNce{nullptr}; //!< A static instance of NCE for use in the signal handler + + void NCE::HostSignalHandler(int signal, siginfo *info, ucontext *ctx) { + if (signal == SIGSEGV) { + if (staticNce && staticNce->TrapHandler(reinterpret_cast(info->si_addr), true)) + return; + + bool runningUnderDebugger{[]() { + static std::ifstream status("/proc/self/status"); + status.seekg(0); + + constexpr std::string_view TracerPidTag{"TracerPid:"}; + for (std::string line; std::getline(status, line);) { + if (line.starts_with(TracerPidTag)) { + line = line.substr(TracerPidTag.size()); + + for (char character : line) + if (std::isspace(character)) + continue; + else + return character != '0'; + + return false; + } + } + + return false; + }()}; + + if (runningUnderDebugger) + raise(SIGTRAP); // Notify the debugger if we've got a SIGSEGV as the debugger doesn't catch them by default as they might be hooked + } + + signal::ExceptionalSignalHandler(signal, info, ctx); // Delegate throwing a host exception to the exceptional signal handler + } + void *NceTlsRestorer() { ThreadContext *threadCtx; asm volatile("MRS %x0, TPIDR_EL0":"=r"(threadCtx)); @@ -149,6 +158,7 @@ namespace skyline::nce { NCE::NCE(const DeviceState &state) : state(state) { signal::SetTlsRestorer(&NceTlsRestorer); + staticNce = this; } constexpr u8 MainSvcTrampolineSize{17}; // Size of the main SVC trampoline function in u32 units diff --git a/app/src/main/cpp/skyline/nce.h b/app/src/main/cpp/skyline/nce.h index 834d5898..5b51f569 100644 --- a/app/src/main/cpp/skyline/nce.h +++ b/app/src/main/cpp/skyline/nce.h @@ -64,6 +64,15 @@ namespace skyline::nce { */ static void SignalHandler(int signal, siginfo *info, ucontext *ctx, void **tls); + /** + * @brief Handles signals for any host threads which may access NCE trapped memory + * @note Any untrapped SIGSEGVs will emit SIGTRAP when a debugger is attached rather than throwing an exception + */ + static void HostSignalHandler(int signal, siginfo *info, ucontext *ctx); + + /** + * @note There should only be one instance of NCE concurrently + */ NCE(const DeviceState &state); struct PatchData { diff --git a/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp b/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp index 009688f5..ecd641d7 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/gpfifo.cpp @@ -330,7 +330,8 @@ namespace skyline::soc::gm20b { void ChannelGpfifo::Run() { pthread_setname_np(pthread_self(), "GPFIFO"); try { - signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler); + signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE}, signal::ExceptionalSignalHandler); + signal::SetSignalHandler({SIGSEGV}, nce::NCE::HostSignalHandler); // We may access NCE trapped memory gpEntries.Process([this](GpEntry gpEntry) { Logger::Debug("Processing pushbuffer: 0x{:X}, Size: 0x{:X}", gpEntry.Address(), +gpEntry.size); diff --git a/app/src/main/cpp/skyline/soc/host1x/command_fifo.cpp b/app/src/main/cpp/skyline/soc/host1x/command_fifo.cpp index 9b3fa0ed..6d31bf51 100644 --- a/app/src/main/cpp/skyline/soc/host1x/command_fifo.cpp +++ b/app/src/main/cpp/skyline/soc/host1x/command_fifo.cpp @@ -2,6 +2,7 @@ // Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/) #include +#include #include #include #include @@ -115,7 +116,8 @@ namespace skyline::soc::host1x { void ChannelCommandFifo::Run() { pthread_setname_np(pthread_self(), "ChannelCommandFifo"); try { - signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE, SIGSEGV}, signal::ExceptionalSignalHandler); + signal::SetSignalHandler({SIGINT, SIGILL, SIGTRAP, SIGBUS, SIGFPE}, signal::ExceptionalSignalHandler); + signal::SetSignalHandler({SIGSEGV}, nce::NCE::HostSignalHandler); // We may access NCE trapped memory gatherQueue.Process([this](span gather) { Logger::Debug("Processing pushbuffer: 0x{:X}, size: 0x{:X}", gather.data(), gather.size()); @@ -144,4 +146,4 @@ namespace skyline::soc::host1x { thread.join(); } } -} \ No newline at end of file +}