/** * Returns the value of the parameter in pParam * * @returns VBox error code * @param pCtx CPU context structure pointer * @param pDis Pointer to the disassembler state. * @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, PCDISSTATE pDis, PCDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype) { memset(pParamVal, 0, sizeof(*pParamVal)); if (DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse)) { // Effective address pParamVal->type = DISQPV_TYPE_ADDRESS; pParamVal->size = pParam->cb; if (pParam->fUse & DISUSE_BASE) { if (pParam->fUse & DISUSE_REG_GEN8) { pParamVal->flags |= DISQPV_FLAG_8; if (RT_FAILURE(DISFetchReg8(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER; } else if (pParam->fUse & DISUSE_REG_GEN16) { pParamVal->flags |= DISQPV_FLAG_16; if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER; } else if (pParam->fUse & DISUSE_REG_GEN32) { pParamVal->flags |= DISQPV_FLAG_32; if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER; } else if (pParam->fUse & DISUSE_REG_GEN64) { pParamVal->flags |= DISQPV_FLAG_64; if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER; } else { AssertFailed(); return VERR_INVALID_PARAMETER; } } // Note that scale implies index (SIB byte) if (pParam->fUse & DISUSE_INDEX) { if (pParam->fUse & DISUSE_REG_GEN16) { uint16_t val16; pParamVal->flags |= DISQPV_FLAG_16; if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Index.idxGenReg, &val16))) return VERR_INVALID_PARAMETER; Assert(!(pParam->fUse & DISUSE_SCALE)); /* shouldn't be possible in 16 bits mode */ pParamVal->val.val16 += val16; } else if (pParam->fUse & DISUSE_REG_GEN32) { uint32_t val32; pParamVal->flags |= DISQPV_FLAG_32; if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Index.idxGenReg, &val32))) return VERR_INVALID_PARAMETER; if (pParam->fUse & DISUSE_SCALE) val32 *= pParam->uScale; pParamVal->val.val32 += val32; } else if (pParam->fUse & DISUSE_REG_GEN64) { uint64_t val64; pParamVal->flags |= DISQPV_FLAG_64; if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Index.idxGenReg, &val64))) return VERR_INVALID_PARAMETER; if (pParam->fUse & DISUSE_SCALE) val64 *= pParam->uScale; pParamVal->val.val64 += val64; } else AssertFailed(); } if (pParam->fUse & DISUSE_DISPLACEMENT8) { if (pDis->uCpuMode == DISCPUMODE_32BIT) pParamVal->val.val32 += (int32_t)pParam->uDisp.i8; else if (pDis->uCpuMode == DISCPUMODE_64BIT) pParamVal->val.val64 += (int64_t)pParam->uDisp.i8; else pParamVal->val.val16 += (int16_t)pParam->uDisp.i8; } else if (pParam->fUse & DISUSE_DISPLACEMENT16) { if (pDis->uCpuMode == DISCPUMODE_32BIT) pParamVal->val.val32 += (int32_t)pParam->uDisp.i16; else if (pDis->uCpuMode == DISCPUMODE_64BIT) pParamVal->val.val64 += (int64_t)pParam->uDisp.i16; else pParamVal->val.val16 += pParam->uDisp.i16; } else if (pParam->fUse & DISUSE_DISPLACEMENT32) { if (pDis->uCpuMode == DISCPUMODE_32BIT) pParamVal->val.val32 += pParam->uDisp.i32; else pParamVal->val.val64 += pParam->uDisp.i32; } else if (pParam->fUse & DISUSE_DISPLACEMENT64) { Assert(pDis->uCpuMode == DISCPUMODE_64BIT); pParamVal->val.val64 += pParam->uDisp.i64; } else if (pParam->fUse & DISUSE_RIPDISPLACEMENT32) { Assert(pDis->uCpuMode == DISCPUMODE_64BIT); /* Relative to the RIP of the next instruction. */ pParamVal->val.val64 += pParam->uDisp.i32 + pCtx->rip + pDis->cbInstr; } return VINF_SUCCESS; } if (pParam->fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32|DISUSE_REG_GEN64|DISUSE_REG_FP|DISUSE_REG_MMX|DISUSE_REG_XMM|DISUSE_REG_CR|DISUSE_REG_DBG|DISUSE_REG_SEG|DISUSE_REG_TEST)) { if (parmtype == DISQPVWHICH_DST) { // Caller needs to interpret the register according to the instruction (source/target, special value etc) pParamVal->type = DISQPV_TYPE_REGISTER; pParamVal->size = pParam->cb; return VINF_SUCCESS; } //else DISQPVWHICH_SRC pParamVal->type = DISQPV_TYPE_IMMEDIATE; if (pParam->fUse & DISUSE_REG_GEN8) { pParamVal->flags |= DISQPV_FLAG_8; pParamVal->size = sizeof(uint8_t); if (RT_FAILURE(DISFetchReg8(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER; } else if (pParam->fUse & DISUSE_REG_GEN16) { pParamVal->flags |= DISQPV_FLAG_16; pParamVal->size = sizeof(uint16_t); if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER; } else if (pParam->fUse & DISUSE_REG_GEN32) { pParamVal->flags |= DISQPV_FLAG_32; pParamVal->size = sizeof(uint32_t); if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER; } else if (pParam->fUse & DISUSE_REG_GEN64) { pParamVal->flags |= DISQPV_FLAG_64; pParamVal->size = sizeof(uint64_t); if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Base.idxGenReg, &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 = DISQPV_TYPE_REGISTER; } Assert(!(pParam->fUse & DISUSE_IMMEDIATE)); return VINF_SUCCESS; } if (pParam->fUse & DISUSE_IMMEDIATE) { pParamVal->type = DISQPV_TYPE_IMMEDIATE; if (pParam->fUse & (DISUSE_IMMEDIATE8|DISUSE_IMMEDIATE8_REL)) { pParamVal->flags |= DISQPV_FLAG_8; if (pParam->cb == 2) { pParamVal->size = sizeof(uint16_t); pParamVal->val.val16 = (uint8_t)pParam->uValue; } else { pParamVal->size = sizeof(uint8_t); pParamVal->val.val8 = (uint8_t)pParam->uValue; } } else if (pParam->fUse & (DISUSE_IMMEDIATE16|DISUSE_IMMEDIATE16_REL|DISUSE_IMMEDIATE_ADDR_0_16|DISUSE_IMMEDIATE16_SX8)) { pParamVal->flags |= DISQPV_FLAG_16; pParamVal->size = sizeof(uint16_t); pParamVal->val.val16 = (uint16_t)pParam->uValue; AssertMsg(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE16_SX8)), ("pParamVal->size %d vs %d EIP=%RX32\n", pParamVal->size, pParam->cb, pCtx->eip) ); } else if (pParam->fUse & (DISUSE_IMMEDIATE32|DISUSE_IMMEDIATE32_REL|DISUSE_IMMEDIATE_ADDR_0_32|DISUSE_IMMEDIATE32_SX8)) { pParamVal->flags |= DISQPV_FLAG_32; pParamVal->size = sizeof(uint32_t); pParamVal->val.val32 = (uint32_t)pParam->uValue; Assert(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE32_SX8)) ); } else if (pParam->fUse & (DISUSE_IMMEDIATE64 | DISUSE_IMMEDIATE64_REL | DISUSE_IMMEDIATE64_SX8)) { pParamVal->flags |= DISQPV_FLAG_64; pParamVal->size = sizeof(uint64_t); pParamVal->val.val64 = pParam->uValue; Assert(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE64_SX8)) ); } else if (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16)) { pParamVal->flags |= DISQPV_FLAG_FARPTR16; pParamVal->size = sizeof(uint16_t)*2; pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->uValue >> 16); pParamVal->val.farptr.offset = (uint32_t)RT_LOWORD(pParam->uValue); Assert(pParamVal->size == pParam->cb); }
/** * 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); }
/** * Returns the contents of register or immediate data of instruction's parameter. * * @returns true on success. * * @todo Get rid of this code. Use DISQueryParamVal instead * * @param pCpu Pointer to current disassembler context. * @param pParam Pointer to parameter of instruction to process. * @param pRegFrame Pointer to CPUMCTXCORE guest structure. * @param pu64Data Where to store retrieved data. * @param pcbSize Where to store the size of data (1, 2, 4, 8). */ bool iomGetRegImmData(PDISCPUSTATE pCpu, PCDISOPPARAM pParam, PCPUMCTXCORE pRegFrame, uint64_t *pu64Data, unsigned *pcbSize) { NOREF(pCpu); if (pParam->fUse & (DISUSE_BASE | DISUSE_INDEX | DISUSE_SCALE | DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32)) { *pcbSize = 0; *pu64Data = 0; return false; } /* divide and conquer */ if (pParam->fUse & (DISUSE_REG_GEN64 | DISUSE_REG_GEN32 | DISUSE_REG_GEN16 | DISUSE_REG_GEN8)) { if (pParam->fUse & DISUSE_REG_GEN32) { *pcbSize = 4; DISFetchReg32(pRegFrame, pParam->Base.idxGenReg, (uint32_t *)pu64Data); return true; } if (pParam->fUse & DISUSE_REG_GEN16) { *pcbSize = 2; DISFetchReg16(pRegFrame, pParam->Base.idxGenReg, (uint16_t *)pu64Data); return true; } if (pParam->fUse & DISUSE_REG_GEN8) { *pcbSize = 1; DISFetchReg8(pRegFrame, pParam->Base.idxGenReg, (uint8_t *)pu64Data); return true; } Assert(pParam->fUse & DISUSE_REG_GEN64); *pcbSize = 8; DISFetchReg64(pRegFrame, pParam->Base.idxGenReg, pu64Data); return true; } else { if (pParam->fUse & (DISUSE_IMMEDIATE64 | DISUSE_IMMEDIATE64_SX8)) { *pcbSize = 8; *pu64Data = pParam->uValue; return true; } if (pParam->fUse & (DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE32_SX8)) { *pcbSize = 4; *pu64Data = (uint32_t)pParam->uValue; return true; } if (pParam->fUse & (DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE16_SX8)) { *pcbSize = 2; *pu64Data = (uint16_t)pParam->uValue; return true; } if (pParam->fUse & DISUSE_IMMEDIATE8) { *pcbSize = 1; *pu64Data = (uint8_t)pParam->uValue; return true; } if (pParam->fUse & DISUSE_REG_SEG) { *pcbSize = 2; DISFetchRegSeg(pRegFrame, (DISSELREG)pParam->Base.idxSegReg, (RTSEL *)pu64Data); return true; } /* Else - error. */ AssertFailed(); *pcbSize = 0; *pu64Data = 0; return false; } }