From aa802ecc0f2697f10562be5187ae9169c13ae818 Mon Sep 17 00:00:00 2001 From: Henrik Rydgard Date: Tue, 12 Feb 2019 10:08:11 +0100 Subject: [PATCH] Skip bad reads/writes by the guest executable. --- Common/ExceptionHandlerSetup.cpp | 1 + Common/x64Analyzer.cpp | 11 ++++- Common/x64Analyzer.h | 2 +- Core/MemMap.cpp | 69 ++++++++++++++++++++++---------- 4 files changed, 59 insertions(+), 24 deletions(-) diff --git a/Common/ExceptionHandlerSetup.cpp b/Common/ExceptionHandlerSetup.cpp index 098b603209..f538efb5a1 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 1940416d6a..42095b03c9 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 ad2fed886d..d448d4c60f 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 93d2029da2..af47ce6668 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. - - 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; + 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; } - // A regular crash of some sort. Pass it on. - return false; + uintptr_t baseAddress = (uintptr_t)base; +#ifdef MASKED_PSP_MEMORY + 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 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; + } + + // 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