DisasmCore.cpp revision f9673005f8230c707b14cebdd209ff6e9801252a
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * VBox Disassembler - Core Components.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Copyright (C) 2006-2012 Oracle Corporation
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* Header Files *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Defined Constants And Macros *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** This must be less or equal to DISSTATE::abInstr. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Whether we can do unaligned access. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Internal Functions *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic void disasmModRMReg(PDISSTATE pDis, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** @name Parsers
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Floating point parsing */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/*******************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync* Global Variables *
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync*******************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Parser opcode table for full disassembly. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic PFNDISPARSE const g_apfnFullDisasm[IDX_ParseMax] =
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/** Parser opcode table for only calculating instruction size. */
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic PFNDISPARSE const g_apfnCalcSize[IDX_ParseMax] =
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync/********************************************************************************************************************************
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Read functions for getting the opcode bytes
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync ********************************************************************************************************************************/
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.}
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncstatic DECLCALLBACK(int) disReadBytesDefault(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n"));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync uint8_t const *pbSrc = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync size_t cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK;
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Read more bytes into the DISSTATE::abInstr buffer, advance
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * DISSTATE::cbCachedInstr.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Will set DISSTATE::rc on failure, but still advance cbCachedInstr.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * The caller shall fend off reads beyond the DISSTATE::abInstr buffer.
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.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncDECL_NO_INLINE(static, void) disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin)
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 * Do the read.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * (No need to zero anything on failure as abInstr is already zeroed by the
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * DISInstrEx API.)
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync int rc = pDis->pfnReadBytes(pDis, offInstr, cbMin, sizeof(pDis->abInstr) - offInstr);
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync Assert(pDis->cbCachedInstr <= sizeof(pDis->abInstr));
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * Function for handling a 8-bit cache miss.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @returns The requested byte.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param pDis The disassembler state.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * @param offInstr The offset of the byte relative to the
8683cfdc9273dd77e1c4e89886a7052de103591avboxsync * instruction.
8683cfdc9273dd77e1c4e89886a7052de103591avboxsyncDECL_NO_INLINE(static, uint8_t) disReadByteSlow(PDISSTATE pDis, size_t offInstr)
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1], pDis->abInstr[offInstr + 2], 0);
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
#ifdef DIS_HOST_UNALIGNED_ACCESS_OK
bool fFiltered = false;
fFiltered = true;
return size;
return size;
/********************************************************************************************************************************
********************************************************************************************************************************/
unsigned regtype;
if (scale != 0)
return size;
static size_t ParseSIB_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return size;
/********************************************************************************************************************************
********************************************************************************************************************************/
static void disasmModRMReg(PDISSTATE pDis, PCDISOPCODE pOp, unsigned idx, PDISOPPARAM pParam, int fRegAddr)
if (fRegAddr)
case DISCPUMODE_32BIT:
case DISCPUMODE_64BIT:
case DISCPUMODE_16BIT:
switch (subtype)
case OP_PARM_b:
case OP_PARM_w:
case OP_PARM_d:
case OP_PARM_q:
switch (vtype)
switch (vtype)
switch (mod)
switch (mod)
static size_t QueryModRM(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis, size_t *pSibInc)
if (!pSibInc)
*pSibInc = 0;
switch (mod)
size += sizeof(char);
switch (mod)
size += sizeof(char);
return size;
static size_t QueryModRM_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis, size_t *pSibInc)
if (!pSibInc)
*pSibInc = 0;
switch (mod)
size += sizeof(char);
switch (mod)
size += sizeof(char);
return size;
AssertFailed();
* This instruction is always treated as a register-to-register (MOD = 11) instruction, regardless of the
return size;
static size_t ParseModRM_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
* This instruction is always treated as a register-to-register (MOD = 11) instruction, regardless of the
return size;
return sizeof(uint8_t);
static size_t ParseImmByte_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint8_t);
return sizeof(uint8_t);
static size_t ParseImmByteSX_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint8_t);
return sizeof(uint16_t);
static size_t ParseImmUshort_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint16_t);
return sizeof(uint32_t);
static size_t ParseImmUlong_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint32_t);
return sizeof(uint64_t);
static size_t ParseImmQword_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint64_t);
return sizeof(uint32_t);
return sizeof(uint64_t);
return sizeof(uint16_t);
static size_t ParseImmV_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint32_t);
return sizeof(uint64_t);
return sizeof(uint16_t);
return sizeof(uint16_t);
return sizeof(uint32_t);
static size_t ParseImmZ_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint16_t);
return sizeof(uint32_t);
static size_t ParseImmBRel_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(int32_t);
return sizeof(int32_t);
return sizeof(int16_t);
static size_t ParseImmVRel_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(int16_t);
return sizeof(int32_t);
return sizeof(uint32_t);
return sizeof(uint64_t);
return sizeof(uint32_t);
return sizeof(uint16_t);
static size_t ParseImmAddr_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint32_t);
return sizeof(uint64_t);
return sizeof(uint32_t);
return sizeof(uint16_t);
return sizeof(uint32_t);
static size_t ParseImmAddrF_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return sizeof(uint32_t);
return size;
static size_t ParseThreeByteEsc4(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return size;
static size_t ParseThreeByteEsc5(size_t offInstr, PCDISOPCODE pOp, PDISOPPARAM pParam, PDISSTATE pDis)
return size;
return size;
return size;
int idx;
return sizeof(uint8_t);
return size;
return size;
return size;
return size;
#ifdef DEBUG_Sander
#ifdef DEBUG_Sander /* bird, 2005-06-28: Alex is getting this during full installation of win2ksp4. */
return size;
return size;
return size;
return size;
return size;
return size;
return size;
return size;
return size;
return size;
return size;
case OP_BTC:
case OP_BTR:
case OP_BTS:
case OP_CMPXCHG:
case OP_XADD:
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:
switch (opcode)
case OP_INVALID:
if (pcbInstr)
case OP_SEG:
case OP_LOCK:
case OP_ADDRSIZE:
case OP_OPSIZE:
pDis->uOpMode = DISCPUMODE_16BIT; /* for 32 and 64 bits mode (there is no 32 bits operand size override prefix) */
case OP_REPE:
case OP_REPNE:
case OP_REX:
if (pcbInstr)
return paOneByteMap;
PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
DISDECL(int) DISInstWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter,
PCDISOPCODE paOneByteMap = disInitializeState(pDis, uInstrAddr, enmCpuMode, fFilter, pfnReadBytes, pvUser);
if (!cbPretched)
DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser,
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);