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" #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; unsigned const char *startCodePtr = codePtr;
u8 rex = 0; u8 rex = 0;
@ -12,11 +12,11 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
u8 codeByte2 = 0; u8 codeByte2 = 0;
//Check for regular prefix //Check for regular prefix
info.operandSize = 4; info->operandSize = 4;
info.zeroExtend = false; info->zeroExtend = false;
info.signExtend = false; info->signExtend = false;
info.hasImmediate = false; info->hasImmediate = false;
info.isMemoryWrite = false; info->isMemoryWrite = false;
u8 modRMbyte = 0; u8 modRMbyte = 0;
u8 sibByte = 0; u8 sibByte = 0;
@ -26,7 +26,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
if (*codePtr == 0x66) if (*codePtr == 0x66)
{ {
info.operandSize = 2; info->operandSize = 2;
codePtr++; codePtr++;
} }
else if (*codePtr == 0x67) else if (*codePtr == 0x67)
@ -40,7 +40,7 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
rex = *codePtr; rex = *codePtr;
if (rex & 8) //REX.W if (rex & 8) //REX.W
{ {
info.operandSize = 8; info->operandSize = 8;
} }
codePtr++; codePtr++;
} }
@ -72,11 +72,11 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
(codeByte2 & 0xF0) == 0x80 || (codeByte2 & 0xF0) == 0x80 ||
((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) || ((codeByte2 & 0xF0) == 0xA0 && (codeByte2 & 0x07) <= 0x02) ||
(codeByte2 & 0xF8) == 0xC8) (codeByte2 & 0xF8) == 0xC8)
{ {
// No mod R/M byte // No mod R/M byte
} }
else else
{ {
modRMbyte = *codePtr++; modRMbyte = *codePtr++;
hasModRM = true; hasModRM = true;
} }
@ -85,21 +85,21 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
if (hasModRM) if (hasModRM)
{ {
ModRM mrm(modRMbyte, rex); ModRM mrm(modRMbyte, rex);
info.regOperandReg = mrm.reg; info->regOperandReg = mrm.reg;
if (mrm.mod < 3) if (mrm.mod < 3)
{ {
if (mrm.rm == 4) if (mrm.rm == 4)
{ {
//SIB byte //SIB byte
sibByte = *codePtr++; sibByte = *codePtr++;
info.scaledReg = (sibByte >> 3) & 7; info->scaledReg = (sibByte >> 3) & 7;
info.otherReg = (sibByte & 7); info->otherReg = (sibByte & 7);
if (rex & 2) info.scaledReg += 8; if (rex & 2) info->scaledReg += 8;
if (rex & 1) info.otherReg += 8; if (rex & 1) info->otherReg += 8;
} }
else else
{ {
//info.scaledReg = //info->scaledReg =
} }
} }
if (mrm.mod == 1 || mrm.mod == 2) if (mrm.mod == 1 || mrm.mod == 2)
@ -112,100 +112,103 @@ bool DisassembleMov(const unsigned char *codePtr, InstructionInfo &info, int acc
} }
if (displacementSize == 1) if (displacementSize == 1)
info.displacement = (s32)(s8)*codePtr; info->displacement = (s32)(s8)*codePtr;
else else
info.displacement = *((s32 *)codePtr); info->displacement = *((s32 *)codePtr);
codePtr += displacementSize; codePtr += displacementSize;
if (accessType == 1) switch (codeByte)
{ {
info.isMemoryWrite = true; // writes
//Write access case 0xC6: // mem <- imm8
switch (codeByte)
{ {
case MOVE_8BIT: //move 8-bit immediate info->isMemoryWrite = true;
{ info->hasImmediate = true;
info.hasImmediate = true; info->immediate = *codePtr;
info.immediate = *codePtr; codePtr++; //move past immediate
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;
} }
} break;
else
{
// Memory read
//mov eax, dword ptr [rax] == 8b 00 case 0xC7: // mem <- imm16/32
switch (codeByte)
{ {
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) switch (codeByte2)
{ {
case MOVZX_BYTE: //movzx on byte case 0xB6: // movzx on byte
info.zeroExtend = true; info->zeroExtend = true;
info.operandSize = 1; info->operandSize = 1;
break; break;
case MOVZX_SHORT: //movzx on short case 0xB7: // movzx on short
info.zeroExtend = true; info->zeroExtend = true;
info.operandSize = 2; info->operandSize = 2;
break; break;
case MOVSX_BYTE: //movsx on byte case 0xBE: // movsx on byte
info.signExtend = true; info->signExtend = true;
info.operandSize = 1; info->operandSize = 1;
break; break;
case MOVSX_SHORT: //movsx on short case 0xBF: // movsx on short
info.signExtend = true; info->signExtend = true;
info.operandSize = 2; info->operandSize = 2;
break; break;
default: default:
return false; return false;
} }
break; 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; break;
} }
else else
return false; 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; return true;
} }

View File

@ -33,21 +33,12 @@ struct ModRM
} }
}; };
enum{ enum AccessType
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{
OP_ACCESS_READ = 0, OP_ACCESS_READ = 0,
OP_ACCESS_WRITE = 1 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_ #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); u32 em_address = (u32)(bad_address - memspace_bottom);
int access_type = 0;
CONTEXT fake_ctx; CONTEXT fake_ctx;
fake_ctx.reg_pc = ctx->arm_pc; 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) { if (new_rip) {
ctx->arm_pc = fake_ctx.reg_pc; 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; 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 // TODO: This ctx needs to be filled with our information
CONTEXT *ctx = (CONTEXT *)ctx_void; 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. // 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 // 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. // 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 #ifdef _M_X64
CONTEXT *ctx = (CONTEXT *)ctx_void; 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 return 0; // this will become a regular crash real soon after this
InstructionInfo info; InstructionInfo info;
if (!DisassembleMov(codePtr, info, accessType)) { if (!DisassembleMov(codePtr, &info)) {
BackPatchError("BackPatch - failed to disassemble MOV instruction", codePtr, emAddress); 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) if (info.otherReg != RBX)
PanicAlert("BackPatch : Base reg not RBX." PanicAlert("BackPatch : Base reg not RBX."
"\n\nAttempted to access %08x.", emAddress); "\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); XEmitter emitter(codePtr);
int bswapNopCount; int bswapNopCount;
@ -205,8 +191,11 @@ const u8 *Jitx86Base::BackPatch(u8 *codePtr, int accessType, u32 emAddress, void
emitter.NOP((int)info.instructionSize + bswapNopCount - 5); emitter.NOP((int)info.instructionSize + bswapNopCount - 5);
return codePtr; 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. // TODO: special case FIFO writes. Also, support 32-bit mode.
// Also, debug this so that it actually works correctly :P // Also, debug this so that it actually works correctly :P
XEmitter emitter(codePtr - 2); XEmitter emitter(codePtr - 2);

View File

@ -74,7 +74,7 @@ public:
virtual void Jit(u32 em_address) = 0; 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; virtual const CommonAsmRoutinesBase *GetAsmRoutines() = 0;
@ -89,7 +89,7 @@ protected:
public: public:
JitBlockCache *GetBlockCache() { return &blocks; } 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); } bool IsInCodeSpace(u8 *ptr) { return IsInSpace(ptr); }
}; };

View File

@ -175,9 +175,9 @@ namespace JitInterface
{ {
return jit->IsInCodeSpace(ptr); 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() void ClearCache()

View File

@ -18,7 +18,7 @@ namespace JitInterface
// Memory Utilities // Memory Utilities
bool IsInCodeSpace(u8 *ptr); 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 // used by JIT to read instructions
u32 Read_Opcode_JIT(const u32 _Address); 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 //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. //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. // Rip/Eip needs to be updated.
if (new_rip) if (new_rip)
@ -214,7 +214,6 @@ void sigsegv_handler(int signal, siginfo_t *info, void *raw_context)
// Backpatch time. // Backpatch time.
// Seems we'll need to disassemble to get access_type - that work is probably // Seems we'll need to disassemble to get access_type - that work is probably
// best done and debugged on the Windows side. // best done and debugged on the Windows side.
int access_type = 0;
CONTEXT fake_ctx; 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.Eax = CREG_EAX(ctx);
fake_ctx.Eip = CREG_EIP(ctx); fake_ctx.Eip = CREG_EIP(ctx);
#endif #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) if (new_rip)
{ {
#ifdef _M_X64 #ifdef _M_X64