Remove accessType from BackPatch's signature in favor of getting it from DisassembleMov.

It isn't easily accessible with sigaction or Mach exceptions (well,
requires an additional system call in the latter), and isn't necessary.

(and get rid of the enum, because it's only used once, and the comments
are more expressive than enum names)
This commit is contained in:
comex 2013-09-02 16:37:04 -04:00
parent e198e201e4
commit 4c3230bcde
9 changed files with 109 additions and 129 deletions

View File

@ -4,7 +4,7 @@
#include "x64Analyzer.h"
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType)
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info)
{
unsigned const char *startCodePtr = codePtr;
u8 rex = 0;
@ -12,11 +12,11 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
u8 codeByte2 = 0;
//Check for regular prefix
info.operandSize = 4;
info.zeroExtend = false;
info.signExtend = false;
info.hasImmediate = false;
info.isMemoryWrite = false;
info->operandSize = 4;
info->zeroExtend = false;
info->signExtend = false;
info->hasImmediate = false;
info->isMemoryWrite = false;
u8 modRMbyte = 0;
u8 sibByte = 0;
@ -26,7 +26,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
if (*codePtr == 0x66)
{
info.operandSize = 2;
info->operandSize = 2;
codePtr++;
}
else if (*codePtr == 0x67)
@ -40,7 +40,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
rex = *codePtr;
if (rex & 8) //REX.W
{
info.operandSize = 8;
info->operandSize = 8;
}
codePtr++;
}
@ -85,21 +85,21 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
if (hasModRM)
{
ModRM mrm(modRMbyte, rex);
info.regOperandReg = mrm.reg;
info->regOperandReg = mrm.reg;
if (mrm.mod < 3)
{
if (mrm.rm == 4)
{
//SIB byte
sibByte = *codePtr++;
info.scaledReg = (sibByte >> 3) & 7;
info.otherReg = (sibByte & 7);
if (rex & 2) info.scaledReg += 8;
if (rex & 1) info.otherReg += 8;
info->scaledReg = (sibByte >> 3) & 7;
info->otherReg = (sibByte & 7);
if (rex & 2) info->scaledReg += 8;
if (rex & 1) info->otherReg += 8;
}
else
{
//info.scaledReg =
//info->scaledReg =
}
}
if (mrm.mod == 1 || mrm.mod == 2)
@ -112,100 +112,103 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
}
if (displacementSize == 1)
info.displacement = (s32)(s8)*codePtr;
info->displacement = (s32)(s8)*codePtr;
else
info.displacement = *((s32 *)codePtr);
info->displacement = *((s32 *)codePtr);
codePtr += displacementSize;
if (accessType == 1)
switch (codeByte)
{
info.isMemoryWrite = true;
//Write access
switch (codeByte)
// writes
case 0xC6: // mem <- imm8
{
case MOVE_8BIT: //move 8-bit immediate
{
info.hasImmediate = true;
info.immediate = *codePtr;
codePtr++; //move past immediate
}
break;
case MOVE_16_32BIT: //move 16 or 32-bit immediate, easiest case for writes
{
if (info.operandSize == 2)
{
info.hasImmediate = true;
info.immediate = *(u16*)codePtr;
codePtr += 2;
}
else if (info.operandSize == 4)
{
info.hasImmediate = true;
info.immediate = *(u32*)codePtr;
codePtr += 4;
}
else if (info.operandSize == 8)
{
info.zeroExtend = true;
info.immediate = *(u32*)codePtr;
codePtr += 4;
}
}
break;
case MOVE_REG_TO_MEM: //move reg to memory
break;
default:
PanicAlert("Unhandled disasm case in write handler!\n\nPlease implement or avoid.");
return false;
info->isMemoryWrite = true;
info->hasImmediate = true;
info->immediate = *codePtr;
codePtr++; //move past immediate
}
}
else
{
// Memory read
break;
//mov eax, dword ptr [rax] == 8b 00
switch (codeByte)
case 0xC7: // mem <- imm16/32
{
case 0x0F:
info->isMemoryWrite = true;
if (info->operandSize == 2)
{
info->hasImmediate = true;
info->immediate = *(u16*)codePtr;
codePtr += 2;
}
else if (info->operandSize == 4)
{
info->hasImmediate = true;
info->immediate = *(u32*)codePtr;
codePtr += 4;
}
else if (info->operandSize == 8)
{
info->zeroExtend = true;
info->immediate = *(u32*)codePtr;
codePtr += 4;
}
}
case 0x89: // mem <- r16/32/64
{
info->isMemoryWrite = true;
break;
}
case 0x0F: // two-byte escape
{
info->isMemoryWrite = false;
switch (codeByte2)
{
case MOVZX_BYTE: //movzx on byte
info.zeroExtend = true;
info.operandSize = 1;
case 0xB6: // movzx on byte
info->zeroExtend = true;
info->operandSize = 1;
break;
case MOVZX_SHORT: //movzx on short
info.zeroExtend = true;
info.operandSize = 2;
case 0xB7: // movzx on short
info->zeroExtend = true;
info->operandSize = 2;
break;
case MOVSX_BYTE: //movsx on byte
info.signExtend = true;
info.operandSize = 1;
case 0xBE: // movsx on byte
info->signExtend = true;
info->operandSize = 1;
break;
case MOVSX_SHORT: //movsx on short
info.signExtend = true;
info.operandSize = 2;
case 0xBF: // movsx on short
info->signExtend = true;
info->operandSize = 2;
break;
default:
return false;
}
break;
case 0x8a:
if (info.operandSize == 4)
}
case 0x8A: // r8 <- mem
{
info->isMemoryWrite = false;
if (info->operandSize == 4)
{
info.operandSize = 1;
info->operandSize = 1;
break;
}
else
return false;
case 0x8b:
break; //it's OK don't need to do anything
default:
return false;
}
case 0x8B: // r16/32/64 <- mem
{
info->isMemoryWrite = false;
break;
}
break;
default:
return false;
}
info.instructionSize = (int)(codePtr - startCodePtr);
info->instructionSize = (int)(codePtr - startCodePtr);
return true;
}

View File

@ -33,21 +33,12 @@ struct ModRM
}
};
enum{
MOVZX_BYTE = 0xB6, //movzx on byte
MOVZX_SHORT = 0xB7, //movzx on short
MOVSX_BYTE = 0xBE, //movsx on byte
MOVSX_SHORT = 0xBF, //movsx on short
MOVE_8BIT = 0xC6, //move 8-bit immediate
MOVE_16_32BIT = 0xC7, //move 16 or 32-bit immediate
MOVE_REG_TO_MEM = 0x89, //move reg to memory
};
enum AccessType{
enum AccessType
{
OP_ACCESS_READ = 0,
OP_ACCESS_WRITE = 1
};
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int accessType);
bool DisassembleMov(const unsigned char *codePtr, InstructionInfo *info);
#endif // _X64ANALYZER_H_

View File

@ -81,11 +81,9 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
u32 em_address = (u32)(bad_address - memspace_bottom);
int access_type = 0;
CONTEXT fake_ctx;
fake_ctx.reg_pc = ctx->arm_pc;
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, access_type, em_address, &fake_ctx);
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, &fake_ctx);
if (new_rip) {
ctx->arm_pc = fake_ctx.reg_pc;
}

View File

@ -96,7 +96,7 @@ bool DisamLoadStore(const u32 inst, ARMReg &rD, u8 &accessSize, bool &Store)
}
return true;
}
const u8 *JitArm::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void *ctx_void)
const u8 *JitArm::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void)
{
// TODO: This ctx needs to be filled with our information
CONTEXT *ctx = (CONTEXT *)ctx_void;

View File

@ -160,7 +160,7 @@ const u8 *TrampolineCache::GetWriteTrampoline(const InstructionInfo &info)
// 1) It's really necessary. We don't know anything about the context.
// 2) It doesn't really hurt. Only instructions that access I/O will get these, and there won't be
// that many of them in a typical program/game.
const u8 *Jitx86Base::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void *ctx_void)
const u8 *Jitx86Base::BackPatch(u8 *codePtr, u32 emAddress, void *ctx_void)
{
#ifdef _M_X64
CONTEXT *ctx = (CONTEXT *)ctx_void;
@ -169,29 +169,15 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void
return 0; // this will become a regular crash real soon after this
InstructionInfo info;
if (!DisassembleMov(codePtr, info, accessType)) {
if (!DisassembleMov(codePtr, &info)) {
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress);
}
/*
if (info.isMemoryWrite) {
if (!Memory::IsRAMAddress(emAddress, true)) {
PanicAlert("Exception: Caught write to invalid address %08x", emAddress);
return;
}
BackPatchError("BackPatch - determined that MOV is write, not yet supported and should have been caught before",
codePtr, emAddress);
}*/
if (info.otherReg != RBX)
PanicAlert("BackPatch : Base reg not RBX."
"\n\nAttempted to access %08x.", emAddress);
if (accessType == OP_ACCESS_WRITE)
PanicAlert("BackPatch : Currently only supporting reads."
"\n\nAttempted to write to %08x.", emAddress);
if (accessType == 0)
if (!info.isMemoryWrite)
{
XEmitter emitter(codePtr);
int bswapNopCount;
@ -205,8 +191,11 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void
emitter.NOP((int)info.instructionSize + bswapNopCount - 5);
return codePtr;
}
else if (accessType == 1)
else
{
PanicAlert("BackPatch : Currently only supporting reads."
"\n\nAttempted to write to %08x.", emAddress);
// TODO: special case FIFO writes. Also, support 32-bit mode.
// Also, debug this so that it actually works correctly :P
XEmitter emitter(codePtr - 2);

View File

@ -74,7 +74,7 @@ public:
virtual void Jit(u32 em_address) = 0;
virtual const u8 *BackPatch(u8 *codePtr, int accessType, u32 em_address, void *ctx) = 0;
virtual const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx) = 0;
virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0;
@ -89,7 +89,7 @@ protected:
public:
JitBlockCache *GetBlockCache() { return &blocks; }
const u8 *BackPatch(u8 *codePtr, int accessType, u32 em_address, void *ctx);
const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx);
bool IsInCodeSpace(u8 *ptr) { return IsInSpace(ptr); }
};

View File

@ -175,9 +175,9 @@ namespace JitInterface
{
return jit->IsInCodeSpace(ptr);
}
const u8 *BackPatch(u8 *codePtr, int accessType, u32 em_address, void *ctx)
const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx)
{
return jit->BackPatch(codePtr, accessType, em_address, ctx);
return jit->BackPatch(codePtr, em_address, ctx);
}
void ClearCache()

View File

@ -18,7 +18,7 @@ namespace JitInterface
// Memory Utilities
bool IsInCodeSpace(u8 *ptr);
const u8 *BackPatch(u8 *codePtr, int accessType, u32 em_address, void *ctx);
const u8 *BackPatch(u8 *codePtr, u32 em_address, void *ctx);
// used by JIT to read instructions
u32 Read_Opcode_JIT(const u32 _Address);

View File

@ -99,7 +99,7 @@ LONG NTAPI Handler(PEXCEPTION_POINTERS pPtrs)
//We could emulate the memory accesses here, but then they would still be around to take up
//execution resources. Instead, we backpatch into a generic memory call and retry.
const u8 *new_rip = JitInterface::BackPatch(codePtr, accessType, emAddress, ctx);
const u8 *new_rip = JitInterface::BackPatch(codePtr, emAddress, ctx);
// Rip/Eip needs to be updated.
if (new_rip)
@ -214,7 +214,6 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
// Backpatch time.
// Seems we'll need to disassemble to get access_type - that work is probably
// best done and debugged on the Windows side.
int access_type = 0;
CONTEXT fake_ctx;
@ -225,7 +224,7 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
fake_ctx.Eax = CREG_EAX(ctx);
fake_ctx.Eip = CREG_EIP(ctx);
#endif
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, access_type, em_address, &fake_ctx);
const u8 *new_rip = jit->BackPatch(fault_instruction_ptr, em_address, &fake_ctx);
if (new_rip)
{
#ifdef _M_X64