Skip bad reads/writes by the guest executable.

This commit is contained in:
Henrik Rydgard 2019-02-12 10:08:11 +01:00 committed by Henrik Rydgård
parent 1fce6de8b1
commit aa802ecc0f
4 changed files with 59 additions and 24 deletions

View file

@ -90,6 +90,7 @@ void InstallExceptionHandler(BadAccessHandler badAccessHandler) {
void UninstallExceptionHandler() {
RemoveVectoredExceptionHandler(g_vectoredExceptionHandle);
g_badAccessHandler = nullptr;
}
#elif defined(__APPLE__) && !defined(USE_SIGACTION_ON_APPLE)

View file

@ -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)
{

View file

@ -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);

View file

@ -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