From 1fce6de8b182ba0418acb4ab24e3b7eba2b63850 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 11 Feb 2019 11:11:56 +0100 Subject: [PATCH 01/17] 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 ee980147402d..9146253dc4c1 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 80278606dff2..6486c530e777 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 ebe7f5068812..c49d67d6af61 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 000000000000..098b603209f7 --- /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 000000000000..8f88176e0e4b --- /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 000000000000..643fac485822 --- /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 9c7a2cce19d1..93d2029da24a 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 4f598961f3a6..a7849a6fb7db 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 c8a8b4c769d0..c679bb60b908 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 a5fe599d1012..88559e8c82a8 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 566049b279eb..100c103e66d1 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 5bdf22bd1893..0adfb91db9f8 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 ab7d30ebdfd9..ed78f44cc444 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 \ From aa802ecc0f2697f10562be5187ae9169c13ae818 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 12 Feb 2019 10:08:11 +0100 Subject: [PATCH 02/17] Skip bad reads/writes by the guest executable. --- Common/ExceptionHandlerSetup.cpp | 1 + Common/x64Analyzer.cpp | 11 ++++-- Common/x64Analyzer.h | 2 +- Core/MemMap.cpp | 57 +++++++++++++++++++++++--------- 4 files changed, 53 insertions(+), 18 deletions(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 098b603209f7..f538efb5a176 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -90,6 +90,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { void UninstallExceptionHandler() { RemoveVectoredExceptionHandler(g_vectoredExceptionHandle); + g_badAccessHandler = nullptr; } #elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE) diff --git a/Common/x64Analyzer.cpp b/Common/x64Analyzer.cpp index 1940416d6a9c..42095b03c986 100644 --- a/Common/x64Analyzer.cpp +++ b/Common/x64Analyzer.cpp @@ -17,8 +17,10 @@ #include "x64Analyzer.h" -bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType) +bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info) { + int accessType = 0; + unsigned const char *startCodePtr = codePtr; u8 rex = 0; u8 codeByte = 0; @@ -80,6 +82,12 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc modRMbyte = *codePtr++; hasModRM = true; } + + // TODO: Add more cases. + if ((codeByte & 0xF0) == 0x80) + accessType = 1; + if ((codeByte & 0xF0) == 0xC0) + accessType = 1; } else { @@ -135,7 +143,6 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc else info.displacement = *((s32 *)codePtr); codePtr += displacementSize; - if (accessType == 1) { diff --git a/Common/x64Analyzer.h b/Common/x64Analyzer.h index ad2fed886d50..d448d4c60fc8 100644 --- a/Common/x64Analyzer.h +++ b/Common/x64Analyzer.h @@ -60,4 +60,4 @@ enum AccessType { OP_ACCESS_WRITE = 1 }; -bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType); +bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info); diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 93d2029da24a..af47ce6668ff 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -29,6 +29,7 @@ #include "Common/MemArena.h" #include "Common/ChunkFile.h" #include "Common/MachineContext.h" +#include "Common/x64Analyzer.h" #include "Core/MemMap.h" #include "Core/HDRemaster.h" @@ -463,29 +464,55 @@ bool HandleFault(uintptr_t hostAddress, void *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. + bool inJitSpace = true; // MIPSComp::jit->IsInSpace(codePtr); + if (!inJitSpace) { + // This is a crash in non-jitted code. Not something we want to handle here, ignore. + return false; + } uintptr_t baseAddress = (uintptr_t)base; - #ifdef MASKED_PSP_MEMORY - const uintptr_t addressSpaceSize = 0x100000000ULL; -#else const uintptr_t addressSpaceSize = 0x40000000ULL; +#else + const uintptr_t addressSpaceSize = 0x100000000ULL; #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; + // Check whether hostAddress is within the PSP memory space, which (likely) means it was a guest executable that did the bad access. + if (hostAddress < baseAddress || hostAddress >= baseAddress + addressSpaceSize) { + // Host address outside - this was a different kind of crash. + return false; } - // A regular crash of some sort. Pass it on. - return false; + // OK, a guest executable did a bad access. Take care of it. + + uint32_t guestAddress = hostAddress - baseAddress; + ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, hostAddress); + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + +#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) + + InstructionInfo info; + DisassembleMov(codePtr, info); + + if (g_Config.bIgnoreBadMemAccess) { + if (!info.isMemoryWrite) { + // Must have been a read. Fill the register with 0. + // TODO + } + // Move on to the next instruction. + context->CTX_PC += info.instructionSize; + } else { + // Jump to a crash handler. + // TODO + context->CTX_PC += info.instructionSize; + } + +#else + // ARM, ARM64 : All instructions are always 4 bytes in size. As an initial implementation, + // let's just skip the offending instruction. + context->CTX_PC += 4; +#endif + return true; } } // namespace From c988d42b046c55d875d56bca122bdd8f380d2398 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 12 Feb 2019 10:58:20 +0100 Subject: [PATCH 03/17] ARM/ARM64 instruction analysis, hook up to handler --- Common/CodeBlock.h | 2 +- Common/ExceptionHandlerSetup.cpp | 22 +++++++++-- Common/x64Analyzer.cpp | 2 +- Common/x64Analyzer.h | 4 +- Core/MIPS/ARM/ArmAsm.cpp | 7 ++++ Core/MIPS/ARM/ArmJit.h | 4 ++ Core/MIPS/ARM64/Arm64Asm.cpp | 7 ++++ Core/MIPS/ARM64/Arm64Jit.h | 4 ++ Core/MIPS/IR/IRJit.h | 5 +++ Core/MIPS/JitCommon/JitCommon.h | 2 + Core/MIPS/x86/Asm.cpp | 10 +++++ Core/MIPS/x86/Jit.cpp | 2 + Core/MIPS/x86/Jit.h | 4 ++ Core/MemMap.cpp | 63 +++++++++++++++++++++++++------- Core/Util/DisArm64.cpp | 35 ++++++++++++++++++ Core/Util/DisArm64.h | 21 +++++++++++ ext/disarm.cpp | 29 +++------------ ext/disarm.h | 30 +++++++++++---- 18 files changed, 202 insertions(+), 51 deletions(-) diff --git a/Common/CodeBlock.h b/Common/CodeBlock.h index f60c4b9305da..777fb164a4d2 100644 --- a/Common/CodeBlock.h +++ b/Common/CodeBlock.h @@ -19,7 +19,7 @@ class CodeBlockCommon { CodeBlockCommon() {} virtual ~CodeBlockCommon() {} - bool IsInSpace(const u8 *ptr) { + bool IsInSpace(const u8 *ptr) const { return (ptr >= region) && (ptr < (region + region_size)); } diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index f538efb5a176..d9c3d5c4adad 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include "Common/ExceptionHandlerSetup.h" - #include #include #include @@ -84,6 +83,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { return; } + INFO_LOG(SYSTEM, "Installing exception handler"); g_badAccessHandler = badAccessHandler; g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, Handler); } @@ -91,6 +91,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { void UninstallExceptionHandler() { RemoveVectoredExceptionHandler(g_vectoredExceptionHandle); g_badAccessHandler = nullptr; + INFO_LOG(SYSTEM, "Removed exception handler"); } #elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE) @@ -186,7 +187,14 @@ static void ExceptionThread(mach_port_t port) { } void InstallExceptionHandler(BadAccessHandler badAccessHandler) { - g_badAccessHandler = badAccessHandler; + if (!g_badAccessHandler) { + g_badAccessHandler = badAccessHandler; + } else { + // The rest of the setup we don't need to do again. + g_badAccessHandler = badAccessHandler; + return; + } + INFO_LOG(SYSTEM, "Installing exception handler"); mach_port_t port; CheckKR("mach_port_allocate", mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port)); @@ -275,6 +283,10 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { } void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + if (g_badAccessHandler) { + return; + } + NOTICE_LOG(SYSTEM, "Installed exception handler"); g_badAccessHandler = badAccessHandler; stack_t signal_stack; @@ -308,10 +320,14 @@ void UninstallExceptionHandler() { #ifdef __APPLE__ sigaction(SIGBUS, &old_sa_bus, nullptr); #endif + NOTICE_LOG(SYSTEM, "Uninstalled exception handler"); + g_badAccessHandler = nullptr; } #else // _M_GENERIC or unsupported platform -void InstallExceptionHandler(BadAccessHandler badAccessHandler) { } +void InstallExceptionHandler(BadAccessHandler badAccessHandler) { + ERROR_LOG(SYSTEM, "Exception handler not implemented on this platform, can't install"); +} void UninstallExceptionHandler() { } #endif diff --git a/Common/x64Analyzer.cpp b/Common/x64Analyzer.cpp index 42095b03c986..0d04346c0457 100644 --- a/Common/x64Analyzer.cpp +++ b/Common/x64Analyzer.cpp @@ -17,7 +17,7 @@ #include "x64Analyzer.h" -bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info) +bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info) { int accessType = 0; diff --git a/Common/x64Analyzer.h b/Common/x64Analyzer.h index d448d4c60fc8..8ba78005e50a 100644 --- a/Common/x64Analyzer.h +++ b/Common/x64Analyzer.h @@ -19,7 +19,7 @@ #include "Common.h" -struct InstructionInfo +struct LSInstructionInfo { int operandSize; //8, 16, 32, 64 int instructionSize; @@ -60,4 +60,4 @@ enum AccessType { OP_ACCESS_WRITE = 1 }; -bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info); +bool X86AnalyzeMOV(const unsigned char *codePtr, LSInstructionInfo &info); diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index 3a5bcba1a53b..fa5a10195d2b 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -237,6 +237,7 @@ void ArmJit::GenerateFixedCode() { CMP(R0, 0); B_CC(CC_EQ, outerLoop); + const uint8_t *quitLoop = GetCodePtr(); SetJumpTarget(badCoreState); SaveDowncount(); @@ -251,6 +252,12 @@ void ArmJit::GenerateFixedCode() { POP(9, R4, R5, R6, R7, R8, R9, R10, R11, R_PC); // Returns + crashHandler = GetCodePtr(); + MOVP2R(R0, &coreState); + MOVI2R(R1, CORE_ERROR); + STR(R1, R0, 0); + B(quitLoop); + // Uncomment if you want to see the output... if (disasm) { INFO_LOG(JIT, "THE DISASM ========================"); diff --git a/Core/MIPS/ARM/ArmJit.h b/Core/MIPS/ARM/ArmJit.h index 80a3bc6ae962..50322a65bc65 100644 --- a/Core/MIPS/ARM/ArmJit.h +++ b/Core/MIPS/ARM/ArmJit.h @@ -51,6 +51,8 @@ class ArmJit : public ArmGen::ARMXCodeBlock, public JitInterface, public MIPSFro void Compile(u32 em_address) override; // Compiles a block at current MIPS PC + const u8 *GetCrashHandler() const override { return crashHandler; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name) override; MIPSOpcode GetOriginalOp(MIPSOpcode op) override; @@ -313,6 +315,8 @@ class ArmJit : public ArmGen::ARMXCodeBlock, public JitInterface, public MIPSFro const u8 *restoreRoundingMode; const u8 *applyRoundingMode; + + const u8 *crashHandler; }; } // namespace MIPSComp diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index 755e35f57c5d..a884f6ac4efc 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -277,6 +277,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { CMP(SCRATCH1, 0); B(CC_EQ, outerLoop); + const uint8_t *quitLoop = GetCodePtr(); SetJumpTarget(badCoreState); SaveStaticRegisters(); @@ -286,6 +287,12 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { RET(); + crashHandler = GetCodePtr(); + MOVP2R(SCRATCH1_64, &coreState); + MOVI2R(SCRATCH2, CORE_ERROR); + STR(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0); + B(quitLoop); + // Generate some integer conversion funcs. // MIPS order! static const RoundingMode roundModes[8] = { ROUND_N, ROUND_Z, ROUND_P, ROUND_M, ROUND_N, ROUND_Z, ROUND_P, ROUND_M }; diff --git a/Core/MIPS/ARM64/Arm64Jit.h b/Core/MIPS/ARM64/Arm64Jit.h index 6ad5921d53ef..17734ade594a 100644 --- a/Core/MIPS/ARM64/Arm64Jit.h +++ b/Core/MIPS/ARM64/Arm64Jit.h @@ -52,6 +52,8 @@ class Arm64Jit : public Arm64Gen::ARM64CodeBlock, public JitInterface, public MI void Compile(u32 em_address) override; // Compiles a block at current MIPS PC const u8 *DoJit(u32 em_address, JitBlock *b); + const u8 *GetCrashHandler() const override { return crashHandler; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name) override; MIPSOpcode GetOriginalOp(MIPSOpcode op) override; @@ -281,6 +283,8 @@ class Arm64Jit : public Arm64Gen::ARM64CodeBlock, public JitInterface, public MI const u8 *applyRoundingMode; const u8 *updateRoundingMode; + const u8 *crashHandler; + int jitStartOffset; // Indexed by FPCR FZ:RN bits for convenience. Uses SCRATCH2. diff --git a/Core/MIPS/IR/IRJit.h b/Core/MIPS/IR/IRJit.h index d378dcfc87a5..9beabe585ac4 100644 --- a/Core/MIPS/IR/IRJit.h +++ b/Core/MIPS/IR/IRJit.h @@ -160,7 +160,12 @@ class IRJit : public JitInterface { void InvalidateCacheAt(u32 em_address, int length = 4) override; void UpdateFCR31() override; + bool CodeInRange(const u8 *ptr) const override { + return false; + } + const u8 *GetDispatcher() const override { return nullptr; } + const u8 *GetCrashHandler() const override { return nullptr; } void LinkBlock(u8 *exitPoint, const u8 *checkedEntry) override; void UnlinkBlock(u8 *checkedEntry, u32 originalAddress) override; diff --git a/Core/MIPS/JitCommon/JitCommon.h b/Core/MIPS/JitCommon/JitCommon.h index bf3023e21d67..08063f866e49 100644 --- a/Core/MIPS/JitCommon/JitCommon.h +++ b/Core/MIPS/JitCommon/JitCommon.h @@ -121,8 +121,10 @@ namespace MIPSComp { public: virtual ~JitInterface() {} + virtual bool CodeInRange(const u8 *ptr) const = 0; virtual bool DescribeCodePtr(const u8 *ptr, std::string &name) = 0; virtual const u8 *GetDispatcher() const = 0; + virtual const u8 *GetCrashHandler() const = 0; virtual JitBlockCache *GetBlockCache() = 0; virtual JitBlockCacheDebugInterface *GetBlockCacheDebugInterface() = 0; virtual void InvalidateCacheAt(u32 em_address, int length = 4) = 0; diff --git a/Core/MIPS/x86/Asm.cpp b/Core/MIPS/x86/Asm.cpp index fd1815132d1b..d927ba8c6d87 100644 --- a/Core/MIPS/x86/Asm.cpp +++ b/Core/MIPS/x86/Asm.cpp @@ -206,11 +206,21 @@ void Jit::GenerateFixedCode(JitOptions &jo) { } J_CC(CC_Z, outerLoop, true); + const uint8_t *quitLoop = GetCodePtr(); SetJumpTarget(badCoreState); RestoreRoundingMode(true); ABI_PopAllCalleeSavedRegsAndAdjustStack(); RET(); + crashHandler = GetCodePtr(); + if (RipAccessible((const void *)&coreState)) { + MOV(32, M(&coreState), Imm32(CORE_RUNTIME_ERROR)); + } else { + MOV(PTRBITS, R(RAX), ImmPtr((const void *)&coreState)); + MOV(32, MatR(RAX), Imm32(CORE_RUNTIME_ERROR)); + } + JMP(quitLoop, true); + // Let's spare the pre-generated code from unprotect-reprotect. endOfPregeneratedCode = AlignCodePage(); EndWrite(); diff --git a/Core/MIPS/x86/Jit.cpp b/Core/MIPS/x86/Jit.cpp index 2716f7233a49..0dbdf34d7b2a 100644 --- a/Core/MIPS/x86/Jit.cpp +++ b/Core/MIPS/x86/Jit.cpp @@ -442,6 +442,8 @@ bool Jit::DescribeCodePtr(const u8 *ptr, std::string &name) { name = "enterDispatcher"; else if (ptr == restoreRoundingMode) name = "restoreRoundingMode"; + else if (ptr == crashHandler) + name = "crashHandler"; else { u32 jitAddr = blocks.GetAddressFromBlockPtr(ptr); diff --git a/Core/MIPS/x86/Jit.h b/Core/MIPS/x86/Jit.h index 0eefe89c40bd..b065d9052216 100644 --- a/Core/MIPS/x86/Jit.h +++ b/Core/MIPS/x86/Jit.h @@ -63,6 +63,8 @@ class Jit : public Gen::XCodeBlock, public JitInterface, public MIPSFrontendInte void Compile(u32 em_address) override; // Compiles a block at current MIPS PC const u8 *DoJit(u32 em_address, JitBlock *b); + const u8 *GetCrashHandler() const override { return crashHandler; } + bool CodeInRange(const u8 *ptr) const override { return IsInSpace(ptr); } bool DescribeCodePtr(const u8 *ptr, std::string &name) override; void Comp_RunBlock(MIPSOpcode op) override; @@ -325,6 +327,8 @@ class Jit : public Gen::XCodeBlock, public JitInterface, public MIPSFrontendInte const u8 *endOfPregeneratedCode; + const u8 *crashHandler; + friend class JitSafeMem; friend class JitSafeMemFuncs; }; diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index af47ce6668ff..78abbaeacb71 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -28,8 +28,20 @@ #include "Common/MemoryUtil.h" #include "Common/MemArena.h" #include "Common/ChunkFile.h" + + +#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) #include "Common/MachineContext.h" #include "Common/x64Analyzer.h" +#elif defined(PPSSPP_ARCH_ARM64) +#include "Core/Util/DisArm64.h" +typedef sigcontext SContext; +#define CTX_PC pc +#elif defined(PPSSPP_ARCH_ARM) +#include "ext/disarm.h" +typedef sigcontext SContext; +#define CTX_PC arm_pc +#endif #include "Core/MemMap.h" #include "Core/HDRemaster.h" @@ -43,6 +55,8 @@ #include "Core/ConfigValues.h" #include "Core/HLE/ReplaceTables.h" #include "Core/MIPS/JitCommon/JitBlockCache.h" +#include "Core/MIPS/JitCommon/JitCommon.h" +#include "UI/OnScreenDisplay.h" namespace Memory { @@ -87,6 +101,8 @@ u32 g_PSPModel; std::recursive_mutex g_shutdownLock; +static int64_t g_numReportedBadAccesses = 0; + // We don't declare the IO region in here since its handled by other means. static MemoryView views[] = { @@ -292,6 +308,8 @@ void Init() { INFO_LOG(MEMMAP, "Memory system initialized. Base at %p (RAM at @ %p, uncached @ %p)", base, m_pPhysicalRAM, m_pUncachedRAM); + + g_numReportedBadAccesses = 0; } void Reinit() { @@ -464,7 +482,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { const uint8_t *codePtr = (uint8_t *)(context->CTX_PC); // TODO: Check that codePtr is within the current JIT space. - bool inJitSpace = true; // MIPSComp::jit->IsInSpace(codePtr); + bool inJitSpace = MIPSComp::jit->CodeInRange(codePtr); if (!inJitSpace) { // This is a crash in non-jitted code. Not something we want to handle here, ignore. return false; @@ -486,32 +504,49 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { // OK, a guest executable did a bad access. Take care of it. uint32_t guestAddress = hostAddress - baseAddress; - ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, hostAddress); - // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + + // TODO: Share the struct between the various analyzers, that will allow us to share most of + // the implementations here. #if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) + // X86, X86-64. Variable instruction size so need to analyze the mov instruction in detail. - InstructionInfo info; - DisassembleMov(codePtr, info); + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + LSInstructionInfo info; + X86AnalyzeMOV(codePtr, info); +#elif defined(PPSSPP_ARCH_ARM64) + uint32_t word; + memcpy(&word, codePtr, 4); + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + Arm64LSInstructionInfo info; + Arm64AnalyzeLoadStore((uint64_t)codePtr, word, &info); +#elif defined(PPSSPP_ARCH_ARM) + uint32_t word; + memcpy(&word, codePtr, 4); + // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC + ArmLSInstructionInfo info; + ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info); +#endif if (g_Config.bIgnoreBadMemAccess) { if (!info.isMemoryWrite) { - // Must have been a read. Fill the register with 0. + // It was a read. Fill the destination register with 0. // TODO } // Move on to the next instruction. context->CTX_PC += info.instructionSize; + // Fall through to logging. } else { - // Jump to a crash handler. - // TODO - context->CTX_PC += info.instructionSize; + // Jump to a crash handler that will exit the game. + context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler(); + ERROR_LOG(SYSTEM, "Bad memory access detected! %08x (%p) Stopping emulation.", guestAddress, (void *)hostAddress); + return true; } -#else - // ARM, ARM64 : All instructions are always 4 bytes in size. As an initial implementation, - // let's just skip the offending instruction. - context->CTX_PC += 4; -#endif + g_numReportedBadAccesses++; + if (g_numReportedBadAccesses < 100) { + ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); + } return true; } diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index fd17c5441239..c891b5eb0567 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -265,6 +265,41 @@ static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *ins } } +void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t w, Arm64LSInstructionInfo *info) { + *info = {}; + info->instructionSize = 4; + int id = (w >> 25) & 0xF; + switch (id) { + case 4: case 6: case 0xC: case 0xE: + info->isLoadOrStore = true; + break; + default: + ERROR_LOG(CPU, "Tried to disassemble %08x at %p as a load/store instruction", w, (void *)addr); + return; // not the expected instruction + } + + info->size = w >> 30; + info->Rt = (w & 0x1F); + info->Rn = ((w >> 5) & 0x1F); + info->Rm = ((w >> 16) & 0x1F); + int opc = (w >> 22) & 0x3; + if (opc == 0 || opc == 2) { + info->isMemoryWrite = true; + } + + if (((w >> 27) & 7) == 7) { + int V = (w >> 26) & 1; + if (V == 0) { + info->isIntegerLoadStore = true; + } else { + info->isFPLoadStore = true; + } + } else { + info->isPairLoadStore = true; + // TODO + } +} + static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) { int size = w >> 30; int imm9 = SignExtend9((w >> 12) & 0x1FF); diff --git a/Core/Util/DisArm64.h b/Core/Util/DisArm64.h index fc55c6c34b8a..73b22db4bdfb 100644 --- a/Core/Util/DisArm64.h +++ b/Core/Util/DisArm64.h @@ -24,3 +24,24 @@ typedef bool (*SymbolCallback)(char *buffer, int bufsize, uint8_t *address); void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool includeWord, SymbolCallback symbolCallback = nullptr); +// Information about a load/store instruction. +struct Arm64LSInstructionInfo { + int instructionSize; + + bool isLoadOrStore; + + bool isIntegerLoadStore; + bool isFPLoadStore; + bool isPairLoadStore; + + int size; // 0 = 8-bit, 1 = 16-bit, 2 = 32-bit, 3 = 64-bit + bool isMemoryWrite; + + int Rt; + int Rn; + int Rm; + + // TODO: more. +}; + +void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t op, Arm64LSInstructionInfo *info); diff --git a/ext/disarm.cpp b/ext/disarm.cpp index 90c89c16b5d3..c3d0662f3f12 100644 --- a/ext/disarm.cpp +++ b/ext/disarm.cpp @@ -72,6 +72,7 @@ #include "base/basictypes.h" #include "Common/ArmEmitter.h" +#include "ext/disarm.h" static const char *CCFlagsStr[] = { "EQ", // Equal @@ -759,30 +760,12 @@ static bool DisasmNeon(uint32_t op, char *text) { return false; } +void ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info) { + *info = {}; + info->instructionSize = 4; - - - - - - - - - - - - - - - - - - - - - - - + // TODO +} typedef unsigned int word; diff --git a/ext/disarm.h b/ext/disarm.h index 9bae68f21567..138f3e3e69dd 100644 --- a/ext/disarm.h +++ b/ext/disarm.h @@ -17,18 +17,34 @@ #pragma once +#include -// This stuff only disassembles very old ARM but should be sufficient -// for the basics except for MOVW/MOVT. - - +// This stuff used to only disassemble very old ARM but has now +// been extended to support most (but not all) modern instructions, including NEON. // Disarm itself has the license you can see in the cpp file. // I'm not entirely sure it's 100% gpl compatible but it's nearly // public domain so meh. -// The only changes I've done is C++ compat and replaced the main -// program with this function. - const char *ArmRegName(int r); void ArmDis(unsigned int addr, unsigned int w, char *output, int bufsize, bool includeWord); + +// Information about a load/store instruction. +struct ArmLSInstructionInfo { + int instructionSize; + + bool isIntegerLoadStore; + bool isFPLoadStore; + bool isMultiLoadStore; + + int size; // 0 = 8-bit, 1 = 16-bit, 2 = 32-bit, 3 = 64-bit + bool isMemoryWrite; + + int Rt; + int Rn; + int Rm; + + // TODO: more. +}; + +void ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info); From cbc90955ba3d27d53e63fead0d9d1cd53b1085f9 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 12 Feb 2019 13:29:37 +0100 Subject: [PATCH 04/17] Draw a minimal crash dump on the emu screen after a crash (if bIgnoreBadMemAccess is false). Add setting for ignore bad memory accesses --- UI/EmuScreen.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index 80170e844bc6..ea0dc9ea113d 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1539,8 +1539,10 @@ bool EmuScreen::hasVisibleUI() { return true; // Exception information. - if (coreState == CORE_RUNTIME_ERROR || coreState == CORE_STEPPING) + if (coreState == CORE_RUNTIME_ERROR || coreState == CORE_STEPPING) { return true; + } + return false; } From c3016fe6a506ef1a8fff8f6e01f32b37ec999241 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Wed, 13 Feb 2019 18:00:57 +0100 Subject: [PATCH 05/17] Mac/Linux buildfixes --- Common/ExceptionHandlerSetup.cpp | 4 +++- Common/MachineContext.h | 12 ++++++------ Core/MemMap.h | 1 + 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index d9c3d5c4adad..62dd26d98488 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -7,11 +7,13 @@ #include #include #include +#include #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" #include "Common/MsgHandler.h" #include "Common/Log.h" +#include "ext/native/thread/threadutil.h" #if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) #include "Common/MachineContext.h" @@ -103,7 +105,7 @@ static void CheckKR(const char* name, kern_return_t kr) { } static void ExceptionThread(mach_port_t port) { - Common::SetCurrentThreadName("Mach exception thread"); + setCurrentThreadName("Mach exception thread"); #pragma pack(4) struct { mach_msg_header_t Head; diff --git a/Common/MachineContext.h b/Common/MachineContext.h index 643fac485822..9ce074ba410d 100644 --- a/Common/MachineContext.h +++ b/Common/MachineContext.h @@ -46,7 +46,7 @@ typedef CONTEXT SContext; #include #include -#if _M_X86_64 +#if PPSSPP_ARCH_AMD64 typedef x86_thread_state64_t SContext; #define CTX_RAX __rax #define CTX_RBX __rbx @@ -94,7 +94,7 @@ typedef _STRUCT_MCONTEXT64 SContext; #include typedef mcontext_t SContext; -#if _M_X86_64 +#if PPSSPP_ARCH_AMD64 #define CTX_RAX gregs[REG_RAX] #define CTX_RBX gregs[REG_RBX] #define CTX_RCX gregs[REG_RCX] @@ -122,7 +122,7 @@ typedef mcontext_t SContext; #elif defined(__OpenBSD__) #include typedef ucontext_t SContext; -#if _M_X86_64 +#if PPSSPP_ARCH_AMD64 #define CTX_RAX sc_rax #define CTX_RBX sc_rbx #define CTX_RCX sc_rcx @@ -146,7 +146,7 @@ typedef ucontext_t SContext; #elif defined(__NetBSD__) #include typedef mcontext_t SContext; -#if _M_X86_64 +#if PPSSPP_ARCH_AMD64 #define CTX_RAX __gregs[_REG_RAX] #define CTX_RBX __gregs[_REG_RBX] #define CTX_RCX __gregs[_REG_RCX] @@ -170,7 +170,7 @@ typedef mcontext_t SContext; #elif defined(__FreeBSD__) #include typedef mcontext_t SContext; -#if _M_X86_64 +#if PPSSPP_ARCH_AMD64 #define CTX_RAX mc_rax #define CTX_RBX mc_rbx #define CTX_RCX mc_rcx @@ -194,7 +194,7 @@ typedef mcontext_t SContext; #elif defined(__HAIKU__) #include typedef mcontext_t SContext; -#if _M_X86_64 +#if PPSSPP_ARCH_AMD64 #define CTX_RAX rax #define CTX_RBX rbx #define CTX_RCX rcx diff --git a/Core/MemMap.h b/Core/MemMap.h index a7849a6fb7db..dcbbad5441f5 100644 --- a/Core/MemMap.h +++ b/Core/MemMap.h @@ -20,6 +20,7 @@ #include "ppsspp_config.h" #include +#include #ifndef offsetof #include #endif From 96a40bb36d32dbcd8fc684afc9f697be065340f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 17 Feb 2019 17:28:36 +0000 Subject: [PATCH 06/17] Exceptions: A bit more consistency in callback registeration. --- Common/ExceptionHandlerSetup.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 62dd26d98488..64dc68286aaa 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2+ // Refer to the license.txt file included. +// The corresponding file is called MemTools in the Dolphin project. + #include "Common/ExceptionHandlerSetup.h" #include #include @@ -82,6 +84,7 @@ 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) { + g_badAccessHandler = badAccessHandler; return; } @@ -189,13 +192,13 @@ static void ExceptionThread(mach_port_t port) { } void InstallExceptionHandler(BadAccessHandler badAccessHandler) { - if (!g_badAccessHandler) { - g_badAccessHandler = badAccessHandler; - } else { + if (g_badAccessHandler) { // The rest of the setup we don't need to do again. g_badAccessHandler = badAccessHandler; return; } + g_badAccessHandler = badAccessHandler; + INFO_LOG(SYSTEM, "Installing exception handler"); mach_port_t port; CheckKR("mach_port_allocate", @@ -286,6 +289,7 @@ static void sigsegv_handler(int sig, siginfo_t* info, void* raw_context) { void InstallExceptionHandler(BadAccessHandler badAccessHandler) { if (g_badAccessHandler) { + g_badAccessHandler = badAccessHandler; return; } NOTICE_LOG(SYSTEM, "Installed exception handler"); From 236cb5722486c55977f0fbfb277aac0960117bca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 17 Feb 2019 17:46:42 +0000 Subject: [PATCH 07/17] More info on crash screen --- UI/EmuScreen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index ea0dc9ea113d..b624dd6186a3 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1271,7 +1271,8 @@ static void DrawCrashDump(DrawBuffer *draw2d) { FontID ubuntu24("UBUNTU24"); char statbuf[4096]; char versionString[256]; - sprintf(versionString, "%s", PPSSPP_GIT_VERSION); + snprintf(versionString, sizeof(versionString), "%s", PPSSPP_GIT_VERSION); + // TODO: Draw a lot more information. Full register set, and so on. #ifdef _DEBUG From fdcf4f06f20457a31ebaa90344df9d09d85fcf0f Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 18 Feb 2019 14:02:39 +0100 Subject: [PATCH 08/17] Add x64Analyzer to Android.mk. Some minor cleanup --- CMakeLists.txt | 3 --- Common/ExceptionHandlerSetup.cpp | 9 +++++--- Common/MachineContext.h | 38 +++++++++++++++++++------------- Core/MIPS/MIPS.h | 6 +++-- Core/MemMap.cpp | 12 +++++----- android/jni/Android.mk | 2 ++ 6 files changed, 41 insertions(+), 29 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9146253dc4c1..9d866fe92c01 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -340,9 +340,6 @@ macro(setup_target_project TargetName ProjectDir) endforeach() endmacro() -# Commented-out files are files that don't compile -# and were disabled in the original MSVC project anyway - set(CommonX86 Common/ABI.cpp Common/ABI.h diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 64dc68286aaa..c5725c581c9a 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -4,6 +4,8 @@ // The corresponding file is called MemTools in the Dolphin project. +#include "ppsspp_config.h" + #include "Common/ExceptionHandlerSetup.h" #include #include @@ -17,7 +19,7 @@ #include "Common/Log.h" #include "ext/native/thread/threadutil.h" -#if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) #include "Common/MachineContext.h" #endif @@ -225,7 +227,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { void UninstallExceptionHandler() { } -#elif defined(_POSIX_VERSION) && !defined(_M_GENERIC) +#elif defined(_POSIX_VERSION) static struct sigaction old_sa_segv; static struct sigaction old_sa_bus; @@ -329,7 +331,8 @@ void UninstallExceptionHandler() { NOTICE_LOG(SYSTEM, "Uninstalled exception handler"); g_badAccessHandler = nullptr; } -#else // _M_GENERIC or unsupported platform + +#else // Unsupported platform. Could also #error void InstallExceptionHandler(BadAccessHandler badAccessHandler) { ERROR_LOG(SYSTEM, "Exception handler not implemented on this platform, can't install"); diff --git a/Common/MachineContext.h b/Common/MachineContext.h index 9ce074ba410d..c39df38abda8 100644 --- a/Common/MachineContext.h +++ b/Common/MachineContext.h @@ -9,7 +9,7 @@ #if PPSSPP_PLATFORM(WINDOWS) #include typedef CONTEXT SContext; -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) #define CTX_RAX Rax #define CTX_RBX Rbx #define CTX_RCX Rcx @@ -46,7 +46,7 @@ typedef CONTEXT SContext; #include #include -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) typedef x86_thread_state64_t SContext; #define CTX_RAX __rax #define CTX_RBX __rbx @@ -94,7 +94,7 @@ typedef _STRUCT_MCONTEXT64 SContext; #include typedef mcontext_t SContext; -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) #define CTX_RAX gregs[REG_RAX] #define CTX_RBX gregs[REG_RBX] #define CTX_RCX gregs[REG_RCX] @@ -122,7 +122,7 @@ typedef mcontext_t SContext; #elif defined(__OpenBSD__) #include typedef ucontext_t SContext; -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) #define CTX_RAX sc_rax #define CTX_RBX sc_rbx #define CTX_RCX sc_rcx @@ -146,7 +146,7 @@ typedef ucontext_t SContext; #elif defined(__NetBSD__) #include typedef mcontext_t SContext; -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) #define CTX_RAX __gregs[_REG_RAX] #define CTX_RBX __gregs[_REG_RBX] #define CTX_RCX __gregs[_REG_RCX] @@ -170,7 +170,7 @@ typedef mcontext_t SContext; #elif defined(__FreeBSD__) #include typedef mcontext_t SContext; -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) #define CTX_RAX mc_rax #define CTX_RBX mc_rbx #define CTX_RCX mc_rcx @@ -194,7 +194,7 @@ typedef mcontext_t SContext; #elif defined(__HAIKU__) #include typedef mcontext_t SContext; -#if PPSSPP_ARCH_AMD64 +#if PPSSPP_ARCH(AMD64) #define CTX_RAX rax #define CTX_RBX rbx #define CTX_RCX rcx @@ -219,17 +219,12 @@ typedef mcontext_t SContext; #error No context definition for OS #endif -#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) +#if PPSSPP_ARCH(AMD64) + #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), @@ -237,7 +232,20 @@ static inline u64* ContextRN(SContext* ctx, int n) 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]); } + +#elif PPSSPP_ARCH(X86) + +#include +#define CTX_PC CTX_RIP + +static inline u32* ContextRN(SContext* ctx, int n) +{ + 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)}; + return (u32*)((char*)ctx + offsets[n]); +} #endif diff --git a/Core/MIPS/MIPS.h b/Core/MIPS/MIPS.h index 7d2c40e8797d..bcc991035895 100644 --- a/Core/MIPS/MIPS.h +++ b/Core/MIPS/MIPS.h @@ -17,6 +17,8 @@ #pragma once +#include "ppsspp_config.h" + #include #include "util/random/rng.h" @@ -148,7 +150,7 @@ extern u8 fromvoffset[128]; enum class CPUCore; -#if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) // Note that CTXREG is offset to point at the first floating point register, intentionally. This is so that a byte offset // can reach both GPR and FPR regs. @@ -246,7 +248,7 @@ class MIPSState static const u32 FCR0_VALUE = 0x00003351; -#if defined(PPSSPP_ARCH_X86) || defined(PPSSPP_ARCH_AMD64) +#if PPSSPP_ARCH(X86) || PPSSPP_ARCH(AMD64) // FPU TEMP0, etc. are swapped in here if necessary (e.g. on x86.) float tempValues[NUM_X86_FPU_TEMPS]; #endif diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 78abbaeacb71..dc92f931212d 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -30,14 +30,14 @@ #include "Common/ChunkFile.h" -#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) +#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) #include "Common/MachineContext.h" #include "Common/x64Analyzer.h" -#elif defined(PPSSPP_ARCH_ARM64) +#elif PPSSPP_ARCH(ARM64) #include "Core/Util/DisArm64.h" typedef sigcontext SContext; #define CTX_PC pc -#elif defined(PPSSPP_ARCH_ARM) +#elif PPSSPP_ARCH(ARM) #include "ext/disarm.h" typedef sigcontext SContext; #define CTX_PC arm_pc @@ -508,19 +508,19 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { // TODO: Share the struct between the various analyzers, that will allow us to share most of // the implementations here. -#if defined(PPSSPP_ARCH_AMD64) || defined(PPSSPP_ARCH_X86) +#if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) // X86, X86-64. Variable instruction size so need to analyze the mov instruction in detail. // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC LSInstructionInfo info; X86AnalyzeMOV(codePtr, info); -#elif defined(PPSSPP_ARCH_ARM64) +#elif PPSSPP_ARCH(ARM64) uint32_t word; memcpy(&word, codePtr, 4); // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC Arm64LSInstructionInfo info; Arm64AnalyzeLoadStore((uint64_t)codePtr, word, &info); -#elif defined(PPSSPP_ARCH_ARM) +#elif PPSSPP_ARCH(ARM) uint32_t word; memcpy(&word, codePtr, 4); // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 0adfb91db9f8..44ab4a73329a 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -15,6 +15,7 @@ ifeq ($(TARGET_ARCH_ABI),x86) ARCH_FILES := \ $(SRC)/Common/ABI.cpp \ $(SRC)/Common/x64Emitter.cpp \ + $(SRC)/Common/x64Analyzer.cpp \ $(SRC)/Common/CPUDetect.cpp \ $(SRC)/Common/Thunk.cpp \ $(SRC)/Core/MIPS/x86/CompALU.cpp \ @@ -36,6 +37,7 @@ ifeq ($(TARGET_ARCH_ABI),x86_64) ARCH_FILES := \ $(SRC)/Common/ABI.cpp \ $(SRC)/Common/x64Emitter.cpp \ + $(SRC)/Common/x64Analyzer.cpp \ $(SRC)/Common/CPUDetect.cpp \ $(SRC)/Common/Thunk.cpp \ $(SRC)/Core/MIPS/x86/CompALU.cpp \ From ac456c2231f4fe3f4e2a020da2cb95010177e96f Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 18 Feb 2019 14:50:57 +0100 Subject: [PATCH 09/17] MachineContext, Linux/Android: Try to support android-x86 (32-bit) --- Common/MachineContext.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Common/MachineContext.h b/Common/MachineContext.h index c39df38abda8..34e5a280a04d 100644 --- a/Common/MachineContext.h +++ b/Common/MachineContext.h @@ -112,10 +112,16 @@ typedef mcontext_t SContext; #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 +#elif PPSSPP_ARCH(X86) +#define CTX_RAX gregs[REG_EAX] +#define CTX_RBX gregs[REG_EBX] +#define CTX_RCX gregs[REG_ECX] +#define CTX_RDX gregs[REG_EDX] +#define CTX_RDI gregs[REG_EDI] +#define CTX_RSI gregs[REG_ESI] +#define CTX_RBP gregs[REG_EBP] +#define CTX_RSP gregs[REG_ESP] +#define CTX_RIP gregs[REG_EIP] #else #error No context definition for architecture #endif From 15c7358e8017981db4098887b7d2583a08ea7b77 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 18 Feb 2019 15:00:31 +0100 Subject: [PATCH 10/17] Try USE_SIGACTION_ON_APPLE on IOS. --- Common/ExceptionHandlerSetup.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index c5725c581c9a..37913774af5a 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -23,6 +23,10 @@ #include "Common/MachineContext.h" #endif +#if PPSSPP_PLATFORM(IOS) +#define USE_SIGACTION_ON_APPLE +#endif + #ifdef __FreeBSD__ #include #endif From 430c3ee6a384749d9fcc5c759cc46920cd3d6955 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 18 Feb 2019 15:09:58 +0100 Subject: [PATCH 11/17] HandleFault: Add missing nullcheck --- Core/MemMap.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index dc92f931212d..684d162b5e4e 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -482,7 +482,7 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { const uint8_t *codePtr = (uint8_t *)(context->CTX_PC); // TODO: Check that codePtr is within the current JIT space. - bool inJitSpace = MIPSComp::jit->CodeInRange(codePtr); + bool inJitSpace = MIPSComp::jit && MIPSComp::jit->CodeInRange(codePtr); if (!inJitSpace) { // This is a crash in non-jitted code. Not something we want to handle here, ignore. return false; @@ -533,19 +533,16 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { // It was a read. Fill the destination register with 0. // TODO } - // Move on to the next instruction. + // Move on to the next instruction. Note that handling bad accesses like this is pretty slow. context->CTX_PC += info.instructionSize; - // Fall through to logging. + g_numReportedBadAccesses++; + if (g_numReportedBadAccesses < 100) { + ERROR_LOG(MEMMAP, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); + } } else { - // Jump to a crash handler that will exit the game. + // Redirect execution to a crash handler that will exit the game. context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler(); - ERROR_LOG(SYSTEM, "Bad memory access detected! %08x (%p) Stopping emulation.", guestAddress, (void *)hostAddress); - return true; - } - - g_numReportedBadAccesses++; - if (g_numReportedBadAccesses < 100) { - ERROR_LOG(SYSTEM, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); + ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation.", guestAddress, (void *)hostAddress); } return true; } From 465367bf1b3116c55bd15d5c44d1398d7acf4429 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Mon, 18 Feb 2019 16:04:38 +0100 Subject: [PATCH 12/17] iOS buildfix attempt --- Core/MemMap.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 684d162b5e4e..fa1e3d96b5c9 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -29,6 +29,12 @@ #include "Common/MemArena.h" #include "Common/ChunkFile.h" +#ifdef __FreeBSD__ +#include +#endif +#ifndef _WIN32 +#include // Needed for _POSIX_VERSION +#endif #if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) #include "Common/MachineContext.h" From a56f39171346708cc5dbbc72a93c8c24ba7d5180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Sun, 5 Jul 2020 11:40:58 +0200 Subject: [PATCH 13/17] Make fastmem memory exceptions report the exceptions to Core correctly. --- Common/ExceptionHandlerSetup.cpp | 4 ++-- Core/Core.h | 1 + Core/MemMap.cpp | 22 ++++++++++++++++++---- UI/EmuScreen.cpp | 2 +- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 37913774af5a..7c8d64b1eb11 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -40,7 +40,7 @@ static BadAccessHandler g_badAccessHandler; static PVOID g_vectoredExceptionHandle; -static LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs) { +static LONG NTAPI GlobalExceptionHandler(PEXCEPTION_POINTERS pPtrs) { switch (pPtrs->ExceptionRecord->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: { @@ -96,7 +96,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) { INFO_LOG(SYSTEM, "Installing exception handler"); g_badAccessHandler = badAccessHandler; - g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, Handler); + g_vectoredExceptionHandle = AddVectoredExceptionHandler(TRUE, GlobalExceptionHandler); } void UninstallExceptionHandler() { diff --git a/Core/Core.h b/Core/Core.h index 6cb8004cf4ce..e7bdb5a46242 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -80,6 +80,7 @@ void Core_SetPowerSaving(bool mode); bool Core_GetPowerSaving(); enum class MemoryExceptionType { + NONE, READ_WORD, WRITE_WORD, READ_BLOCK, diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index fa1e3d96b5c9..9e8968fd8cc8 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -513,28 +513,38 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { // TODO: Share the struct between the various analyzers, that will allow us to share most of // the implementations here. + bool success = false; + + MemoryExceptionType type = MemoryExceptionType::NONE; #if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) // X86, X86-64. Variable instruction size so need to analyze the mov instruction in detail. // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC LSInstructionInfo info; - X86AnalyzeMOV(codePtr, info); + success = X86AnalyzeMOV(codePtr, info); #elif PPSSPP_ARCH(ARM64) uint32_t word; memcpy(&word, codePtr, 4); // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC Arm64LSInstructionInfo info; - Arm64AnalyzeLoadStore((uint64_t)codePtr, word, &info); + success = Arm64AnalyzeLoadStore((uint64_t)codePtr, word, &info); #elif PPSSPP_ARCH(ARM) uint32_t word; memcpy(&word, codePtr, 4); // To ignore the access, we need to disassemble the instruction and modify context->CTX_PC ArmLSInstructionInfo info; - ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info); + success = ArmAnalyzeLoadStore((uint32_t)codePtr, word, &info); #endif + if (success) { + if (info.isMemoryWrite) { + type = MemoryExceptionType::WRITE_WORD; + } else { + type = MemoryExceptionType::READ_WORD; + } + } - if (g_Config.bIgnoreBadMemAccess) { + if (success && g_Config.bIgnoreBadMemAccess) { if (!info.isMemoryWrite) { // It was a read. Fill the destination register with 0. // TODO @@ -546,6 +556,10 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { ERROR_LOG(MEMMAP, "Bad memory access detected and ignored: %08x (%p)", guestAddress, (void *)hostAddress); } } else { + // Either bIgnoreBadMemAccess is off, or we failed recovery analysis. + uint32_t approximatePC = currentMIPS->pc; + Core_MemoryException(guestAddress, currentMIPS->pc, type); + // Redirect execution to a crash handler that will exit the game. context->CTX_PC = (uintptr_t)MIPSComp::jit->GetCrashHandler(); ERROR_LOG(MEMMAP, "Bad memory access detected! %08x (%p) Stopping emulation.", guestAddress, (void *)hostAddress); diff --git a/UI/EmuScreen.cpp b/UI/EmuScreen.cpp index b624dd6186a3..7992aeab3155 100644 --- a/UI/EmuScreen.cpp +++ b/UI/EmuScreen.cpp @@ -1158,7 +1158,7 @@ void EmuScreen::update() { PSP_CoreParameter().pixelHeight = pixel_yres * bounds.h / dp_yres; #endif - if (!invalid_) { + if (!invalid_ && coreState != CORE_RUNTIME_ERROR) { UpdateUIState(UISTATE_INGAME); } From 6f97c3d4228a34f6c4dad0c0b724d38c758c0282 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 13 Jul 2020 09:17:42 +0200 Subject: [PATCH 14/17] Various platform buildfixes --- Common/ExceptionHandlerSetup.cpp | 3 ++- Core/Core.cpp | 1 + Core/Core.h | 1 + Core/CoreTiming.cpp | 5 +++++ Core/MIPS/ARM/ArmAsm.cpp | 2 +- Core/MIPS/ARM64/Arm64Asm.cpp | 2 +- Core/MemMap.cpp | 2 ++ Core/Util/DisArm64.cpp | 7 +++---- Core/Util/DisArm64.h | 6 ++---- ext/disarm.cpp | 4 +++- ext/disarm.h | 2 +- 11 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 7c8d64b1eb11..6cdbefede4f0 100644 --- a/Common/ExceptionHandlerSetup.cpp +++ b/Common/ExceptionHandlerSetup.cpp @@ -36,7 +36,8 @@ static BadAccessHandler g_badAccessHandler; -#ifdef _WIN32 +// We cannot handle exceptions in UWP builds. Bleh. +#if PPSSPP_PLATFORM(WINDOWS) && !PPSSPP_PLATFORM(UWP) static PVOID g_vectoredExceptionHandle; diff --git a/Core/Core.cpp b/Core/Core.cpp index ecc3d08259c4..dfb28a6fc890 100644 --- a/Core/Core.cpp +++ b/Core/Core.cpp @@ -395,6 +395,7 @@ const char *ExceptionTypeAsString(ExceptionType type) { const char *MemoryExceptionTypeAsString(MemoryExceptionType type) { switch (type) { + case MemoryExceptionType::UNKNOWN: return "Unknown"; case MemoryExceptionType::READ_WORD: return "Read Word"; case MemoryExceptionType::WRITE_WORD: return "Write Word"; case MemoryExceptionType::READ_BLOCK: return "Read Block"; diff --git a/Core/Core.h b/Core/Core.h index e7bdb5a46242..314a2823a15b 100644 --- a/Core/Core.h +++ b/Core/Core.h @@ -81,6 +81,7 @@ bool Core_GetPowerSaving(); enum class MemoryExceptionType { NONE, + UNKNOWN, READ_WORD, WRITE_WORD, READ_BLOCK, diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 2f0016d511e3..251a2c0f9e8c 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -97,6 +97,11 @@ void FireMhzChange() { } void SetClockFrequencyHz(int cpuHz) { + if (cpuHz <= 0) { + // Paranoid check, protecting against division by zero and similar nonsense. + return; + } + // When the mhz changes, we keep track of what "time" it was before hand. // This way, time always moves forward, even if mhz is changed. lastGlobalTimeUs = GetGlobalTimeUs(); diff --git a/Core/MIPS/ARM/ArmAsm.cpp b/Core/MIPS/ARM/ArmAsm.cpp index fa5a10195d2b..44176dc293f8 100644 --- a/Core/MIPS/ARM/ArmAsm.cpp +++ b/Core/MIPS/ARM/ArmAsm.cpp @@ -254,7 +254,7 @@ void ArmJit::GenerateFixedCode() { crashHandler = GetCodePtr(); MOVP2R(R0, &coreState); - MOVI2R(R1, CORE_ERROR); + MOVI2R(R1, CORE_RUNTIME_ERROR); STR(R1, R0, 0); B(quitLoop); diff --git a/Core/MIPS/ARM64/Arm64Asm.cpp b/Core/MIPS/ARM64/Arm64Asm.cpp index a884f6ac4efc..81f67fa3a351 100644 --- a/Core/MIPS/ARM64/Arm64Asm.cpp +++ b/Core/MIPS/ARM64/Arm64Asm.cpp @@ -289,7 +289,7 @@ void Arm64Jit::GenerateFixedCode(const JitOptions &jo) { crashHandler = GetCodePtr(); MOVP2R(SCRATCH1_64, &coreState); - MOVI2R(SCRATCH2, CORE_ERROR); + MOVI2R(SCRATCH2, CORE_RUNTIME_ERROR); STR(INDEX_UNSIGNED, SCRATCH2, SCRATCH1_64, 0); B(quitLoop); diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 9e8968fd8cc8..34d2b5f76de8 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -542,6 +542,8 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { } else { type = MemoryExceptionType::READ_WORD; } + } else { + type = MemoryExceptionType::UNKNOWN; } if (success && g_Config.bIgnoreBadMemAccess) { diff --git a/Core/Util/DisArm64.cpp b/Core/Util/DisArm64.cpp index c891b5eb0567..e6c983be554e 100644 --- a/Core/Util/DisArm64.cpp +++ b/Core/Util/DisArm64.cpp @@ -265,17 +265,15 @@ static void BranchExceptionAndSystem(uint32_t w, uint64_t addr, Instruction *ins } } -void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t w, Arm64LSInstructionInfo *info) { +bool Arm64AnalyzeLoadStore(uint64_t addr, uint32_t w, Arm64LSInstructionInfo *info) { *info = {}; info->instructionSize = 4; int id = (w >> 25) & 0xF; switch (id) { case 4: case 6: case 0xC: case 0xE: - info->isLoadOrStore = true; break; default: - ERROR_LOG(CPU, "Tried to disassemble %08x at %p as a load/store instruction", w, (void *)addr); - return; // not the expected instruction + return false; // not the expected instruction } info->size = w >> 30; @@ -298,6 +296,7 @@ void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t w, Arm64LSInstructionInfo *in info->isPairLoadStore = true; // TODO } + return true; } static void LoadStore(uint32_t w, uint64_t addr, Instruction *instr) { diff --git a/Core/Util/DisArm64.h b/Core/Util/DisArm64.h index 73b22db4bdfb..ced77f2cc269 100644 --- a/Core/Util/DisArm64.h +++ b/Core/Util/DisArm64.h @@ -18,7 +18,7 @@ // Basic ARM64 disassembler. // No promises of accuracy, mostly just made to debug JIT code. -#include +#include typedef bool (*SymbolCallback)(char *buffer, int bufsize, uint8_t *address); @@ -28,8 +28,6 @@ void Arm64Dis(uint64_t addr, uint32_t w, char *output, int bufsize, bool include struct Arm64LSInstructionInfo { int instructionSize; - bool isLoadOrStore; - bool isIntegerLoadStore; bool isFPLoadStore; bool isPairLoadStore; @@ -44,4 +42,4 @@ struct Arm64LSInstructionInfo { // TODO: more. }; -void Arm64AnalyzeLoadStore(uint64_t addr, uint32_t op, Arm64LSInstructionInfo *info); +bool Arm64AnalyzeLoadStore(uint64_t addr, uint32_t op, Arm64LSInstructionInfo *info); diff --git a/ext/disarm.cpp b/ext/disarm.cpp index c3d0662f3f12..ece10410f4fb 100644 --- a/ext/disarm.cpp +++ b/ext/disarm.cpp @@ -760,11 +760,13 @@ static bool DisasmNeon(uint32_t op, char *text) { return false; } -void ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info) { +bool ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info) { *info = {}; info->instructionSize = 4; // TODO + + return false; } diff --git a/ext/disarm.h b/ext/disarm.h index 138f3e3e69dd..901e74cd4fc2 100644 --- a/ext/disarm.h +++ b/ext/disarm.h @@ -47,4 +47,4 @@ struct ArmLSInstructionInfo { // TODO: more. }; -void ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info); +bool ArmAnalyzeLoadStore(uint32_t addr, uint32_t op, ArmLSInstructionInfo *info); From f6cc45a96a9caa3e23498e37386d2bf16caf9789 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Jul 2020 09:31:58 +0200 Subject: [PATCH 15/17] Another iOS buildfix attempt --- Core/MemMap.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index 34d2b5f76de8..c935d6b99b16 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -43,7 +43,7 @@ #include "Core/Util/DisArm64.h" typedef sigcontext SContext; #define CTX_PC pc -#elif PPSSPP_ARCH(ARM) +#elif PPSSPP_ARCH(ARM) && !PPSSPP_PLATFORM(IOS) #include "ext/disarm.h" typedef sigcontext SContext; #define CTX_PC arm_pc @@ -245,16 +245,22 @@ bool MemoryMap_Setup(u32 flags) { #if !PPSSPP_PLATFORM(ANDROID) if (g_arena.NeedsProbing()) { int base_attempts = 0; -#if defined(_WIN32) && PPSSPP_ARCH(32BIT) +#if PPSSPP_PLATFORM(WINDOWS) && PPSSPP_ARCH(32BIT) // Try a whole range of possible bases. Return once we got a valid one. uintptr_t max_base_addr = 0x7FFF0000 - 0x10000000; uintptr_t min_base_addr = 0x01000000; uintptr_t stride = 0x400000; -#else +#elif PPSSPP_ARCH(ARM64) && PPSSPP_PLATFORM(IOS) // iOS uintptr_t max_base_addr = 0x1FFFF0000ULL - 0x80000000ULL; uintptr_t min_base_addr = 0x100000000ULL; uintptr_t stride = 0x800000; +#else + uintptr_t max_base_addr = 0; + uintptr_t min_base_addr = 0; + uintptr_t stride = 0; + ERROR_LOG(MEMMAP, "MemoryMap_Setup: Hit a wrong path, should not be needed on this platform."); + return false; #endif for (uintptr_t base_addr = min_base_addr; base_addr < max_base_addr; base_addr += stride) { base_attempts++; From 893aa29191fe3aeef808102f1827552ba2c2ccf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Jul 2020 10:34:40 +0200 Subject: [PATCH 16/17] Yet another iOS buildfix attempt --- Core/MemMap.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index c935d6b99b16..b20a39d783f4 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -489,6 +489,10 @@ void Memset(const u32 _Address, const u8 _iValue, const u32 _iLength) { CBreakPoints::ExecMemCheck(_Address, true, _iLength, currentMIPS->pc); } +// We do not support crash catching on UWP and iOS. +// On iOS, the sigcontext struct seems to be missing?? +#if !PPSSPP_PLATFORM(IOS) && !PPSSPP_PLATFORM(UWP) + bool HandleFault(uintptr_t hostAddress, void *ctx) { SContext *context = (SContext *)ctx; const uint8_t *codePtr = (uint8_t *)(context->CTX_PC); @@ -575,4 +579,13 @@ bool HandleFault(uintptr_t hostAddress, void *ctx) { return true; } +#else + +bool HandleFault(uintptr_t hostAddress, void *ctx) { + ERROR_LOG(MEMMAP, "Exception handling not supported"); + return false; +} + +#endif + } // namespace From f62df94ab2ad86550276a21c91043de1559b926e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Tue, 14 Jul 2020 11:39:18 +0200 Subject: [PATCH 17/17] There's no sigcontext on 64-bit iOS either, apparently. --- Core/MemMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/MemMap.cpp b/Core/MemMap.cpp index b20a39d783f4..4c36b7c6087c 100644 --- a/Core/MemMap.cpp +++ b/Core/MemMap.cpp @@ -39,7 +39,7 @@ #if PPSSPP_ARCH(AMD64) || PPSSPP_ARCH(X86) #include "Common/MachineContext.h" #include "Common/x64Analyzer.h" -#elif PPSSPP_ARCH(ARM64) +#elif PPSSPP_ARCH(ARM64) && !PPSSPP_PLATFORM(IOS) #include "Core/Util/DisArm64.h" typedef sigcontext SContext; #define CTX_PC pc