From 5acc167a0772b5e3401aab943a13662fd9b47fce Mon Sep 17 00:00:00 2001 From: PatrickvL Date: Mon, 9 Jan 2017 18:27:32 +0100 Subject: [PATCH] distorm starts to work --- import/distorm/lib/Win32/distorm.lib | Bin 116438 -> 116438 bytes src/CxbxKrnl/Emu.cpp | 227 +++++++++++++-------------- src/CxbxKrnl/EmuX86.cpp | 225 ++++++++++++++++++++------ 3 files changed, 294 insertions(+), 158 deletions(-) diff --git a/import/distorm/lib/Win32/distorm.lib b/import/distorm/lib/Win32/distorm.lib index 58a97555dfff8a1bb3804ccf6e0f26b3bebadd67..fa0d7537b7a43b27fb2abad4a36f1226340ec4d2 100644 GIT binary patch delta 611 zcmccC%YLnweS#c|vAKcilZMHC&aXp@EsH zp#lgbaQQIuGk7d1j^I>fV6dA0v5irB^EAH4oQ!b@-Bz0~NCe2kwNJLP0J&?kk42&w zWBlZGe$G(mY}WK|Y+$oAhk8Jb4P@?m#>oX-PMhT}@G~+dAj|~0J!bkSFfd3%Tv2tYos}_hGt-THMwt04Z&oM6oiW|cmJ#HR?E$uob9oq(w!iaaG=?g* z*dFE0_&^V#Hl&JC0BpfFE(Qi+um#&Ysu=y5CjSvyGC9&+X!`XYM%U?=Y8geR+qy6s zO_!`=RGvPskCA)2dmW?MDbr6(W~_$zdxWv%4Y|i1j%fu*vs&X}4m87A8nW>=y z2qbX%F!D2eo?RTlsmj1$HT`27qx9x!e2+O9)eyR^HeZkkkcVrZY-Is**JdA!L@`Fo z$?N=_q0ZT?>EGDEW@u2|h^Aa`sJuw|Uf!|1X7 zohPF)RH?=GC~w9GdI+^4Rg3~)3$}4FFbIP!*xpga=+6Z7z+a)o;sOjDg24g|4DrtS zDXE@$Y55GiKoPI$cX}A*87-&(>0wlueyNsGR8)xpsK`GptvIzLq_QBD0jzQQpISx- zMz86%b&L+vr`9nFF@{dJb7d4~Trr&wNGW^*Y7$`Vaqf=)ymcAREz84iXZfo>XJGgY z6nAH2V3_`}AE;ETp3!moc~?fx>75f8<)?qBXLM%tL&QR;J`Y2UbGM^F>wyxk<{ykD ztj#}|N{yN;IT%WGnrl>mlxnx5Nb>_`8|D(}=1QLJR~i`Ku&_8K^Z%ZHq?Pd(A~bHa dK|=0T8{=Ib#^C8ECNtJU!q{Sa!xY9aBLMuV;|Kr% diff --git a/src/CxbxKrnl/Emu.cpp b/src/CxbxKrnl/Emu.cpp index 27616ad69..98113bea3 100644 --- a/src/CxbxKrnl/Emu.cpp +++ b/src/CxbxKrnl/Emu.cpp @@ -145,126 +145,125 @@ extern "C" CXBXKRNL_API void NTAPI EmuWarning(const char *szWarningMessage, ...) } #endif +void EmuExceptionPrintDebugInformation(LPEXCEPTION_POINTERS e, bool IsBreakpointException) +{ + // print debug information + { + if (IsBreakpointException) + printf("EmuMain (0x%X): Recieved Breakpoint Exception (int 3)\n", GetCurrentThreadId()); + else + printf("EmuMain (0x%X): Recieved Exception (Code := 0x%.08X)\n", GetCurrentThreadId(), e->ExceptionRecord->ExceptionCode); + + 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); +} + +void EmuExceptionExitProcess() +{ + printf("EmuMain (0x%X): Aborting Emulation\n", GetCurrentThreadId()); + fflush(stdout); + + if (CxbxKrnl_hEmuParent != NULL) + SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0); + + 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 - { - char buffer[256]; - - if(e->ExceptionRecord->ExceptionCode == 0x80000003) - { - // print debug information - { - 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" - " 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 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) - { - printf("EmuMain (0x%X): Aborting Emulation\n", GetCurrentThreadId()); - fflush(stdout); - - if(CxbxKrnl_hEmuParent != NULL) - SendMessage(CxbxKrnl_hEmuParent, WM_PARENTNOTIFY, WM_DESTROY, 0); - - ExitProcess(1); - } - } - } - - g_bEmuException = false; + // notify user + EmuExceptionNonBreakpointUnhandledShow(e); + } + // Unhandled exception : + g_bEmuException = false; return EXCEPTION_CONTINUE_SEARCH; } diff --git a/src/CxbxKrnl/EmuX86.cpp b/src/CxbxKrnl/EmuX86.cpp index a11242eed..8bfcf179e 100644 --- a/src/CxbxKrnl/EmuX86.cpp +++ b/src/CxbxKrnl/EmuX86.cpp @@ -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,26 +180,70 @@ 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; - 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(&base, e, info.base); - *output = base + (index * info.scale) + info.imm.dword; - return true; + uint32_t index = 0; + 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; +} + +void EmuX86_ReadAddr(uint32_t srcAddr, uint16_t size, OUT uint32_t *value) +{ + switch (size) { + case 8: + *value = EmuX86_Read8(srcAddr); + break; + case 16: + *value = EmuX86_Read16(srcAddr); + break; + case 32: + *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) { - // TODO : other operand.type - case O_IMM: + case O_NONE: { - *value = info.imm.dword; - break; + // ignore operand } case O_REG: { @@ -208,27 +252,60 @@ bool EmuX86_ReadValueFromSource(LPEXCEPTION_POINTERS e, _DInst& info, int operan break; } - case O_MEM: + case O_IMM: { - uint32_t srcAddr = 0; - if (!EmuX86_DecodeMemoryOperand(&srcAddr, e, info, operand)) - return false; - switch (info.ops[operand].size) { case 8: - *value = EmuX86_Read8(srcAddr); + *value = info.imm.byte; break; case 16: - *value = EmuX86_Read16(srcAddr); + *value = info.imm.word; break; case 32: - *value = EmuX86_Read32(srcAddr); + *value = info.imm.dword; break; - default: - return false; + // 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_IMM: + { + // 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 = 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: - return false; - } + 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; } @@ -291,7 +394,25 @@ bool EmuX86_WriteValueToDestination(LPEXCEPTION_POINTERS e, _DInst& info, int op bool EmuX86_MOV(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; +} + +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)) @@ -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;