/* $Id$ */
/** @file
* CPU Instruction Decoding & Execution Tests - Simple Instructions.
*/
/*
* Copyright (C) 2014 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** @def CIDET_DPRINTF
* Debug printf. */
#if 1 //def DEBUG_bird
# define CIDET_DPRINTF_ENABLED
#else
# define CIDET_DPRINTF(a) do { } while (0)
#endif
/** @def CIDET_DEBUG_DISAS
* Enables instruction disassembly. */
#if defined(DOXYGEN_RUNNING)
#endif
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include "cidet.h"
#if defined(CIDET_DPRINTF_ENABLED) || defined(CIDET_DEBUG_DISAS)
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** For translating CIDET_OF_Z_XXX values (after shifting). */
{
/* [CIDET_OF_Z_NONE] = */ 0,
/* [CIDET_OF_Z_BYTE] = */ 1,
/* [CIDET_OF_Z_WORD] = */ 2,
/* [CIDET_OF_Z_DWORD] = */ 4,
/* [CIDET_OF_Z_QWORD] = */ 8,
/* [CIDET_OF_Z_TBYTE] = */ 10,
/* [CIDET_OF_Z_OWORD] = */ 16,
/* [CIDET_OF_Z_YWORD] = */ 32,
/* [CIDET_OF_Z_ZWORD] = */ 64,
/* [CIDET_OF_Z_VAR_WDQ] = */ UINT16_MAX,
/* [0xa] = */ 0,
/* [0xb] = */ 0,
/* [0xc] = */ 0,
/* [0xd] = */ 0,
/* [0xe] = */ 0,
};
/** Converts operand sizes in bytes to 64-bit masks. */
{
UINT64_C(0x0000000000000000),
UINT64_C(0x00000000000000ff),
UINT64_C(0x000000000000ffff),
UINT64_C(0x0000000000ffffff),
UINT64_C(0x00000000ffffffff),
UINT64_C(0x000000ffffffffff),
UINT64_C(0x0000ffffffffffff),
UINT64_C(0x00ffffffffffffff),
UINT64_C(0xffffffffffffffff),
};
/** Converts operand sizes in bytes to 64-bit signed max values. */
{
INT64_C(0x0000000000000000),
INT64_C(0x000000000000007f),
INT64_C(0x0000000000007fff),
INT64_C(0x00000000007fffff),
INT64_C(0x000000007fffffff),
INT64_C(0x0000007fffffffff),
INT64_C(0x00007fffffffffff),
INT64_C(0x007fffffffffffff),
INT64_C(0x7fffffffffffffff),
};
{
}
{
}
{
}
{
return VINF_SUCCESS;
}
{
}
/**
* Report a test failure via CIDET::pfnFailure
*
* @returns false
* @param pThis Pointer to the core structure.
* @param pszFormat Format string containing failure details.
* @param va Arguments referenced in @a pszFormat.
*/
{
return false;
}
/**
* Report a test failure via CIDET::pfnFailure
*
* @returns false
* @param pThis Pointer to the core structure.
* @param pszFormat Format string containing failure details.
* @param ... Arguments referenced in @a pszFormat.
*/
{
return false;
}
/**
* Get a signed random number, with a given number of significant bytes.
*
* @returns Random number.
* @param pThis Pointer to the core structure.
* @param cbSignificant The number of significant bytes.
*/
{
switch (cbSignificant)
{
case 8: return iVal;
default:
return iVal;
}
}
/**
* Get an unsigned random number, with a given number of significant bytes.
*
* @returns Random number.
* @param pThis Pointer to the core structure.
* @param cbSignificant The number of significant bytes.
*/
{
return uVal;
}
{
while (i-- > 0)
| ((uint64_t)i << 32)
| ((uint32_t)i << 8);
else
while (i-- > 0)
| ((uint32_t)i << 12)
| ((uint32_t)i << 8);
while (i-- > 0)
#ifndef CIDET_REDUCED_CTX
#endif
}
/**
* Sets the target mode.
*
* Caller must set up default selector values after calling this function.
*
* @returns VBox status code.
* @param pThis Pointer to the core structure.
* @param bMode The new mode.
*/
{
AssertPtrReturn(pThis, VERR_INVALID_HANDLE); AssertReturn(pThis->u32Magic == CIDETCORE_MAGIC, VERR_INVALID_HANDLE);
switch (bMode)
{
//case CIDETMODE_RM:
//case CIDETMODE_PE_16:
//case CIDETMODE_PE_32:
//case CIDETMODE_PE_V86:
//case CIDETMODE_PP_16:
case CIDETMODE_PP_32:
//case CIDETMODE_PP_V86:
//case CIDETMODE_PAE_16:
case CIDETMODE_PAE_32:
//case CIDETMODE_PAE_V86:
//case CIDETMODE_LM_S16:
//case CIDETMODE_LM_32:
case CIDETMODE_LM_64:
break;
default:
return VERR_NOT_IMPLEMENTED;
}
return VINF_SUCCESS;
}
{
return true;
}
/**
* Selects the next address size mode.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
*/
{
if (pThis->fAddrSizePrf)
{
/*
* Reset to default.
*/
pThis->fAddrSizePrf = false;
}
else
{
/*
* The other addressing size.
*/
else
{
}
pThis->fAddrSizePrf = true;
}
return pThis->fAddrSizePrf;
}
/**
* Selects the first REG encoding.
*
* @param pThis The core state structure.
*/
{
}
/**
* Selects the next REG (ModR/M) encoding.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
Assert(pThis->idxMrmRegOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRegOp].fIsMem);
/*
* Clear the collision flags here because of the byte register kludge.
*/
pThis->fHasRegCollisionDirect = false;
pThis->fHasRegCollisionMemBase = false;
pThis->fHasRegCollisionMemIndex = false;
pThis->fHasRegCollisionMem = false;
/*
* Clear the REX prefix and high byte register tracking too. ASSUMES MrmReg is after MrmRmMod.
*/
pThis->fNoRexPrefixMrmReg = false;
pThis->fNoRexPrefix = false;
pThis->fHasHighByteRegInMrmReg = false;
/*
* Special kludge for ah, ch, dh, bh, spl, bpl, sil, and dil.
* Needs extra care in 64-bit mode and special collision detection code.
*/
CIDET_DPRINTF(("aOperands[%u].cb=%u fGpr=%u iReg=%d fRex=%d fRexW=%u fRexX=%u fRexB=%u fRexR=%d\n",
pThis->idxMrmRegOp, pThis->aOperands[pThis->idxMrmRegOp].cb, CIDET_OF_K_IS_GPR(pThis->fMrmRegOp), iReg,
&& iReg >= 3
&& ( iReg <= 6
{
{
/* The AMD64 low variants: spl, bpl, sil and dil. */
/* Check for collisions. */
{
else
{
}
}
}
else
{
/* Next register: ah, ch, dh and bh. */
iReg++;
pThis->fNoRexPrefixMrmReg = true;
pThis->fNoRexPrefix = true;
pThis->fHasHighByteRegInMrmReg = true;
pThis->fHasStackRegInMrmReg = false;
/* Check for collisions. */
{
else
{
}
}
}
return true;
}
/*
* Next register.
*/
/*
* Register collision detection.
*/
{
{
}
}
return iReg != 0;
}
/**
* Selects the next MOD & R/M encoding, 16-bit addressing variant.
*
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
{
pThis->fHasMemoryOperand = false;
pThis->fHasRegCollisionMem = false;
pThis->fHasRegCollisionMemBase = false;
pThis->fHasRegCollisionMemIndex = false;
pThis->fHasStackRegInMrmRmBase = false;
}
else
{
pThis->fHasMemoryOperand = true;
pThis->fHasRegCollisionDirect = false;
pThis->fHasStackRegInMrmRmBase = false;
}
}
/**
* Selects the next MOD & R/M encoding, 16-bit addressing variant.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
if (iMod == 3)
{
/*
* Register access mode.
*/
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
if (iRm < 7)
{
iRm++;
return true;
}
/* If no memory modes, we're done. */
{
return false;
}
/* Next mode: 16-bit memory addressing without displacement. */
iMod = 0;
}
else
{
/*
* Memory access mode.
*/
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
if (iRm < 7)
{
iRm++;
switch (iRm)
{
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
break;
case 5:
break;
case 6:
if (iMod == 0)
{
}
else
break;
case 7:
if (iMod == 0)
break;
default: AssertReleaseFailed();
}
{
}
return true;
}
/* Last mode? */
if (iMod >= 2)
{
return false;
}
/* Next memory addressing mode (if any). */
iMod++;
}
pThis->fHasMemoryOperand = true;
pThis->fHasRegCollisionDirect = false;
pThis->fHasStackRegInMrmRmBase = false;
{
}
return true;
}
/**
* Selects the first MOD & R/M encoding, 32-bit and 64-bit addressing variant.
*
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
* @param f64Bit Set if 64-bit, clear if 32-bit.
*/
static void cidetCoreSetupFirstBaseEncoding_MrmRmMod_32bit64bit(PCIDETCORE pThis, uint8_t iReg, bool f64Bit)
{
{
pThis->fHasMemoryOperand = false;
pThis->fHasRegCollisionMem = false;
pThis->fHasRegCollisionMemBase = false;
pThis->fHasRegCollisionMemIndex = false;
pThis->fHasStackRegInMrmRmBase = false;
}
else
{
pThis->fHasMemoryOperand = true;
pThis->fHasRegCollisionDirect = false;
pThis->fHasRegCollisionMemIndex = false;
pThis->fHasRegCollisionMemBase = iReg == pThis->fHasHighByteRegInMrmReg * 4 && CIDET_OF_K_IS_GPR(pThis->fMrmRegOp);
pThis->fHasStackRegInMrmRmBase = false;
}
}
/**
* Selects the next MOD & R/M encoding, 32-bit and 64-bit addressing variant.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
* @param f64Bit Set if 64-bit, clear if 32-bit.
*/
static bool cidetCoreSetupNextBaseEncoding_MrmRmMod_32bit64bit(PCIDETCORE pThis, uint8_t iReg, bool f64Bit)
{
if (iMod == 3)
{
/*
* Register access mode.
*/
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && !pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
if (CIDETMODE_IS_64BIT(pThis->bMode) && !pThis->fRexX && !pThis->fNoRexPrefix) /* should be ignored. */
{
return true;
}
/* Reset the byte register kludges variables. */
pThis->fHasHighByteRegInMrmRm = false;
pThis->fNoRexPrefixMrmRm = false;
{
/*
* Byte register kludge.
*/
&& iRm >= 3
&& ( iRm <= 6
{
{
/* The AMD64 low variants: spl, bpl, sil and dil. (Using fRexX here as REG covers fRex.) */
}
else
{
/* Next register: ah, ch, dh and bh. */
iRm++;
{
pThis->fNoRexPrefixMrmRm = true;
pThis->fNoRexPrefix = true;
pThis->fHasHighByteRegInMrmRm = true;
pThis->fHasStackRegInMrmRmBase = false;
}
else
{
/* Can't do the high stuff, so do the spl, bpl, sil and dil variation instead.
Note! We don't set the RexX yet since the base register or operand width holds it down. */
}
}
}
/*
* Normal register.
*/
else
{
iRm++;
pThis->fHasRegCollisionDirect = iRm == iReg && CIDET_OF_K_IS_SAME(pThis->fMrmRmOp, pThis->fMrmRegOp);
}
return true;
}
/* If no memory modes, we're done. */
{
return false;
}
/* Next mode: 32-bit/64-bit memory addressing without displacement. */
iMod = 0;
}
else
{
/*
* Memory access mode.
*/
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
{
iRm++;
if (iRm == 12)
iRm++; /* Leave REX.B=1 to the next-sib-base function. */
if (iRm == 4)
{
/* SIB */
}
{
/* Absolute or wrt rip addressing. */
}
else
{
{
}
}
{
}
return true;
}
/* Last mode? */
if (iMod >= 2)
{
return false;
}
/* Next memory addressing mode (if any). */
iMod++;
}
pThis->fHasMemoryOperand = true;
pThis->fHasRegCollisionDirect = false;
pThis->fHasRegCollisionMemIndex = false;
pThis->fHasStackRegInMrmRmBase = false;
return true;
}
/**
* Selects the next MOD & R/M encoding.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
AssertReleaseFailedReturn(false);
}
/**
* Selects the next SIB base register (/ encoding).
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
{
}
else
{
}
return iBase != 0;
}
/**
* Selects the next SIB index register (/ encoding).
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
Assert(pThis->idxMrmRmOp < RT_ELEMENTS(pThis->aOperands) && pThis->aOperands[pThis->idxMrmRmOp].fIsMem);
else
&& ( !pThis->fUsesVexIndexRegs
return iIndex != 0;
}
/**
* Selects the next SIB scale.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
* @param iReg The value of MODRM.REG /w REX.R applied.
*/
{
{
case 0:
return true;
case 1:
return true;
case 2:
return true;
case 3:
return false;
default: AssertReleaseFailedReturn(false);
}
}
/**
* Selects the next segment prefix.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
*/
{
if ( pThis->fHasMemoryOperand
{
{
case X86_SREG_COUNT:
return true;
/* fall thru */
case X86_SREG_ES:
return true;
/* fall thru */
case X86_SREG_CS:
return true;
/* fall thru */
case X86_SREG_SS:
return true;
/* fall thru */
case X86_SREG_DS:
return true;
/* fall thru */
case X86_SREG_FS:
return true;
/* fall thru */
case X86_SREG_GS:
break;
default: AssertReleaseFailedBreak();
}
}
return false;
}
/**
* Updates the variable sized operands.
*
* @param pThis The core state structure.
*/
{
while (iOp-- > 0)
}
/**
* Selects the next operand size.
*
* @returns @c true if done, @c false if the next wheel needs to be moved.
* @param pThis The core state structure.
*/
{
{
{
{
case 0:
pThis->fOpSizePrf = true;
return true;
case 1:
pThis->fOpSizePrf = false;
if (pThis->fNoRexPrefix)
break;
return true;
case 2:
return true;
default: AssertReleaseFailed();
case 3:
break;
}
}
else
{
if (!pThis->fOpSizePrf)
{
pThis->fOpSizePrf = true;
return true;
}
}
pThis->fOpSizePrf = false;
}
return false;
}
{
if (pThis->fUsesModRm)
{
/*
* The wheels are lined up as follows:
* 1. Address size prefix.
* 2. MODRM.MOD
* 3. MODRM.REG + REX.R
* 4. MODRM.R/M + REX.B
* 5. SIB - MODRM.R/M == 4 && MODRM.MOD != 3:
* 5a) SIB.BASE + REX.B
* 5b) SIB.INDEX + REX.X
* 5c) SIB.SCALE
* 6. Segment prefix overrides if applicable and supported (memory).
* 7. Operand size prefix and REX.W if applicable.
*/
return true;
return true;
/* The ModR/M register value for collision detection. */
{
return true;
return true;
return true;
}
return true;
return true;
return true;
}
else
AssertFailedReturn(false);
return false;
}
{
/*
* Reset all the knobs and wheels.
*/
pThis->fAddrSizePrf = false;
pThis->fOpSizePrf = false;
/* Indicators. */
pThis->fHasMemoryOperand = false;
pThis->fHasRegCollisionMem = false;
pThis->fHasRegCollisionMemBase = false;
pThis->fHasRegCollisionMemIndex = false;
pThis->fHasStackRegInMrmRmBase = false;
/*
* Now, drill down on the instruction encoding.
*/
{
else
AssertReleaseFailedReturn(false);
}
else
AssertFailedReturn(false);
return true;
}
/**
* The next memory operand configuration.
*
* @returns true if new one to test, false if we've reached end already.
* @param pThis The core state structure.
*/
{
return false;
}
/**
* Sets up the first memory operand configuration and counts memory operands.
*
* @returns true on success, false if no data buffers configured or failure.
* @param pThis The core state structure.
*/
{
pThis->cMemoryOperands = 0;
while (idxOp-- > 0)
else
{
return false;
pDataBuf->offSegBase = 0;
pDataBuf->fXcptAfterInstruction = false;
pThis->cMemoryOperands++;
pDataBuf++;
}
/** @todo implement more than one memory operand. */
return true;
}
/**
* The next code buffer configuration.
*
* @returns true if new one to test, false if we've reached end already.
* @param pThis The core state structure.
*/
{
return false;
}
/**
* Sets up the first code buffer configuration.
*
* @returns true on success, false if no data buffers configured or failure.
* @param pThis The core state structure.
*/
{
return true;
}
/**
* Gets the (encoded) size of the given operand in the current context.
*
* @returns Size in bytes.
* @param pThis The core state structure (for context).
* @param iOp The operand index.
*/
{
uint32_t cbOp = g_acbCidetOfSizes[(pThis->aOperands[iOp].fFlags & CIDET_OF_Z_MASK) >> CIDET_OF_Z_SHIFT];
if (cbOp == UINT16_MAX)
{
{
cbOp = 8;
else if (!pThis->fOpSizePrf)
cbOp = 4;
else
cbOp = 2;
}
else
{
}
return cbOp;
}
{
}
if (cbOp)
{
#ifdef VBOX_STRICT
switch (cbOp)
{
default: AssertFailed();
}
#endif
return cbOp;
}
}
{
/*
* Extract info from the instruction descriptor.
*/
pThis->fUsesModRm = false;
pThis->fUsesVexIndexRegs = false;
{
pThis->fUsesModRm = true;
{
}
{
}
}
else
AssertFailedReturn(false);
{
}
{
}
/*
* Reset various things.
*/
return true;
}
{
/*
* Enumerate the operands.
*/
while (idxOp-- > 0)
{
{
/*
* Memory operand.
*/
/* Set the In & Expected members to point to temporary buffer space. */
/* Initialize the buffer we're gonna use. */
: X86_SREG_ES;
AssertReleaseReturn(pDataBuf, false);
{
return false;
}
/* Calc buffer related operand members. */
/*
* Select register and displacement values for the buffer addressing (works on offSeg).
*/
{
/* rip relative. */
{
return false;
}
}
else if (iMemBaseReg != UINT8_MAX)
{
if ( iMemBaseReg != iMemIndexReg
|| pThis->fUsesVexIndexRegs)
{
/* [base] or [base + disp] or [base + index * scale] or [base + index * scale + disp] */
{
pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
}
if (iMemIndexReg != UINT8_MAX)
{
}
}
else
{
/* base == index; [base + index * scale] or [base * (scale + 1)]. */
{
pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
if (uRemainder != 0)
{
+ uRemainder;
offSeg -= uRemainder;
{
}
}
}
else
{
{
return false;
}
}
}
}
else if (iMemIndexReg != UINT8_MAX)
{
/* [index * scale] or [index * scale + disp] */
{
pThis->aOperands[idxOp].uImmDispValue = CidetCoreGetRandS64(pThis, pThis->aOperands[idxOp].cbMemDisp);
pThis->aOperands[idxOp].uImmDispValue += offSeg & (RT_BIT_64(pThis->aOperands[idxOp].uMemScale) - 1);
}
{
return false;
}
}
else
{
/* [disp] */
: false /* 8 */)
{
return false;
}
}
/*
* Modify the input and expected output contexts with the base and
* index register values. To simplify verification and the work
* here, we update the uMemBaseRegValue and uMemIndexRegValue
* members to reflect the whole register.
*/
if (iMemBaseReg != UINT8_MAX)
{
{
pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffff00000000);
}
{
pThis->aOperands[idxOp].uMemBaseRegValue |= pThis->InCtx.aGRegs[iMemBaseReg] & UINT64_C(0xffffffffffff0000);
}
}
if (iMemIndexReg != UINT8_MAX)
{
{
pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffff00000000);
}
{
pThis->aOperands[idxOp].uMemIndexRegValue |= pThis->InCtx.aGRegs[iMemIndexReg] & UINT64_C(0xffffffffffff0000);
}
}
}
else
{
/*
* Non-memory, so clear the memory related members.
*/
{
case CIDET_OF_K_GPR:
{
}
else
{
}
break;
case CIDET_OF_K_IMM:
break;
case CIDET_OF_K_SREG:
{
}
else
{
}
break;
case CIDET_OF_K_CR:
case CIDET_OF_K_SSE:
case CIDET_OF_K_AVX:
case CIDET_OF_K_AVX512:
case CIDET_OF_K_FPU:
case CIDET_OF_K_MMX:
case CIDET_OF_K_AVXFUTURE:
case CIDET_OF_K_SPECIAL:
case CIDET_OF_K_TEST:
/** @todo Implement testing these registers. */
case CIDET_OF_K_NONE:
default:
AssertReleaseFailedReturn(false);
}
}
}
/*
* Call instruction specific setup function (for operand values and flags).
*/
if (RT_FAILURE(rc))
{
return false;
}
/*
* Do the 2nd set of the memory operand preparations.
*/
if (pThis->fHasMemoryOperand)
{
while (idxOp-- > 0)
{
if (!pThis->pfnSetupDataBuf(pThis, pThis->aOperands[idxOp].pDataBuf, pThis->aOperands[idxOp].In.pv))
{
return false;
}
|| pThis->InCtx.aGRegs[pThis->aOperands[idxOp].iMemBaseReg] == pThis->aOperands[idxOp].uMemBaseRegValue);
|| ( !pThis->fUsesVexIndexRegs
: false /** @todo VEX indexing */));
}
}
return true;
}
/**
* Figures the instruction length.
*
* This is a duplicate of CidetCoreAssemble() with the buffer updates removed.
*
* @returns true and pThis->cbInstr on success, false on failure.
* @param pThis The core state structure (for context).
*/
{
/*
* Prefixes.
*/
if (1)
{
if (pThis->fAddrSizePrf)
off++;
if (pThis->fOpSizePrf)
off++;
}
else
{
/** @todo prefix list. */
}
/*
* Prefixes that must come right before the opcode.
*/
/** @todo VEX and EVEX. */
{
/** @todo VEX and EVEX. */
}
{
/** @todo VEX and EVEX. */
}
else
{
off++;
}
/*
* The opcode.
*/
{
case 3: off++;
case 2: off++;
case 1: off++;
break;
default:
AssertReleaseFailedReturn(false);
}
/*
* Mod R/M
*/
if (pThis->fUsesModRm)
{
off++;
off++;
{
{
case 0: break;
case 8:
case 7:
case 6:
case 5:
case 4:
case 3:
case 2:
case 1:
break;
default: AssertReleaseFailedReturn(false);
}
}
}
/*
* Immediates.
*/
while (iOp-- > 0)
{
{
case 8:
case 7:
case 6:
case 5:
case 4:
case 3:
case 2:
case 1:
break;
default: AssertReleaseFailedReturn(false);
}
}
return true;
}
/**
* Assembles the instruction.
*
* This is a duplicate of CidetCoreAssembleLength() with buffer writes.
*
* @returns true and pThis->cbInstr and pThis->abInstr on success, false on
* failure.
* @param pThis The core state structure (for context).
*/
{
/*
* Prefixes.
*/
if (1)
{
if (pThis->fAddrSizePrf)
if (pThis->fOpSizePrf)
}
else
{
/** @todo prefix list. */
}
/*
* Prefixes that must come right before the opcode.
*/
/** @todo VEX and EVEX. */
{
/** @todo VEX and EVEX. */
}
{
/** @todo VEX and EVEX. */
}
else
{
pThis->abInstr[off++] = 0x40 | (pThis->fRexB * 1) | (pThis->fRexX * 2) | (pThis->fRexR * 4) | (pThis->fRexW * 8);
}
/*
* The opcode.
*/
{
break;
default:
AssertReleaseFailedReturn(false);
}
/*
* Mod R/M
*/
if (pThis->fUsesModRm)
{
{
{
case 0: break;
break;
default: AssertReleaseFailedReturn(false);
}
}
}
/*
* Immediates.
*/
while (iOp-- > 0)
{
{
break;
default: AssertReleaseFailedReturn(false);
}
}
return true;
}
{
/*
* Re-initialize the buffer. Requires instruction length and positioning.
*/
if (CidetCoreAssembleLength(pThis))
{
{
/*
* Update the RIP and CS values in the input and expected contexts.
*/
pThis->ExpectedCtx.rip = pThis->InCtx.rip + pThis->cbInstr; /** @todo account for expected traps. */
{
}
return true;
}
else
}
else
return false;
}
#ifdef CIDET_DEBUG_DISAS
/**
* @callback_method_impl{FNDISREADBYTES}
*/
static DECLCALLBACK(int) cidetCoreDisReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)
{
return VINF_SUCCESS;
}
#endif
{
if (CidetCoreAssemble(pThis))
{
//CIDET_DPRINTF(("%04u: %.*Rhxs\n", i, pThis->cbInstr, pThis->abInstr));
#ifdef CIDET_DEBUG_DISAS
char szInstr[80] = {0};
&Dis,
&cbInstr,
#endif
{
return true;
}
}
else
return false;
}
/**
* Compares the output with the output expectations.
*
* @returns true if ok, false if not (calls pfnFailure too).
* @param pThis The core state structure.
*/
{
return true;
unsigned cDiffs = 0;
{ \
cDiffs++; \
} else do { } while (0)
#ifndef CIDET_REDUCED_CTX
#endif
return cDiffs == 0;
}
{
/*
* Iterate all encodings.
*/
unsigned cExecuted = 0;
unsigned cSkipped = 0;
do
{
/*
* Iterate data buffer configurations (one iteration if none).
*/
{
do
{
/*
* Iterate code buffer configurations.
*/
do
{
/*
* Set up inputs and expected outputs, then emit the test code.
*/
if ( CidetCoreReInitCodeBuf(pThis)
)
{
{
cExecuted++;
/*
* Check the result against our expectations.
*/
/** @todo check result. */
}
else
cSkipped++;
}
else
cSkipped++;
} while (CidetCoreSetupNextCodeBufferConfig(pThis));
} while (CidetCoreSetupNextMemoryOperandConfig(pThis));
}
else
cSkipped++;
} while (CidetCoreSetupNextBaseEncoding(pThis));
CIDET_DPRINTF(("CidetCoreTest_Basic: cExecuted=%u cSkipped=%u\n"
" cSkippedSetupInOut =%u\n"
" cSkippedReInitDataBuf =%u\n"
" cSkippedSetupDataBuf =%u\n"
" cSkippedDataBufWrtRip =%u\n"
" cSkippedAssemble =%u\n"
" cSkippedReInitCodeBuf =%u\n"
" cSkippedSetupCodeBuf =%u\n"
" cSkippedSameBaseIndexRemainder =%u\n"
" cSkippedOnlyIndexRemainder =%u\n"
" cSkippedDirectAddressingOverflow =%u\n"
,
));
return true;
}
{
return fResult;
}