DisasmCore.cpp revision f9673005f8230c707b14cebdd209ff6e9801252a
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/* $Id$ */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** @file
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * VBox Disassembler - Core Components.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Copyright (C) 2006-2012 Oracle Corporation
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * available from http://www.virtualbox.org. This file is free software;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * you can redistribute it and/or modify it under the terms of the GNU
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * General Public License (GPL) as published by the Free Software
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Header Files *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#define LOG_GROUP LOG_GROUP_DIS
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <VBox/dis.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <VBox/disopcode.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <VBox/err.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <VBox/log.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <iprt/assert.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <iprt/param.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <iprt/string.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include <iprt/stdarg.h>
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#include "DisasmInternal.h"
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Defined Constants And Macros *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** This must be less or equal to DISSTATE::abInstr. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#define DIS_MAX_INSTR_LENGTH 16
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Whether we can do unaligned access. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync# define DIS_HOST_UNALIGNED_ACCESS_OK
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#endif
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Internal Functions *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic void disasmModRMReg(PDISSTATE pDis, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** @name Parsers
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @{ */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseIllegal;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseModRM;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseModRM_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE UseModRM;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmByte;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmByte_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmByteSX;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmByteSX_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmBRel;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmBRel_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmUshort;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmUshort_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmV;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmV_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmVRel;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmVRel_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmZ;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmZ_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmAddr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmAddr_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmAddrF;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmAddrF_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseFixedReg;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmUlong;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmUlong_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmQword;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmQword_SizeOnly;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseTwoByteEsc;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseThreeByteEsc4;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseThreeByteEsc5;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseImmGrpl;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseShiftGrp2;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp3;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp4;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp5;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE Parse3DNow;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp6;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp7;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp8;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp9;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp10;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp12;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp13;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp14;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp15;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseGrp16;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseModFence;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseNopPause;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseYv;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseYb;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseXv;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseXb;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Floating point parsing */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic FNDISPARSE ParseEscFP;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** @} */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Global Variables *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Parser opcode table for full disassembly. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic PFNDISPARSE const g_apfnFullDisasm[IDX_ParseMax] =
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync{
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseIllegal,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseModRM,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync UseModRM,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmByte,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmBRel,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmUshort,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmV,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmVRel,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmAddr,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseFixedReg,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmUlong,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmQword,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseTwoByteEsc,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmGrpl,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseShiftGrp2,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp3,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp4,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp5,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Parse3DNow,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp6,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp7,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp8,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp9,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp10,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp12,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp13,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp14,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp15,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp16,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseModFence,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseYv,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseYb,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseXv,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseXb,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseEscFP,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseNopPause,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmByteSX,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmZ,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseThreeByteEsc4,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseThreeByteEsc5,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmAddrF
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync};
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Parser opcode table for only calculating instruction size. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic PFNDISPARSE const g_apfnCalcSize[IDX_ParseMax] =
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync{
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseIllegal,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseModRM_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync UseModRM,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmByte_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmBRel_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmUshort_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmV_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmVRel_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmAddr_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseFixedReg,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmUlong_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmQword_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseTwoByteEsc,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmGrpl,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseShiftGrp2,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp3,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp4,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp5,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Parse3DNow,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp6,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp7,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp8,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp9,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp10,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp12,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp13,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp14,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp15,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseGrp16,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseModFence,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseYv,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseYb,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseXv,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseXb,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseEscFP,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseNopPause,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmByteSX_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmZ_SizeOnly,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseThreeByteEsc4,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseThreeByteEsc5,
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ParseImmAddrF_SizeOnly
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync};
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/********************************************************************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Read functions for getting the opcode bytes
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ********************************************************************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/**
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.}
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic DECLCALLBACK(int) disReadBytesDefault(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync{
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#ifdef IN_RING0
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync RT_BZERO(&pDis->abInstr[offInstr], cbMaxRead);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync pDis->cbCachedInstr = offInstr + cbMaxRead;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync return VERR_DIS_NO_READ_CALLBACK;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#else
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync uint8_t const *pbSrc = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync size_t cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync uint8_t cbToRead = cbLeftOnPage >= cbMaxRead
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ? cbMaxRead
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync : cbLeftOnPage <= cbMinRead
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ? cbMinRead
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync : (uint8_t)cbLeftOnPage;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync memcpy(&pDis->abInstr[offInstr], pbSrc, cbToRead);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync pDis->cbCachedInstr = offInstr + cbToRead;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync return VINF_SUCCESS;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync#endif
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync}
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/**
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Read more bytes into the DISSTATE::abInstr buffer, advance
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * DISSTATE::cbCachedInstr.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Will set DISSTATE::rc on failure, but still advance cbCachedInstr.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * The caller shall fend off reads beyond the DISSTATE::abInstr buffer.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param pDis The disassembler state.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param offInstr The offset of the read request.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param cbMin The size of the read request that needs to be
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * satisfied.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncDECL_NO_INLINE(static, void) disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync{
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Assert(cbMin + offInstr <= sizeof(pDis->abInstr));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync /*
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Adjust the incoming request to not overlap with bytes that has already
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * been read and to make sure we don't leave unread gaps.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync if (offInstr < pDis->cbCachedInstr)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync {
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Assert(offInstr + cbMin > pDis->cbCachedInstr);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync cbMin -= pDis->cbCachedInstr - offInstr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync offInstr = pDis->cbCachedInstr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync }
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync else if (offInstr > pDis->cbCachedInstr)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync {
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync cbMin += offInstr - pDis->cbCachedInstr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync offInstr = pDis->cbCachedInstr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync }
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync /*
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Do the read.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * (No need to zero anything on failure as abInstr is already zeroed by the
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * DISInstrEx API.)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync int rc = pDis->pfnReadBytes(pDis, offInstr, cbMin, sizeof(pDis->abInstr) - offInstr);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync if (RT_SUCCESS(rc))
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync {
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Assert(pDis->cbCachedInstr >= offInstr + cbMin);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Assert(pDis->cbCachedInstr <= sizeof(pDis->abInstr));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync }
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync else
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync {
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Log(("disReadMore failed with rc=%Rrc!!\n", rc));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync pDis->rc = VERR_DIS_MEM_READ;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync }
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync}
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/**
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Function for handling a 8-bit cache miss.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @returns The requested byte.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param pDis The disassembler state.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param offInstr The offset of the byte relative to the
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * instruction.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncDECL_NO_INLINE(static, uint8_t) disReadByteSlow(PDISSTATE pDis, size_t offInstr)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync{
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync if (RT_UNLIKELY(offInstr >= DIS_MAX_INSTR_LENGTH))
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync {
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Log(("disReadByte: too long instruction...\n"));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync pDis->rc = VERR_DIS_TOO_LONG_INSTR;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync return 0;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync }
disReadMore(pDis, (uint8_t)offInstr, 1);
return pDis->abInstr[offInstr];
}
/**
* Read a byte (8-bit) instruction.
*
* @returns The requested byte.
* @param pDis The disassembler state.
* @param uAddress The address.
*/
DECLINLINE(uint8_t) disReadByte(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr >= pDis->cbCachedInstr))
return disReadByteSlow(pDis, offInstr);
return pDis->abInstr[offInstr];
}
/**
* Function for handling a 16-bit cache miss.
*
* @returns The requested word.
* @param pDis The disassembler state.
* @param offInstr The offset of the word relative to the
* instruction.
*/
DECL_NO_INLINE(static, uint16_t) disReadWordSlow(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr + 2 > DIS_MAX_INSTR_LENGTH))
{
Log(("disReadWord: too long instruction...\n"));
pDis->rc = VERR_DIS_TOO_LONG_INSTR;
if (offInstr < DIS_MAX_INSTR_LENGTH)
return pDis->abInstr[offInstr];
return 0;
}
disReadMore(pDis, (uint8_t)offInstr, 2);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return *(uint16_t const *)&pDis->abInstr[offInstr];
#else
return RT_MAKE_U16(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1]);
#endif
}
/**
* Read a word (16-bit) instruction.
*
* @returns The requested word.
* @param pDis The disassembler state.
* @param offInstr The offset of the qword relative to the
* instruction.
*/
DECLINLINE(uint16_t) disReadWord(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr + 2 > pDis->cbCachedInstr))
return disReadWordSlow(pDis, offInstr);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return *(uint16_t const *)&pDis->abInstr[offInstr];
#else
return RT_MAKE_U16(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1]);
#endif
}
/**
* Function for handling a 32-bit cache miss.
*
* @returns The requested dword.
* @param pDis The disassembler state.
* @param offInstr The offset of the dword relative to the
* instruction.
*/
DECL_NO_INLINE(static, uint32_t) disReadDWordSlow(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr + 4 > DIS_MAX_INSTR_LENGTH))
{
Log(("disReadDWord: too long instruction...\n"));
pDis->rc = VERR_DIS_TOO_LONG_INSTR;
switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - offInstr)
{
case 1:
return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr], 0, 0, 0);
case 2:
return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1], 0, 0);
case 3:
return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1], pDis->abInstr[offInstr + 2], 0);
}
return 0;
}
disReadMore(pDis, (uint8_t)offInstr, 4);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return *(uint32_t const *)&pDis->abInstr[offInstr];
#else
return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3]);
#endif
}
/**
* Read a dword (32-bit) instruction.
*
* @returns The requested dword.
* @param pDis The disassembler state.
* @param offInstr The offset of the qword relative to the
* instruction.
*/
DECLINLINE(uint32_t) disReadDWord(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr + 4 > pDis->cbCachedInstr))
return disReadDWordSlow(pDis, offInstr);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return *(uint32_t const *)&pDis->abInstr[offInstr];
#else
return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3]);
#endif
}
/**
* Function for handling a 64-bit cache miss.
*
* @returns The requested qword.
* @param pDis The disassembler state.
* @param offInstr The offset of the qword relative to the
* instruction.
*/
DECL_NO_INLINE(static, uint64_t) disReadQWordSlow(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr + 8 > DIS_MAX_INSTR_LENGTH))
{
Log(("disReadQWord: too long instruction...\n"));
pDis->rc = VERR_DIS_TOO_LONG_INSTR;
switch ((RTUINTPTR)DIS_MAX_INSTR_LENGTH - offInstr)
{
case 1:
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr], 0, 0, 0, 0, 0, 0, 0);
case 2:
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1], 0, 0, 0, 0, 0, 0);
case 3:
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], 0, 0, 0, 0, 0);
case 4:
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3],
pDis->abInstr[offInstr + 4], 0, 0, 0);
case 5:
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3],
pDis->abInstr[offInstr + 4], pDis->abInstr[offInstr + 5], 0, 0);
case 6:
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3],
pDis->abInstr[offInstr + 4], pDis->abInstr[offInstr + 5],
pDis->abInstr[offInstr + 6], 0);
}
return 0;
}
disReadMore(pDis, (uint8_t)offInstr, 8);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return *(uint64_t const *)&pDis->abInstr[offInstr];
#else
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3],
pDis->abInstr[offInstr + 4], pDis->abInstr[offInstr + 5],
pDis->abInstr[offInstr + 6], pDis->abInstr[offInstr + 7]);
#endif
}
/**
* Read a qword (64-bit) instruction.
*
* @returns The requested qword.
* @param pDis The disassembler state.
* @param uAddress The address.
*/
DECLINLINE(uint64_t) disReadQWord(PDISSTATE pDis, size_t offInstr)
{
if (RT_UNLIKELY(offInstr + 8 > pDis->cbCachedInstr))
return disReadQWordSlow(pDis, offInstr);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return *(uint64_t const *)&pDis->abInstr[offInstr];
#else
return RT_MAKE_U64_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1],
pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3],
pDis->abInstr[offInstr + 4], pDis->abInstr[offInstr + 5],
pDis->abInstr[offInstr + 6], pDis->abInstr[offInstr + 7]);
#endif
}
//*****************************************************************************
//*****************************************************************************
static size_t disParseInstruction(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis)
{
size_t size = 0;
bool fFiltered = false;
Assert(pOp); Assert(pDis);
// Store the opcode format string for disasmPrintf
pDis->pCurInstr = pOp;
/*
* Apply filter to instruction type to determine if a full disassembly is required.
* Note! Multibyte opcodes are always marked harmless until the final byte.
*/
if ((pOp->fOpType & pDis->fFilter) == 0)
{
fFiltered = true;
pDis->pfnDisasmFnTable = g_apfnCalcSize;
}
else
{
/* Not filtered out -> full disassembly */
pDis->pfnDisasmFnTable = g_apfnFullDisasm;
}
// Should contain the parameter type on input
pDis->Param1.fParam = pOp->fParam1;
pDis->Param2.fParam = pOp->fParam2;
pDis->Param3.fParam = pOp->fParam3;
/* Correct the operand size if the instruction is marked as forced or default 64 bits */
if (pDis->uCpuMode == DISCPUMODE_64BIT)
{
if (pOp->fOpType & DISOPTYPE_FORCED_64_OP_SIZE)
pDis->uOpMode = DISCPUMODE_64BIT;
else
if ( (pOp->fOpType & DISOPTYPE_DEFAULT_64_OP_SIZE)
&& !(pDis->fPrefix & DISPREFIX_OPSIZE))
pDis->uOpMode = DISCPUMODE_64BIT;
}
else
if (pOp->fOpType & DISOPTYPE_FORCED_32_OP_SIZE_X86)
{
/* Forced 32 bits operand size for certain instructions (mov crx, mov drx). */
Assert(pDis->uCpuMode != DISCPUMODE_64BIT);
pDis->uOpMode = DISCPUMODE_32BIT;
}
if (pOp->idxParse1 != IDX_ParseNop)
{
size += pDis->pfnDisasmFnTable[pOp->idxParse1](offInstr, pOp, &pDis->Param1, pDis);
if (fFiltered == false) pDis->Param1.cb = DISGetParamSize(pDis, &pDis->Param1);
}
if (pOp->idxParse2 != IDX_ParseNop)
{
size += pDis->pfnDisasmFnTable[pOp->idxParse2](offInstr+size, pOp, &pDis->Param2, pDis);
if (fFiltered == false) pDis->Param2.cb = DISGetParamSize(pDis, &pDis->Param2);
}
if (pOp->idxParse3 != IDX_ParseNop)
{
size += pDis->pfnDisasmFnTable[pOp->idxParse3](offInstr+size, pOp, &pDis->Param3, pDis);
if (fFiltered == false) pDis->Param3.cb = DISGetParamSize(pDis, &pDis->Param3);
}
// else simple one byte instruction
return size;
}
//*****************************************************************************
/* Floating point opcode parsing */
//*****************************************************************************
static size_t ParseEscFP(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
PCDISOPCODE fpop;
NOREF(pOp);
unsigned ModRM = disReadByte(pDis, offInstr);
unsigned index = pDis->bOpCode - 0xD8;
if (ModRM <= 0xBF)
{
fpop = &(g_apMapX86_FP_Low[index])[MODRM_REG(ModRM)];
pDis->pCurInstr = fpop;
// Should contain the parameter type on input
pDis->Param1.fParam = fpop->fParam1;
pDis->Param2.fParam = fpop->fParam2;
}
else
{
fpop = &(g_apMapX86_FP_High[index])[ModRM - 0xC0];
pDis->pCurInstr = fpop;
}
/*
* Apply filter to instruction type to determine if a full disassembly is required.
* @note Multibyte opcodes are always marked harmless until the final byte.
*/
if ((fpop->fOpType & pDis->fFilter) == 0)
pDis->pfnDisasmFnTable = g_apfnCalcSize;
else
/* Not filtered out -> full disassembly */
pDis->pfnDisasmFnTable = g_apfnFullDisasm;
/* Correct the operand size if the instruction is marked as forced or default 64 bits */
if (pDis->uCpuMode == DISCPUMODE_64BIT)
{
/* Note: redundant, but just in case this ever changes */
if (fpop->fOpType & DISOPTYPE_FORCED_64_OP_SIZE)
pDis->uOpMode = DISCPUMODE_64BIT;
else
if ( (fpop->fOpType & DISOPTYPE_DEFAULT_64_OP_SIZE)
&& !(pDis->fPrefix & DISPREFIX_OPSIZE))
pDis->uOpMode = DISCPUMODE_64BIT;
}
// Little hack to make sure the ModRM byte is included in the returned size
if (fpop->idxParse1 != IDX_ParseModRM && fpop->idxParse2 != IDX_ParseModRM)
size = sizeof(uint8_t); //ModRM byte
if (fpop->idxParse1 != IDX_ParseNop)
size += pDis->pfnDisasmFnTable[fpop->idxParse1](offInstr+size, fpop, pParam, pDis);
if (fpop->idxParse2 != IDX_ParseNop)
size += pDis->pfnDisasmFnTable[fpop->idxParse2](offInstr+size, fpop, pParam, pDis);
return size;
}
/********************************************************************************************************************************
*
*
* SIB byte: (not 16-bit mode)
* 7 - 6 5 - 3 2-0
* Scale Index Base
*
*
********************************************************************************************************************************/
static void UseSIB(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp);
unsigned scale = pDis->SIB.Bits.Scale;
unsigned base = pDis->SIB.Bits.Base;
unsigned index = pDis->SIB.Bits.Index;
unsigned regtype;
if (pDis->uAddrMode == DISCPUMODE_32BIT)
regtype = DISUSE_REG_GEN32;
else
regtype = DISUSE_REG_GEN64;
if (index != 4)
{
pParam->fUse |= DISUSE_INDEX | regtype;
pParam->Index.idxGenReg = index;
if (scale != 0)
{
pParam->fUse |= DISUSE_SCALE;
pParam->uScale = (1<<scale);
}
}
if (base == 5 && pDis->ModRM.Bits.Mod == 0)
{
// [scaled index] + disp32
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
pParam->fUse |= DISUSE_DISPLACEMENT32;
pParam->uDisp.i32 = pDis->i32SibDisp;
}
else
{ /* sign-extend to 64 bits */
pParam->fUse |= DISUSE_DISPLACEMENT64;
pParam->uDisp.i64 = pDis->i32SibDisp;
}
}
else
{
pParam->fUse |= DISUSE_BASE | regtype;
pParam->Base.idxGenReg = base;
}
return; /* Already fetched everything in ParseSIB; no size returned */
}
static size_t ParseSIB(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
unsigned size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
unsigned SIB = disReadByte(pDis, offInstr);
offInstr += size;
pDis->SIB.Bits.Base = SIB_BASE(SIB);
pDis->SIB.Bits.Index = SIB_INDEX(SIB);
pDis->SIB.Bits.Scale = SIB_SCALE(SIB);
if (pDis->fPrefix & DISPREFIX_REX)
{
/* REX.B extends the Base field if not scaled index + disp32 */
if (!(pDis->SIB.Bits.Base == 5 && pDis->ModRM.Bits.Mod == 0))
pDis->SIB.Bits.Base |= (!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_B)) << 3;
pDis->SIB.Bits.Index |= (!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_X)) << 3;
}
if ( pDis->SIB.Bits.Base == 5
&& pDis->ModRM.Bits.Mod == 0)
{
/* Additional 32 bits displacement. No change in long mode. */
pDis->i32SibDisp = disReadDWord(pDis, offInstr);
size += sizeof(int32_t);
}
return size;
}
static size_t ParseSIB_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
unsigned size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
unsigned SIB = disReadByte(pDis, offInstr);
pDis->SIB.Bits.Base = SIB_BASE(SIB);
pDis->SIB.Bits.Index = SIB_INDEX(SIB);
pDis->SIB.Bits.Scale = SIB_SCALE(SIB);
if (pDis->fPrefix & DISPREFIX_REX)
{
/* REX.B extends the Base field. */
pDis->SIB.Bits.Base |= ((!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_B)) << 3);
/* REX.X extends the Index field. */
pDis->SIB.Bits.Index |= ((!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_X)) << 3);
}
if ( pDis->SIB.Bits.Base == 5
&& pDis->ModRM.Bits.Mod == 0)
{
/* Additional 32 bits displacement. No change in long mode. */
size += sizeof(int32_t);
}
return size;
}
/********************************************************************************************************************************
*
*
* ModR/M byte:
* 7 - 6 5 - 3 2-0
* Mod Reg/Opcode R/M
*
*
********************************************************************************************************************************/
static void disasmModRMReg(PDISSTATE pDis, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr)
{
NOREF(pOp); NOREF(pDis);
unsigned mod = pDis->ModRM.Bits.Mod;
unsigned type = OP_PARM_VTYPE(pParam->fParam);
unsigned subtype = OP_PARM_VSUBTYPE(pParam->fParam);
if (fRegAddr)
subtype = (pDis->uAddrMode == DISCPUMODE_64BIT) ? OP_PARM_q : OP_PARM_d;
else
if (subtype == OP_PARM_v || subtype == OP_PARM_NONE)
{
switch (pDis->uOpMode)
{
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 < (pDis->fPrefix & 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 ( (pDis->fPrefix & DISPREFIX_REX)
&& idx >= DISGREG_AH
&& idx <= DISGREG_BH)
{
idx += (DISGREG_SPL - DISGREG_AH);
}
pParam->fUse |= DISUSE_REG_GEN8;
pParam->Base.idxGenReg = idx;
break;
case OP_PARM_w:
Assert(idx < (pDis->fPrefix & DISPREFIX_REX ? 16U : 8U));
pParam->fUse |= DISUSE_REG_GEN16;
pParam->Base.idxGenReg = idx;
break;
case OP_PARM_d:
Assert(idx < (pDis->fPrefix & DISPREFIX_REX ? 16U : 8U));
pParam->fUse |= DISUSE_REG_GEN32;
pParam->Base.idxGenReg = idx;
break;
case OP_PARM_q:
pParam->fUse |= DISUSE_REG_GEN64;
pParam->Base.idxGenReg = idx;
break;
default:
Log(("disasmModRMReg %x:%x failed!!\n", type, subtype));
pDis->rc = VERR_DIS_INVALID_MODRM;
break;
}
}
static void disasmModRMReg16(PDISSTATE pDis, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam)
{
static const uint8_t s_auBaseModRMReg16[8] =
{ DISGREG_BX, DISGREG_BX, DISGREG_BP, DISGREG_BP, DISGREG_SI, DISGREG_DI, DISGREG_BP, DISGREG_BX };
NOREF(pDis); NOREF(pOp);
pParam->fUse |= DISUSE_REG_GEN16;
pParam->Base.idxGenReg = s_auBaseModRMReg16[idx];
if (idx < 4)
{
static const uint8_t s_auIndexModRMReg16[4] = { DISGREG_SI, DISGREG_DI, DISGREG_SI, DISGREG_DI };
pParam->fUse |= DISUSE_INDEX;
pParam->Index.idxGenReg = s_auIndexModRMReg16[idx];
}
}
//*****************************************************************************
//*****************************************************************************
static void disasmModRMSReg(PDISSTATE pDis, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam)
{
NOREF(pOp);
if (idx >= DISSELREG_END)
{
Log(("disasmModRMSReg %d failed!!\n", idx));
pDis->rc = VERR_DIS_INVALID_PARAMETER;
return;
}
pParam->fUse |= DISUSE_REG_SEG;
pParam->Base.idxSegReg = (DISSELREG)idx;
}
static size_t UseModRM(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
unsigned vtype = OP_PARM_VTYPE(pParam->fParam);
unsigned reg = pDis->ModRM.Bits.Reg;
unsigned mod = pDis->ModRM.Bits.Mod;
unsigned rm = pDis->ModRM.Bits.Rm;
switch (vtype)
{
case OP_PARM_G: //general purpose register
disasmModRMReg(pDis, pOp, reg, pParam, 0);
return 0;
default:
if (IS_OP_PARM_RARE(vtype))
{
switch (vtype)
{
case OP_PARM_C: //control register
pParam->fUse |= DISUSE_REG_CR;
if ( pDis->pCurInstr->uOpcode == OP_MOV_CR
&& pDis->uOpMode == DISCPUMODE_32BIT
&& (pDis->fPrefix & DISPREFIX_LOCK))
{
pDis->fPrefix &= ~DISPREFIX_LOCK;
pParam->Base.idxCtrlReg = DISCREG_CR8;
}
else
pParam->Base.idxCtrlReg = reg;
return 0;
case OP_PARM_D: //debug register
pParam->fUse |= DISUSE_REG_DBG;
pParam->Base.idxDbgReg = reg;
return 0;
case OP_PARM_P: //MMX register
reg &= 7; /* REX.R has no effect here */
pParam->fUse |= DISUSE_REG_MMX;
pParam->Base.idxMmxReg = reg;
return 0;
case OP_PARM_S: //segment register
reg &= 7; /* REX.R has no effect here */
disasmModRMSReg(pDis, pOp, reg, pParam);
pParam->fUse |= DISUSE_REG_SEG;
return 0;
case OP_PARM_T: //test register
reg &= 7; /* REX.R has no effect here */
pParam->fUse |= DISUSE_REG_TEST;
pParam->Base.idxTestReg = reg;
return 0;
case OP_PARM_W: //XMM register or memory operand
if (mod != 3)
break; /* memory operand */
reg = rm; /* the RM field specifies the xmm register */
/* else no break */
case OP_PARM_V: //XMM register
pParam->fUse |= DISUSE_REG_XMM;
pParam->Base.idxXmmReg = reg;
return 0;
}
}
}
/* @todo bound */
if (pDis->uAddrMode != DISCPUMODE_16BIT)
{
Assert(pDis->uAddrMode == DISCPUMODE_32BIT || pDis->uAddrMode == DISCPUMODE_64BIT);
/*
* Note: displacements in long mode are 8 or 32 bits and sign-extended to 64 bits
*/
switch (mod)
{
case 0: //effective address
if (rm == 4)
{ /* SIB byte follows ModRM */
UseSIB(offInstr, pOp, pParam, pDis);
}
else
if (rm == 5)
{
/* 32 bits displacement */
if (pDis->uCpuMode != DISCPUMODE_64BIT)
{
pParam->fUse |= DISUSE_DISPLACEMENT32;
pParam->uDisp.i32 = pDis->i32SibDisp;
}
else
{
pParam->fUse |= DISUSE_RIPDISPLACEMENT32;
pParam->uDisp.i32 = pDis->i32SibDisp;
}
}
else
{ //register address
pParam->fUse |= DISUSE_BASE;
disasmModRMReg(pDis, pOp, rm, pParam, 1);
}
break;
case 1: //effective address + 8 bits displacement
if (rm == 4) {//SIB byte follows ModRM
UseSIB(offInstr, pOp, pParam, pDis);
}
else
{
pParam->fUse |= DISUSE_BASE;
disasmModRMReg(pDis, pOp, rm, pParam, 1);
}
pParam->uDisp.i8 = pDis->i32SibDisp;
pParam->fUse |= DISUSE_DISPLACEMENT8;
break;
case 2: //effective address + 32 bits displacement
if (rm == 4) {//SIB byte follows ModRM
UseSIB(offInstr, pOp, pParam, pDis);
}
else
{
pParam->fUse |= DISUSE_BASE;
disasmModRMReg(pDis, pOp, rm, pParam, 1);
}
pParam->uDisp.i32 = pDis->i32SibDisp;
pParam->fUse |= DISUSE_DISPLACEMENT32;
break;
case 3: //registers
disasmModRMReg(pDis, 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 = pDis->i32SibDisp;
pParam->fUse |= DISUSE_DISPLACEMENT16;
}
else
{
pParam->fUse |= DISUSE_BASE;
disasmModRMReg16(pDis, pOp, rm, pParam);
}
break;
case 1: //effective address + 8 bits displacement
disasmModRMReg16(pDis, pOp, rm, pParam);
pParam->uDisp.i8 = pDis->i32SibDisp;
pParam->fUse |= DISUSE_BASE | DISUSE_DISPLACEMENT8;
break;
case 2: //effective address + 16 bits displacement
disasmModRMReg16(pDis, pOp, rm, pParam);
pParam->uDisp.i16 = pDis->i32SibDisp;
pParam->fUse |= DISUSE_BASE | DISUSE_DISPLACEMENT16;
break;
case 3: //registers
disasmModRMReg(pDis, 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)
//*****************************************************************************
static size_t QueryModRM(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis, size_t *pSibInc)
{
size_t sibinc;
size_t size = 0;
// unsigned reg = pDis->ModRM.Bits.Reg;
unsigned mod = pDis->ModRM.Bits.Mod;
unsigned rm = pDis->ModRM.Bits.Rm;
if (!pSibInc)
pSibInc = &sibinc;
*pSibInc = 0;
if (pDis->uAddrMode != DISCPUMODE_16BIT)
{
Assert(pDis->uAddrMode == DISCPUMODE_32BIT || pDis->uAddrMode == 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(offInstr, pOp, pParam, pDis);
offInstr += *pSibInc;
size += *pSibInc;
}
switch (mod)
{
case 0: /* Effective address */
if (rm == 5) { /* 32 bits displacement */
pDis->i32SibDisp = disReadDWord(pDis, offInstr);
size += sizeof(int32_t);
}
/* else register address */
break;
case 1: /* Effective address + 8 bits displacement */
pDis->i32SibDisp = (int8_t)disReadByte(pDis, offInstr);
size += sizeof(char);
break;
case 2: /* Effective address + 32 bits displacement */
pDis->i32SibDisp = disReadDWord(pDis, offInstr);
size += sizeof(int32_t);
break;
case 3: /* registers */
break;
}
}
else
{
/* 16 bits mode */
switch (mod)
{
case 0: /* Effective address */
if (rm == 6) {
pDis->i32SibDisp = disReadWord(pDis, offInstr);
size += sizeof(uint16_t);
}
/* else register address */
break;
case 1: /* Effective address + 8 bits displacement */
pDis->i32SibDisp = (int8_t)disReadByte(pDis, offInstr);
size += sizeof(char);
break;
case 2: /* Effective address + 32 bits displacement */
pDis->i32SibDisp = (int16_t)disReadWord(pDis, offInstr);
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)
//*****************************************************************************
static size_t QueryModRM_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis, size_t *pSibInc)
{
size_t sibinc;
size_t size = 0;
// unsigned reg = pDis->ModRM.Bits.Reg;
unsigned mod = pDis->ModRM.Bits.Mod;
unsigned rm = pDis->ModRM.Bits.Rm;
if (!pSibInc)
pSibInc = &sibinc;
*pSibInc = 0;
if (pDis->uAddrMode != DISCPUMODE_16BIT)
{
Assert(pDis->uAddrMode == DISCPUMODE_32BIT || pDis->uAddrMode == 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(offInstr, pOp, pParam, pDis);
offInstr += *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;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseIllegal(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
AssertFailed();
return 0;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseModRM(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = sizeof(uint8_t); //ModRM byte
size_t sibinc;
unsigned ModRM = disReadByte(pDis, offInstr);
offInstr += sizeof(uint8_t);
pDis->ModRM.Bits.Rm = MODRM_RM(ModRM);
pDis->ModRM.Bits.Mod = MODRM_MOD(ModRM);
pDis->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->fOpType & DISOPTYPE_MOD_FIXED_11)
pDis->ModRM.Bits.Mod = 3;
if (pDis->fPrefix & DISPREFIX_REX)
{
Assert(pDis->uCpuMode == DISCPUMODE_64BIT);
/* REX.R extends the Reg field. */
pDis->ModRM.Bits.Reg |= ((!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_R)) << 3);
/* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
if (!( pDis->ModRM.Bits.Mod != 3
&& pDis->ModRM.Bits.Rm == 4)
&&
!( pDis->ModRM.Bits.Mod == 0
&& pDis->ModRM.Bits.Rm == 5))
{
pDis->ModRM.Bits.Rm |= ((!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_B)) << 3);
}
}
size += QueryModRM(offInstr, pOp, pParam, pDis, &sibinc);
offInstr += sibinc;
UseModRM(offInstr, pOp, pParam, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseModRM_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = sizeof(uint8_t); //ModRM byte
size_t sibinc;
unsigned ModRM = disReadByte(pDis, offInstr);
offInstr += sizeof(uint8_t);
pDis->ModRM.Bits.Rm = MODRM_RM(ModRM);
pDis->ModRM.Bits.Mod = MODRM_MOD(ModRM);
pDis->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->fOpType & DISOPTYPE_MOD_FIXED_11)
pDis->ModRM.Bits.Mod = 3;
if (pDis->fPrefix & DISPREFIX_REX)
{
Assert(pDis->uCpuMode == DISCPUMODE_64BIT);
/* REX.R extends the Reg field. */
pDis->ModRM.Bits.Reg |= ((!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_R)) << 3);
/* REX.B extends the Rm field if there is no SIB byte nor a 32 bits displacement */
if (!( pDis->ModRM.Bits.Mod != 3
&& pDis->ModRM.Bits.Rm == 4)
&&
!( pDis->ModRM.Bits.Mod == 0
&& pDis->ModRM.Bits.Rm == 5))
{
pDis->ModRM.Bits.Rm |= ((!!(pDis->fRexPrefix & DISPREFIX_REX_FLAGS_B)) << 3);
}
}
size += QueryModRM_SizeOnly(offInstr, pOp, pParam, pDis, &sibinc);
offInstr += sibinc;
/* UseModRM is not necessary here; we're only interested in the opcode size */
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseModFence(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
////AssertMsgFailed(("??\n"));
//nothing to do apparently
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return 0;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmByte(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
pParam->uValue = disReadByte(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE8;
pParam->cb = sizeof(uint8_t);
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmByte_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmByteSX(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
if (pDis->uOpMode == DISCPUMODE_32BIT)
{
pParam->uValue = (uint32_t)(int8_t)disReadByte(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE32_SX8;
pParam->cb = sizeof(uint32_t);
}
else
if (pDis->uOpMode == DISCPUMODE_64BIT)
{
pParam->uValue = (uint64_t)(int8_t)disReadByte(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE64_SX8;
pParam->cb = sizeof(uint64_t);
}
else
{
pParam->uValue = (uint16_t)(int8_t)disReadByte(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE16_SX8;
pParam->cb = sizeof(uint16_t);
}
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmByteSX_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return sizeof(uint8_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmUshort(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
pParam->uValue = disReadWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmUshort_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmUlong(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
pParam->uValue = disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE32;
pParam->cb = sizeof(uint32_t);
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmUlong_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmQword(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
pParam->uValue = disReadQWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE64;
pParam->cb = sizeof(uint64_t);
return sizeof(uint64_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmQword_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return sizeof(uint64_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmV(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
if (pDis->uOpMode == DISCPUMODE_32BIT)
{
pParam->uValue = disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE32;
pParam->cb = sizeof(uint32_t);
return sizeof(uint32_t);
}
if (pDis->uOpMode == DISCPUMODE_64BIT)
{
pParam->uValue = disReadQWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE64;
pParam->cb = sizeof(uint64_t);
return sizeof(uint64_t);
}
pParam->uValue = disReadWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmV_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam);
if (pDis->uOpMode == DISCPUMODE_32BIT)
return sizeof(uint32_t);
if (pDis->uOpMode == DISCPUMODE_64BIT)
return sizeof(uint64_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmZ(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
/* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */
if (pDis->uOpMode == DISCPUMODE_16BIT)
{
pParam->uValue = disReadWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
/* 64 bits op mode means *sign* extend to 64 bits. */
if (pDis->uOpMode == DISCPUMODE_64BIT)
{
pParam->uValue = (uint64_t)(int32_t)disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE64;
pParam->cb = sizeof(uint64_t);
}
else
{
pParam->uValue = disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE32;
pParam->cb = sizeof(uint32_t);
}
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmZ_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam);
/* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */
if (pDis->uOpMode == DISCPUMODE_16BIT)
return sizeof(uint16_t);
return sizeof(uint32_t);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
static size_t ParseImmBRel(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
pParam->uValue = disReadByte(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE8_REL;
pParam->cb = sizeof(uint8_t);
return sizeof(char);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
static size_t ParseImmBRel_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam); NOREF(pDis);
return sizeof(char);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
static size_t ParseImmVRel(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(pOp);
if (pDis->uOpMode == DISCPUMODE_32BIT)
{
pParam->uValue = disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE32_REL;
pParam->cb = sizeof(int32_t);
return sizeof(int32_t);
}
if (pDis->uOpMode == DISCPUMODE_64BIT)
{
/* 32 bits relative immediate sign extended to 64 bits. */
pParam->uValue = (uint64_t)(int32_t)disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE64_REL;
pParam->cb = sizeof(int64_t);
return sizeof(int32_t);
}
pParam->uValue = disReadWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE16_REL;
pParam->cb = sizeof(int16_t);
return sizeof(int16_t);
}
//*****************************************************************************
// Relative displacement for branches (rel. to next instruction)
//*****************************************************************************
static size_t ParseImmVRel_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp); NOREF(pParam);
if (pDis->uOpMode == DISCPUMODE_16BIT)
return sizeof(int16_t);
/* Both 32 & 64 bits mode use 32 bits relative immediates. */
return sizeof(int32_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmAddr(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p)
{
/* far 16:32 pointer */
pParam->uValue = disReadDWord(pDis, offInstr);
*((uint32_t*)&pParam->uValue+1) = disReadWord(pDis, offInstr+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(pDis, offInstr);
pParam->fUse |= DISUSE_DISPLACEMENT32;
pParam->cb = sizeof(uint32_t);
return sizeof(uint32_t);
}
if (pDis->uAddrMode == DISCPUMODE_64BIT)
{
Assert(OP_PARM_VSUBTYPE(pParam->fParam) != 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(pDis, offInstr);
pParam->fUse |= DISUSE_DISPLACEMENT64;
pParam->cb = sizeof(uint64_t);
return sizeof(uint64_t);
}
if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p)
{
/* far 16:16 pointer */
pParam->uValue = disReadDWord(pDis, offInstr);
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(pDis, offInstr);
pParam->fUse |= DISUSE_DISPLACEMENT16;
pParam->cb = sizeof(uint16_t);
return sizeof(uint16_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmAddr_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp);
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p)
{// far 16:32 pointer
return sizeof(uint32_t) + sizeof(uint16_t);
}
else
{// near 32 bits pointer
return sizeof(uint32_t);
}
}
if (pDis->uAddrMode == DISCPUMODE_64BIT)
{
Assert(OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_p);
return sizeof(uint64_t);
}
else
{
if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p)
{// far 16:16 pointer
return sizeof(uint32_t);
}
else
{// near 16 bits pointer
return sizeof(uint16_t);
}
}
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmAddrF(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
// immediate far pointers - only 16:16 or 16:32; determined by operand, *not* address size!
Assert(pDis->uOpMode == DISCPUMODE_16BIT || pDis->uOpMode == DISCPUMODE_32BIT);
Assert(OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p);
if (pDis->uOpMode == DISCPUMODE_32BIT)
{
// far 16:32 pointer
pParam->uValue = disReadDWord(pDis, offInstr);
*((uint32_t*)&pParam->uValue+1) = disReadWord(pDis, offInstr+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->uValue = disReadDWord(pDis, offInstr);
pParam->fUse |= DISUSE_IMMEDIATE_ADDR_16_16;
pParam->cb = 2*sizeof(uint16_t);
return sizeof(uint32_t);
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmAddrF_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp);
// immediate far pointers - only 16:16 or 16:32
Assert(pDis->uOpMode == DISCPUMODE_16BIT || pDis->uOpMode == DISCPUMODE_32BIT);
Assert(OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p);
if (pDis->uOpMode == DISCPUMODE_32BIT)
{
// far 16:32 pointer
return sizeof(uint32_t) + sizeof(uint16_t);
}
else
{
// far 16:16 pointer
return sizeof(uint32_t);
}
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseFixedReg(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr);
/*
* Sets up flags for stored in OPC fixed registers.
*/
if (pParam->fParam == 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->fParam <= OP_PARM_REG_GEN32_END)
{
/* 32-bit EAX..EDI registers. */
if (pDis->uOpMode == DISCPUMODE_32BIT)
{
/* Use 32-bit registers. */
pParam->Base.idxGenReg = pParam->fParam - OP_PARM_REG_GEN32_START;
pParam->fUse |= DISUSE_REG_GEN32;
pParam->cb = 4;
}
else
if (pDis->uOpMode == DISCPUMODE_64BIT)
{
/* Use 64-bit registers. */
pParam->Base.idxGenReg = pParam->fParam - OP_PARM_REG_GEN32_START;
if ( (pOp->fOpType & DISOPTYPE_REXB_EXTENDS_OPREG)
&& pParam == &pDis->Param1 /* ugly assumption that it only applies to the first parameter */
&& (pDis->fPrefix & DISPREFIX_REX)
&& (pDis->fRexPrefix & DISPREFIX_REX_FLAGS))
pParam->Base.idxGenReg += 8;
pParam->fUse |= DISUSE_REG_GEN64;
pParam->cb = 8;
}
else
{
/* Use 16-bit registers. */
pParam->Base.idxGenReg = pParam->fParam - OP_PARM_REG_GEN32_START;
pParam->fUse |= DISUSE_REG_GEN16;
pParam->cb = 2;
pParam->fParam = pParam->fParam - OP_PARM_REG_GEN32_START + OP_PARM_REG_GEN16_START;
}
}
else
if (pParam->fParam <= OP_PARM_REG_SEG_END)
{
/* Segment ES..GS registers. */
pParam->Base.idxSegReg = (DISSELREG)(pParam->fParam - OP_PARM_REG_SEG_START);
pParam->fUse |= DISUSE_REG_SEG;
pParam->cb = 2;
}
else
if (pParam->fParam <= OP_PARM_REG_GEN16_END)
{
/* 16-bit AX..DI registers. */
pParam->Base.idxGenReg = pParam->fParam - OP_PARM_REG_GEN16_START;
pParam->fUse |= DISUSE_REG_GEN16;
pParam->cb = 2;
}
else
if (pParam->fParam <= OP_PARM_REG_GEN8_END)
{
/* 8-bit AL..DL, AH..DH registers. */
pParam->Base.idxGenReg = pParam->fParam - OP_PARM_REG_GEN8_START;
pParam->fUse |= DISUSE_REG_GEN8;
pParam->cb = 1;
if (pDis->uOpMode == DISCPUMODE_64BIT)
{
if ( (pOp->fOpType & DISOPTYPE_REXB_EXTENDS_OPREG)
&& pParam == &pDis->Param1 /* ugly assumption that it only applies to the first parameter */
&& (pDis->fPrefix & DISPREFIX_REX)
&& (pDis->fRexPrefix & DISPREFIX_REX_FLAGS))
pParam->Base.idxGenReg += 8; /* least significant byte of R8-R15 */
}
}
else
if (pParam->fParam <= OP_PARM_REG_FP_END)
{
/* FPU registers. */
pParam->Base.idxFpuReg = pParam->fParam - OP_PARM_REG_FP_START;
pParam->fUse |= DISUSE_REG_FP;
pParam->cb = 10;
}
Assert(!(pParam->fParam >= OP_PARM_REG_GEN64_START && pParam->fParam <= OP_PARM_REG_GEN64_END));
/* else - not supported for now registers. */
return 0;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseXv(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr);
pParam->fUse |= DISUSE_POINTER_DS_BASED;
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
pParam->Base.idxGenReg = DISGREG_ESI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pDis->uAddrMode == DISCPUMODE_64BIT)
{
pParam->Base.idxGenReg = DISGREG_RSI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->Base.idxGenReg = DISGREG_SI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseXb(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp);
pParam->fUse |= DISUSE_POINTER_DS_BASED;
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
pParam->Base.idxGenReg = DISGREG_ESI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pDis->uAddrMode == DISCPUMODE_64BIT)
{
pParam->Base.idxGenReg = DISGREG_RSI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->Base.idxGenReg = DISGREG_SI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseYv(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr);
pParam->fUse |= DISUSE_POINTER_ES_BASED;
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
pParam->Base.idxGenReg = DISGREG_EDI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pDis->uAddrMode == DISCPUMODE_64BIT)
{
pParam->Base.idxGenReg = DISGREG_RDI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->Base.idxGenReg = DISGREG_DI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseYb(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
NOREF(offInstr); NOREF(pOp);
pParam->fUse |= DISUSE_POINTER_ES_BASED;
if (pDis->uAddrMode == DISCPUMODE_32BIT)
{
pParam->Base.idxGenReg = DISGREG_EDI;
pParam->fUse |= DISUSE_REG_GEN32;
}
else
if (pDis->uAddrMode == DISCPUMODE_64BIT)
{
pParam->Base.idxGenReg = DISGREG_RDI;
pParam->fUse |= DISUSE_REG_GEN64;
}
else
{
pParam->Base.idxGenReg = DISGREG_DI;
pParam->fUse |= DISUSE_REG_GEN16;
}
return 0; //no additional opcode bytes
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseTwoByteEsc(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
PCDISOPCODE pOpcode;
size_t size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
/* 2nd byte */
pDis->bOpCode = disReadByte(pDis, offInstr);
/* default to the non-prefixed table. */
pOpcode = &g_aTwoByteMapX86[pDis->bOpCode];
/* 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 (pDis->bLastPrefix)
{
switch (pDis->bLastPrefix)
{
case OP_OPSIZE: /* 0x66 */
if (g_aTwoByteMapX86_PF66[pDis->bOpCode].uOpcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
pOpcode = &g_aTwoByteMapX86_PF66[pDis->bOpCode];
/* Cancel prefix changes. */
pDis->fPrefix &= ~DISPREFIX_OPSIZE;
pDis->uOpMode = pDis->uCpuMode;
}
break;
case OP_REPNE: /* 0xF2 */
if (g_aTwoByteMapX86_PFF2[pDis->bOpCode].uOpcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
pOpcode = &g_aTwoByteMapX86_PFF2[pDis->bOpCode];
/* Cancel prefix changes. */
pDis->fPrefix &= ~DISPREFIX_REPNE;
}
break;
case OP_REPE: /* 0xF3 */
if (g_aTwoByteMapX86_PFF3[pDis->bOpCode].uOpcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
pOpcode = &g_aTwoByteMapX86_PFF3[pDis->bOpCode];
/* Cancel prefix changes. */
pDis->fPrefix &= ~DISPREFIX_REP;
}
break;
}
}
size += disParseInstruction(offInstr+size, pOpcode, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseThreeByteEsc4(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
PCDISOPCODE pOpcode;
size_t size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
/* 3rd byte */
pDis->bOpCode = disReadByte(pDis, offInstr);
/* default to the non-prefixed table. */
if (g_apThreeByteMapX86_0F38[pDis->bOpCode >> 4])
{
pOpcode = g_apThreeByteMapX86_0F38[pDis->bOpCode >> 4];
pOpcode = &pOpcode[pDis->bOpCode & 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 (pDis->bLastPrefix)
{
case OP_OPSIZE: /* 0x66 */
if (g_apThreeByteMapX86_660F38[pDis->bOpCode >> 4])
{
pOpcode = g_apThreeByteMapX86_660F38[pDis->bOpCode >> 4];
pOpcode = &pOpcode[pDis->bOpCode & 0xf];
if (pOpcode->uOpcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
/* Cancel prefix changes. */
pDis->fPrefix &= ~DISPREFIX_OPSIZE;
pDis->uOpMode = pDis->uCpuMode;
}
}
break;
case OP_REPNE: /* 0xF2 */
if (g_apThreeByteMapX86_F20F38[pDis->bOpCode >> 4])
{
pOpcode = g_apThreeByteMapX86_F20F38[pDis->bOpCode >> 4];
pOpcode = &pOpcode[pDis->bOpCode & 0xf];
if (pOpcode->uOpcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
/* Cancel prefix changes. */
pDis->fPrefix &= ~DISPREFIX_REPNE;
}
}
break;
}
size += disParseInstruction(offInstr+size, pOpcode, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseThreeByteEsc5(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
PCDISOPCODE pOpcode;
size_t size = sizeof(uint8_t);
NOREF(pOp); NOREF(pParam);
/* 3rd byte */
pDis->bOpCode = disReadByte(pDis, offInstr);
/** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */
Assert(pDis->bLastPrefix == OP_OPSIZE);
/* default to the non-prefixed table. */
if (g_apThreeByteMapX86_660F3A[pDis->bOpCode >> 4])
{
pOpcode = g_apThreeByteMapX86_660F3A[pDis->bOpCode >> 4];
pOpcode = &pOpcode[pDis->bOpCode & 0xf];
if (pOpcode->uOpcode != OP_INVALID)
{
/* Table entry is valid, so use the extension table. */
/* Cancel prefix changes. */
pDis->fPrefix &= ~DISPREFIX_OPSIZE;
pDis->uOpMode = pDis->uCpuMode;
}
}
else
pOpcode = &g_InvalidOpcode[0];
size += disParseInstruction(offInstr+size, pOpcode, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseNopPause(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
if (pDis->fPrefix & DISPREFIX_REP)
{
pOp = &g_aMapX86_NopPause[1]; /* PAUSE */
pDis->fPrefix &= ~DISPREFIX_REP;
}
else
pOp = &g_aMapX86_NopPause[0]; /* NOP */
size += disParseInstruction(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseImmGrpl(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
int idx = (pDis->bOpCode - 0x80) * 8;
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseShiftGrp2(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
int idx;
size_t size = 0;
NOREF(pParam);
switch (pDis->bOpCode)
{
case 0xC0:
case 0xC1:
idx = (pDis->bOpCode - 0xC0)*8;
break;
case 0xD0:
case 0xD1:
case 0xD2:
case 0xD3:
idx = (pDis->bOpCode - 0xD0 + 2)*8;
break;
default:
AssertMsgFailed(("Oops\n"));
return sizeof(uint8_t);
}
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp3(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
int idx = (pDis->bOpCode - 0xF6) * 8;
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp4(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp5(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
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?
//
//*****************************************************************************
static size_t Parse3DNow(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
#ifdef DEBUG_Sander
//needs testing
AssertMsgFailed(("Test me\n"));
#endif
unsigned ModRM = disReadByte(pDis, offInstr);
pDis->ModRM.Bits.Rm = MODRM_RM(ModRM);
pDis->ModRM.Bits.Mod = MODRM_MOD(ModRM);
pDis->ModRM.Bits.Reg = MODRM_REG(ModRM);
size_t modrmsize = QueryModRM(offInstr+sizeof(uint8_t), pOp, pParam, pDis, NULL);
uint8_t opcode = disReadByte(pDis, offInstr+sizeof(uint8_t)+modrmsize);
pOp = &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(offInstr, pOp, pDis);
size += sizeof(uint8_t); //imm8_opcode uint8_t
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp6(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp7(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned mod = MODRM_MOD(modrm);
unsigned reg = MODRM_REG(modrm);
unsigned rm = MODRM_RM(modrm);
if (mod == 3 && rm == 0)
pOp = &g_aMapX86_Group7_mod11_rm000[reg];
else
if (mod == 3 && rm == 1)
pOp = &g_aMapX86_Group7_mod11_rm001[reg];
else
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp8(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp9(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp10(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp12(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
if (pDis->fPrefix & DISPREFIX_OPSIZE)
reg += 8; //2nd table
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp13(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
if (pDis->fPrefix & DISPREFIX_OPSIZE)
reg += 8; //2nd table
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp14(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
if (pDis->fPrefix & DISPREFIX_OPSIZE)
reg += 8; //2nd table
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp15(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned mod = MODRM_MOD(modrm);
unsigned reg = MODRM_REG(modrm);
unsigned rm = MODRM_RM(modrm);
if (mod == 3 && rm == 0)
pOp = &g_aMapX86_Group15_mod11_rm000[reg];
else
pOp = &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(offInstr, pOp, pDis);
return size;
}
//*****************************************************************************
//*****************************************************************************
static size_t ParseGrp16(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
{
size_t size = 0;
NOREF(pParam);
unsigned modrm = disReadByte(pDis, offInstr);
unsigned reg = MODRM_REG(modrm);
pOp = &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(offInstr, pOp, pDis);
return size;
}
/**
* 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 pDis Fully disassembled instruction.
*/
static void disValidateLockSequence(PDISSTATE pDis)
{
Assert(pDis->fPrefix & DISPREFIX_LOCK);
/*
* Filter out the valid lock sequences.
*/
switch (pDis->pCurInstr->uOpcode)
{
/* 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 (pDis->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 (pDis->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.
*/
pDis->pCurInstr = &g_aTwoByteMapX86[11];
Assert(pDis->pCurInstr->uOpcode == OP_ILLUD2);
}
/**
* Internal worker for DISInstEx.
*
* @returns VBox status code.
* @param pDis Initialized disassembler state.
* @param paOneByteMap The one byte opcode map to use.
* @param pcbInstr Where to store the instruction size. Can be NULL.
*/
static int disInstrWorker(PDISSTATE pDis, PCDISOPCODE paOneByteMap, uint32_t *pcbInstr)
{
/*
* Parse byte by byte.
*/
size_t offInstr = 0;
for (;;)
{
uint8_t codebyte = disReadByte(pDis, offInstr++);
uint8_t opcode = paOneByteMap[codebyte].uOpcode;
/* Hardcoded assumption about OP_* values!! */
if (opcode <= OP_LAST_PREFIX)
{
/* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */
if (opcode != OP_REX)
{
/** Last prefix byte (for SSE2 extension tables); don't include the REX prefix */
pDis->bLastPrefix = opcode;
pDis->fPrefix &= ~DISPREFIX_REX;
}
switch (opcode)
{
case OP_INVALID:
if (pcbInstr)
*pcbInstr = (uint32_t)offInstr;
return pDis->rc = VERR_DIS_INVALID_OPCODE;
// segment override prefix byte
case OP_SEG:
pDis->idxSegPrefix = (DISSELREG)(paOneByteMap[codebyte].fParam1 - OP_PARM_REG_SEG_START);
/* Segment prefixes for CS, DS, ES and SS are ignored in long mode. */
if ( pDis->uCpuMode != DISCPUMODE_64BIT
|| pDis->idxSegPrefix >= DISSELREG_FS)
{
pDis->fPrefix |= DISPREFIX_SEG;
}
continue; //fetch the next byte
// lock prefix byte
case OP_LOCK:
pDis->fPrefix |= DISPREFIX_LOCK;
continue; //fetch the next byte
// address size override prefix byte
case OP_ADDRSIZE:
pDis->fPrefix |= DISPREFIX_ADDRSIZE;
if (pDis->uCpuMode == DISCPUMODE_16BIT)
pDis->uAddrMode = DISCPUMODE_32BIT;
else
if (pDis->uCpuMode == DISCPUMODE_32BIT)
pDis->uAddrMode = DISCPUMODE_16BIT;
else
pDis->uAddrMode = DISCPUMODE_32BIT; /* 64 bits */
continue; //fetch the next byte
// operand size override prefix byte
case OP_OPSIZE:
pDis->fPrefix |= DISPREFIX_OPSIZE;
if (pDis->uCpuMode == DISCPUMODE_16BIT)
pDis->uOpMode = DISCPUMODE_32BIT;
else
pDis->uOpMode = DISCPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
continue; //fetch the next byte
// rep and repne are not really prefixes, but we'll treat them as such
case OP_REPE:
pDis->fPrefix |= DISPREFIX_REP;
continue; //fetch the next byte
case OP_REPNE:
pDis->fPrefix |= DISPREFIX_REPNE;
continue; //fetch the next byte
case OP_REX:
Assert(pDis->uCpuMode == DISCPUMODE_64BIT);
/* REX prefix byte */
pDis->fPrefix |= DISPREFIX_REX;
pDis->fRexPrefix = DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[codebyte].fParam1);
if (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_W)
pDis->uOpMode = DISCPUMODE_64BIT; /* overrides size prefix byte */
continue; //fetch the next byte
}
}
/* first opcode byte. */
pDis->bOpCode = codebyte;
pDis->cbPrefix = (uint8_t)offInstr - 1;
offInstr += disParseInstruction(offInstr, &paOneByteMap[pDis->bOpCode], pDis);
break;
}
pDis->cbInstr = (uint8_t)offInstr;
if (pcbInstr)
*pcbInstr = (uint32_t)offInstr;
if (pDis->fPrefix & DISPREFIX_LOCK)
disValidateLockSequence(pDis);
return pDis->rc;
}
/**
* Inlined worker that initializes the disassembler state.
*
* @returns The primary opcode map to use.
* @param pDis The disassembler state.
* @param uInstrAddr The instruction address.
* @param enmCpuMode The CPU mode.
* @param fFilter The instruction filter settings.
* @param pfnReadBytes The byte reader, can be NULL.
* @param pvUser The the user data for the reader.
*/
DECL_FORCE_INLINE(PCDISOPCODE)
disInitializeState(PDISSTATE pDis, RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
PFNDISREADBYTES pfnReadBytes, void *pvUser)
{
RT_ZERO(*pDis);
#ifdef VBOX_STRICT /* poison */
pDis->Param1.Base.idxGenReg = 0xc1;
pDis->Param2.Base.idxGenReg = 0xc2;
pDis->Param3.Base.idxGenReg = 0xc3;
pDis->Param1.Index.idxGenReg = 0xc4;
pDis->Param2.Index.idxGenReg = 0xc5;
pDis->Param3.Index.idxGenReg = 0xc6;
pDis->Param1.uDisp.u64 = UINT64_C(0xd1d1d1d1d1d1d1d1);
pDis->Param2.uDisp.u64 = UINT64_C(0xd2d2d2d2d2d2d2d2);
pDis->Param3.uDisp.u64 = UINT64_C(0xd3d3d3d3d3d3d3d3);
pDis->Param1.uValue = UINT64_C(0xb1b1b1b1b1b1b1b1);
pDis->Param2.uValue = UINT64_C(0xb2b2b2b2b2b2b2b2);
pDis->Param3.uValue = UINT64_C(0xb3b3b3b3b3b3b3b3);
pDis->Param1.uScale = 28;
pDis->Param2.uScale = 29;
pDis->Param3.uScale = 30;
#endif
pDis->fPrefix = DISPREFIX_NONE;
pDis->idxSegPrefix = DISSELREG_DS;
pDis->rc = VINF_SUCCESS;
pDis->pfnDisasmFnTable = g_apfnFullDisasm;
pDis->uInstrAddr = uInstrAddr;
pDis->fFilter = fFilter;
pDis->pfnReadBytes = pfnReadBytes ? pfnReadBytes : disReadBytesDefault;
pDis->pvUser = pvUser;
pDis->uCpuMode = enmCpuMode;
PCDISOPCODE paOneByteMap;
if (enmCpuMode == DISCPUMODE_64BIT)
{
pDis->uAddrMode = DISCPUMODE_64BIT;
pDis->uOpMode = DISCPUMODE_32BIT;
paOneByteMap = g_aOneByteMapX64;
}
else
{
pDis->uAddrMode = enmCpuMode;
pDis->uOpMode = enmCpuMode;
paOneByteMap = g_aOneByteMapX86;
}
return paOneByteMap;
}
/**
* Reads some bytes into the cache.
*
* While this will set DISSTATE::rc on failure, the caller should disregard
* this since that is what would happen if we didn't prefetch bytes prior to the
* instruction parsing.
*
* @param pDis The disassembler state.
*/
DECL_FORCE_INLINE(void) disPrefetchBytes(PDISSTATE pDis)
{
/*
* Read some bytes into the cache. (If this fail we continue as nothing
* has gone wrong since this is what would happen if we didn't precharge
* the cache here.)
*/
int rc = pDis->pfnReadBytes(pDis, 0, 1, sizeof(pDis->abInstr));
if (RT_SUCCESS(rc))
{
Assert(pDis->cbCachedInstr >= 1);
Assert(pDis->cbCachedInstr <= sizeof(pDis->abInstr));
}
else
{
Log(("Initial read failed with rc=%Rrc!!\n", rc));
pDis->rc = VERR_DIS_MEM_READ;
}
}
/**
* Disassembles on instruction, details in @a pDis and length in @a pcbInstr.
*
* @returns VBox status code.
* @param uInstrAddr Address of the instruction to decode. What this means
* is left to the pfnReadBytes function.
* @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
* @param pfnReadBytes Callback for reading instruction bytes.
* @param fFilter Instruction type filter.
* @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
* @param pDis Pointer to disassembler state (output).
* @param pcbInstr Where to store the size of the instruction. (This
* is also stored in PDISSTATE::cbInstr.) Optional.
*/
DISDECL(int) DISInstEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
PFNDISREADBYTES pfnReadBytes, void *pvUser,
PDISSTATE pDis, uint32_t *pcbInstr)
{
PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
disPrefetchBytes(pDis);
return disInstrWorker(pDis, paOneByteMap, pcbInstr);
}
/**
* Disassembles on instruction partially or fully from prefetched bytes, details
* in @a pDis and length in @a pcbInstr.
*
* @returns VBox status code.
* @param uInstrAddr Address of the instruction to decode. What this means
* is left to the pfnReadBytes function.
* @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
* @param pvPrefetched Pointer to the prefetched bytes.
* @param cbPrefetched The number of valid bytes pointed to by @a
* pbPrefetched.
* @param pfnReadBytes Callback for reading instruction bytes.
* @param fFilter Instruction type filter.
* @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
* @param pDis Pointer to disassembler state (output).
* @param pcbInstr Where to store the size of the instruction. (This
* is also stored in PDISSTATE::cbInstr.) Optional.
*/
DISDECL(int) DISInstWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
void const *pvPrefetched, size_t cbPretched,
PFNDISREADBYTES pfnReadBytes, void *pvUser,
PDISSTATE pDis, uint32_t *pcbInstr)
{
PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
if (!cbPretched)
disPrefetchBytes(pDis);
else
{
if (cbPretched >= sizeof(pDis->abInstr))
{
memcpy(pDis->abInstr, pvPrefetched, sizeof(pDis->abInstr));
pDis->cbCachedInstr = (uint8_t)sizeof(pDis->abInstr);
}
else
{
memcpy(pDis->abInstr, pvPrefetched, cbPretched);
pDis->cbCachedInstr = (uint8_t)cbPretched;
}
}
return disInstrWorker(pDis, paOneByteMap, pcbInstr);
}
/**
* Parses one guest instruction.
*
* The result is found in pDis and pcbInstr.
*
* @returns VBox status code.
* @param uInstrAddr Address of the instruction to decode. What this means
* is left to the pfnReadBytes function.
* @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
* @param pfnReadBytes Callback for reading instruction bytes.
* @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
* @param pDis Pointer to disassembler state (output).
* @param pcbInstr Where to store the size of the instruction.
* NULL is allowed. This is also stored in
* PDISSTATE::cbInstr.
*/
DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
PDISSTATE pDis, uint32_t *pcbInstr)
{
return DISInstEx(uInstrAddr, enmCpuMode, DISOPTYPE_ALL, pfnReadBytes, pvUser, pDis, pcbInstr);
}
/**
* Parses one guest instruction.
*
* The result is found in pDis and pcbInstr.
*
* @returns VBox status code.
* @param pvInstr Address of the instruction to decode. This is a
* real address in the current context that can be
* accessed without faulting. (Consider
* DISInstrWithReader if this isn't the case.)
* @param enmCpuMode The CPU mode. DISCPUMODE_32BIT, DISCPUMODE_16BIT, or DISCPUMODE_64BIT.
* @param pfnReadBytes Callback for reading instruction bytes.
* @param pvUser User argument for the instruction reader. (Ends up in pvUser.)
* @param pDis Pointer to disassembler state (output).
* @param pcbInstr Where to store the size of the instruction.
* NULL is allowed. This is also stored in
* PDISSTATE::cbInstr.
*/
DISDECL(int) DISInstr(const void *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr)
{
return DISInstEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pDis, pcbInstr);
}