From 1fce6de8b182ba0418acb4ab24e3b7eba2b63850 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 11 Feb 2019 11:11:56 +0100 Subject: [PATCH] Simple exception handler so we can ignore accesses that happen within the PSP memory space. --- CMakeLists.txt | 2 + Common/Common.vcxproj | 5 +- Common/Common.vcxproj.filters | 5 +- Common/ExceptionHandlerSetup.cpp | 316 ++++++++++++++++++++++++ Common/ExceptionHandlerSetup.h | 17 ++ Common/MachineContext.h | 243 ++++++++++++++++++ Core/MemMap.cpp | 31 +++ Core/MemMap.h | 4 + Core/System.cpp | 6 +- UWP/CommonUWP/CommonUWP.vcxproj | 2 + UWP/CommonUWP/CommonUWP.vcxproj.filters | 2 + android/jni/Android.mk | 1 + libretro/Makefile.common | 1 + 13 files changed, 632 insertions(+), 3 deletions(-) create mode 100644 Common/ExceptionHandlerSetup.cpp create mode 100644 Common/ExceptionHandlerSetup.h create mode 100644 Common/MachineContext.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ee98014740..9146253dc4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -428,6 +428,8 @@ add_library(Common STATIC Common/Crypto/sha1.h Common/Crypto/sha256.cpp Common/Crypto/sha256.h + Common/ExceptionHandlerSetup.cpp + Common/ExceptionHandlerSetup.h Common/FileUtil.cpp Common/FileUtil.h Common/KeyMap.cpp diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index 80278606df..6486c530e7 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -368,6 +368,7 @@ + @@ -397,6 +398,7 @@ + @@ -449,6 +451,7 @@ + true @@ -521,4 +524,4 @@ - \ No newline at end of file + diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index ebe7f50688..c49d67d6af 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -74,6 +74,8 @@ Vulkan + + @@ -137,6 +139,7 @@ Vulkan + @@ -152,4 +155,4 @@ {c14d66ef-5f7c-4565-975a-72774e7ccfb9} - \ No newline at end of file + diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp new file mode 100644 index 0000000000..098b603209 --- /dev/null +++ b/Common/ExceptionHandlerSetup.cpp @@ -0,0 +1,316 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Common/ExceptionHandlerSetup.h" + +#include +#include +#include +#include + +#include "Common/CommonFuncs.h" +#include "Common/CommonTypes.h" +#include "Common/MsgHandler.h" +#include "Common/Log.h" + +#if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) +#include "Common/MachineContext.h" +#endif + +#ifdef __FreeBSD__ +#include +#endif +#ifndef _WIN32 +#include // Needed for _POSIX_VERSION +#endif + +static BadAccessHandler g_badAccessHandler; + +#ifdef _WIN32 + +static PVOID g_vectoredExceptionHandle; + +static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) { + switch (pPtrs->ExceptionRecord->ExceptionCode) { + case EXCEPTION_ACCESS_VIOLATION: + { + int accessType = (int)pPtrs->ExceptionRecord->ExceptionInformation[0]; + if (accessType == 8) { // Rule out DEP + return (DWORD)EXCEPTION_CONTINUE_SEARCH; + } + + // virtual address of the inaccessible data + uintptr_t badAddress = (uintptr_t)pPtrs->ExceptionRecord->ExceptionInformation[1]; + CONTEXT* ctx = pPtrs->ContextRecord; + + if (g_badAccessHandler(badAddress, ctx)) { + return (DWORD)EXCEPTION_CONTINUE_EXECUTION; + } else { + // Let's not prevent debugging. + return (DWORD)EXCEPTION_CONTINUE_SEARCH; + } + } + + case EXCEPTION_STACK_OVERFLOW: + // Dolphin has some handling of this for the RET optimization emulation. + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_ILLEGAL_INSTRUCTION: + // No SSE support? Or simply bad codegen? + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_PRIV_INSTRUCTION: + // okay, dynarec codegen is obviously broken. + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_IN_PAGE_ERROR: + // okay, something went seriously wrong, out of memory? + return EXCEPTION_CONTINUE_SEARCH; + + case EXCEPTION_BREAKPOINT: + // might want to do something fun with this one day? + return EXCEPTION_CONTINUE_SEARCH; + + default: + return EXCEPTION_CONTINUE_SEARCH; + } +} + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + // Make sure this is only called once per process execution + // Instead, could make a Uninstall function, but whatever.. + if (g_badAccessHandler) { + return; + } + + g_badAccessHandler = badAccessHandler; + g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, Handler); +} + +void UninstallExceptionHandler() { + RemoveVectoredExceptionHandler(g_vectoredExceptionHandle); +} + +#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE) + +static void CheckKR(const char* name, kern_return_t kr) { + if (kr) { + PanicAlert("%s failed: kr=%x", name, kr); + } +} + +static void ExceptionThread(mach_port_t port) { + Common::SetCurrentThreadName("Mach exception thread"); +#pragma pack(4) + struct { + mach_msg_header_t Head; + NDR_record_t NDR; + exception_type_t exception; + mach_msg_type_number_t codeCnt; + int64_t code[2]; + int flavor; + mach_msg_type_number_t old_stateCnt; + natural_t old_state[x86_THREAD_STATE64_COUNT]; + mach_msg_trailer_t trailer; + } msg_in; + + struct { + mach_msg_header_t Head; + NDR_record_t NDR; + kern_return_t RetCode; + int flavor; + mach_msg_type_number_t new_stateCnt; + natural_t new_state[x86_THREAD_STATE64_COUNT]; + } msg_out; +#pragma pack() + memset(&msg_in, 0xee, sizeof(msg_in)); + memset(&msg_out, 0xee, sizeof(msg_out)); + mach_msg_header_t* send_msg = nullptr; + mach_msg_size_t send_size = 0; + mach_msg_option_t option = MACH_RCV_MSG; + while (true) { + // If this isn't the first run, send the reply message. Then, receive + // a message: either a mach_exception_raise_state RPC due to + // thread_set_exception_ports, or MACH_NOTIFY_NO_SENDERS due to + // mach_port_request_notification. + CheckKR("mach_msg_overwrite", + mach_msg_overwrite(send_msg, option, send_size, sizeof(msg_in), port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL, &msg_in.Head, 0)); + + if (msg_in.Head.msgh_id == MACH_NOTIFY_NO_SENDERS) { + // the other thread exited + mach_port_destroy(mach_task_self(), port); + return; + } + + if (msg_in.Head.msgh_id != 2406) { + PanicAlert("unknown message received"); + return; + } + + if (msg_in.flavor != x86_THREAD_STATE64) { + PanicAlert("unknown flavor %d (expected %d)", msg_in.flavor, x86_THREAD_STATE64); + return; + } + + x86_thread_state64_t* state = (x86_thread_state64_t*)msg_in.old_state; + + bool ok = g_badAccessHandler((uintptr_t)msg_in.code[1], state); + + // Set up the reply. + msg_out.Head.msgh_bits = MACH_MSGH_BITS(MACH_MSGH_BITS_REMOTE(msg_in.Head.msgh_bits), 0); + msg_out.Head.msgh_remote_port = msg_in.Head.msgh_remote_port; + msg_out.Head.msgh_local_port = MACH_PORT_NULL; + msg_out.Head.msgh_id = msg_in.Head.msgh_id + 100; + msg_out.NDR = msg_in.NDR; + if (ok) { + msg_out.RetCode = KERN_SUCCESS; + msg_out.flavor = x86_THREAD_STATE64; + msg_out.new_stateCnt = x86_THREAD_STATE64_COUNT; + memcpy(msg_out.new_state, msg_in.old_state, x86_THREAD_STATE64_COUNT * sizeof(natural_t)); + } else { + // Pass the exception to the next handler (debugger or crash). + msg_out.RetCode = KERN_FAILURE; + msg_out.flavor = 0; + msg_out.new_stateCnt = 0; + } + msg_out.Head.msgh_size = + offsetof(__typeof__(msg_out), new_state) + msg_out.new_stateCnt * sizeof(natural_t); + + send_msg = &msg_out.Head; + send_size = msg_out.Head.msgh_size; + option |= MACH_SEND_MSG; + } +} + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + g_badAccessHandler = badAccessHandler; + mach_port_t port; + CheckKR("mach_port_allocate", + mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); + std::thread exc_thread(ExceptionThread, port); + exc_thread.detach(); + // Obtain a send right for thread_set_exception_ports to copy... + CheckKR("mach_port_insert_right", + mach_port_insert_right(mach_task_self(), port, port, MACH_MSG_TYPE_MAKE_SEND)); + // Mach tries the following exception ports in order: thread, task, host. + // Debuggers set the task port, so we grab the thread port. + CheckKR("thread_set_exception_ports", + thread_set_exception_ports(mach_thread_self(), EXC_MASK_BAD_ACCESS, port, + EXCEPTION_STATE | MACH_EXCEPTION_CODES, x86_THREAD_STATE64)); + // ...and get rid of our copy so that MACH_NOTIFY_NO_SENDERS works. + CheckKR("mach_port_mod_refs", + mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, -1)); + mach_port_t previous; + CheckKR("mach_port_request_notification", + mach_port_request_notification(mach_task_self(), port, MACH_NOTIFY_NO_SENDERS, 0, port, + MACH_MSG_TYPE_MAKE_SEND_ONCE, &previous)); +} + +void UninstallExceptionHandler() { +} + +#elif defined(_POSIX_VERSION) && !defined(_M_GENERIC) + +static struct sigaction old_sa_segv; +static struct sigaction old_sa_bus; + +static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { + if (sig != SIGSEGV && sig != SIGBUS) { + // We are not interested in other signals - handle it as usual. + return; + } + ucontext_t* context = (ucontext_t*)raw_context; + int sicode = info->si_code; + if (sicode != SEGV_MAPERR && sicode != SEGV_ACCERR) { + // Huh? Return. + return; + } + uintptr_t bad_address = (uintptr_t)info->si_addr; + + // Get all the information we can out of the context. +#ifdef __OpenBSD__ + ucontext_t* ctx = context; +#else + mcontext_t* ctx = &context->uc_mcontext; +#endif + // assume it's not a write + if (!g_badAccessHandler(bad_address, +#ifdef __APPLE__ + *ctx +#else + ctx +#endif + )) { + // retry and crash + // According to the sigaction man page, if sa_flags "SA_SIGINFO" is set to the sigaction + // function pointer, otherwise sa_handler contains one of: + // SIG_DEF: The 'default' action is performed + // SIG_IGN: The signal is ignored + // Any other value is a function pointer to a signal handler + + struct sigaction* old_sa; + if (sig == SIGSEGV) { + old_sa = &old_sa_segv; + } else { + old_sa = &old_sa_bus; + } + + if (old_sa->sa_flags & SA_SIGINFO) { + old_sa->sa_sigaction(sig, info, raw_context); + return; + } + if (old_sa->sa_handler == SIG_DFL) { + signal(sig, SIG_DFL); + return; + } + if (old_sa->sa_handler == SIG_IGN) { + // Ignore signal + return; + } + old_sa->sa_handler(sig); + } +} + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + g_badAccessHandler = badAccessHandler; + + stack_t signal_stack; +#ifdef __FreeBSD__ + signal_stack.ss_sp = (char*)malloc(SIGSTKSZ); +#else + signal_stack.ss_sp = malloc(SIGSTKSZ); +#endif + signal_stack.ss_size = SIGSTKSZ; + signal_stack.ss_flags = 0; + if (sigaltstack(&signal_stack, nullptr)) + PanicAlert("sigaltstack failed"); + struct sigaction sa; + sa.sa_handler = nullptr; + sa.sa_sigaction = &sigsegv_handler; + sa.sa_flags = SA_SIGINFO; + sigemptyset(&sa.sa_mask); + sigaction(SIGSEGV, &sa, &old_sa_segv); +#ifdef __APPLE__ + sigaction(SIGBUS, &sa, &old_sa_bus); +#endif +} + +void UninstallExceptionHandler() { + stack_t signal_stack, old_stack; + signal_stack.ss_flags = SS_DISABLE; + if (!sigaltstack(&signal_stack, &old_stack) && !(old_stack.ss_flags & SS_DISABLE)) { + free(old_stack.ss_sp); + } + sigaction(SIGSEGV, &old_sa_segv, nullptr); +#ifdef __APPLE__ + sigaction(SIGBUS, &old_sa_bus, nullptr); +#endif +} +#else // _M_GENERIC or unsupported platform + +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { } +void UninstallExceptionHandler() { } + +#endif diff --git a/Common/ExceptionHandlerSetup.h b/Common/ExceptionHandlerSetup.h new file mode 100644 index 0000000000..8f88176e0e --- /dev/null +++ b/Common/ExceptionHandlerSetup.h @@ -0,0 +1,17 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include + +// On Windows, context is a CONTEXT object. +// On Apple, context is a x86_thread_state64_t. +// On Unix/Linux, context is a mcontext_t. +// On OpenBSD, context is a ucontext_t. +// Ugh, might need to abstract this better. +typedef bool (*BadAccessHandler)(uintptr_t address, void *context); + +void InstallExceptionHandler(BadAccessHandler accessHandler); +void UninstallExceptionHandler(); diff --git a/Common/MachineContext.h b/Common/MachineContext.h new file mode 100644 index 0000000000..643fac4858 --- /dev/null +++ b/Common/MachineContext.h @@ -0,0 +1,243 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "ppsspp_config.h" + +#if PPSSPP_PLATFORM(WINDOWS) +#include +typedef CONTEXT SContext; +#if PPSSPP_ARCH_AMD64 +#define CTX_RAX Rax +#define CTX_RBX Rbx +#define CTX_RCX Rcx +#define CTX_RDX Rdx +#define CTX_RDI Rdi +#define CTX_RSI Rsi +#define CTX_RBP Rbp +#define CTX_RSP Rsp +#define CTX_R8 R8 +#define CTX_R9 R9 +#define CTX_R10 R10 +#define CTX_R11 R11 +#define CTX_R12 R12 +#define CTX_R13 R13 +#define CTX_R14 R14 +#define CTX_R15 R15 +#define CTX_RIP Rip +#else +#define CTX_RAX Eax +#define CTX_RBX Ebx +#define CTX_RCX Ecx +#define CTX_RDX Edx +#define CTX_RDI Edi +#define CTX_RSI Esi +#define CTX_RBP Ebp +#define CTX_RSP Esp +#define CTX_RIP Eip + +#endif +#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE) +// for modules: +#define _XOPEN_SOURCE +#include + +#include +#include +#if _M_X86_64 +typedef x86_thread_state64_t SContext; +#define CTX_RAX __rax +#define CTX_RBX __rbx +#define CTX_RCX __rcx +#define CTX_RDX __rdx +#define CTX_RDI __rdi +#define CTX_RSI __rsi +#define CTX_RBP __rbp +#define CTX_RSP __rsp +#define CTX_R8 __r8 +#define CTX_R9 __r9 +#define CTX_R10 __r10 +#define CTX_R11 __r11 +#define CTX_R12 __r12 +#define CTX_R13 __r13 +#define CTX_R14 __r14 +#define CTX_R15 __r15 +#define CTX_RIP __rip +#else +#error No context definition for architecture +#endif +#elif defined(__APPLE__) +#include +typedef _STRUCT_MCONTEXT64 SContext; +#define CTX_RAX __ss.__rax +#define CTX_RBX __ss.__rbx +#define CTX_RCX __ss.__rcx +#define CTX_RDX __ss.__rdx +#define CTX_RDI __ss.__rdi +#define CTX_RSI __ss.__rsi +#define CTX_RBP __ss.__rbp +#define CTX_RSP __ss.__rsp +#define CTX_R8 __ss.__r8 +#define CTX_R9 __ss.__r9 +#define CTX_R10 __ss.__r10 +#define CTX_R11 __ss.__r11 +#define CTX_R12 __ss.__r12 +#define CTX_R13 __ss.__r13 +#define CTX_R14 __ss.__r14 +#define CTX_R15 __ss.__r15 +#define CTX_RIP __ss.__rip +#elif defined(__linux__) +#include + +#include +typedef mcontext_t SContext; + +#if _M_X86_64 +#define CTX_RAX gregs[REG_RAX] +#define CTX_RBX gregs[REG_RBX] +#define CTX_RCX gregs[REG_RCX] +#define CTX_RDX gregs[REG_RDX] +#define CTX_RDI gregs[REG_RDI] +#define CTX_RSI gregs[REG_RSI] +#define CTX_RBP gregs[REG_RBP] +#define CTX_RSP gregs[REG_RSP] +#define CTX_R8 gregs[REG_R8] +#define CTX_R9 gregs[REG_R9] +#define CTX_R10 gregs[REG_R10] +#define CTX_R11 gregs[REG_R11] +#define CTX_R12 gregs[REG_R12] +#define CTX_R13 gregs[REG_R13] +#define CTX_R14 gregs[REG_R14] +#define CTX_R15 gregs[REG_R15] +#define CTX_RIP gregs[REG_RIP] +#elif _M_ARM_64 +#define CTX_REG(x) regs[x] +#define CTX_SP sp +#define CTX_PC pc +#else +#error No context definition for architecture +#endif +#elif defined(__OpenBSD__) +#include +typedef ucontext_t SContext; +#if _M_X86_64 +#define CTX_RAX sc_rax +#define CTX_RBX sc_rbx +#define CTX_RCX sc_rcx +#define CTX_RDX sc_rdx +#define CTX_RDI sc_rdi +#define CTX_RSI sc_rsi +#define CTX_RBP sc_rbp +#define CTX_RSP sc_rsp +#define CTX_R8 sc_r8 +#define CTX_R9 sc_r9 +#define CTX_R10 sc_r10 +#define CTX_R11 sc_r11 +#define CTX_R12 sc_r12 +#define CTX_R13 sc_r13 +#define CTX_R14 sc_r14 +#define CTX_R15 sc_r15 +#define CTX_RIP sc_rip +#else +#error No context definition for architecture +#endif +#elif defined(__NetBSD__) +#include +typedef mcontext_t SContext; +#if _M_X86_64 +#define CTX_RAX __gregs[_REG_RAX] +#define CTX_RBX __gregs[_REG_RBX] +#define CTX_RCX __gregs[_REG_RCX] +#define CTX_RDX __gregs[_REG_RDX] +#define CTX_RDI __gregs[_REG_RDI] +#define CTX_RSI __gregs[_REG_RSI] +#define CTX_RBP __gregs[_REG_RBP] +#define CTX_RSP __gregs[_REG_RSP] +#define CTX_R8 __gregs[_REG_R8] +#define CTX_R9 __gregs[_REG_R9] +#define CTX_R10 __gregs[_REG_R10] +#define CTX_R11 __gregs[_REG_R11] +#define CTX_R12 __gregs[_REG_R12] +#define CTX_R13 __gregs[_REG_R13] +#define CTX_R14 __gregs[_REG_R14] +#define CTX_R15 __gregs[_REG_R15] +#define CTX_RIP __gregs[_REG_RIP] +#else +#error No context definition for architecture +#endif +#elif defined(__FreeBSD__) +#include +typedef mcontext_t SContext; +#if _M_X86_64 +#define CTX_RAX mc_rax +#define CTX_RBX mc_rbx +#define CTX_RCX mc_rcx +#define CTX_RDX mc_rdx +#define CTX_RDI mc_rdi +#define CTX_RSI mc_rsi +#define CTX_RBP mc_rbp +#define CTX_RSP mc_rsp +#define CTX_R8 mc_r8 +#define CTX_R9 mc_r9 +#define CTX_R10 mc_r10 +#define CTX_R11 mc_r11 +#define CTX_R12 mc_r12 +#define CTX_R13 mc_r13 +#define CTX_R14 mc_r14 +#define CTX_R15 mc_r15 +#define CTX_RIP mc_rip +#else +#error No context definition for architecture +#endif +#elif defined(__HAIKU__) +#include +typedef mcontext_t SContext; +#if _M_X86_64 +#define CTX_RAX rax +#define CTX_RBX rbx +#define CTX_RCX rcx +#define CTX_RDX rdx +#define CTX_RDI rdi +#define CTX_RSI rsi +#define CTX_RBP rbp +#define CTX_RSP rsp +#define CTX_R8 r8 +#define CTX_R9 r9 +#define CTX_R10 r10 +#define CTX_R11 r11 +#define CTX_R12 r12 +#define CTX_R13 r13 +#define CTX_R14 r14 +#define CTX_R15 r15 +#define CTX_RIP rip +#else +#error No context definition for machine +#endif +#else +#error No context definition for OS +#endif + +#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) +#include +#define CTX_PC CTX_RIP +static inline u64* ContextRN(SContext* ctx, int n) +{ +#if PPSSPP_ARCH_32BIT + static const u8 offsets[] = { + offsetof(SContext, CTX_RAX), offsetof(SContext, CTX_RCX), offsetof(SContext, CTX_RDX), + offsetof(SContext, CTX_RBX), offsetof(SContext, CTX_RSP), offsetof(SContext, CTX_RBP), + offsetof(SContext, CTX_RSI), offsetof(SContext, CTX_RDI)}; +#else + static const u8 offsets[] = { + offsetof(SContext, CTX_RAX), offsetof(SContext, CTX_RCX), offsetof(SContext, CTX_RDX), + offsetof(SContext, CTX_RBX), offsetof(SContext, CTX_RSP), offsetof(SContext, CTX_RBP), + offsetof(SContext, CTX_RSI), offsetof(SContext, CTX_RDI), offsetof(SContext, CTX_R8), + offsetof(SContext, CTX_R9), offsetof(SContext, CTX_R10), offsetof(SContext, CTX_R11), + offsetof(SContext, CTX_R12), offsetof(SContext, CTX_R13), offsetof(SContext, CTX_R14), + offsetof(SContext, CTX_R15)}; +#endif + return (u64*)((char*)ctx + offsets[n]); +} +#endif diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 9c7a2cce19..93d2029da2 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -28,6 +28,7 @@ #include "Common/MemoryUtil.h" #include "Common/MemArena.h" #include "Common/ChunkFile.h" +#include "Common/MachineContext.h" #include "Core/MemMap.h" #include "Core/HDRemaster.h" @@ -457,4 +458,34 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) { CBreakPoints::ExecMemCheck(_Address, true, _iLength, currentMIPS->pc); } +bool HandleFault(uintptr_t hostAddress, void *ctx) { + SContext *context = (SContext *)ctx; + const uint8_t *codePtr = (uint8_t *)(context->CTX_PC); + + // TODO: Check that codePtr is within the current JIT space. + // bool inJitSpace = MIPSComp::jit->IsInSpace(codePtr); + // if (!inJitSpace) return false; + + // TODO: Disassemble at codePtr to figure out if it's a read or a write. + + uintptr_t baseAddress = (uintptr_t)base; + +#ifdef MASKED_PSP_MEMORY + const uintptr_t addressSpaceSize = 0x100000000ULL; +#else + const uintptr_t addressSpaceSize = 0x40000000ULL; +#endif + + // Check whether hostAddress is within the PSP memory space, which (likely) means it was a game that did the bad access. + if (hostAddress >= baseAddress && hostAddress <= baseAddress + addressSpaceSize) { + uint32_t guestAddress = hostAddress - baseAddress; + // Maybe we should also somehow check whether the JIT is on the stack. + ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, hostAddress); + return true; + } + + // A regular crash of some sort. Pass it on. + return false; +} + } // namespace diff --git a/Core/MemMap.h b/Core/MemMap.h index 4f598961f3..a7849a6fb7 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -147,6 +147,10 @@ Opcode Read_Opcode_JIT(const u32 _Address); // used by JIT. Reads in the "Locked cache" mode void Write_Opcode_JIT(const u32 _Address, const Opcode& _Value); +// Called by exception handlers. We simply filter out accesses to PSP RAM and otherwise +// just leave it as-is. +bool HandleFault(uintptr_t hostAddress, void *context); + // Should be used by analyzers, disassemblers etc. Does resolve replacements. Opcode Read_Instruction(const u32 _Address, bool resolveReplacements = false); Opcode ReadUnchecked_Instruction(const u32 _Address, bool resolveReplacements = false); diff --git a/Core/System.cpp b/Core/System.cpp index c8a8b4c769..c679bb60b9 100644 --- a/Core/System.cpp +++ b/Core/System.cpp @@ -62,6 +62,7 @@ #include "Core/ELF/ParamSFO.h" #include "Core/SaveState.h" #include "Common/LogManager.h" +#include "Common/ExceptionHandlerSetup.h" #include "Core/HLE/sceAudiocodec.h" #include "GPU/GPUState.h" @@ -266,10 +267,11 @@ void CPU_Init() { return; } - if (coreParameter.updateRecent) { g_Config.AddRecent(filename); } + + InstallExceptionHandler(&Memory::HandleFault); } PSP_LoadingLock::PSP_LoadingLock() { @@ -281,6 +283,8 @@ PSP_LoadingLock::~PSP_LoadingLock() { } void CPU_Shutdown() { + UninstallExceptionHandler(); + // Since we load on a background thread, wait for startup to complete. PSP_LoadingLock lock; PSPLoaders_Shutdown(); diff --git a/UWP/CommonUWP/CommonUWP.vcxproj b/UWP/CommonUWP/CommonUWP.vcxproj index a5fe599d10..88559e8c82 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj +++ b/UWP/CommonUWP/CommonUWP.vcxproj @@ -398,6 +398,7 @@ + @@ -435,6 +436,7 @@ + diff --git a/UWP/CommonUWP/CommonUWP.vcxproj.filters b/UWP/CommonUWP/CommonUWP.vcxproj.filters index 566049b279..100c103e66 100644 --- a/UWP/CommonUWP/CommonUWP.vcxproj.filters +++ b/UWP/CommonUWP/CommonUWP.vcxproj.filters @@ -16,6 +16,7 @@ + @@ -65,6 +66,7 @@ + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 5bdf22bd18..0adfb91db9 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -205,6 +205,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Common/Crypto/sha256.cpp \ $(SRC)/Common/ChunkFile.cpp \ $(SRC)/Common/ColorConv.cpp \ + $(SRC)/Common/ExceptionHandlerSetup.cpp \ $(SRC)/Common/KeyMap.cpp \ $(SRC)/Common/LogManager.cpp \ $(SRC)/Common/MemArenaAndroid.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index ab7d30ebdf..ed78f44cc4 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -143,6 +143,7 @@ SOURCES_CXX += \ SOURCES_CXX += \ $(COMMONDIR)/ChunkFile.cpp \ $(COMMONDIR)/ConsoleListener.cpp \ + $(COMMONDIR)/ExceptionHandlerSetup.cpp \ $(COMMONDIR)/FileUtil.cpp \ $(COMMONDIR)/KeyMap.cpp \ $(COMMONDIR)/LogManager.cpp \