Complete Exceptional Signal Handler Implementation + Fix More Destruction Behavior

This commit is contained in:
◱ PixelyIon 2020-11-17 06:18:41 +05:30 committed by ◱ PixelyIon
parent 8bf08ed66f
commit d155e9cd71
21 changed files with 231 additions and 135 deletions

View File

@ -9,9 +9,18 @@
<JetCodeStyleSettings>
<option name="PACKAGES_TO_USE_STAR_IMPORTS">
<value>
<package name="java.util" withSubpackages="false" static="false" />
<package name="kotlinx.android.synthetic" withSubpackages="true" static="false" />
<package name="io.ktor" withSubpackages="true" static="false" />
<package name="java.util" alias="false" withSubpackages="false" />
<package name="kotlinx.android.synthetic" alias="false" withSubpackages="true" />
<package name="io.ktor" alias="false" withSubpackages="true" />
</value>
</option>
<option name="PACKAGES_IMPORT_LAYOUT">
<value>
<package name="" alias="false" withSubpackages="true" />
<package name="java" alias="false" withSubpackages="true" />
<package name="javax" alias="false" withSubpackages="true" />
<package name="kotlin" alias="false" withSubpackages="true" />
<package name="" alias="true" withSubpackages="true" />
</value>
</option>
<option name="SPACE_BEFORE_TYPE_COLON" value="true" />

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DiscordIntegrationProjectSettings" description="Lightswitch is an experimental Nintendo Switch emulator for Android phones." />
<component name="DiscordProjectSettings">
<option name="show" value="PROJECT_FILES" />
</component>
</project>

View File

@ -10,7 +10,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -Wno-unused-command-line-argument")
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -fno-stack-protector -Wno-unused-command-line-argument")
if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
add_compile_definitions(NDEBUG)
endif ()

View File

@ -25,7 +25,6 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
FrameTime = 0;
pthread_setname_np(pthread_self(), "EmuMain");
setpriority(PRIO_PGRP, static_cast<id_t>(gettid()), -8); // Set the priority of this process to the highest value
auto jvmManager{std::make_shared<skyline::JvmManager>(env, instance)};
auto settings{std::make_shared<skyline::Settings>(preferenceFd)};
@ -72,15 +71,10 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_stopEmulation(JNIEn
os = OsWeak.lock();
auto process{os->state.process};
while (!process) {
__sync_synchronize();
process = os->state.process;
__sync_synchronize();
}
while (!process->mainThread)
__sync_synchronize();
auto thread{process->mainThread}; // We just need to kill the main thread, it'll kill the rest itself
while (!thread->running)
__sync_synchronize();
thread->Kill(true);
process->Kill(true, false, true);
}
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setSurface(JNIEnv *, jobject, jobject surface) {

View File

@ -61,12 +61,9 @@ namespace skyline {
DeviceState::DeviceState(kernel::OS *os, std::shared_ptr<JvmManager> jvmManager, std::shared_ptr<Settings> settings, std::shared_ptr<Logger> logger)
: os(os), jvm(std::move(jvmManager)), settings(std::move(settings)), logger(std::move(logger)) {
// We assign these later as they use the state in their constructor and we don't want null pointers
nce = std::make_shared<nce::NCE>(*this);
gpu = std::make_shared<gpu::GPU>(*this);
audio = std::make_shared<audio::Audio>(*this);
nce = std::make_shared<nce::NCE>(*this);
input = std::make_shared<input::Input>(*this);
}
thread_local std::shared_ptr<kernel::type::KThread> DeviceState::thread = nullptr;
thread_local nce::ThreadContext *DeviceState::ctx = nullptr;
}

View File

@ -479,10 +479,10 @@ namespace skyline {
std::shared_ptr<loader::Loader> loader;
std::shared_ptr<gpu::GPU> gpu;
std::shared_ptr<audio::Audio> audio;
std::shared_ptr<input::Input> input;
std::shared_ptr<nce::NCE> nce;
std::shared_ptr<kernel::type::KProcess> process;
thread_local static std::shared_ptr<kernel::type::KThread> thread; //!< The KThread of the thread which accesses this object
thread_local static nce::ThreadContext *ctx; //!< The context of the guest thread for the corresponding host thread
static thread_local inline std::shared_ptr<kernel::type::KThread> thread{}; //!< The KThread of the thread which accesses this object
static thread_local inline nce::ThreadContext *ctx{}; //!< The context of the guest thread for the corresponding host thread
std::shared_ptr<input::Input> input;
};
}

View File

@ -21,9 +21,9 @@ namespace skyline {
std::condition_variable produceCondition;
public:
CircularQueue(size_t size) : vector(size * sizeof(Type)) {}
inline CircularQueue(size_t size) : vector(size * sizeof(Type)) {}
~CircularQueue() {
inline ~CircularQueue() {
ssize_t size{};
if (start < end)
size = end - start;

View File

@ -4,22 +4,59 @@
#include <unistd.h>
#include <dlfcn.h>
#include <unwind.h>
#include <android/log.h>
#include "signal.h"
namespace skyline::signal {
thread_local SignalException signalException;
thread_local std::exception_ptr SignalExceptionPtr;
void ExceptionThrow() {
throw signalException;
std::rethrow_exception(SignalExceptionPtr);
}
std::terminate_handler terminateHandler{};
void TerminateHandler() {
auto exception{std::current_exception()};
if (terminateHandler && exception && exception == SignalExceptionPtr) {
struct StackFrame {
StackFrame *next;
void *lr;
} *frame;
asm("MOV %0, FP" : "=r"(frame));
frame = frame->next->next;
if (_Unwind_FindEnclosingFunction(frame->lr) == &ExceptionThrow) // We're in a loop, skip past a frame
frame = frame->next->next;
else if (_Unwind_FindEnclosingFunction(frame->next->next->next->next->next->lr) == &ExceptionThrow) // We're in a deeper loop, just terminate
frame = frame->next->next->next->next->next->next->next;
asm("MOV SP, %x0\n\t" // Stack frame is the first item on a function's stack, it's used to calculate calling function's stack pointer
"MOV LR, %x1\n\t"
"MOV FP, %x2\n\t" // The stack frame of the calling function should be set
"BR %x3"
: : "r"(frame + 1), "r"(frame->lr), "r"(frame->next), "r"(&ExceptionThrow));
__builtin_unreachable();
} else {
terminateHandler();
}
}
void ExceptionalSignalHandler(int signal, siginfo *info, ucontext *context) {
SignalException signalException;
signalException.signal = signal;
signalException.pc = context->uc_mcontext.pc;
if (signal == SIGSEGV)
signalException.faultAddress = info->si_addr;
SignalExceptionPtr = std::make_exception_ptr(signalException);
context->uc_mcontext.pc = reinterpret_cast<u64>(&ExceptionThrow);
auto handler{std::get_terminate()};
if (handler != TerminateHandler) {
terminateHandler = handler;
std::set_terminate(TerminateHandler);
}
}
template<typename Signature>
@ -47,48 +84,42 @@ namespace skyline::signal {
TlsRestorer = function;
}
std::array<void (*)(int, struct siginfo *, void *), NSIG> DefaultSignalHandlers;
struct DefaultSignalHandler {
void (*function)(int, struct siginfo *, void *){};
struct ThreadSignalHandler {
pthread_key_t key;
std::atomic<u32> count;
void Decrement();
static void DecrementStatic(ThreadSignalHandler *thiz) {
thiz->Decrement();
}
~DefaultSignalHandler();
};
std::array<ThreadSignalHandler, NSIG> ThreadSignalHandlers;
std::array<DefaultSignalHandler, NSIG> DefaultSignalHandlers;
void ThreadSignalHandler::Decrement() {
u32 current;
while ((current = count.load()) && !count.compare_exchange_strong(current, --current));
if (current == 0) {
int signal{static_cast<int>(this - ThreadSignalHandlers.data())};
DefaultSignalHandler::~DefaultSignalHandler() {
if (function) {
int signal{static_cast<int>(this - DefaultSignalHandlers.data())};
struct sigaction oldAction;
Sigaction(signal, nullptr, &oldAction);
struct sigaction action{
.sa_sigaction = DefaultSignalHandlers.at(signal),
.sa_sigaction = function,
.sa_flags = oldAction.sa_flags,
};
Sigaction(signal, &action);
}
}
thread_local std::array<SignalHandler, NSIG> ThreadSignalHandlers{};
__attribute__((no_stack_protector)) // Stack protector stores data in TLS at the function epilog and verifies it at the prolog, we cannot allow writes to guest TLS and may switch to an alternative TLS during the signal handler and have disabled the stack protector as a result
void ThreadSignalHandler(int signal, siginfo *info, ucontext *context) {
void *tls{}; // The TLS value prior to being restored if it is
if (TlsRestorer)
tls = TlsRestorer();
auto handler{reinterpret_cast<void (*)(int, struct siginfo *, ucontext *, void *)>(pthread_getspecific(ThreadSignalHandlers.at(signal).key))};
auto handler{ThreadSignalHandlers.at(signal)};
if (handler) {
handler(signal, info, context, tls);
handler(signal, info, context, &tls);
} else {
auto defaultHandler{DefaultSignalHandlers.at(signal)};
auto defaultHandler{DefaultSignalHandlers.at(signal).function};
if (defaultHandler)
defaultHandler(signal, info, context);
}
@ -97,7 +128,7 @@ namespace skyline::signal {
asm volatile("MSR TPIDR_EL0, %x0"::"r"(tls));
}
void SetSignalHandler(std::initializer_list<int> signals, void (*function)(int, struct siginfo *, ucontext *, void *)) {
void SetSignalHandler(std::initializer_list<int> signals, SignalHandler function) {
static std::array<std::once_flag, NSIG> signalHandlerOnce{};
stack_t stack;
@ -108,21 +139,15 @@ namespace skyline::signal {
};
for (int signal : signals) {
auto &threadHandler{ThreadSignalHandlers.at(signal)};
std::call_once(signalHandlerOnce[signal], [signal, action, &threadHandler]() {
if (int result = pthread_key_create(&threadHandler.key, reinterpret_cast<void (*)(void *)>(&ThreadSignalHandler::DecrementStatic)))
throw exception("Failed to create per-thread signal handler pthread key: {}", strerror(result));
std::call_once(signalHandlerOnce[signal], [signal, action]() {
struct sigaction oldAction;
Sigaction(signal, &action, &oldAction);
if (oldAction.sa_flags && oldAction.sa_flags != action.sa_flags)
throw exception("Old sigaction flags aren't equivalent to the replaced signal: {:#b} | {:#b}", oldAction.sa_flags, action.sa_flags);
DefaultSignalHandlers.at(signal) = oldAction.sa_sigaction;
DefaultSignalHandlers.at(signal).function = (oldAction.sa_flags & SA_SIGINFO) ? oldAction.sa_sigaction : reinterpret_cast<void (*)(int, struct siginfo *, void *)>(oldAction.sa_handler);
});
if (!pthread_getspecific(ThreadSignalHandlers.at(signal).key))
threadHandler.count++;
pthread_setspecific(ThreadSignalHandlers.at(signal).key, reinterpret_cast<void *>(function));
ThreadSignalHandlers.at(signal) = function;
}
}

View File

@ -27,6 +27,7 @@ namespace skyline::signal {
/**
* @brief A signal handler which automatically throws an exception with the corresponding signal metadata in a SignalException
* @note A termination handler is set in this which prevents any termination from going through as to break out of 'noexcept', do not use std::terminate in a catch clause for this exception
*/
void ExceptionalSignalHandler(int signal, siginfo *, ucontext *context);
@ -42,14 +43,17 @@ namespace skyline::signal {
*/
void SetTlsRestorer(void *(*function)());
using SignalHandler = void (*)(int, struct siginfo *, ucontext *, void **);
/**
* @brief A wrapper around Sigaction to make it easy to set a sigaction signal handler for multiple signals and also allow for thread-local signal handlers
* @param function A sa_action callback with the old TLS (If present) as the 4th argument
* @param function A sa_action callback with a pointer to the old TLS (If present) as the 4th argument
* @note If 'nullptr' is written into the 4th argument then the old TLS won't be restored or it'll be set to any non-null value written into it
*/
void SetSignalHandler(std::initializer_list<int> signals, void (*function)(int, struct siginfo *, ucontext *, void *));
void SetSignalHandler(std::initializer_list<int> signals, SignalHandler function);
inline void SetSignalHandler(std::initializer_list<int> signals, void (*function)(int, struct siginfo *, ucontext *)) {
SetSignalHandler(signals, reinterpret_cast<void (*)(int, struct siginfo *, ucontext *, void *)>(function));
SetSignalHandler(signals, reinterpret_cast<SignalHandler>(function));
}
/**

View File

@ -101,11 +101,11 @@ namespace skyline::gpu::gpfifo {
if (e.signal != SIGINT) {
state.logger->Write(Logger::LogLevel::Error, e.what());
signal::BlockSignal({SIGINT});
state.process->mainThread->Kill(false);
state.process->Kill(false);
}
} catch (const std::exception &e) {
state.logger->Write(Logger::LogLevel::Error, e.what());
state.process->mainThread->Kill(false);
state.process->Kill(false);
}
}

View File

@ -217,7 +217,7 @@ namespace skyline::kernel::svc {
void ExitProcess(const DeviceState &state) {
state.logger->Debug("svcExitProcess: Exiting process");
if (state.thread->id)
state.process->mainThread->Kill(false);
state.process->Kill(false);
std::longjmp(state.thread->originalCtx, true);
}
@ -250,10 +250,15 @@ namespace skyline::kernel::svc {
throw exception("svcCreateThread: Cannot find memory object in handle table for thread stack: 0x{:X}", stackTop);
auto thread{state.process->CreateThread(entry, entryArgument, stackTop, priority, idealCore)};
state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, ID: {})", thread->handle, entry, entryArgument, stackTop, priority, thread->id);
if (thread) {
state.logger->Debug("svcCreateThread: Created thread with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, ID: {})", thread->handle, entry, entryArgument, stackTop, priority, thread->id);
state.ctx->gpr.w1 = thread->handle;
state.ctx->gpr.w0 = Result{};
state.ctx->gpr.w1 = thread->handle;
state.ctx->gpr.w0 = Result{};
} else {
state.ctx->gpr.w1 = 0;
state.ctx->gpr.w0 = result::OutOfResource;
}
}
void StartThread(const DeviceState &state) {
@ -509,7 +514,8 @@ namespace skyline::kernel::svc {
span waitHandles(reinterpret_cast<KHandle *>(state.ctx->gpr.x1), numHandles);
for (const auto &handle : waitHandles) {
handleStr += fmt::format("* 0x{:X}\n", handle);
if (Logger::LogLevel::Debug <= state.logger->configLevel)
handleStr += fmt::format("* 0x{:X}\n", handle);
auto object{state.process->GetHandle(handle)};
switch (object->objectType) {

View File

@ -30,6 +30,31 @@ namespace skyline::kernel::type {
KProcess::KProcess(const DeviceState &state) : memory(state), KSyncObject(state, KType::KProcess) {}
KProcess::~KProcess() {
std::lock_guard guard(threadMutex);
disableThreadCreation = true;
for (const auto &thread : threads)
thread->Kill(true);
}
void KProcess::Kill(bool join, bool all, bool disableCreation) {
std::lock_guard guard(threadMutex);
if (disableCreation)
disableThreadCreation = true;
if (all) {
for (const auto &thread : threads)
thread->Kill(join);
} else {
std::shared_ptr<KThread> thread;
try {
thread = threads.at(0);
} catch (const std::out_of_range &) {
return;
}
thread->Kill(join);
}
}
void KProcess::InitializeHeap() {
constexpr size_t DefaultHeapSize{0x200000};
heap = heap.make_shared(state, reinterpret_cast<u8 *>(state.process->memory.heap.address), DefaultHeapSize, memory::Permission{true, true, false}, memory::states::Heap);
@ -50,15 +75,17 @@ namespace skyline::kernel::type {
}
std::shared_ptr<KThread> KProcess::CreateThread(void *entry, u64 argument, void *stackTop, i8 priority, i8 idealCore) {
if (!stackTop && !mainThread) { //!< Main thread stack is created by the kernel and owned by the process
std::lock_guard guard(threadMutex);
if (disableThreadCreation)
return nullptr;
if (!stackTop && threads.empty()) { //!< Main thread stack is created by the kernel and owned by the process
mainThreadStack = mainThreadStack.make_shared(state, reinterpret_cast<u8 *>(state.process->memory.stack.address), state.process->npdm.meta.mainThreadStackSize, memory::Permission{true, true, false}, memory::states::Stack);
if (mprotect(mainThreadStack->ptr, PAGE_SIZE, PROT_NONE))
throw exception("Failed to create guard page for thread stack at 0x{:X}", mainThreadStack->ptr);
stackTop = mainThreadStack->ptr + mainThreadStack->size;
}
auto thread{NewHandle<KThread>(this, threadIndex++, entry, argument, stackTop, (priority == -1) ? state.process->npdm.meta.mainThreadPriority : priority, (idealCore == -1) ? state.process->npdm.meta.idealCore : idealCore).item};
if (!mainThread)
mainThread = thread;
auto thread{NewHandle<KThread>(this, threads.size(), entry, argument, stackTop, (priority == -1) ? state.process->npdm.meta.mainThreadPriority : priority, (idealCore == -1) ? state.process->npdm.meta.idealCore : idealCore).item};
threads.push_back(thread);
return thread;
}

View File

@ -44,7 +44,9 @@ namespace skyline {
std::mutex mutexLock;
std::mutex conditionalLock;
size_t threadIndex{}; //!< The ID assigned to the next created thread
std::mutex threadMutex; //!< Synchronizes thread creation to prevent a race between thread creation and thread killing
bool disableThreadCreation{}; //!< If to disable thread creation, we use this to prevent thread creation after all threads have been killed
std::vector<std::shared_ptr<KThread>> threads;
/**
* @brief The status of a single TLS page (A page is 4096 bytes on ARMv8)
@ -69,7 +71,6 @@ namespace skyline {
std::shared_ptr<KPrivateMemory> mainThreadStack;
std::shared_ptr<KPrivateMemory> heap;
std::vector<std::shared_ptr<TlsPage>> tlsPages;
std::shared_ptr<KThread> mainThread;
vfs::NPDM npdm;
private:
@ -79,6 +80,18 @@ namespace skyline {
public:
KProcess(const DeviceState &state);
~KProcess();
/**
* @brief Kill the main thread/all running threads in the process in a graceful manner
* @param join Return after the main thread has joined rather than instantly
* @param all If to kill all running threads or just the main thread
* @param disableCreation If to disable further thread creation
* @note If there are no threads then this will silently return
* @note The main thread should eventually kill the rest of the threads itself
*/
void Kill(bool join, bool all = false, bool disableCreation = false);
/**
* @note This requires VMM regions to be initialized, it will map heap at an arbitrary location otherwise
*/
@ -90,6 +103,7 @@ namespace skyline {
u8 *AllocateTlsSlot();
/**
* @return A shared pointer to a KThread initialized with the specified values or nullptr, if thread creation has been disabled
* @note The default values are for the main thread and will use values from the NPDM
*/
std::shared_ptr<KThread> CreateThread(void *entry, u64 argument = 0, void *stackTop = nullptr, i8 priority = -1, i8 idealCore = -1);
@ -144,20 +158,24 @@ namespace skyline {
if (handle == threadSelf)
return state.thread;
objectType = KType::KThread;
} else if constexpr(std::is_same<objectClass, KProcess>())
} else if constexpr(std::is_same<objectClass, KProcess>()) {
constexpr KHandle processSelf{0xFFFF8001}; // The handle used by threads in a process to refer to the process
if (handle == processSelf)
return state.process;
objectType = KType::KProcess;
else if constexpr(std::is_same<objectClass, KSharedMemory>())
} else if constexpr(std::is_same<objectClass, KSharedMemory>()) {
objectType = KType::KSharedMemory;
else if constexpr(std::is_same<objectClass, KTransferMemory>())
} else if constexpr(std::is_same<objectClass, KTransferMemory>()) {
objectType = KType::KTransferMemory;
else if constexpr(std::is_same<objectClass, KPrivateMemory>())
} else if constexpr(std::is_same<objectClass, KPrivateMemory>()) {
objectType = KType::KPrivateMemory;
else if constexpr(std::is_same<objectClass, KSession>())
} else if constexpr(std::is_same<objectClass, KSession>()) {
objectType = KType::KSession;
else if constexpr(std::is_same<objectClass, KEvent>())
} else if constexpr(std::is_same<objectClass, KEvent>()) {
objectType = KType::KEvent;
else
} else {
throw exception("KProcess::GetHandle couldn't determine object type");
}
try {
auto &item{handles.at(handle - constant::BaseHandleIndex)};
if (item != nullptr && item->objectType == objectType)
@ -166,7 +184,7 @@ namespace skyline {
throw exception("GetHandle was called with a deleted handle: 0x{:X}", handle);
else
throw exception("Tried to get kernel object (0x{:X}) with different type: {} when object is {}", handle, objectType, item->objectType);
} catch (std::out_of_range) {
} catch (const std::out_of_range&) {
throw std::out_of_range(fmt::format("GetHandle was called with an invalid handle: 0x{:X}", handle));
}
}

View File

@ -15,13 +15,14 @@ namespace skyline::kernel::type {
}
KThread::~KThread() {
std::unique_lock lock(mutex);
if (running && pthread != pthread_self()) {
pthread_kill(pthread, SIGINT);
if (thread)
thread->join();
else
if (!thread.joinable())
pthread_join(pthread, nullptr);
}
if (thread.joinable())
thread.join();
}
void KThread::StartThread() {
@ -41,8 +42,10 @@ namespace skyline::kernel::type {
running = false;
Signal();
pthread_setname_np(pthread, threadName.data());
state.logger->UpdateTag();
if (threadName[0] != 'H' || threadName[1] != 'O' || threadName[2] != 'S' || threadName[3] != '-') {
pthread_setname_np(pthread, threadName.data());
state.logger->UpdateTag();
}
return;
}
@ -140,8 +143,8 @@ namespace skyline::kernel::type {
lock.unlock();
StartThread();
} else {
thread.emplace(&KThread::StartThread, this);
pthread = thread->native_handle();
thread = std::thread(&KThread::StartThread, this);
pthread = thread.native_handle();
}
}
}
@ -150,8 +153,12 @@ namespace skyline::kernel::type {
std::lock_guard lock(mutex);
if (running) {
pthread_kill(pthread, SIGINT);
if (join)
pthread_join(pthread, nullptr);
if (join) {
if (thread.joinable())
thread.join();
else
pthread_join(pthread, nullptr);
}
running = false;
}
}

View File

@ -46,7 +46,7 @@ namespace skyline {
class KThread : public KSyncObject, public std::enable_shared_from_this<KThread> {
private:
KProcess *parent;
std::optional<std::thread> thread; //!< If this KThread is backed by a host thread then this'll hold it
std::thread thread; //!< If this KThread is backed by a host thread then this'll hold it
pthread_t pthread{}; //!< The pthread_t for the host thread running this guest thread
void StartThread();
@ -83,7 +83,7 @@ namespace skyline {
void Start(bool self = false);
/**
* @param join Returns after the guest thread has joined rather than instantly
* @param join Return after the thread has joined rather than instantly
*/
void Kill(bool join);

View File

@ -1,6 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include <cxxabi.h>
#include <unistd.h>
#include "common/signal.h"
#include "os.h"
@ -28,62 +29,72 @@ namespace skyline::nce {
state.logger->Error("{} (SVC: 0x{:X})", e.what(), svc);
if (state.thread->id) {
signal::BlockSignal({SIGINT});
state.process->mainThread->Kill(false);
state.process->Kill(false);
}
}
abi::__cxa_end_catch(); // We call this prior to the longjmp to cause the exception object to be destroyed
std::longjmp(state.thread->originalCtx, true);
} catch (const std::exception &e) {
state.logger->Error("{} (SVC: 0x{:X})", e.what(), svc);
if (state.thread->id) {
signal::BlockSignal({SIGINT});
state.process->mainThread->Kill(false);
state.process->Kill(false);
}
abi::__cxa_end_catch();
std::longjmp(state.thread->originalCtx, true);
}
}
void NCE::SignalHandler(int signal, siginfo *info, ucontext *context, void *oldTls) {
if (oldTls) {
const auto &state{*reinterpret_cast<ThreadContext *>(oldTls)->state};
void NCE::SignalHandler(int signal, siginfo *info, ucontext *context, void **tls) {
if (*tls) {
const auto &state{*reinterpret_cast<ThreadContext *>(*tls)->state};
if (signal != SIGINT) {
state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal));
state.logger->Warn("Thread #{} has crashed due to signal: {}", state.thread->id, strsignal(signal));
std::string raw;
std::string trace;
std::string cpuContext;
std::string raw;
std::string trace;
std::string cpuContext;
const auto &ctx{reinterpret_cast<ucontext *>(context)->uc_mcontext};
constexpr u16 instructionCount{20}; // The amount of previous instructions to print
auto offset{ctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))};
span instructions(reinterpret_cast<u32 *>(offset), instructionCount);
if (mprotect(instructions.data(), instructions.size_bytes(), PROT_READ | PROT_WRITE | PROT_EXEC) == 0) {
for (auto &instruction : instructions) {
instruction = __builtin_bswap32(instruction);
const auto &ctx{reinterpret_cast<ucontext *>(context)->uc_mcontext};
constexpr u16 instructionCount{20}; // The amount of previous instructions to print
auto offset{ctx.pc - (instructionCount * sizeof(u32)) + (2 * sizeof(u32))};
span instructions(reinterpret_cast<u32 *>(offset), instructionCount);
for (auto &instruction : instructions) {
instruction = __builtin_bswap32(instruction);
if (offset == ctx.pc)
trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instruction);
else
trace += fmt::format("\n 0x{:X} : 0x{:08X}", offset, instruction);
if (offset == ctx.pc)
trace += fmt::format("\n-> 0x{:X} : 0x{:08X}", offset, instruction);
else
trace += fmt::format("\n 0x{:X} : 0x{:08X}", offset, instruction);
raw += fmt::format("{:08X}", instruction);
offset += sizeof(u32);
}
raw += fmt::format("{:08X}", instruction);
offset += sizeof(u32);
state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw);
} else {
cpuContext += fmt::format("\nPC: 0x{:X}", ctx.pc);
}
if (ctx.fault_address)
cpuContext += fmt::format("\nFault Address: 0x{:X}", ctx.fault_address);
if (ctx.sp)
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp);
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2)
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? ' ' : '\0', index + 1, ctx.regs[index]);
state.logger->Debug("CPU Context:{}", cpuContext);
}
if (ctx.fault_address)
cpuContext += fmt::format("\nFault Address: 0x{:X}", ctx.fault_address);
if (ctx.sp)
cpuContext += fmt::format("\nStack Pointer: 0x{:X}", ctx.sp);
for (u8 index{}; index < ((sizeof(mcontext_t::regs) / sizeof(u64)) - 2); index += 2)
cpuContext += fmt::format("\n{}X{}: 0x{:<16X} {}{}: 0x{:X}", index < 10 ? ' ' : '\0', index, ctx.regs[index], index < 10 ? ' ' : '\0', index + 1, ctx.regs[index]);
state.logger->Debug("Process Trace:{}", trace);
state.logger->Debug("Raw Instructions: 0x{}", raw);
state.logger->Debug("CPU Context:{}", cpuContext);
context->uc_mcontext.pc = reinterpret_cast<skyline::u64>(&std::longjmp);
context->uc_mcontext.regs[0] = reinterpret_cast<u64>(state.thread->originalCtx);
context->uc_mcontext.regs[1] = true;
*tls = nullptr;
} else {
signal::ExceptionalSignalHandler(signal, info, context); //!< Delegate throwing a host exception to the exceptional signal handler
}

View File

@ -17,7 +17,7 @@ namespace skyline::nce {
static void SvcHandler(u16 svc, ThreadContext *ctx);
public:
static void SignalHandler(int signal, siginfo *info, ucontext *context, void *oldTls);
static void SignalHandler(int signal, siginfo *info, ucontext *context, void **tls);
NCE(const DeviceState &state);

View File

@ -33,6 +33,10 @@ namespace skyline::kernel {
process = std::make_shared<kernel::type::KProcess>(state);
auto entry{state.loader->LoadProcessData(process, state)};
process->InitializeHeap();
process->CreateThread(entry)->Start(true);
auto thread{process->CreateThread(entry)};
if (thread) {
thread->Start(true);
process->Kill(true, true, true);
}
}
}

View File

@ -62,7 +62,7 @@ namespace skyline::service::audio {
Result IAudioOut::GetReleasedAudioOutBuffer(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response) {
auto maxCount{static_cast<u32>(request.outputBuf.at(0).size() >> 3)};
std::vector<u64> releasedBuffers{track->GetReleasedBuffers(maxCount)};
auto releasedBuffers{track->GetReleasedBuffers(maxCount)};
auto count{static_cast<u32>(releasedBuffers.size())};
// Fill rest of output buffer with zeros

View File

@ -67,6 +67,7 @@ namespace skyline::service::fssrv {
/**
* @brief Returns a handle to an instance of #IFileSystem
* @url https://switchbrew.org/wiki/Filesystem_services#IFileSystem for the requested save data area
* @url https://switchbrew.org/wiki/Filesystem_services#OpenSaveDataFileSystem
*/
Result OpenSaveDataFileSystem(type::KSession &session, ipc::IpcRequest &request, ipc::IpcResponse &response);

View File

@ -114,7 +114,7 @@ namespace skyline::service::nvdrv::device {
auto &event{*events.at(userEventId)};
if (event.state == NvHostEvent::State::Cancelled || event.state == NvHostEvent::State::Available || event.state == NvHostEvent::State::Signaled) {
state.logger->Debug("Now waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id);
state.logger->Debug("Waiting on nvhost event: {} with fence: {}", userEventId, data.fence.id);
event.Wait(state.gpu, data.fence);
data.value.val = 0;
@ -139,7 +139,7 @@ namespace skyline::service::nvdrv::device {
}
NvStatus NvHostCtrl::EventSignal(IoctlType type, span<u8> buffer, span<u8> inlineBuffer) {
auto userEventId{buffer.as<u32>()};
auto userEventId{buffer.as<u16>()};
state.logger->Debug("Signalling nvhost event: {}", userEventId);
if (userEventId >= constant::NvHostEventCount || !events.at(userEventId))