/** @file * * VBox disassembler: * Core components */ /* * Copyright (C) 2006-2007 Oracle Corporation * * This file is part of VirtualBox Open Source Edition (OSE), as * available from http://www.virtualbox.org. This file is free software; * you can redistribute it and/or modify it under the terms of the GNU * General Public License (GPL) as published by the Free Software * Foundation, in version 2 as it comes in the "COPYING" file of the * VirtualBox OSE distribution. VirtualBox OSE is distributed in the * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind. */ /******************************************************************************* * Header Files * *******************************************************************************/ #define LOG_GROUP LOG_GROUP_DIS #ifdef USING_VISUAL_STUDIO # include #endif #include #include #include #include #include #include #include #include #include "DisasmInternal.h" #include "DisasmTables.h" #if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED) # include # include #endif /******************************************************************************* * Global Variables * *******************************************************************************/ /** * Array for accessing 64-bit general registers in VMMREGFRAME structure * by register's index from disasm. */ static const unsigned g_aReg64Index[] = { RT_OFFSETOF(CPUMCTXCORE, rax), /* USE_REG_RAX */ RT_OFFSETOF(CPUMCTXCORE, rcx), /* USE_REG_RCX */ RT_OFFSETOF(CPUMCTXCORE, rdx), /* USE_REG_RDX */ RT_OFFSETOF(CPUMCTXCORE, rbx), /* USE_REG_RBX */ RT_OFFSETOF(CPUMCTXCORE, rsp), /* USE_REG_RSP */ RT_OFFSETOF(CPUMCTXCORE, rbp), /* USE_REG_RBP */ RT_OFFSETOF(CPUMCTXCORE, rsi), /* USE_REG_RSI */ RT_OFFSETOF(CPUMCTXCORE, rdi), /* USE_REG_RDI */ RT_OFFSETOF(CPUMCTXCORE, r8), /* USE_REG_R8 */ RT_OFFSETOF(CPUMCTXCORE, r9), /* USE_REG_R9 */ RT_OFFSETOF(CPUMCTXCORE, r10), /* USE_REG_R10 */ RT_OFFSETOF(CPUMCTXCORE, r11), /* USE_REG_R11 */ RT_OFFSETOF(CPUMCTXCORE, r12), /* USE_REG_R12 */ RT_OFFSETOF(CPUMCTXCORE, r13), /* USE_REG_R13 */ RT_OFFSETOF(CPUMCTXCORE, r14), /* USE_REG_R14 */ RT_OFFSETOF(CPUMCTXCORE, r15) /* USE_REG_R15 */ }; /** * Macro for accessing 64-bit general purpose registers in CPUMCTXCORE structure. */ #define DIS_READ_REG64(p, idx) (*(uint64_t *)((char *)(p) + g_aReg64Index[idx])) #define DIS_WRITE_REG64(p, idx, val) (*(uint64_t *)((char *)(p) + g_aReg64Index[idx]) = val) #define DIS_PTR_REG64(p, idx) ( (uint64_t *)((char *)(p) + g_aReg64Index[idx])) /** * Array for accessing 32-bit general registers in VMMREGFRAME structure * by register's index from disasm. */ static const unsigned g_aReg32Index[] = { RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_EAX */ RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_ECX */ RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_EDX */ RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_EBX */ RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_ESP */ RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_EBP */ RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_ESI */ RT_OFFSETOF(CPUMCTXCORE, edi), /* USE_REG_EDI */ RT_OFFSETOF(CPUMCTXCORE, r8), /* USE_REG_R8D */ RT_OFFSETOF(CPUMCTXCORE, r9), /* USE_REG_R9D */ RT_OFFSETOF(CPUMCTXCORE, r10), /* USE_REG_R10D */ RT_OFFSETOF(CPUMCTXCORE, r11), /* USE_REG_R11D */ RT_OFFSETOF(CPUMCTXCORE, r12), /* USE_REG_R12D */ RT_OFFSETOF(CPUMCTXCORE, r13), /* USE_REG_R13D */ RT_OFFSETOF(CPUMCTXCORE, r14), /* USE_REG_R14D */ RT_OFFSETOF(CPUMCTXCORE, r15) /* USE_REG_R15D */ }; /** * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure. */ #define DIS_READ_REG32(p, idx) (*(uint32_t *)((char *)(p) + g_aReg32Index[idx])) /* From http://www.cs.cmu.edu/~fp/courses/15213-s06/misc/asm64-handout.pdf: * ``Perhaps unexpectedly, instructions that move or generate 32-bit register * values also set the upper 32 bits of the register to zero. Consequently * there is no need for an instruction movzlq.'' */ #define DIS_WRITE_REG32(p, idx, val) (*(uint64_t *)((char *)(p) + g_aReg32Index[idx]) = (uint32_t)val) #define DIS_PTR_REG32(p, idx) ( (uint32_t *)((char *)(p) + g_aReg32Index[idx])) /** * Array for accessing 16-bit general registers in CPUMCTXCORE structure * by register's index from disasm. */ static const unsigned g_aReg16Index[] = { RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AX */ RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CX */ RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DX */ RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BX */ RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_SP */ RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_BP */ RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_SI */ RT_OFFSETOF(CPUMCTXCORE, edi), /* USE_REG_DI */ RT_OFFSETOF(CPUMCTXCORE, r8), /* USE_REG_R8W */ RT_OFFSETOF(CPUMCTXCORE, r9), /* USE_REG_R9W */ RT_OFFSETOF(CPUMCTXCORE, r10), /* USE_REG_R10W */ RT_OFFSETOF(CPUMCTXCORE, r11), /* USE_REG_R11W */ RT_OFFSETOF(CPUMCTXCORE, r12), /* USE_REG_R12W */ RT_OFFSETOF(CPUMCTXCORE, r13), /* USE_REG_R13W */ RT_OFFSETOF(CPUMCTXCORE, r14), /* USE_REG_R14W */ RT_OFFSETOF(CPUMCTXCORE, r15) /* USE_REG_R15W */ }; /** * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure. */ #define DIS_READ_REG16(p, idx) (*(uint16_t *)((char *)(p) + g_aReg16Index[idx])) #define DIS_WRITE_REG16(p, idx, val) (*(uint16_t *)((char *)(p) + g_aReg16Index[idx]) = val) #define DIS_PTR_REG16(p, idx) ( (uint16_t *)((char *)(p) + g_aReg16Index[idx])) /** * Array for accessing 8-bit general registers in CPUMCTXCORE structure * by register's index from disasm. */ static const unsigned g_aReg8Index[] = { RT_OFFSETOF(CPUMCTXCORE, eax), /* USE_REG_AL */ RT_OFFSETOF(CPUMCTXCORE, ecx), /* USE_REG_CL */ RT_OFFSETOF(CPUMCTXCORE, edx), /* USE_REG_DL */ RT_OFFSETOF(CPUMCTXCORE, ebx), /* USE_REG_BL */ RT_OFFSETOF_ADD(CPUMCTXCORE, eax, 1), /* USE_REG_AH */ RT_OFFSETOF_ADD(CPUMCTXCORE, ecx, 1), /* USE_REG_CH */ RT_OFFSETOF_ADD(CPUMCTXCORE, edx, 1), /* USE_REG_DH */ RT_OFFSETOF_ADD(CPUMCTXCORE, ebx, 1), /* USE_REG_BH */ RT_OFFSETOF(CPUMCTXCORE, r8), /* USE_REG_R8B */ RT_OFFSETOF(CPUMCTXCORE, r9), /* USE_REG_R9B */ RT_OFFSETOF(CPUMCTXCORE, r10), /* USE_REG_R10B*/ RT_OFFSETOF(CPUMCTXCORE, r11), /* USE_REG_R11B */ RT_OFFSETOF(CPUMCTXCORE, r12), /* USE_REG_R12B */ RT_OFFSETOF(CPUMCTXCORE, r13), /* USE_REG_R13B */ RT_OFFSETOF(CPUMCTXCORE, r14), /* USE_REG_R14B */ RT_OFFSETOF(CPUMCTXCORE, r15), /* USE_REG_R15B */ RT_OFFSETOF(CPUMCTXCORE, esp), /* USE_REG_SPL; with REX prefix only */ RT_OFFSETOF(CPUMCTXCORE, ebp), /* USE_REG_BPL; with REX prefix only */ RT_OFFSETOF(CPUMCTXCORE, esi), /* USE_REG_SIL; with REX prefix only */ RT_OFFSETOF(CPUMCTXCORE, edi) /* USE_REG_DIL; with REX prefix only */ }; /** * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure. */ #define DIS_READ_REG8(p, idx) (*(uint8_t *)((char *)(p) + g_aReg8Index[idx])) #define DIS_WRITE_REG8(p, idx, val) (*(uint8_t *)((char *)(p) + g_aReg8Index[idx]) = val) #define DIS_PTR_REG8(p, idx) ( (uint8_t *)((char *)(p) + g_aReg8Index[idx])) /** * Array for accessing segment registers in CPUMCTXCORE structure * by register's index from disasm. */ static const unsigned g_aRegSegIndex[] = { RT_OFFSETOF(CPUMCTXCORE, es), /* DIS_SELREG_ES */ RT_OFFSETOF(CPUMCTXCORE, cs), /* DIS_SELREG_CS */ RT_OFFSETOF(CPUMCTXCORE, ss), /* DIS_SELREG_SS */ RT_OFFSETOF(CPUMCTXCORE, ds), /* DIS_SELREG_DS */ RT_OFFSETOF(CPUMCTXCORE, fs), /* DIS_SELREG_FS */ RT_OFFSETOF(CPUMCTXCORE, gs) /* DIS_SELREG_GS */ }; static const unsigned g_aRegHidSegIndex[] = { RT_OFFSETOF(CPUMCTXCORE, esHid), /* DIS_SELREG_ES */ RT_OFFSETOF(CPUMCTXCORE, csHid), /* DIS_SELREG_CS */ RT_OFFSETOF(CPUMCTXCORE, ssHid), /* DIS_SELREG_SS */ RT_OFFSETOF(CPUMCTXCORE, dsHid), /* DIS_SELREG_DS */ RT_OFFSETOF(CPUMCTXCORE, fsHid), /* DIS_SELREG_FS */ RT_OFFSETOF(CPUMCTXCORE, gsHid) /* DIS_SELREG_GS */ }; /** * Macro for accessing segment registers in CPUMCTXCORE structure. */ #define DIS_READ_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx]))) #define DIS_WRITE_REGSEG(p, idx, val) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])) = val) //***************************************************************************** //***************************************************************************** DISDECL(int) DISGetParamSize(PDISCPUSTATE pCpu, POP_PARAMETER pParam) { int subtype = OP_PARM_VSUBTYPE(pParam->param); if (subtype == OP_PARM_v) { switch(pCpu->opmode) { case CPUMODE_32BIT: subtype = OP_PARM_d; break; case CPUMODE_64BIT: subtype = OP_PARM_q; break; case CPUMODE_16BIT: subtype = OP_PARM_w; break; default: /* make gcc happy */ break; } } switch(subtype) { case OP_PARM_b: return 1; case OP_PARM_w: return 2; case OP_PARM_d: return 4; case OP_PARM_q: case OP_PARM_dq: return 8; case OP_PARM_p: /* far pointer */ if (pCpu->addrmode == CPUMODE_32BIT) return 6; /* 16:32 */ else if (pCpu->addrmode == CPUMODE_64BIT) return 12; /* 16:64 */ else return 4; /* 16:16 */ default: if (pParam->size) return pParam->size; else //@todo dangerous!!! return 4; } } //***************************************************************************** //***************************************************************************** DISDECL(DIS_SELREG) DISDetectSegReg(PDISCPUSTATE pCpu, POP_PARAMETER pParam) { if (pCpu->prefix & PREFIX_SEG) { /* Use specified SEG: prefix. */ return pCpu->enmPrefixSeg; } else { /* Guess segment register by parameter type. */ if (pParam->flags & (USE_REG_GEN32|USE_REG_GEN64|USE_REG_GEN16)) { AssertCompile(USE_REG_ESP == USE_REG_RSP); AssertCompile(USE_REG_EBP == USE_REG_RBP); AssertCompile(USE_REG_ESP == USE_REG_SP); AssertCompile(USE_REG_EBP == USE_REG_BP); if (pParam->base.reg_gen == USE_REG_ESP || pParam->base.reg_gen == USE_REG_EBP) return DIS_SELREG_SS; } /* Default is use DS: for data access. */ return DIS_SELREG_DS; } } //***************************************************************************** //***************************************************************************** DISDECL(uint8_t) DISQuerySegPrefixByte(PDISCPUSTATE pCpu) { Assert(pCpu->prefix & PREFIX_SEG); switch(pCpu->enmPrefixSeg) { case DIS_SELREG_ES: return 0x26; case DIS_SELREG_CS: return 0x2E; case DIS_SELREG_SS: return 0x36; case DIS_SELREG_DS: return 0x3E; case DIS_SELREG_FS: return 0x64; case DIS_SELREG_GS: return 0x65; default: AssertFailed(); return 0; } } /** * Returns the value of the specified 8 bits general purpose register * */ DISDECL(int) DISFetchReg8(PCCPUMCTXCORE pCtx, unsigned reg8, uint8_t *pVal) { AssertReturn(reg8 < RT_ELEMENTS(g_aReg8Index), VERR_INVALID_PARAMETER); *pVal = DIS_READ_REG8(pCtx, reg8); return VINF_SUCCESS; } /** * Returns the value of the specified 16 bits general purpose register * */ DISDECL(int) DISFetchReg16(PCCPUMCTXCORE pCtx, unsigned reg16, uint16_t *pVal) { AssertReturn(reg16 < RT_ELEMENTS(g_aReg16Index), VERR_INVALID_PARAMETER); *pVal = DIS_READ_REG16(pCtx, reg16); return VINF_SUCCESS; } /** * Returns the value of the specified 32 bits general purpose register * */ DISDECL(int) DISFetchReg32(PCCPUMCTXCORE pCtx, unsigned reg32, uint32_t *pVal) { AssertReturn(reg32 < RT_ELEMENTS(g_aReg32Index), VERR_INVALID_PARAMETER); *pVal = DIS_READ_REG32(pCtx, reg32); return VINF_SUCCESS; } /** * Returns the value of the specified 64 bits general purpose register * */ DISDECL(int) DISFetchReg64(PCCPUMCTXCORE pCtx, unsigned reg64, uint64_t *pVal) { AssertReturn(reg64 < RT_ELEMENTS(g_aReg64Index), VERR_INVALID_PARAMETER); *pVal = DIS_READ_REG64(pCtx, reg64); return VINF_SUCCESS; } /** * Returns the pointer to the specified 8 bits general purpose register * */ DISDECL(int) DISPtrReg8(PCPUMCTXCORE pCtx, unsigned reg8, uint8_t **ppReg) { AssertReturn(reg8 < RT_ELEMENTS(g_aReg8Index), VERR_INVALID_PARAMETER); *ppReg = DIS_PTR_REG8(pCtx, reg8); return VINF_SUCCESS; } /** * Returns the pointer to the specified 16 bits general purpose register * */ DISDECL(int) DISPtrReg16(PCPUMCTXCORE pCtx, unsigned reg16, uint16_t **ppReg) { AssertReturn(reg16 < RT_ELEMENTS(g_aReg16Index), VERR_INVALID_PARAMETER); *ppReg = DIS_PTR_REG16(pCtx, reg16); return VINF_SUCCESS; } /** * Returns the pointer to the specified 32 bits general purpose register * */ DISDECL(int) DISPtrReg32(PCPUMCTXCORE pCtx, unsigned reg32, uint32_t **ppReg) { AssertReturn(reg32 < RT_ELEMENTS(g_aReg32Index), VERR_INVALID_PARAMETER); *ppReg = DIS_PTR_REG32(pCtx, reg32); return VINF_SUCCESS; } /** * Returns the pointer to the specified 64 bits general purpose register * */ DISDECL(int) DISPtrReg64(PCPUMCTXCORE pCtx, unsigned reg64, uint64_t **ppReg) { AssertReturn(reg64 < RT_ELEMENTS(g_aReg64Index), VERR_INVALID_PARAMETER); *ppReg = DIS_PTR_REG64(pCtx, reg64); return VINF_SUCCESS; } /** * Returns the value of the specified segment register * */ DISDECL(int) DISFetchRegSeg(PCCPUMCTXCORE pCtx, DIS_SELREG sel, RTSEL *pVal) { AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER); AssertCompile(sizeof(uint16_t) == sizeof(RTSEL)); *pVal = DIS_READ_REGSEG(pCtx, sel); return VINF_SUCCESS; } /** * Returns the value of the specified segment register including a pointer to the hidden register in the supplied cpu context * */ DISDECL(int) DISFetchRegSegEx(PCCPUMCTXCORE pCtx, DIS_SELREG sel, RTSEL *pVal, CPUMSELREGHID **ppSelHidReg) { AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER); AssertCompile(sizeof(uint16_t) == sizeof(RTSEL)); *pVal = DIS_READ_REGSEG(pCtx, sel); *ppSelHidReg = (CPUMSELREGHID *)((char *)pCtx + g_aRegHidSegIndex[sel]); return VINF_SUCCESS; } /** * Updates the value of the specified 64 bits general purpose register * */ DISDECL(int) DISWriteReg64(PCPUMCTXCORE pRegFrame, unsigned reg64, uint64_t val64) { AssertReturn(reg64 < RT_ELEMENTS(g_aReg64Index), VERR_INVALID_PARAMETER); DIS_WRITE_REG64(pRegFrame, reg64, val64); return VINF_SUCCESS; } /** * Updates the value of the specified 32 bits general purpose register * */ DISDECL(int) DISWriteReg32(PCPUMCTXCORE pRegFrame, unsigned reg32, uint32_t val32) { AssertReturn(reg32 < RT_ELEMENTS(g_aReg32Index), VERR_INVALID_PARAMETER); DIS_WRITE_REG32(pRegFrame, reg32, val32); return VINF_SUCCESS; } /** * Updates the value of the specified 16 bits general purpose register * */ DISDECL(int) DISWriteReg16(PCPUMCTXCORE pRegFrame, unsigned reg16, uint16_t val16) { AssertReturn(reg16 < RT_ELEMENTS(g_aReg16Index), VERR_INVALID_PARAMETER); DIS_WRITE_REG16(pRegFrame, reg16, val16); return VINF_SUCCESS; } /** * Updates the specified 8 bits general purpose register * */ DISDECL(int) DISWriteReg8(PCPUMCTXCORE pRegFrame, unsigned reg8, uint8_t val8) { AssertReturn(reg8 < RT_ELEMENTS(g_aReg8Index), VERR_INVALID_PARAMETER); DIS_WRITE_REG8(pRegFrame, reg8, val8); return VINF_SUCCESS; } /** * Updates the specified segment register * */ DISDECL(int) DISWriteRegSeg(PCPUMCTXCORE pCtx, DIS_SELREG sel, RTSEL val) { AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER); AssertCompile(sizeof(uint16_t) == sizeof(RTSEL)); DIS_WRITE_REGSEG(pCtx, sel, val); return VINF_SUCCESS; } /** * Returns the value of the parameter in pParam * * @returns VBox error code * @param pCtx CPU context structure pointer * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode * set correctly. * @param pParam Pointer to the parameter to parse * @param pParamVal Pointer to parameter value (OUT) * @param parmtype Parameter type * * @note Currently doesn't handle FPU/XMM/MMX/3DNow! parameters correctly!! * */ DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PDISCPUSTATE pCpu, POP_PARAMETER pParam, POP_PARAMVAL pParamVal, PARAM_TYPE parmtype) { memset(pParamVal, 0, sizeof(*pParamVal)); if (DIS_IS_EFFECTIVE_ADDR(pParam->flags)) { // Effective address pParamVal->type = PARMTYPE_ADDRESS; pParamVal->size = pParam->size; if (pParam->flags & USE_BASE) { if (pParam->flags & USE_REG_GEN8) { pParamVal->flags |= PARAM_VAL8; if (RT_FAILURE(DISFetchReg8(pCtx, pParam->base.reg_gen, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER; } else if (pParam->flags & USE_REG_GEN16) { pParamVal->flags |= PARAM_VAL16; if (RT_FAILURE(DISFetchReg16(pCtx, pParam->base.reg_gen, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER; } else if (pParam->flags & USE_REG_GEN32) { pParamVal->flags |= PARAM_VAL32; if (RT_FAILURE(DISFetchReg32(pCtx, pParam->base.reg_gen, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER; } else if (pParam->flags & USE_REG_GEN64) { pParamVal->flags |= PARAM_VAL64; if (RT_FAILURE(DISFetchReg64(pCtx, pParam->base.reg_gen, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER; } else { AssertFailed(); return VERR_INVALID_PARAMETER; } } // Note that scale implies index (SIB byte) if (pParam->flags & USE_INDEX) { if (pParam->flags & USE_REG_GEN16) { uint16_t val16; pParamVal->flags |= PARAM_VAL16; if (RT_FAILURE(DISFetchReg16(pCtx, pParam->index.reg_gen, &val16))) return VERR_INVALID_PARAMETER; Assert(!(pParam->flags & USE_SCALE)); /* shouldn't be possible in 16 bits mode */ pParamVal->val.val16 += val16; } else if (pParam->flags & USE_REG_GEN32) { uint32_t val32; pParamVal->flags |= PARAM_VAL32; if (RT_FAILURE(DISFetchReg32(pCtx, pParam->index.reg_gen, &val32))) return VERR_INVALID_PARAMETER; if (pParam->flags & USE_SCALE) val32 *= pParam->scale; pParamVal->val.val32 += val32; } else if (pParam->flags & USE_REG_GEN64) { uint64_t val64; pParamVal->flags |= PARAM_VAL64; if (RT_FAILURE(DISFetchReg64(pCtx, pParam->index.reg_gen, &val64))) return VERR_INVALID_PARAMETER; if (pParam->flags & USE_SCALE) val64 *= pParam->scale; pParamVal->val.val64 += val64; } else AssertFailed(); } if (pParam->flags & USE_DISPLACEMENT8) { if (pCpu->mode == CPUMODE_32BIT) pParamVal->val.val32 += (int32_t)pParam->disp8; else if (pCpu->mode == CPUMODE_64BIT) pParamVal->val.val64 += (int64_t)pParam->disp8; else pParamVal->val.val16 += (int16_t)pParam->disp8; } else if (pParam->flags & USE_DISPLACEMENT16) { if (pCpu->mode == CPUMODE_32BIT) pParamVal->val.val32 += (int32_t)pParam->disp16; else if (pCpu->mode == CPUMODE_64BIT) pParamVal->val.val64 += (int64_t)pParam->disp16; else pParamVal->val.val16 += pParam->disp16; } else if (pParam->flags & USE_DISPLACEMENT32) { if (pCpu->mode == CPUMODE_32BIT) pParamVal->val.val32 += pParam->disp32; else pParamVal->val.val64 += pParam->disp32; } else if (pParam->flags & USE_DISPLACEMENT64) { Assert(pCpu->mode == CPUMODE_64BIT); pParamVal->val.val64 += (int64_t)pParam->disp64; } else if (pParam->flags & USE_RIPDISPLACEMENT32) { Assert(pCpu->mode == CPUMODE_64BIT); /* Relative to the RIP of the next instruction. */ pParamVal->val.val64 += pParam->disp32 + pCtx->rip + pCpu->opsize; } return VINF_SUCCESS; } if (pParam->flags & (USE_REG_GEN8|USE_REG_GEN16|USE_REG_GEN32|USE_REG_GEN64|USE_REG_FP|USE_REG_MMX|USE_REG_XMM|USE_REG_CR|USE_REG_DBG|USE_REG_SEG|USE_REG_TEST)) { if (parmtype == PARAM_DEST) { // Caller needs to interpret the register according to the instruction (source/target, special value etc) pParamVal->type = PARMTYPE_REGISTER; pParamVal->size = pParam->size; return VINF_SUCCESS; } //else PARAM_SOURCE pParamVal->type = PARMTYPE_IMMEDIATE; if (pParam->flags & USE_REG_GEN8) { pParamVal->flags |= PARAM_VAL8; pParamVal->size = sizeof(uint8_t); if (RT_FAILURE(DISFetchReg8(pCtx, pParam->base.reg_gen, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER; } else if (pParam->flags & USE_REG_GEN16) { pParamVal->flags |= PARAM_VAL16; pParamVal->size = sizeof(uint16_t); if (RT_FAILURE(DISFetchReg16(pCtx, pParam->base.reg_gen, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER; } else if (pParam->flags & USE_REG_GEN32) { pParamVal->flags |= PARAM_VAL32; pParamVal->size = sizeof(uint32_t); if (RT_FAILURE(DISFetchReg32(pCtx, pParam->base.reg_gen, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER; } else if (pParam->flags & USE_REG_GEN64) { pParamVal->flags |= PARAM_VAL64; pParamVal->size = sizeof(uint64_t); if (RT_FAILURE(DISFetchReg64(pCtx, pParam->base.reg_gen, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER; } else { // Caller needs to interpret the register according to the instruction (source/target, special value etc) pParamVal->type = PARMTYPE_REGISTER; } Assert(!(pParam->flags & USE_IMMEDIATE)); return VINF_SUCCESS; } if (pParam->flags & USE_IMMEDIATE) { pParamVal->type = PARMTYPE_IMMEDIATE; if (pParam->flags & (USE_IMMEDIATE8|USE_IMMEDIATE8_REL)) { pParamVal->flags |= PARAM_VAL8; if (pParam->size == 2) { pParamVal->size = sizeof(uint16_t); pParamVal->val.val16 = (uint8_t)pParam->parval; } else { pParamVal->size = sizeof(uint8_t); pParamVal->val.val8 = (uint8_t)pParam->parval; } } else if (pParam->flags & (USE_IMMEDIATE16|USE_IMMEDIATE16_REL|USE_IMMEDIATE_ADDR_0_16|USE_IMMEDIATE16_SX8)) { pParamVal->flags |= PARAM_VAL16; pParamVal->size = sizeof(uint16_t); pParamVal->val.val16 = (uint16_t)pParam->parval; AssertMsg(pParamVal->size == pParam->size || ((pParam->size == 1) && (pParam->flags & USE_IMMEDIATE16_SX8)), ("pParamVal->size %d vs %d EIP=%RX32\n", pParamVal->size, pParam->size, pCtx->eip) ); } else if (pParam->flags & (USE_IMMEDIATE32|USE_IMMEDIATE32_REL|USE_IMMEDIATE_ADDR_0_32|USE_IMMEDIATE32_SX8)) { pParamVal->flags |= PARAM_VAL32; pParamVal->size = sizeof(uint32_t); pParamVal->val.val32 = (uint32_t)pParam->parval; Assert(pParamVal->size == pParam->size || ((pParam->size == 1) && (pParam->flags & USE_IMMEDIATE32_SX8)) ); } else if (pParam->flags & (USE_IMMEDIATE64 | USE_IMMEDIATE64_REL | USE_IMMEDIATE64_SX8)) { pParamVal->flags |= PARAM_VAL64; pParamVal->size = sizeof(uint64_t); pParamVal->val.val64 = pParam->parval; Assert(pParamVal->size == pParam->size || ((pParam->size == 1) && (pParam->flags & USE_IMMEDIATE64_SX8)) ); } else if (pParam->flags & (USE_IMMEDIATE_ADDR_16_16)) { pParamVal->flags |= PARAM_VALFARPTR16; pParamVal->size = sizeof(uint16_t)*2; pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->parval >> 16); pParamVal->val.farptr.offset = (uint32_t)RT_LOWORD(pParam->parval); Assert(pParamVal->size == pParam->size); } else if (pParam->flags & (USE_IMMEDIATE_ADDR_16_32)) { pParamVal->flags |= PARAM_VALFARPTR32; pParamVal->size = sizeof(uint16_t) + sizeof(uint32_t); pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->parval >> 32); pParamVal->val.farptr.offset = (uint32_t)(pParam->parval & 0xFFFFFFFF); Assert(pParam->size == 8); } } return VINF_SUCCESS; } /** * Returns the pointer to a register of the parameter in pParam. We need this * pointer when an interpreted instruction updates a register as a side effect. * In CMPXCHG we know that only [r/e]ax is updated, but with XADD this could * be every register. * * @returns VBox error code * @param pCtx CPU context structure pointer * @param pCpu Pointer to cpu structure which have DISCPUSTATE::mode * set correctly. * @param pParam Pointer to the parameter to parse * @param pReg Pointer to parameter value (OUT) * @param cbsize Parameter size (OUT) * * @note Currently doesn't handle FPU/XMM/MMX/3DNow! parameters correctly!! * */ DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PDISCPUSTATE pCpu, POP_PARAMETER pParam, void **ppReg, size_t *pcbSize) { if (pParam->flags & (USE_REG_GEN8|USE_REG_GEN16|USE_REG_GEN32|USE_REG_FP|USE_REG_MMX|USE_REG_XMM|USE_REG_CR|USE_REG_DBG|USE_REG_SEG|USE_REG_TEST)) { if (pParam->flags & USE_REG_GEN8) { uint8_t *pu8Reg; if (RT_SUCCESS(DISPtrReg8(pCtx, pParam->base.reg_gen, &pu8Reg))) { *pcbSize = sizeof(uint8_t); *ppReg = (void *)pu8Reg; return VINF_SUCCESS; } } else if (pParam->flags & USE_REG_GEN16) { uint16_t *pu16Reg; if (RT_SUCCESS(DISPtrReg16(pCtx, pParam->base.reg_gen, &pu16Reg))) { *pcbSize = sizeof(uint16_t); *ppReg = (void *)pu16Reg; return VINF_SUCCESS; } } else if (pParam->flags & USE_REG_GEN32) { uint32_t *pu32Reg; if (RT_SUCCESS(DISPtrReg32(pCtx, pParam->base.reg_gen, &pu32Reg))) { *pcbSize = sizeof(uint32_t); *ppReg = (void *)pu32Reg; return VINF_SUCCESS; } } else if (pParam->flags & USE_REG_GEN64) { uint64_t *pu64Reg; if (RT_SUCCESS(DISPtrReg64(pCtx, pParam->base.reg_gen, &pu64Reg))) { *pcbSize = sizeof(uint64_t); *ppReg = (void *)pu64Reg; return VINF_SUCCESS; } } } return VERR_INVALID_PARAMETER; } //***************************************************************************** //*****************************************************************************