distorm starts to work
This commit is contained in:
parent
a6ec272604
commit
5acc167a07
Binary file not shown.
|
@ -145,83 +145,13 @@ extern "C" CXBXKRNL_API void NTAPI EmuWarning(const char *szWarningMessage, ...)
|
|||
}
|
||||
#endif
|
||||
|
||||
// exception handler
|
||||
extern int EmuException(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
g_bEmuException = true;
|
||||
|
||||
// notify user
|
||||
{
|
||||
char buffer[256];
|
||||
|
||||
if(e->ExceptionRecord->ExceptionCode == 0x80000003)
|
||||
void EmuExceptionPrintDebugInformation(LPEXCEPTION_POINTERS e, bool IsBreakpointException)
|
||||
{
|
||||
// print debug information
|
||||
{
|
||||
if (IsBreakpointException)
|
||||
printf("EmuMain (0x%X): Recieved Breakpoint Exception (int 3)\n", GetCurrentThreadId());
|
||||
|
||||
printf("\n"
|
||||
" EIP := 0x%.08X EFL := 0x%.08X\n"
|
||||
" EAX := 0x%.08X EBX := 0x%.08X ECX := 0x%.08X EDX := 0x%.08X\n"
|
||||
" ESI := 0x%.08X EDI := 0x%.08X ESP := 0x%.08X EBP := 0x%.08X\n"
|
||||
" CR2 := 0x%.08X\n"
|
||||
"\n",
|
||||
e->ContextRecord->Eip, e->ContextRecord->EFlags,
|
||||
e->ContextRecord->Eax, e->ContextRecord->Ebx, e->ContextRecord->Ecx, e->ContextRecord->Edx,
|
||||
e->ContextRecord->Esi, e->ContextRecord->Edi, e->ContextRecord->Esp, e->ContextRecord->Ebp,
|
||||
e->ContextRecord->Dr2);
|
||||
|
||||
#ifdef _DEBUG
|
||||
CONTEXT Context = *(e->ContextRecord);
|
||||
EmuPrintStackTrace(&Context);
|
||||
#endif
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
sprintf(buffer,
|
||||
"Recieved Breakpoint Exception (int 3) @ EIP := 0x%.08X\n"
|
||||
"\n"
|
||||
" Press Abort to terminate emulation.\n"
|
||||
" Press Retry to debug.\n"
|
||||
" Press Ignore to continue emulation.",
|
||||
e->ContextRecord->Eip);
|
||||
|
||||
e->ContextRecord->Eip += 1;
|
||||
|
||||
int ret = MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_ABORTRETRYIGNORE);
|
||||
|
||||
if(ret == IDABORT)
|
||||
{
|
||||
printf("EmuMain (0x%X): Aborting Emulation\n", GetCurrentThreadId());
|
||||
fflush(stdout);
|
||||
|
||||
if(CxbxKrnl_hEmuParent != NULL)
|
||||
SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0);
|
||||
|
||||
ExitProcess(1);
|
||||
}
|
||||
else if(ret == IDIGNORE)
|
||||
{
|
||||
printf("EmuMain (0x%X): Ignored Breakpoint Exception\n", GetCurrentThreadId());
|
||||
|
||||
g_bEmuException = false;
|
||||
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pass the exception to our X86 implementation, to try and execute the failing instruction
|
||||
if (EmuX86_DecodeException(e))
|
||||
{
|
||||
g_bEmuException = false;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
|
||||
// print debug information
|
||||
{
|
||||
printf("EmuMain (0x%X): Recieved Exception (Code := 0x%.08X)\n", GetCurrentThreadId(), e->ExceptionRecord->ExceptionCode);
|
||||
|
||||
printf("\n"
|
||||
|
@ -242,15 +172,9 @@ extern int EmuException(LPEXCEPTION_POINTERS e)
|
|||
}
|
||||
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
sprintf(buffer,
|
||||
"Recieved Exception Code 0x%.08X @ EIP := 0x%.08X\n"
|
||||
"\n"
|
||||
" Press \"OK\" to terminate emulation.\n"
|
||||
" Press \"Cancel\" to debug.",
|
||||
e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip);
|
||||
|
||||
if(MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_OKCANCEL) == IDOK)
|
||||
void EmuExceptionExitProcess()
|
||||
{
|
||||
printf("EmuMain (0x%X): Aborting Emulation\n", GetCurrentThreadId());
|
||||
fflush(stdout);
|
||||
|
@ -260,11 +184,86 @@ extern int EmuException(LPEXCEPTION_POINTERS e)
|
|||
|
||||
ExitProcess(1);
|
||||
}
|
||||
|
||||
bool EmuExceptionBreakpointAsk(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
EmuExceptionPrintDebugInformation(e, /*IsBreakpointException=*/true);
|
||||
|
||||
char buffer[256];
|
||||
sprintf(buffer,
|
||||
"Recieved Breakpoint Exception (int 3) @ EIP := 0x%.08X\n"
|
||||
"\n"
|
||||
" Press Abort to terminate emulation.\n"
|
||||
" Press Retry to debug.\n"
|
||||
" Press Ignore to continue emulation.",
|
||||
e->ContextRecord->Eip);
|
||||
|
||||
int ret = MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_ABORTRETRYIGNORE);
|
||||
if (ret == IDABORT)
|
||||
{
|
||||
EmuExceptionExitProcess();
|
||||
}
|
||||
else if (ret == IDIGNORE)
|
||||
{
|
||||
printf("EmuMain (0x%X): Ignored Breakpoint Exception\n", GetCurrentThreadId());
|
||||
fflush(stdout);
|
||||
|
||||
e->ContextRecord->Eip += 1; // TODO : Skip actual instruction size bytes
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void EmuExceptionNonBreakpointUnhandledShow(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
EmuExceptionPrintDebugInformation(e, /*IsBreakpointException=*/false);
|
||||
|
||||
char buffer[256];
|
||||
sprintf(buffer,
|
||||
"Recieved Exception Code 0x%.08X @ EIP := 0x%.08X\n"
|
||||
"\n"
|
||||
" Press \"OK\" to terminate emulation.\n"
|
||||
" Press \"Cancel\" to debug.",
|
||||
e->ExceptionRecord->ExceptionCode, e->ContextRecord->Eip);
|
||||
|
||||
if (MessageBox(g_hEmuWindow, buffer, "Cxbx-Reloaded", MB_ICONSTOP | MB_OKCANCEL) == IDOK)
|
||||
{
|
||||
EmuExceptionExitProcess();
|
||||
}
|
||||
}
|
||||
|
||||
// exception handler
|
||||
extern int EmuException(LPEXCEPTION_POINTERS e)
|
||||
{
|
||||
g_bEmuException = true;
|
||||
if (e->ExceptionRecord->ExceptionCode == STATUS_BREAKPOINT)
|
||||
{
|
||||
// notify user
|
||||
if (EmuExceptionBreakpointAsk(e))
|
||||
{
|
||||
// We're allowed to continue :
|
||||
g_bEmuException = false;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pass the exception to our X86 implementation, to try and execute the failing instruction
|
||||
if (EmuX86_DecodeException(e))
|
||||
{
|
||||
// We're allowed to continue :
|
||||
g_bEmuException = false;
|
||||
return EXCEPTION_CONTINUE_EXECUTION;
|
||||
}
|
||||
|
||||
// notify user
|
||||
EmuExceptionNonBreakpointUnhandledShow(e);
|
||||
}
|
||||
|
||||
// Unhandled exception :
|
||||
g_bEmuException = false;
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
}
|
||||
|
||||
|
|
|
@ -101,9 +101,9 @@ uint16_t EmuX86_Read16(uint32_t addr)
|
|||
EmuWarning("EmuX86_Read16(0x%08X) Forwarding to EmuX86_Read32...", addr);
|
||||
uint16_t value;
|
||||
if (addr & 2)
|
||||
value = (uint16_t)EmuX86_Read32(addr - 2);
|
||||
value = (uint16_t)(EmuX86_Read32(addr - 2) >> 16);
|
||||
else
|
||||
value = (uint16_t)(EmuX86_Read32(addr) >> 16);
|
||||
value = (uint16_t)EmuX86_Read32(addr);
|
||||
|
||||
EmuWarning("EmuX86_Read16(0x%08X) = 0x%04X", addr, value);
|
||||
return value;
|
||||
|
@ -114,9 +114,9 @@ uint8_t EmuX86_Read8(uint32_t addr)
|
|||
EmuWarning("EmuX86_Read8(0x%08X) Forwarding to EmuX86_Read16...", addr);
|
||||
uint8_t value;
|
||||
if (addr & 1)
|
||||
value = (uint8_t)EmuX86_Read16(addr - 1);
|
||||
value = (uint8_t)(EmuX86_Read16(addr - 1) >> 8);
|
||||
else
|
||||
value = (uint8_t)(EmuX86_Read16(addr) >> 8);
|
||||
value = (uint8_t)EmuX86_Read16(addr);
|
||||
|
||||
EmuWarning("EmuX86_Read8(0x%08X) = 0x%02X", addr, value);
|
||||
return value;
|
||||
|
@ -180,41 +180,31 @@ inline bool EmuX86_GetRegisterValue(uint32_t* output, LPEXCEPTION_POINTERS e, ui
|
|||
return true;
|
||||
}
|
||||
|
||||
inline bool EmuX86_DecodeMemoryOperand(uint32_t* output, LPEXCEPTION_POINTERS e, _DInst& info, int operand)
|
||||
uint32_t EmuX86_Distorm_O_SMEM_Addr(LPEXCEPTION_POINTERS e, _DInst& info, int operand)
|
||||
{
|
||||
uint32_t base;
|
||||
EmuX86_GetRegisterValue(&base, e, info.ops[operand].index);
|
||||
|
||||
return base + info.disp;
|
||||
}
|
||||
|
||||
uint32_t EmuX86_Distorm_O_MEM_Addr(LPEXCEPTION_POINTERS e, _DInst& info, int operand)
|
||||
{
|
||||
uint32_t base = 0;
|
||||
EmuX86_GetRegisterValue(&base, e, info.base);
|
||||
|
||||
uint32_t index = 0;
|
||||
if (!EmuX86_GetRegisterValue(&base, e, info.ops[operand].index) || !EmuX86_GetRegisterValue(&index, e, info.ops[operand].index)) {
|
||||
return false;
|
||||
EmuX86_GetRegisterValue(&index, e, info.ops[operand].index);
|
||||
|
||||
if (info.scale >= 2)
|
||||
return base + (index * info.scale) + info.disp;
|
||||
else
|
||||
return base + index + info.disp;
|
||||
}
|
||||
|
||||
*output = base + (index * info.scale) + info.imm.dword;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operand, OUT uint32_t *value)
|
||||
void EmuX86_ReadAddr(uint32_t srcAddr, uint16_t size, OUT uint32_t *value)
|
||||
{
|
||||
switch (info.ops[operand].type) {
|
||||
// TODO : other operand.type
|
||||
case O_IMM:
|
||||
{
|
||||
*value = info.imm.dword;
|
||||
break;
|
||||
}
|
||||
case O_REG:
|
||||
{
|
||||
if (!EmuX86_GetRegisterValue(value, e, info.ops[operand].index))
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
case O_MEM:
|
||||
{
|
||||
uint32_t srcAddr = 0;
|
||||
if (!EmuX86_DecodeMemoryOperand(&srcAddr, e, info, operand))
|
||||
return false;
|
||||
|
||||
switch (info.ops[operand].size) {
|
||||
switch (size) {
|
||||
case 8:
|
||||
*value = EmuX86_Read8(srcAddr);
|
||||
break;
|
||||
|
@ -225,10 +215,97 @@ bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operan
|
|||
*value = EmuX86_Read32(srcAddr);
|
||||
break;
|
||||
default:
|
||||
// TODO : Handle other sizes?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EmuX86_WriteAddr(uint32_t destAddr, uint16_t size, uint32_t value)
|
||||
{
|
||||
switch (size) {
|
||||
case 8:
|
||||
EmuX86_Write8(destAddr, value & 0xFF);
|
||||
break;
|
||||
case 16:
|
||||
EmuX86_Write16(destAddr, value & 0xFFFF);
|
||||
break;
|
||||
case 32:
|
||||
EmuX86_Write32(destAddr, value);
|
||||
break;
|
||||
default:
|
||||
// TODO : Handle other sizes?
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operand, OUT uint32_t *value)
|
||||
{
|
||||
switch (info.ops[operand].type) {
|
||||
case O_NONE:
|
||||
{
|
||||
// ignore operand
|
||||
}
|
||||
case O_REG:
|
||||
{
|
||||
if (!EmuX86_GetRegisterValue(value, e, info.ops[operand].index))
|
||||
return false;
|
||||
|
||||
break;
|
||||
}
|
||||
case O_IMM:
|
||||
{
|
||||
switch (info.ops[operand].size) {
|
||||
case 8:
|
||||
*value = info.imm.byte;
|
||||
break;
|
||||
case 16:
|
||||
*value = info.imm.word;
|
||||
break;
|
||||
case 32:
|
||||
*value = info.imm.dword;
|
||||
break;
|
||||
// TODO : Handle other sizes?
|
||||
}
|
||||
break;
|
||||
}
|
||||
case O_IMM1:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_IMM2:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_DISP:
|
||||
{
|
||||
uint32_t srcAddr = info.disp;
|
||||
EmuX86_ReadAddr(srcAddr, info.ops[operand].size, value);
|
||||
break;
|
||||
}
|
||||
case O_SMEM:
|
||||
{
|
||||
uint32_t srcAddr = EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
|
||||
EmuX86_ReadAddr(srcAddr, info.ops[operand].size, value);
|
||||
break;
|
||||
}
|
||||
case O_MEM:
|
||||
{
|
||||
uint32_t srcAddr = EmuX86_Distorm_O_MEM_Addr(e, info, operand);
|
||||
EmuX86_ReadAddr(srcAddr, info.ops[operand].size, value);
|
||||
break;
|
||||
}
|
||||
case O_PC:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_PTR:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -239,6 +316,10 @@ bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operan
|
|||
bool EmuX86_WriteValueToDestination(LPEXCEPTION_POINTERS e, _DInst& info, int operand, uint32_t value)
|
||||
{
|
||||
switch (info.ops[operand].type) {
|
||||
case O_NONE:
|
||||
{
|
||||
// ignore operand
|
||||
}
|
||||
case O_REG:
|
||||
{
|
||||
DWORD* pDstReg = EmuX86_GetRegisterPointer(e, info.ops[operand].index);
|
||||
|
@ -260,27 +341,49 @@ bool EmuX86_WriteValueToDestination(LPEXCEPTION_POINTERS e, _DInst& info, int op
|
|||
}
|
||||
break;
|
||||
}
|
||||
case O_MEM:
|
||||
case O_IMM:
|
||||
{
|
||||
uint32_t destAddr = 0;
|
||||
if (!EmuX86_DecodeMemoryOperand(&destAddr, e, info, operand))
|
||||
return false;
|
||||
|
||||
switch (info.ops[operand].size) {
|
||||
case 8:
|
||||
EmuX86_Write8(destAddr, value & 0xFF);
|
||||
break;
|
||||
case 16:
|
||||
EmuX86_Write16(destAddr, value & 0xFFFF);
|
||||
break;
|
||||
case 32:
|
||||
EmuX86_Write32(destAddr, value);
|
||||
break;
|
||||
default:
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_IMM1:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_IMM2:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_DISP:
|
||||
{
|
||||
uint32_t destAddr = info.disp;
|
||||
EmuX86_WriteAddr(destAddr, info.ops[operand].size, value);
|
||||
break;
|
||||
}
|
||||
case O_SMEM:
|
||||
{
|
||||
uint32_t destAddr = EmuX86_Distorm_O_SMEM_Addr(e, info, operand);
|
||||
EmuX86_WriteAddr(destAddr, info.ops[operand].size, value);
|
||||
break;
|
||||
}
|
||||
case O_MEM:
|
||||
{
|
||||
uint32_t destAddr = EmuX86_Distorm_O_MEM_Addr(e, info, operand);
|
||||
EmuX86_WriteAddr(destAddr, info.ops[operand].size, value);
|
||||
break;
|
||||
}
|
||||
case O_PC:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
case O_PTR:
|
||||
{
|
||||
// TODO
|
||||
return false;
|
||||
}
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -306,6 +409,24 @@ bool EmuX86_MOV(LPEXCEPTION_POINTERS e, _DInst& info)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool EmuX86_MOVZX(LPEXCEPTION_POINTERS e, _DInst& info)
|
||||
{
|
||||
// TODO : Test this refactoring
|
||||
|
||||
// MOV reads value from source :
|
||||
uint32_t value = 0;
|
||||
if (!EmuX86_ReadValueFromSource(e, info, 1, &value))
|
||||
return false;
|
||||
|
||||
// MOV writes value to destination :
|
||||
if (!EmuX86_WriteValueToDestination(e, info, 0, value))
|
||||
return false;
|
||||
|
||||
// Note : MOV instructions never update CPU flags
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void EmuX86_SetFlag(LPEXCEPTION_POINTERS e, int flag, int value)
|
||||
{
|
||||
e->ContextRecord->EFlags ^= (-value ^ e->ContextRecord->EFlags) & (1 << flag);
|
||||
|
@ -361,7 +482,13 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
|
|||
ci.codeOffset = 0;
|
||||
ci.dt = (_DecodeType)Decode32Bits;
|
||||
ci.features = DF_NONE;
|
||||
if (DECRES_SUCCESS != distorm_decompose(&ci, &info, 1, &decodedInstructionsCount))
|
||||
|
||||
// Checking for DECRES_SUCCESS won't work, since we're passing distorm_decompose
|
||||
// a codeLen big enough to decode any instruction-length, plus distorm doesn't
|
||||
// halt cleanly after reaching maxInstructions 1. So instead, just call distorm :
|
||||
distorm_decompose(&ci, &info, /*maxInstructions=*/1, &decodedInstructionsCount);
|
||||
// and check if it successfully decoded one instruction :
|
||||
if (decodedInstructionsCount != 1)
|
||||
{
|
||||
EmuWarning("EmuX86: Error decoding opcode at 0x%08X\n", e->ContextRecord->Eip);
|
||||
}
|
||||
|
@ -374,6 +501,12 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
|
|||
break;
|
||||
}
|
||||
|
||||
goto unimplemented_opcode;
|
||||
case I_MOVZX:
|
||||
if (EmuX86_MOVZX(e, info)) {
|
||||
break;
|
||||
}
|
||||
|
||||
goto unimplemented_opcode;
|
||||
case I_TEST:
|
||||
if (EmuX86_TEST(e, info)) {
|
||||
|
@ -384,8 +517,12 @@ bool EmuX86_DecodeException(LPEXCEPTION_POINTERS e)
|
|||
case I_WBINVD:
|
||||
// We can safely ignore this
|
||||
break;
|
||||
default:
|
||||
goto unimplemented_opcode;
|
||||
}
|
||||
|
||||
// When falling through here, the instruction was handled correctly,
|
||||
// skip over the instruction and continue execution :
|
||||
e->ContextRecord->Eip += info.size;
|
||||
return true;
|
||||
|
||||
|
|
Loading…
Reference in New Issue