DisasmCore.cpp revision 643ac6d84030a2ec7e6d6f536f2b547a8a196858
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/* $Id$ */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/** @file
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * VBox Disassembler - Core Components.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/*
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2006-2012 Oracle Corporation
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * available from http://www.virtualbox.org. This file is free software;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * you can redistribute it and/or modify it under the terms of the GNU
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * General Public License (GPL) as published by the Free Software
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/*******************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync* Header Files *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync*******************************************************************************/
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#define LOG_GROUP LOG_GROUP_DIS
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync#include <VBox/dis.h>
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#include <VBox/disopcode.h>
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#include <VBox/err.h>
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#include <VBox/log.h>
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#include <iprt/assert.h>
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#include <iprt/string.h>
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsync#include <iprt/stdarg.h>
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#include "DisasmInternal.h"
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/*******************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync* Internal Functions *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync*******************************************************************************/
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic unsigned disParseInstruction(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISCPUSTATE pCpu);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic unsigned QueryModRM(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic unsigned QueryModRM_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc = NULL);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic void UseSIB(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);
590bfe12ce22cd3716448fbb9f4dc51664bfe5e2vboxsyncstatic unsigned ParseSIB_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu);
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsync
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsyncstatic void disasmModRMReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr);
43747b1f0bc8302a238fb35e55857a5e9aa1933dvboxsyncstatic void disasmModRMReg16(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic void disasmModRMSReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam);
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic void disValidateLockSequence(PDISCPUSTATE pCpu);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
f5e53763b0a581b0299e98028c6c52192eb06785vboxsync/* Read functions */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR pAddress);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pCpu, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/** @name Parsers
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @{ */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseIllegal;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseModRM;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseModRM_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE UseModRM;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmByte;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmByte_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmByteSX;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic FNDISPARSE ParseImmByteSX_SizeOnly;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic FNDISPARSE ParseImmBRel;
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsyncstatic FNDISPARSE ParseImmBRel_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmUshort;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmUshort_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmV;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic FNDISPARSE ParseImmV_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmVRel;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsyncstatic FNDISPARSE ParseImmVRel_SizeOnly;
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsyncstatic FNDISPARSE ParseImmZ;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsyncstatic FNDISPARSE ParseImmZ_SizeOnly;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmAddr;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmAddr_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmAddrF;
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsyncstatic FNDISPARSE ParseImmAddrF_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseFixedReg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmUlong;
ad27e1d5e48ca41245120c331cc88b50464813cevboxsyncstatic FNDISPARSE ParseImmUlong_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmQword;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmQword_SizeOnly;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseTwoByteEsc;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseThreeByteEsc4;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseThreeByteEsc5;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseImmGrpl;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseShiftGrp2;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp3;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp4;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp5;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE Parse3DNow;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp6;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp7;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp8;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp9;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp10;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp12;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp13;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseGrp14;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsyncstatic FNDISPARSE ParseGrp15;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsyncstatic FNDISPARSE ParseGrp16;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseModFence;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseNopPause;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseYv;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseYb;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseXv;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseXb;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/** Floating point parsing */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic FNDISPARSE ParseEscFP;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/** @} */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/*******************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync* Global Variables *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync*******************************************************************************/
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/** Parser opcode table for full disassembly. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic PFNDISPARSE const g_apfnFullDisasm[IDX_ParseMax] =
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseIllegal,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseModRM,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync UseModRM,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmByte,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmBRel,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmUshort,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmV,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmVRel,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmAddr,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseFixedReg,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmUlong,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmQword,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseTwoByteEsc,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmGrpl,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseShiftGrp2,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp3,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp4,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp5,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync Parse3DNow,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp6,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp7,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp8,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp9,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp10,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp12,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp13,
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync ParseGrp14,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp15,
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync ParseGrp16,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseModFence,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseYv,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseYb,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseXv,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseXb,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseEscFP,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseNopPause,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmByteSX,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmZ,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseThreeByteEsc4,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseThreeByteEsc5,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmAddrF
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync/** Parser opcode table for only calculating instruction size. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic PFNDISPARSE const g_apfnCalcSize[IDX_ParseMax] =
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseIllegal,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseModRM_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync UseModRM,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmByte_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmBRel_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmUshort_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmV_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmVRel_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmAddr_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseFixedReg,
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync ParseImmUlong_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmQword_SizeOnly,
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync ParseTwoByteEsc,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmGrpl,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseShiftGrp2,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp3,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp4,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp5,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync Parse3DNow,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp6,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp7,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp8,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp9,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp10,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp12,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp13,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp14,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp15,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseGrp16,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseModFence,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseYv,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseYb,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseXv,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseXb,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseEscFP,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseNopPause,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmByteSX_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmZ_SizeOnly,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseThreeByteEsc4,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseThreeByteEsc5,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ParseImmAddrF_SizeOnly
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/**
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Parses one guest instruction.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * The result is found in pCpu and pcbInstr.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @returns VBox status code.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pvInstr Address of the instruction to decode. This is a
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * real address in the current context that can be
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * accessed without faulting. (Consider
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * DISInstrWithReader if this isn't the case.)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pfnReadBytes Callback for reading instruction bytes.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pCpu Pointer to cpu structure. Will be initialized.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pcbInstr Where to store the size of the instruction.
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * NULL is allowed. This is also stored in
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * PDISCPUSTATE::opsize.
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync */
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsyncDISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISCPUSTATE pCpu, uint32_t *pcbInstr)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync{
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync return DISInstEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pCpu, pcbInstr);
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync}
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync/**
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Parses one guest instruction.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync *
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * The result is found in pCpu and pcbInstr.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync *
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @returns VBox status code.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param uInstrAddr Address of the instruction to decode. What this means
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * is left to the pfnReadBytes function.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pfnReadBytes Callback for reading instruction bytes.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pCpu Pointer to cpu structure. Will be initialized.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pcbInstr Where to store the size of the instruction.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * NULL is allowed. This is also stored in
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * PDISCPUSTATE::opsize.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync */
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsyncDISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync PDISCPUSTATE pCpu, uint32_t *pcbInstr)
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync{
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync return DISInstEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pCpu, pcbInstr);
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync}
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync/**
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * Disassembles on instruction, details in @a pCpu and length in @a pcbInstr.
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync *
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * @returns VBox status code.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param uInstrAddr Address of the instruction to decode. What this means
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * is left to the pfnReadBytes function.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pfnReadBytes Callback for reading instruction bytes.
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param fFilter Instruction type filter.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * @param pCpu Pointer to CPU structure. With the exception of
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * DISCPUSTATE::pvUser2, the structure will be
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * completely initialized by this API, i.e. no input is
4fcfe0bd966753617b7ab5fb81fb24709914fc1cvboxsync * taken from it.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pcbInstr Where to store the size of the instruction. (This
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * is also stored in PDISCPUSTATE::opsize.) Optional.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncDISDECL(int) DISInstEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync PFNDISREADBYTES pfnReadBytes, void *pvUser,
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync PDISCPUSTATE pCpu, uint32_t *pcbInstr)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync PCDISOPCODE paOneByteMap;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /*
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Initialize the CPU state.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Note! The RT_BZERO make ASSUMPTIONS about the placement of pvUser2.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync RT_BZERO(pCpu, RT_OFFSETOF(DISCPUSTATE, pvUser2));
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->mode = enmCpuMode;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (enmCpuMode == DISCPUMODE_64BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync paOneByteMap = g_aOneByteMapX64;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->addrmode = DISCPUMODE_64BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = DISCPUMODE_32BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync paOneByteMap = g_aOneByteMapX86;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->addrmode = enmCpuMode;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = enmCpuMode;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix = DISPREFIX_NONE;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->idxSegPrefix = DISSELREG_DS;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->uInstrAddr = uInstrAddr;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->pfnDisasmFnTable = g_apfnFullDisasm;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->fFilter = fFilter;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->rc = VINF_SUCCESS;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->pfnReadBytes = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->pvUser = pvUser;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return disInstrWorker(pCpu, uInstrAddr, paOneByteMap, pcbInstr);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync}
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync/**
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Internal worker for DISInstEx.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync *
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @returns VBox status code.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pCpu Initialized cpu state.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param paOneByteMap The one byte opcode map to use.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param uInstrAddr Instruction address.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @param pcbInstr Where to store the instruction size. Can be NULL.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic int disInstrWorker(PDISCPUSTATE pCpu, RTUINTPTR uInstrAddr, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /*
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Parse byte by byte.
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync */
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync unsigned iByte = 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned cbInc;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync for (;;)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync uint8_t codebyte = disReadByte(pCpu, uInstrAddr+iByte);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync uint8_t opcode = paOneByteMap[codebyte].opcode;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Hardcoded assumption about OP_* values!! */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (opcode <= OP_LAST_PREFIX)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (opcode != OP_REX)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->lastprefix = opcode;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix &= ~DISPREFIX_REX;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync switch (opcode)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_INVALID:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pcbInstr)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync *pcbInstr = iByte + 1;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return pCpu->rc = VERR_DIS_INVALID_OPCODE;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync // segment override prefix byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_SEG:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->idxSegPrefix = (DISSELREG)(paOneByteMap[codebyte].param1 - OP_PARM_REG_SEG_START);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if ( pCpu->mode != DISCPUMODE_64BIT
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync || pCpu->idxSegPrefix >= DISSELREG_FS)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix |= DISPREFIX_SEG;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync iByte += sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync continue; //fetch the next byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync // lock prefix byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_LOCK:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix |= DISPREFIX_LOCK;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync iByte += sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync continue; //fetch the next byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync // address size override prefix byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_ADDRSIZE:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix |= DISPREFIX_ADDRSIZE;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->mode == DISCPUMODE_16BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->addrmode = DISCPUMODE_32BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->mode == DISCPUMODE_32BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->addrmode = DISCPUMODE_16BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->addrmode = DISCPUMODE_32BIT; /* 64 bits */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync iByte += sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync continue; //fetch the next byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync // operand size override prefix byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_OPSIZE:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix |= DISPREFIX_OPSIZE;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->mode == DISCPUMODE_16BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = DISCPUMODE_32BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync pCpu->opmode = DISCPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
a7d402dcc23137e7b9527be6de80400043a5fbf4vboxsync
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync iByte += sizeof(uint8_t);
a7d402dcc23137e7b9527be6de80400043a5fbf4vboxsync continue; //fetch the next byte
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync // rep and repne are not really prefixes, but we'll treat them as such
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync case OP_REPE:
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync pCpu->prefix |= DISPREFIX_REP;
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync iByte += sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync continue; //fetch the next byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_REPNE:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix |= DISPREFIX_REPNE;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync iByte += sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync continue; //fetch the next byte
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_REX:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync Assert(pCpu->mode == DISCPUMODE_64BIT);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* REX prefix byte */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix |= DISPREFIX_REX;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->prefix_rex = DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].param1);
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync iByte += sizeof(uint8_t);
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync if (pCpu->prefix_rex & DISPREFIX_REX_FLAGS_W)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->opmode = DISCPUMODE_64BIT; /* overrides size prefix byte */
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync continue; //fetch the next byte
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync }
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync }
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync unsigned uIdx = iByte;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync iByte += sizeof(uint8_t); //first opcode byte
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->opcode = codebyte;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync cbInc = disParseInstruction(uInstrAddr + iByte, &paOneByteMap[pCpu->opcode], pCpu);
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync iByte += cbInc;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync break;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync }
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync AssertMsg(pCpu->opsize == iByte || RT_FAILURE_NP(pCpu->rc), ("%u %u\n", pCpu->opsize, iByte));
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->opsize = iByte;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync if (pcbInstr)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync *pcbInstr = iByte;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync if (pCpu->prefix & DISPREFIX_LOCK)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync disValidateLockSequence(pCpu);
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync return pCpu->rc;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync}
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync//*****************************************************************************
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync//*****************************************************************************
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsyncstatic unsigned disParseInstruction(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISCPUSTATE pCpu)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync{
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync int size = 0;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync bool fFiltered = false;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync Assert(uCodePtr && pOp && pCpu);
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync // Store the opcode format string for disasmPrintf
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->pCurInstr = pOp;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync /*
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * Apply filter to instruction type to determine if a full disassembly is required.
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync * Note! Multibyte opcodes are always marked harmless until the final byte.
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync */
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync if ((pOp->optype & pCpu->fFilter) == 0)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync {
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync fFiltered = true;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->pfnDisasmFnTable = g_apfnCalcSize;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync }
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync else
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync {
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync /* Not filtered out -> full disassembly */
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->pfnDisasmFnTable = g_apfnFullDisasm;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync }
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync // Should contain the parameter type on input
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->param1.param = pOp->param1;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->param2.param = pOp->param2;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync pCpu->param3.param = pOp->param3;
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync /* Correct the operand size if the instruction is marked as forced or default 64 bits */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pCpu->mode == DISCPUMODE_64BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pOp->optype & DISOPTYPE_FORCED_64_OP_SIZE)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync pCpu->opmode = DISCPUMODE_64BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if ( (pOp->optype & DISOPTYPE_DEFAULT_64_OP_SIZE)
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync && !(pCpu->prefix & DISPREFIX_OPSIZE))
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = DISCPUMODE_64BIT;
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync }
a39ea3668b7019c23a68936259545f9b71bce1aavboxsync else
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsync if (pOp->optype & DISOPTYPE_FORCED_32_OP_SIZE_X86)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync {
ee4d840f54fd2dcea8a73b1b86d5ec0db370b05dvboxsync /* Forced 32 bits operand size for certain instructions (mov crx, mov drx). */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync Assert(pCpu->mode != DISCPUMODE_64BIT);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = DISCPUMODE_32BIT;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pOp->idxParse1 != IDX_ParseNop)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync size += pCpu->pfnDisasmFnTable[pOp->idxParse1](uCodePtr, pOp, &pCpu->param1, pCpu);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (fFiltered == false) pCpu->param1.cb = DISGetParamSize(pCpu, &pCpu->param1);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pOp->idxParse2 != IDX_ParseNop)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync size += pCpu->pfnDisasmFnTable[pOp->idxParse2](uCodePtr+size, pOp, &pCpu->param2, pCpu);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (fFiltered == false) pCpu->param2.cb = DISGetParamSize(pCpu, &pCpu->param2);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (pOp->idxParse3 != IDX_ParseNop)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync {
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync size += pCpu->pfnDisasmFnTable[pOp->idxParse3](uCodePtr+size, pOp, &pCpu->param3, pCpu);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (fFiltered == false) pCpu->param3.cb = DISGetParamSize(pCpu, &pCpu->param3);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync // else simple one byte instruction
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync return size;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync}
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync//*****************************************************************************
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync/* Floating point opcode parsing */
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync//*****************************************************************************
e74eef731a813e4e06680c587a6759b9974b29c9vboxsyncunsigned ParseEscFP(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync{
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync int index;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync PCDISOPCODE fpop;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync unsigned size = 0;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync unsigned ModRM;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync NOREF(pOp);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync ModRM = disReadByte(pCpu, uCodePtr);
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync index = pCpu->opcode - 0xD8;
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync if (ModRM <= 0xBF)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync fpop = &(g_apMapX86_FP_Low[index])[MODRM_REG(ModRM)];
cad8876b46f9e366c4a1007a40c27ca1df078950vboxsync pCpu->pCurInstr = (PCDISOPCODE)fpop;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync // Should contain the parameter type on input
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync pCpu->param1.param = fpop->param1;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->param2.param = fpop->param2;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync {
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync fpop = &(g_apMapX86_FP_High[index])[ModRM - 0xC0];
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->pCurInstr = (PCDISOPCODE)fpop;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
e74eef731a813e4e06680c587a6759b9974b29c9vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /*
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Apply filter to instruction type to determine if a full disassembly is required.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * @note Multibyte opcodes are always marked harmless until the final byte.
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync if ((fpop->optype & pCpu->fFilter) == 0)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->pfnDisasmFnTable = g_apfnCalcSize;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Not filtered out -> full disassembly */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->pfnDisasmFnTable = g_apfnFullDisasm;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Correct the operand size if the instruction is marked as forced or default 64 bits */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->mode == DISCPUMODE_64BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Note: redundant, but just in case this ever changes */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (fpop->optype & DISOPTYPE_FORCED_64_OP_SIZE)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = DISCPUMODE_64BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if ( (fpop->optype & DISOPTYPE_DEFAULT_64_OP_SIZE)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync && !(pCpu->prefix & DISPREFIX_OPSIZE))
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->opmode = DISCPUMODE_64BIT;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsync
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync // Little hack to make sure the ModRM byte is included in the returned size
fbf08fabb4c4b383d6aa2830c2bd5b943a26f10cvboxsync if (fpop->idxParse1 != IDX_ParseModRM && fpop->idxParse2 != IDX_ParseModRM)
a7d402dcc23137e7b9527be6de80400043a5fbf4vboxsync size = sizeof(uint8_t); //ModRM byte
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync if (fpop->idxParse1 != IDX_ParseNop)
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync size += pCpu->pfnDisasmFnTable[fpop->idxParse1](uCodePtr+size, (PCDISOPCODE)fpop, pParam, pCpu);
72730eaca1e865cb4503d6f8f00bc00bc5e1c038vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (fpop->idxParse2 != IDX_ParseNop)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync size += pCpu->pfnDisasmFnTable[fpop->idxParse2](uCodePtr+size, (PCDISOPCODE)fpop, pParam, pCpu);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return size;
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync}
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync// SIB byte: (32 bits mode only)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync// 7 - 6 5 - 3 2-0
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync// Scale Index Base
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic const char *szSIBBaseReg[8] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic const char *szSIBIndexReg[8] = {"EAX", "ECX", "EDX", "EBX", NULL, "EBP", "ESI", "EDI"};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic const char *szSIBBaseReg64[16] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic const char *szSIBIndexReg64[16]= {"RAX", "RCX", "RDX", "RBX", NULL, "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED) || defined(_MSC_VER)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncstatic const char *szSIBScale[4] = {"", "*2", "*4", "*8"};
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync#endif
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncvoid UseSIB(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned scale, base, index, regtype;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync const char **ppszSIBIndexReg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync const char **ppszSIBBaseReg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync NOREF(uCodePtr); NOREF(pOp);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync scale = pCpu->SIB.Bits.Scale;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync base = pCpu->SIB.Bits.Base;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync index = pCpu->SIB.Bits.Index;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->addrmode == DISCPUMODE_32BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ppszSIBIndexReg = szSIBIndexReg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ppszSIBBaseReg = szSIBBaseReg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync regtype = DISUSE_REG_GEN32;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ppszSIBIndexReg = szSIBIndexReg64;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync ppszSIBBaseReg = szSIBBaseReg64;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync regtype = DISUSE_REG_GEN64;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (ppszSIBIndexReg[index])
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_INDEX | regtype;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->index.reg_gen = index;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (scale != 0)
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_SCALE;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->scale = (1<<scale);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (base == 5 && pCpu->ModRM.Bits.Mod == 0)
c28fa006ba669ad8f26ae31d00a338379c04ea1bvboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync // [scaled index] + disp32
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->addrmode == DISCPUMODE_32BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_DISPLACEMENT32;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->uDisp.i32 = pCpu->i32SibDisp;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync { /* sign-extend to 64 bits */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_DISPLACEMENT64;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->uDisp.i64 = pCpu->i32SibDisp;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_BASE | regtype;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_gen = base;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return; /* Already fetched everything in ParseSIB; no size returned */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync}
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncunsigned ParseSIB(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned size = sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned SIB;
787c7e6ef15f993c455c374f5158e7bb753b1c33vboxsync NOREF(pOp); NOREF(pParam);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync SIB = disReadByte(pCpu, uCodePtr);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync uCodePtr += size;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Base = SIB_BASE(SIB);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->prefix & DISPREFIX_REX)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* REX.B extends the Base field if not scaled index + disp32 */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (!(pCpu->SIB.Bits.Base == 5 && pCpu->ModRM.Bits.Mod == 0))
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_B)) << 3);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_X)) << 3);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if ( pCpu->SIB.Bits.Base == 5
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync && pCpu->ModRM.Bits.Mod == 0)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Additional 32 bits displacement. No change in long mode. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->i32SibDisp = disReadDWord(pCpu, uCodePtr);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync size += sizeof(int32_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return size;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync}
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncunsigned ParseSIB_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned size = sizeof(uint8_t);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned SIB;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync NOREF(pOp); NOREF(pParam);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync SIB = disReadByte(pCpu, uCodePtr);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync uCodePtr += size;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Base = SIB_BASE(SIB);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Index = SIB_INDEX(SIB);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Scale = SIB_SCALE(SIB);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->prefix & DISPREFIX_REX)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* REX.B extends the Base field. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Base |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_B)) << 3);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* REX.X extends the Index field. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->SIB.Bits.Index |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_X)) << 3);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if ( pCpu->SIB.Bits.Base == 5
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync && pCpu->ModRM.Bits.Mod == 0)
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* Additional 32 bits displacement. No change in long mode. */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync size += sizeof(int32_t);
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync }
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync return size;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync}
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync// ModR/M byte:
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync// 7 - 6 5 - 3 2-0
25747178cb66800d8386c20b8ffd87f78f24f4e5vboxsync// Mod Reg/Opcode R/M
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync//*****************************************************************************
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsyncunsigned UseModRM(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync{
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync int vtype = OP_PARM_VTYPE(pParam->param);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned reg = pCpu->ModRM.Bits.Reg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned mod = pCpu->ModRM.Bits.Mod;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync unsigned rm = pCpu->ModRM.Bits.Rm;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync switch (vtype)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_G: //general purpose register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync disasmModRMReg(pCpu, pOp, reg, pParam, 0);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync default:
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (IS_OP_PARM_RARE(vtype))
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync switch (vtype)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_C: //control register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_REG_CR;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if ( pCpu->pCurInstr->opcode == OP_MOV_CR
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync && pCpu->opmode == DISCPUMODE_32BIT
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync && (pCpu->prefix & DISPREFIX_LOCK))
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pCpu->prefix &= ~DISPREFIX_LOCK;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_ctrl = DISCREG_CR8;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_ctrl = reg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_D: //debug register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_REG_DBG;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_dbg = reg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_P: //MMX register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync reg &= 7; /* REX.R has no effect here */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_REG_MMX;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_mmx = reg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_S: //segment register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync reg &= 7; /* REX.R has no effect here */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync disasmModRMSReg(pCpu, pOp, reg, pParam);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_REG_SEG;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_T: //test register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync reg &= 7; /* REX.R has no effect here */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_REG_TEST;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_test = reg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
2c8ee291fb75c4a6f05df160f5d67f4e9ef1cabcvboxsync case OP_PARM_W: //XMM register or memory operand
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (mod != 3)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync break; /* memory operand */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync reg = rm; /* the RM field specifies the xmm register */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* else no break */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case OP_PARM_V: //XMM register
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_REG_XMM;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->base.reg_xmm = reg;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync return 0;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* @todo bound */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->addrmode != DISCPUMODE_16BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync Assert(pCpu->addrmode == DISCPUMODE_32BIT || pCpu->addrmode == DISCPUMODE_64BIT);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /*
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync * Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync switch (mod)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync case 0: //effective address
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (rm == 4)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync { /* SIB byte follows ModRM */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync UseSIB(uCodePtr, pOp, pParam, pCpu);
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (rm == 5)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync /* 32 bits displacement */
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync if (pCpu->mode != DISCPUMODE_64BIT)
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_DISPLACEMENT32;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->uDisp.i32 = pCpu->i32SibDisp;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync {
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->fUse |= DISUSE_RIPDISPLACEMENT32;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync pParam->uDisp.i32 = pCpu->i32SibDisp;
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync }
24ab761b2beb5af0393c6f2585b6351d8b3085f0vboxsync else
{ //register address
pParam->fUse |= DISUSE_BASE;
disasmModRMReg(pCpu, pOp, rm, pParam, 1);
}
break;
case 1: //effective address + 8 bits displacement
if (rm == 4) {//SIB byte follows ModRM
UseSIB(uCodePtr, pOp, pParam, pCpu);
}
else
{
pParam->fUse |= DISUSE_BASE;
disasmModRMReg(pCpu, pOp, rm, pParam, 1);
}
pParam->uDisp.i8 = pCpu->i32SibDisp;
pParam->fUse |= DISUSE_DISPLACEMENT8;
break;
case 2: //effective address + 32 bits displacement
if (rm == 4) {//SIB byte follows ModRM
UseSIB(uCodePtr, pOp, pParam, pCpu);
}
else
{
pParam->fUse |= DISUSE_BASE;
disasmModRMReg(pCpu, pOp, rm, pParam, 1);
}
pParam->uDisp.i32 = pCpu->i32SibDisp;
pParam->fUse |= DISUSE_DISPLACEMENT32;
break;
case 3: //registers
disasmModRMReg(pCpu, pOp, rm, pParam, 0);
break;
}
}
else
{//16 bits addressing mode
switch (mod)
{
case 0: //effective address
if (rm == 6)
{//16 bits displacement
pParam->uDisp.i16 = pCpu->i32SibDisp;
pParam->fUse |= DISUSE_DISPLACEMENT16;
}
else
{
pParam->fUse |= DISUSE_BASE;
disasmModRMReg16(pCpu, pOp, rm, pParam);
}
break;
case 1: //effective address + 8 bits displacement
disasmModRMReg16(pCpu, pOp, rm, pParam);
pParam->uDisp.i8 = pCpu->i32SibDisp;
pParam->fUse |= DISUSE_BASE | DISUSE_DISPLACEMENT8;
break;
case 2: //effective address + 16 bits displacement
disasmModRMReg16(pCpu, pOp, rm, pParam);
pParam->uDisp.i16 = pCpu->i32SibDisp;
pParam->fUse |= DISUSE_BASE | DISUSE_DISPLACEMENT16;
break;
case 3: //registers
disasmModRMReg(pCpu, pOp, rm, pParam, 0);
break;
}
}
return 0; //everything was already fetched in ParseModRM
}
//*****************************************************************************
// Query the size of the ModRM parameters and fetch the immediate data (if any)
//*****************************************************************************
unsigned QueryModRM(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
{
unsigned sibinc;
unsigned size = 0;
// unsigned reg = pCpu->ModRM.Bits.Reg;
unsigned mod = pCpu->ModRM.Bits.Mod;
unsigned rm = pCpu->ModRM.Bits.Rm;
if (!pSibInc)
pSibInc = &sibinc;
*pSibInc = 0;
if (pCpu->addrmode != DISCPUMODE_16BIT)
{
Assert(pCpu->addrmode == DISCPUMODE_32BIT || pCpu->addrmode == DISCPUMODE_64BIT);
/*
* Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
*/
if (mod != 3 && rm == 4)
{ /* SIB byte follows ModRM */
*pSibInc = ParseSIB(uCodePtr, pOp, pParam, pCpu);
uCodePtr += *pSibInc;
size += *pSibInc;
}
switch (mod)
{
case 0: /* Effective address */
if (rm == 5) { /* 32 bits displacement */
pCpu->i32SibDisp = disReadDWord(pCpu, uCodePtr);
size += sizeof(int32_t);
}
/* else register address */
break;
case 1: /* Effective address + 8 bits displacement */
pCpu->i32SibDisp = (int8_t)disReadByte(pCpu, uCodePtr);
size += sizeof(char);
break;
case 2: /* Effective address + 32 bits displacement */
pCpu->i32SibDisp = disReadDWord(pCpu, uCodePtr);
size += sizeof(int32_t);
break;
case 3: /* registers */
break;
}
}
else
{
/* 16 bits mode */
switch (mod)
{
case 0: /* Effective address */
if (rm == 6) {
pCpu->i32SibDisp = disReadWord(pCpu, uCodePtr);
size += sizeof(uint16_t);
}
/* else register address */
break;
case 1: /* Effective address + 8 bits displacement */
pCpu->i32SibDisp = (int8_t)disReadByte(pCpu, uCodePtr);
size += sizeof(char);
break;
case 2: /* Effective address + 32 bits displacement */
pCpu->i32SibDisp = (int16_t)disReadWord(pCpu, uCodePtr);
size += sizeof(uint16_t);
break;
case 3: /* registers */
break;
}
}
return size;
}
//*****************************************************************************
// Query the size of the ModRM parameters and fetch the immediate data (if any)
//*****************************************************************************
unsigned QueryModRM_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu, unsigned *pSibInc)
{
unsigned sibinc;
unsigned size = 0;
// unsigned reg = pCpu->ModRM.Bits.Reg;
unsigned mod = pCpu->ModRM.Bits.Mod;
unsigned rm = pCpu->ModRM.Bits.Rm;
if (!pSibInc)
pSibInc = &sibinc;
*pSibInc = 0;
if (pCpu->addrmode != DISCPUMODE_16BIT)
{
Assert(pCpu->addrmode == DISCPUMODE_32BIT || pCpu->addrmode == DISCPUMODE_64BIT);
/*
* Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
*/
if (mod != 3 && rm == 4)
{ /* SIB byte follows ModRM */
*pSibInc = ParseSIB_SizeOnly(uCodePtr, pOp, pParam, pCpu);
uCodePtr += *pSibInc;
size += *pSibInc;
}
switch (mod)
{
case 0: //effective address
if (rm == 5) { /* 32 bits displacement */
size += sizeof(int32_t);
}
/* else register address */
break;
case 1: /* Effective address + 8 bits displacement */
size += sizeof(char);
break;
case 2: /* Effective address + 32 bits displacement */
size += sizeof(int32_t);
break;
case 3: /* registers */
break;
}
}
else
{
/* 16 bits mode */
switch (mod)
{
case 0: //effective address
if (rm == 6) {
size += sizeof(uint16_t);
}
/* else register address */
break;
case 1: /* Effective address + 8 bits displacement */
size += sizeof(char);
break;
case 2: /* Effective address + 32 bits displacement */
size += sizeof(uint16_t);
break;
case 3: /* registers */
break;
}
}
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseIllegal(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
AssertFailed();
return 0;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseModRM(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = sizeof(uint8_t); //ModRM byte
unsigned sibinc, ModRM;
ModRM = disReadByte(pCpu, uCodePtr);
uCodePtr += sizeof(uint8_t);
pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
/* Disregard the mod bits for certain instructions (mov crx, mov drx).
*
* From the AMD manual:
* This instruction is always treated as a register-to-register (MOD = 11) instruction, regardless of the
* encoding of the MOD field in the MODR/M byte.
*/
if (pOp->optype & DISOPTYPE_MOD_FIXED_11)
pCpu->ModRM.Bits.Mod = 3;
if (pCpu->prefix & DISPREFIX_REX)
{
Assert(pCpu->mode == DISCPUMODE_64BIT);
/* REX.R extends the Reg field. */
pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_R)) << 3);
/* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
if (!( pCpu->ModRM.Bits.Mod != 3
&& pCpu->ModRM.Bits.Rm == 4)
&&
!( pCpu->ModRM.Bits.Mod == 0
&& pCpu->ModRM.Bits.Rm == 5))
{
pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_B)) << 3);
}
}
size += QueryModRM(uCodePtr, pOp, pParam, pCpu, &sibinc);
uCodePtr += sibinc;
UseModRM(uCodePtr, pOp, pParam, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseModRM_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = sizeof(uint8_t); //ModRM byte
unsigned sibinc, ModRM;
ModRM = disReadByte(pCpu, uCodePtr);
uCodePtr += sizeof(uint8_t);
pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
/* Disregard the mod bits for certain instructions (mov crx, mov drx).
*
* From the AMD manual:
* This instruction is always treated as a register-to-register (MOD = 11) instruction, regardless of the
* encoding of the MOD field in the MODR/M byte.
*/
if (pOp->optype & DISOPTYPE_MOD_FIXED_11)
pCpu->ModRM.Bits.Mod = 3;
if (pCpu->prefix & DISPREFIX_REX)
{
Assert(pCpu->mode == DISCPUMODE_64BIT);
/* REX.R extends the Reg field. */
pCpu->ModRM.Bits.Reg |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_R)) << 3);
/* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
if (!( pCpu->ModRM.Bits.Mod != 3
&& pCpu->ModRM.Bits.Rm == 4)
&&
!( pCpu->ModRM.Bits.Mod == 0
&& pCpu->ModRM.Bits.Rm == 5))
{
pCpu->ModRM.Bits.Rm |= ((!!(pCpu->prefix_rex & DISPREFIX_REX_FLAGS_B)) << 3);
}
}
size += QueryModRM_SizeOnly(uCodePtr, pOp, pParam, pCpu, &sibinc);
uCodePtr += sibinc;
/* UseModRM is not necessary here; we're only interested in the opcode size */
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseModFence(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
////AssertMsgFailed(("??\n"));
//nothing to do apparently
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return 0;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmByte(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
pParam->parval = disReadByte(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE8;
pParam->cb = sizeof(uint8_t);
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmByte_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmByteSX(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
if (pCpu->opmode == DISCPUMODE_32BIT)
{
pParam->parval = (uint32_t)(int8_t)disReadByte(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE32_SX8;
pParam->cb = sizeof(uint32_t);
}
else
if (pCpu->opmode == DISCPUMODE_64BIT)
{
pParam->parval = (uint64_t)(int8_t)disReadByte(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE64_SX8;
pParam->cb = sizeof(uint64_t);
}
else
{
pParam->parval = (uint16_t)(int8_t)disReadByte(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE16_SX8;
pParam->cb = sizeof(uint16_t);
}
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmByteSX_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmUshort(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
pParam->parval = disReadWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmUshort_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmUlong(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
pParam->parval = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE32;
pParam->cb = sizeof(uint32_t);
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmUlong_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmQword(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
pParam->parval = disReadQWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE64;
pParam->cb = sizeof(uint64_t);
return sizeof(uint64_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmQword_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return sizeof(uint64_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmV(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
if (pCpu->opmode == DISCPUMODE_32BIT)
{
pParam->parval = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE32;
pParam->cb = sizeof(uint32_t);
return sizeof(uint32_t);
}
if (pCpu->opmode == DISCPUMODE_64BIT)
{
pParam->parval = disReadQWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE64;
pParam->cb = sizeof(uint64_t);
return sizeof(uint64_t);
}
pParam->parval = disReadWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmV_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam);
if (pCpu->opmode == DISCPUMODE_32BIT)
return sizeof(uint32_t);
if (pCpu->opmode == DISCPUMODE_64BIT)
return sizeof(uint64_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmZ(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
/* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */
if (pCpu->opmode == DISCPUMODE_16BIT)
{
pParam->parval = disReadWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
/* 64 bits op mode means *sign* extend to 64 bits. */
if (pCpu->opmode == DISCPUMODE_64BIT)
{
pParam->parval = (uint64_t)(int32_t)disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE64;
pParam->cb = sizeof(uint64_t);
}
else
{
pParam->parval = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE32;
pParam->cb = sizeof(uint32_t);
}
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmZ_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam);
/* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */
if (pCpu->opmode == DISCPUMODE_16BIT)
return sizeof(uint16_t);
return sizeof(uint32_t);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
unsigned ParseImmBRel(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
pParam->parval = disReadByte(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE8_REL;
pParam->cb = sizeof(uint8_t);
return sizeof(char);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
unsigned ParseImmBRel_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam); NOREF(pCpu);
return sizeof(char);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
unsigned ParseImmVRel(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(pOp);
if (pCpu->opmode == DISCPUMODE_32BIT)
{
pParam->parval = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE32_REL;
pParam->cb = sizeof(int32_t);
return sizeof(int32_t);
}
if (pCpu->opmode == DISCPUMODE_64BIT)
{
/* 32 bits relative immediate sign extended to 64 bits. */
pParam->parval = (uint64_t)(int32_t)disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE64_REL;
pParam->cb = sizeof(int64_t);
return sizeof(int32_t);
}
pParam->parval = disReadWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE16_REL;
pParam->cb = sizeof(int16_t);
return sizeof(int16_t);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
unsigned ParseImmVRel_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp); NOREF(pParam);
if (pCpu->opmode == DISCPUMODE_16BIT)
return sizeof(int16_t);
/* Both 32 & 64 bits mode use 32 bits relative immediates. */
return sizeof(int32_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmAddr(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
if (pCpu->addrmode == DISCPUMODE_32BIT)
{
if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
{
/* far 16:32 pointer */
pParam->parval = disReadDWord(pCpu, uCodePtr);
*((uint32_t*)&pParam->parval+1) = disReadWord(pCpu, uCodePtr+sizeof(uint32_t));
pParam->fUse |= DISUSE_IMMEDIATE_ADDR_16_32;
pParam->cb = sizeof(uint16_t) + sizeof(uint32_t);
return sizeof(uint32_t) + sizeof(uint16_t);
}
/*
* near 32 bits pointer
*
* Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
* so we treat it like displacement.
*/
pParam->uDisp.i32 = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_DISPLACEMENT32;
pParam->cb = sizeof(uint32_t);
return sizeof(uint32_t);
}
if (pCpu->addrmode == DISCPUMODE_64BIT)
{
Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
/*
* near 64 bits pointer
*
* Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
* so we treat it like displacement.
*/
pParam->uDisp.i64 = disReadQWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_DISPLACEMENT64;
pParam->cb = sizeof(uint64_t);
return sizeof(uint64_t);
}
if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
{
/* far 16:16 pointer */
pParam->parval = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE_ADDR_16_16;
pParam->cb = 2*sizeof(uint16_t);
return sizeof(uint32_t);
}
/*
* near 16 bits pointer
*
* Note: used only in "mov al|ax|eax, [Addr]" and "mov [Addr], al|ax|eax"
* so we treat it like displacement.
*/
pParam->uDisp.i16 = disReadWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_DISPLACEMENT16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmAddr_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp);
if (pCpu->addrmode == DISCPUMODE_32BIT)
{
if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
{// far 16:32 pointer
return sizeof(uint32_t) + sizeof(uint16_t);
}
else
{// near 32 bits pointer
return sizeof(uint32_t);
}
}
if (pCpu->addrmode == DISCPUMODE_64BIT)
{
Assert(OP_PARM_VSUBTYPE(pParam->param) != OP_PARM_p);
return sizeof(uint64_t);
}
else
{
if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p)
{// far 16:16 pointer
return sizeof(uint32_t);
}
else
{// near 16 bits pointer
return sizeof(uint16_t);
}
}
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmAddrF(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
// immediate far pointers - only 16:16 or 16:32; determined by operand, *not* address size!
Assert(pCpu->opmode == DISCPUMODE_16BIT || pCpu->opmode == DISCPUMODE_32BIT);
Assert(OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p);
if (pCpu->opmode == DISCPUMODE_32BIT)
{
// far 16:32 pointer
pParam->parval = disReadDWord(pCpu, uCodePtr);
*((uint32_t*)&pParam->parval+1) = disReadWord(pCpu, uCodePtr+sizeof(uint32_t));
pParam->fUse |= DISUSE_IMMEDIATE_ADDR_16_32;
pParam->cb = sizeof(uint16_t) + sizeof(uint32_t);
return sizeof(uint32_t) + sizeof(uint16_t);
}
// far 16:16 pointer
pParam->parval = disReadDWord(pCpu, uCodePtr);
pParam->fUse |= DISUSE_IMMEDIATE_ADDR_16_16;
pParam->cb = 2*sizeof(uint16_t);
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmAddrF_SizeOnly(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp);
// immediate far pointers - only 16:16 or 16:32
Assert(pCpu->opmode == DISCPUMODE_16BIT || pCpu->opmode == DISCPUMODE_32BIT);
Assert(OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p);
if (pCpu->opmode == DISCPUMODE_32BIT)
{
// far 16:32 pointer
return sizeof(uint32_t) + sizeof(uint16_t);
}
else
{
// far 16:16 pointer
return sizeof(uint32_t);
}
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseFixedReg(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr);
/*
* Sets up flags for stored in OPC fixed registers.
*/
if (pParam->param == OP_PARM_NONE)
{
/* No parameter at all. */
return 0;
}
AssertCompile(OP_PARM_REG_GEN32_END < OP_PARM_REG_SEG_END);
AssertCompile(OP_PARM_REG_SEG_END < OP_PARM_REG_GEN16_END);
AssertCompile(OP_PARM_REG_GEN16_END < OP_PARM_REG_GEN8_END);
AssertCompile(OP_PARM_REG_GEN8_END < OP_PARM_REG_FP_END);
if (pParam->param <= OP_PARM_REG_GEN32_END)
{
/* 32-bit EAX..EDI registers. */
if (pCpu->opmode == DISCPUMODE_32BIT)
{
/* Use 32-bit registers. */
pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
pParam->fUse |= DISUSE_REG_GEN32;
pParam->cb = 4;
}
else
if (pCpu->opmode == DISCPUMODE_64BIT)
{
/* Use 64-bit registers. */
pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
if ( (pOp->optype & DISOPTYPE_REXB_EXTENDS_OPREG)
&& pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
&& (pCpu->prefix & DISPREFIX_REX)
&& (pCpu->prefix_rex & DISPREFIX_REX_FLAGS))
pParam->base.reg_gen += 8;
pParam->fUse |= DISUSE_REG_GEN64;
pParam->cb = 8;
}
else
{
/* Use 16-bit registers. */
pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN32_START;
pParam->fUse |= DISUSE_REG_GEN16;
pParam->cb = 2;
pParam->param = pParam->param - OP_PARM_REG_GEN32_START + OP_PARM_REG_GEN16_START;
}
}
else
if (pParam->param <= OP_PARM_REG_SEG_END)
{
/* Segment ES..GS registers. */
pParam->base.reg_seg = (DISSELREG)(pParam->param - OP_PARM_REG_SEG_START);
pParam->fUse |= DISUSE_REG_SEG;
pParam->cb = 2;
}
else
if (pParam->param <= OP_PARM_REG_GEN16_END)
{
/* 16-bit AX..DI registers. */
pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN16_START;
pParam->fUse |= DISUSE_REG_GEN16;
pParam->cb = 2;
}
else
if (pParam->param <= OP_PARM_REG_GEN8_END)
{
/* 8-bit AL..DL, AH..DH registers. */
pParam->base.reg_gen = pParam->param - OP_PARM_REG_GEN8_START;
pParam->fUse |= DISUSE_REG_GEN8;
pParam->cb = 1;
if (pCpu->opmode == DISCPUMODE_64BIT)
{
if ( (pOp->optype & DISOPTYPE_REXB_EXTENDS_OPREG)
&& pParam == &pCpu->param1 /* ugly assumption that it only applies to the first parameter */
&& (pCpu->prefix & DISPREFIX_REX)
&& (pCpu->prefix_rex & DISPREFIX_REX_FLAGS))
pParam->base.reg_gen += 8; /* least significant byte of R8-R15 */
}
}
else
if (pParam->param <= OP_PARM_REG_FP_END)
{
/* FPU registers. */
pParam->base.reg_fp = pParam->param - OP_PARM_REG_FP_START;
pParam->fUse |= DISUSE_REG_FP;
pParam->cb = 10;
}
Assert(!(pParam->param >= OP_PARM_REG_GEN64_START && pParam->param <= OP_PARM_REG_GEN64_END));
/* else - not supported for now registers. */
return 0;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseXv(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr);
pParam->fUse |= DISUSE_POINTER_DS_BASED;
if (pCpu->addrmode == DISCPUMODE_32BIT)
{
pParam->base.reg_gen = DISGREG_ESI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pCpu->addrmode == DISCPUMODE_64BIT)
{
pParam->base.reg_gen = DISGREG_RSI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->base.reg_gen = DISGREG_SI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseXb(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp);
pParam->fUse |= DISUSE_POINTER_DS_BASED;
if (pCpu->addrmode == DISCPUMODE_32BIT)
{
pParam->base.reg_gen = DISGREG_ESI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pCpu->addrmode == DISCPUMODE_64BIT)
{
pParam->base.reg_gen = DISGREG_RSI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->base.reg_gen = DISGREG_SI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseYv(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr);
pParam->fUse |= DISUSE_POINTER_ES_BASED;
if (pCpu->addrmode == DISCPUMODE_32BIT)
{
pParam->base.reg_gen = DISGREG_EDI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pCpu->addrmode == DISCPUMODE_64BIT)
{
pParam->base.reg_gen = DISGREG_RDI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->base.reg_gen = DISGREG_DI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseYb(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
NOREF(uCodePtr); NOREF(pOp);
pParam->fUse |= DISUSE_POINTER_ES_BASED;
if (pCpu->addrmode == DISCPUMODE_32BIT)
{
pParam->base.reg_gen = DISGREG_EDI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pCpu->addrmode == DISCPUMODE_64BIT)
{
pParam->base.reg_gen = DISGREG_RDI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->base.reg_gen = DISGREG_DI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseTwoByteEsc(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
PCDISOPCODE pOpcode;
int size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
/* 2nd byte */
pCpu->opcode = disReadByte(pCpu, uCodePtr);
/* default to the non-prefixed table. */
pOpcode = &g_aTwoByteMapX86[pCpu->opcode];
/* Handle opcode table extensions that rely on the address, repe or repne prefix byte. */
/** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
if (pCpu->lastprefix)
{
switch (pCpu->lastprefix)
{
case OP_OPSIZE: /* 0x66 */
if (g_aTwoByteMapX86_PF66[pCpu->opcode].opcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
pOpcode = &g_aTwoByteMapX86_PF66[pCpu->opcode];
/* Cancel prefix changes. */
pCpu->prefix &= ~DISPREFIX_OPSIZE;
pCpu->opmode = pCpu->mode;
}
break;
case OP_REPNE: /* 0xF2 */
if (g_aTwoByteMapX86_PFF2[pCpu->opcode].opcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
pOpcode = &g_aTwoByteMapX86_PFF2[pCpu->opcode];
/* Cancel prefix changes. */
pCpu->prefix &= ~DISPREFIX_REPNE;
}
break;
case OP_REPE: /* 0xF3 */
if (g_aTwoByteMapX86_PFF3[pCpu->opcode].opcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
pOpcode = &g_aTwoByteMapX86_PFF3[pCpu->opcode];
/* Cancel prefix changes. */
pCpu->prefix &= ~DISPREFIX_REP;
}
break;
}
}
size += disParseInstruction(uCodePtr+size, pOpcode, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseThreeByteEsc4(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
PCDISOPCODE pOpcode;
int size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
/* 3rd byte */
pCpu->opcode = disReadByte(pCpu, uCodePtr);
/* default to the non-prefixed table. */
if (g_apThreeByteMapX86_0F38[pCpu->opcode >> 4])
{
pOpcode = g_apThreeByteMapX86_0F38[pCpu->opcode >> 4];
pOpcode = &pOpcode[pCpu->opcode & 0xf];
}
else
pOpcode = &g_InvalidOpcode[0];
/* Handle opcode table extensions that rely on the address, repne prefix byte. */
/** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
switch (pCpu->lastprefix)
{
case OP_OPSIZE: /* 0x66 */
if (g_apThreeByteMapX86_660F38[pCpu->opcode >> 4])
{
pOpcode = g_apThreeByteMapX86_660F38[pCpu->opcode >> 4];
pOpcode = &pOpcode[pCpu->opcode & 0xf];
if (pOpcode->opcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
/* Cancel prefix changes. */
pCpu->prefix &= ~DISPREFIX_OPSIZE;
pCpu->opmode = pCpu->mode;
}
}
break;
case OP_REPNE: /* 0xF2 */
if (g_apThreeByteMapX86_F20F38[pCpu->opcode >> 4])
{
pOpcode = g_apThreeByteMapX86_F20F38[pCpu->opcode >> 4];
pOpcode = &pOpcode[pCpu->opcode & 0xf];
if (pOpcode->opcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
/* Cancel prefix changes. */
pCpu->prefix &= ~DISPREFIX_REPNE;
}
}
break;
}
size += disParseInstruction(uCodePtr+size, pOpcode, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseThreeByteEsc5(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
PCDISOPCODE pOpcode;
int size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
/* 3rd byte */
pCpu->opcode = disReadByte(pCpu, uCodePtr);
/** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
Assert(pCpu->lastprefix == OP_OPSIZE);
/* default to the non-prefixed table. */
if (g_apThreeByteMapX86_660F3A[pCpu->opcode >> 4])
{
pOpcode = g_apThreeByteMapX86_660F3A[pCpu->opcode >> 4];
pOpcode = &pOpcode[pCpu->opcode & 0xf];
if (pOpcode->opcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
/* Cancel prefix changes. */
pCpu->prefix &= ~DISPREFIX_OPSIZE;
pCpu->opmode = pCpu->mode;
}
}
else
pOpcode = &g_InvalidOpcode[0];
size += disParseInstruction(uCodePtr+size, pOpcode, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseNopPause(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0;
NOREF(pParam);
if (pCpu->prefix & DISPREFIX_REP)
{
pOp = &g_aMapX86_NopPause[1]; /* PAUSE */
pCpu->prefix &= ~DISPREFIX_REP;
}
else
pOp = &g_aMapX86_NopPause[0]; /* NOP */
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseImmGrpl(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
int idx = (pCpu->opcode - 0x80) * 8;
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group1[idx+reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseShiftGrp2(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
int idx;
unsigned size = 0, modrm, reg;
NOREF(pParam);
switch (pCpu->opcode)
{
case 0xC0:
case 0xC1:
idx = (pCpu->opcode - 0xC0)*8;
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
idx = (pCpu->opcode - 0xD0 + 2)*8;
break;
default:
AssertMsgFailed(("Oops\n"));
return sizeof(uint8_t);
}
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group2[idx+reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp3(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
int idx = (pCpu->opcode - 0xF6) * 8;
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group3[idx+reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp4(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group4[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp5(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group5[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
// 0xF 0xF [ModRM] [SIB] [displacement] imm8_opcode
// It would appear the ModRM byte must always be present. How else can you
// determine the offset of the imm8_opcode byte otherwise?
//
//*****************************************************************************
unsigned Parse3DNow(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrmsize;
#ifdef DEBUG_Sander
//needs testing
AssertMsgFailed(("Test me\n"));
#endif
unsigned ModRM = disReadByte(pCpu, uCodePtr);
pCpu->ModRM.Bits.Rm = MODRM_RM(ModRM);
pCpu->ModRM.Bits.Mod = MODRM_MOD(ModRM);
pCpu->ModRM.Bits.Reg = MODRM_REG(ModRM);
modrmsize = QueryModRM(uCodePtr+sizeof(uint8_t), pOp, pParam, pCpu);
uint8_t opcode = disReadByte(pCpu, uCodePtr+sizeof(uint8_t)+modrmsize);
pOp = (PCDISOPCODE)&g_aTwoByteMapX86_3DNow[opcode];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
{
#ifdef DEBUG_Sander /* bird, 2005-06-28: Alex is getting this during full installation of win2ksp4. */
AssertMsgFailed(("Oops!\n")); //shouldn't happen!
#endif
size = sizeof(uint8_t); //ModRM byte
}
size += disParseInstruction(uCodePtr, pOp, pCpu);
size += sizeof(uint8_t); //imm8_opcode uint8_t
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp6(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group6[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp7(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg, rm, mod;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
mod = MODRM_MOD(modrm);
reg = MODRM_REG(modrm);
rm = MODRM_RM(modrm);
if (mod == 3 && rm == 0)
pOp = (PCDISOPCODE)&g_aMapX86_Group7_mod11_rm000[reg];
else
if (mod == 3 && rm == 1)
pOp = (PCDISOPCODE)&g_aMapX86_Group7_mod11_rm001[reg];
else
pOp = (PCDISOPCODE)&g_aMapX86_Group7_mem[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp8(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group8[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp9(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group9[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp10(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group10[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp12(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
if (pCpu->prefix & DISPREFIX_OPSIZE)
reg += 8; //2nd table
pOp = (PCDISOPCODE)&g_aMapX86_Group12[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp13(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
if (pCpu->prefix & DISPREFIX_OPSIZE)
reg += 8; //2nd table
pOp = (PCDISOPCODE)&g_aMapX86_Group13[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp14(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
if (pCpu->prefix & DISPREFIX_OPSIZE)
reg += 8; //2nd table
pOp = (PCDISOPCODE)&g_aMapX86_Group14[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp15(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg, mod, rm;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
mod = MODRM_MOD(modrm);
reg = MODRM_REG(modrm);
rm = MODRM_RM(modrm);
if (mod == 3 && rm == 0)
pOp = (PCDISOPCODE)&g_aMapX86_Group15_mod11_rm000[reg];
else
pOp = (PCDISOPCODE)&g_aMapX86_Group15_mem[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
//*****************************************************************************
unsigned ParseGrp16(RTUINTPTR uCodePtr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISCPUSTATE pCpu)
{
unsigned size = 0, modrm, reg;
NOREF(pParam);
modrm = disReadByte(pCpu, uCodePtr);
reg = MODRM_REG(modrm);
pOp = (PCDISOPCODE)&g_aMapX86_Group16[reg];
//little hack to make sure the ModRM byte is included in the returned size
if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
size += disParseInstruction(uCodePtr, pOp, pCpu);
return size;
}
//*****************************************************************************
#if !defined(DIS_CORE_ONLY) && defined(LOG_ENABLED)
static const char *szModRMReg8[] = {"AL", "CL", "DL", "BL", "AH", "CH", "DH", "BH", "R8B", "R9B", "R10B", "R11B", "R12B", "R13B", "R14B", "R15B", "SPL", "BPL", "SIL", "DIL"};
static const char *szModRMReg16[] = {"AX", "CX", "DX", "BX", "SP", "BP", "SI", "DI", "R8W", "R9W", "R10W", "R11W", "R12W", "R13W", "R14W", "R15W"};
static const char *szModRMReg32[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI", "R8D", "R9D", "R10D", "R11D", "R12D", "R13D", "R14D", "R15D"};
static const char *szModRMReg64[] = {"RAX", "RCX", "RDX", "RBX", "RSP", "RBP", "RSI", "RDI", "R8", "R9", "R10", "R11", "R12", "R13", "R14", "R15"};
static const char *szModRMReg1616[8] = {"BX+SI", "BX+DI", "BP+SI", "BP+DI", "SI", "DI", "BP", "BX"};
#endif
static const char *szModRMSegReg[6] = {"ES", "CS", "SS", "DS", "FS", "GS"};
static const int BaseModRMReg16[8] = { DISGREG_BX, DISGREG_BX, DISGREG_BP, DISGREG_BP, DISGREG_SI, DISGREG_DI, DISGREG_BP, DISGREG_BX};
static const int IndexModRMReg16[4] = { DISGREG_SI, DISGREG_DI, DISGREG_SI, DISGREG_DI};
//*****************************************************************************
static void disasmModRMReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr)
{
int subtype, type, mod;
NOREF(pOp); NOREF(pCpu);
mod = pCpu->ModRM.Bits.Mod;
type = OP_PARM_VTYPE(pParam->param);
subtype = OP_PARM_VSUBTYPE(pParam->param);
if (fRegAddr)
subtype = (pCpu->addrmode == DISCPUMODE_64BIT) ? OP_PARM_q : OP_PARM_d;
else
if (subtype == OP_PARM_v || subtype == OP_PARM_NONE)
{
switch(pCpu->opmode)
{
case DISCPUMODE_32BIT:
subtype = OP_PARM_d;
break;
case DISCPUMODE_64BIT:
subtype = OP_PARM_q;
break;
case DISCPUMODE_16BIT:
subtype = OP_PARM_w;
break;
default:
/* make gcc happy */
break;
}
}
switch (subtype)
{
case OP_PARM_b:
Assert(idx < (pCpu->prefix & DISPREFIX_REX ? 16U : 8U));
/* AH, BH, CH & DH map to DIL, SIL, EBL & SPL when a rex prefix is present. */
/* Intel� 64 and IA-32 Architectures Software Developer�s Manual: 3.4.1.1 */
if ( (pCpu->prefix & DISPREFIX_REX)
&& idx >= DISGREG_AH
&& idx <= DISGREG_BH)
{
idx += (DISGREG_SPL - DISGREG_AH);
}
pParam->fUse |= DISUSE_REG_GEN8;
pParam->base.reg_gen = idx;
break;
case OP_PARM_w:
Assert(idx < (pCpu->prefix & DISPREFIX_REX ? 16U : 8U));
pParam->fUse |= DISUSE_REG_GEN16;
pParam->base.reg_gen = idx;
break;
case OP_PARM_d:
Assert(idx < (pCpu->prefix & DISPREFIX_REX ? 16U : 8U));
pParam->fUse |= DISUSE_REG_GEN32;
pParam->base.reg_gen = idx;
break;
case OP_PARM_q:
pParam->fUse |= DISUSE_REG_GEN64;
pParam->base.reg_gen = idx;
break;
default:
Log(("disasmModRMReg %x:%x failed!!\n", type, subtype));
pCpu->rc = VERR_DIS_INVALID_MODRM;
break;
}
}
//*****************************************************************************
//*****************************************************************************
static void disasmModRMReg16(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam)
{
NOREF(pCpu); NOREF(pOp);
pParam->fUse |= DISUSE_REG_GEN16;
pParam->base.reg_gen = BaseModRMReg16[idx];
if (idx < 4)
{
pParam->fUse |= DISUSE_INDEX;
pParam->index.reg_gen = IndexModRMReg16[idx];
}
}
//*****************************************************************************
//*****************************************************************************
static void disasmModRMSReg(PDISCPUSTATE pCpu, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam)
{
NOREF(pOp);
if (idx >= RT_ELEMENTS(szModRMSegReg))
{
Log(("disasmModRMSReg %d failed!!\n", idx));
pCpu->rc = VERR_DIS_INVALID_PARAMETER;
return;
}
pParam->fUse |= DISUSE_REG_SEG;
pParam->base.reg_seg = (DISSELREG)idx;
}
/**
* Slow path for storing instruction bytes.
*
* @param pCpu The disassembler state.
* @param uAddress The address.
* @param pbSrc The bytes.
* @param cbSrc The number of bytes.
*/
DECL_NO_INLINE(static, void)
disStoreInstrBytesSlow(PDISCPUSTATE pCpu, RTUINTPTR uAddress, const uint8_t *pbSrc, size_t cbSrc)
{
/*
* Figure out which case it is.
*/
uint32_t cbInstr = pCpu->opsize;
RTUINTPTR off = uAddress - pCpu->uInstrAddr;
if (off < cbInstr)
{
if (off + cbSrc <= cbInstr)
{
AssertMsg(memcmp(&pCpu->abInstr[off], pbSrc, cbSrc) == 0,
("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr));
return; /* fully re-reading old stuff. */
}
/* Only partially re-reading stuff, skip ahead and add the rest. */
uint32_t cbAlreadyRead = cbInstr - (uint32_t)off;
Assert(memcmp(&pCpu->abInstr[off], pbSrc, cbAlreadyRead) == 0);
uAddress += cbAlreadyRead;
pbSrc += cbAlreadyRead;
cbSrc -= cbAlreadyRead;
}
if (off >= sizeof(cbInstr))
{
/* The instruction is too long! This shouldn't happen. */
AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr));
return;
}
else if (off > cbInstr)
{
/* Mind the gap - this shouldn't happen, but read the gap bytes if it does. */
AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.16Rhxs)", uAddress, cbSrc, off, cbInstr, pCpu->abInstr));
uint32_t cbGap = off - cbInstr;
int rc = pCpu->pfnReadBytes(pCpu, &pCpu->abInstr[cbInstr], uAddress - cbGap, cbGap);
if (RT_FAILURE(rc))
{
pCpu->rc = VERR_DIS_MEM_READ;
RT_BZERO(&pCpu->abInstr[cbInstr], cbGap);
}
pCpu->opsize = cbInstr = off;
}
/*
* Copy the bytes.
*/
if (off + cbSrc <= sizeof(pCpu->abInstr))
{
memcpy(&pCpu->abInstr[cbInstr], pbSrc, cbSrc);
pCpu->opsize = cbInstr + (uint32_t)cbSrc;
}
else
{
size_t cbToCopy = sizeof(pCpu->abInstr) - off;
memcpy(&pCpu->abInstr[cbInstr], pbSrc, cbToCopy);
pCpu->opsize = sizeof(pCpu->abInstr);
AssertMsgFailed(("%RTptr LB %zx off=%RTptr (%.*Rhxs)", uAddress, cbSrc, off, sizeof(pCpu->abInstr), pCpu->abInstr));
}
}
DECLCALLBACK(int) disReadBytesDefault(PDISCPUSTATE pCpu, uint8_t *pbDst, RTUINTPTR uSrcAddr, uint32_t cbToRead)
{
#ifdef IN_RING0
AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
RT_BZERO(pbDst, cbToRead);
return VERR_DIS_NO_READ_CALLBACK;
#else
memcpy(pbDst, (void const *)(uintptr_t)uSrcAddr, cbToRead);
return VINF_SUCCESS;
#endif
}
//*****************************************************************************
/* Read functions for getting the opcode bytes */
//*****************************************************************************
uint8_t disReadByte(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
{
uint8_t bTemp = 0;
int rc = pCpu->pfnReadBytes(pCpu, &bTemp, uAddress, sizeof(bTemp));
if (RT_FAILURE(rc))
{
Log(("disReadByte failed!!\n"));
pCpu->rc = VERR_DIS_MEM_READ;
}
/** @todo change this into reading directly into abInstr and use it as a
* cache. */
if (RT_LIKELY( pCpu->uInstrAddr + pCpu->opsize == uAddress
&& pCpu->opsize + sizeof(bTemp) < sizeof(pCpu->abInstr)))
pCpu->abInstr[pCpu->opsize++] = bTemp;
else
disStoreInstrBytesSlow(pCpu, uAddress, &bTemp, sizeof(bTemp));
return bTemp;
}
//*****************************************************************************
//*****************************************************************************
uint16_t disReadWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
{
RTUINT16U uTemp;
uTemp.u = 0;
int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp));
if (RT_FAILURE(rc))
{
Log(("disReadWord failed!!\n"));
pCpu->rc = VERR_DIS_MEM_READ;
}
if (RT_LIKELY( pCpu->uInstrAddr + pCpu->opsize == uAddress
&& pCpu->opsize + sizeof(uTemp) < sizeof(pCpu->abInstr)))
{
pCpu->abInstr[pCpu->opsize ] = uTemp.au8[0];
pCpu->abInstr[pCpu->opsize + 1] = uTemp.au8[1];
pCpu->opsize += 2;
}
else
disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp));
return uTemp.u;
}
//*****************************************************************************
//*****************************************************************************
uint32_t disReadDWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
{
RTUINT32U uTemp;
uTemp.u = 0;
int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp));
if (RT_FAILURE(rc))
{
Log(("disReadDWord failed!!\n"));
pCpu->rc = VERR_DIS_MEM_READ;
}
if (RT_LIKELY( pCpu->uInstrAddr + pCpu->opsize == uAddress
&& pCpu->opsize + sizeof(uTemp) < sizeof(pCpu->abInstr)))
{
pCpu->abInstr[pCpu->opsize ] = uTemp.au8[0];
pCpu->abInstr[pCpu->opsize + 1] = uTemp.au8[1];
pCpu->abInstr[pCpu->opsize + 2] = uTemp.au8[2];
pCpu->abInstr[pCpu->opsize + 3] = uTemp.au8[3];
pCpu->opsize += 4;
}
else
disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp));
return uTemp.u;
}
//*****************************************************************************
//*****************************************************************************
uint64_t disReadQWord(PDISCPUSTATE pCpu, RTUINTPTR uAddress)
{
RTUINT64U uTemp;
uTemp.u = 0;
int rc = pCpu->pfnReadBytes(pCpu, uTemp.au8, uAddress, sizeof(uTemp));
if (RT_FAILURE(rc))
{
Log(("disReadQWord %x failed!!\n", uAddress));
pCpu->rc = VERR_DIS_MEM_READ;
}
if (RT_LIKELY( pCpu->uInstrAddr + pCpu->opsize == uAddress
&& pCpu->opsize + sizeof(uTemp) < sizeof(pCpu->abInstr)))
{
pCpu->abInstr[pCpu->opsize ] = uTemp.au8[0];
pCpu->abInstr[pCpu->opsize + 1] = uTemp.au8[1];
pCpu->abInstr[pCpu->opsize + 2] = uTemp.au8[2];
pCpu->abInstr[pCpu->opsize + 3] = uTemp.au8[3];
pCpu->abInstr[pCpu->opsize + 4] = uTemp.au8[4];
pCpu->abInstr[pCpu->opsize + 5] = uTemp.au8[5];
pCpu->abInstr[pCpu->opsize + 6] = uTemp.au8[6];
pCpu->abInstr[pCpu->opsize + 7] = uTemp.au8[7];
pCpu->opsize += 8;
}
else
disStoreInstrBytesSlow(pCpu, uAddress, uTemp.au8, sizeof(uTemp));
return uTemp.u;
}
/**
* Validates the lock sequence.
*
* The AMD manual lists the following instructions:
* ADC
* ADD
* AND
* BTC
* BTR
* BTS
* CMPXCHG
* CMPXCHG8B
* CMPXCHG16B
* DEC
* INC
* NEG
* NOT
* OR
* SBB
* SUB
* XADD
* XCHG
* XOR
*
* @param pCpu Fully disassembled instruction.
*/
static void disValidateLockSequence(PDISCPUSTATE pCpu)
{
Assert(pCpu->prefix & DISPREFIX_LOCK);
/*
* Filter out the valid lock sequences.
*/
switch (pCpu->pCurInstr->opcode)
{
/* simple: no variations */
case OP_CMPXCHG8B: /* == OP_CMPXCHG16B? */
return;
/* simple: /r - reject register destination. */
case OP_BTC:
case OP_BTR:
case OP_BTS:
case OP_CMPXCHG:
case OP_XADD:
if (pCpu->ModRM.Bits.Mod == 3)
break;
return;
/*
* Lots of variants but its sufficient to check that param 1
* is a memory operand.
*/
case OP_ADC:
case OP_ADD:
case OP_AND:
case OP_DEC:
case OP_INC:
case OP_NEG:
case OP_NOT:
case OP_OR:
case OP_SBB:
case OP_SUB:
case OP_XCHG:
case OP_XOR:
if (pCpu->param1.fUse & (DISUSE_BASE | DISUSE_INDEX | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32
| DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT8 | DISUSE_RIPDISPLACEMENT32))
return;
break;
default:
break;
}
/*
* Invalid lock sequence, make it a OP_ILLUD2.
*/
pCpu->pCurInstr = &g_aTwoByteMapX86[11];
Assert(pCpu->pCurInstr->opcode == OP_ILLUD2);
}