diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-11 08:17:27 +0000 |
commit | f215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch) | |
tree | 6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Disassembler | |
parent | Initial commit. (diff) | |
download | virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip |
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Disassembler')
30 files changed, 14555 insertions, 0 deletions
diff --git a/src/VBox/Disassembler/.scm-settings b/src/VBox/Disassembler/.scm-settings new file mode 100644 index 00000000..32b0a169 --- /dev/null +++ b/src/VBox/Disassembler/.scm-settings @@ -0,0 +1,30 @@ +# $Id: .scm-settings $ +## @file +# Source code massager settings for the diassembler. +# + +# +# Copyright (C) 2010-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +--filter-out-files *.bin +/*.h: --guard-relative-to-dir . + diff --git a/src/VBox/Disassembler/Disasm.cpp b/src/VBox/Disassembler/Disasm.cpp new file mode 100644 index 00000000..734cbfb0 --- /dev/null +++ b/src/VBox/Disassembler/Disasm.cpp @@ -0,0 +1,126 @@ +/* $Id: Disasm.cpp $ */ +/** @file + * VBox disassembler - Disassemble and optionally format. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DIS +#include <VBox/dis.h> +#include <VBox/disopcode.h> +#include <iprt/errcore.h> +#include <iprt/assert.h> +#include <iprt/string.h> +#include "DisasmInternal.h" + + +/** + * Disassembles one instruction + * + * @returns VBox error code + * @param pvInstr Pointer to the instruction to disassemble. + * @param enmCpuMode The CPU state. + * @param pDis The disassembler state (output). + * @param pcbInstr Where to store the size of the instruction. NULL is + * allowed. + * @param pszOutput Storage for disassembled instruction + * @param cbOutput Size of the output buffer. + * + * @todo Define output callback. + */ +DISDECL(int) DISInstrToStr(void const *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr, + char *pszOutput, size_t cbOutput) +{ + return DISInstrToStrEx((uintptr_t)pvInstr, enmCpuMode, NULL, NULL, DISOPTYPE_ALL, + pDis, pcbInstr, pszOutput, cbOutput); +} + +/** + * Disassembles one instruction with a byte fetcher caller. + * + * @returns VBox error code + * @param uInstrAddr Pointer to the structure to disassemble. + * @param enmCpuMode The CPU mode. + * @param pfnCallback The byte fetcher callback. + * @param pvUser The user argument (found in + * DISSTATE::pvUser). + * @param pDis The disassembler state (output). + * @param pcbInstr Where to store the size of the instruction. NULL is + * allowed. + * @param pszOutput Storage for disassembled instruction. + * @param cbOutput Size of the output buffer. + * + * @todo Define output callback. + */ +DISDECL(int) DISInstrToStrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput) + +{ + return DISInstrToStrEx(uInstrAddr, enmCpuMode, pfnReadBytes, pvUser, DISOPTYPE_ALL, + pDis, pcbInstr, pszOutput, cbOutput); +} + +/** + * Disassembles one instruction; only fully disassembly an instruction if it matches the filter criteria + * + * @returns VBox error code + * @param uInstrAddr Pointer to the structure to disassemble. + * @param enmCpuMode The CPU mode. + * @param pfnCallback The byte fetcher callback. + * @param uFilter Instruction filter. + * @param pDis Where to return the disassembled instruction info. + * @param pcbInstr Where to store the size of the instruction. NULL is + * allowed. + * @param pszOutput Storage for disassembled instruction. + * @param cbOutput Size of the output buffer. + * + * @todo Define output callback. + */ +DISDECL(int) DISInstrToStrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, + PFNDISREADBYTES pfnReadBytes, void *pvUser, uint32_t uFilter, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput) +{ + /* Don't filter if formatting is desired. */ + if (uFilter != DISOPTYPE_ALL && pszOutput && cbOutput) + uFilter = DISOPTYPE_ALL; + + int rc = DISInstrEx(uInstrAddr, enmCpuMode, uFilter, pfnReadBytes, pvUser, pDis, pcbInstr); + if (RT_SUCCESS(rc) && pszOutput && cbOutput) + { + size_t cch = DISFormatYasmEx(pDis, pszOutput, cbOutput, + DIS_FMT_FLAGS_BYTES_LEFT | DIS_FMT_FLAGS_BYTES_BRACKETS | DIS_FMT_FLAGS_BYTES_SPACED + | DIS_FMT_FLAGS_RELATIVE_BRANCH | DIS_FMT_FLAGS_ADDR_LEFT, + NULL /*pfnGetSymbol*/, NULL /*pvUser*/); + if (cch + 2 <= cbOutput) + { + pszOutput[cch++] = '\n'; + pszOutput[cch] = '\0'; + } + } + return rc; +} + diff --git a/src/VBox/Disassembler/DisasmCore.cpp b/src/VBox/Disassembler/DisasmCore.cpp new file mode 100644 index 00000000..c2613523 --- /dev/null +++ b/src/VBox/Disassembler/DisasmCore.cpp @@ -0,0 +1,3000 @@ +/* $Id: DisasmCore.cpp $ */ +/** @file + * VBox Disassembler - Core Components. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DIS +#include <VBox/dis.h> +#include <VBox/disopcode.h> +#include <VBox/err.h> +#include <VBox/log.h> +#include <iprt/assert.h> +#include <iprt/param.h> +#include <iprt/string.h> +#include <iprt/stdarg.h> +#include "DisasmInternal.h" + + +/********************************************************************************************************************************* +* Defined Constants And Macros * +*********************************************************************************************************************************/ +/** This must be less or equal to DISSTATE::abInstr. + * See Vol3A/Table 6-2 and Vol3B/Section22.25 for instance. */ +#define DIS_MAX_INSTR_LENGTH 15 + +/** Whether we can do unaligned access. */ +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +# define DIS_HOST_UNALIGNED_ACCESS_OK +#endif + + +/********************************************************************************************************************************* +* Internal Functions * +*********************************************************************************************************************************/ +/** @name Parsers + * @{ */ +static FNDISPARSE ParseIllegal; +static FNDISPARSE ParseModRM; +static FNDISPARSE ParseModRM_SizeOnly; +static FNDISPARSE UseModRM; +static FNDISPARSE ParseImmByte; +static FNDISPARSE ParseImmByte_SizeOnly; +static FNDISPARSE ParseImmByteSX; +static FNDISPARSE ParseImmByteSX_SizeOnly; +static FNDISPARSE ParseImmBRel; +static FNDISPARSE ParseImmBRel_SizeOnly; +static FNDISPARSE ParseImmUshort; +static FNDISPARSE ParseImmUshort_SizeOnly; +static FNDISPARSE ParseImmV; +static FNDISPARSE ParseImmV_SizeOnly; +static FNDISPARSE ParseImmVRel; +static FNDISPARSE ParseImmVRel_SizeOnly; +static FNDISPARSE ParseImmZ; +static FNDISPARSE ParseImmZ_SizeOnly; + +static FNDISPARSE ParseImmAddr; +static FNDISPARSE ParseImmAddr_SizeOnly; +static FNDISPARSE ParseImmAddrF; +static FNDISPARSE ParseImmAddrF_SizeOnly; +static FNDISPARSE ParseFixedReg; +static FNDISPARSE ParseImmUlong; +static FNDISPARSE ParseImmUlong_SizeOnly; +static FNDISPARSE ParseImmQword; +static FNDISPARSE ParseImmQword_SizeOnly; +static FNDISPARSE ParseInvOpModRm; + +static FNDISPARSE ParseTwoByteEsc; +static FNDISPARSE ParseThreeByteEsc4; +static FNDISPARSE ParseThreeByteEsc5; +static FNDISPARSE ParseGrp1; +static FNDISPARSE ParseShiftGrp2; +static FNDISPARSE ParseGrp3; +static FNDISPARSE ParseGrp4; +static FNDISPARSE ParseGrp5; +static FNDISPARSE Parse3DNow; +static FNDISPARSE ParseGrp6; +static FNDISPARSE ParseGrp7; +static FNDISPARSE ParseGrp8; +static FNDISPARSE ParseGrp9; +static FNDISPARSE ParseGrp10; +static FNDISPARSE ParseGrp12; +static FNDISPARSE ParseGrp13; +static FNDISPARSE ParseGrp14; +static FNDISPARSE ParseGrp15; +static FNDISPARSE ParseGrp16; +static FNDISPARSE ParseGrp17; +static FNDISPARSE ParseModFence; +static FNDISPARSE ParseNopPause; +static FNDISPARSE ParseVex2b; +static FNDISPARSE ParseVex3b; +static FNDISPARSE ParseVexDest; + +static FNDISPARSE ParseYv; +static FNDISPARSE ParseYb; +static FNDISPARSE ParseXv; +static FNDISPARSE ParseXb; + +/** Floating point parsing */ +static FNDISPARSE ParseEscFP; +/** @} */ + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** Parser opcode table for full disassembly. */ +static PFNDISPARSE const g_apfnFullDisasm[IDX_ParseMax] = +{ + ParseIllegal, + ParseModRM, + UseModRM, + ParseImmByte, + ParseImmBRel, + ParseImmUshort, + ParseImmV, + ParseImmVRel, + ParseImmAddr, + ParseFixedReg, + ParseImmUlong, + ParseImmQword, + ParseTwoByteEsc, + ParseGrp1, + ParseShiftGrp2, + ParseGrp3, + ParseGrp4, + ParseGrp5, + Parse3DNow, + ParseGrp6, + ParseGrp7, + ParseGrp8, + ParseGrp9, + ParseGrp10, + ParseGrp12, + ParseGrp13, + ParseGrp14, + ParseGrp15, + ParseGrp16, + ParseGrp17, + ParseModFence, + ParseYv, + ParseYb, + ParseXv, + ParseXb, + ParseEscFP, + ParseNopPause, + ParseImmByteSX, + ParseImmZ, + ParseThreeByteEsc4, + ParseThreeByteEsc5, + ParseImmAddrF, + ParseInvOpModRm, + ParseVex2b, + ParseVex3b, + ParseVexDest +}; + +/** Parser opcode table for only calculating instruction size. */ +static PFNDISPARSE const g_apfnCalcSize[IDX_ParseMax] = +{ + ParseIllegal, + ParseModRM_SizeOnly, + UseModRM, + ParseImmByte_SizeOnly, + ParseImmBRel_SizeOnly, + ParseImmUshort_SizeOnly, + ParseImmV_SizeOnly, + ParseImmVRel_SizeOnly, + ParseImmAddr_SizeOnly, + ParseFixedReg, + ParseImmUlong_SizeOnly, + ParseImmQword_SizeOnly, + ParseTwoByteEsc, + ParseGrp1, + ParseShiftGrp2, + ParseGrp3, + ParseGrp4, + ParseGrp5, + Parse3DNow, + ParseGrp6, + ParseGrp7, + ParseGrp8, + ParseGrp9, + ParseGrp10, + ParseGrp12, + ParseGrp13, + ParseGrp14, + ParseGrp15, + ParseGrp16, + ParseGrp17, + ParseModFence, + ParseYv, + ParseYb, + ParseXv, + ParseXb, + ParseEscFP, + ParseNopPause, + ParseImmByteSX_SizeOnly, + ParseImmZ_SizeOnly, + ParseThreeByteEsc4, + ParseThreeByteEsc5, + ParseImmAddrF_SizeOnly, + ParseInvOpModRm, + ParseVex2b, + ParseVex3b, + ParseVexDest +}; + + + + + +/******************************************************************************************************************************** + * + * + * Read functions for getting the opcode bytes + * + * + ********************************************************************************************************************************/ + +/** + * @interface_method_impl{FNDISREADBYTES, The default byte reader callber.} + */ +static DECLCALLBACK(int) disReadBytesDefault(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead) +{ +#if 0 /*def IN_RING0 - why? */ + RT_NOREF_PV(cbMinRead); + AssertMsgFailed(("disReadWord with no read callback in ring 0!!\n")); + RT_BZERO(&pDis->abInstr[offInstr], cbMaxRead); + pDis->cbCachedInstr = offInstr + cbMaxRead; + return VERR_DIS_NO_READ_CALLBACK; +#else + uint8_t const *pbSrc = (uint8_t const *)(uintptr_t)pDis->uInstrAddr + offInstr; + size_t cbLeftOnPage = (uintptr_t)pbSrc & PAGE_OFFSET_MASK; + uint8_t cbToRead = cbLeftOnPage >= cbMaxRead + ? cbMaxRead + : cbLeftOnPage <= cbMinRead + ? cbMinRead + : (uint8_t)cbLeftOnPage; + memcpy(&pDis->abInstr[offInstr], pbSrc, cbToRead); + pDis->cbCachedInstr = offInstr + cbToRead; + return VINF_SUCCESS; +#endif +} + + +/** + * Read more bytes into the DISSTATE::abInstr buffer, advance + * DISSTATE::cbCachedInstr. + * + * Will set DISSTATE::rc on failure, but still advance cbCachedInstr. + * + * The caller shall fend off reads beyond the DISSTATE::abInstr buffer. + * + * @param pDis The disassembler state. + * @param offInstr The offset of the read request. + * @param cbMin The size of the read request that needs to be + * satisfied. + */ +DECL_NO_INLINE(static, void) disReadMore(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMin) +{ + Assert(cbMin + offInstr <= sizeof(pDis->abInstr)); + + /* + * Adjust the incoming request to not overlap with bytes that has already + * been read and to make sure we don't leave unread gaps. + */ + if (offInstr < pDis->cbCachedInstr) + { + Assert(offInstr + cbMin > pDis->cbCachedInstr); + cbMin -= pDis->cbCachedInstr - offInstr; + offInstr = pDis->cbCachedInstr; + } + else if (offInstr > pDis->cbCachedInstr) + { + cbMin += offInstr - pDis->cbCachedInstr; + offInstr = pDis->cbCachedInstr; + } + + /* + * Do the read. + * (No need to zero anything on failure as abInstr is already zeroed by the + * DISInstrEx API.) + */ + int rc = pDis->pfnReadBytes(pDis, offInstr, cbMin, sizeof(pDis->abInstr) - offInstr); + if (RT_SUCCESS(rc)) + { + Assert(pDis->cbCachedInstr >= offInstr + cbMin); + Assert(pDis->cbCachedInstr <= sizeof(pDis->abInstr)); + } + else + { + Log(("disReadMore failed with rc=%Rrc!!\n", rc)); + pDis->rc = rc; + } +} + + +/** + * Function for handling a 8-bit cache miss. + * + * @returns The requested byte. + * @param pDis The disassembler state. + * @param offInstr The offset of the byte relative to the + * instruction. + */ +DECL_NO_INLINE(static, uint8_t) disReadByteSlow(PDISSTATE pDis, size_t offInstr) +{ + if (RT_LIKELY(offInstr < DIS_MAX_INSTR_LENGTH)) + { + disReadMore(pDis, (uint8_t)offInstr, 1); + return pDis->abInstr[offInstr]; + } + + Log(("disReadByte: too long instruction...\n")); + pDis->rc = VERR_DIS_TOO_LONG_INSTR; + ssize_t cbLeft = (ssize_t)(sizeof(pDis->abInstr) - offInstr); + if (cbLeft > 0) + return pDis->abInstr[offInstr]; + return 0; +} + + +/** + * 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 (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_LIKELY(offInstr + 2 <= DIS_MAX_INSTR_LENGTH)) + { + 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 + } + + Log(("disReadWord: too long instruction...\n")); + pDis->rc = VERR_DIS_TOO_LONG_INSTR; + ssize_t cbLeft = (ssize_t)(sizeof(pDis->abInstr) - offInstr); + switch (cbLeft) + { + case 1: + return pDis->abInstr[offInstr]; + default: + if (cbLeft >= 2) + return RT_MAKE_U16(pDis->abInstr[offInstr], pDis->abInstr[offInstr + 1]); + return 0; + } +} + + +/** + * 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 (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_LIKELY(offInstr + 4 <= DIS_MAX_INSTR_LENGTH)) + { + 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 + } + + Log(("disReadDWord: too long instruction...\n")); + pDis->rc = VERR_DIS_TOO_LONG_INSTR; + ssize_t cbLeft = (ssize_t)(sizeof(pDis->abInstr) - offInstr); + switch (cbLeft) + { + 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); + default: + if (cbLeft >= 4) + return RT_MAKE_U32_FROM_U8(pDis->abInstr[offInstr ], pDis->abInstr[offInstr + 1], + pDis->abInstr[offInstr + 2], pDis->abInstr[offInstr + 3]); + return 0; + } +} + + +/** + * 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 (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_LIKELY(offInstr + 8 <= DIS_MAX_INSTR_LENGTH)) + { + 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 + } + + Log(("disReadQWord: too long instruction...\n")); + pDis->rc = VERR_DIS_TOO_LONG_INSTR; + ssize_t cbLeft = (ssize_t)(sizeof(pDis->abInstr) - offInstr); + switch (cbLeft) + { + 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], + 0, 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], 0, 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], + 0, 0); + case 7: + 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); + default: + if (cbLeft >= 8) + 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]); + return 0; + } +} + + +/** + * 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 (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) +{ + 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. + */ + bool fFiltered; + if ((pOp->fOpType & pDis->fFilter) == 0) + { + fFiltered = true; + pDis->pfnDisasmFnTable = g_apfnCalcSize; + } + else + { + /* Not filtered out -> full disassembly */ + fFiltered = false; + 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; + pDis->Param4.fParam = pOp->fParam4; + + /* Correct the operand size if the instruction is marked as forced or default 64 bits */ + if (!(pOp->fOpType & (DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_FORCED_32_OP_SIZE_X86))) + { /* probably likely */ } + else + { + 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) + { + offInstr = pDis->pfnDisasmFnTable[pOp->idxParse1](offInstr, pOp, pDis, &pDis->Param1); + if (fFiltered == false) pDis->Param1.cb = DISGetParamSize(pDis, &pDis->Param1); + } + + if (pOp->idxParse2 != IDX_ParseNop) + { + offInstr = pDis->pfnDisasmFnTable[pOp->idxParse2](offInstr, pOp, pDis, &pDis->Param2); + if (fFiltered == false) pDis->Param2.cb = DISGetParamSize(pDis, &pDis->Param2); + } + + if (pOp->idxParse3 != IDX_ParseNop) + { + offInstr = pDis->pfnDisasmFnTable[pOp->idxParse3](offInstr, pOp, pDis, &pDis->Param3); + if (fFiltered == false) pDis->Param3.cb = DISGetParamSize(pDis, &pDis->Param3); + } + + if (pOp->idxParse4 != IDX_ParseNop) + { + offInstr = pDis->pfnDisasmFnTable[pOp->idxParse4](offInstr, pOp, pDis, &pDis->Param4); + if (fFiltered == false) pDis->Param4.cb = DISGetParamSize(pDis, &pDis->Param4); + } + // else simple one byte instruction + + return offInstr; +} +//***************************************************************************** +/* Floating point opcode parsing */ +//***************************************************************************** +static size_t ParseEscFP(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + PCDISOPCODE fpop; + RT_NOREF_PV(pOp); + + uint8_t ModRM = disReadByte(pDis, offInstr); + uint8_t 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 + || !(fpop->fOpType & (DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_DEFAULT_64_OP_SIZE))) + { /* probably likely */ } + else + { + /* 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) + offInstr++; //ModRM byte + + if (fpop->idxParse1 != IDX_ParseNop) + offInstr = pDis->pfnDisasmFnTable[fpop->idxParse1](offInstr, fpop, pDis, pParam); + + if (fpop->idxParse2 != IDX_ParseNop) + offInstr = pDis->pfnDisasmFnTable[fpop->idxParse2](offInstr, fpop, pDis, pParam); + + return offInstr; +} + + +/******************************************************************************************************************************** + * + * + * SIB byte: (not 16-bit mode) + * 7 - 6 5 - 3 2-0 + * Scale Index Base + * + * + ********************************************************************************************************************************/ +static void UseSIB(PDISSTATE pDis, PDISOPPARAM pParam) +{ + unsigned scale = pDis->SIB.Bits.Scale; + uint8_t base = pDis->SIB.Bits.Base; + uint8_t index = pDis->SIB.Bits.Index; + + unsigned regtype, vregtype; + /* There's no way to distinguish between SIB and VSIB + * and having special parameter to parse explicitly VSIB + * is not an options since only one instruction (gather) + * supports it currently. May be changed in the future. */ + if (pDis->uAddrMode == DISCPUMODE_32BIT) + regtype = DISUSE_REG_GEN32; + else + regtype = DISUSE_REG_GEN64; + if (pDis->pCurInstr->uOpcode == OP_GATHER) + vregtype = (VEXREG_IS256B(pDis->bVexDestReg) ? DISUSE_REG_YMM : DISUSE_REG_XMM); + else + vregtype = regtype; + + if (index != 4) + { + pParam->fUse |= DISUSE_INDEX | vregtype; + pParam->Index.idxGenReg = index; + + if (scale != 0) + { + pParam->fUse |= DISUSE_SCALE; + pParam->uScale = (uint8_t)(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, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + uint8_t SIB = disReadByte(pDis, offInstr); + 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 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 = (int32_t)disReadDWord(pDis, offInstr); + offInstr += 4; + } + return offInstr; +} + + +static size_t ParseSIB_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + uint8_t SIB = disReadByte(pDis, offInstr); + 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. */ + offInstr += 4; + } + return offInstr; +} + + + +/******************************************************************************************************************************** + * + * + * ModR/M byte: + * 7 - 6 5 - 3 2-0 + * Mod Reg/Opcode R/M + * + * + ********************************************************************************************************************************/ +static void disasmModRMReg(unsigned idx, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam, int fRegAddr) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pDis); + +#ifdef LOG_ENABLED + unsigned type = OP_PARM_VTYPE(pParam->fParam); +#endif + 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 || subtype == OP_PARM_y) + { + switch (pDis->uOpMode) + { + case DISCPUMODE_32BIT: + subtype = OP_PARM_d; + break; + case DISCPUMODE_64BIT: + subtype = OP_PARM_q; + break; + case DISCPUMODE_16BIT: + if (subtype != OP_PARM_y) /** @todo r=bird: This cannot be right! OP_PARM_y should translate to OP_PARM_d (32-bit), shouldn't it? */ + 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 = (uint8_t)idx; + break; + + case OP_PARM_w: + Assert(idx < (pDis->fPrefix & DISPREFIX_REX ? 16U : 8U)); + + pParam->fUse |= DISUSE_REG_GEN16; + pParam->Base.idxGenReg = (uint8_t)idx; + break; + + case OP_PARM_d: + Assert(idx < (pDis->fPrefix & DISPREFIX_REX ? 16U : 8U)); + + if ( !(pOp->fOpType & DISOPTYPE_DEFAULT_64_OP_SIZE) /* Tweak for vpmovmskb & pmovmskb. */ + || pDis->uOpMode != DISCPUMODE_64BIT) + pParam->fUse |= DISUSE_REG_GEN32; + else + pParam->fUse |= DISUSE_REG_GEN64; + pParam->Base.idxGenReg = (uint8_t)idx; + break; + + case OP_PARM_q: + pParam->fUse |= DISUSE_REG_GEN64; + pParam->Base.idxGenReg = (uint8_t)idx; + break; + + default: + Log(("disasmModRMReg %x:%x failed!!\n", type, subtype)); + pDis->rc = VERR_DIS_INVALID_MODRM; + break; + } +} + + +static void disasmModRMReg16(unsigned idx, PCDISOPCODE pOp, PDISSTATE pDis, 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 }; + + RT_NOREF_PV(pDis); RT_NOREF_PV(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(unsigned idx, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 = (uint8_t)idx; +} + + +static size_t UseModRM(size_t const offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + unsigned vtype = OP_PARM_VTYPE(pParam->fParam); + uint8_t reg = pDis->ModRM.Bits.Reg; + uint8_t mod = pDis->ModRM.Bits.Mod; + uint8_t rm = pDis->ModRM.Bits.Rm; + + switch (vtype) + { + case OP_PARM_G: //general purpose register + disasmModRMReg(reg, pOp, pDis, pParam, 0); + return offInstr; + + 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 offInstr; + + case OP_PARM_D: //debug register + pParam->fUse |= DISUSE_REG_DBG; + pParam->Base.idxDbgReg = reg; + return offInstr; + + case OP_PARM_Q: //MMX or memory operand + if (mod != 3) + break; /* memory operand */ + reg = rm; /* the RM field specifies the xmm register */ + RT_FALL_THRU(); + + case OP_PARM_P: //MMX register + reg &= 7; /* REX.R has no effect here */ + pParam->fUse |= DISUSE_REG_MMX; + pParam->Base.idxMmxReg = reg; + return offInstr; + + case OP_PARM_S: //segment register + reg &= 7; /* REX.R has no effect here */ + disasmModRMSReg(reg, pOp, pDis, pParam); + pParam->fUse |= DISUSE_REG_SEG; + return offInstr; + + case OP_PARM_T: //test register + reg &= 7; /* REX.R has no effect here */ + pParam->fUse |= DISUSE_REG_TEST; + pParam->Base.idxTestReg = reg; + return offInstr; + + case OP_PARM_W: //XMM register or memory operand + if (mod != 3) + break; /* memory operand */ + RT_FALL_THRU(); + + case OP_PARM_U: // XMM/YMM register + reg = rm; /* the RM field specifies the xmm register */ + RT_FALL_THRU(); + + case OP_PARM_V: //XMM register + if (VEXREG_IS256B(pDis->bVexDestReg) + && OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_dq + && OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_q + && OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_d + && OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_w) + { + // Use YMM register if VEX.L is set. + pParam->fUse |= DISUSE_REG_YMM; + pParam->Base.idxYmmReg = reg; + } + else + { + pParam->fUse |= DISUSE_REG_XMM; + pParam->Base.idxXmmReg = reg; + } + return offInstr; + } + } + } + + /** @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(pDis, pParam); + 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(rm, pOp, pDis, pParam, 1); + } + break; + + case 1: //effective address + 8 bits displacement + if (rm == 4) /* SIB byte follows ModRM */ + UseSIB(pDis, pParam); + else + { + pParam->fUse |= DISUSE_BASE; + disasmModRMReg(rm, pOp, pDis, 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(pDis, pParam); + else + { + pParam->fUse |= DISUSE_BASE; + disasmModRMReg(rm, pOp, pDis, pParam, 1); + } + pParam->uDisp.i32 = pDis->i32SibDisp; + pParam->fUse |= DISUSE_DISPLACEMENT32; + break; + + case 3: //registers + disasmModRMReg(rm, pOp, pDis, 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(rm, pOp, pDis, pParam); + } + break; + + case 1: //effective address + 8 bits displacement + disasmModRMReg16(rm, pOp, pDis, pParam); + pParam->uDisp.i8 = pDis->i32SibDisp; + pParam->fUse |= DISUSE_BASE | DISUSE_DISPLACEMENT8; + break; + + case 2: //effective address + 16 bits displacement + disasmModRMReg16(rm, pOp, pDis, pParam); + pParam->uDisp.i16 = pDis->i32SibDisp; + pParam->fUse |= DISUSE_BASE | DISUSE_DISPLACEMENT16; + break; + + case 3: //registers + disasmModRMReg(rm, pOp, pDis, pParam, 0); + break; + } + } + return offInstr; +} +//***************************************************************************** +// Query the size of the ModRM parameters and fetch the immediate data (if any) +//***************************************************************************** +static size_t QueryModRM(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + uint8_t mod = pDis->ModRM.Bits.Mod; + uint8_t rm = pDis->ModRM.Bits.Rm; + + 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 */ + offInstr = ParseSIB(offInstr, pOp, pDis, pParam); + + switch (mod) + { + case 0: /* Effective address */ + if (rm == 5) /* 32 bits displacement */ + { + pDis->i32SibDisp = (int32_t)disReadDWord(pDis, offInstr); + offInstr += 4; + } + /* else register address */ + break; + + case 1: /* Effective address + 8 bits displacement */ + pDis->i32SibDisp = (int8_t)disReadByte(pDis, offInstr); + offInstr++; + break; + + case 2: /* Effective address + 32 bits displacement */ + pDis->i32SibDisp = (int32_t)disReadDWord(pDis, offInstr); + offInstr += 4; + break; + + case 3: /* registers */ + break; + } + } + else + { + /* 16 bits mode */ + switch (mod) + { + case 0: /* Effective address */ + if (rm == 6) + { + pDis->i32SibDisp = disReadWord(pDis, offInstr); + offInstr += 2; + } + /* else register address */ + break; + + case 1: /* Effective address + 8 bits displacement */ + pDis->i32SibDisp = (int8_t)disReadByte(pDis, offInstr); + offInstr++; + break; + + case 2: /* Effective address + 32 bits displacement */ + pDis->i32SibDisp = (int16_t)disReadWord(pDis, offInstr); + offInstr += 2; + break; + + case 3: /* registers */ + break; + } + } + return offInstr; +} +//***************************************************************************** +// Parse the ModRM parameters and fetch the immediate data (if any) +//***************************************************************************** +static size_t QueryModRM_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + uint8_t mod = pDis->ModRM.Bits.Mod; + uint8_t rm = pDis->ModRM.Bits.Rm; + + 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 */ + offInstr = ParseSIB_SizeOnly(offInstr, pOp, pDis, pParam); + } + + switch (mod) + { + case 0: //effective address + if (rm == 5) /* 32 bits displacement */ + offInstr += 4; + /* else register address */ + break; + + case 1: /* Effective address + 8 bits displacement */ + offInstr += 1; + break; + + case 2: /* Effective address + 32 bits displacement */ + offInstr += 4; + break; + + case 3: /* registers */ + break; + } + } + else + { + /* 16 bits mode */ + switch (mod) + { + case 0: //effective address + if (rm == 6) + offInstr += 2; + /* else register address */ + break; + + case 1: /* Effective address + 8 bits displacement */ + offInstr++; + break; + + case 2: /* Effective address + 32 bits displacement */ + offInstr += 2; + break; + + case 3: /* registers */ + break; + } + } + return offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseIllegal(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + AssertFailed(); + return offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseModRM(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + uint8_t ModRM = disReadByte(pDis, offInstr); + offInstr++; + + 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); + } + } + offInstr = QueryModRM(offInstr, pOp, pDis, pParam); + + return UseModRM(offInstr, pOp, pDis, pParam); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseModRM_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + uint8_t ModRM = disReadByte(pDis, offInstr); + offInstr++; + + 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); + } + } + + offInstr = QueryModRM_SizeOnly(offInstr, pOp, pDis, pParam); + + /* UseModRM is not necessary here; we're only interested in the opcode size */ + return offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseModFence(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + /* Note! Only used in group 15, so we must account for the mod/rm byte. */ + return offInstr + 1; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmByte(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + uint8_t byte = disReadByte(pDis, offInstr); + if (pParam->fParam == OP_PARM_Lx) + { + pParam->fUse |= (VEXREG_IS256B(pDis->bVexDestReg) ? DISUSE_REG_YMM : DISUSE_REG_XMM); + + // Ignore MSB in 32-bit mode. + if (pDis->uCpuMode == DISCPUMODE_32BIT) + byte &= 0x7f; + + pParam->Base.idxXmmReg = byte >> 4; + } + else + { + pParam->uValue = byte; + pParam->fUse |= DISUSE_IMMEDIATE8; + pParam->cb = sizeof(uint8_t); + } + return offInstr + 1; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmByte_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + return offInstr + 1; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmByteSX(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 offInstr + 1; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmByteSX_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + return offInstr + 1; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmUshort(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + pParam->uValue = disReadWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE16; + pParam->cb = sizeof(uint16_t); + return offInstr + 2; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmUshort_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + return offInstr + 2; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmUlong(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + pParam->uValue = disReadDWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE32; + pParam->cb = sizeof(uint32_t); + return offInstr + 4; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmUlong_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + return offInstr + 4; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmQword(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + pParam->uValue = disReadQWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE64; + pParam->cb = sizeof(uint64_t); + return offInstr + 8; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmQword_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + return offInstr + 8; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmV(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + if (pDis->uOpMode == DISCPUMODE_32BIT) + { + pParam->uValue = disReadDWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE32; + pParam->cb = sizeof(uint32_t); + return offInstr + 4; + } + + if (pDis->uOpMode == DISCPUMODE_64BIT) + { + pParam->uValue = disReadQWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE64; + pParam->cb = sizeof(uint64_t); + return offInstr + 8; + } + + pParam->uValue = disReadWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE16; + pParam->cb = sizeof(uint16_t); + return offInstr + 2; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmV_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + if (pDis->uOpMode == DISCPUMODE_32BIT) + return offInstr + 4; + if (pDis->uOpMode == DISCPUMODE_64BIT) + return offInstr + 8; + return offInstr + 2; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmZ(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 offInstr + 2; + } + + /* 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 offInstr + 4; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmZ_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + /* Word for 16-bit operand-size or doubleword for 32 or 64-bit operand-size. */ + if (pDis->uOpMode == DISCPUMODE_16BIT) + return offInstr + 2; + return offInstr + 4; +} + +//***************************************************************************** +// Relative displacement for branches (rel. to next instruction) +//***************************************************************************** +static size_t ParseImmBRel(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + pParam->uValue = disReadByte(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE8_REL; + pParam->cb = sizeof(uint8_t); + return offInstr + 1; +} +//***************************************************************************** +// Relative displacement for branches (rel. to next instruction) +//***************************************************************************** +static size_t ParseImmBRel_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); RT_NOREF_PV(pDis); + return offInstr + 1; +} +//***************************************************************************** +// Relative displacement for branches (rel. to next instruction) +//***************************************************************************** +static size_t ParseImmVRel(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + if (pDis->uOpMode == DISCPUMODE_32BIT) + { + pParam->uValue = disReadDWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE32_REL; + pParam->cb = sizeof(int32_t); + return offInstr + 4; + } + + 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 offInstr + 4; + } + + pParam->uValue = disReadWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE16_REL; + pParam->cb = sizeof(int16_t); + return offInstr + 2; +} +//***************************************************************************** +// Relative displacement for branches (rel. to next instruction) +//***************************************************************************** +static size_t ParseImmVRel_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + if (pDis->uOpMode == DISCPUMODE_16BIT) + return offInstr + 2; + /* Both 32 & 64 bits mode use 32 bits relative immediates. */ + return offInstr + 4; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmAddr(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + 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 offInstr + 4 + 2; + } + + /* + * 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.u32 = disReadDWord(pDis, offInstr); + pParam->fUse |= DISUSE_DISPLACEMENT32; + pParam->cb = sizeof(uint32_t); + return offInstr + 4; + } + + if (pDis->uAddrMode == DISCPUMODE_64BIT) + { + /* + * 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. + */ + Assert(OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_p); + pParam->uDisp.u64 = disReadQWord(pDis, offInstr); + pParam->fUse |= DISUSE_DISPLACEMENT64; + pParam->cb = sizeof(uint64_t); + return offInstr + 8; + } + 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 offInstr + 4; + } + + /* + * 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 offInstr + 2; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmAddr_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(pOp); + if (pDis->uAddrMode == DISCPUMODE_32BIT) + { + if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p) + return offInstr + 4 + 2; /* far 16:32 pointer */ + return offInstr + 4; /* near 32 bits pointer */ + } + if (pDis->uAddrMode == DISCPUMODE_64BIT) + { + Assert(OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_p); + return offInstr + 8; + } + if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p) + return offInstr + 4; /* far 16:16 pointer */ + return offInstr + 2; /* near 16 bits pointer */ +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmAddrF(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + // 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 offInstr + 4 + 2; + } + + // far 16:16 pointer + pParam->uValue = disReadDWord(pDis, offInstr); + pParam->fUse |= DISUSE_IMMEDIATE_ADDR_16_16; + pParam->cb = 2*sizeof(uint16_t); + return offInstr + 2 + 2; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseImmAddrF_SizeOnly(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); RT_NOREF_PV(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); RT_NOREF_PV(pParam); + if (pDis->uOpMode == DISCPUMODE_32BIT) + return offInstr + 4 + 2; /* far 16:32 pointer */ + return offInstr + 2 + 2; /* far 16:16 pointer */ +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseFixedReg(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(offInstr); + + /* + * Sets up flags for stored in OPC fixed registers. + */ + + if (pParam->fParam == OP_PARM_NONE) + { + /* No parameter at all. */ + return offInstr; + } + + 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 = (uint8_t)(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 = (uint8_t)(pParam->fParam - OP_PARM_REG_GEN32_START); + pParam->fUse |= DISUSE_REG_GEN64; + pParam->cb = 8; + } + else + { + /* Use 16-bit registers. */ + pParam->Base.idxGenReg = (uint8_t)(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; + } + + 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_B)) + { + Assert(pDis->uCpuMode == DISCPUMODE_64BIT); + pParam->Base.idxGenReg += 8; + } + } + else if (pParam->fParam <= OP_PARM_REG_SEG_END) + { + /* Segment ES..GS registers. */ + pParam->Base.idxSegReg = (uint8_t)(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 = (uint8_t)(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 = (uint8_t)(pParam->fParam - OP_PARM_REG_GEN8_START); + pParam->fUse |= DISUSE_REG_GEN8; + pParam->cb = 1; + + if ( pDis->uCpuMode == DISCPUMODE_64BIT + && (pOp->fOpType & DISOPTYPE_REXB_EXTENDS_OPREG) + && pParam == &pDis->Param1 /* ugly assumption that it only applies to the first parameter */ + && (pDis->fPrefix & DISPREFIX_REX)) + { + if (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_B) + pParam->Base.idxGenReg += 8; /* least significant byte of R8-R15 */ + else if ( pParam->Base.idxGenReg >= DISGREG_AH + && pParam->Base.idxGenReg <= DISGREG_BH) + pParam->Base.idxGenReg += DISGREG_SPL - DISGREG_AH; + } + } + else if (pParam->fParam <= OP_PARM_REG_FP_END) + { + /* FPU registers. */ + pParam->Base.idxFpuReg = (uint8_t)(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 offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseXv(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseXb(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseYv(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseYb(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(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 offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseInvOpModRm(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pDis); RT_NOREF_PV(pParam); + /* This is used to avoid a bunch of special hacks to get the ModRM byte + included when encountering invalid opcodes in groups. */ + return offInstr + 1; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseVexDest(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); + + unsigned type = OP_PARM_VTYPE(pParam->fParam); + switch (type) + { + case OP_PARM_H: //XMM or YMM register + if (VEXREG_IS256B(pDis->bVexDestReg)) + { + pParam->fUse |= DISUSE_REG_YMM; + pParam->Base.idxYmmReg = (pDis->bVexDestReg >> 1) ^ 0xf; + } + else + { + pParam->fUse |= DISUSE_REG_XMM; + pParam->Base.idxXmmReg = (pDis->bVexDestReg >> 1) ^ 0xf; + } + break; + + case OP_PARM_B: // Always OP_PARM_By. Change if it is not so. + if (pDis->bVexWFlag && pDis->uCpuMode == DISCPUMODE_64BIT) + pParam->fUse |= DISUSE_REG_GEN64; + else + pParam->fUse |= DISUSE_REG_GEN32; + /// @todo Check if the register number is correct + pParam->Base.idxGenReg = (pDis->bVexDestReg >> 1) ^ 0xf; + break; + } + + return offInstr; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseTwoByteEsc(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + /* 2nd byte */ + pDis->bOpCode = disReadByte(pDis, offInstr); + offInstr++; + + /* default to the non-prefixed table. */ + PCDISOPCODE pOpcode = &g_aTwoByteMapX86[pDis->bOpCode]; + + /* Handle opcode table extensions that rely on the opsize, 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; + + if (pDis->uCpuMode == DISCPUMODE_64BIT) + { + pDis->uOpMode = (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_W ? DISCPUMODE_64BIT : DISCPUMODE_32BIT); + } + else + 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; + } + } + + return disParseInstruction(offInstr, pOpcode, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseThreeByteEsc4(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + /* 3rd byte */ + pDis->bOpCode = disReadByte(pDis, offInstr); + offInstr++; + + /* default to the non-prefixed table. */ + PCDISOPCODE pOpcode; + 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; + if (pDis->uCpuMode == DISCPUMODE_64BIT) + { + pDis->uOpMode = (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_W ? DISCPUMODE_64BIT : DISCPUMODE_32BIT); + } + else + pDis->uOpMode = pDis->uCpuMode; + + } + } + break; + + case OP_REPNE: /* 0xF2 */ + if ((pDis->fPrefix & DISPREFIX_OPSIZE) && g_apThreeByteMapX86_66F20F38[pDis->bOpCode >> 4]) + { + /* 0x66F2 */ + pOpcode = g_apThreeByteMapX86_66F20F38[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; + pDis->fPrefix &= ~DISPREFIX_OPSIZE; + if (pDis->uCpuMode == DISCPUMODE_64BIT) + { + pDis->uOpMode = (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_W ? DISCPUMODE_64BIT : DISCPUMODE_32BIT); + } + else + pDis->uOpMode = pDis->uCpuMode; + } + } + else 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; + + case OP_REPE: /* 0xF3 */ + if (g_apThreeByteMapX86_F30F38[pDis->bOpCode >> 4]) + { + pOpcode = g_apThreeByteMapX86_F30F38[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_REP; + } + } + } + + return disParseInstruction(offInstr, pOpcode, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseThreeByteEsc5(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + /* 3rd byte */ + pDis->bOpCode = disReadByte(pDis, offInstr); + offInstr++; + + /* default to the non-prefixed table. */ + PCDISOPCODE pOpcode; + if (g_apThreeByteMapX86_0F3A[pDis->bOpCode >> 4]) + { + pOpcode = g_apThreeByteMapX86_0F3A[pDis->bOpCode >> 4]; + pOpcode = &pOpcode[pDis->bOpCode & 0xf]; + } + else + pOpcode = &g_InvalidOpcode[0]; + + /** @todo Should we take the first or last prefix byte in case of multiple prefix bytes??? */ + if (pDis->bLastPrefix == OP_OPSIZE && 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; + if (pDis->uCpuMode == DISCPUMODE_64BIT) + { + pDis->uOpMode = (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_W ? DISCPUMODE_64BIT : DISCPUMODE_32BIT); + } + else + pDis->uOpMode = pDis->uCpuMode; + + } + } + + return disParseInstruction(offInstr, pOpcode, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseNopPause(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + if (pDis->fPrefix & DISPREFIX_REP) + { + pOp = &g_aMapX86_NopPause[1]; /* PAUSE */ + pDis->fPrefix &= ~DISPREFIX_REP; + } + else + pOp = &g_aMapX86_NopPause[0]; /* NOP */ + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp1(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + unsigned idx = (pDis->bOpCode - 0x80) * 8; + + pOp = &g_aMapX86_Group1[idx+reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseShiftGrp2(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + unsigned idx; + 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: + Log(("ParseShiftGrp2: bOpCode=%#x\n", pDis->bOpCode)); + pDis->rc = VERR_DIS_INVALID_OPCODE; + return offInstr; + } + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group2[idx+reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp3(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + unsigned idx = (pDis->bOpCode - 0xF6) * 8; + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group3[idx+reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp4(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group4[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp5(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group5[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +// 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, PDISSTATE pDis, PDISOPPARAM pParam) +{ + /** @todo This code needs testing! Esp. wrt invalid opcodes. */ + + uint8_t 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 offRet = QueryModRM(offInstr + 1, pOp, pDis, pParam); + + uint8_t opcode = disReadByte(pDis, offRet); + offRet++; + pOp = &g_aTwoByteMapX86_3DNow[opcode]; + + size_t offStrict = disParseInstruction(offInstr, pOp, pDis); + + AssertMsg(offStrict == offRet - 1 /* the imm8_opcode */ || pOp->uOpcode == OP_INVALID, + ("offStrict=%#x offRet=%#x uOpCode=%u\n", offStrict, offRet, pOp->uOpcode)); + RT_NOREF_PV(offStrict); + + return offRet; +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp6(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group6[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp7(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t mod = MODRM_MOD(modrm); + uint8_t reg = MODRM_REG(modrm); + uint8_t 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]; + + /* Cannot easily skip this hack because of monitor and vmcall! */ + //little hack to make sure the ModRM byte is included in the returned size + if (pOp->idxParse1 != IDX_ParseModRM && pOp->idxParse2 != IDX_ParseModRM) + offInstr++; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp8(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group8[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp9(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group9[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp10(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + pOp = &g_aMapX86_Group10[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp12(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + + if (pDis->fPrefix & DISPREFIX_OPSIZE) + reg += 8; /* 2nd table */ + + pOp = &g_aMapX86_Group12[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp13(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + if (pDis->fPrefix & DISPREFIX_OPSIZE) + reg += 8; /* 2nd table */ + + pOp = &g_aMapX86_Group13[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp14(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t reg = MODRM_REG(modrm); + if (pDis->fPrefix & DISPREFIX_OPSIZE) + reg += 8; /* 2nd table */ + + pOp = &g_aMapX86_Group14[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp15(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + uint8_t mod = MODRM_MOD(modrm); + uint8_t reg = MODRM_REG(modrm); + uint8_t rm = MODRM_RM(modrm); + + if (mod == 3 && rm == 0) + pOp = &g_aMapX86_Group15_mod11_rm000[reg]; + else + pOp = &g_aMapX86_Group15_mem[reg]; + + return disParseInstruction(offInstr, pOp, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseGrp16(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t modrm = disReadByte(pDis, offInstr); + pOp = &g_aMapX86_Group16[MODRM_REG(modrm)]; + + return disParseInstruction(offInstr, pOp, pDis); +} + + +/** + * Parses (vex) group 17. + */ +static size_t ParseGrp17(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pParam); + + uint8_t const bRm = disReadByte(pDis, offInstr); + pOp = &g_aMapX86_Group17[(MODRM_REG(bRm) << 1) | (pDis->bVexDestReg & 1)]; + + return disParseInstruction(offInstr, pOp, pDis); +} + + +//***************************************************************************** +//***************************************************************************** +static size_t ParseVex2b(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + uint8_t byte = disReadByte(pDis, offInstr++); + pDis->bOpCode = disReadByte(pDis, offInstr++); + + pDis->bVexDestReg = VEX_2B2INT(byte); + + // VEX.R (equivalent to REX.R) + if (pDis->uCpuMode == DISCPUMODE_64BIT && !(byte & 0x80)) + { + /* REX prefix byte */ + pDis->fPrefix |= DISPREFIX_REX; + pDis->fRexPrefix = DISPREFIX_REX_FLAGS_R; + } + + PCDISOPMAPDESC const pRange = g_aapVexOpcodesMapRanges[byte & 3][1]; + unsigned const idxOpcode = pDis->bOpCode - pRange->idxFirst; + PCDISOPCODE pOpCode; + if (idxOpcode < pRange->cOpcodes) + pOpCode = &pRange->papOpcodes[idxOpcode]; + else + pOpCode = &g_InvalidOpcode[0]; + + return disParseInstruction(offInstr, pOpCode, pDis); +} +//***************************************************************************** +//***************************************************************************** +static size_t ParseVex3b(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam) +{ + RT_NOREF_PV(pOp); RT_NOREF_PV(pParam); + + uint8_t byte1 = disReadByte(pDis, offInstr++); + uint8_t byte2 = disReadByte(pDis, offInstr++); + pDis->bOpCode = disReadByte(pDis, offInstr++); + pDis->bVexDestReg = VEX_2B2INT(byte2); /** @todo r=bird: why on earth ~vvvv + L; this is obfuscation non-sense. Either split the shit up or just store byte2 raw here! */ + + // VEX.W + pDis->bVexWFlag = !!(byte2 & 0x80); /** @todo r=bird: why a whole byte for this one flag? bVexWFlag and bVexDestReg makes little sense. */ + + /* Hack alert! Assume VEX.W rules over any 66h prefix and that no VEX + encoded instructions ever uses the regular uOpMode w/o VEX.W. */ + pDis->uOpMode = (byte2 & 0x80) && pDis->uCpuMode == DISCPUMODE_64BIT ? DISCPUMODE_64BIT : DISCPUMODE_32BIT; + + // VEX.~R~X~B => REX.RXB + if (pDis->uCpuMode == DISCPUMODE_64BIT) + { + pDis->fRexPrefix |= (byte1 >> 5) ^ 7; + if (pDis->fRexPrefix) + pDis->fPrefix |= DISPREFIX_REX; + } + + PCDISOPCODE pOpCode; + uint8_t const idxVexMap = byte1 & 0x1f; + if (idxVexMap < RT_ELEMENTS(g_aapVexOpcodesMapRanges[byte2 & 3])) + { + PCDISOPMAPDESC const pRange = g_aapVexOpcodesMapRanges[byte2 & 3][idxVexMap]; + unsigned const idxOpcode = pDis->bOpCode - pRange->idxFirst; + if (idxOpcode < pRange->cOpcodes) + pOpCode = &pRange->papOpcodes[idxOpcode]; + else + pOpCode = &g_InvalidOpcode[0]; + } + else + pOpCode = &g_InvalidOpcode[0]; + + return disParseInstruction(offInstr, pOpCode, pDis); +} + + +/** + * 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 DISInstrEx and DISInstrWithPrefetchedBytes. + * + * @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 const bCode = disReadByte(pDis, offInstr++); + enum OPCODES const enmOpcode = (enum OPCODES)paOneByteMap[bCode].uOpcode; + + /* Hardcoded assumption about OP_* values!! */ + if (enmOpcode <= OP_LAST_PREFIX) + { + /* The REX prefix must precede the opcode byte(s). Any other placement is ignored. */ + if (enmOpcode != OP_REX) + { + /* Last prefix byte (for SSE2 extension tables); don't include the REX prefix */ + pDis->bLastPrefix = (uint8_t)enmOpcode; + pDis->fPrefix &= ~DISPREFIX_REX; + } + + switch (enmOpcode) + { + 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 = (uint8_t)(paOneByteMap[bCode].fParam1 - OP_PARM_REG_SEG_START); +#if 0 /* Try be accurate in our reporting, shouldn't break anything... :-) */ + /* 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; +#else + pDis->fPrefix |= DISPREFIX_SEG; +#endif + 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 = (uint8_t)DISPREFIX_REX_OP_2_FLAGS(paOneByteMap[bCode].fParam1); + if (pDis->fRexPrefix & DISPREFIX_REX_FLAGS_W) + pDis->uOpMode = DISCPUMODE_64BIT; /* overrides size prefix byte */ + continue; //fetch the next byte + default: + AssertFailed(); + break; + } + } + + /* Check if this is a VEX prefix. Not for 32-bit mode. */ + if (pDis->uCpuMode != DISCPUMODE_64BIT + && (enmOpcode == OP_LES || enmOpcode == OP_LDS) + && (disReadByte(pDis, offInstr) & 0xc0) == 0xc0) + { + paOneByteMap = g_aOneByteMapX64; + } + + /* first opcode byte. */ + pDis->bOpCode = bCode; + pDis->cbPrefix = (uint8_t)offInstr - 1; + + offInstr = disParseInstruction(offInstr, &paOneByteMap[bCode], 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 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 = (uint8_t)enmCpuMode; + PCDISOPCODE paOneByteMap; + if (enmCpuMode == DISCPUMODE_64BIT) + { + pDis->uAddrMode = DISCPUMODE_64BIT; + pDis->uOpMode = DISCPUMODE_32BIT; + paOneByteMap = g_aOneByteMapX64; + } + else + { + pDis->uAddrMode = (uint8_t)enmCpuMode; + pDis->uOpMode = (uint8_t)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 = rc; + } +} + + +/** + * 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) DISInstrEx(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) DISInstrWithPrefetchedBytes(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 DISInstrEx(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 DISInstrEx((uintptr_t)pvInstr, enmCpuMode, DISOPTYPE_ALL, NULL /*pfnReadBytes*/, NULL /*pvUser*/, pDis, pcbInstr); +} + diff --git a/src/VBox/Disassembler/DisasmFormatBytes.cpp b/src/VBox/Disassembler/DisasmFormatBytes.cpp new file mode 100644 index 00000000..f012d15b --- /dev/null +++ b/src/VBox/Disassembler/DisasmFormatBytes.cpp @@ -0,0 +1,97 @@ +/* $Id: DisasmFormatBytes.cpp $ */ +/** @file + * VBox Disassembler - Helper for formatting the opcode bytes. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include "DisasmInternal.h" +#include <iprt/string.h> +#include <iprt/assert.h> +#include <iprt/errcore.h> + + +/** + * Helper function for formatting the opcode bytes. + * + * @returns The number of output bytes. + * + * @param pDis Pointer to the disassembler state. + * @param pszDst The output buffer. + * @param cchDst The size of the output buffer. + * @param fFlags The flags passed to the formatter. + */ +size_t disFormatBytes(PCDISSTATE pDis, char *pszDst, size_t cchDst, uint32_t fFlags) +{ + size_t cchOutput = 0; + uint32_t cb = pDis->cbInstr; + AssertStmt(cb <= 16, cb = 16); + +#define PUT_C(ch) \ + do { \ + cchOutput++; \ + if (cchDst > 1) \ + { \ + cchDst--; \ + *pszDst++ = (ch); \ + } \ + } while (0) +#define PUT_NUM(cch, fmt, num) \ + do { \ + cchOutput += (cch); \ + if (cchDst > 1) \ + { \ + const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \ + pszDst += cchTmp; \ + cchDst -= cchTmp; \ + } \ + } while (0) + + + if (fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) + PUT_C('['); + + for (uint32_t i = 0; i < cb; i++) + { + if (i != 0 && (fFlags & DIS_FMT_FLAGS_BYTES_SPACED)) + PUT_NUM(3, " %02x", pDis->abInstr[i]); + else + PUT_NUM(2, "%02x", pDis->abInstr[i]); + } + + if (fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) + PUT_C(']'); + + /* Terminate it just in case. */ + if (cchDst >= 1) + *pszDst = '\0'; + +#undef PUT_C +#undef PUT_NUM + return cchOutput; +} + diff --git a/src/VBox/Disassembler/DisasmFormatYasm.cpp b/src/VBox/Disassembler/DisasmFormatYasm.cpp new file mode 100644 index 00000000..4be9e043 --- /dev/null +++ b/src/VBox/Disassembler/DisasmFormatYasm.cpp @@ -0,0 +1,1765 @@ +/* $Id: DisasmFormatYasm.cpp $ */ +/** @file + * VBox Disassembler - Yasm(/Nasm) Style Formatter. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/dis.h> +#include "DisasmInternal.h" +#include <iprt/assert.h> +#include <iprt/ctype.h> +#include <iprt/err.h> +#include <iprt/string.h> + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +static const char g_szSpaces[] = +" "; +static const char g_aszYasmRegGen8[20][5] = +{ + "al\0\0", "cl\0\0", "dl\0\0", "bl\0\0", "ah\0\0", "ch\0\0", "dh\0\0", "bh\0\0", "r8b\0", "r9b\0", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b", "spl\0", "bpl\0", "sil\0", "dil\0" +}; +static const char g_aszYasmRegGen16[16][5] = +{ + "ax\0\0", "cx\0\0", "dx\0\0", "bx\0\0", "sp\0\0", "bp\0\0", "si\0\0", "di\0\0", "r8w\0", "r9w\0", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" +}; +#if 0 /* unused */ +static const char g_aszYasmRegGen1616[8][6] = +{ + "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0" +}; +#endif +static const char g_aszYasmRegGen32[16][5] = +{ + "eax\0", "ecx\0", "edx\0", "ebx\0", "esp\0", "ebp\0", "esi\0", "edi\0", "r8d\0", "r9d\0", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" +}; +static const char g_aszYasmRegGen64[16][4] = +{ + "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8\0", "r9\0", "r10", "r11", "r12", "r13", "r14", "r15" +}; +static const char g_aszYasmRegSeg[6][3] = +{ + "es", "cs", "ss", "ds", "fs", "gs" +}; +static const char g_aszYasmRegFP[8][4] = +{ + "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7" +}; +static const char g_aszYasmRegMMX[8][4] = +{ + "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" +}; +static const char g_aszYasmRegXMM[16][6] = +{ + "xmm0\0", "xmm1\0", "xmm2\0", "xmm3\0", "xmm4\0", "xmm5\0", "xmm6\0", "xmm7\0", "xmm8\0", "xmm9\0", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" +}; +static const char g_aszYasmRegYMM[16][6] = +{ + "ymm0\0", "ymm1\0", "ymm2\0", "ymm3\0", "ymm4\0", "ymm5\0", "ymm6\0", "ymm7\0", "ymm8\0", "ymm9\0", "ymm10", "ymm11", "ymm12", "ymm13", "ymm14", "ymm15" +}; +static const char g_aszYasmRegCRx[16][5] = +{ + "cr0\0", "cr1\0", "cr2\0", "cr3\0", "cr4\0", "cr5\0", "cr6\0", "cr7\0", "cr8\0", "cr9\0", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15" +}; +static const char g_aszYasmRegDRx[16][5] = +{ + "dr0\0", "dr1\0", "dr2\0", "dr3\0", "dr4\0", "dr5\0", "dr6\0", "dr7\0", "dr8\0", "dr9\0", "dr10", "dr11", "dr12", "dr13", "dr14", "dr15" +}; +static const char g_aszYasmRegTRx[16][5] = +{ + "tr0\0", "tr1\0", "tr2\0", "tr3\0", "tr4\0", "tr5\0", "tr6\0", "tr7\0", "tr8\0", "tr9\0", "tr10", "tr11", "tr12", "tr13", "tr14", "tr15" +}; + + + +/** + * Gets the base register name for the given parameter. + * + * @returns Pointer to the register name. + * @param pDis The disassembler state. + * @param pParam The parameter. + * @param pcchReg Where to store the length of the name. + */ +static const char *disasmFormatYasmBaseReg(PCDISSTATE pDis, PCDISOPPARAM pParam, size_t *pcchReg) +{ + RT_NOREF_PV(pDis); + + switch (pParam->fUse & ( DISUSE_REG_GEN8 | DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64 + | DISUSE_REG_FP | DISUSE_REG_MMX | DISUSE_REG_XMM | DISUSE_REG_YMM + | DISUSE_REG_CR | DISUSE_REG_DBG | DISUSE_REG_SEG | DISUSE_REG_TEST)) + + { + case DISUSE_REG_GEN8: + { + Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen8)); + const char *psz = g_aszYasmRegGen8[pParam->Base.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + case DISUSE_REG_GEN16: + { + Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen16)); + const char *psz = g_aszYasmRegGen16[pParam->Base.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + // VSIB + case DISUSE_REG_XMM | DISUSE_REG_GEN32: + case DISUSE_REG_YMM | DISUSE_REG_GEN32: + case DISUSE_REG_GEN32: + { + Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen32)); + const char *psz = g_aszYasmRegGen32[pParam->Base.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + // VSIB + case DISUSE_REG_XMM | DISUSE_REG_GEN64: + case DISUSE_REG_YMM | DISUSE_REG_GEN64: + case DISUSE_REG_GEN64: + { + Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen64)); + const char *psz = g_aszYasmRegGen64[pParam->Base.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + case DISUSE_REG_FP: + { + Assert(pParam->Base.idxFpuReg < RT_ELEMENTS(g_aszYasmRegFP)); + const char *psz = g_aszYasmRegFP[pParam->Base.idxFpuReg]; + *pcchReg = 3; + return psz; + } + + case DISUSE_REG_MMX: + { + Assert(pParam->Base.idxMmxReg < RT_ELEMENTS(g_aszYasmRegMMX)); + const char *psz = g_aszYasmRegMMX[pParam->Base.idxMmxReg]; + *pcchReg = 3; + return psz; + } + + case DISUSE_REG_XMM: + { + Assert(pParam->Base.idxXmmReg < RT_ELEMENTS(g_aszYasmRegXMM)); + const char *psz = g_aszYasmRegXMM[pParam->Base.idxXmmReg]; + *pcchReg = 4 + !!psz[4]; + return psz; + } + + case DISUSE_REG_YMM: + { + Assert(pParam->Base.idxYmmReg < RT_ELEMENTS(g_aszYasmRegYMM)); + const char *psz = g_aszYasmRegYMM[pParam->Base.idxYmmReg]; + *pcchReg = 4 + !!psz[4]; + return psz; + } + + case DISUSE_REG_CR: + { + Assert(pParam->Base.idxCtrlReg < RT_ELEMENTS(g_aszYasmRegCRx)); + const char *psz = g_aszYasmRegCRx[pParam->Base.idxCtrlReg]; + *pcchReg = 3; + return psz; + } + + case DISUSE_REG_DBG: + { + Assert(pParam->Base.idxDbgReg < RT_ELEMENTS(g_aszYasmRegDRx)); + const char *psz = g_aszYasmRegDRx[pParam->Base.idxDbgReg]; + *pcchReg = 3; + return psz; + } + + case DISUSE_REG_SEG: + { + Assert(pParam->Base.idxSegReg < RT_ELEMENTS(g_aszYasmRegCRx)); + const char *psz = g_aszYasmRegSeg[pParam->Base.idxSegReg]; + *pcchReg = 2; + return psz; + } + + case DISUSE_REG_TEST: + { + Assert(pParam->Base.idxTestReg < RT_ELEMENTS(g_aszYasmRegTRx)); + const char *psz = g_aszYasmRegTRx[pParam->Base.idxTestReg]; + *pcchReg = 3; + return psz; + } + + default: + AssertMsgFailed(("%#x\n", pParam->fUse)); + *pcchReg = 3; + return "r??"; + } +} + + +/** + * Gets the index register name for the given parameter. + * + * @returns The index register name. + * @param pDis The disassembler state. + * @param pParam The parameter. + * @param pcchReg Where to store the length of the name. + */ +static const char *disasmFormatYasmIndexReg(PCDISSTATE pDis, PCDISOPPARAM pParam, size_t *pcchReg) +{ + if (pParam->fUse & DISUSE_REG_XMM) + { + Assert(pParam->Index.idxXmmReg < RT_ELEMENTS(g_aszYasmRegXMM)); + const char *psz = g_aszYasmRegXMM[pParam->Index.idxXmmReg]; + *pcchReg = 4 + !!psz[4]; + return psz; + } + else if (pParam->fUse & DISUSE_REG_YMM) + { + Assert(pParam->Index.idxYmmReg < RT_ELEMENTS(g_aszYasmRegYMM)); + const char *psz = g_aszYasmRegYMM[pParam->Index.idxYmmReg]; + *pcchReg = 4 + !!psz[4]; + return psz; + + } + else + switch (pDis->uAddrMode) + { + case DISCPUMODE_16BIT: + { + Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen16)); + const char *psz = g_aszYasmRegGen16[pParam->Index.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + case DISCPUMODE_32BIT: + { + Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen32)); + const char *psz = g_aszYasmRegGen32[pParam->Index.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + case DISCPUMODE_64BIT: + { + Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen64)); + const char *psz = g_aszYasmRegGen64[pParam->Index.idxGenReg]; + *pcchReg = 2 + !!psz[2] + !!psz[3]; + return psz; + } + + default: + AssertMsgFailed(("%#x %#x\n", pParam->fUse, pDis->uAddrMode)); + *pcchReg = 3; + return "r??"; + } +} + + +/** + * Formats the current instruction in Yasm (/ Nasm) style. + * + * + * @returns The number of output characters. If this is >= cchBuf, then the content + * of pszBuf will be truncated. + * @param pDis Pointer to the disassembler state. + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. + * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*. + * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional. + * @param pvUser User argument for pfnGetSymbol. + */ +DISDECL(size_t) DISFormatYasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, + PFNDISGETSYMBOL pfnGetSymbol, void *pvUser) +{ +/** @todo monitor and mwait aren't formatted correctly in 64-bit mode. */ + /* + * Input validation and massaging. + */ + AssertPtr(pDis); + AssertPtrNull(pszBuf); + Assert(pszBuf || !cchBuf); + AssertPtrNull(pfnGetSymbol); + AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags)); + if (fFlags & DIS_FMT_FLAGS_ADDR_COMMENT) + fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT; + if (fFlags & DIS_FMT_FLAGS_BYTES_COMMENT) + fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT; + + PCDISOPCODE const pOp = pDis->pCurInstr; + + /* + * Output macros + */ + char *pszDst = pszBuf; + size_t cchDst = cchBuf; + size_t cchOutput = 0; +#define PUT_C(ch) \ + do { \ + cchOutput++; \ + if (cchDst > 1) \ + { \ + cchDst--; \ + *pszDst++ = (ch); \ + } \ + } while (0) +#define PUT_STR(pszSrc, cchSrc) \ + do { \ + cchOutput += (cchSrc); \ + if (cchDst > (cchSrc)) \ + { \ + memcpy(pszDst, (pszSrc), (cchSrc)); \ + pszDst += (cchSrc); \ + cchDst -= (cchSrc); \ + } \ + else if (cchDst > 1) \ + { \ + memcpy(pszDst, (pszSrc), cchDst - 1); \ + pszDst += cchDst - 1; \ + cchDst = 1; \ + } \ + } while (0) +#define PUT_SZ(sz) \ + PUT_STR((sz), sizeof(sz) - 1) +#define PUT_SZ_STRICT(szStrict, szRelaxed) \ + do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0) +#define PUT_PSZ(psz) \ + do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0) +#define PUT_NUM(cch, fmt, num) \ + do { \ + cchOutput += (cch); \ + if (cchDst > 1) \ + { \ + const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \ + pszDst += cchTmp; \ + cchDst -= cchTmp; \ + Assert(cchTmp == (cch) || cchDst == 1); \ + } \ + } while (0) +/** @todo add two flags for choosing between %X / %x and h / 0x. */ +#define PUT_NUM_8(num) PUT_NUM(4, "0%02xh", (uint8_t)(num)) +#define PUT_NUM_16(num) PUT_NUM(6, "0%04xh", (uint16_t)(num)) +#define PUT_NUM_32(num) PUT_NUM(10, "0%08xh", (uint32_t)(num)) +#define PUT_NUM_64(num) PUT_NUM(18, "0%016RX64h", (uint64_t)(num)) + +#define PUT_NUM_SIGN(cch, fmt, num, stype, utype) \ + do { \ + if ((stype)(num) >= 0) \ + { \ + PUT_C('+'); \ + PUT_NUM(cch, fmt, (utype)(num)); \ + } \ + else \ + { \ + PUT_C('-'); \ + PUT_NUM(cch, fmt, (utype)-(stype)(num)); \ + } \ + } while (0) +#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0%02xh", num, int8_t, uint8_t) +#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0%04xh", num, int16_t, uint16_t) +#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0%08xh", num, int32_t, uint32_t) +#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0%016RX64h", num, int64_t, uint64_t) + +#define PUT_SYMBOL_TWO(a_rcSym, a_szStart, a_chEnd) \ + do { \ + if (RT_SUCCESS(a_rcSym)) \ + { \ + PUT_SZ(a_szStart); \ + PUT_PSZ(szSymbol); \ + if (off != 0) \ + { \ + if ((int8_t)off == off) \ + PUT_NUM_S8(off); \ + else if ((int16_t)off == off) \ + PUT_NUM_S16(off); \ + else if ((int32_t)off == off) \ + PUT_NUM_S32(off); \ + else \ + PUT_NUM_S64(off); \ + } \ + PUT_C(a_chEnd); \ + } \ + } while (0) + +#define PUT_SYMBOL(a_uSeg, a_uAddr, a_szStart, a_chEnd) \ + do { \ + if (pfnGetSymbol) \ + { \ + int rcSym = pfnGetSymbol(pDis, a_uSeg, a_uAddr, szSymbol, sizeof(szSymbol), &off, pvUser); \ + PUT_SYMBOL_TWO(rcSym, a_szStart, a_chEnd); \ + } \ + } while (0) + + + /* + * The address? + */ + if (fFlags & DIS_FMT_FLAGS_ADDR_LEFT) + { +#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64 + if (pDis->uInstrAddr >= _4G) + PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32)); +#endif + PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr); + PUT_C(' '); + } + + /* + * The opcode bytes? + */ + if (fFlags & DIS_FMT_FLAGS_BYTES_LEFT) + { + size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags); + cchOutput += cchTmp; + if (cchDst > 1) + { + if (cchTmp <= cchDst) + { + cchDst -= cchTmp; + pszDst += cchTmp; + } + else + { + pszDst += cchDst - 1; + cchDst = 1; + } + } + + /* Some padding to align the instruction. */ + size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED))) + + !!(fFlags & DIS_FMT_FLAGS_BYTES_BRACKETS) * 2 + + 2; + cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp; + PUT_STR(g_szSpaces, cchPadding); + } + + + /* + * Filter out invalid opcodes first as they need special + * treatment. UD2 is an exception and should be handled normally. + */ + size_t const offInstruction = cchOutput; + if ( pOp->uOpcode == OP_INVALID + || ( pOp->uOpcode == OP_ILLUD2 + && (pDis->fPrefix & DISPREFIX_LOCK))) + PUT_SZ("Illegal opcode"); + else + { + /* + * Prefixes + */ + if (pDis->fPrefix & DISPREFIX_LOCK) + PUT_SZ("lock "); + if (pDis->fPrefix & DISPREFIX_REP) + PUT_SZ("rep "); + else if(pDis->fPrefix & DISPREFIX_REPNE) + PUT_SZ("repne "); + + /* + * Adjust the format string to the correct mnemonic + * or to avoid things the assembler cannot handle correctly. + */ + char szTmpFmt[48]; + const char *pszFmt = pOp->pszOpcode; + bool fIgnoresOpSize = false; + bool fMayNeedAddrSize = false; + switch (pOp->uOpcode) + { + case OP_JECXZ: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "jcxz %Jb" : pDis->uOpMode == DISCPUMODE_32BIT ? "jecxz %Jb" : "jrcxz %Jb"; + break; + case OP_PUSHF: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "pushfw" : pDis->uOpMode == DISCPUMODE_32BIT ? "pushfd" : "pushfq"; + break; + case OP_POPF: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "popfw" : pDis->uOpMode == DISCPUMODE_32BIT ? "popfd" : "popfq"; + break; + case OP_PUSHA: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "pushaw" : "pushad"; + break; + case OP_POPA: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "popaw" : "popad"; + break; + case OP_INSB: + pszFmt = "insb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_INSWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "insw" : pDis->uOpMode == DISCPUMODE_32BIT ? "insd" : "insq"; + fMayNeedAddrSize = true; + break; + case OP_OUTSB: + pszFmt = "outsb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_OUTSWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "outsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "outsd" : "outsq"; + fMayNeedAddrSize = true; + break; + case OP_MOVSB: + pszFmt = "movsb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_MOVSWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "movsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "movsd" : "movsq"; + fMayNeedAddrSize = true; + break; + case OP_CMPSB: + pszFmt = "cmpsb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_CMPWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "cmpsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "cmpsd" : "cmpsq"; + fMayNeedAddrSize = true; + break; + case OP_SCASB: + pszFmt = "scasb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_SCASWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "scasw" : pDis->uOpMode == DISCPUMODE_32BIT ? "scasd" : "scasq"; + fMayNeedAddrSize = true; + break; + case OP_LODSB: + pszFmt = "lodsb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_LODSWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "lodsw" : pDis->uOpMode == DISCPUMODE_32BIT ? "lodsd" : "lodsq"; + fMayNeedAddrSize = true; + break; + case OP_STOSB: + pszFmt = "stosb"; + fIgnoresOpSize = fMayNeedAddrSize = true; + break; + case OP_STOSWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "stosw" : pDis->uOpMode == DISCPUMODE_32BIT ? "stosd" : "stosq"; + fMayNeedAddrSize = true; + break; + case OP_CBW: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "cbw" : pDis->uOpMode == DISCPUMODE_32BIT ? "cwde" : "cdqe"; + break; + case OP_CWD: + pszFmt = pDis->uOpMode == DISCPUMODE_16BIT ? "cwd" : pDis->uOpMode == DISCPUMODE_32BIT ? "cdq" : "cqo"; + break; + case OP_SHL: + Assert(pszFmt[3] == '/'); + pszFmt += 4; + break; + case OP_XLAT: + pszFmt = "xlatb"; + break; + case OP_INT3: + pszFmt = "int3"; + break; + + /* + * Don't know how to tell yasm to generate complicated nop stuff, so 'db' it. + */ + case OP_NOP: + if (pDis->bOpCode == 0x90) + /* fine, fine */; + else if (pszFmt[sizeof("nop %Ev") - 1] == '/' && pszFmt[sizeof("nop %Ev")] == 'p') + pszFmt = "prefetch %Eb"; + else if (pDis->bOpCode == 0x1f) + { + Assert(pDis->cbInstr >= 3); + PUT_SZ("db 00fh, 01fh,"); + PUT_NUM_8(MAKE_MODRM(pDis->ModRM.Bits.Mod, pDis->ModRM.Bits.Reg, pDis->ModRM.Bits.Rm)); + for (unsigned i = 3; i < pDis->cbInstr; i++) + { + PUT_C(','); + PUT_NUM_8(0x90); /// @todo fixme. + } + pszFmt = ""; + } + break; + + default: + /* ST(X) -> stX (floating point) */ + if (*pszFmt == 'f' && strchr(pszFmt, '(')) + { + char *pszFmtDst = szTmpFmt; + char ch; + do + { + ch = *pszFmt++; + if (ch == 'S' && pszFmt[0] == 'T' && pszFmt[1] == '(') + { + *pszFmtDst++ = 's'; + *pszFmtDst++ = 't'; + pszFmt += 2; + ch = *pszFmt; + Assert(pszFmt[1] == ')'); + pszFmt += 2; + *pszFmtDst++ = ch; + } + else + *pszFmtDst++ = ch; + } while (ch != '\0'); + pszFmt = szTmpFmt; + } + if (strchr("#@&", *pszFmt)) + { + const char *pszDelim = strchr(pszFmt, '/'); + const char *pszSpace = (pszDelim ? strchr(pszDelim, ' ') : NULL); + if (pszDelim != NULL) + { + char *pszFmtDst = szTmpFmt; + if (pszSpace == NULL) pszSpace = strchr(pszDelim, 0); + if ( (*pszFmt == '#' && !pDis->bVexWFlag) /** @todo check this*/ + || (*pszFmt == '@' && !VEXREG_IS256B(pDis->bVexDestReg)) + || (*pszFmt == '&' && ( DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse) + || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse) + || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param3.fUse) + || DISUSE_IS_EFFECTIVE_ADDR(pDis->Param4.fUse)))) + { + strncpy(pszFmtDst, pszFmt + 1, pszDelim - pszFmt - 1); + pszFmtDst += pszDelim - pszFmt - 1; + } + else + { + strncpy(pszFmtDst, pszDelim + 1, pszSpace - pszDelim - 1); + pszFmtDst += pszSpace - pszDelim - 1; + } + strcpy (pszFmtDst, pszSpace); + pszFmt = szTmpFmt; + } + } + break; + + /* + * Horrible hacks. + */ + case OP_FLD: + if (pDis->bOpCode == 0xdb) /* m80fp workaround. */ + *(int *)&pDis->Param1.fParam &= ~0x1f; /* make it pure OP_PARM_M */ + break; + case OP_LAR: /* hack w -> v, probably not correct. */ + *(int *)&pDis->Param2.fParam &= ~0x1f; + *(int *)&pDis->Param2.fParam |= OP_PARM_v; + break; + } + + /* + * Add operand size and address prefixes for outsb, movsb, etc. + */ + if (pDis->fPrefix & (DISPREFIX_OPSIZE | DISPREFIX_ADDRSIZE)) + { + if (fIgnoresOpSize && (pDis->fPrefix & DISPREFIX_OPSIZE) ) + { + if (pDis->uCpuMode == DISCPUMODE_16BIT) + PUT_SZ("o32 "); + else + PUT_SZ("o16 "); + } + if (fMayNeedAddrSize && (pDis->fPrefix & DISPREFIX_ADDRSIZE) ) + { + if (pDis->uCpuMode == DISCPUMODE_16BIT) + PUT_SZ("a32 "); + else + PUT_SZ("a16 "); + } + } + + /* + * Formatting context and associated macros. + */ + PCDISOPPARAM pParam = &pDis->Param1; + int iParam = 1; + +#define PUT_FAR() \ + do { \ + if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p \ + && pOp->uOpcode != OP_LDS /* table bugs? */ \ + && pOp->uOpcode != OP_LES \ + && pOp->uOpcode != OP_LFS \ + && pOp->uOpcode != OP_LGS \ + && pOp->uOpcode != OP_LSS ) \ + PUT_SZ("far "); \ + } while (0) + /** @todo mov ah,ch ends up with a byte 'override'... - check if this wasn't fixed. */ + /** @todo drop the work/dword/qword override when the src/dst is a register (except for movsx/movzx). */ +#define PUT_SIZE_OVERRIDE() \ + do { \ + switch (OP_PARM_VSUBTYPE(pParam->fParam)) \ + { \ + case OP_PARM_v: \ + case OP_PARM_y: \ + switch (pDis->uOpMode) \ + { \ + case DISCPUMODE_16BIT: if (OP_PARM_VSUBTYPE(pParam->fParam) != OP_PARM_y) PUT_SZ("word "); break; \ + case DISCPUMODE_32BIT: \ + if (pDis->pCurInstr->uOpcode != OP_GATHER || pDis->bVexWFlag) { PUT_SZ("dword "); break; } \ + RT_FALL_THRU(); \ + case DISCPUMODE_64BIT: PUT_SZ("qword "); break; \ + default: break; \ + } \ + break; \ + case OP_PARM_b: PUT_SZ("byte "); break; \ + case OP_PARM_w: \ + if ( OP_PARM_VTYPE(pParam->fParam) == OP_PARM_W \ + || OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M) \ + { \ + if (VEXREG_IS256B(pDis->bVexDestReg)) PUT_SZ("dword "); \ + else PUT_SZ("word "); \ + } \ + break; \ + case OP_PARM_d: \ + if ( OP_PARM_VTYPE(pParam->fParam) == OP_PARM_W \ + || OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M) \ + { \ + if (VEXREG_IS256B(pDis->bVexDestReg)) PUT_SZ("qword "); \ + else PUT_SZ("dword "); \ + } \ + break; \ + case OP_PARM_q: \ + if ( OP_PARM_VTYPE(pParam->fParam) == OP_PARM_W \ + || OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M) \ + { \ + if (VEXREG_IS256B(pDis->bVexDestReg)) PUT_SZ("oword "); \ + else PUT_SZ("qword "); \ + } \ + break; \ + case OP_PARM_ps: \ + case OP_PARM_pd: \ + case OP_PARM_x: if (VEXREG_IS256B(pDis->bVexDestReg)) { PUT_SZ("yword "); break; } RT_FALL_THRU(); \ + case OP_PARM_ss: \ + case OP_PARM_sd: \ + case OP_PARM_dq: PUT_SZ("oword "); break; \ + case OP_PARM_qq: PUT_SZ("yword "); break; \ + case OP_PARM_p: break; /* see PUT_FAR */ \ + case OP_PARM_s: if (pParam->fUse & DISUSE_REG_FP) PUT_SZ("tword "); break; /* ?? */ \ + case OP_PARM_z: break; \ + case OP_PARM_NONE: \ + if ( OP_PARM_VTYPE(pParam->fParam) == OP_PARM_M \ + && ((pParam->fUse & DISUSE_REG_FP) || pOp->uOpcode == OP_FLD)) \ + PUT_SZ("tword "); \ + break; \ + default: break; /*no pointer type specified/necessary*/ \ + } \ + } while (0) + static const char s_szSegPrefix[6][4] = { "es:", "cs:", "ss:", "ds:", "fs:", "gs:" }; +#define PUT_SEGMENT_OVERRIDE() \ + do { \ + if (pDis->fPrefix & DISPREFIX_SEG) \ + PUT_STR(s_szSegPrefix[pDis->idxSegPrefix], 3); \ + } while (0) + + + /* + * Segment prefixing for instructions that doesn't do memory access. + */ + if ( (pDis->fPrefix & DISPREFIX_SEG) + && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse) + && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse) + && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param3.fUse)) + { + PUT_STR(s_szSegPrefix[pDis->idxSegPrefix], 2); + PUT_C(' '); + } + + + /* + * The formatting loop. + */ + RTINTPTR off; + char szSymbol[128]; + char ch; + while ((ch = *pszFmt++) != '\0') + { + if (ch == '%') + { + ch = *pszFmt++; + switch (ch) + { + /* + * ModRM - Register only / VEX.vvvv. + */ + case 'C': /* Control register (ParseModRM / UseModRM). */ + case 'D': /* Debug register (ParseModRM / UseModRM). */ + case 'G': /* ModRM selects general register (ParseModRM / UseModRM). */ + case 'S': /* ModRM byte selects a segment register (ParseModRM / UseModRM). */ + case 'T': /* ModRM byte selects a test register (ParseModRM / UseModRM). */ + case 'V': /* ModRM byte selects an XMM/SSE register (ParseModRM / UseModRM). */ + case 'P': /* ModRM byte selects MMX register (ParseModRM / UseModRM). */ + case 'H': /* The VEX.vvvv field of the VEX prefix selects a XMM/YMM register. */ + case 'B': /* The VEX.vvvv field of the VEX prefix selects a general register (ParseVexDest). */ + case 'L': /* The upper 4 bits of the 8-bit immediate selects a XMM/YMM register. */ + { + pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0; + Assert(!(pParam->fUse & (DISUSE_INDEX | DISUSE_SCALE) /* No SIB here... */)); + Assert(!(pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32))); + + size_t cchReg; + const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg); + PUT_STR(pszReg, cchReg); + break; + } + + /* + * ModRM - Register or memory. + */ + case 'E': /* ModRM specifies parameter (ParseModRM / UseModRM / UseSIB). */ + case 'Q': /* ModRM byte selects MMX register or memory address (ParseModRM / UseModRM). */ + case 'R': /* ModRM byte may only refer to a general register (ParseModRM / UseModRM). */ + case 'W': /* ModRM byte selects an XMM/SSE register or a memory address (ParseModRM / UseModRM). */ + case 'U': /* ModRM byte may only refer to a XMM/SSE register (ParseModRM / UseModRM). */ + case 'M': /* ModRM byte may only refer to memory (ParseModRM / UseModRM). */ + { + pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0; + + PUT_FAR(); + uint32_t const fUse = pParam->fUse; + if (DISUSE_IS_EFFECTIVE_ADDR(fUse)) + { + /* Work around mov seg,[mem16] and mov [mem16],seg as these always make a 16-bit mem + while the register variants deals with 16, 32 & 64 in the normal fashion. */ + if ( pParam->fParam != OP_PARM_Ev + || pOp->uOpcode != OP_MOV + || ( pOp->fParam1 != OP_PARM_Sw + && pOp->fParam2 != OP_PARM_Sw)) + PUT_SIZE_OVERRIDE(); + PUT_C('['); + } + if ( (fFlags & DIS_FMT_FLAGS_STRICT) + && (fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32))) + { + if ( (fUse & DISUSE_DISPLACEMENT8) + && !pParam->uDisp.i8) + PUT_SZ("byte "); + else if ( (fUse & DISUSE_DISPLACEMENT16) + && (int8_t)pParam->uDisp.i16 == (int16_t)pParam->uDisp.i16) + PUT_SZ("word "); + else if ( (fUse & DISUSE_DISPLACEMENT32) + && (int16_t)pParam->uDisp.i32 == (int32_t)pParam->uDisp.i32) //?? + PUT_SZ("dword "); + else if ( (fUse & DISUSE_DISPLACEMENT64) + && (pDis->SIB.Bits.Base != 5 || pDis->ModRM.Bits.Mod != 0) + && (int32_t)pParam->uDisp.i64 == (int64_t)pParam->uDisp.i64) //?? + PUT_SZ("qword "); + } + if (DISUSE_IS_EFFECTIVE_ADDR(fUse)) + PUT_SEGMENT_OVERRIDE(); + + bool fBase = (fUse & DISUSE_BASE) /* When exactly is DISUSE_BASE supposed to be set? disasmModRMReg doesn't set it. */ + || ( (fUse & ( DISUSE_REG_GEN8 + | DISUSE_REG_GEN16 + | DISUSE_REG_GEN32 + | DISUSE_REG_GEN64 + | DISUSE_REG_FP + | DISUSE_REG_MMX + | DISUSE_REG_XMM + | DISUSE_REG_YMM + | DISUSE_REG_CR + | DISUSE_REG_DBG + | DISUSE_REG_SEG + | DISUSE_REG_TEST )) + && !DISUSE_IS_EFFECTIVE_ADDR(fUse)); + if (fBase) + { + size_t cchReg; + const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg); + PUT_STR(pszReg, cchReg); + } + + if (fUse & DISUSE_INDEX) + { + if (fBase) + PUT_C('+'); + + size_t cchReg; + const char *pszReg = disasmFormatYasmIndexReg(pDis, pParam, &cchReg); + PUT_STR(pszReg, cchReg); + + if (fUse & DISUSE_SCALE) + { + PUT_C('*'); + PUT_C('0' + pParam->uScale); + } + } + else + Assert(!(fUse & DISUSE_SCALE)); + + int64_t off2 = 0; + if (fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)) + { + if (fUse & DISUSE_DISPLACEMENT8) + off2 = pParam->uDisp.i8; + else if (fUse & DISUSE_DISPLACEMENT16) + off2 = pParam->uDisp.i16; + else if (fUse & (DISUSE_DISPLACEMENT32 | DISUSE_RIPDISPLACEMENT32)) + off2 = pParam->uDisp.i32; + else if (fUse & DISUSE_DISPLACEMENT64) + off2 = pParam->uDisp.i64; + else + { + AssertFailed(); + off2 = 0; + } + + int64_t off3 = off2; + if (fBase || (fUse & (DISUSE_INDEX | DISUSE_RIPDISPLACEMENT32))) + { + PUT_C(off3 >= 0 ? '+' : '-'); + if (off3 < 0) + off3 = -off3; + } + if (fUse & DISUSE_DISPLACEMENT8) + PUT_NUM_8( off3); + else if (fUse & DISUSE_DISPLACEMENT16) + PUT_NUM_16(off3); + else if (fUse & DISUSE_DISPLACEMENT32) + PUT_NUM_32(off3); + else if (fUse & DISUSE_DISPLACEMENT64) + PUT_NUM_64(off3); + else + { + PUT_NUM_32(off3); + PUT_SZ(" wrt rip ("); + off2 += pDis->uInstrAddr + pDis->cbInstr; + PUT_NUM_64(off2); + if (pfnGetSymbol) + PUT_SYMBOL((pDis->fPrefix & DISPREFIX_SEG) + ? DIS_FMT_SEL_FROM_REG(pDis->idxSegPrefix) + : DIS_FMT_SEL_FROM_REG(DISSELREG_DS), + pDis->uAddrMode == DISCPUMODE_64BIT + ? (uint64_t)off2 + : pDis->uAddrMode == DISCPUMODE_32BIT + ? (uint32_t)off2 + : (uint16_t)off2, + " = ", + ')'); + else + PUT_C(')'); + } + } + + if (DISUSE_IS_EFFECTIVE_ADDR(fUse)) + { + if (pfnGetSymbol && !fBase && !(fUse & (DISUSE_INDEX | DISUSE_RIPDISPLACEMENT32)) && off2 != 0) + PUT_SYMBOL((pDis->fPrefix & DISPREFIX_SEG) + ? DIS_FMT_SEL_FROM_REG(pDis->idxSegPrefix) + : DIS_FMT_SEL_FROM_REG(DISSELREG_DS), + pDis->uAddrMode == DISCPUMODE_64BIT + ? (uint64_t)off2 + : pDis->uAddrMode == DISCPUMODE_32BIT + ? (uint32_t)off2 + : (uint16_t)off2, + " (=", + ')'); + PUT_C(']'); + } + break; + } + + case 'F': /* Eflags register (0 - popf/pushf only, avoided in adjustments above). */ + AssertFailed(); + break; + + case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */ + Assert(*pszFmt == 'b' || *pszFmt == 'v' || *pszFmt == 'w' || *pszFmt == 'z'); pszFmt++; + switch (pParam->fUse & ( DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64 + | DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8)) + { + case DISUSE_IMMEDIATE8: + if ( (fFlags & DIS_FMT_FLAGS_STRICT) + && ( (pOp->fParam1 >= OP_PARM_REG_GEN8_START && pOp->fParam1 <= OP_PARM_REG_GEN8_END) + || (pOp->fParam2 >= OP_PARM_REG_GEN8_START && pOp->fParam2 <= OP_PARM_REG_GEN8_END)) + ) + PUT_SZ("strict byte "); + PUT_NUM_8(pParam->uValue); + break; + + case DISUSE_IMMEDIATE16: + if ( pDis->uCpuMode != pDis->uOpMode + || ( (fFlags & DIS_FMT_FLAGS_STRICT) + && ( (int8_t)pParam->uValue == (int16_t)pParam->uValue + || (pOp->fParam1 >= OP_PARM_REG_GEN16_START && pOp->fParam1 <= OP_PARM_REG_GEN16_END) + || (pOp->fParam2 >= OP_PARM_REG_GEN16_START && pOp->fParam2 <= OP_PARM_REG_GEN16_END)) + ) + ) + { + if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_b) + PUT_SZ_STRICT("strict byte ", "byte "); + else if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_v + || OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_z) + PUT_SZ_STRICT("strict word ", "word "); + } + PUT_NUM_16(pParam->uValue); + break; + + case DISUSE_IMMEDIATE16_SX8: + if ( !(pDis->fPrefix & DISPREFIX_OPSIZE) + || pDis->pCurInstr->uOpcode != OP_PUSH) + PUT_SZ_STRICT("strict byte ", "byte "); + else + PUT_SZ("word "); + PUT_NUM_16(pParam->uValue); + break; + + case DISUSE_IMMEDIATE32: + if ( pDis->uOpMode != (pDis->uCpuMode == DISCPUMODE_16BIT ? DISCPUMODE_16BIT : DISCPUMODE_32BIT) /* not perfect */ + || ( (fFlags & DIS_FMT_FLAGS_STRICT) + && ( (int8_t)pParam->uValue == (int32_t)pParam->uValue + || (pOp->fParam1 >= OP_PARM_REG_GEN32_START && pOp->fParam1 <= OP_PARM_REG_GEN32_END) + || (pOp->fParam2 >= OP_PARM_REG_GEN32_START && pOp->fParam2 <= OP_PARM_REG_GEN32_END)) + ) + ) + { + if (OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_b) + PUT_SZ_STRICT("strict byte ", "byte "); + else if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_v + || OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_z) + PUT_SZ_STRICT("strict dword ", "dword "); + } + PUT_NUM_32(pParam->uValue); + if (pDis->uCpuMode == DISCPUMODE_32BIT) + PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uValue, " (=", ')'); + break; + + case DISUSE_IMMEDIATE32_SX8: + if ( !(pDis->fPrefix & DISPREFIX_OPSIZE) + || pDis->pCurInstr->uOpcode != OP_PUSH) + PUT_SZ_STRICT("strict byte ", "byte "); + else + PUT_SZ("dword "); + PUT_NUM_32(pParam->uValue); + break; + + case DISUSE_IMMEDIATE64_SX8: + if ( !(pDis->fPrefix & DISPREFIX_OPSIZE) + || pDis->pCurInstr->uOpcode != OP_PUSH) + PUT_SZ_STRICT("strict byte ", "byte "); + else + PUT_SZ("qword "); + PUT_NUM_64(pParam->uValue); + break; + + case DISUSE_IMMEDIATE64: + PUT_NUM_64(pParam->uValue); + break; + + default: + AssertFailed(); + break; + } + break; + + case 'J': /* Relative jump offset (ParseImmBRel + ParseImmVRel). */ + { + int32_t offDisplacement; + Assert(iParam == 1); + bool fPrefix = (fFlags & DIS_FMT_FLAGS_STRICT) + && pOp->uOpcode != OP_CALL + && pOp->uOpcode != OP_LOOP + && pOp->uOpcode != OP_LOOPE + && pOp->uOpcode != OP_LOOPNE + && pOp->uOpcode != OP_JECXZ; + if (pOp->uOpcode == OP_CALL) + fFlags &= ~DIS_FMT_FLAGS_RELATIVE_BRANCH; + + if (pParam->fUse & DISUSE_IMMEDIATE8_REL) + { + if (fPrefix) + PUT_SZ("short "); + offDisplacement = (int8_t)pParam->uValue; + Assert(*pszFmt == 'b'); pszFmt++; + + if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH) + PUT_NUM_S8(offDisplacement); + } + else if (pParam->fUse & DISUSE_IMMEDIATE16_REL) + { + if (fPrefix) + PUT_SZ("near "); + offDisplacement = (int16_t)pParam->uValue; + Assert(*pszFmt == 'v'); pszFmt++; + + if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH) + PUT_NUM_S16(offDisplacement); + } + else + { + if (fPrefix) + PUT_SZ("near "); + offDisplacement = (int32_t)pParam->uValue; + Assert(pParam->fUse & (DISUSE_IMMEDIATE32_REL | DISUSE_IMMEDIATE64_REL)); + Assert(*pszFmt == 'v'); pszFmt++; + + if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH) + PUT_NUM_S32(offDisplacement); + } + if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH) + PUT_SZ(" ("); + + RTUINTPTR uTrgAddr = pDis->uInstrAddr + pDis->cbInstr + offDisplacement; + if (pDis->uCpuMode == DISCPUMODE_16BIT) + PUT_NUM_16(uTrgAddr); + else if (pDis->uCpuMode == DISCPUMODE_32BIT) + PUT_NUM_32(uTrgAddr); + else + PUT_NUM_64(uTrgAddr); + + if (fFlags & DIS_FMT_FLAGS_RELATIVE_BRANCH) + { + PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " = ", ' '); + PUT_C(')'); + } + else + PUT_SYMBOL(DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, " (", ')'); + break; + } + + case 'A': /* Direct (jump/call) address (ParseImmAddr). */ + { + Assert(*pszFmt == 'p'); pszFmt++; + PUT_FAR(); + PUT_SIZE_OVERRIDE(); + PUT_SEGMENT_OVERRIDE(); + off = 0; + int rc = VERR_SYMBOL_NOT_FOUND; + switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16)) + { + case DISUSE_IMMEDIATE_ADDR_16_16: + PUT_NUM_16(pParam->uValue >> 16); + PUT_C(':'); + PUT_NUM_16(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_IMMEDIATE_ADDR_16_32: + PUT_NUM_16(pParam->uValue >> 32); + PUT_C(':'); + PUT_NUM_32(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_DISPLACEMENT16: + PUT_NUM_16(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_DISPLACEMENT32: + PUT_NUM_32(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_DISPLACEMENT64: + PUT_NUM_64(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint64_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + default: + AssertFailed(); + break; + } + + PUT_SYMBOL_TWO(rc, " [", ']'); + break; + } + + case 'O': /* No ModRM byte (ParseImmAddr). */ + { + Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++; + PUT_FAR(); + PUT_SIZE_OVERRIDE(); + PUT_C('['); + PUT_SEGMENT_OVERRIDE(); + off = 0; + int rc = VERR_SYMBOL_NOT_FOUND; + switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16)) + { + case DISUSE_IMMEDIATE_ADDR_16_16: + PUT_NUM_16(pParam->uValue >> 16); + PUT_C(':'); + PUT_NUM_16(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_IMMEDIATE_ADDR_16_32: + PUT_NUM_16(pParam->uValue >> 32); + PUT_C(':'); + PUT_NUM_32(pParam->uValue); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_DISPLACEMENT16: + PUT_NUM_16(pParam->uDisp.i16); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u16, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_DISPLACEMENT32: + PUT_NUM_32(pParam->uDisp.i32); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u32, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + case DISUSE_DISPLACEMENT64: + PUT_NUM_64(pParam->uDisp.i64); + if (pfnGetSymbol) + rc = pfnGetSymbol(pDis, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u64, szSymbol, sizeof(szSymbol), &off, pvUser); + break; + default: + AssertFailed(); + break; + } + PUT_C(']'); + + PUT_SYMBOL_TWO(rc, " (", ')'); + break; + } + + case 'X': /* DS:SI (ParseXb, ParseXv). */ + case 'Y': /* ES:DI (ParseYb, ParseYv). */ + { + Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++; + PUT_FAR(); + PUT_SIZE_OVERRIDE(); + PUT_C('['); + if (pParam->fUse & DISUSE_POINTER_DS_BASED) + PUT_SZ("ds:"); + else + PUT_SZ("es:"); + + size_t cchReg; + const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg); + PUT_STR(pszReg, cchReg); + PUT_C(']'); + break; + } + + case 'e': /* Register based on operand size (e.g. %eAX, %eAH) (ParseFixedReg). */ + { + Assert(RT_C_IS_ALPHA(pszFmt[0]) && RT_C_IS_ALPHA(pszFmt[1]) && !RT_C_IS_ALPHA(pszFmt[2])); + pszFmt += 2; + size_t cchReg; + const char *pszReg = disasmFormatYasmBaseReg(pDis, pParam, &cchReg); + PUT_STR(pszReg, cchReg); + break; + } + + default: + AssertMsgFailed(("%c%s!\n", ch, pszFmt)); + break; + } + AssertMsg(*pszFmt == ',' || *pszFmt == '\0', ("%c%s\n", ch, pszFmt)); + } + else + { + PUT_C(ch); + if (ch == ',') + { + Assert(*pszFmt != ' '); + PUT_C(' '); + switch (++iParam) + { + case 2: pParam = &pDis->Param2; break; + case 3: pParam = &pDis->Param3; break; + case 4: pParam = &pDis->Param4; break; + default: pParam = NULL; break; + } + } + } + } /* while more to format */ + } + + /* + * Any additional output to the right of the instruction? + */ + if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT)) + { + /* some up front padding. */ + size_t cchPadding = cchOutput - offInstruction; + cchPadding = cchPadding + 1 >= 42 ? 1 : 42 - cchPadding; + PUT_STR(g_szSpaces, cchPadding); + + /* comment? */ + if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT)) + PUT_SZ(";"); + + /* + * The address? + */ + if (fFlags & DIS_FMT_FLAGS_ADDR_RIGHT) + { + PUT_C(' '); +#if HC_ARCH_BITS == 64 || GC_ARCH_BITS == 64 + if (pDis->uInstrAddr >= _4G) + PUT_NUM(9, "%08x`", (uint32_t)(pDis->uInstrAddr >> 32)); +#endif + PUT_NUM(8, "%08x", (uint32_t)pDis->uInstrAddr); + } + + /* + * Opcode bytes? + */ + if (fFlags & DIS_FMT_FLAGS_BYTES_RIGHT) + { + PUT_C(' '); + size_t cchTmp = disFormatBytes(pDis, pszDst, cchDst, fFlags); + cchOutput += cchTmp; + if (cchTmp >= cchDst) + cchTmp = cchDst - (cchDst != 0); + cchDst -= cchTmp; + pszDst += cchTmp; + } + } + + /* + * Terminate it - on overflow we'll have reserved one byte for this. + */ + if (cchDst > 0) + *pszDst = '\0'; + else + Assert(!cchBuf); + + /* clean up macros */ +#undef PUT_PSZ +#undef PUT_SZ +#undef PUT_STR +#undef PUT_C + return cchOutput; +} + + +/** + * Formats the current instruction in Yasm (/ Nasm) style. + * + * This is a simplified version of DISFormatYasmEx() provided for your convenience. + * + * + * @returns The number of output characters. If this is >= cchBuf, then the content + * of pszBuf will be truncated. + * @param pDis Pointer to the disassembler state. + * @param pszBuf The output buffer. + * @param cchBuf The size of the output buffer. + */ +DISDECL(size_t) DISFormatYasm(PCDISSTATE pDis, char *pszBuf, size_t cchBuf) +{ + return DISFormatYasmEx(pDis, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */); +} + + +/** + * Checks if the encoding of the given disassembled instruction is something we + * can never get YASM to produce. + * + * @returns true if it's odd, false if it isn't. + * @param pDis The disassembler output. The byte fetcher callback will + * be used if present as we might need to fetch opcode + * bytes. + */ +DISDECL(bool) DISFormatYasmIsOddEncoding(PDISSTATE pDis) +{ + /* + * Mod rm + SIB: Check for duplicate EBP encodings that yasm won't use for very good reasons. + */ + if ( pDis->uAddrMode != DISCPUMODE_16BIT /// @todo correct? + && pDis->ModRM.Bits.Rm == 4 + && pDis->ModRM.Bits.Mod != 3) + { + /* No scaled index SIB (index=4), except for ESP. */ + if ( pDis->SIB.Bits.Index == 4 + && pDis->SIB.Bits.Base != 4) + return true; + + /* EBP + displacement */ + if ( pDis->ModRM.Bits.Mod != 0 + && pDis->SIB.Bits.Base == 5 + && pDis->SIB.Bits.Scale == 0) + return true; + } + + /* + * Seems to be an instruction alias here, but I cannot find any docs on it... hrmpf! + */ + if ( pDis->pCurInstr->uOpcode == OP_SHL + && pDis->ModRM.Bits.Reg == 6) + return true; + + /* + * Check for multiple prefixes of the same kind. + */ + uint8_t off1stSeg = UINT8_MAX; + uint8_t offOpSize = UINT8_MAX; + uint8_t offAddrSize = UINT8_MAX; + uint32_t fPrefixes = 0; + for (uint32_t offOpcode = 0; offOpcode < RT_ELEMENTS(pDis->abInstr); offOpcode++) + { + uint32_t f; + switch (pDis->abInstr[offOpcode]) + { + case 0xf0: + f = DISPREFIX_LOCK; + break; + + case 0xf2: + case 0xf3: + f = DISPREFIX_REP; /* yes, both */ + break; + + case 0x2e: + case 0x3e: + case 0x26: + case 0x36: + case 0x64: + case 0x65: + if (off1stSeg == UINT8_MAX) + off1stSeg = offOpcode; + f = DISPREFIX_SEG; + break; + + case 0x66: + if (offOpSize == UINT8_MAX) + offOpSize = offOpcode; + f = DISPREFIX_OPSIZE; + break; + + case 0x67: + if (offAddrSize == UINT8_MAX) + offAddrSize = offOpcode; + f = DISPREFIX_ADDRSIZE; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: + case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f: + f = pDis->uCpuMode == DISCPUMODE_64BIT ? DISPREFIX_REX : 0; + break; + + default: + f = 0; + break; + } + if (!f) + break; /* done */ + if (fPrefixes & f) + return true; + fPrefixes |= f; + } + + /* segment overrides are fun */ + if (fPrefixes & DISPREFIX_SEG) + { + /* no effective address which it may apply to. */ + Assert((pDis->fPrefix & DISPREFIX_SEG) || pDis->uCpuMode == DISCPUMODE_64BIT); + if ( !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param1.fUse) + && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param2.fUse) + && !DISUSE_IS_EFFECTIVE_ADDR(pDis->Param3.fUse)) + return true; + + /* Yasm puts the segment prefixes before the operand prefix with no + way of overriding it. */ + if (offOpSize < off1stSeg) + return true; + } + + /* fixed register + addr override doesn't go down all that well. */ + if (fPrefixes & DISPREFIX_ADDRSIZE) + { + Assert(pDis->fPrefix & DISPREFIX_ADDRSIZE); + if ( pDis->pCurInstr->fParam3 == OP_PARM_NONE + && pDis->pCurInstr->fParam2 == OP_PARM_NONE + && ( pDis->pCurInstr->fParam1 >= OP_PARM_REG_GEN32_START + && pDis->pCurInstr->fParam1 <= OP_PARM_REG_GEN32_END)) + return true; + } + + /* Almost all prefixes are bad for jumps. */ + if (fPrefixes) + { + switch (pDis->pCurInstr->uOpcode) + { + /* nop w/ prefix(es). */ + case OP_NOP: + return true; + + case OP_JMP: + if ( pDis->pCurInstr->fParam1 != OP_PARM_Jb + && pDis->pCurInstr->fParam1 != OP_PARM_Jv) + break; + RT_FALL_THRU(); + case OP_JO: + case OP_JNO: + case OP_JC: + case OP_JNC: + case OP_JE: + case OP_JNE: + case OP_JBE: + case OP_JNBE: + case OP_JS: + case OP_JNS: + case OP_JP: + case OP_JNP: + case OP_JL: + case OP_JNL: + case OP_JLE: + case OP_JNLE: + /** @todo branch hinting 0x2e/0x3e... */ + return true; + } + + } + + /* All but the segment prefix is bad news for push/pop. */ + if (fPrefixes & ~DISPREFIX_SEG) + { + switch (pDis->pCurInstr->uOpcode) + { + case OP_POP: + case OP_PUSH: + if ( pDis->pCurInstr->fParam1 >= OP_PARM_REG_SEG_START + && pDis->pCurInstr->fParam1 <= OP_PARM_REG_SEG_END) + return true; + if ( (fPrefixes & ~DISPREFIX_OPSIZE) + && pDis->pCurInstr->fParam1 >= OP_PARM_REG_GEN32_START + && pDis->pCurInstr->fParam1 <= OP_PARM_REG_GEN32_END) + return true; + break; + + case OP_POPA: + case OP_POPF: + case OP_PUSHA: + case OP_PUSHF: + if (fPrefixes & ~DISPREFIX_OPSIZE) + return true; + break; + } + } + + /* Implicit 8-bit register instructions doesn't mix with operand size. */ + if ( (fPrefixes & DISPREFIX_OPSIZE) + && ( ( pDis->pCurInstr->fParam1 == OP_PARM_Gb /* r8 */ + && pDis->pCurInstr->fParam2 == OP_PARM_Eb /* r8/mem8 */) + || ( pDis->pCurInstr->fParam2 == OP_PARM_Gb /* r8 */ + && pDis->pCurInstr->fParam1 == OP_PARM_Eb /* r8/mem8 */)) + ) + { + switch (pDis->pCurInstr->uOpcode) + { + case OP_ADD: + case OP_OR: + case OP_ADC: + case OP_SBB: + case OP_AND: + case OP_SUB: + case OP_XOR: + case OP_CMP: + return true; + default: + break; + } + } + + /* Instructions taking no address or operand which thus may be annoyingly + difficult to format for yasm. */ + if (fPrefixes) + { + switch (pDis->pCurInstr->uOpcode) + { + case OP_STI: + case OP_STC: + case OP_CLI: + case OP_CLD: + case OP_CLC: + case OP_INT: + case OP_INT3: + case OP_INTO: + case OP_HLT: + /** @todo Many more to can be added here. */ + return true; + default: + break; + } + } + + /* FPU and other instructions that ignores operand size override. */ + if (fPrefixes & DISPREFIX_OPSIZE) + { + switch (pDis->pCurInstr->uOpcode) + { + /* FPU: */ + case OP_FIADD: + case OP_FIMUL: + case OP_FISUB: + case OP_FISUBR: + case OP_FIDIV: + case OP_FIDIVR: + /** @todo there are many more. */ + return true; + + case OP_MOV: + /** @todo could be that we're not disassembling these correctly. */ + if (pDis->pCurInstr->fParam1 == OP_PARM_Sw) + return true; + /** @todo what about the other way? */ + break; + + default: + break; + } + } + + + /* + * Check for the version of xyz reg,reg instruction that the assembler doesn't use. + * + * For example: + * expected: 1aee sbb ch, dh ; SBB r8, r/m8 + * yasm: 18F5 sbb ch, dh ; SBB r/m8, r8 + */ + if (pDis->ModRM.Bits.Mod == 3 /* reg,reg */) + { + switch (pDis->pCurInstr->uOpcode) + { + case OP_ADD: + case OP_OR: + case OP_ADC: + case OP_SBB: + case OP_AND: + case OP_SUB: + case OP_XOR: + case OP_CMP: + if ( ( pDis->pCurInstr->fParam1 == OP_PARM_Gb /* r8 */ + && pDis->pCurInstr->fParam2 == OP_PARM_Eb /* r8/mem8 */) + || ( pDis->pCurInstr->fParam1 == OP_PARM_Gv /* rX */ + && pDis->pCurInstr->fParam2 == OP_PARM_Ev /* rX/memX */)) + return true; + + /* 82 (see table A-6). */ + if (pDis->bOpCode == 0x82) + return true; + break; + + /* ff /0, fe /0, ff /1, fe /0 */ + case OP_DEC: + case OP_INC: + return true; + + case OP_POP: + case OP_PUSH: + Assert(pDis->bOpCode == 0x8f); + return true; + + case OP_MOV: + if ( pDis->bOpCode == 0x8a + || pDis->bOpCode == 0x8b) + return true; + break; + + default: + break; + } + } + + /* shl eax,1 will be assembled to the form without the immediate byte. */ + if ( pDis->pCurInstr->fParam2 == OP_PARM_Ib + && (uint8_t)pDis->Param2.uValue == 1) + { + switch (pDis->pCurInstr->uOpcode) + { + case OP_SHL: + case OP_SHR: + case OP_SAR: + case OP_RCL: + case OP_RCR: + case OP_ROL: + case OP_ROR: + return true; + } + } + + /* And some more - see table A-6. */ + if (pDis->bOpCode == 0x82) + { + switch (pDis->pCurInstr->uOpcode) + { + case OP_ADD: + case OP_OR: + case OP_ADC: + case OP_SBB: + case OP_AND: + case OP_SUB: + case OP_XOR: + case OP_CMP: + return true; + break; + } + } + + + /* check for REX.X = 1 without SIB. */ + + /* Yasm encodes setnbe al with /2 instead of /0 like the AMD manual + says (intel doesn't appear to care). */ + switch (pDis->pCurInstr->uOpcode) + { + case OP_SETO: + case OP_SETNO: + case OP_SETC: + case OP_SETNC: + case OP_SETE: + case OP_SETNE: + case OP_SETBE: + case OP_SETNBE: + case OP_SETS: + case OP_SETNS: + case OP_SETP: + case OP_SETNP: + case OP_SETL: + case OP_SETNL: + case OP_SETLE: + case OP_SETNLE: + AssertMsg(pDis->bOpCode >= 0x90 && pDis->bOpCode <= 0x9f, ("%#x\n", pDis->bOpCode)); + if (pDis->ModRM.Bits.Reg != 2) + return true; + break; + } + + /* + * The MOVZX reg32,mem16 instruction without an operand size prefix + * doesn't quite make sense... + */ + if ( pDis->pCurInstr->uOpcode == OP_MOVZX + && pDis->bOpCode == 0xB7 + && (pDis->uCpuMode == DISCPUMODE_16BIT) != !!(fPrefixes & DISPREFIX_OPSIZE)) + return true; + + /* + * YASM doesn't do ICEBP/INT1/INT01, unlike NASM. + */ + if (pDis->bOpCode == 0xF1) + return true; + + return false; +} + diff --git a/src/VBox/Disassembler/DisasmInternal.h b/src/VBox/Disassembler/DisasmInternal.h new file mode 100644 index 00000000..cf233fb5 --- /dev/null +++ b/src/VBox/Disassembler/DisasmInternal.h @@ -0,0 +1,262 @@ +/* $Id: DisasmInternal.h $ */ +/** @file + * VBox disassembler - Internal header. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + +#ifndef VBOX_INCLUDED_SRC_DisasmInternal_h +#define VBOX_INCLUDED_SRC_DisasmInternal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include <VBox/types.h> +#include <VBox/dis.h> + + +/** @defgroup grp_dis_int Internals. + * @ingroup grp_dis + * @{ + */ + +/** @name Index into g_apfnCalcSize and g_apfnFullDisasm. + * @{ */ +enum IDX_Parse +{ + IDX_ParseNop = 0, + IDX_ParseModRM, + IDX_UseModRM, + IDX_ParseImmByte, + IDX_ParseImmBRel, + IDX_ParseImmUshort, + IDX_ParseImmV, + IDX_ParseImmVRel, + IDX_ParseImmAddr, + IDX_ParseFixedReg, + IDX_ParseImmUlong, + IDX_ParseImmQword, + IDX_ParseTwoByteEsc, + IDX_ParseGrp1, + IDX_ParseShiftGrp2, + IDX_ParseGrp3, + IDX_ParseGrp4, + IDX_ParseGrp5, + IDX_Parse3DNow, + IDX_ParseGrp6, + IDX_ParseGrp7, + IDX_ParseGrp8, + IDX_ParseGrp9, + IDX_ParseGrp10, + IDX_ParseGrp12, + IDX_ParseGrp13, + IDX_ParseGrp14, + IDX_ParseGrp15, + IDX_ParseGrp16, + IDX_ParseGrp17, + IDX_ParseModFence, + IDX_ParseYv, + IDX_ParseYb, + IDX_ParseXv, + IDX_ParseXb, + IDX_ParseEscFP, + IDX_ParseNopPause, + IDX_ParseImmByteSX, + IDX_ParseImmZ, + IDX_ParseThreeByteEsc4, + IDX_ParseThreeByteEsc5, + IDX_ParseImmAddrF, + IDX_ParseInvOpModRM, + IDX_ParseVex2b, + IDX_ParseVex3b, + IDX_ParseVexDest, + IDX_ParseMax +}; +AssertCompile(IDX_ParseMax < 64 /* Packed DISOPCODE assumption. */); +/** @} */ + +/** + * Opcode map descriptor. + * + * This is used a number of places to save storage space where there are lots of + * invalid instructions and the beginning or end of the map. + */ +typedef struct DISOPMAPDESC +{ + /** Pointer to the opcodes described by this structure. */ + PCDISOPCODE papOpcodes; +#if ARCH_BITS <= 32 + uint16_t +#else + uint32_t +#endif + /** The map index corresponding to the first papOpcodes entry. */ + idxFirst, + /** Number of opcodes in the map. */ + cOpcodes; +} DISOPMAPDESC; +/** Pointer to a const opcode map descriptor. */ +typedef DISOPMAPDESC const *PCDISOPMAPDESC; + +/** @name Opcode maps. + * @{ */ +extern const DISOPCODE g_InvalidOpcode[1]; + +extern const DISOPCODE g_aOneByteMapX86[256]; +extern const DISOPCODE g_aOneByteMapX64[256]; +extern const DISOPCODE g_aTwoByteMapX86[256]; + +/** Two byte opcode map with prefix 0x66 */ +extern const DISOPCODE g_aTwoByteMapX86_PF66[256]; + +/** Two byte opcode map with prefix 0xF2 */ +extern const DISOPCODE g_aTwoByteMapX86_PFF2[256]; + +/** Two byte opcode map with prefix 0xF3 */ +extern const DISOPCODE g_aTwoByteMapX86_PFF3[256]; + +/** Three byte opcode map (0xF 0x38) */ +extern PCDISOPCODE const g_apThreeByteMapX86_0F38[16]; + +/** Three byte opcode map with prefix 0x66 (0xF 0x38) */ +extern PCDISOPCODE const g_apThreeByteMapX86_660F38[16]; + +/** Three byte opcode map with prefix 0xF2 (0xF 0x38) */ +extern PCDISOPCODE const g_apThreeByteMapX86_F20F38[16]; + +/** Three byte opcode map with prefix 0xF3 (0xF 0x38) */ +extern PCDISOPCODE const g_apThreeByteMapX86_F30F38[16]; + +extern PCDISOPCODE const g_apThreeByteMapX86_0F3A[16]; + +/** Three byte opcode map with prefix 0x66 (0xF 0x3A) */ +extern PCDISOPCODE const g_apThreeByteMapX86_660F3A[16]; + +/** Three byte opcode map with prefixes 0x66 0xF2 (0xF 0x38) */ +extern PCDISOPCODE const g_apThreeByteMapX86_66F20F38[16]; + +/** VEX opcodes table defined by [VEX.m-mmmm - 1]. + * 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 00b */ +extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_None[3]; + +/** VEX opcodes table defined by [VEX.m-mmmm - 1]. + * 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 01b (66h) */ +extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_66H[3]; + +/** 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 10b (F3h) */ +extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_F3H[3]; + +/** 0Fh, 0F38h, 0F3Ah correspondingly, VEX.pp = 11b (F2h) */ +extern PCDISOPMAPDESC const g_apVexOpcodesMapRanges_F2H[3]; + +/** Two dimmentional map descriptor array: first index is by VEX.pp (prefix), + * second by the VEX.mmmm (map). + * The latter has to be bounced checked as we only have the first 4 maps. */ +extern PCDISOPMAPDESC const g_aapVexOpcodesMapRanges[4][4]; +/** @} */ + +/** @name Opcode extensions (Group tables) + * @{ */ +extern const DISOPCODE g_aMapX86_Group1[8*4]; +extern const DISOPCODE g_aMapX86_Group2[8*6]; +extern const DISOPCODE g_aMapX86_Group3[8*2]; +extern const DISOPCODE g_aMapX86_Group4[8]; +extern const DISOPCODE g_aMapX86_Group5[8]; +extern const DISOPCODE g_aMapX86_Group6[8]; +extern const DISOPCODE g_aMapX86_Group7_mem[8]; +extern const DISOPCODE g_aMapX86_Group7_mod11_rm000[8]; +extern const DISOPCODE g_aMapX86_Group7_mod11_rm001[8]; +extern const DISOPCODE g_aMapX86_Group8[8]; +extern const DISOPCODE g_aMapX86_Group9[8]; +extern const DISOPCODE g_aMapX86_Group10[8]; +extern const DISOPCODE g_aMapX86_Group11[8*2]; +extern const DISOPCODE g_aMapX86_Group12[8*2]; +extern const DISOPCODE g_aMapX86_Group13[8*2]; +extern const DISOPCODE g_aMapX86_Group14[8*2]; +extern const DISOPCODE g_aMapX86_Group15_mem[8]; +extern const DISOPCODE g_aMapX86_Group15_mod11_rm000[8]; +extern const DISOPCODE g_aMapX86_Group16[8]; +extern const DISOPCODE g_aMapX86_Group17[8*2]; +extern const DISOPCODE g_aMapX86_NopPause[2]; +/** @} */ + +/** 3DNow! map (0x0F 0x0F prefix) */ +extern const DISOPCODE g_aTwoByteMapX86_3DNow[256]; + +/** Floating point opcodes starting with escape byte 0xDF + * @{ */ +extern const DISOPCODE g_aMapX86_EscF0_Low[8]; +extern const DISOPCODE g_aMapX86_EscF0_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF1_Low[8]; +extern const DISOPCODE g_aMapX86_EscF1_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF2_Low[8]; +extern const DISOPCODE g_aMapX86_EscF2_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF3_Low[8]; +extern const DISOPCODE g_aMapX86_EscF3_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF4_Low[8]; +extern const DISOPCODE g_aMapX86_EscF4_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF5_Low[8]; +extern const DISOPCODE g_aMapX86_EscF5_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF6_Low[8]; +extern const DISOPCODE g_aMapX86_EscF6_High[16*4]; +extern const DISOPCODE g_aMapX86_EscF7_Low[8]; +extern const DISOPCODE g_aMapX86_EscF7_High[16*4]; + +extern const PCDISOPCODE g_apMapX86_FP_Low[8]; +extern const PCDISOPCODE g_apMapX86_FP_High[8]; +/** @} */ + +/** @def OP + * Wrapper which initializes an DISOPCODE. + * We must use this so that we can exclude unused fields in order + * to save precious bytes in the GC version. + * + * @internal + */ +#if DISOPCODE_FORMAT == 0 +# define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \ + { pszOpcode, idxParse1, idxParse2, idxParse3, 0, opcode, param1, param2, param3, 0, 0, optype } +# define OPVEX(pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, optype) \ + { pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, 0, optype | DISOPTYPE_SSE } + +#elif DISOPCODE_FORMAT == 16 +# define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \ + { optype, opcode, idxParse1, idxParse2, param1, param2, idxParse3, param3, 0, 0 } +# define OPVEX(pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, optype) \ + { optype | DISOPTYPE_SSE, opcode, idxParse1, idxParse2, param1, param2, idxParse3, param3, param4, idxParse4 } + +#elif DISOPCODE_FORMAT == 15 +# define OP(pszOpcode, idxParse1, idxParse2, idxParse3, opcode, param1, param2, param3, optype) \ + { opcode, idxParse1, idxParse2, idxParse3, param1, param2, param3, optype, 0, 0 } +# define OPVEX(pszOpcode, idxParse1, idxParse2, idxParse3, idxParse4, opcode, param1, param2, param3, param4, optype) \ + { opcode, idxParse1, idxParse2, idxParse3, param1, param2, param3, optype | DISOPTYPE_SSE, param4, idxParse4 } +#else +# error Unsupported DISOPCODE_FORMAT value +#endif + + +size_t disFormatBytes(PCDISSTATE pDis, char *pszDst, size_t cchDst, uint32_t fFlags); + +/** @} */ +#endif /* !VBOX_INCLUDED_SRC_DisasmInternal_h */ + diff --git a/src/VBox/Disassembler/DisasmMisc.cpp b/src/VBox/Disassembler/DisasmMisc.cpp new file mode 100644 index 00000000..16d90e8d --- /dev/null +++ b/src/VBox/Disassembler/DisasmMisc.cpp @@ -0,0 +1,175 @@ +/* $Id: DisasmMisc.cpp $ */ +/** @file + * VBox disassembler- Misc Helpers. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DIS +#include <VBox/dis.h> +#include <VBox/disopcode.h> +#include <iprt/errcore.h> +#include <VBox/log.h> +#include <VBox/vmm/cpum.h> +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/stdarg.h> +#include "DisasmInternal.h" + + +DISDECL(uint8_t) DISGetParamSize(PCDISSTATE pDis, PCDISOPPARAM pParam) +{ + unsigned subtype = OP_PARM_VSUBTYPE(pParam->fParam); + switch (subtype) + { + case OP_PARM_v: + switch (pDis->uOpMode) + { + case DISCPUMODE_32BIT: + return 4; + case DISCPUMODE_64BIT: + return 8; + case DISCPUMODE_16BIT: + return 2; + default: AssertFailed(); /* make gcc happy */ return 4; + } + break; + + case OP_PARM_b: + return 1; + + case OP_PARM_w: + return 2; + + case OP_PARM_d: + return 4; + + case OP_PARM_q: + return 8; + + case OP_PARM_dq: + return 16; + + case OP_PARM_qq: + return 32; + + case 0: /* nop, pause, lea, wrmsr, rdmsr, etc. Most of these due to DISOPPARAM::cb being initialized in the wrong place + (disParseInstruction) where it will be called on intermediate stuff like IDX_ParseTwoByteEsc. The parameter + parsers should do it instead, though I see the potential filtering issue. */ + //Assert( pDis->pCurInstr + // && ( pDis->pCurInstr->uOpcode == OP_NOP + // || pDis->pCurInstr->uOpcode == OP_LEA )); + return 0; + + case OP_PARM_p: /* far pointer */ + if (pDis->uAddrMode == DISCPUMODE_32BIT) + return 6; /* 16:32 */ + if (pDis->uAddrMode == DISCPUMODE_64BIT) + return 12; /* 16:64 */ + return 4; /* 16:16 */ + + case OP_PARM_s: /* lgdt, sgdt, lidt, sidt */ + return pDis->uCpuMode == DISCPUMODE_64BIT ? 2 + 8 : 2 + 4; + + case OP_PARM_a: + return pDis->uOpMode == DISCPUMODE_16BIT ? 2 + 2 : 4 + 4; + + case OP_PARM_pi: + return 8; + + case OP_PARM_sd: + case OP_PARM_ss: + return 16; + + case OP_PARM_x: + case OP_PARM_pd: + case OP_PARM_ps: + return VEXREG_IS256B(pDis->bVexDestReg) ? 32 : 16; //?? + + case OP_PARM_y: + return pDis->uOpMode == DISCPUMODE_64BIT ? 4 : 8; //?? + + case OP_PARM_z: + if (pParam->cb) + return pParam->cb; + return pDis->uOpMode == DISCPUMODE_16BIT ? 2 : 4; //?? + + default: + if (pParam->cb) + return pParam->cb; + /// @todo dangerous!!! + AssertMsgFailed(("subtype=%#x fParam=%#x fUse=%#RX64 op=%#x\n", subtype, pParam->fParam, pParam->fUse, + pDis->pCurInstr ? pDis->pCurInstr->uOpcode : 0)); + return 4; + } +} + +#if 0 /* currently unused */ +DISDECL(DISSELREG) DISDetectSegReg(PCDISSTATE pDis, PCDISOPPARAM pParam) +{ + if (pDis->fPrefix & DISPREFIX_SEG) + /* Use specified SEG: prefix. */ + return (DISSELREG)pDis->idxSegPrefix; + + /* Guess segment register by parameter type. */ + if (pParam->fUse & (DISUSE_REG_GEN32|DISUSE_REG_GEN64|DISUSE_REG_GEN16)) + { + AssertCompile(DISGREG_ESP == DISGREG_RSP); + AssertCompile(DISGREG_EBP == DISGREG_RBP); + AssertCompile(DISGREG_ESP == DISGREG_SP); + AssertCompile(DISGREG_EBP == DISGREG_BP); + if (pParam->Base.idxGenReg == DISGREG_ESP || pParam->Base.idxGenReg == DISGREG_EBP) + return DISSELREG_SS; + } + /* Default is use DS: for data access. */ + return DISSELREG_DS; +} + + +DISDECL(uint8_t) DISQuerySegPrefixByte(PCDISSTATE pDis) +{ + Assert(pDis->fPrefix & DISPREFIX_SEG); + switch (pDis->idxSegPrefix) + { + case DISSELREG_ES: + return 0x26; + case DISSELREG_CS: + return 0x2E; + case DISSELREG_SS: + return 0x36; + case DISSELREG_DS: + return 0x3E; + case DISSELREG_FS: + return 0x64; + case DISSELREG_GS: + return 0x65; + default: + AssertFailed(); + return 0; + } +} +#endif diff --git a/src/VBox/Disassembler/DisasmReg.cpp b/src/VBox/Disassembler/DisasmReg.cpp new file mode 100644 index 00000000..155e525b --- /dev/null +++ b/src/VBox/Disassembler/DisasmReg.cpp @@ -0,0 +1,685 @@ +/* $Id: DisasmReg.cpp $ */ +/** @file + * VBox disassembler- Register Info Helpers. + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#define LOG_GROUP LOG_GROUP_DIS +#include <VBox/dis.h> +#include <VBox/disopcode.h> +#include <iprt/errcore.h> +#include <VBox/log.h> +#include <VBox/vmm/cpum.h> +#include <iprt/assert.h> +#include <iprt/string.h> +#include <iprt/stdarg.h> +#include "DisasmInternal.h" + + +/********************************************************************************************************************************* +* Global Variables * +*********************************************************************************************************************************/ +/** + * Array for accessing 64-bit general registers in VMMREGFRAME structure + * by register's index from disasm. + */ +static const unsigned g_aReg64Index[] = +{ + RT_OFFSETOF(CPUMCTXCORE, rax), /* DISGREG_RAX */ + RT_OFFSETOF(CPUMCTXCORE, rcx), /* DISGREG_RCX */ + RT_OFFSETOF(CPUMCTXCORE, rdx), /* DISGREG_RDX */ + RT_OFFSETOF(CPUMCTXCORE, rbx), /* DISGREG_RBX */ + RT_OFFSETOF(CPUMCTXCORE, rsp), /* DISGREG_RSP */ + RT_OFFSETOF(CPUMCTXCORE, rbp), /* DISGREG_RBP */ + RT_OFFSETOF(CPUMCTXCORE, rsi), /* DISGREG_RSI */ + RT_OFFSETOF(CPUMCTXCORE, rdi), /* DISGREG_RDI */ + RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8 */ + RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9 */ + RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R10 */ + RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11 */ + RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12 */ + RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13 */ + RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14 */ + RT_OFFSETOF(CPUMCTXCORE, r15) /* DISGREG_R15 */ +}; + +/** + * Macro for accessing 64-bit general purpose registers in CPUMCTXCORE structure. + */ +#define DIS_READ_REG64(p, idx) (*(uint64_t *)((char *)(p) + g_aReg64Index[idx])) +#define DIS_WRITE_REG64(p, idx, val) (*(uint64_t *)((char *)(p) + g_aReg64Index[idx]) = val) +#define DIS_PTR_REG64(p, idx) ( (uint64_t *)((char *)(p) + g_aReg64Index[idx])) + +/** + * Array for accessing 32-bit general registers in VMMREGFRAME structure + * by register's index from disasm. + */ +static const unsigned g_aReg32Index[] = +{ + RT_OFFSETOF(CPUMCTXCORE, eax), /* DISGREG_EAX */ + RT_OFFSETOF(CPUMCTXCORE, ecx), /* DISGREG_ECX */ + RT_OFFSETOF(CPUMCTXCORE, edx), /* DISGREG_EDX */ + RT_OFFSETOF(CPUMCTXCORE, ebx), /* DISGREG_EBX */ + RT_OFFSETOF(CPUMCTXCORE, esp), /* DISGREG_ESP */ + RT_OFFSETOF(CPUMCTXCORE, ebp), /* DISGREG_EBP */ + RT_OFFSETOF(CPUMCTXCORE, esi), /* DISGREG_ESI */ + RT_OFFSETOF(CPUMCTXCORE, edi), /* DISGREG_EDI */ + RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8D */ + RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9D */ + RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R1D */ + RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11D */ + RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12D */ + RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13D */ + RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14D */ + RT_OFFSETOF(CPUMCTXCORE, r15) /* DISGREG_R15D */ +}; + +/** + * Macro for accessing 32-bit general purpose registers in CPUMCTXCORE structure. + */ +#define DIS_READ_REG32(p, idx) (*(uint32_t *)((char *)(p) + g_aReg32Index[idx])) +/* From http://www.cs.cmu.edu/~fp/courses/15213-s06/misc/asm64-handout.pdf: + * ``Perhaps unexpectedly, instructions that move or generate 32-bit register + * values also set the upper 32 bits of the register to zero. Consequently + * there is no need for an instruction movzlq.'' + */ +#define DIS_WRITE_REG32(p, idx, val) (*(uint64_t *)((char *)(p) + g_aReg32Index[idx]) = (uint32_t)val) +#define DIS_PTR_REG32(p, idx) ( (uint32_t *)((char *)(p) + g_aReg32Index[idx])) + +/** + * Array for accessing 16-bit general registers in CPUMCTXCORE structure + * by register's index from disasm. + */ +static const unsigned g_aReg16Index[] = +{ + RT_OFFSETOF(CPUMCTXCORE, eax), /* DISGREG_AX */ + RT_OFFSETOF(CPUMCTXCORE, ecx), /* DISGREG_CX */ + RT_OFFSETOF(CPUMCTXCORE, edx), /* DISGREG_DX */ + RT_OFFSETOF(CPUMCTXCORE, ebx), /* DISGREG_BX */ + RT_OFFSETOF(CPUMCTXCORE, esp), /* DISGREG_SP */ + RT_OFFSETOF(CPUMCTXCORE, ebp), /* DISGREG_BP */ + RT_OFFSETOF(CPUMCTXCORE, esi), /* DISGREG_SI */ + RT_OFFSETOF(CPUMCTXCORE, edi), /* DISGREG_DI */ + RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8W */ + RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9W */ + RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R10W */ + RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11W */ + RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12W */ + RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13W */ + RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14W */ + RT_OFFSETOF(CPUMCTXCORE, r15) /* DISGREG_R15W */ +}; + +/** + * Macro for accessing 16-bit general purpose registers in CPUMCTXCORE structure. + */ +#define DIS_READ_REG16(p, idx) (*(uint16_t *)((char *)(p) + g_aReg16Index[idx])) +#define DIS_WRITE_REG16(p, idx, val) (*(uint16_t *)((char *)(p) + g_aReg16Index[idx]) = val) +#define DIS_PTR_REG16(p, idx) ( (uint16_t *)((char *)(p) + g_aReg16Index[idx])) + +/** + * Array for accessing 8-bit general registers in CPUMCTXCORE structure + * by register's index from disasm. + */ +static const unsigned g_aReg8Index[] = +{ + RT_OFFSETOF(CPUMCTXCORE, eax), /* DISGREG_AL */ + RT_OFFSETOF(CPUMCTXCORE, ecx), /* DISGREG_CL */ + RT_OFFSETOF(CPUMCTXCORE, edx), /* DISGREG_DL */ + RT_OFFSETOF(CPUMCTXCORE, ebx), /* DISGREG_BL */ + RT_OFFSETOF_ADD(CPUMCTXCORE, eax, 1), /* DISGREG_AH */ + RT_OFFSETOF_ADD(CPUMCTXCORE, ecx, 1), /* DISGREG_CH */ + RT_OFFSETOF_ADD(CPUMCTXCORE, edx, 1), /* DISGREG_DH */ + RT_OFFSETOF_ADD(CPUMCTXCORE, ebx, 1), /* DISGREG_BH */ + RT_OFFSETOF(CPUMCTXCORE, r8), /* DISGREG_R8B */ + RT_OFFSETOF(CPUMCTXCORE, r9), /* DISGREG_R9B */ + RT_OFFSETOF(CPUMCTXCORE, r10), /* DISGREG_R10B*/ + RT_OFFSETOF(CPUMCTXCORE, r11), /* DISGREG_R11B */ + RT_OFFSETOF(CPUMCTXCORE, r12), /* DISGREG_R12B */ + RT_OFFSETOF(CPUMCTXCORE, r13), /* DISGREG_R13B */ + RT_OFFSETOF(CPUMCTXCORE, r14), /* DISGREG_R14B */ + RT_OFFSETOF(CPUMCTXCORE, r15), /* DISGREG_R15B */ + RT_OFFSETOF(CPUMCTXCORE, esp), /* DISGREG_SPL; with REX prefix only */ + RT_OFFSETOF(CPUMCTXCORE, ebp), /* DISGREG_BPL; with REX prefix only */ + RT_OFFSETOF(CPUMCTXCORE, esi), /* DISGREG_SIL; with REX prefix only */ + RT_OFFSETOF(CPUMCTXCORE, edi) /* DISGREG_DIL; with REX prefix only */ +}; + +/** + * Macro for accessing 8-bit general purpose registers in CPUMCTXCORE structure. + */ +#define DIS_READ_REG8(p, idx) (*(uint8_t *)((char *)(p) + g_aReg8Index[idx])) +#define DIS_WRITE_REG8(p, idx, val) (*(uint8_t *)((char *)(p) + g_aReg8Index[idx]) = val) +#define DIS_PTR_REG8(p, idx) ( (uint8_t *)((char *)(p) + g_aReg8Index[idx])) + +/** + * Array for accessing segment registers in CPUMCTXCORE structure + * by register's index from disasm. + */ +static const unsigned g_aRegSegIndex[] = +{ + RT_OFFSETOF(CPUMCTXCORE, es), /* DISSELREG_ES */ + RT_OFFSETOF(CPUMCTXCORE, cs), /* DISSELREG_CS */ + RT_OFFSETOF(CPUMCTXCORE, ss), /* DISSELREG_SS */ + RT_OFFSETOF(CPUMCTXCORE, ds), /* DISSELREG_DS */ + RT_OFFSETOF(CPUMCTXCORE, fs), /* DISSELREG_FS */ + RT_OFFSETOF(CPUMCTXCORE, gs) /* DISSELREG_GS */ +}; + +/** + * Macro for accessing segment registers in CPUMCTXCORE structure. + */ +#define DIS_READ_REGSEG(p, idx) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx]))) +#define DIS_WRITE_REGSEG(p, idx, val) (*((uint16_t *)((char *)(p) + g_aRegSegIndex[idx])) = val) + + + +/** + * Returns the value of the specified 8 bits general purpose register + * + */ +DISDECL(int) DISFetchReg8(PCCPUMCTXCORE pCtx, unsigned reg8, uint8_t *pVal) +{ + AssertReturnStmt(reg8 < RT_ELEMENTS(g_aReg8Index), *pVal = 0, VERR_INVALID_PARAMETER); + + *pVal = DIS_READ_REG8(pCtx, reg8); + return VINF_SUCCESS; +} + +/** + * Returns the value of the specified 16 bits general purpose register + * + */ +DISDECL(int) DISFetchReg16(PCCPUMCTXCORE pCtx, unsigned reg16, uint16_t *pVal) +{ + AssertReturnStmt(reg16 < RT_ELEMENTS(g_aReg16Index), *pVal = 0, VERR_INVALID_PARAMETER); + + *pVal = DIS_READ_REG16(pCtx, reg16); + return VINF_SUCCESS; +} + +/** + * Returns the value of the specified 32 bits general purpose register + * + */ +DISDECL(int) DISFetchReg32(PCCPUMCTXCORE pCtx, unsigned reg32, uint32_t *pVal) +{ + AssertReturnStmt(reg32 < RT_ELEMENTS(g_aReg32Index), *pVal = 0, VERR_INVALID_PARAMETER); + + *pVal = DIS_READ_REG32(pCtx, reg32); + return VINF_SUCCESS; +} + +/** + * Returns the value of the specified 64 bits general purpose register + * + */ +DISDECL(int) DISFetchReg64(PCCPUMCTXCORE pCtx, unsigned reg64, uint64_t *pVal) +{ + AssertReturnStmt(reg64 < RT_ELEMENTS(g_aReg64Index), *pVal = 0, VERR_INVALID_PARAMETER); + + *pVal = DIS_READ_REG64(pCtx, reg64); + return VINF_SUCCESS; +} + +/** + * Returns the pointer to the specified 8 bits general purpose register + * + */ +DISDECL(int) DISPtrReg8(PCPUMCTXCORE pCtx, unsigned reg8, uint8_t **ppReg) +{ + AssertReturnStmt(reg8 < RT_ELEMENTS(g_aReg8Index), *ppReg = NULL, VERR_INVALID_PARAMETER); + + *ppReg = DIS_PTR_REG8(pCtx, reg8); + return VINF_SUCCESS; +} + +/** + * Returns the pointer to the specified 16 bits general purpose register + * + */ +DISDECL(int) DISPtrReg16(PCPUMCTXCORE pCtx, unsigned reg16, uint16_t **ppReg) +{ + AssertReturnStmt(reg16 < RT_ELEMENTS(g_aReg16Index), *ppReg = NULL, VERR_INVALID_PARAMETER); + + *ppReg = DIS_PTR_REG16(pCtx, reg16); + return VINF_SUCCESS; +} + +/** + * Returns the pointer to the specified 32 bits general purpose register + */ +DISDECL(int) DISPtrReg32(PCPUMCTXCORE pCtx, unsigned reg32, uint32_t **ppReg) +{ + AssertReturnStmt(reg32 < RT_ELEMENTS(g_aReg32Index), *ppReg = NULL, VERR_INVALID_PARAMETER); + + *ppReg = DIS_PTR_REG32(pCtx, reg32); + return VINF_SUCCESS; +} + +/** + * Returns the pointer to the specified 64 bits general purpose register + */ +DISDECL(int) DISPtrReg64(PCPUMCTXCORE pCtx, unsigned reg64, uint64_t **ppReg) +{ + AssertReturnStmt(reg64 < RT_ELEMENTS(g_aReg64Index), *ppReg = NULL, VERR_INVALID_PARAMETER); + + *ppReg = DIS_PTR_REG64(pCtx, reg64); + return VINF_SUCCESS; +} + +/** + * Returns the value of the specified segment register + */ +DISDECL(int) DISFetchRegSeg(PCCPUMCTXCORE pCtx, DISSELREG sel, RTSEL *pVal) +{ + AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER); + + AssertCompile(sizeof(uint16_t) == sizeof(RTSEL)); + *pVal = DIS_READ_REGSEG(pCtx, sel); + return VINF_SUCCESS; +} + +/** + * Updates the value of the specified 64 bits general purpose register + * + */ +DISDECL(int) DISWriteReg64(PCPUMCTXCORE pRegFrame, unsigned reg64, uint64_t val64) +{ + AssertReturn(reg64 < RT_ELEMENTS(g_aReg64Index), VERR_INVALID_PARAMETER); + + DIS_WRITE_REG64(pRegFrame, reg64, val64); + return VINF_SUCCESS; +} + +/** + * Updates the value of the specified 32 bits general purpose register + * + */ +DISDECL(int) DISWriteReg32(PCPUMCTXCORE pRegFrame, unsigned reg32, uint32_t val32) +{ + AssertReturn(reg32 < RT_ELEMENTS(g_aReg32Index), VERR_INVALID_PARAMETER); + + DIS_WRITE_REG32(pRegFrame, reg32, val32); + return VINF_SUCCESS; +} + +/** + * Updates the value of the specified 16 bits general purpose register + * + */ +DISDECL(int) DISWriteReg16(PCPUMCTXCORE pRegFrame, unsigned reg16, uint16_t val16) +{ + AssertReturn(reg16 < RT_ELEMENTS(g_aReg16Index), VERR_INVALID_PARAMETER); + + DIS_WRITE_REG16(pRegFrame, reg16, val16); + return VINF_SUCCESS; +} + +/** + * Updates the specified 8 bits general purpose register + * + */ +DISDECL(int) DISWriteReg8(PCPUMCTXCORE pRegFrame, unsigned reg8, uint8_t val8) +{ + AssertReturn(reg8 < RT_ELEMENTS(g_aReg8Index), VERR_INVALID_PARAMETER); + + DIS_WRITE_REG8(pRegFrame, reg8, val8); + return VINF_SUCCESS; +} + +/** + * Updates the specified segment register + * + */ +DISDECL(int) DISWriteRegSeg(PCPUMCTXCORE pCtx, DISSELREG sel, RTSEL val) +{ + AssertReturn((unsigned)sel < RT_ELEMENTS(g_aRegSegIndex), VERR_INVALID_PARAMETER); + + AssertCompile(sizeof(uint16_t) == sizeof(RTSEL)); + DIS_WRITE_REGSEG(pCtx, sel, val); + return VINF_SUCCESS; +} + +/** + * Returns the value of the parameter in pParam + * + * @returns VBox error code + * @param pCtx CPU context structure pointer + * @param pDis Pointer to the disassembler state. + * @param pParam Pointer to the parameter to parse + * @param pParamVal Pointer to parameter value (OUT) + * @param parmtype Parameter type + * + * @note Currently doesn't handle FPU/XMM/MMX/3DNow! parameters correctly!! + * + */ +DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype) +{ + memset(pParamVal, 0, sizeof(*pParamVal)); + + if (DISUSE_IS_EFFECTIVE_ADDR(pParam->fUse)) + { + // Effective address + pParamVal->type = DISQPV_TYPE_ADDRESS; + pParamVal->size = pParam->cb; + + if (pParam->fUse & DISUSE_BASE) + { + if (pParam->fUse & DISUSE_REG_GEN8) + { + pParamVal->flags |= DISQPV_FLAG_8; + if (RT_FAILURE(DISFetchReg8(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER; + } + else + if (pParam->fUse & DISUSE_REG_GEN16) + { + pParamVal->flags |= DISQPV_FLAG_16; + if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER; + } + else + if (pParam->fUse & DISUSE_REG_GEN32) + { + pParamVal->flags |= DISQPV_FLAG_32; + if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER; + } + else + if (pParam->fUse & DISUSE_REG_GEN64) + { + pParamVal->flags |= DISQPV_FLAG_64; + if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER; + } + else + { + AssertFailed(); + return VERR_INVALID_PARAMETER; + } + } + // Note that scale implies index (SIB byte) + if (pParam->fUse & DISUSE_INDEX) + { + if (pParam->fUse & DISUSE_REG_GEN16) + { + uint16_t val16; + + pParamVal->flags |= DISQPV_FLAG_16; + if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Index.idxGenReg, &val16))) return VERR_INVALID_PARAMETER; + + Assert(!(pParam->fUse & DISUSE_SCALE)); /* shouldn't be possible in 16 bits mode */ + + pParamVal->val.val16 += val16; + } + else + if (pParam->fUse & DISUSE_REG_GEN32) + { + uint32_t val32; + + pParamVal->flags |= DISQPV_FLAG_32; + if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Index.idxGenReg, &val32))) return VERR_INVALID_PARAMETER; + + if (pParam->fUse & DISUSE_SCALE) + val32 *= pParam->uScale; + + pParamVal->val.val32 += val32; + } + else + if (pParam->fUse & DISUSE_REG_GEN64) + { + uint64_t val64; + + pParamVal->flags |= DISQPV_FLAG_64; + if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Index.idxGenReg, &val64))) return VERR_INVALID_PARAMETER; + + if (pParam->fUse & DISUSE_SCALE) + val64 *= pParam->uScale; + + pParamVal->val.val64 += val64; + } + else + AssertFailed(); + } + + if (pParam->fUse & DISUSE_DISPLACEMENT8) + { + if (pDis->uCpuMode == DISCPUMODE_32BIT) + pParamVal->val.i32 += (int32_t)pParam->uDisp.i8; + else if (pDis->uCpuMode == DISCPUMODE_64BIT) + pParamVal->val.i64 += (int64_t)pParam->uDisp.i8; + else + pParamVal->val.i16 += (int16_t)pParam->uDisp.i8; + } + else if (pParam->fUse & DISUSE_DISPLACEMENT16) + { + if (pDis->uCpuMode == DISCPUMODE_32BIT) + pParamVal->val.i32 += (int32_t)pParam->uDisp.i16; + else if (pDis->uCpuMode == DISCPUMODE_64BIT) + pParamVal->val.i64 += (int64_t)pParam->uDisp.i16; + else + pParamVal->val.i16 += pParam->uDisp.i16; + } + else if (pParam->fUse & DISUSE_DISPLACEMENT32) + { + if (pDis->uCpuMode == DISCPUMODE_32BIT) + pParamVal->val.i32 += pParam->uDisp.i32; + else + pParamVal->val.i64 += pParam->uDisp.i32; + } + else if (pParam->fUse & DISUSE_DISPLACEMENT64) + { + Assert(pDis->uCpuMode == DISCPUMODE_64BIT); + pParamVal->val.i64 += pParam->uDisp.i64; + } + else if (pParam->fUse & DISUSE_RIPDISPLACEMENT32) + { + Assert(pDis->uCpuMode == DISCPUMODE_64BIT); + /* Relative to the RIP of the next instruction. */ + pParamVal->val.i64 += pParam->uDisp.i32 + pCtx->rip + pDis->cbInstr; + } + return VINF_SUCCESS; + } + + if (pParam->fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32|DISUSE_REG_GEN64|DISUSE_REG_FP|DISUSE_REG_MMX|DISUSE_REG_XMM|DISUSE_REG_CR|DISUSE_REG_DBG|DISUSE_REG_SEG|DISUSE_REG_TEST)) + { + if (parmtype == DISQPVWHICH_DST) + { + // Caller needs to interpret the register according to the instruction (source/target, special value etc) + pParamVal->type = DISQPV_TYPE_REGISTER; + pParamVal->size = pParam->cb; + return VINF_SUCCESS; + } + //else DISQPVWHICH_SRC + + pParamVal->type = DISQPV_TYPE_IMMEDIATE; + + if (pParam->fUse & DISUSE_REG_GEN8) + { + pParamVal->flags |= DISQPV_FLAG_8; + pParamVal->size = sizeof(uint8_t); + if (RT_FAILURE(DISFetchReg8(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val8))) return VERR_INVALID_PARAMETER; + } + else + if (pParam->fUse & DISUSE_REG_GEN16) + { + pParamVal->flags |= DISQPV_FLAG_16; + pParamVal->size = sizeof(uint16_t); + if (RT_FAILURE(DISFetchReg16(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val16))) return VERR_INVALID_PARAMETER; + } + else + if (pParam->fUse & DISUSE_REG_GEN32) + { + pParamVal->flags |= DISQPV_FLAG_32; + pParamVal->size = sizeof(uint32_t); + if (RT_FAILURE(DISFetchReg32(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val32))) return VERR_INVALID_PARAMETER; + } + else + if (pParam->fUse & DISUSE_REG_GEN64) + { + pParamVal->flags |= DISQPV_FLAG_64; + pParamVal->size = sizeof(uint64_t); + if (RT_FAILURE(DISFetchReg64(pCtx, pParam->Base.idxGenReg, &pParamVal->val.val64))) return VERR_INVALID_PARAMETER; + } + else + { + // Caller needs to interpret the register according to the instruction (source/target, special value etc) + pParamVal->type = DISQPV_TYPE_REGISTER; + } + Assert(!(pParam->fUse & DISUSE_IMMEDIATE)); + return VINF_SUCCESS; + } + + if (pParam->fUse & DISUSE_IMMEDIATE) + { + pParamVal->type = DISQPV_TYPE_IMMEDIATE; + if (pParam->fUse & (DISUSE_IMMEDIATE8|DISUSE_IMMEDIATE8_REL)) + { + pParamVal->flags |= DISQPV_FLAG_8; + if (pParam->cb == 2) + { + pParamVal->size = sizeof(uint16_t); + pParamVal->val.val16 = (uint8_t)pParam->uValue; + } + else + { + pParamVal->size = sizeof(uint8_t); + pParamVal->val.val8 = (uint8_t)pParam->uValue; + } + } + else + if (pParam->fUse & (DISUSE_IMMEDIATE16|DISUSE_IMMEDIATE16_REL|DISUSE_IMMEDIATE_ADDR_0_16|DISUSE_IMMEDIATE16_SX8)) + { + pParamVal->flags |= DISQPV_FLAG_16; + pParamVal->size = sizeof(uint16_t); + pParamVal->val.val16 = (uint16_t)pParam->uValue; + AssertMsg(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE16_SX8)), ("pParamVal->size %d vs %d EIP=%RX32\n", pParamVal->size, pParam->cb, pCtx->eip) ); + } + else + if (pParam->fUse & (DISUSE_IMMEDIATE32|DISUSE_IMMEDIATE32_REL|DISUSE_IMMEDIATE_ADDR_0_32|DISUSE_IMMEDIATE32_SX8)) + { + pParamVal->flags |= DISQPV_FLAG_32; + pParamVal->size = sizeof(uint32_t); + pParamVal->val.val32 = (uint32_t)pParam->uValue; + Assert(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE32_SX8)) ); + } + else + if (pParam->fUse & (DISUSE_IMMEDIATE64 | DISUSE_IMMEDIATE64_REL | DISUSE_IMMEDIATE64_SX8)) + { + pParamVal->flags |= DISQPV_FLAG_64; + pParamVal->size = sizeof(uint64_t); + pParamVal->val.val64 = pParam->uValue; + Assert(pParamVal->size == pParam->cb || ((pParam->cb == 1) && (pParam->fUse & DISUSE_IMMEDIATE64_SX8)) ); + } + else + if (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16)) + { + pParamVal->flags |= DISQPV_FLAG_FARPTR16; + pParamVal->size = sizeof(uint16_t)*2; + pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->uValue >> 16); + pParamVal->val.farptr.offset = (uint32_t)RT_LOWORD(pParam->uValue); + Assert(pParamVal->size == pParam->cb); + } + else + if (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_32)) + { + pParamVal->flags |= DISQPV_FLAG_FARPTR32; + pParamVal->size = sizeof(uint16_t) + sizeof(uint32_t); + pParamVal->val.farptr.sel = (uint16_t)RT_LOWORD(pParam->uValue >> 32); + pParamVal->val.farptr.offset = (uint32_t)(pParam->uValue & 0xFFFFFFFF); + Assert(pParam->cb == 8); + } + } + return VINF_SUCCESS; +} + +/** + * Returns the pointer to a register of the parameter in pParam. We need this + * pointer when an interpreted instruction updates a register as a side effect. + * In CMPXCHG we know that only [r/e]ax is updated, but with XADD this could + * be every register. + * + * @returns VBox error code + * @param pCtx CPU context structure pointer + * @param pDis Pointer to the disassembler state. + * @param pParam Pointer to the parameter to parse + * @param pReg Pointer to parameter value (OUT) + * @param cbsize Parameter size (OUT) + * + * @note Currently doesn't handle FPU/XMM/MMX/3DNow! parameters correctly!! + * + */ +DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, void **ppReg, size_t *pcbSize) +{ + NOREF(pDis); + if (pParam->fUse & (DISUSE_REG_GEN8|DISUSE_REG_GEN16|DISUSE_REG_GEN32|DISUSE_REG_FP|DISUSE_REG_MMX|DISUSE_REG_XMM|DISUSE_REG_CR|DISUSE_REG_DBG|DISUSE_REG_SEG|DISUSE_REG_TEST)) + { + if (pParam->fUse & DISUSE_REG_GEN8) + { + uint8_t *pu8Reg; + if (RT_SUCCESS(DISPtrReg8(pCtx, pParam->Base.idxGenReg, &pu8Reg))) + { + *pcbSize = sizeof(uint8_t); + *ppReg = (void *)pu8Reg; + return VINF_SUCCESS; + } + } + else + if (pParam->fUse & DISUSE_REG_GEN16) + { + uint16_t *pu16Reg; + if (RT_SUCCESS(DISPtrReg16(pCtx, pParam->Base.idxGenReg, &pu16Reg))) + { + *pcbSize = sizeof(uint16_t); + *ppReg = (void *)pu16Reg; + return VINF_SUCCESS; + } + } + else + if (pParam->fUse & DISUSE_REG_GEN32) + { + uint32_t *pu32Reg; + if (RT_SUCCESS(DISPtrReg32(pCtx, pParam->Base.idxGenReg, &pu32Reg))) + { + *pcbSize = sizeof(uint32_t); + *ppReg = (void *)pu32Reg; + return VINF_SUCCESS; + } + } + else + if (pParam->fUse & DISUSE_REG_GEN64) + { + uint64_t *pu64Reg; + if (RT_SUCCESS(DISPtrReg64(pCtx, pParam->Base.idxGenReg, &pu64Reg))) + { + *pcbSize = sizeof(uint64_t); + *ppReg = (void *)pu64Reg; + return VINF_SUCCESS; + } + } + } + return VERR_INVALID_PARAMETER; +} + diff --git a/src/VBox/Disassembler/DisasmTables.cpp b/src/VBox/Disassembler/DisasmTables.cpp new file mode 100644 index 00000000..d7971cdf --- /dev/null +++ b/src/VBox/Disassembler/DisasmTables.cpp @@ -0,0 +1,4320 @@ +/* $Id: DisasmTables.cpp $ */ +/** @file + * VBox disassembler - Tables for X86 (32-bit and 16-bit modes). + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/dis.h> +#include <VBox/disopcode.h> +#include "DisasmInternal.h" + + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +/// @todo Verify tables for correctness +/// @todo opcode type (harmless, potentially dangerous, dangerous) +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef DIS_CORE_ONLY +static char g_szInvalidOpcode[] = "Invalid Opcode"; +#endif + +#define INVALID_OPCODE \ + OP(g_szInvalidOpcode, 0, 0, 0, OP_INVALID, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INVALID) +#define INVALID_OPCODE_BLOCK \ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE, + +#define INVALID_OPCODE_MOD_RM(a_Index) \ + OP(g_szInvalidOpcode, IDX_ParseInvOpModRM, 0, 0, OP_INVALID, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INVALID) +#define INVALID_OPCODE_BLOCK_MOD_RM(a_UpperDigit) \ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 0),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 1),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 2),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 3),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 4),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 5),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 6),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 7),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 8),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## 9),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## a),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## b),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## c),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## d),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## e),\ + INVALID_OPCODE_MOD_RM(a_UpperDigit ## f), + + +/* Invalid opcode */ +const DISOPCODE g_InvalidOpcode[1] = +{ + INVALID_OPCODE +}; + +/* Tables for the elegant Intel X86 instruction set */ +const DISOPCODE g_aOneByteMapX86[256] = +{ + /* 0 */ + OP("add %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_ADD, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_ADD, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("push ES", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ES, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("pop ES", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ES, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("or %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_OR, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_OR, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("push CS", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_CS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64 | DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("EscTwo0f", IDX_ParseTwoByteEsc, 0, 0, OP_2B_ESC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 1 */ + OP("adc %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_ADC, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_ADC, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("push SS", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_SS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64 | DISOPTYPE_RRM_DANGEROUS), + OP("pop SS", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_SS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INHIBIT_IRQS | DISOPTYPE_INVALID_64 | DISOPTYPE_RRM_DANGEROUS), + OP("sbb %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_SBB, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_SBB, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("push DS", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_DS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("pop DS", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_DS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64 | DISOPTYPE_RRM_DANGEROUS), + + /* 2 */ + OP("and %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_AND, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_AND, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG ES", 0, 0, 0, OP_SEG, OP_PARM_REG_ES, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("daa", 0, 0, 0, OP_DAA, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("sub %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_SUB, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_SUB, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* Branch not taken hint prefix for branches on a Pentium 4 or Xeon CPU (or higher)! */ + OP("SEG CS", 0, 0, 0, OP_SEG, OP_PARM_REG_CS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("das", 0, 0, 0, OP_DAS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + + /* 3 */ + OP("xor %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_XOR, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_XOR, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG SS", 0, 0, 0, OP_SEG, OP_PARM_REG_SS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aaa", 0, 0, 0, OP_AAA, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("cmp %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_CMP, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_CMP, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* Branch not taken hint prefix for branches on a Pentium 4 or Xeon CPU (or higher)! */ + OP("SEG DS", 0, 0, 0, OP_SEG, OP_PARM_REG_DS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aas", 0, 0, 0, OP_AAS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + + /* 4 */ + OP("inc %eAX", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eCX", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eDX", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eBX", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eSP", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eBP", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eSI", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc %eDI", IDX_ParseFixedReg, 0, 0, OP_INC, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eAX", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eCX", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eDX", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eBX", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eSP", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eBP", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eSI", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %eDI", IDX_ParseFixedReg, 0, 0, OP_DEC, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 5 */ + OP("push %eAX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eCX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eDX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eBX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eSP", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eBP", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eSI", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eDI", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eAX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eCX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eDX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eBX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eSP", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eBP", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eSI", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eDI", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + + /* 6 */ + OP("pusha", 0, 0, 0, OP_PUSHA, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("popa", 0, 0, 0, OP_POPA, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("bound %Gv,%Ma", IDX_ParseModRM, IDX_UseModRM, 0, OP_BOUND, OP_PARM_Gv, OP_PARM_Ma, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("arpl %Ew,%Gw", IDX_ParseModRM, IDX_UseModRM, 0, OP_ARPL, OP_PARM_Ew, OP_PARM_Gw, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG FS", 0, 0, 0, OP_SEG, OP_PARM_REG_FS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG GS", 0, 0, 0, OP_SEG, OP_PARM_REG_GS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("OP SIZE", 0, 0, 0, OP_OPSIZE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ADR SIZE", 0, 0, 0, OP_ADDRSIZE,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("push %Iz", IDX_ParseImmZ, 0, 0, OP_PUSH, OP_PARM_Iz, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("imul %Gv,%Ev,%Iz", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmZ, OP_IMUL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_Iz, DISOPTYPE_HARMLESS), + OP("push %Ib", IDX_ParseImmByteSX, 0, 0, OP_PUSH, OP_PARM_Ib, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("imul %Gv,%Ev,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByteSX, OP_IMUL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("insb %Yb,DX", IDX_ParseYb, IDX_ParseFixedReg, 0, OP_INSB, OP_PARM_Yb, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("insw/d %Yv,DX", IDX_ParseYv, IDX_ParseFixedReg, 0, OP_INSWD, OP_PARM_Yv, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("outsb DX,%Xb", IDX_ParseFixedReg, IDX_ParseXb, 0, OP_OUTSB, OP_PARM_REG_DX, OP_PARM_Yb, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("outsw/d DX,%Xv", IDX_ParseFixedReg, IDX_ParseXv, 0, OP_OUTSWD, OP_PARM_REG_DX, OP_PARM_Yv, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + + + /* 7 */ + OP("jo %Jb", IDX_ParseImmBRel, 0, 0, OP_JO, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jno %Jb", IDX_ParseImmBRel, 0, 0, OP_JNO, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jc %Jb", IDX_ParseImmBRel, 0, 0, OP_JC, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jnc %Jb", IDX_ParseImmBRel, 0, 0, OP_JNC, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("je %Jb", IDX_ParseImmBRel, 0, 0, OP_JE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jne %Jb", IDX_ParseImmBRel, 0, 0, OP_JNE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jbe %Jb", IDX_ParseImmBRel, 0, 0, OP_JBE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jnbe %Jb", IDX_ParseImmBRel, 0, 0, OP_JNBE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("js %Jb", IDX_ParseImmBRel, 0, 0, OP_JS, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jns %Jb", IDX_ParseImmBRel, 0, 0, OP_JNS, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jp %Jb", IDX_ParseImmBRel, 0, 0, OP_JP, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jnp %Jb", IDX_ParseImmBRel, 0, 0, OP_JNP, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jl %Jb", IDX_ParseImmBRel, 0, 0, OP_JL, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jnl %Jb", IDX_ParseImmBRel, 0, 0, OP_JNL, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jle %Jb", IDX_ParseImmBRel, 0, 0, OP_JLE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("jnle %Jb", IDX_ParseImmBRel, 0, 0, OP_JNLE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + + /* 8 */ + OP("Imm Grp1 %Eb,%Ib", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Imm Grp1 %Ev,%Iz", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Ev, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Imm Grp1 %Eb,%Ib", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("Imm Grp1 %Ev,%Ib", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Ev, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_TEST, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_TEST, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xchg %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XCHG, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xchg %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_XCHG, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ev,%Sw", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Sw, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("lea %Gv,%M", IDX_ParseModRM, IDX_UseModRM, 0, OP_LEA, OP_PARM_Gv, OP_PARM_M, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Sw,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Sw, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS | DISOPTYPE_INHIBIT_IRQS), + /** @todo this is grp 1a, actually */ + OP("pop %Ev", IDX_ParseModRM, 0, 0, OP_POP, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 9 */ + OP("nop/pause/xchg %eAX,%eAX", IDX_ParseNopPause, 0, 0, OP_NOP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xchg %eCX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_ECX, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eDX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EDX, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eBX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EBX, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eSP,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_ESP, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eBP,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EBP, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eSI,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_ESI, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eDI,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EDI, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("cbw", 0, 0, 0, OP_CBW, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cwd", 0, 0, 0, OP_CWD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("call %Ap", IDX_ParseImmAddrF, 0, 0, OP_CALL, OP_PARM_Ap, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_INVALID_64), + OP("wait", 0, 0, 0, OP_WAIT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pushf %Fv", 0, 0, 0, OP_PUSHF, OP_PARM_Fv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("popf %Fv", 0, 0, 0, OP_POPF, OP_PARM_Fv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("sahf", 0, 0, 0, OP_SAHF, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lahf", 0, 0, 0, OP_LAHF, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* A */ + OP("mov AL,%Ob", IDX_ParseFixedReg, IDX_ParseImmAddr, 0, OP_MOV, OP_PARM_REG_AL, OP_PARM_Ob, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %eAX,%Ov", IDX_ParseFixedReg, IDX_ParseImmAddr, 0, OP_MOV, OP_PARM_REG_EAX, OP_PARM_Ov, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ob,AL", IDX_ParseImmAddr, IDX_ParseFixedReg, 0, OP_MOV, OP_PARM_Ob, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ov,%eAX", IDX_ParseImmAddr, IDX_ParseFixedReg, 0, OP_MOV, OP_PARM_Ov, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsb %Xb,%Yb", IDX_ParseXb, IDX_ParseYb, 0, OP_MOVSB, OP_PARM_Xb, OP_PARM_Yb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsw/d %Xv,%Yv", IDX_ParseXv, IDX_ParseYv, 0, OP_MOVSWD, OP_PARM_Xv, OP_PARM_Yv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmpsb %Xb,%Yb", IDX_ParseXb, IDX_ParseYb, 0, OP_CMPSB, OP_PARM_Xb, OP_PARM_Yb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmpsw/d %Xv,%Yv", IDX_ParseXv, IDX_ParseYv, 0, OP_CMPWD, OP_PARM_Xv, OP_PARM_Yv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_TEST, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_TEST, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stosb %Yb,AL", IDX_ParseYb, IDX_ParseFixedReg, 0, OP_STOSB, OP_PARM_Yb, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stosw/d %Yv,%eAX", IDX_ParseYv, IDX_ParseFixedReg, 0, OP_STOSWD, OP_PARM_Yv, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lodsb AL,%Xb", IDX_ParseFixedReg, IDX_ParseXb, 0, OP_LODSB, OP_PARM_REG_AL, OP_PARM_Xb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lodsw/d %eAX,%Xv", IDX_ParseFixedReg, IDX_ParseXv, 0, OP_LODSWD, OP_PARM_REG_EAX, OP_PARM_Xv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("scasb AL,%Xb", IDX_ParseFixedReg, IDX_ParseXb, 0, OP_SCASB, OP_PARM_REG_AL, OP_PARM_Xb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("scasw/d %eAX,%Xv", IDX_ParseFixedReg, IDX_ParseXv, 0, OP_SCASWD, OP_PARM_REG_EAX, OP_PARM_Xv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* B */ + OP("mov AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov CL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_CL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov DL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_DL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov BL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_BL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov AH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_AH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov CH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_CH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov DH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_DH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov BH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_BH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eAX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EAX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eCX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_ECX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eDX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EDX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eBX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EBX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eSP,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_ESP, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eBP,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EBP, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eSI,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_ESI, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eDI,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EDI, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + + /* C */ + OP("Shift Grp2 %Eb,%Ib", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Ev,%Ib", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Ev, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("retn %Iw", IDX_ParseImmUshort, 0, 0, OP_RETN, OP_PARM_Iw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("retn", 0, 0, 0, OP_RETN, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("les %Gv,%Mp", IDX_ParseModRM, IDX_UseModRM, 0, OP_LES, OP_PARM_Gv, OP_PARM_Mp, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("lds %Gv,%Mp", IDX_ParseModRM, IDX_UseModRM, 0, OP_LDS, OP_PARM_Gv, OP_PARM_Mp, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64 | DISOPTYPE_RRM_DANGEROUS), + /** @todo these two are actually group11 */ + OP("mov %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("enter %Iw,%Ib", IDX_ParseImmUshort, IDX_ParseImmByte, 0, OP_ENTER, OP_PARM_Iw, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("leave", 0, 0, 0, OP_LEAVE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("retf %Iw", IDX_ParseImmUshort, 0, 0, OP_RETF, OP_PARM_Iw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + OP("retf", 0, 0, 0, OP_RETF, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + OP("int 3", 0, 0, 0, OP_INT3, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT), + OP("int %Ib", IDX_ParseImmByte, 0, 0, OP_INT, OP_PARM_Ib, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT), + OP("into", 0, 0, 0, OP_INTO, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT | DISOPTYPE_INVALID_64), + OP("iret", 0, 0, 0, OP_IRET, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + + /* D */ + OP("Shift Grp2 %Eb,1", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Eb, OP_PARM_1, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Ev,1", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Ev, OP_PARM_1, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Eb,CL", IDX_ParseShiftGrp2, IDX_ParseFixedReg, 0, OP_SHIFT_GRP2, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Ev,CL", IDX_ParseShiftGrp2, IDX_ParseFixedReg, 0, OP_SHIFT_GRP2, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aam %Ib", IDX_ParseImmByte, 0, 0, OP_AAM, OP_PARM_Ib, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("aad %Ib", IDX_ParseImmByte, 0, 0, OP_AAD, OP_PARM_Ib, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + OP("salc", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_SALC, OP_PARM_REG_AL, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_INVALID_64), + /** @todo xlat has AL as both source and destination and DS:xBX as + * translation table pointer. */ + OP("xlat", 0, 0, 0, OP_XLAT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf0", IDX_ParseEscFP, 0, 0, OP_ESCF0, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf1", IDX_ParseEscFP, 0, 0, OP_ESCF1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf2", IDX_ParseEscFP, 0, 0, OP_ESCF2, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf3", IDX_ParseEscFP, 0, 0, OP_ESCF3, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf4", IDX_ParseEscFP, 0, 0, OP_ESCF4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf5", IDX_ParseEscFP, 0, 0, OP_ESCF5, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf6", IDX_ParseEscFP, 0, 0, OP_ESCF6, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf7", IDX_ParseEscFP, 0, 0, OP_ESCF7, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* E */ + OP("loopne %Jb", IDX_ParseImmBRel, 0, 0, OP_LOOPNE, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("loope %Jb", IDX_ParseImmBRel, 0, 0, OP_LOOPE, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("loop %Jb", IDX_ParseImmBRel, 0, 0, OP_LOOP, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("j(e)cxz %Jb", IDX_ParseImmBRel, 0, 0, OP_JECXZ, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE | DISOPTYPE_RELATIVE_CONTROLFLOW), + OP("in AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_IN, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("in %eAX,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_IN, OP_PARM_REG_EAX, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("out %Ib,AL", IDX_ParseImmByte, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_Ib, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("out %Ib,%eAX", IDX_ParseImmByte, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_Ib, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("call %Jv", IDX_ParseImmVRel, 0, 0, OP_CALL, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jmp %Jv", IDX_ParseImmVRel, 0, 0, OP_JMP, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jmp %Ap", IDX_ParseImmAddrF, 0, 0, OP_JMP, OP_PARM_Ap, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_INVALID_64), + OP("jmp %Jb", IDX_ParseImmBRel, 0, 0, OP_JMP, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("in AL,DX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_IN, OP_PARM_REG_AL, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("in %eAX,DX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_IN, OP_PARM_REG_EAX, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("out DX,AL", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_REG_DX, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("out DX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_REG_DX, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + + + /* F */ + OP("lock", 0, 0, 0, OP_LOCK, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("icebp", 0, 0, 0, OP_INT1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT), + OP("repne", 0, 0, 0, OP_REPNE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rep(e)", 0, 0, 0, OP_REPE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("hlt", 0, 0, 0, OP_HLT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_PRIVILEGED), + OP("cmc", 0, 0, 0, OP_CMC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Unary Grp3 %Eb", IDX_ParseGrp3, 0, 0, OP_UNARY_GRP3, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Unary Grp3 %Ev", IDX_ParseGrp3, 0, 0, OP_UNARY_GRP3, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("clc", 0, 0, 0, OP_CLC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stc", 0, 0, 0, OP_STC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cli", 0, 0, 0, OP_CLI, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("sti", 0, 0, 0, OP_STI, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED | DISOPTYPE_INHIBIT_IRQS), + OP("cld", 0, 0, 0, OP_CLD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("std", 0, 0, 0, OP_STD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc/dec Grp4", IDX_ParseGrp4, 0, 0, OP_INC_GRP4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Indirect Grp5", IDX_ParseGrp5, 0, 0, OP_IND_GRP5, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +const DISOPCODE g_aTwoByteMapX86[256] = +{ + /* 0 */ + OP("Grp6", IDX_ParseGrp6, 0, 0, OP_GRP6, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Grp7", IDX_ParseGrp7, 0, 0, OP_GRP7, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lar %Gv,%Ew", IDX_ParseModRM, IDX_UseModRM, 0, OP_LAR, OP_PARM_Gv, OP_PARM_Ew, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + OP("lsl %Gv,%Ew", IDX_ParseModRM, IDX_UseModRM, 0, OP_LSL, OP_PARM_Gv, OP_PARM_Ew, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + INVALID_OPCODE, + OP("syscall", 0, 0, 0, OP_SYSCALL, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_ONLY_64), + OP("clts", 0, 0, 0, OP_CLTS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + OP("sysret", 0, 0, 0, OP_SYSRET, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_ONLY_64), + OP("invd", 0, 0, 0, OP_INVD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + OP("wbinvd", 0, 0, 0, OP_WBINVD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + INVALID_OPCODE, + OP("Two Byte Illegal Opcodes UD2", 0, 0, 0, OP_ILLUD2, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_ILLEGAL), + INVALID_OPCODE, + /* NOP Ev or prefetch (Intel vs AMD) */ + OP("nop %Ev/prefetch", IDX_ParseModRM, 0, 0, OP_NOP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("femms", 0, 0, 0, OP_FEMMS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("3DNow! Esc", IDX_Parse3DNow, 0, 0, OP_3DNOW, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 1 */ + OP("movups %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVUPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movups %Wps,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVUPS, OP_PARM_Wps, OP_PARM_Vps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* Next instruction has the following format: + * &name1/name2, + * where name1 is used when one of the operands + * is a location in memory, name2 otherwise. */ + OP("&movlps/movhlps %Vq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVLPS, OP_PARM_Vq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movlps %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVLPS, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("unpcklps %Vps,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_UNPCKLPS, OP_PARM_Vps, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("unpckhps %Vps,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_UNPCKHPS, OP_PARM_Vps, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* can also be movlhps when reg->reg */ + OP("&movhps/movlhps %Vq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVHPS, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movhps %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVHPS, OP_PARM_Vq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("prefetch Grp16", IDX_ParseGrp16, 0, 0, OP_PREFETCH_GRP16, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("nop %Ev", IDX_ParseModRM, 0, 0, OP_NOP, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 2 */ + OP("mov %Rd,%Cd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV_CR, OP_PARM_Rd, OP_PARM_Cd, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED | DISOPTYPE_MOD_FIXED_11 | DISOPTYPE_FORCED_32_OP_SIZE_X86), + OP("mov %Rd,%Dd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV_DR, OP_PARM_Rd, OP_PARM_Dd, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED | DISOPTYPE_MOD_FIXED_11 | DISOPTYPE_FORCED_32_OP_SIZE_X86), + OP("mov %Cd,%Rd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV_CR, OP_PARM_Cd, OP_PARM_Rd, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED | DISOPTYPE_MOD_FIXED_11 | DISOPTYPE_FORCED_32_OP_SIZE_X86), + OP("mov %Dd,%Rd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV_DR, OP_PARM_Dd, OP_PARM_Rd, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED | DISOPTYPE_MOD_FIXED_11 | DISOPTYPE_FORCED_32_OP_SIZE_X86), + /* only valid for Pentium Pro & Pentium II */ + OP("mov %Rd,%Td", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV_TR, OP_PARM_Rd, OP_PARM_Td, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + INVALID_OPCODE, + /* only valid for Pentium Pro & Pentium II */ + OP("mov %Td,%Rd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV_TR, OP_PARM_Td, OP_PARM_Rd, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + INVALID_OPCODE, + + OP("movaps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVAPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movaps %Wps,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVAPS, OP_PARM_Wps, OP_PARM_Vps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtpi2ps %Vps,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPI2PS,OP_PARM_Vps, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movntps %Wps,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVNTPS, OP_PARM_Wps, OP_PARM_Vps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvttps2pi %Qq,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTTPS2PI,OP_PARM_Qq, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtps2pi %Qq,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPS2PI,OP_PARM_Qq, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ucomiss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_UCOMISS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("comiss %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_COMISS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 3 */ + OP("wrmsr", 0, 0, 0, OP_WRMSR, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("rdtsc", 0, 0, 0, OP_RDTSC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("rdmsr", 0, 0, 0, OP_RDMSR, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + OP("rdpmc", 0, 0, 0, OP_RDPMC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_PRIVILEGED), + OP("sysenter", 0, 0, 0, OP_SYSENTER,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW), + OP("sysexit", 0, 0, 0, OP_SYSEXIT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + INVALID_OPCODE, + OP("getsec", 0, 0, 0, OP_GETSEC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("3 byte escape A4", IDX_ParseThreeByteEsc4, 0, 0, OP_3B_ESC4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("3 byte escape A5", IDX_ParseThreeByteEsc5, 0, 0, OP_3B_ESC5, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + /* SSE2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 4 */ + OP("cmovo %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVO, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovno %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNO, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovc %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVC, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovnc %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNC, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovz %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVZ, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovnz %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNZ, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovbe %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVBE, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovnbe %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNBE, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovs %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVS, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovns %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNS, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovp %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVP, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovnp %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNP, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovl %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovnl %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovle %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVLE, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmovnle %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMOVNLE, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 5 */ + OP("movmskps %Ed,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVMSKPS,OP_PARM_Ed, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sqrtps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_SQRTPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rsqrtps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_RSQRTPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcpps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_RCPPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("andps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_ANDPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("andnps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_ANDNPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("orps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_ORPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xorps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_XORPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("addps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADDPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mulps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MULPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtps2pd %Vpd,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPS2PD,OP_PARM_Vpd, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtdq2ps %Vps,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTDQ2PS,OP_PARM_Vps, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("subps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUBPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("minps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MINPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("divps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_DIVPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("maxps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_MAXPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 */ + OP("punpcklbw %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLBW, OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpcklwd %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLWD, OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckldq %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLDQ, OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packsswb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKSSWB,OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpgtb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpgtw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpgtd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packuswb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKUSWB,OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhbw %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHBW, OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhwd %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHWD, OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhdq %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHDQ, OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packssdw %Pq,%Qd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKSSDW,OP_PARM_Pq, OP_PARM_Qd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, /** @todo 0x0f 0x6c punpcklqdq Vdq,Wdq */ + INVALID_OPCODE, /** @todo 0x0f 0x6d punpckhqdq Vdq,Wdq */ + OP("movd %Pd,%Ed", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVD, OP_PARM_Pd, OP_PARM_Ed, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 7 */ + OP("pshufw %Pq,%Qq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PSHUFW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("Grp12", IDX_ParseGrp12, 0, 0, OP_GRP12, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Grp13", IDX_ParseGrp13, 0, 0, OP_GRP13, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Grp14", IDX_ParseGrp14, 0, 0, OP_GRP14, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpeqb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpeqw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpeqd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("emms", 0, 0, 0, OP_EMMS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("vmread %Ey,%Gy", IDX_ParseModRM, IDX_UseModRM, 0, OP_VMREAD, OP_PARM_Ey, OP_PARM_Gy, OP_PARM_NONE, DISOPTYPE_HARMLESS|DISOPTYPE_FORCED_64_OP_SIZE), + OP("vmwrite %Gy,%Ey", IDX_ParseModRM, IDX_UseModRM, 0, OP_VMWRITE, OP_PARM_Gy, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS|DISOPTYPE_FORCED_64_OP_SIZE), + OP("MMX UD 0x7A", 0, 0, 0, OP_MMX_UD7A,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("MMX UD 0x7B", 0, 0, 0, OP_MMX_UD7B,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("MMX UD 0x7C", 0, 0, 0, OP_MMX_UD7C,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), /** @todo 0x0f 0x7c haddpd/haddps */ + OP("MMX UD 0x7D", 0, 0, 0, OP_MMX_UD7D,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), /** @todo 0x0f 0x7d hsubpd/hsubps */ + OP("movd %Ed,%Pd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVD, OP_PARM_Ed, OP_PARM_Pd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movq %Qq,%Pq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVQ, OP_PARM_Qq, OP_PARM_Pq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 8 */ + OP("jo %Jv", IDX_ParseImmVRel, 0, 0, OP_JO, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jno %Jv", IDX_ParseImmVRel, 0, 0, OP_JNO, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jc %Jv", IDX_ParseImmVRel, 0, 0, OP_JC, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnc %Jv", IDX_ParseImmVRel, 0, 0, OP_JNC, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("je %Jv", IDX_ParseImmVRel, 0, 0, OP_JE, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jne %Jv", IDX_ParseImmVRel, 0, 0, OP_JNE, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jbe %Jv", IDX_ParseImmVRel, 0, 0, OP_JBE, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnbe %Jv", IDX_ParseImmVRel, 0, 0, OP_JNBE, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("js %Jv", IDX_ParseImmVRel, 0, 0, OP_JS, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jns %Jv", IDX_ParseImmVRel, 0, 0, OP_JNS, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jp %Jv", IDX_ParseImmVRel, 0, 0, OP_JP, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnp %Jv", IDX_ParseImmVRel, 0, 0, OP_JNP, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jl %Jv", IDX_ParseImmVRel, 0, 0, OP_JL, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnl %Jv", IDX_ParseImmVRel, 0, 0, OP_JNL, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jle %Jv", IDX_ParseImmVRel, 0, 0, OP_JLE, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnle %Jv", IDX_ParseImmVRel, 0, 0, OP_JNLE, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW|DISOPTYPE_FORCED_64_OP_SIZE), + + /* 9 */ + OP("seto %Eb", IDX_ParseModRM, 0, 0, OP_SETO, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setno %Eb", IDX_ParseModRM, 0, 0, OP_SETNO, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setc %Eb", IDX_ParseModRM, 0, 0, OP_SETC, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setnc %Eb", IDX_ParseModRM, 0, 0, OP_SETNC, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sete %Eb", IDX_ParseModRM, 0, 0, OP_SETE, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setne %Eb", IDX_ParseModRM, 0, 0, OP_SETNE, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setbe %Eb", IDX_ParseModRM, 0, 0, OP_SETBE, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setnbe %Eb", IDX_ParseModRM, 0, 0, OP_SETNBE, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sets %Eb", IDX_ParseModRM, 0, 0, OP_SETS, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setns %Eb", IDX_ParseModRM, 0, 0, OP_SETNS, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setp %Eb", IDX_ParseModRM, 0, 0, OP_SETP, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setnp %Eb", IDX_ParseModRM, 0, 0, OP_SETNP, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setl %Eb", IDX_ParseModRM, 0, 0, OP_SETL, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setnl %Eb", IDX_ParseModRM, 0, 0, OP_SETNL, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setle %Eb", IDX_ParseModRM, 0, 0, OP_SETLE, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("setnle %Eb", IDX_ParseModRM, 0, 0, OP_SETNLE, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* a */ + OP("push fs", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_FS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("pop fs", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_FS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("cpuid", 0, 0, 0, OP_CPUID, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("bt %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_BT, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shld %Ev,%Gv,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_SHLD, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("shld %Ev,%Gv,CL", IDX_ParseModRM, IDX_UseModRM, 0, OP_SHLD, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("push gs", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_GS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("pop gs", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_GS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("rsm", 0, 0, 0, OP_RSM, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("bts %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_BTS, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shrd %Ev,%Gv,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_SHRD, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("shrd %Ev,%Gv,CL", IDX_ParseModRM, IDX_UseModRM, IDX_ParseFixedReg,OP_SHRD, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_REG_CL, DISOPTYPE_HARMLESS), + OP("Grp15", IDX_ParseGrp15, 0, 0, OP_GRP15, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("imul %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_IMUL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* b */ + OP("cmpxchg %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMPXCHG, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmpxchg %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMPXCHG, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lss %Gv,%Mp", IDX_ParseModRM, IDX_UseModRM, 0, OP_LSS, OP_PARM_Gv, OP_PARM_Mp, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_RRM_DANGEROUS), + OP("btr %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_BTR, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lfs %Gv,%Mp", IDX_ParseModRM, IDX_UseModRM, 0, OP_LFS, OP_PARM_Gv, OP_PARM_Mp, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lgs %Gv,%Mp", IDX_ParseModRM, IDX_UseModRM, 0, OP_LGS, OP_PARM_Gv, OP_PARM_Mp, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movzx %Gv,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVZX, OP_PARM_Gv, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movzx %Gv,%Ew", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVZX, OP_PARM_Gv, OP_PARM_Ew, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, /** @todo 0x0f 0xb8 popcnt Gv,Ev / jmpe */ + OP("Grp10 Invalid Op", IDX_ParseGrp10, 0, 0, OP_GRP10_INV,OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Grp8", IDX_ParseGrp8, 0, 0, OP_GRP8, OP_PARM_Ev, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("btc %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_BTC, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("bsf %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_BSF, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("bsr %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_BSR, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsx %Gv,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSX, OP_PARM_Gv, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsx %Gv,%Ew", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSX, OP_PARM_Gv, OP_PARM_Ew, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* c */ + OP("xadd %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XADD, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xadd %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_XADD, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmpps %Vps,%Wps,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_CMPPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_Ib, DISOPTYPE_HARMLESS), + /* SSE2 */ + OP("movnti %Ed,%Gd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVNTI, OP_PARM_Ed, OP_PARM_Gd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pinsrw %Pq,%Ed,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PINSRW, OP_PARM_Pq, OP_PARM_Ed, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pextrw %Gd,%Pq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PEXTRW, OP_PARM_Gd, OP_PARM_Pq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("shufps %Vps,%Wps,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_SHUFPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("Grp9", IDX_ParseGrp9, 0, 0, OP_GRP9, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("bswap EAX", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap ECX", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap EDX", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap EBX", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap ESP", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap EBP", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap ESI", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("bswap EDI", IDX_ParseFixedReg, 0, 0, OP_BSWAP, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + + /* d */ + INVALID_OPCODE, /** @todo 0x0f 0xd0 addsubpd/addsubps */ + OP("psrlw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrld %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrlq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmullw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULLW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("pmovmskb %Gd,%Pq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVMSKB,OP_PARM_Gd, OP_PARM_Pq, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("psubusb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBUSB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubusw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBUSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminub %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINUB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pand %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAND, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddusb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDUSB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddusw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDUSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxub %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXUB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pandn %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PANDN, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* e */ + OP("pavgb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAVGB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psraw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRAW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrad %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRAD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pavgw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAVGW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhuw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULHUW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULHW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("movntq %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVNTQ, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubsb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBSB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("por %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_POR, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddsb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDSB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pxor %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PXOR, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + INVALID_OPCODE, + OP("psllw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSLLW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pslld %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSLLD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psllq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSSQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmuludq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULUDQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaddwd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMADDWD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psadbw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSADBW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("maskmovq %Ppi,%Qpi", IDX_ParseModRM, IDX_UseModRM, 0, OP_MASKMOVQ,OP_PARM_Ppi, OP_PARM_Qpi, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, +}; + +/** Two byte opcode map with prefix 0x66 */ +const DISOPCODE g_aTwoByteMapX86_PF66[256] = +{ + /* 0 */ + INVALID_OPCODE_BLOCK + + /* 1 */ + OP("movupd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVUPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movupd %Wpd,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVUPD, OP_PARM_Wpd, OP_PARM_Vpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movlpd %Vq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVLPD, OP_PARM_Vq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movlpd %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVLPD, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("unpcklpd %Vpd,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_UNPCKLPD,OP_PARM_Vpd, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("unpckhpd %Vpd,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_UNPCKHPD,OP_PARM_Vpd, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movhpd %Vq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVHPD, OP_PARM_Vq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movhpd %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVHPD, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movapd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVAPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movapd %Wpd,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVAPD, OP_PARM_Wpd, OP_PARM_Vpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtpi2pd %Vpd,%Qdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPI2PD,OP_PARM_Vpd, OP_PARM_Qdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movntpd %Wpd,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVNTPD, OP_PARM_Wpd, OP_PARM_Vpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvttpd2pi %Qdq,%Wpd",IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTTPD2PI,OP_PARM_Qdq, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtpd2pi %Qdq,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPD2PI,OP_PARM_Qdq, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ucomisd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_UCOMISD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("comisd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_COMISD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 3 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("3 byte escape A4", IDX_ParseThreeByteEsc4, 0, 0, OP_3B_ESC4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("3 byte escape A5", IDX_ParseThreeByteEsc5, 0, 0, OP_3B_ESC5, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + OP("movmskpd %Ed,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVMSKPD,OP_PARM_Ed, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sqrtpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_SQRTPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("andpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_ANDPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("andnpd %Vps,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_ANDNPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("orpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_ORPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xorpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_XORPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("addpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADDPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mulpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MULPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtpd2ps %Vps,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPD2PS,OP_PARM_Vps, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtps2dq %Vdq,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPS2DQ,OP_PARM_Vdq, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("subpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUBPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("minpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MINPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("divpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_DIVPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("maxpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MAXPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 */ + OP("punpcklbw %Vdq,%Wdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLBW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpcklwd %Vdq,%Wdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLWD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckldq %Vdq,%Wdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLDQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packsswb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKSSWB,OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpgtb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpgtw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpgtd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packuswb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKUSWB,OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhbw %Pdq,%Qdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHBW, OP_PARM_Pdq, OP_PARM_Qdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhwd %Pdq,%Qdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHWD, OP_PARM_Pdq, OP_PARM_Qdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhdq %Pdq,%Qdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHDQ, OP_PARM_Pdq, OP_PARM_Qdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packssdw %Pdq,%Qdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKSSDW,OP_PARM_Pdq, OP_PARM_Qdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpcklqdq %Vdq,%Wdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKLQDQ,OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("punpckhqdq %Vdq,%Wdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_PUNPCKHQDQ,OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movd %Vdq,%Ed", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVD, OP_PARM_Vdq, OP_PARM_Ed, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movdqa %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVDQA, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 7 */ + OP("pshufd %Vdq,%Wdq,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PSHUFD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("pcmpeqb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQB, OP_PARM_Vdq, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpeqw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQW, OP_PARM_Vdq, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpeqd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQD, OP_PARM_Vdq, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movd %Ed,%Vdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVD, OP_PARM_Ed, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movdqa %Qq,%Pq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVDQA, OP_PARM_Wdq, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 8 */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c */ + INVALID_OPCODE, + INVALID_OPCODE, + OP("cmppd %Vpd,%Wpd,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_CMPPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("pinsrw %Vdq,%Ed,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PINSRW, OP_PARM_Vdq, OP_PARM_Ed, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pextrw %Gd,%Vdq,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PEXTRW, OP_PARM_Gd, OP_PARM_Vdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("shufpd %Vpd,%Wpd,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_SHUFPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + INVALID_OPCODE, + OP("psrlw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrld %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrlq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRLQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmullw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movq %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVQ, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovmskb %Gd,%Ux", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVMSKB,OP_PARM_Gd, OP_PARM_Ux, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("psubusb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBUSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubusw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBUSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminub %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINUB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pand %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAND, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddusb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDUSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddusw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDUSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxub %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXUB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pandn %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PANDN, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* e */ + OP("pavgb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAVGB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psraw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRAW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrad %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSRAD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pavgw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAVGW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhuw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULHUW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULHW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvttpd2dq %Vdq,%Wpd",IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTTPD2DQ,OP_PARM_Vdq, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movntdq %Wdq,%Vdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVNTDQ, OP_PARM_Wdq, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubsb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("por %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_POR, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddsb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pxor %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PXOR, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + INVALID_OPCODE, + OP("psllw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSLLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pslld %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSLLD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psllq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSSQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmuludq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULUDQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaddwd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMADDWD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psadbw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSADBW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("maskmovdqu %Vdq,%Wdq",IDX_ParseModRM, IDX_UseModRM, 0, OP_MASKMOVDQU, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psubq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSUBD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("paddd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PADDD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, +}; + +/* Two byte opcode map with prefix 0xF2 */ +const DISOPCODE g_aTwoByteMapX86_PFF2[256] = +{ + /* 0 */ + INVALID_OPCODE_BLOCK + + /* 1 */ + OP("movsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsd %Wsd,%Vsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSD, OP_PARM_Wpd, OP_PARM_Vpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movddup %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVDDUP, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("cvtsi2sd %Vsd,%Ed", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTSI2SD,OP_PARM_Vsd, OP_PARM_Ed, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("cvttsd2si %Gd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTTSD2SI,OP_PARM_Gd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtsd2si %Gd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTSD2SI,OP_PARM_Gd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* 3 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("3 byte escape A4", IDX_ParseThreeByteEsc4, 0, 0, OP_3B_ESC4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + INVALID_OPCODE, + OP("sqrtsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_SQRTSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("addsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADDSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mulsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MULSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtsd2ss %Vss,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTSD2SS,OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("subsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUBSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("minsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MINSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("divsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_DIVSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("maxsd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, OP_MAXSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 */ + INVALID_OPCODE_BLOCK + + /* 7 */ + OP("pshuflw %Vdq,%Wdq,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PSHUFLW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 8 */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c */ + INVALID_OPCODE, + INVALID_OPCODE, + OP("cmpsd %Vsd,%Wsd,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_CMPSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movdq2q %Pq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVDQ2Q, OP_PARM_Pq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* e */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("cvtpd2dq %Vdq,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTPD2DQ,OP_PARM_Vdq, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* f */ + OP("lddqu %Vdq,%Mdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_LDDQU, OP_PARM_Vdq, OP_PARM_Mdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE +}; + + +/* Two byte opcode map with prefix 0xF3 */ +const DISOPCODE g_aTwoByteMapX86_PFF3[256] = +{ + /* 0 */ + INVALID_OPCODE_BLOCK + + /* 1 */ + OP("movss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movss %Wss,%Vss", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSS, OP_PARM_Wss, OP_PARM_Vss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsldup %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSLDUP,OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movshdup %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSHDUP,OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("cvtsi2ss %Vss,%Ed", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTSI2SS,OP_PARM_Vss, OP_PARM_Ed, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("cvttss2si %Gd,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTTSS2SI,OP_PARM_Gd, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvtss2si %Gd,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTSS2SI,OP_PARM_Gd, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* 3 */ + INVALID_OPCODE_BLOCK + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + INVALID_OPCODE, + OP("sqrtss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_SQRTSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rsqrtss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_RSQRTSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcpss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_RCPSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("addss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADDSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mulss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_MULSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + //?? + OP("cvtss2sd %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTSD2SS,OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cvttps2dq %Vdq,%Wps",IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTTPS2DQ,OP_PARM_Vdq, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("subss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUBSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("minss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_MINSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("divss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_DIVSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("maxss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, OP_MAXSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movdqu %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVDQU, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 7 */ + OP("pshufhw %Vdq,%Wdq,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_PSHUFHW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movq %Vq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVQ, OP_PARM_Vq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movdqu %Wdq,%Vdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVDQU, OP_PARM_Wdq, OP_PARM_Vdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 8 */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("popcnt %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_POPCNT, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("tzcnt %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_TZCNT, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lzcnt %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_LZCNT, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* c */ + INVALID_OPCODE, + INVALID_OPCODE, + OP("cmpss %Vss,%Wss,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte,OP_CMPSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movq2dq %Vdq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVQ2DQ, OP_PARM_Vdq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* e */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("cvtdq2pd %Vpd,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_CVTDQ2PD,OP_PARM_Vpd, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* f */ + INVALID_OPCODE_BLOCK +}; + +/** Three byte opcode map (0xF 0x38 0x0x) */ +const DISOPCODE g_aThreeByteMapX86_0F38_0[16] = +{ + /* 0 */ + OP("pshufb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSHUFB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phaddw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHADDW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phaddd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHADDD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phaddsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHADDSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaddubsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMADDUBSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phsubw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHSUBW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phsubd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHSUBD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phsubsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHSUBSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psignb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSIGNB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psignw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSIGNW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psignd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSIGND, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhrsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULHRSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x0F 0x38 0x1x) */ +const DISOPCODE g_aThreeByteMapX86_0F38_1[16] = +{ + /* 1 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("pabsb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PABSB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pabsw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PABSW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pabsd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PABSD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x0F 0x38 0xFx) */ +const DISOPCODE g_aThreeByteMapX86_0F38_F[16] = +{ + /* F */ + OP("movbe %Gy,%My", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVBEGM, OP_PARM_Gy, OP_PARM_My, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movbe %My,%Gy", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVBEMG, OP_PARM_My, OP_PARM_Gy, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** These tables are mostly sparse, so use another level of indirection to save space. */ +PCDISOPCODE const g_apThreeByteMapX86_0F38[16] = +{ + /* 0 */ + &g_aThreeByteMapX86_0F38_0[0], + /* 1 */ + &g_aThreeByteMapX86_0F38_1[0], + /* 2 */ + NULL, + /* 3 */ + NULL, + /* 4 */ + NULL, + /* 5 */ + NULL, + /* 6 */ + NULL, + /* 7 */ + NULL, + /* 8 */ + NULL, + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + NULL, + /* e */ + NULL, + /* f */ + &g_aThreeByteMapX86_0F38_F[0], +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0x0x) */ +const DISOPCODE g_aThreeByteMapX86_660F38_0[16] = +{ + /* 0 */ + OP("pshufb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSHUFB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phaddw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHADDW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phaddd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHADDD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phaddsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHADDSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaddubsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMADDUBSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phsubw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHSUBW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phsubd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHSUBD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phsubsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHSUBSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psignb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSIGNB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psignw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSIGNW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psignd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PSIGND, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhrsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULHRSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0x1x) */ +const DISOPCODE g_aThreeByteMapX86_660F38_1[16] = +{ + /* 1 */ + OP("pblendvb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PBLENDVB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("blendvps %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_BLENDVPS, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("blendvpd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_BLENDVPD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("ptest %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PTEST, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("pabsb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PABSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pabsw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PABSW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pabsd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PABSD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0x2x) */ +const DISOPCODE g_aThreeByteMapX86_660F38_2[16] = +{ + /* 2 */ + OP("pmovsxbw %Vdq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVSXBW, OP_PARM_Vdq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovsxbd %Vdq,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVSXBD, OP_PARM_Vdq, OP_PARM_Wd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovsxbq %Vdq,%Ww", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVSXBQ, OP_PARM_Vdq, OP_PARM_Ww, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovsxwd %Vdq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVSXBW, OP_PARM_Vdq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovsxwq %Vdq,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVSXWQ, OP_PARM_Vdq, OP_PARM_Wd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovsxdq %Vdq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVSXDQ, OP_PARM_Vdq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("pmuldq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULDQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pcmpeqq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPEQQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movntdqa %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVNTDQA, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("packusdw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PACKUSDW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0x3x) */ +const DISOPCODE g_aThreeByteMapX86_660F38_3[16] = +{ + /* 3 */ + OP("pmovzxbw %Vdq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVZXBW, OP_PARM_Vdq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovzxbd %Vdq,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVZXBD, OP_PARM_Vdq, OP_PARM_Wd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovzxbq %Vdq,%Ww", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVZXBQ, OP_PARM_Vdq, OP_PARM_Ww, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovzxwd %Vdq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVZXWD, OP_PARM_Vdq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovzxwq %Vdq,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVZXWQ, OP_PARM_Vdq, OP_PARM_Wd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmovzxdq %Vdq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMOVZXDQ, OP_PARM_Vdq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("pcmpgtq %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PCMPGTQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminsb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminsd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminuw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINUW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pminud %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMINUD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxsb %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXSB, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxsd %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXSD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxuw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXUW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmaxud %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMAXUD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0x4x) */ +const DISOPCODE g_aThreeByteMapX86_660F38_4[16] = +{ + /* 4 */ + OP("pmulld %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PMULLD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("phminposuw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PHMINPOSUW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0x8x) */ +const DISOPCODE g_aThreeByteMapX86_660F38_8[16] = +{ + /* 8 */ + OP("invept %Gy,%Mdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_INVEPT, OP_PARM_Gy, OP_PARM_Mdq, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_FORCED_64_OP_SIZE), + OP("invvpid %Gy,%Mdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_INVVPID, OP_PARM_Gy, OP_PARM_Mdq, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_FORCED_64_OP_SIZE), + OP("invpcid %Gy,%Mdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_INVPCID, OP_PARM_Gy, OP_PARM_Mdq, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_FORCED_64_OP_SIZE), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map (0x66 0x0F 0x38 0xDx) */ +const DISOPCODE g_aThreeByteMapX86_660F38_D[16] = +{ + /* D */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("aesimc %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_AESIMC, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aesenc %Vdq,%Hdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_AESENC, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aesenclast %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_AESENCLAST, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aesdec %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_AESDEC, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("aesdeclast %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, OP_AESDECLAST, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +const DISOPCODE g_aThreeByteMapX86_660F38_F[16] = +{ + /* F */ + OP("movbe %Gw,%Mw", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVBEGM, OP_PARM_Gw, OP_PARM_Mw, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movbe %Mw,%Gw", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVBEMG, OP_PARM_Mw, OP_PARM_Gw, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("adcx %Gy,%Ey", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADCX, OP_PARM_Gy, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map with prefix 0x66 (0xF 0x38) */ +PCDISOPCODE const g_apThreeByteMapX86_660F38[16] = +{ + /* 0 */ + &g_aThreeByteMapX86_660F38_0[0], + /* 1 */ + &g_aThreeByteMapX86_660F38_1[0], + /* 2 */ + &g_aThreeByteMapX86_660F38_2[0], + /* 3 */ + &g_aThreeByteMapX86_660F38_3[0], + /* 4 */ + &g_aThreeByteMapX86_660F38_4[0], + /* 5 */ + NULL, + /* 6 */ + NULL, + /* 7 */ + NULL, + /* 8 */ + &g_aThreeByteMapX86_660F38_8[0], + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + &g_aThreeByteMapX86_660F38_D[0], + /* e */ + NULL, + /* f */ + &g_aThreeByteMapX86_660F38_F[0], +}; + +const DISOPCODE g_aThreeByteMapX86_F20F38_F[16] = +{ + /* According to Intel opcodes map in Intel® 64 and IA-32 Architectures Software Developer’s Manual dated September 2014 + it should be %Gd (always dword regardless of operand-size attribute), but from the description of the command + it is clear that REX.W prefix can change this size to 64 bit, therefore it is set to %Gy. Seems to be a mistake. */ + /** @todo r=bird: While the destination can be a 64-bit register, it is + * always treated like a dword register given that the upper half is + * always cleared. So, it is really just a convenience for a more + * natural syntax when using a 64-bit source register. */ + OP("crc32 %Gy,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CRC32, OP_PARM_Gy, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("crc32 %Gy,%Ey", IDX_ParseModRM, IDX_UseModRM, 0, OP_CRC32, OP_PARM_Gy, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +const DISOPCODE g_aThreeByteMapX86_66F20F38_F[16] = +{ + /* According to Intel opcodes map in Intel® 64 and IA-32 Architectures Software Developer’s Manual dated September 2014 + it should be %Gd (always dword regardless of operand-size attribute), but from the description of the command + it is clear that REX.W prefix can change this size to 64 bit, therefore it is set to %Gy. Seems to be a mistake. */ + OP("crc32 %Gy,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CRC32, OP_PARM_Gy, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("crc32 %Gy,%Ew", IDX_ParseModRM, IDX_UseModRM, 0, OP_CRC32, OP_PARM_Gy, OP_PARM_Ew, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map with prefix 0xF2 (0xF 0x38) */ +/** @todo remainder missing (too lazy now) */ +PCDISOPCODE const g_apThreeByteMapX86_F20F38[16] = +{ + /* 0 */ + NULL, + /* 1 */ + NULL, + /* 2 */ + NULL, + /* 3 */ + NULL, + /* 4 */ + NULL, + /* 5 */ + NULL, + /* 6 */ + NULL, + /* 7 */ + NULL, + /* 8 */ + NULL, + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + NULL, + /* e */ + NULL, + /* f */ + &g_aThreeByteMapX86_F20F38_F[0], +}; + +/** Three byte opcode map with prefixes 0x66 0xF2 (0xF 0x38) */ +PCDISOPCODE const g_apThreeByteMapX86_66F20F38[16] = +{ + /* 0 */ + NULL, + /* 1 */ + NULL, + /* 2 */ + NULL, + /* 3 */ + NULL, + /* 4 */ + NULL, + /* 5 */ + NULL, + /* 6 */ + NULL, + /* 7 */ + NULL, + /* 8 */ + NULL, + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + NULL, + /* e */ + NULL, + /* f */ + &g_aThreeByteMapX86_66F20F38_F[0], +}; + +const DISOPCODE g_aThreeByteMapX86_F30F38_F[16] = +{ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("adox %Gy,%Ey", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADOX, OP_PARM_Gy, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +/** Three byte opcode map with prefix 0xF3 (0xF 0x38) */ +PCDISOPCODE const g_apThreeByteMapX86_F30F38[16] = +{ + /* 0 */ + NULL, + /* 1 */ + NULL, + /* 2 */ + NULL, + /* 3 */ + NULL, + /* 4 */ + NULL, + /* 5 */ + NULL, + /* 6 */ + NULL, + /* 7 */ + NULL, + /* 8 */ + NULL, + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + NULL, + /* e */ + NULL, + /* f */ + &g_aThreeByteMapX86_F30F38_F[0], +}; + +const DISOPCODE g_aThreeByteMapX86_0F3A_0[16] = +{ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("palignr %Pq,%Qq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PALIGNR, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_Ib, DISOPTYPE_HARMLESS), +}; + +PCDISOPCODE const g_apThreeByteMapX86_0F3A[16] = +{ + /* 0 */ + g_aThreeByteMapX86_0F3A_0, + /* 1 */ + NULL, + /* 2 */ + NULL, + /* 3 */ + NULL, + /* 4 */ + NULL, + /* 5 */ + NULL, + /* 6 */ + NULL, + /* 7 */ + NULL, + /* 8 */ + NULL, + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + NULL, + /* e */ + NULL, + /* f */ + NULL, +}; + +const DISOPCODE g_aThreeByteMapX86_660F3A_0[16] = +{ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("roundps %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_ROUNDPS, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("roundpd %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_ROUNDPD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("roundss %Vss,%Wss,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_ROUNDSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("roundsd %Vsd,%Wsd,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_ROUNDSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("blendps %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_BLENDPS, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("blendpd %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_BLENDPD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pblendw %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PBLENDW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("palignr %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PALIGNR, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), +}; + +const DISOPCODE g_aThreeByteMapX86_660F3A_10[16] = +{ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("pextrb %Eb,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PEXTRB, OP_PARM_Eb, OP_PARM_Vdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pextrw %Ew,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PEXTRW, OP_PARM_Ew, OP_PARM_Vdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pextrd %Ed,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PEXTRD, OP_PARM_Ed, OP_PARM_Vdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("extractps %Ed,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_EXTRACTPS, OP_PARM_Ed, OP_PARM_Vdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +const DISOPCODE g_aThreeByteMapX86_660F3A_20[16] = +{ + // pinsrb %Vdq,%Ry/Mb,%Ib + OP("pinsrb %Vdq,%Ey,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PINSRB, OP_PARM_Vdq, OP_PARM_Ey, OP_PARM_Ib, DISOPTYPE_HARMLESS), + // insertps %Vdq,%Udq/Md,%Ib + OP("insertps %Vdq,%Wdq,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_INSERTPS, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pinsrd %Vdq,%Ey,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PINSRD, OP_PARM_Vdq, OP_PARM_Ey, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +const DISOPCODE g_aThreeByteMapX86_660F3A_40[16] = +{ + OP("dpps %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_DPPS, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("dppd %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_DPPD, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("mpsadbw %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_MPSADBW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("pclmulqdq %Vdq,%Wdq,%Ib",IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PCLMULQDQ, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +const DISOPCODE g_aThreeByteMapX86_660F3A_60[16] = +{ + OP("pcmpestrm %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PCMPESTRM, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pcmpestri %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PCMPESTRI, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pcmpistrm %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PCMPISTRM, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("pcmpistri %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_PCMPISTRI, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + +const DISOPCODE g_aThreeByteMapX86_660F3A_D0[16] = +{ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("aeskeygen %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, OP_AESKEYGEN, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), +}; + +/** Three byte opcode map with prefix 0x66 (0xF 0x3A) */ +/** @todo remainder missing (too lazy now) */ +PCDISOPCODE const g_apThreeByteMapX86_660F3A[16] = +{ + /* 0 */ + g_aThreeByteMapX86_660F3A_0, + /* 1 */ + g_aThreeByteMapX86_660F3A_10, + /* 2 */ + g_aThreeByteMapX86_660F3A_20, + /* 3 */ + NULL, + /* 4 */ + g_aThreeByteMapX86_660F3A_40, + /* 5 */ + NULL, + /* 6 */ + g_aThreeByteMapX86_660F3A_60, + /* 7 */ + NULL, + /* 8 */ + NULL, + /* 9 */ + NULL, + /* a */ + NULL, + /* b */ + NULL, + /* c */ + NULL, + /* d */ + g_aThreeByteMapX86_660F3A_D0, + /* e */ + NULL, + /* f */ + NULL, +}; + +/* 3DNow! map (0x0F 0x0F prefix) */ +const DISOPCODE g_aTwoByteMapX86_3DNow[256] = +{ + /* 0 */ + INVALID_OPCODE_MOD_RM(0x00), + INVALID_OPCODE_MOD_RM(0x01), + INVALID_OPCODE_MOD_RM(0x02), + INVALID_OPCODE_MOD_RM(0x03), + INVALID_OPCODE_MOD_RM(0x04), + INVALID_OPCODE_MOD_RM(0x05), + INVALID_OPCODE_MOD_RM(0x06), + INVALID_OPCODE_MOD_RM(0x07), + INVALID_OPCODE_MOD_RM(0x08), + INVALID_OPCODE_MOD_RM(0x09), + INVALID_OPCODE_MOD_RM(0x0a), + INVALID_OPCODE_MOD_RM(0x0c), + OP("pi2fw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PI2FW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pi2fd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PI2FD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x0e), + INVALID_OPCODE_MOD_RM(0x0f), + + /* 1 */ + INVALID_OPCODE_MOD_RM(0x10), + INVALID_OPCODE_MOD_RM(0x11), + INVALID_OPCODE_MOD_RM(0x12), + INVALID_OPCODE_MOD_RM(0x13), + INVALID_OPCODE_MOD_RM(0x14), + INVALID_OPCODE_MOD_RM(0x15), + INVALID_OPCODE_MOD_RM(0x16), + INVALID_OPCODE_MOD_RM(0x17), + INVALID_OPCODE_MOD_RM(0x18), + INVALID_OPCODE_MOD_RM(0x19), + INVALID_OPCODE_MOD_RM(0x1a), + INVALID_OPCODE_MOD_RM(0x1b), + OP("pf2iw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PF2IW, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pf2id %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PF2ID, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x1e), + INVALID_OPCODE_MOD_RM(0x1f), + + /* 2 */ + INVALID_OPCODE_BLOCK_MOD_RM(0x2) + + /* 3 */ + INVALID_OPCODE_BLOCK_MOD_RM(0x3) + + /* 4 */ + INVALID_OPCODE_BLOCK_MOD_RM(0x4) + + /* 5 */ + INVALID_OPCODE_BLOCK_MOD_RM(0x5) + + /* 6 */ + INVALID_OPCODE_BLOCK_MOD_RM(0x6) + + /* 7 */ + INVALID_OPCODE_BLOCK_MOD_RM(0x7) + + /* 8 */ + INVALID_OPCODE_MOD_RM(0x80), + INVALID_OPCODE_MOD_RM(0x81), + INVALID_OPCODE_MOD_RM(0x82), + INVALID_OPCODE_MOD_RM(0x83), + INVALID_OPCODE_MOD_RM(0x84), + INVALID_OPCODE_MOD_RM(0x85), + INVALID_OPCODE_MOD_RM(0x86), + INVALID_OPCODE_MOD_RM(0x87), + INVALID_OPCODE_MOD_RM(0x88), + INVALID_OPCODE_MOD_RM(0x89), + OP("pfnacc %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFNACC, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x8b), + INVALID_OPCODE_MOD_RM(0x8c), + INVALID_OPCODE_MOD_RM(0x8d), + OP("pfpnacc %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFPNACC, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x8f), + + /* 9 */ + OP("pfcmpge %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFCMPGE, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x91), + INVALID_OPCODE_MOD_RM(0x92), + INVALID_OPCODE_MOD_RM(0x93), + OP("pfmin %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFMIN, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x95), + OP("pfrcp %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFRCP, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pfrsqrt %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFRSQRT, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x98), + INVALID_OPCODE_MOD_RM(0x99), + OP("pfsub %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFSUB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x9b), + INVALID_OPCODE_MOD_RM(0x9c), + INVALID_OPCODE_MOD_RM(0x9d), + OP("pfadd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFADD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x9f), + + /* a */ + OP("pfcmpgt %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFCMPGT, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xa1), + INVALID_OPCODE_MOD_RM(0xa2), + INVALID_OPCODE_MOD_RM(0xa3), + OP("pfmax %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFMAX, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xa5), + OP("pfrcpit1 %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFRCPIT1,OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pfrsqit1 %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFRSQRTIT1, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xa8), + INVALID_OPCODE_MOD_RM(0xa9), + OP("pfsubr %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFSUBR, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xab), + INVALID_OPCODE_MOD_RM(0xac), + INVALID_OPCODE_MOD_RM(0xad), + OP("pfacc %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFACC, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xaf), + + /* b */ + OP("pfcmpeq %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFCMPEQ, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xb1), + INVALID_OPCODE_MOD_RM(0xb2), + INVALID_OPCODE_MOD_RM(0xb3), + OP("pfmul %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFMUL, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xb5), + OP("pfrcpit2 %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFRCPIT2,OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pmulhrw %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFMULHRW,OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xb8), + INVALID_OPCODE_MOD_RM(0xb9), + INVALID_OPCODE_MOD_RM(0xba), + OP("pswapd %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PFSWAPD, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xbc), + INVALID_OPCODE_MOD_RM(0xbd), + INVALID_OPCODE_MOD_RM(0xbe), + OP("pavgusb %Pq,%Qq", IDX_ParseModRM, IDX_UseModRM, 0, OP_PAVGUSB, OP_PARM_Pq, OP_PARM_Qq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* c */ + INVALID_OPCODE_BLOCK_MOD_RM(0xc) + + /* d */ + INVALID_OPCODE_BLOCK_MOD_RM(0xd) + + /* e */ + INVALID_OPCODE_BLOCK_MOD_RM(0xe) + + /* f */ + INVALID_OPCODE_BLOCK_MOD_RM(0xf) +}; + + + +/* Floating point opcode starting with escape byte 0xD8 (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF0_Low[8] = +{ + /* 0 */ + OP("fadd %Md", IDX_ParseModRM, 0, 0, OP_FADD, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul %Md", IDX_ParseModRM, 0, 0, OP_FMUL, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom %Md", IDX_ParseModRM, 0, 0, OP_FCOM, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp %Md", IDX_ParseModRM, 0, 0, OP_FCOMP, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub %Md", IDX_ParseModRM, 0, 0, OP_FSUB, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr %Md", IDX_ParseModRM, 0, 0, OP_FSUBR, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv %Md", IDX_ParseModRM, 0, 0, OP_FDIV, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr %Md", IDX_ParseModRM, 0, 0, OP_FDIVR, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +/* Floating point opcode starting with escape byte 0xD8 (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF0_High[16*4] = +{ + /* c */ + OP("fadd ST(0),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(1)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(2)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(3)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(4)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(5)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(6)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(0),ST(7)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(1)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(2)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(3)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(4)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(5)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(6)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(7)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* d */ + OP("fcom ST(0),ST(0)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(1)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(2)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(3)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(4)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(5)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(6)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom ST(0),ST(7)", 0, 0, 0, OP_FCOM, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(0)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(1)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(2)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(3)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(4)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(5)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(6)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp ST(0),ST(7)", 0, 0, 0, OP_FCOMP, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* e */ + OP("fsub ST(0),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(1)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(2)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(3)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(4)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(5)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(6)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(7)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(1)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(2)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(3)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(4)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(5)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(6)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(0),ST(7)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + OP("fdiv ST(0),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(1)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(2)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(3)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(4)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(5)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(6)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(7)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(1)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(2)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(3)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(4)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(5)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(6)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(0),ST(7)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +/* Floating point opcode starting with escape byte 0xD9 (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF1_Low[8] = +{ + /* 0 */ + OP("fld %Md", IDX_ParseModRM, 0, 0, OP_FLD, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("fst %Md", IDX_ParseModRM, 0, 0, OP_FST, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp %Md", IDX_ParseModRM, 0, 0, OP_FSTP, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /// @todo ?? + OP("fldenv %M", IDX_ParseModRM, 0, 0, OP_FLDENV, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldcw %Ew", IDX_ParseModRM, 0, 0, OP_FSUBR, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /// @todo ?? + OP("fstenv %M", IDX_ParseModRM, 0, 0, OP_FSTENV, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstcw %Ew", IDX_ParseModRM, 0, 0, OP_FSTCW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xD9 (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF1_High[16*4] = +{ + /* c */ + OP("fld ST(0),ST(0)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(1)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(2)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(3)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(4)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(5)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(6)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fld ST(0),ST(7)", 0, 0, 0, OP_FLD, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(0)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(1)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(2)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(3)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(4)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(5)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(6)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxch ST(0),ST(7)", 0, 0, 0, OP_FXCH, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* d */ + OP("fnop", 0, 0, 0, OP_FNOP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + + /* e */ + OP("fchs", 0, 0, 0, OP_FCHS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fabs", 0, 0, 0, OP_FABS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("ftst", 0, 0, 0, OP_FCHS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxam", 0, 0, 0, OP_FCHS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("fld1", 0, 0, 0, OP_FLD1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldl2t", 0, 0, 0, OP_FLDL2T, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldl2e", 0, 0, 0, OP_FLDL2E, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldpi", 0, 0, 0, OP_FLDPI, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldlg2", 0, 0, 0, OP_FLDLG2, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldln2", 0, 0, 0, OP_FLDLN2, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fldz", 0, 0, 0, OP_FLDZ, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + + /* f */ + OP("f2xm1", 0, 0, 0, OP_F2XM1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fyl2x", 0, 0, 0, OP_FYL2X, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fptan", 0, 0, 0, OP_FPTAN, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fpatan", 0, 0, 0, OP_FPATAN, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxtract", 0, 0, 0, OP_FXTRACT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("frem1", 0, 0, 0, OP_FREM1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdecstp", 0, 0, 0, OP_FDECSTP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fincstp", 0, 0, 0, OP_FINCSTP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fprem", 0, 0, 0, OP_FPREM, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fyl2xp1", 0, 0, 0, OP_FYL2XP1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsqrt", 0, 0, 0, OP_FSQRT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsincos", 0, 0, 0, OP_FSINCOS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("frndint", 0, 0, 0, OP_FRNDINT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fscale", 0, 0, 0, OP_FSCALE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsin", 0, 0, 0, OP_FSIN, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcos", 0, 0, 0, OP_FCOS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xDA (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF2_Low[8] = +{ + /* 0 */ + OP("fiadd %Md", IDX_ParseModRM, 0, 0, OP_FIADD, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fimul %Md", IDX_ParseModRM, 0, 0, OP_FIMUL, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ficom %Md", IDX_ParseModRM, 0, 0, OP_FICOM, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ficomp %Md", IDX_ParseModRM, 0, 0, OP_FICOMP, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fisub %Md", IDX_ParseModRM, 0, 0, OP_FISUB, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fisubr %Md", IDX_ParseModRM, 0, 0, OP_FISUBR, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fidiv %Md", IDX_ParseModRM, 0, 0, OP_FIDIV, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fidivr %Md", IDX_ParseModRM, 0, 0, OP_FIDIVR, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xD9 (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF2_High[16*4] = +{ + /* c */ + OP("fcmovb ST(0),ST(0)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(1)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(2)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(3)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(4)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(5)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(6)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovb ST(0),ST(7)", 0, 0, 0, OP_FCMOVB, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(0)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(1)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(2)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(3)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(4)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(5)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(6)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmove ST(0),ST(7)", 0, 0, 0, OP_FCMOVE, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* d */ + OP("fcmovbe ST(0),ST(0)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(1)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(2)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(3)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(4)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(5)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(6)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovbe ST(0),ST(7)", 0, 0, 0, OP_FCMOVBE, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(0)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(1)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(2)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(3)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(4)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(5)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(6)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovu ST(0),ST(7)", 0, 0, 0, OP_FCMOVU, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* e */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("fucompp", 0, 0, 0, OP_FUCOMPP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* f */ + INVALID_OPCODE_BLOCK +}; + + +/* Floating point opcode starting with escape byte 0xDB (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF3_Low[8] = +{ + /* 0 */ + OP("fild %Md", IDX_ParseModRM, 0, 0, OP_FILD, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("fist %Md", IDX_ParseModRM, 0, 0, OP_FIST, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fistp %Md", IDX_ParseModRM, 0, 0, OP_FISTP, OP_PARM_Md, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("fld %Mq", IDX_ParseModRM, 0, 0, OP_FLD, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("fstp %Mq", IDX_ParseModRM, 0, 0, OP_FSTP, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xDB (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF3_High[16*4] = +{ + /* c */ + OP("fcmovnb ST(0),ST(0)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(1)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(2)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(3)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(4)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(5)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(6)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnb ST(0),ST(7)", 0, 0, 0, OP_FCMOVNB, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(0)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(1)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(2)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(3)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(4)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(5)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(6)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovne ST(0),ST(7)", 0, 0, 0, OP_FCMOVNE, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* d */ + OP("fcmovnbe ST(0),ST(0)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(1)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(2)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(3)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(4)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(5)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(6)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnbe ST(0),ST(7)", 0, 0, 0, OP_FCMOVNBE,OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(0)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(1)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(2)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(3)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(4)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(5)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(6)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcmovnu ST(0),ST(7)", 0, 0, 0, OP_FCMOVNU, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* e */ + INVALID_OPCODE, + INVALID_OPCODE, + OP("fclex", 0, 0, 0, OP_FCLEX, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("finit", 0, 0, 0, OP_FINIT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("fucomi ST(0),ST(0)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(1)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(2)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(3)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(4)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(5)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(6)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomi ST(0),ST(7)", 0, 0, 0, OP_FUCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* e */ + OP("fcomi ST(0),ST(0)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(1)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(2)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(3)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(4)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(5)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(6)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomi ST(0),ST(7)", 0, 0, 0, OP_FCOMI, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + + +/* Floating point opcode starting with escape byte 0xDC (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF4_Low[8] = +{ + /* 0 */ + OP("fadd %Mq", IDX_ParseModRM, 0, 0, OP_FADD, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul %Mq", IDX_ParseModRM, 0, 0, OP_FMUL, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcom %Mq", IDX_ParseModRM, 0, 0, OP_FCOM, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomp %Mq", IDX_ParseModRM, 0, 0, OP_FCOMP, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub %Mq", IDX_ParseModRM, 0, 0, OP_FSUB, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr %Mq", IDX_ParseModRM, 0, 0, OP_FSUBR, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv %Mq", IDX_ParseModRM, 0, 0, OP_FDIV, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr %Mq", IDX_ParseModRM, 0, 0, OP_FDIVR, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xDC (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF4_High[16*4] = +{ + /* c */ + OP("fadd ST(0),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(1),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(2),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(3),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(4),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(5),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(6),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fadd ST(7),ST(0)", 0, 0, 0, OP_FADD, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(0),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(1),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(2),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(3),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(4),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(5),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(6),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmul ST(7),ST(0)", 0, 0, 0, OP_FMUL, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* d */ + INVALID_OPCODE_BLOCK + + + /* e */ + OP("fsubr ST(0),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(1),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(2),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(3),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(4),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(5),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(6),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubr ST(7),ST(0)", 0, 0, 0, OP_FSUBR, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(0),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(1),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(2),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(3),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(4),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(5),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(6),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsub ST(7),ST(0)", 0, 0, 0, OP_FSUB, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + OP("fdivr ST(0),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(1),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(2),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(3),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(4),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(5),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(6),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivr ST(7),ST(0)", 0, 0, 0, OP_FDIVR, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(0),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(1),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(2),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(3),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(4),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(5),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(6),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdiv ST(7),ST(0)", 0, 0, 0, OP_FDIV, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xDD (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF5_Low[8] = +{ + /* 0 */ + OP("fld %Mq", IDX_ParseModRM, 0, 0, OP_FLD, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS /* fixme: wasn't initialized! */), + INVALID_OPCODE, + OP("fst %Mq", IDX_ParseModRM, 0, 0, OP_FST, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS /* fixme: wasn't initialized! */), + OP("fstp %Mq", IDX_ParseModRM, 0, 0, OP_FSTP, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS /* fixme: wasn't initialized! */), + OP("frstor %M", IDX_ParseModRM, 0, 0, OP_FRSTOR, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS /* fixme: wasn't initialized! */), + INVALID_OPCODE, + OP("fnsave %M", IDX_ParseModRM, 0, 0, OP_FSAVE, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS /* fixme: wasn't initialized! */), + OP("fnstsw %Mw", IDX_ParseModRM, 0, 0, OP_FNSTSW, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS /* fixme: wasn't initialized! */), +}; + + +/* Floating point opcode starting with escape byte 0xDD (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF5_High[16*4] = +{ + /* c */ + OP("ffree ST(0)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_0, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(1)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_1, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(2)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_2, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(3)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_3, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(4)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_4, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(5)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_5, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(6)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_6, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ffree ST(7)", 0, 0, 0, OP_FFREE, OP_PARM_REGFP_7, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + OP("fst ST(0)", 0, 0, 0, OP_FST, OP_PARM_REGFP_0, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(1)", 0, 0, 0, OP_FST, OP_PARM_REGFP_1, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(2)", 0, 0, 0, OP_FST, OP_PARM_REGFP_2, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(3)", 0, 0, 0, OP_FST, OP_PARM_REGFP_3, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(4)", 0, 0, 0, OP_FST, OP_PARM_REGFP_4, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(5)", 0, 0, 0, OP_FST, OP_PARM_REGFP_5, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(6)", 0, 0, 0, OP_FST, OP_PARM_REGFP_6, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fst ST(7)", 0, 0, 0, OP_FST, OP_PARM_REGFP_7, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(0)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_0, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(1)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_1, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(2)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_2, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(3)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_3, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(4)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_4, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(5)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_5, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(6)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_6, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fstp ST(7)", 0, 0, 0, OP_FSTP, OP_PARM_REGFP_7, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* e */ + OP("fucom ST(0)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_0, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(1)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_1, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(2)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_2, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(3)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_3, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(4)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_4, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(5)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_5, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(6)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_6, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucom ST(7)", 0, 0, 0, OP_FUCOM, OP_PARM_REGFP_7, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(0)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_0, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(1)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_1, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(2)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_2, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(3)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_3, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(4)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_4, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(5)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_5, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(6)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_6, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomp ST(7)", 0, 0, 0, OP_FUCOMP, OP_PARM_REGFP_7, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + INVALID_OPCODE_BLOCK +}; + + + +/* Floating point opcode starting with escape byte 0xDE (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF6_Low[8] = +{ + /* 0 */ + OP("fiadd %Mw", IDX_ParseModRM, 0, 0, OP_FIADD, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fimul %Mw", IDX_ParseModRM, 0, 0, OP_FIMUL, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ficom %Mw", IDX_ParseModRM, 0, 0, OP_FICOM, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ficomp %Mw", IDX_ParseModRM, 0, 0, OP_FICOMP, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fisub %Mw", IDX_ParseModRM, 0, 0, OP_FISUB, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fisubr %Mw", IDX_ParseModRM, 0, 0, OP_FISUBR, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fidiv %Mw", IDX_ParseModRM, 0, 0, OP_FIDIV, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fidivr %Mw", IDX_ParseModRM, 0, 0, OP_FIDIVR, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xDE (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF6_High[16*4] = +{ + /* c */ + OP("faddp ST(0),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(1),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(2),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(3),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(4),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(5),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(6),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("faddp ST(7),ST(0)", 0, 0, 0, OP_FADDP, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(0),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(1),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(2),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(3),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(4),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(5),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(6),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fmulp ST(7),ST(0)", 0, 0, 0, OP_FMULP, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* d */ + INVALID_OPCODE, + OP("fcompp", 0, 0, 0, OP_FCOMPP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + + /* e */ + OP("fsubrp ST(0),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(1),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(2),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(3),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(4),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(5),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(6),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubrp ST(7),ST(0)", 0, 0, 0, OP_FSUBRP, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(0),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(1),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(2),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(3),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(4),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(5),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(6),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fsubp ST(7),ST(0)", 0, 0, 0, OP_FSUBP, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + OP("fdivrp ST(0),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(1),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(2),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(3),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(4),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(5),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(6),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivrp ST(7),ST(0)", 0, 0, 0, OP_FDIVRP, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(0),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(1),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_1, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(2),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_2, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(3),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_3, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(4),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_4, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(5),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_5, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(6),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_6, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fdivp ST(7),ST(0)", 0, 0, 0, OP_FDIVP, OP_PARM_REGFP_7, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +/* Floating point opcode starting with escape byte 0xDF (values 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF7_Low[8] = +{ + /* 0 */ + OP("fild %Mw", IDX_ParseModRM, 0, 0, OP_FILD, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("fist %Mw", IDX_ParseModRM, 0, 0, OP_FIST, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fistp %Mw", IDX_ParseModRM, 0, 0, OP_FISTP, OP_PARM_Mw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fbld %M", IDX_ParseModRM, 0, 0, OP_FBLD, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fild %Mq", IDX_ParseModRM, 0, 0, OP_FILD, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fbstp %M", IDX_ParseModRM, 0, 0, OP_FBSTP, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fistp %Mq", IDX_ParseModRM, 0, 0, OP_FISTP, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* Floating point opcode starting with escape byte 0xDF (outside 0-0xBF)*/ +const DISOPCODE g_aMapX86_EscF7_High[16*4] = +{ + /* c */ + INVALID_OPCODE_BLOCK + + /* d */ + INVALID_OPCODE_BLOCK + + /* e */ + OP("fnstsw ax", IDX_ParseFixedReg, 0, 0, OP_FNSTSW, OP_PARM_REG_AX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("fucomip ST(0),ST(0)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(1)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(2)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(3)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(4)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(5)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(6)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fucomip ST(0),ST(7)", 0, 0, 0, OP_FUCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + OP("fcomip ST(0),ST(0)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_0,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(1)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_1,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(2)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_2,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(3)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_3,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(4)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_4,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(5)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_5,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(6)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_6,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fcomip ST(0),ST(7)", 0, 0, 0, OP_FCOMIP, OP_PARM_REGFP_0, OP_PARM_REGFP_7,OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + + +const PCDISOPCODE g_apMapX86_FP_Low[8] = +{ + g_aMapX86_EscF0_Low, + g_aMapX86_EscF1_Low, + g_aMapX86_EscF2_Low, + g_aMapX86_EscF3_Low, + g_aMapX86_EscF4_Low, + g_aMapX86_EscF5_Low, + g_aMapX86_EscF6_Low, + g_aMapX86_EscF7_Low +}; + +const PCDISOPCODE g_apMapX86_FP_High[8] = +{ + g_aMapX86_EscF0_High, + g_aMapX86_EscF1_High, + g_aMapX86_EscF2_High, + g_aMapX86_EscF3_High, + g_aMapX86_EscF4_High, + g_aMapX86_EscF5_High, + g_aMapX86_EscF6_High, + g_aMapX86_EscF7_High +}; + +/* Opcode extensions (Group tables) */ +const DISOPCODE g_aMapX86_Group1[8*4] = +{ + /* 80 */ + OP("add %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ADD, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_OR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ADC, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SBB, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_AND, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SUB, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_XOR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_CMP, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 81 */ + OP("add %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_ADD, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_OR, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_ADC, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_SBB, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_AND, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_SUB, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_XOR, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_CMP, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 82 */ + OP("add %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ADD, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_OR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ADC, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SBB, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_AND, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SUB, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_XOR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_CMP, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 83 */ + OP("add %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_ADD, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_OR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_ADC, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_SBB, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_AND, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_SUB, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_XOR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByteSX, 0, OP_CMP, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +const DISOPCODE g_aMapX86_Group2[8*6] = +{ + /* C0 */ + OP("rol %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ROL, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ror %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ROR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcl %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_RCL, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcr %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_RCR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SHL, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shr %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SHR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SHL, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sar %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SAR, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* C1 */ + OP("rol %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ROL, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ror %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_ROR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcl %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_RCL, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcr %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_RCR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SHL, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shr %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SHR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SHL, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sar %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_SAR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* D0 */ + OP("rol %Eb,1", IDX_ParseModRM, 0, 0, OP_ROL, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ror %Eb,1", IDX_ParseModRM, 0, 0, OP_ROR, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcl %Eb,1", IDX_ParseModRM, 0, 0, OP_RCL, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcr %Eb,1", IDX_ParseModRM, 0, 0, OP_RCR, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Eb,1", IDX_ParseModRM, 0, 0, OP_SHL, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shr %Eb,1", IDX_ParseModRM, 0, 0, OP_SHR, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Eb,1", IDX_ParseModRM, 0, 0, OP_SHL, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sar %Eb,1", IDX_ParseModRM, 0, 0, OP_SAR, OP_PARM_Eb, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* D1 */ + OP("rol %Ev,1", IDX_ParseModRM, 0, 0, OP_ROL, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ror %Ev,1", IDX_ParseModRM, 0, 0, OP_ROR, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcl %Ev,1", IDX_ParseModRM, 0, 0, OP_RCL, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcr %Ev,1", IDX_ParseModRM, 0, 0, OP_RCR, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Ev,1", IDX_ParseModRM, 0, 0, OP_SHL, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shr %Ev,1", IDX_ParseModRM, 0, 0, OP_SHR, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Ev,1", IDX_ParseModRM, 0, 0, OP_SHL, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sar %Ev,1", IDX_ParseModRM, 0, 0, OP_SAR, OP_PARM_Ev, OP_PARM_1 , OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* D2 */ + OP("rol %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_ROL, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ror %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_ROR, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcl %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_RCL, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcr %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_RCR, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SHL, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shr %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SHR, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SHL, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sar %Eb,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SAR, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* D3 */ + OP("rol %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_ROL, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ror %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_ROR, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcl %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_RCL, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rcr %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_RCR, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SHL, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shr %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SHR, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("shl/sal %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SHL, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sar %Ev,CL", IDX_ParseModRM, IDX_ParseFixedReg, 0, OP_SAR, OP_PARM_Ev, OP_PARM_REG_CL ,OP_PARM_NONE, DISOPTYPE_HARMLESS), + +}; + + +const DISOPCODE g_aMapX86_Group3[8*2] = +{ + /* F6 */ + OP("test %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_TEST, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + //AMD manual claims test?? + INVALID_OPCODE_MOD_RM(0xf601), + OP("not %Eb", IDX_ParseModRM, 0, 0, OP_NOT, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("neg %Eb", IDX_ParseModRM, 0, 0, OP_NEG, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mul %Eb", IDX_ParseModRM, 0, 0, OP_MUL, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("imul %Eb", IDX_ParseModRM, 0, 0, OP_IMUL, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("div %Eb", IDX_ParseModRM, 0, 0, OP_DIV, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("idiv %Eb", IDX_ParseModRM, 0, 0, OP_IDIV, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* F7 */ + OP("test %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_TEST, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + //AMD manual claims test?? + INVALID_OPCODE_MOD_RM(0xf701), + OP("not %Ev", IDX_ParseModRM, 0, 0, OP_NOT, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("neg %Ev", IDX_ParseModRM, 0, 0, OP_NEG, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mul %Ev", IDX_ParseModRM, 0, 0, OP_MUL, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("imul %Ev", IDX_ParseModRM, 0, 0, OP_IMUL, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("div %Ev", IDX_ParseModRM, 0, 0, OP_DIV, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("idiv %Ev", IDX_ParseModRM, 0, 0, OP_IDIV, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +const DISOPCODE g_aMapX86_Group4[8] = +{ + /* FE */ + OP("inc %Eb", IDX_ParseModRM, 0, 0, OP_INC, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %Eb", IDX_ParseModRM, 0, 0, OP_DEC, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0xfe02), + INVALID_OPCODE_MOD_RM(0xfe03), + INVALID_OPCODE_MOD_RM(0xfe04), + INVALID_OPCODE_MOD_RM(0xfe05), + INVALID_OPCODE_MOD_RM(0xfe06), + INVALID_OPCODE_MOD_RM(0xfe07), +}; + +const DISOPCODE g_aMapX86_Group5[8] = +{ + /* FF */ + OP("inc %Ev", IDX_ParseModRM, 0, 0, OP_INC, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("dec %Ev", IDX_ParseModRM, 0, 0, OP_DEC, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("call %Ev", IDX_ParseModRM, 0, 0, OP_CALL, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("call %Ep", IDX_ParseModRM, 0, 0, OP_CALL, OP_PARM_Ep, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW), + OP("jmp %Ev", IDX_ParseModRM, 0, 0, OP_JMP, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jmp %Ep", IDX_ParseModRM, 0, 0, OP_JMP, OP_PARM_Ep, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + OP("push %Ev", IDX_ParseModRM, 0, 0, OP_PUSH, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + INVALID_OPCODE_MOD_RM(0xff07), +}; + + +const DISOPCODE g_aMapX86_Group6[8] = +{ + /* 0F 00 */ + OP("sldt %Ew", IDX_ParseModRM, 0, 0, OP_SLDT, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + OP("str %Ev", IDX_ParseModRM, 0, 0, OP_STR, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + OP("lldt %Ew", IDX_ParseModRM, 0, 0, OP_LLDT, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("ltr %Ew", IDX_ParseModRM, 0, 0, OP_LTR, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("verr %Ew", IDX_ParseModRM, 0, 0, OP_VERR, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + OP("verw %Ew", IDX_ParseModRM, 0, 0, OP_VERW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + INVALID_OPCODE_MOD_RM(0x0f0006), + INVALID_OPCODE_MOD_RM(0x0f0007), +}; + +/* Note!! Group 7 is NOT using the INVALID_OPCODE_MOD_RM because of monitor and vmcall. */ +const DISOPCODE g_aMapX86_Group7_mem[8] = +{ + /* 0F 01 */ + OP("sgdt %Ms", IDX_ParseModRM, 0, 0, OP_SGDT, OP_PARM_Ms, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + OP("sidt %Ms", IDX_ParseModRM, 0, 0, OP_SIDT, OP_PARM_Ms, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + OP("lgdt %Ms", IDX_ParseModRM, 0, 0, OP_LGDT, OP_PARM_Ms, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("lidt %Ms", IDX_ParseModRM, 0, 0, OP_LIDT, OP_PARM_Ms, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("smsw %Ew", IDX_ParseModRM, 0, 0, OP_SMSW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + INVALID_OPCODE, + OP("lmsw %Ew", IDX_ParseModRM, 0, 0, OP_LMSW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("invlpg %Mb", IDX_ParseModRM, 0, 0, OP_INVLPG, OP_PARM_Mb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), +}; + +/* Note!! Group 7 is NOT using the INVALID_OPCODE_MOD_RM because of monitor and vmcall. */ +const DISOPCODE g_aMapX86_Group7_mod11_rm000[8] = +{ + /* 0F 01 MOD=11b */ + INVALID_OPCODE, + OP("monitor %eAX,%eCX,%eDX", IDX_ParseFixedReg, IDX_ParseFixedReg, IDX_ParseFixedReg, OP_MONITOR, OP_PARM_REG_EAX, OP_PARM_REG_ECX, OP_PARM_REG_EDX, DISOPTYPE_HARMLESS ), + OP("xgetbv", 0, 0, 0, OP_XGETBV, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS ), /* fixed ops: ECX & EDX:EAX like wrmsr we don't details these */ + INVALID_OPCODE, + OP("smsw %Ew", IDX_ParseModRM, 0, 0, OP_SMSW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + INVALID_OPCODE, + OP("lmsw %Ew", IDX_ParseModRM, 0, 0, OP_LMSW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("swapgs", 0, 0, 0, OP_SWAPGS, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS ) +}; + +/* Note!! Group 7 is NOT using the INVALID_OPCODE_MOD_RM because of monitor and vmcall. */ +const DISOPCODE g_aMapX86_Group7_mod11_rm001[8] = +{ + /* 0F 01 MOD=11b */ + OP("vmcall", 0, 0, 0, OP_VMCALL, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS ), + OP("mwait %eAX,%eCX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_MWAIT, OP_PARM_REG_EAX, OP_PARM_REG_ECX,OP_PARM_NONE, DISOPTYPE_HARMLESS ), + OP("xsetbv", 0, 0, 0, OP_XSETBV, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS ), /* fixed ops: ECX & EDX:EAX like wrmsr we don't details these */ + OP("vmmcall", 0, 0, 0, OP_VMMCALL, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS ), + OP("smsw %Ew", IDX_ParseModRM, 0, 0, OP_SMSW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED_NOTRAP), + INVALID_OPCODE, + OP("lmsw %Ew", IDX_ParseModRM, 0, 0, OP_LMSW, OP_PARM_Ew, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("rdtscp", 0, 0, 0, OP_RDTSCP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS ), +}; + +const DISOPCODE g_aMapX86_Group8[8] = +{ + /* 0F BA */ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("bt %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_BT, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("bts %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_BTS, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("btr %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_BTR, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("btc %Ev,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_BTC, OP_PARM_Ev, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +const DISOPCODE g_aMapX86_Group9[8] = +{ + /* 0F C7 */ + INVALID_OPCODE_MOD_RM(0x), + OP("cmpxchg8b %Mq", IDX_ParseModRM, 0, 0, OP_CMPXCHG8B, OP_PARM_Mq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("rdrand %Ev", IDX_ParseModRM, 0, 0, OP_RDRAND, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rdseed %Ev", IDX_ParseModRM, 0, 0, OP_RDSEED, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +const DISOPCODE g_aMapX86_Group10[8] = +{ + /* 0F B9 */ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), +}; + + +const DISOPCODE g_aMapX86_Group11[8*2] = +{ + /* 0F C6 */ + OP("mov %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_Eb, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + /* 0F C7 */ + OP("mov %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, +}; + + +/* 0xF 0x71 */ +const DISOPCODE g_aMapX86_Group12[8*2] = +{ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psrlw %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLW, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("psraw %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRAW, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("psllw %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLW, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + + /* Group 12 with prefix 0x66 */ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psrlw %Pdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLW, OP_PARM_Pdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("psraw %Pdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRAW, OP_PARM_Pdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("psllw %Pdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLW, OP_PARM_Pdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), +}; + +/* 0xF 0x72 */ +const DISOPCODE g_aMapX86_Group13[8*2] = +{ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psrld %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLD, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("psrad %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRAD, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("pslld %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLD, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + + /* Group 13 with prefix 0x66 */ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psrld %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLD, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("psrad %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRAD, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + OP("pslld %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLD, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), +}; + +/* 0xF 0x73 */ +const DISOPCODE g_aMapX86_Group14[8*2] = +{ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psrlq %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLQ, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psllq %Pq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLQ, OP_PARM_Pq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + + /* Group 14 with prefix 0x66 */ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psrlq %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLD, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("psrldq %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSRLDQ, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + OP("psllq %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLD, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pslldq %Wdq,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_PSLLDQ, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + +/* 0xF 0xAE */ +const DISOPCODE g_aMapX86_Group15_mem[8] = +{ + OP("fxsave %M", IDX_ParseModRM, 0, 0, OP_FXSAVE, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("fxrstor %M", IDX_ParseModRM, 0, 0, OP_FXRSTOR, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ldmxcsr %M", IDX_ParseModRM, 0, 0, OP_LDMXCSR, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stmxcsr %M", IDX_ParseModRM, 0, 0, OP_STMXCSR, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xsave %M", IDX_ParseModRM, 0, 0, OP_XSAVE, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xrstor %M", IDX_ParseModRM, 0, 0, OP_XRSTOR, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xsaveopt %M", IDX_ParseModRM, 0, 0, OP_XSAVEOPT, OP_PARM_M, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("clflush %Mb", IDX_ParseModRM, 0, 0, OP_CLFLUSH, OP_PARM_Mb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +/* 0xF 0xAE */ +const DISOPCODE g_aMapX86_Group15_mod11_rm000[8] = +{ + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + /** @todo mfence + lfence + sfence instructions do not require rm=0, + * they work for any RM value. See bs2-cpu-instr-1.asm for details. */ + OP("lfence", IDX_ParseModFence, 0, 0, OP_LFENCE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mfence", IDX_ParseModFence, 0, 0, OP_MFENCE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sfence", IDX_ParseModFence, 0, 0, OP_SFENCE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + +/* 0xF 0x18 */ +const DISOPCODE g_aMapX86_Group16[8] = +{ + OP("prefetchnta %Mb", IDX_ParseModRM, 0, 0, OP_PREFETCH,OP_PARM_Mb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("prefetcht0 %Mb", IDX_ParseModRM, 0, 0, OP_PREFETCH,OP_PARM_Mb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("prefetcht1 %Mb", IDX_ParseModRM, 0, 0, OP_PREFETCH,OP_PARM_Mb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("prefetcht2 %Mb", IDX_ParseModRM, 0, 0, OP_PREFETCH,OP_PARM_Mb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), + INVALID_OPCODE_MOD_RM(0x), +}; + +/* 0x90 or 0xF3 0x90 */ +const DISOPCODE g_aMapX86_NopPause[2] = +{ + OP("nop", 0, 0, 0, OP_NOP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pause", 0, 0, 0, OP_PAUSE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + + + +/* VEX Map 1 - two bytes opcodes starting with 0Fh */ +const DISOPCODE g_aDisasVexMap1[] = +{ + /* 1 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("vmovups %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVUPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovups %Wps,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVUPS, OP_PARM_Wps, OP_PARM_Vps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("&vmovlps/vmovhlps %Vq,%Hq,%Wq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVLPS, OP_PARM_Vq, OP_PARM_Hq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovlps %Mq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVLPS, OP_PARM_Mq, OP_PARM_Vq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vunpcklps %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VUNPCKLPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vunpckhps %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VUNPCKHPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("&vmovhps/vmovlhps %Vdq,%Hq,%Wq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVHPS, OP_PARM_Vdq, OP_PARM_Hq, OP_PARM_Wq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovhps %Mq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVHPS, OP_PARM_Mq, OP_PARM_Vq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vmovaps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVAPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovaps %Wps,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVAPS, OP_PARM_Wps, OP_PARM_Vps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vmovntps %Mps,%Vps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVNTPS, OP_PARM_Mps, OP_PARM_Vps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vucomiss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VUCOMISS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcomiss %Vss,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCOMISS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 3 */ + INVALID_OPCODE_BLOCK + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + OPVEX("vmovmskps %Gy,%Ups", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVMSKPS, OP_PARM_Gy, OP_PARM_Ups, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vsqrtps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VSQRTPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vrsqrtps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VRSQRTPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vrcpps %Vps,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VRCPPS, OP_PARM_Vps, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vandps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VANDPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vandnps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VANDNPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vorps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VORPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vxorps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VXORPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vaddps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VADDPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmulps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMULPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtps2pd %Vpd,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTPS2PD, OP_PARM_Vpd, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtdq2ps %Vps,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTDQ2PS, OP_PARM_Vps, OP_PARM_Wdq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vsubps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VSUBPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vminps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMINPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vdivps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VDIVPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaxps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMAXPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE_BLOCK + + /* 7 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + /* Next instruction has the following format: + * @name1/name2, + * where name2 is used when VEX.L bit is set, + * name1 otherwise. */ + OPVEX("@vzeroupper/vzeroall", 0, 0, 0, 0, OP_VZEROALL, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 8 */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c */ + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcmpss %Vps,%Hps,%Wps,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VCMPSS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vshufps %Vps,%Hps,%Wps,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VSHUFPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_Ib, DISOPTYPE_HARMLESS), + /* format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ +}; +const DISOPMAPDESC g_DisasVexMap1Range = { &g_aDisasVexMap1[0], 0x10, RT_ELEMENTS(g_aDisasVexMap1) }; + +/* Vex codes for two bytes opcodes starting with 0Fh with prefix 66H*/ +static const DISOPCODE g_aDisasVexMap1_66[] = +{ + /* 1 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("vmovupd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVUPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovupd %Wpd,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVUPD, OP_PARM_Wpd, OP_PARM_Vpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovlpd %Vq,%Hq,%Mq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVLPD, OP_PARM_Vq, OP_PARM_Hq, OP_PARM_Mq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovlpd %Mq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVLPD, OP_PARM_Mq, OP_PARM_Vq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vunpcklpd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VUNPCKLPD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vunpckhpd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VUNPCKHPD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovhpd %Vdq,%Hq,%Mq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVHPD, OP_PARM_Vdq, OP_PARM_Hq, OP_PARM_Mq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovhpd %Mq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVHPD, OP_PARM_Mq, OP_PARM_Vq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vmovapd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVAPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovapd %Wpd,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVAPD, OP_PARM_Wpd, OP_PARM_Vpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vmovntpd %Mpd,%Vpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVNTPD, OP_PARM_Mpd, OP_PARM_Vpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vucomisd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VUCOMISD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcomisd %Vsd,%Wsd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCOMISD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 3 */ + INVALID_OPCODE_BLOCK + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + OPVEX("vmovmskpd %Gy,%Upd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVMSKPD, OP_PARM_Gy, OP_PARM_Upd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vsqrtpd %Vpd,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VSQRTPD, OP_PARM_Vpd, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vandpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VANDPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vandnpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VANDNPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vorpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VORPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vxorpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VXORPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vaddpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VADDPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmulpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMULPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtpd2ps %Vps,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTPD2PS, OP_PARM_Vps, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtps2dq %Vdq,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTPS2DQ, OP_PARM_Vdq, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vsubpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VSUBPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vminpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMINPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vdivpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VDIVPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaxpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMAXPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* 6 */ + OPVEX("vpunpcklbw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKLBW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpcklwd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKLWD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpckldq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKLDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpacksswb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPACKSSWB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpgtb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPGTB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpgtw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPGTW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpgtd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPGTD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpackuswb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPACKUSWB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpckhbw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKHBW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpckhwd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKHWD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpckhdq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKHDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpackssdw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPACKSSDW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpcklqdq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKLQDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpunpckhqdq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPUNPCKHQDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vmovd/vmovq %Vy,%Ey", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVD, OP_PARM_Vy, OP_PARM_Ey, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovdqa %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVDQA, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 7 */ + OPVEX("vpshufd %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPSHUFD, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vpcmpeqb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPEQB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpeqw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPEQW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpeqd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPEQD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vhaddpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VHADDPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vhsubpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VHSUBPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovd/vmovq %Ey,%Vy", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVD, OP_PARM_Ey, OP_PARM_Vy, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovdqa %Wx,%Vx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVDQA, OP_PARM_Wx, OP_PARM_Vx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 8 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcmpps %Vpd,%Hpd,%Wpd,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VCMPSS, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + // vpinsrw Vdq,Hdq,Ry/Mw,Ib + OPVEX("vpinsrw %Vdq,%Hdq,%Ey,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPINSRW, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Ey, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vpextrw %Gd,%Udq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPEXTRW, OP_PARM_Gd, OP_PARM_Udq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vshufpd %Vpd,%Hpd,%Wpd,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VSHUFPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + OPVEX("vaddsubpd %Vpd,%Hpd,%Wpd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VADDSUBPD, OP_PARM_Vpd, OP_PARM_Hpd, OP_PARM_Wpd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsrlw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRLW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsrld %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRLD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsrlq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRLQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmullw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULLW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovq %Wq,%Vq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVQ, OP_PARM_Wq, OP_PARM_Vq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovmskb %Gd,%Ux", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVMSKB, OP_PARM_Gd, OP_PARM_Ux, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OPVEX("vpsubusb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBUSB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubusw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBUSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpminub %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMINUB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpand %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPAND, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddusb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDUSB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddusw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDUSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaxub %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMAXUB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpandn %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPANDN, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* e */ + OPVEX("vpavgb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPAVGB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsraw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRAW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsrad %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRAD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpavgw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPAVGW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmulhuw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULHUW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmulhw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULHW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvttpd2dq %Vx,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTTPD2DQ, OP_PARM_Vx, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovntdq %Mx,%Vx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVNTDQ, OP_PARM_Mx, OP_PARM_Vx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubsb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBSB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpminsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMINSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpor %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPOR, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddsb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDSB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaxsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMAXSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpxor %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPXOR, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* f */ + INVALID_OPCODE, + OPVEX("vpsllw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSLLW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpslld %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSLLD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsllq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSLLQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmuludq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULUDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaddwd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMADDWD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsadbw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSADBW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaskmovdqu %Vdq,%Udq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMASKMOVDQU, OP_PARM_Vdq, OP_PARM_Udq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsubq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSUBQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpaddd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPADDD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ +}; +const DISOPMAPDESC g_DisasVexMap1_66Range = { &g_aDisasVexMap1_66[0], 0x10, RT_ELEMENTS(g_aDisasVexMap1_66) }; + +static const DISOPCODE g_aDisasVexMap1F2[] = +{ + /* 1 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("vmovsd %Vx,%Hx,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVSD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovsd %Wsd,%Hx,%Vsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVSD, OP_PARM_Wsd, OP_PARM_Hx, OP_PARM_Vsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovddup %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVDDUP, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE_BLOCK + + /* 3 */ + INVALID_OPCODE_BLOCK + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + INVALID_OPCODE, + OPVEX("vsqrtsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VSQRTSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vaddsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VADDSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmulsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMULSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtsd2ss %Vss,%Hx,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VCVTSD2SS, OP_PARM_Vss, OP_PARM_Hx, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vsubsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VSUBSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vminsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMINSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vdivsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VDIVSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaxsd %Vsd,%Hsd,%Wsd", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMAXSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 */ + INVALID_OPCODE_BLOCK + + /* 7 */ + OPVEX("vpshuflw %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPSHUFLW, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vhaddps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VHADDPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vhsubps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VHSUBPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* 8 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c */ + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcmpsd %Vsd,%Hsd,%Wsd,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VCMPSD, OP_PARM_Vsd, OP_PARM_Hsd, OP_PARM_Wsd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + OPVEX("vaddsubps %Vps,%Hps,%Wps", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VADDSUBPS, OP_PARM_Vps, OP_PARM_Hps, OP_PARM_Wps, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* e */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcvtpd2dq %Vx,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTPD2DQ, OP_PARM_Vx, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* f */ + OPVEX("vlddqu %Vx,%Mx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VLDDQU, OP_PARM_Vx, OP_PARM_Mx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ +}; +const DISOPMAPDESC g_DisasVexMap1F2Range = { &g_aDisasVexMap1F2[0], 0x10, RT_ELEMENTS(g_aDisasVexMap1F2) }; + +/* Vex codes for two bytes opcodes starting with 0Fh with prefix F3H*/ +static const DISOPCODE g_aDisasVexMap1F3[] = +{ + /* 1 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("vmovss %Vx,%Hx,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVSS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovss %Wss,%Hx,%Vss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMOVSS, OP_PARM_Wss, OP_PARM_Hx, OP_PARM_Vss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovsldup %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVSLDUP, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vmovshdup %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVSHDUP, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcvtsi2ss %Vss,%Hss,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VCVTSI2SS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vcvttss2si %Gy,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTTSS2SI, OP_PARM_Gy, OP_PARM_Wss, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtss2si %Gy,%Wss", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTSS2SI, OP_PARM_Gy, OP_PARM_Wss, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* 3 */ + INVALID_OPCODE_BLOCK + + /* 4 */ + INVALID_OPCODE_BLOCK + + /* 5 */ + INVALID_OPCODE, + OPVEX("vsqrtss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VSQRTSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vrsqrtss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VRSQRTSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vrcpss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VRCPSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vaddss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VADDSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmulss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMULSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvtss2sd %Vsd,%Hx,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VCVTSS2SD, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vcvttps2dq %Vdq,%Wps", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTTPS2DQ, OP_PARM_Vdq, OP_PARM_Wps, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vsubss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VSUBSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vminss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMINSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vdivss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VDIVSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaxss %Vss,%Hss,%Wss", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMAXSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 6 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vmovdqu %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVDQU, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 7 */ + OPVEX("vpshufhw %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPSHUFHW, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vmovq %Vq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVQ, OP_PARM_Vq, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovdqu %Wx,%Vx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVDQU, OP_PARM_Wx, OP_PARM_Vx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 8 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c */ + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcmpps %Vss,%Hss,%Wss,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VCMPSS, OP_PARM_Vss, OP_PARM_Hss, OP_PARM_Wss, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* d */ + INVALID_OPCODE_BLOCK + + /* e */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcvtdq2pd %Vx,%Wpd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VCVTDQ2PD, OP_PARM_Vx, OP_PARM_Wpd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ +}; +const DISOPMAPDESC g_DisasVexMap1F3Range = { &g_aDisasVexMap1F3[0], 0x10, RT_ELEMENTS(g_aDisasVexMap1F3) }; + +/** Indexed by: (/r << 1) | VEX.L */ +const DISOPCODE g_aMapX86_Group17[8*2] = +{ + /* 0 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE_MOD_RM(0x00), + INVALID_OPCODE_MOD_RM(0x01), + OPVEX("blsr %By,%Ey", IDX_ParseVexDest, IDX_ParseModRM, 0, 0, OP_BLSR, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x03), + OPVEX("blsmsk %By,%Ey", IDX_ParseVexDest, IDX_ParseModRM, 0, 0, OP_BLSMSK, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x05), + OPVEX("blsi %By,%Ey", IDX_ParseVexDest, IDX_ParseModRM, 0, 0, OP_BLSI, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE_MOD_RM(0x07), + INVALID_OPCODE_MOD_RM(0x08), + INVALID_OPCODE_MOD_RM(0x09), + INVALID_OPCODE_MOD_RM(0x0a), + INVALID_OPCODE_MOD_RM(0x0b), + INVALID_OPCODE_MOD_RM(0x0c), + INVALID_OPCODE_MOD_RM(0x0d), + INVALID_OPCODE_MOD_RM(0x0e), + INVALID_OPCODE_MOD_RM(0x0f), +}; + +static const DISOPCODE g_aDisasVexMap2[] = +{ + /** @todo vsha1nexte at 0xc8 + ? */ + /* 0xf2 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("andn %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_ANDN, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vgroup17", IDX_ParseGrp17, 0, 0, 0, OP_GRP17, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("bzhi %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_BZHI, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("bextr %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_BEXTR, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; +const DISOPMAPDESC g_DisasVexMap2Range = { &g_aDisasVexMap2[0], 0xf2, RT_ELEMENTS(g_aDisasVexMap2) }; + +static const DISOPCODE g_aDisasVexMap2F3[] = +{ + /* 0xf5 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("pext %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_PEXT, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("sarx %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_SARX, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; +const DISOPMAPDESC g_DisasVexMap2F3Range = { &g_aDisasVexMap2F3[0], 0xf5, RT_ELEMENTS(g_aDisasVexMap2F3) }; + +static const DISOPCODE g_aDisasVexMap2F2[] = +{ + /* 0xf5 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("pdep %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_PDEP, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("mulx %By,%Gy,%Ey", IDX_ParseVexDest, IDX_ParseModRM, IDX_UseModRM, 0, OP_MULX, OP_PARM_By, OP_PARM_Gy, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("shrx %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_SHRX, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; +const DISOPMAPDESC g_DisasVexMap2F2Range = { &g_aDisasVexMap2F2[0], 0xf5, RT_ELEMENTS(g_aDisasVexMap2F2) }; + +static const DISOPCODE g_aDisasVexMap2_66[] = +{ + /* 0 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("vpshufb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSHUFB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphaddw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPHADDW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphaddd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPHADDD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphaddsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPHADDSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaddubsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMADDUBSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphsubw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPHSUBW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphsubd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPHSUBD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphsubsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPHSUBSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsignb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSIGNB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsignw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSIGNW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsignd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSIGND, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmulhrsw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULHRSW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpermilps %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPERMILPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpermilpd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPERMILPD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vtestps %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VTESTPS, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vtestpd %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VTESTPD, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 1 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcvtph2ps %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VCVTPH2PS, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vpermps %Vqq,%Hqq,%Wqq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPERMPS, OP_PARM_Vqq, OP_PARM_Hqq, OP_PARM_Wqq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vptest %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPTEST, OP_PARM_Vx, OP_PARM_Wd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vbroadcastss %Vx,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VBROADCASTSS, OP_PARM_Vx, OP_PARM_Wd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vbroadcastsd %Vqq,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VBROADCASTSD, OP_PARM_Vqq, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vbroadcastf128 %Vqq,%Mdq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VBROADCASTF128, OP_PARM_Vqq, OP_PARM_Wdq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vpabsb %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPABSB, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpabsw %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPABSW, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpabsd %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPABSD, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + + /* 2 */ + OPVEX("vpmovsxbw %Vx,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVSXBW, OP_PARM_Vx, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovsxbd %Vx,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVSXBD, OP_PARM_Vx, OP_PARM_Wd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovsxbq %Vx,%Ww", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVSXBQ, OP_PARM_Vx, OP_PARM_Ww, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovsxwd %Vx,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVSXWD, OP_PARM_Vx, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovsxwq %Vx,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVSXWQ, OP_PARM_Vx, OP_PARM_Wd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovsxdq %Vx,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVSXDQ, OP_PARM_Vx, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vpmuldq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULDQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpeqq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPEQQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmovntdqa %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VMOVNTDQA, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpackusdw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VVPACKUSDW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaskmovps %Vx,%Hx,%Mx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMASKMOVPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Mx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaskmovpd %Vx,%Hx,%Mx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMASKMOVPD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Mx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaskmovps %Mx,%Hx,%Vx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMASKMOVPS, OP_PARM_Mx, OP_PARM_Hx, OP_PARM_Vx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vmaskmovpd %Mx,%Hx,%Vx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VMASKMOVPD, OP_PARM_Mx, OP_PARM_Hx, OP_PARM_Vx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 3 */ + OPVEX("vpmovzxbw %Vx,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVZXBW, OP_PARM_Vx, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovzxbd %Vx,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVZXBD, OP_PARM_Vx, OP_PARM_Wd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovzxbq %Vx,%Ww", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVZXBQ, OP_PARM_Vx, OP_PARM_Ww, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovzxwd %Vx,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVZXWD, OP_PARM_Vx, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovzxwq %Vx,%Wd", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVZXWQ, OP_PARM_Vx, OP_PARM_Wd, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmovzxdq %Vx,%Wq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPMOVZXDQ, OP_PARM_Vx, OP_PARM_Wq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpermd %Vqq,%Hqq,%Wqq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPERMD, OP_PARM_Vqq, OP_PARM_Hqq, OP_PARM_Wqq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpgtq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPCMPGTQ, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpminsb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMINSB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpminsd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMINSD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpminuw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMINUW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpminud %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMINUD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaxsb %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMAXSB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaxsd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMAXSD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaxuw %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMAXUW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpmaxud %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMAXUD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 4 */ + OPVEX("vpmulld %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMULLD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vphminposuw %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPHMINPOSUW, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("#vpsrlvd/vpsrlvq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRLVD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpsravd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSRAVD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vpsllvd/vpsllvq %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPSLLVD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 5 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vpbroadcastd %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPBROADCASTD, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpbroadcastq %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPBROADCASTQ, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpbroadcasti128 %Vqq,%Mdq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPBROADCASTI128, OP_PARM_Vqq, OP_PARM_Mdq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 6 */ + INVALID_OPCODE_BLOCK + + /* 7 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vpbroadcastb %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPBROADCASTB, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpbroadcastw %Vx,%Wx", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VPBROADCASTW, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 8 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("#vpmaskmovd/vpmaskmovq %Vx,%Hx,%Mx",IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VPMASKMOVD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Mx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("#vpmaskmovd/vpmaskmovq %Mx,%Vx,%Hx",IDX_ParseModRM, IDX_UseModRM, IDX_ParseVexDest, 0, OP_VPMASKMOVD, OP_PARM_Mx, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + + /* 9 */ + /* Seems incorrect format is used in the Intel opcode tables. + * Correct form according to Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 2 (2A, 2B & 2C): Instruction Set Reference, A-Z + * is the following: + * v?gather?d/q %Vx, %Md/q, %Hx , + * where d/q is defined by VEX.W bit. + * + * The instruction are in the following format: + * #name1/name2 format + * if REX.W is set name2 is used, + * otherwise name1. + */ + OPVEX("#vpgatherdd/vpgatherdq %Vx,%My,%Hx", IDX_ParseModRM, IDX_UseModRM, IDX_ParseVexDest, 0, OP_VGATHER, OP_PARM_Vx, OP_PARM_My, OP_PARM_Hx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vpgatherqd/vpgatherqq %Vx,%My,%Hx", IDX_ParseModRM, IDX_UseModRM, IDX_ParseVexDest, 0, OP_VGATHER, OP_PARM_Vx, OP_PARM_My, OP_PARM_Hx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vgatherdps/vgatherdpd %Vx,%My,%Hx", IDX_ParseModRM, IDX_UseModRM, IDX_ParseVexDest, 0, OP_VGATHER, OP_PARM_Vx, OP_PARM_My, OP_PARM_Hx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vgatherqps/vgatherqpd %Vx,%My,%Hx", IDX_ParseModRM, IDX_UseModRM, IDX_ParseVexDest, 0, OP_VGATHER, OP_PARM_Vx, OP_PARM_My, OP_PARM_Hx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("#vfmaddsub132ps/vfmaddsub132pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADDSUB132PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsubadd132ps/vfmsubadd132pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUBADD132PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmadd132ps/vfmadd132pd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADD132PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmadd132ss/vfmadd132sd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADD132SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsub132ps/vfmsub132pd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUB132PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsub132ss/vfmsub132sd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUB132SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmadd132ps/vfnmadd132pd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMADD132PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmadd132ss/vfnmadd132sd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMADD132SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmsub132ps/vfnmsub132pd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMSUB132PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmsub132ss/vfnmsub132sd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMSUB132SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* a */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("#vfmaddsub213ps/vfmaddsub213pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADDSUB213PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsubadd213ps/vfmsubadd213pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUBADD213PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmadd213ps/vfmadd213pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADD213PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmadd213ss/vfmadd213sd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADD213SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsub213ps/vfmsub213pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUB213PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsub213ss/vfmsub213sd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUB213SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmadd213ps/vfnmadd213pd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMADD213PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmadd213ss/vfnmadd213sd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMADD213SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmsub213ps/vfnmsub213pd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMSUB213PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmsub213ss/vfnmsub213sd %Vx,%Hx,%Wx",IDX_ParseModRM,IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMSUB213SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* b */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("#vfmaddsub231ps/vfmaddsub231pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADDSUB231PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsubadd231ps/vfmsubadd231pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUBADD231PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmadd231ps/vfmadd231pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADD231PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmadd231ss/vfmadd231sd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMADD231SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsub231ps/vfmsub231pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUB231PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfmsub231ss/vfmsub231sd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFMSUB231SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmadd231ps/vfnmadd231pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMADD231PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmadd231ss/vfnmadd231sd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMADD231SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmsub231ps/vfnmsub231pd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMSUB231PS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vfnmsub231ss/vfnmsub231sd %Vx,%Hx,%Wx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VFNMSUB231SS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* c */ + INVALID_OPCODE_BLOCK + + /* d */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vaesimc %Vdq,%Wdq", IDX_ParseModRM, IDX_UseModRM, 0, 0, OP_VAESIMC, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vaesenc %Vdq,%Hdq,%Wdq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VAESENC, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vaesenclast %Vdq,%Hdq,%Wdq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VAESENCLAST, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vaesdec %Vdq,%Hdq,%Wdq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VAESDEC, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vaesdeclast %Vdq,%Hdq,%Wdq", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_VAESDECLAST, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wdq, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* e */ + INVALID_OPCODE_BLOCK + + /* f */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("shlx %Gy,%By,%Ey", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, 0, OP_SHLX, OP_PARM_Gy, OP_PARM_By, OP_PARM_Ey, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ +}; +const DISOPMAPDESC g_DisasVexMap2_66Range = { &g_aDisasVexMap2_66[0], 0x00, RT_ELEMENTS(g_aDisasVexMap2_66) }; + +const DISOPCODE g_aDisasVexMap3[] = +{ + INVALID_OPCODE, /* dummy */ +}; +const DISOPMAPDESC g_DisasVexMap3Range = { &g_aDisasVexMap3[0], 0, RT_ELEMENTS(g_aDisasVexMap3) }; + +static const DISOPCODE g_aDisasVexMap3_66[] = +{ + /* 0 format string, parse param #1, parse param #2, parse param #3, parse param #4, opcode, param #1, param #2, param #3, param #4, flags */ + OPVEX("vpermq %Vqq,%Wqq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPERMQ, OP_PARM_Vqq, OP_PARM_Wqq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpermpd %Vqq,%Wqq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPERMPD, OP_PARM_Vqq, OP_PARM_Wqq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpblendd %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPBLENDD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vpermilps %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPERMILPS, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpermilpd %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPERMILPD, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vperm2f128 %Vqq,%Hqq,%Wqq,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPERM2F128, OP_PARM_Vqq, OP_PARM_Hqq, OP_PARM_Wqq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vroundps %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VROUNDPS, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vroundpd %Vx,%Wx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VROUNDPD, OP_PARM_Vx, OP_PARM_Wx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vroundss %Vss,%Wss,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VROUNDSS, OP_PARM_Vss, OP_PARM_Wss, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vroundsd %Vsd,%Wsd,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VROUNDSD, OP_PARM_Vsd, OP_PARM_Wsd, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vblendps %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VBLENDPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vblendpd %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VBLENDPD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vpblendw %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPBLENDW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vpalignr %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPALIGNR, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + + /* 1 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + // vpextrb %Rd/Mb,%Vdq,%Ib + OPVEX("vpextrb %Eb,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPEXTRB, OP_PARM_Eb, OP_PARM_Vdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + // vpextrw %Rd/Mw,%Vdq,%Ib + OPVEX("vpextrw %Ew,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPEXTRW, OP_PARM_Ew, OP_PARM_Vdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("#vpextrd/vpextrq %Ey,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPEXTRD, OP_PARM_Ey, OP_PARM_Vdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vextractps %Ed,%Vdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VEXTRACTPS, OP_PARM_Ed, OP_PARM_Vdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vinsertf128 %Vqq,%Hqq,%Wqq,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VINSERTF128, OP_PARM_Vqq, OP_PARM_Hqq, OP_PARM_Wqq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vextractf128 %Wdq,%Vqq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VEXTRACTF128, OP_PARM_Eb, OP_PARM_Vdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vcvtps2ph %Wx,%Vx,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VCVTPS2PH, OP_PARM_Wx, OP_PARM_Vx, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + // vpinsrb %Vdq,%Hdq,%Ry/Mb,%Ib + OPVEX("vpinsrb %Vdq,%Hdq,%Eb,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPINSRB, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Eb, OP_PARM_Ib, DISOPTYPE_HARMLESS), + // vinsertps %Vdq,%Hdq,%Udq/Md,%Ib + OPVEX("vinsertps %Vdq,%Hdq,%Wd,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VINSERTPS, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wd, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("#vpinsrd/vpinsrq %Vdq,%Hdq,%Ey,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPINSRD, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Ey, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 3 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vinserti128 %Vqq,%Hqq,%Wqq,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VINSERTI128, OP_PARM_Vqq, OP_PARM_Hqq, OP_PARM_Wqq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vextracti128 %Wdq,%Vqq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VEXTRACTI128, OP_PARM_Wdq, OP_PARM_Vqq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 4 */ + OPVEX("vdpps %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VDPPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vdppd %Vdq,%Hdq,%Wdq,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VDPPD, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OPVEX("vmpsadbw %Vx,%Hx,%Wx,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VMPSADBW, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vpclmulqdq %Vdq,%Hdq,%Wdq,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPCLMULQDQ, OP_PARM_Vdq, OP_PARM_Hdq, OP_PARM_Wdq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OPVEX("vperm2i128 %Vqq,%Hqq,%Wqq,%Ib", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPERM2I128, OP_PARM_Vqq, OP_PARM_Hqq, OP_PARM_Wqq, OP_PARM_Ib, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vblendvps %Vx,%Hx,%Wx,%Lx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VBLENDVPS, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Lx, DISOPTYPE_HARMLESS), + OPVEX("vblendvpd %Vx,%Hx,%Wx,%Lx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VBLENDVPD, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Lx, DISOPTYPE_HARMLESS), + OPVEX("vpblendvb %Vx,%Hx,%Wx,%Lx", IDX_ParseModRM, IDX_ParseVexDest, IDX_UseModRM, IDX_ParseImmByte, OP_VPBLENDVB, OP_PARM_Vx, OP_PARM_Hx, OP_PARM_Wx, OP_PARM_Lx, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 5 */ + INVALID_OPCODE_BLOCK + + /* 6 */ + OPVEX("vpcmpestrm %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPCMPESTRM, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpestri %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPCMPESTRI, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpistrm %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPCMPISTRM, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OPVEX("vpcmpistri %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VPCMPISTRI, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + + /* 7 */ + INVALID_OPCODE_BLOCK + + /* 8 */ + INVALID_OPCODE_BLOCK + + /* 9 */ + INVALID_OPCODE_BLOCK + + /* a */ + INVALID_OPCODE_BLOCK + + /* b */ + INVALID_OPCODE_BLOCK + + /* c */ + INVALID_OPCODE_BLOCK + + /* d */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OPVEX("vaeskeygen %Vdq,%Wdq,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_VAESKEYGEN, OP_PARM_Vdq, OP_PARM_Wdq, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; +const DISOPMAPDESC g_DisasVexMap3_66Range = { &g_aDisasVexMap3_66[0], 0x00, RT_ELEMENTS(g_aDisasVexMap3_66) }; + +const DISOPCODE g_aDisasVexMap3F2[] = +{ + OPVEX("rorx %Gy,%Ey,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByte, 0, OP_RORX, OP_PARM_Gy, OP_PARM_Ey, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; +const DISOPMAPDESC g_DisasVexMap3F2Range = { &g_aDisasVexMap3F2[0], 0xf0, RT_ELEMENTS(g_aDisasVexMap3F2) }; + +const DISOPCODE g_aDisasVexMap3F3[] = +{ + INVALID_OPCODE, /* dummy */ +}; +const DISOPMAPDESC g_DisasVexMap3F3Range = { &g_aDisasVexMap3F3[0], 0, RT_ELEMENTS(g_aDisasVexMap3F3) }; + + +/** Invalid range for the g_aapVexOpcodesMapRanges table. */ +const DISOPMAPDESC g_DisasVexMapInvalidRange = { &g_InvalidOpcode[0], 0, 1 }; + + +PCDISOPMAPDESC const g_aapVexOpcodesMapRanges[4][4] = +{ + /* No prefix: */ + { + &g_DisasVexMapInvalidRange, + &g_DisasVexMap1Range, // 0fh 2-byte opcodes + &g_DisasVexMap2Range, // 0f38h 3-byte opcodes + &g_DisasVexMap3Range, // 0f3ah 3-byte opcodes + }, + /* 66h prefix: */ + { + &g_DisasVexMapInvalidRange, + &g_DisasVexMap1_66Range, // 0fh 2-byte opcodes + &g_DisasVexMap2_66Range, // 0f38h 3-byte opcodes + &g_DisasVexMap3_66Range, // 0f3ah 3-byte opcodes + }, + /* f3h prefix: */ + { + &g_DisasVexMapInvalidRange, + &g_DisasVexMap1F3Range, // 0fh 2-byte opcodes + &g_DisasVexMap2F3Range, // 0f38h 3-byte opcodes + &g_DisasVexMap3F3Range, // 0f3ah 3-byte opcodes + }, + /* f2h prefix: */ + { + &g_DisasVexMapInvalidRange, + &g_DisasVexMap1F2Range, // 0fh 2-byte opcodes + &g_DisasVexMap2F2Range, // 0f38h 3-byte opcodes2 + &g_DisasVexMap3F2Range, // 0f3ah 3-byte opcodes + } +}; + diff --git a/src/VBox/Disassembler/DisasmTablesX64.cpp b/src/VBox/Disassembler/DisasmTablesX64.cpp new file mode 100644 index 00000000..05de6d0b --- /dev/null +++ b/src/VBox/Disassembler/DisasmTablesX64.cpp @@ -0,0 +1,369 @@ +/* $Id: DisasmTablesX64.cpp $ */ +/** @file + * VBox disassembler - Tables for AMD64 (64-bit mode). + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/dis.h> +#include <VBox/disopcode.h> +#include "DisasmInternal.h" + + +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +/// @todo Verify tables for correctness +/// @todo opcode type (harmless, potentially dangerous, dangerous) +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + +#ifndef DIS_CORE_ONLY +static char g_szInvalidOpcode[] = "Invalid Opcode"; +#endif + +#define INVALID_OPCODE \ + OP(g_szInvalidOpcode, 0, 0, 0, OP_INVALID, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INVALID) + +#define INVALID_OPCODE_BLOCK \ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE,\ + INVALID_OPCODE, + +/* Tables for the elegant Intel X64 instruction set */ + +const DISOPCODE g_aOneByteMapX64[256] = +{ + /* 0 */ + OP("add %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Eb, OP_PARM_Gb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Ev, OP_PARM_Gv , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Gb, OP_PARM_Eb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADD, OP_PARM_Gv, OP_PARM_Ev , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_ADD, OP_PARM_REG_AL, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("add %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_ADD, OP_PARM_REG_EAX, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("or %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Eb, OP_PARM_Gb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Ev, OP_PARM_Gv , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Gb, OP_PARM_Eb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_OR, OP_PARM_Gv, OP_PARM_Ev , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_OR, OP_PARM_REG_AL, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("or %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_OR, OP_PARM_REG_EAX, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("2-BYTE ESCAPE", IDX_ParseTwoByteEsc,0, 0, OP_2B_ESC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 1 */ + OP("adc %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Eb, OP_PARM_Gb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Ev, OP_PARM_Gv , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Gb, OP_PARM_Eb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_ADC, OP_PARM_Gv, OP_PARM_Ev , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_ADC, OP_PARM_REG_AL, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("adc %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_ADC, OP_PARM_REG_EAX, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + OP("sbb %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Eb, OP_PARM_Gb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Ev, OP_PARM_Gv , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Gb, OP_PARM_Eb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_SBB, OP_PARM_Gv, OP_PARM_Ev , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_SBB, OP_PARM_REG_AL, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sbb %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_SBB, OP_PARM_REG_EAX, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + + /* 2 */ + OP("and %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Eb, OP_PARM_Gb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Ev, OP_PARM_Gv , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Gb, OP_PARM_Eb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_AND, OP_PARM_Gv, OP_PARM_Ev , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_AND, OP_PARM_REG_AL, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("and %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_AND, OP_PARM_REG_EAX, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG ES", 0, 0, 0, OP_SEG, OP_PARM_REG_ES, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("sub %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Eb, OP_PARM_Gb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Ev, OP_PARM_Gv , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Gb, OP_PARM_Eb , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_SUB, OP_PARM_Gv, OP_PARM_Ev , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_SUB, OP_PARM_REG_AL, OP_PARM_Ib , OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("sub %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_SUB, OP_PARM_REG_EAX, OP_PARM_Iz , OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* Branch not taken hint prefix for branches on a Pentium 4 or Xeon CPU (or higher)! */ + OP("SEG CS", 0, 0, 0, OP_SEG, OP_PARM_REG_CS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + + /* 3 */ + OP("xor %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_XOR, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_XOR, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xor %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_XOR, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG SS", 0, 0, 0, OP_SEG, OP_PARM_REG_SS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("cmp %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_CMP, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte,0, OP_CMP, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmp %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_CMP, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /* Branch not taken hint prefix for branches on a Pentium 4 or Xeon CPU (or higher)! */ + OP("SEG DS", 0, 0, 0, OP_SEG, OP_PARM_REG_DS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + + /* 4 */ + OP("REX", 0, 0, 0, OP_REX, OP_PARM_REX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.B", 0, 0, 0, OP_REX, OP_PARM_REX_B, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.X", 0, 0, 0, OP_REX, OP_PARM_REX_X, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.XB", 0, 0, 0, OP_REX, OP_PARM_REX_XB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.R", 0, 0, 0, OP_REX, OP_PARM_REX_R, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.RB", 0, 0, 0, OP_REX, OP_PARM_REX_RB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.RX", 0, 0, 0, OP_REX, OP_PARM_REX_RX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.RXB", 0, 0, 0, OP_REX, OP_PARM_REX_RXB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.W", 0, 0, 0, OP_REX, OP_PARM_REX_W, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WB", 0, 0, 0, OP_REX, OP_PARM_REX_WB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WX", 0, 0, 0, OP_REX, OP_PARM_REX_WX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WXB", 0, 0, 0, OP_REX, OP_PARM_REX_WXB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WR", 0, 0, 0, OP_REX, OP_PARM_REX_WR, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WRB", 0, 0, 0, OP_REX, OP_PARM_REX_WRB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WRX", 0, 0, 0, OP_REX, OP_PARM_REX_WRX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("REX.WRXB", 0, 0, 0, OP_REX, OP_PARM_REX_WRXB, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 5 */ + OP("push %eAX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eCX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eDX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eBX", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eSP", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eBP", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eSI", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("push %eDI", IDX_ParseFixedReg, 0, 0, OP_PUSH, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eAX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EAX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eCX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ECX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eDX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EDX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eBX", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EBX, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eSP", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ESP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eBP", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EBP, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eSI", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_ESI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("pop %eDI", IDX_ParseFixedReg, 0, 0, OP_POP, OP_PARM_REG_EDI, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE | DISOPTYPE_REXB_EXTENDS_OPREG), + + /* 6 */ + INVALID_OPCODE, + INVALID_OPCODE, + INVALID_OPCODE, + OP("movsxd %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOVSXD, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG FS", 0, 0, 0, OP_SEG, OP_PARM_REG_FS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("SEG GS", 0, 0, 0, OP_SEG, OP_PARM_REG_GS, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("OP SIZE", 0, 0, 0, OP_OPSIZE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("ADDR SIZE", 0, 0, 0, OP_ADDRSIZE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("push %Iz", IDX_ParseImmZ, 0, 0, OP_PUSH, OP_PARM_Iz, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("imul %Gv,%Ev,%Iz", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmZ, OP_IMUL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_Iz, DISOPTYPE_HARMLESS), + OP("push %Ib", IDX_ParseImmByteSX, 0, 0, OP_PUSH, OP_PARM_Ib, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("imul %Gv,%Ev,%Ib", IDX_ParseModRM, IDX_UseModRM, IDX_ParseImmByteSX, OP_IMUL, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_Ib, DISOPTYPE_HARMLESS), + OP("insb %Yb,DX", IDX_ParseYb, IDX_ParseFixedReg, 0, OP_INSB, OP_PARM_Yb, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("insw/d %Yv,DX", IDX_ParseYv, IDX_ParseFixedReg, 0, OP_INSWD, OP_PARM_Yv, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("outsb DX,%Xb", IDX_ParseFixedReg, IDX_ParseXb, 0, OP_OUTSB, OP_PARM_REG_DX, OP_PARM_Yb, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("outsw/d DX,%Xv", IDX_ParseFixedReg, IDX_ParseXv, 0, OP_OUTSWD, OP_PARM_REG_DX, OP_PARM_Yv, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + + + /* 7 */ + OP("jo %Jb", IDX_ParseImmBRel, 0, 0, OP_JO, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jno %Jb", IDX_ParseImmBRel, 0, 0, OP_JNO, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jc %Jb", IDX_ParseImmBRel, 0, 0, OP_JC, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnc %Jb", IDX_ParseImmBRel, 0, 0, OP_JNC, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("je %Jb", IDX_ParseImmBRel, 0, 0, OP_JE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jne %Jb", IDX_ParseImmBRel, 0, 0, OP_JNE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jbe %Jb", IDX_ParseImmBRel, 0, 0, OP_JBE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnbe %Jb", IDX_ParseImmBRel, 0, 0, OP_JNBE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("js %Jb", IDX_ParseImmBRel, 0, 0, OP_JS, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jns %Jb", IDX_ParseImmBRel, 0, 0, OP_JNS, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jp %Jb", IDX_ParseImmBRel, 0, 0, OP_JP, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnp %Jb", IDX_ParseImmBRel, 0, 0, OP_JNP, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jl %Jb", IDX_ParseImmBRel, 0, 0, OP_JL, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnl %Jb", IDX_ParseImmBRel, 0, 0, OP_JNL, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jle %Jb", IDX_ParseImmBRel, 0, 0, OP_JLE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jnle %Jb", IDX_ParseImmBRel, 0, 0, OP_JNLE, OP_PARM_Jb , OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + + /* 8 */ + OP("Imm Grp1 %Eb,%Ib", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Imm Grp1 %Ev,%Iz", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Ev, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("Imm Grp1 %Ev,%Ib", IDX_ParseGrp1, 0, 0, OP_IMM_GRP1,OP_PARM_Ev, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_TEST, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_TEST, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xchg %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_XCHG, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("xchg %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_XCHG, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Eb,%Gb", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Eb, OP_PARM_Gb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ev,%Gv", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Gv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Gb,%Eb", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Gb, OP_PARM_Eb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Gv,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Gv, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ev,%Sw", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Sw, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS), + OP("lea %Gv,%M", IDX_ParseModRM, IDX_UseModRM, 0, OP_LEA, OP_PARM_Gv, OP_PARM_M, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Sw,%Ev", IDX_ParseModRM, IDX_UseModRM, 0, OP_MOV, OP_PARM_Sw, OP_PARM_Ev, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS | DISOPTYPE_INHIBIT_IRQS), + /** @todo this is grp 1a, actually */ + OP("pop %Ev", IDX_ParseModRM, 0, 0, OP_POP, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + /* 9 */ + OP("nop/pause/xchg %eAX,%eAX", IDX_ParseNopPause, 0, 0, OP_NOP, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eCX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_ECX, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eDX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EDX, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eBX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EBX, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eSP,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_ESP, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eBP,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EBP, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eSI,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_ESI, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("xchg %eDI,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_XCHG, OP_PARM_REG_EDI, OP_PARM_REG_EAX, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("cbw", 0, 0, 0, OP_CBW, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cwd", 0, 0, 0, OP_CWD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + OP("wait", 0, 0, 0, OP_WAIT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("pushf %Fv", 0, 0, 0, OP_PUSHF, OP_PARM_Fv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("popf %Fv", 0, 0, 0, OP_POPF, OP_PARM_Fv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_POTENTIALLY_DANGEROUS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("sahf", 0, 0, 0, OP_SAHF, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lahf", 0, 0, 0, OP_LAHF, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* A */ + OP("mov AL,%Ob", IDX_ParseFixedReg, IDX_ParseImmAddr, 0, OP_MOV, OP_PARM_REG_AL, OP_PARM_Ob, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %eAX,%Ov", IDX_ParseFixedReg, IDX_ParseImmAddr, 0, OP_MOV, OP_PARM_REG_EAX, OP_PARM_Ov, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ob,AL", IDX_ParseImmAddr, IDX_ParseFixedReg, 0, OP_MOV, OP_PARM_Ob, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ov,%eAX", IDX_ParseImmAddr, IDX_ParseFixedReg, 0, OP_MOV, OP_PARM_Ov, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsb %Xb,%Yb", IDX_ParseXb, IDX_ParseYb, 0, OP_MOVSB, OP_PARM_Xb, OP_PARM_Yb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("movsw/d %Xv,%Yv", IDX_ParseXv, IDX_ParseYv, 0, OP_MOVSWD, OP_PARM_Xv, OP_PARM_Yv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmpsb %Xb,%Yb", IDX_ParseXb, IDX_ParseYb, 0, OP_CMPSB, OP_PARM_Xb, OP_PARM_Yb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cmpsw/d %Xv,%Yv", IDX_ParseXv, IDX_ParseYv, 0, OP_CMPWD, OP_PARM_Xv, OP_PARM_Yv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_TEST, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("test %eAX,%Iz", IDX_ParseFixedReg, IDX_ParseImmZ, 0, OP_TEST, OP_PARM_REG_EAX, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stosb %Yb,AL", IDX_ParseYb, IDX_ParseFixedReg, 0, OP_STOSB, OP_PARM_Yb, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stosw/d %Yv,%eAX", IDX_ParseYv, IDX_ParseFixedReg, 0, OP_STOSWD, OP_PARM_Yv, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lodsb AL,%Xb", IDX_ParseFixedReg, IDX_ParseXb, 0, OP_LODSB, OP_PARM_REG_AL, OP_PARM_Xb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("lodsw/d %eAX,%Xv", IDX_ParseFixedReg, IDX_ParseXv, 0, OP_LODSWD, OP_PARM_REG_EAX, OP_PARM_Xv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("scasb AL,%Xb", IDX_ParseFixedReg, IDX_ParseXb, 0, OP_SCASB, OP_PARM_REG_AL, OP_PARM_Xb, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("scasw/d %eAX,%Xv", IDX_ParseFixedReg, IDX_ParseXv, 0, OP_SCASWD, OP_PARM_REG_EAX, OP_PARM_Xv, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* B */ + OP("mov %eAL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eCL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_CL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eDL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_DL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eBL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_BL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eAH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_AH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eCH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_CH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eDH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_DH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eBH,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_REG_BH, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eAX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EAX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eCX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_ECX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eDX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EDX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eBX,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EBX, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eSP,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_ESP, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eBP,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EBP, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eSI,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_ESI, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + OP("mov %eDI,%Iv", IDX_ParseFixedReg, IDX_ParseImmV, 0, OP_MOV, OP_PARM_REG_EDI, OP_PARM_Iv, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_REXB_EXTENDS_OPREG), + + /* C */ + OP("Shift Grp2 %Eb,%Ib", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Ev,%Ib", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Ev, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("retn %Iw", IDX_ParseImmUshort, 0, 0, OP_RETN, OP_PARM_Iw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("retn", 0, 0, 0, OP_RETN, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("VEX 3-byte", IDX_ParseVex3b, 0, 0, OP_VEX3B, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("VEX 2-byte", IDX_ParseVex2b, 0, 0, OP_VEX2B, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + /** @todo these two are actually group11 */ + OP("mov %Eb,%Ib", IDX_ParseModRM, IDX_ParseImmByte, 0, OP_MOV, OP_PARM_Eb, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("mov %Ev,%Iz", IDX_ParseModRM, IDX_ParseImmZ, 0, OP_MOV, OP_PARM_Ev, OP_PARM_Iz, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("enter %Iw,%Ib", IDX_ParseImmUshort, IDX_ParseImmByte, 0, OP_ENTER, OP_PARM_Iw, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("leave", 0, 0, 0, OP_LEAVE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_DEFAULT_64_OP_SIZE), + OP("retf %Iw", IDX_ParseImmUshort, 0, 0, OP_RETF, OP_PARM_Iw, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + OP("retf", 0, 0, 0, OP_RETF, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + OP("int 3", 0, 0, 0, OP_INT3, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT), + OP("int %Ib", IDX_ParseImmByte, 0, 0, OP_INT, OP_PARM_Ib, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT), + INVALID_OPCODE, + OP("iret", 0, 0, 0, OP_IRET, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW), + + /* D */ + OP("Shift Grp2 %Eb,1", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Eb, OP_PARM_1, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Ev,1", IDX_ParseShiftGrp2, 0, 0, OP_SHIFT_GRP2, OP_PARM_Ev, OP_PARM_1, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Eb,CL", IDX_ParseShiftGrp2, IDX_ParseFixedReg, 0, OP_SHIFT_GRP2, OP_PARM_Eb, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Shift Grp2 %Ev,CL", IDX_ParseShiftGrp2, IDX_ParseFixedReg, 0, OP_SHIFT_GRP2, OP_PARM_Ev, OP_PARM_REG_CL, OP_PARM_NONE, DISOPTYPE_HARMLESS), + INVALID_OPCODE, + INVALID_OPCODE, + /* setalc?? */ + INVALID_OPCODE, + OP("xlat", 0, 0, 0, OP_XLAT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf0", IDX_ParseEscFP, 0, 0, OP_ESCF0, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf1", IDX_ParseEscFP, 0, 0, OP_ESCF1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf2", IDX_ParseEscFP, 0, 0, OP_ESCF2, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf3", IDX_ParseEscFP, 0, 0, OP_ESCF3, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf4", IDX_ParseEscFP, 0, 0, OP_ESCF4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf5", IDX_ParseEscFP, 0, 0, OP_ESCF5, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf6", IDX_ParseEscFP, 0, 0, OP_ESCF6, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("esc 0xf7", IDX_ParseEscFP, 0, 0, OP_ESCF7, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + + + /* E */ + OP("loopne %Jb", IDX_ParseImmBRel, 0, 0, OP_LOOPNE, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("loope %Jb", IDX_ParseImmBRel, 0, 0, OP_LOOPE, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("loop %Jb", IDX_ParseImmBRel, 0, 0, OP_LOOP, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("j(e)cxz %Jb", IDX_ParseImmBRel, 0, 0, OP_JECXZ, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW|DISOPTYPE_RELATIVE_CONTROLFLOW|DISOPTYPE_COND_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("in AL,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_IN, OP_PARM_REG_AL, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("in %eAX,%Ib", IDX_ParseFixedReg, IDX_ParseImmByte, 0, OP_IN, OP_PARM_REG_EAX, OP_PARM_Ib, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("out %Ib,AL", IDX_ParseImmByte, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_Ib, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("out %Ib,%eAX", IDX_ParseImmByte, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_Ib, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("call %Jv", IDX_ParseImmVRel, 0, 0, OP_CALL, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("jmp %Jv", IDX_ParseImmVRel, 0, 0, OP_JMP, OP_PARM_Jv, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + INVALID_OPCODE, + OP("jmp %Jb", IDX_ParseImmBRel, 0, 0, OP_JMP, OP_PARM_Jb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_CONTROLFLOW | DISOPTYPE_UNCOND_CONTROLFLOW | DISOPTYPE_RELATIVE_CONTROLFLOW | DISOPTYPE_FORCED_64_OP_SIZE), + OP("in AL,DX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_IN, OP_PARM_REG_AL, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("in %eAX,DX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_IN, OP_PARM_REG_EAX, OP_PARM_REG_DX, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_READ), + OP("out DX,AL", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_REG_DX, OP_PARM_REG_AL, OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + OP("out DX,%eAX", IDX_ParseFixedReg, IDX_ParseFixedReg, 0, OP_OUT, OP_PARM_REG_DX, OP_PARM_REG_EAX,OP_PARM_NONE, DISOPTYPE_PORTIO | DISOPTYPE_PRIVILEGED | DISOPTYPE_PORTIO_WRITE), + + + /* F */ + OP("lock", 0, 0, 0, OP_LOCK, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("icebp", 0, 0, 0, OP_INT1, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_INTERRUPT), + OP("repne", 0, 0, 0, OP_REPNE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("rep(e)", 0, 0, 0, OP_REPE, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("hlt", 0, 0, 0, OP_HLT, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS | DISOPTYPE_PRIVILEGED), + OP("cmc", 0, 0, 0, OP_CMC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Unary Grp3 %Eb", IDX_ParseGrp3, 0, 0, OP_UNARY_GRP3, OP_PARM_Eb, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Unary Grp3 %Ev", IDX_ParseGrp3, 0, 0, OP_UNARY_GRP3, OP_PARM_Ev, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("clc", 0, 0, 0, OP_CLC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("stc", 0, 0, 0, OP_STC, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("cli", 0, 0, 0, OP_CLI, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED), + OP("sti", 0, 0, 0, OP_STI, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_DANGEROUS | DISOPTYPE_PRIVILEGED | DISOPTYPE_INHIBIT_IRQS), + OP("cld", 0, 0, 0, OP_CLD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("std", 0, 0, 0, OP_STD, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("inc/dec Grp4", IDX_ParseGrp4, 0, 0, OP_INC_GRP4, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), + OP("Indirect Grp5", IDX_ParseGrp5, 0, 0, OP_IND_GRP5, OP_PARM_NONE, OP_PARM_NONE, OP_PARM_NONE, DISOPTYPE_HARMLESS), +}; + diff --git a/src/VBox/Disassembler/Makefile.kmk b/src/VBox/Disassembler/Makefile.kmk new file mode 100644 index 00000000..cdc72106 --- /dev/null +++ b/src/VBox/Disassembler/Makefile.kmk @@ -0,0 +1,91 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the VBox Disassembler. +# + +# +# Copyright (C) 2006-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../.. +include $(KBUILD_PATH)/subheader.kmk + +# include the sub-makefile first. +if defined(VBOX_WITH_TESTCASES) && !defined(VBOX_ONLY_VALIDATIONKIT) + include $(PATH_SUB_CURRENT)/testcase/Makefile.kmk +endif + + +LIBRARIES += DisasmR3 +DisasmR3_TEMPLATE = VBoxR3Dll +DisasmR3_DEFS = IN_DIS +DisasmR3_SOURCES = \ + Disasm.cpp \ + DisasmCore.cpp \ + DisasmTables.cpp \ + DisasmTablesX64.cpp \ + DisasmMisc.cpp \ + DisasmFormatBytes.cpp \ + DisasmFormatYasm.cpp + +LIBRARIES += DisasmR3Static +DisasmR3Static_TEMPLATE = VBoxR3Static +DisasmR3Static_EXTENDS = DisasmR3 + +ifndef VBOX_ONLY_VALIDATIONKIT + + LIBRARIES += DisasmBldProg + DisasmBldProg_TEMPLATE = VBoxAdvBldProg + DisasmBldProg_EXTENDS = DisasmR3 + + LIBRARIES += DisasmCoreR3 + DisasmCoreR3_TEMPLATE = VBoxR3Dll + DisasmCoreR3_DEFS = IN_DIS DIS_CORE_ONLY + DisasmCoreR3_SOURCES = \ + DisasmCore.cpp \ + DisasmTables.cpp \ + DisasmTablesX64.cpp \ + DisasmMisc.cpp + + ifdef VBOX_WITH_RAW_MODE + LIBRARIES += DisasmRC + DisasmRC_TEMPLATE = VBoxRc + DisasmRC_DEFS = IN_DIS IN_RT_RC DIS_CORE_ONLY + DisasmRC_SOURCES = \ + DisasmCore.cpp \ + DisasmTables.cpp \ + DisasmTablesX64.cpp \ + DisasmMisc.cpp + endif # VBOX_WITH_RAW_MODE + + LIBRARIES += DisasmR0 + DisasmR0_TEMPLATE = VBoxR0 + DisasmR0_DEFS = IN_DIS IN_RT_R0 DIS_CORE_ONLY + DisasmR0_SOURCES = \ + DisasmCore.cpp \ + DisasmTables.cpp \ + DisasmTablesX64.cpp \ + DisasmMisc.cpp + +endif # !VBOX_ONLY_VALIDATIONKIT + +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Disassembler/testcase/Makefile.kmk b/src/VBox/Disassembler/testcase/Makefile.kmk new file mode 100644 index 00000000..1f993247 --- /dev/null +++ b/src/VBox/Disassembler/testcase/Makefile.kmk @@ -0,0 +1,271 @@ +# $Id: Makefile.kmk $ +## @file +# Sub-Makefile for the VBox Disassembler. +# + +# +# Copyright (C) 2006-2023 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see <https://www.gnu.org/licenses>. +# +# SPDX-License-Identifier: GPL-3.0-only +# + +SUB_DEPTH = ../../../.. +include $(KBUILD_PATH)/subheader.kmk +ifdef VBOX_WITH_TESTCASES + + + if1of ($(KBUILD_TARGET_ARCH), amd64 x86) + PROGRAMS += tstDisasm-1 + tstDisasm-1_TEMPLATE = VBoxR3TstExe + tstDisasm-1_DEFS = IN_DIS + tstDisasm-1_SOURCES = \ + tstDisasm-1.cpp \ + tstDisasm-1A.asm + tstDisasm-1_LIBS = \ + $(PATH_STAGE_LIB)/DisasmR3$(VBOX_SUFF_LIB) \ + $(LIB_RUNTIME) + + PROGRAMS += tstDisasmCore-1 + tstDisasmCore-1_EXTENDS = tstDisasm-1 + tstDisasmCore-1_DEFS = IN_DIS DIS_CORE_ONLY + tstDisasmCore-1_LIBS = \ + $(PATH_STAGE_LIB)/DisasmCoreR3$(VBOX_SUFF_LIB) \ + $(LIB_RUNTIME) + endif + + + PROGRAMS += tstDisasm-2 + tstDisasm-2_TEMPLATE = VBoxR3TstExe + tstDisasm-2_DEFS = IN_DIS + tstDisasm-2_SOURCES = \ + tstDisasm-2.cpp + tstDisasm-2_LIBS = \ + $(PATH_STAGE_LIB)/DisasmR3$(VBOX_SUFF_LIB) \ + $(LIB_RUNTIME) + + # Tests that will be build, disassembled and re-build from disassembly. + VBOX_DISAS_TESTS_BUILD = \ + tstAsmFnstsw-1.asm \ + tstAsmLock-1.asm \ + tstAsmMovFixedReg-1.asm \ + tstAsmMovSeg-1.asm \ + tstAsmMovzx-1.asm \ + tstAsmPop-1.asm \ + tstAsmPush-1.asm \ + tstAsmSignExtend-1.asm \ + tstAsmRegs-1.asm \ + tstAsm3DNow-1.asm + + # Tests that only contains invalid/undefined instructions. + VBOX_DISAS_TESTS_INVALID = \ + tstAsmLock-2.asm \ + tstAsmLock-3.asm + + # Tests that will be disassembled and re-build from disassembly (list of binaries). + ## @todo tstBinMovzx-1.bin: does C7 imply 32-bit reg in 16-bit mode, or what exactly does it do? + VBOX_DISAS_TESTS_BINARIES := \ + tstBinMovzx-1.bin \ + tstBinFnstsw-1.bin + ifeq ($(USER)x,bird) + VBOX_DISAS_TESTS_BINARIES += \ + tstBin-1.bin \ + tstBin-2.bin \ + tstBin-3.bin \ + tstBin-4.bin \ + tstBin-5.bin \ + tstBin-6.bin + # $(PATH_STAGE_BIN)/testcase/tstDisasm-2$(SUFF_EXEC) + endif + VBOX_DISAS_TESTS_BINARIES_NOT_16BIT := \ + tstBinFnstsw-1.bin + VBOX_DISAS_TESTS_BINARIES_NOT_32BIT := + VBOX_DISAS_TESTS_BINARIES_NOT_64BIT := + + + # + # The gory bits... + # + + # Where we put the output files from the testcases. + VBOX_DISAS_TEST_OUT_DIR := $(PATH_TARGET)/Disassembler/testcase + BLDDIRS += $(VBOX_DISAS_TEST_OUT_DIR) + + # Generate the rules for creating the .bin files. + VBOX_DISAS_TESTS_BIN = $(VBOX_DISAS_TESTS_BUILD) $(VBOX_DISAS_TESTS_INVALID) + VBOX_DISAS_TEST_CLEAN += $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, \ + $(VBOX_DISAS_TESTS_BIN:.asm=-16.bin) \ + $(VBOX_DISAS_TESTS_BIN:.asm=-32.bin) \ + $(VBOX_DISAS_TESTS_BIN:.asm=-64.bin)) + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BIN:.asm=-16.bin)): $(PATH_SUB_CURRENT)/$$(patsubst %-16.bin,%.asm,$$(notdir $$(@))) | $$(dir $$@) + @$(ECHO) "Assembling: $(<F) into $(@F)" + $(TOOL_YASM_AS) -f bin -a x86 --force-strict -DTEST_BITS=16 -o $@ $< + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BIN:.asm=-32.bin)): $(PATH_SUB_CURRENT)/$$(patsubst %-32.bin,%.asm,$$(notdir $$(@))) | $$(dir $$@) + @$(ECHO) "Assembling: $(<F) into $(@F)" + $(TOOL_YASM_AS) -f bin -a x86 --force-strict -DTEST_BITS=32 -o $@ $< + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BIN:.asm=-64.bin)): $(PATH_SUB_CURRENT)/$$(patsubst %-64.bin,%.asm,$$(notdir $$(@))) | $$(dir $$@) + @$(ECHO) "Assembling: $(<F) into $(@F)" + $(TOOL_YASM_AS) -f bin -a x86 --force-strict -DTEST_BITS=64 -o $@ $< + + + # Generate the rules for the 'build' tests. + VBOX_DISAS_TEST_CLEAN += $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-16-disas.asm) \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-32-disas.asm) \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-64-disas.asm)) + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BUILD:.asm=-16-disas.asm)): $$(subst -disas.asm,.bin,$$@) $$(tstDisasm-2_1_STAGE_TARGET) | $$(dir $$@) + @$(ECHO) "Generating: $(@F) from $(<F)" + $(REDIRECT) -E VBOX_LOG_DEST=nofile -o $@ -- $(tstDisasm-2_1_STAGE_TARGET) --style=yasm --cpumode=16 $< + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BUILD:.asm=-32-disas.asm)): $$(subst -disas.asm,.bin,$$@) $$(tstDisasm-2_1_STAGE_TARGET) | $$(dir $$@) + @$(ECHO) "Generating: $(@F) from $(<F)" + $(REDIRECT) -E VBOX_LOG_DEST=nofile -o $@ -- $(tstDisasm-2_1_STAGE_TARGET) --style=yasm --cpumode=32 $< + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BUILD:.asm=-64-disas.asm)): $$(subst -disas.asm,.bin,$$@) $$(tstDisasm-2_1_STAGE_TARGET) | $$(dir $$@) + @$(ECHO) "Generating: $(@F) from $(<F)" + $(REDIRECT) -E VBOX_LOG_DEST=nofile -o $@ -- $(tstDisasm-2_1_STAGE_TARGET) --style=yasm --cpumode=64 $< + + + VBOX_DISAS_TEST_CLEAN += $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-16-disas.bin) \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-32-disas.bin) \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-64-disas.bin)) + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BUILD:.asm=-16-disas.bin)): $$(subst .bin,.asm,$$@) | $$(dir $$@) + @$(ECHO) "Re-assembling: $(<F) into $(@F)" + $(TOOL_YASM_AS) -f bin -a x86 --force-strict -DTEST_BITS=16 -o $@ $< + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BUILD:.asm=-32-disas.bin)): $$(subst .bin,.asm,$$@) | $$(dir $$@) + @$(ECHO) "Re-assembling: $(<F) into $(@F)" + $(TOOL_YASM_AS) -f bin -a x86 --force-strict -DTEST_BITS=32 -o $@ $< + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_BUILD:.asm=-64-disas.bin)): $$(subst .bin,.asm,$$@) | $$(dir $$@) + @$(ECHO) "Re-assembling: $(<F) into $(@F)" + $(TOOL_YASM_AS) -f bin -a x86 --force-strict -DTEST_BITS=64 -o $@ $< + + + VBOX_DISAS_TESTS += $(foreach test, $(VBOX_DISAS_TESTS_BUILD:.asm=), $(test)-16.tst $(test)-32.tst $(test)-64.tst) + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-16.tst) \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-32.tst) \ + $(VBOX_DISAS_TESTS_BUILD:.asm=-64.tst) ): $$(subst .tst,-disas.bin,$$@) | $$(dir $$@) + @$(ECHO) "Verifying build: $(<F) and $(@F:.tst=.bin)" + @$(RM) -f $@ + $(CMP) $(@:.tst=.bin) $< + @$(APPEND) $@ "done" + @$(ECHO) " PASSED: $(<F) [re-assembled]" + + + + # Generate the rules for the 'invalid' tests. + VBOX_DISAS_TESTS += $(foreach test, $(VBOX_DISAS_TESTS_INVALID:.asm=), $(test)-16.tst $(test)-32.tst $(test)-64.tst) + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-16.tst)): $$(patsubst %.tst,%.bin,$$@) $$(tstDisasm-2_1_STAGE_TARGET) | $$(dir $$@) + @$(ECHO) "TESTING: $(@F) [--undef-op=all]" + @$(RM) -f $@ + $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(tstDisasm-2_1_STAGE_TARGET) --undef-op=all --cpumode=16 $< + @$(APPEND) $@ "done" + @$(ECHO) " PASSED: $(@F) [--undef-op=all]" + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-32.tst)): $$(patsubst %.tst,%.bin,$$@) $$(tstDisasm-2_1_STAGE_TARGET) | $$(dir $$@) + @$(ECHO) "TESTING: $(@F) [--undef-op=all]" + @$(RM) -f $@ + $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(tstDisasm-2_1_STAGE_TARGET) --undef-op=all --cpumode=32 $< + @$(APPEND) $@ "done" + @$(ECHO) " PASSED: $(@F) [--undef-op=all]" + + $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-64.tst)): $$(patsubst %.tst,%.bin,$$@) $$(tstDisasm-2_1_STAGE_TARGET) | $$(dir $$@) + @$(ECHO) "TESTING: $(@F) [--undef-op=all]" + @$(RM) -f $@ + $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(tstDisasm-2_1_STAGE_TARGET) --undef-op=all --cpumode=64 $< + @$(APPEND) $@ "done" + @$(ECHO) " PASSED: $(@F) [--undef-op=all]" + + + # Generate the rules for the binary tests. + define def_vbox_disas_binary_rules + $(outbase).asm: $(full_binary) $$$$(tstDisasm-2_1_STAGE_TARGET) | $(VBOX_DISAS_TEST_OUT_DIR)/ + @$$(ECHO) "Generating: $$(@F) from $$(<F)" + $$(REDIRECT) -E VBOX_LOG_DEST=nofile -o $$@ -- $$(tstDisasm-2_1_STAGE_TARGET) --style=yasm --cpumode=$(bits) --undef-op=db $$< + + $(outbase).bin + $(outbase).lst: $(outbase).asm + @$$(ECHO) "Re-assembling: $$(<F) into $$(@F)" + $$(TOOL_YASM_AS) -f bin -a x86 --force-strict -l $(outbase).lst -o $$@ $$< + + $(outbase).tst: $(outbase).bin + @$$(ECHO) "Verifying build: $$(<F) against $(not-dir $(full_binary))" + @$$(RM) -f $$@ + $$(CMP) -l $(full_binary) $$< + @$$(APPEND) $$@ "done" + @$$(ECHO) " PASSED: $$(<F) [binary]" + + $(name).tst:: $(outbase).tst + VBOX_DISAS_TEST_CLEAN += $(outbase).tst $(outbase).bin $(outbase).asm + VBOX_DISAS_TESTS += $(name)-rebuild-$(bits).tst + endef # def_vbox_disas_binary_rules + + define def_vbox_disas_binary + local name := $(notdir $(basename $(binary))) + local full_binary := $(abspathex $(binary),$(PATH_SUB_CURRENT)) + local outbase := $(VBOX_DISAS_TEST_OUT_DIR)/$(name)-rebuild-$(bits) + $(eval $(def_vbox_disas_binary_rules)) + endef # def_vbox_disas_binary + + ## @todo 64-bit is problematic because of bugs like POP RDI ending up as POP EDI (incorrect default opmode). + #$(foreach bits, 64, $(foreach binary, $(VBOX_DISAS_TESTS_BINARIES), $(evalvalctx def_vbox_disas_binary))) + $(foreach bits, 32 16, $(foreach binary, $(filter-out $(VBOX_DISAS_TESTS_BINARIES_NOT_$(bits)BIT), $(VBOX_DISAS_TESTS_BINARIES)) \ + , $(evalvalctx def_vbox_disas_binary))) + + + # Add the .tst to the clean up. + VBOX_DISAS_TEST_CLEAN += $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/, $(VBOX_DISAS_TESTS)) + OTHER_CLEAN += $(VBOX_DISAS_TEST_CLEAN) + + + # + # Add the tests to the target list for the testing pass. + # (kBuild r1646) + # + TESTING += $(addprefix $(VBOX_DISAS_TEST_OUT_DIR)/,$(VBOX_DISAS_TESTS)) + + + # + # The test aliases + # + # To run the tstAsmLock-3.asm test: kmk tstAsmLock-3.tst + # To run the 64-bit tstAsmLock-3.asm test: kmk tstAsmLock-3-64.tst + # + define def_vbox_test_aliases + local test_base := $(basename $(test)) + local test_root := $(patsubst %-16,%,$(patsubst %-32,%,$(patsubst %-64,%,$(test_base)))) + $(test_base).tst:: $(VBOX_DISAS_TEST_OUT_DIR)/$(test) + $(test_root).tst:: $(test_base).tst + $(test_base).o:: $(test_base).tst + $(test_base).obj:: $(test_base).tst + $(test_root).o:: $(test_root).tst + $(test_root).obj:: $(test_root).tst + endef + $(foreach test,$(VBOX_DISAS_TESTS),$(evalvalctx def_vbox_test_aliases)) + +endif # VBOX_WITH_TESTCASES +include $(FILE_KBUILD_SUB_FOOTER) + diff --git a/src/VBox/Disassembler/testcase/tstAsm.mac b/src/VBox/Disassembler/testcase/tstAsm.mac new file mode 100644 index 00000000..32491bc1 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsm.mac @@ -0,0 +1,68 @@ +; $Id: tstAsm.mac $ +;; @file +; Disassembly testcase - Common header for the xREG macros. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%if TEST_BITS == 64 + %define xCB 8 + %define xSP rsp + %define xBP rbp + %define xAX rax + %define xBX rbx + %define xCX rcx + %define xDX rdx + %define xDI rdi + %define xSI rsi +%endif +%if TEST_BITS == 32 + %define xCB 4 + %define xSP esp + %define xBP ebp + %define xAX eax + %define xBX ebx + %define xCX ecx + %define xDX edx + %define xDI edi + %define xSI esi +%endif +%if TEST_BITS == 16 + %define xCB 2 + %define xSP sp + %define xBP bp + %define xAX ax + %define xBX bx + %define xCX cx + %define xDX dx + %define xDI di + %define xSI si +%endif +%ifndef xCB + %error "TEST_BITS is missing or wrong." +%endif + +%if __YASM_VERSION_ID__ >= 001020001h ; v1.2.0.1 and greater, make sure to exclude v1.2.0.0. + %define pmulhrwa pmulhrw +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsm3DNow-1.asm b/src/VBox/Disassembler/testcase/tstAsm3DNow-1.asm new file mode 100644 index 00000000..bd188e41 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsm3DNow-1.asm @@ -0,0 +1,91 @@ +; $Id: tstAsm3DNow-1.asm $ +;; @file +; Disassembly testcase - 3DNow! +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" + + BITS TEST_BITS + + pavgusb mm1, mm0 + pf2id mm5, mm4 + pf2iw mm6, mm3 + pfacc mm7, mm2 + pfadd mm5, mm4 + pfcmpeq mm6, mm3 + pfcmpge mm2, mm7 + pfcmpgt mm4, mm5 + pfmax mm3, mm6 + pfmin mm1, mm0 + pfmul mm5, mm4 + pmulhrwa mm3, mm6 + pfnacc mm4, mm5 + pfpnacc mm3, mm6 + pfrcp mm0, mm1 + pfrcpit1 mm2, mm7 + pfrcpit2 mm4, mm5 + pfrsqrt mm7, mm2 + pfrsqit1 mm1, mm0 + pfsub mm6, mm3 + pfsubr mm0, mm1 + pi2fd mm7, mm2 + pi2fw mm0, mm1 + pswapd mm2, mm7 + +%if TEST_BITS == 16 + %define SIB(extra) + %define SIB(extra) +%else + %define SIB(extra) extra +%endif + pf2id mm5, qword [ds:xSI SIB(+000101010h)] + pf2iw mm6, qword [fs:xSI SIB(+000101010h)] + pfacc mm7, qword [gs:xSI SIB(+000101010h)] + pfadd mm5, qword [ xSI SIB(+000101010h)] + pfcmpeq mm6, qword [ xDI SIB(*8+000101010h)] + pfcmpge mm2, qword [es:xSI SIB(+000100010h)] + pfcmpgt mm4, qword [es:xSI SIB(+000101010h)] + pfmax mm3, qword [es:xSI SIB(+000101010h)] + pfmin mm1, qword [es:xSI SIB(+000101010h)] + pfmul mm5, qword [es:xSI SIB(+000101000h)] + pfrcpit1 mm2, qword [es:xBP SIB(+000101510h)] +%if TEST_BITS != 16 + pavgusb mm1, qword [es:xAX SIB(+000000010h)] + pfpnacc mm3, qword [es:xDX SIB(+000102900h)] + pfrcp mm0, qword [es:xCX SIB(+000101020h)] + pmulhrwa mm3, qword [es:xAX SIB(+0ffffffffh)] + pfrcpit2 mm4, qword [es:xSP SIB(+000101310h)] +%endif + pfnacc mm4, qword [es:xBX SIB(+000101010h)] + pfrsqrt mm7, qword [es:xSI SIB(+0f0106010h)] + pfrsqit1 mm1, qword [es:xDI SIB(+0001f1010h)] + pfsub mm6, qword [es:xSI SIB(*2)] + pfsubr mm0, qword [es:xSI SIB(*3)] + pi2fd mm7, qword [es:xSI SIB(*4)] + pi2fw mm0, qword [es:xSI SIB(*5)] + pswapd mm2, qword [es:xSI SIB(*8)] + + pmulhrwa mm0, qword [ds:xBP SIB(+xDI*8+00f000001h)] + diff --git a/src/VBox/Disassembler/testcase/tstAsmFnstsw-1.asm b/src/VBox/Disassembler/testcase/tstAsmFnstsw-1.asm new file mode 100644 index 00000000..d9899823 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmFnstsw-1.asm @@ -0,0 +1,41 @@ +; $Id: tstAsmFnstsw-1.asm $ +;; @file +; Disassembly testcase - Valid fnstsw* instructitons. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" + BITS TEST_BITS + + fstsw ax + fnstsw ax + fstsw [xBX] + fnstsw [xBX] + fstsw [xBX+xDI] + fnstsw [xBX+xDI] + diff --git a/src/VBox/Disassembler/testcase/tstAsmLock-1.asm b/src/VBox/Disassembler/testcase/tstAsmLock-1.asm new file mode 100644 index 00000000..f9a0b618 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmLock-1.asm @@ -0,0 +1,685 @@ +; $Id: tstAsmLock-1.asm $ +;; @file +; Disassembly testcase - Valid lock sequences and related instructions. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" +%if TEST_BITS == 64 + +; The disassembler doesn't do imm32 right for 64-bit stuff, so disable it for now. +; %define WITH_64_BIT_TESTS_IMM32 + +; The cmpxchg16b/8b stuff isn't handled correctly in 64-bit mode. In the 8b case +; it could be both yasm and the vbox disassembler. Have to check docs/gas/nasm. +; %define WITH_64_BIT_TESTS_CMPXCHG16B + +; Seems there are some issues with the byte, word and dword variants of r8-15. +; Again, this could be yasm issues too... +; %define WITH_64_BIT_TESTS_BORKED_REGS + + %define WITH_64_BIT_TESTS +%endif + + BITS TEST_BITS + + ; + ; ADC + ; + ; 80 /2 ib ADC reg/mem8, imm8 - sans reg dst + lock adc byte [1000h], byte 8 + lock adc byte [xBX], byte 8 + lock adc byte [xDI], byte 8 + ; 81 /2 i[wd] ADC reg/memX, immX - sans reg dst + lock adc word [1000h], word 090cch + lock adc word [xBX], word 090cch + lock adc word [xDI], word 090cch + lock adc dword [1000h], dword 0cc90cc90h + lock adc dword [xBX], dword 0cc90cc90h + lock adc dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock adc qword [1000h], dword 0cc90cc90h + lock adc qword [rbx], dword 0cc90cc90h + lock adc qword [rdi], dword 0cc90cc90h + lock adc qword [r9], dword 0cc90cc90h +%endif + ; 83 /2 ib ADC reg/memX, imm8 - sans reg dst + lock adc word [1000h], byte 07fh + lock adc word [xBX], byte 07fh + lock adc word [xDI], byte 07fh + lock adc dword [1000h], byte 07fh + lock adc dword [xBX], byte 07fh + lock adc dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock adc qword [1000h], byte 07fh + lock adc qword [rbx], byte 07fh + lock adc qword [rdi], byte 07fh + lock adc qword [r10], byte 07fh +%endif + + ; 10 /r ADC reg/mem8, reg8 - sans reg dst + lock adc byte [1000h], bl + lock adc byte [xBX], bl + lock adc byte [xSI], bl + ; 11 /r ADC reg/memX, regX - sans reg dst + lock adc word [1000h], bx + lock adc word [xBX], bx + lock adc word [xSI], bx + lock adc dword [1000h], ebx + lock adc dword [xBX], ebx + lock adc dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock adc qword [1000h], rbx + lock adc qword [rbx], rbx + lock adc qword [rsi], rbx + lock adc qword [r11], rbx +%endif + + ; + ; ADD + ; + ; 80 /0 ib ADD reg/mem8, imm8 - sans reg dst + lock add byte [1000h], byte 8 + lock add byte [xBX], byte 8 + lock add byte [xDI], byte 8 + ; 81 /0 i[wd] ADD reg/memX, immX - sans reg dst + lock add word [1000h], word 090cch + lock add word [xBX], word 090cch + lock add word [xDI], word 090cch + lock add dword [1000h], dword 0cc90cc90h + lock add dword [xBX], dword 0cc90cc90h + lock add dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock add qword [1000h], dword 0cc90cc90h + lock add qword [rbx], dword 0cc90cc90h + lock add qword [rdi], dword 0cc90cc90h + lock add qword [r9], dword 0cc90cc90h +%endif + ; 83 /0 ib ADD reg/memX, imm8 - sans reg dst + lock add word [1000h], byte 07fh + lock add word [xBX], byte 07fh + lock add word [xDI], byte 07fh + lock add dword [1000h], byte 07fh + lock add dword [xBX], byte 07fh + lock add dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock add qword [1000h], byte 07fh + lock add qword [rbx], byte 07fh + lock add qword [rdi], byte 07fh + lock add qword [r10], byte 07fh +%endif + + ; 00 /r ADD reg/mem8, reg8 - sans reg dst + lock add byte [1000h], bl + lock add byte [xBX], bl + lock add byte [xSI], bl + ; 01 /r ADD reg/memX, regX - sans reg dst + lock add word [1000h], bx + lock add word [xBX], bx + lock add word [xSI], bx + lock add dword [1000h], ebx + lock add dword [xBX], ebx + lock add dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock add qword [1000h], rbx + lock add qword [rbx], rbx + lock add qword [rsi], rbx + lock add qword [r11], rbx +%endif + + ; + ; AND + ; + ; 80 /4 ib AND reg/mem8, imm8 - sans reg dst + lock and byte [1000h], byte 8 + lock and byte [xBX], byte 8 + lock and byte [xDI], byte 8 + ; 81 /4 i[wd] AND reg/memX, immX - sans reg dst + lock and word [1000h], word 090cch + lock and word [xBX], word 090cch + lock and word [xDI], word 090cch + lock and dword [1000h], dword 0cc90cc90h + lock and dword [xBX], dword 0cc90cc90h + lock and dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock and qword [1000h], dword 0cc90cc90h + lock and qword [rbx], dword 0cc90cc90h + lock and qword [rdi], dword 0cc90cc90h + lock and qword [r9], dword 0cc90cc90h +%endif + ; 83 /4 ib AND reg/memX, imm8 - sans reg dst + lock and word [1000h], byte 07fh + lock and word [xBX], byte 07fh + lock and word [xDI], byte 07fh + lock and dword [1000h], byte 07fh + lock and dword [xBX], byte 07fh + lock and dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock and qword [1000h], byte 07fh + lock and qword [rbx], byte 07fh + lock and qword [rdi], byte 07fh + lock and qword [r10], byte 07fh +%endif + + ; 20 /r AND reg/mem8, reg8 - sans reg dst + lock and byte [1000h], bl + lock and byte [xBX], bl + lock and byte [xSI], bl + ; 21 /r AND reg/memX, regX - sans reg dst + lock and word [1000h], bx + lock and word [xBX], bx + lock and word [xSI], bx + lock and dword [1000h], ebx + lock and dword [xBX], ebx + lock and dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock and qword [1000h], rbx + lock and qword [rbx], rbx + lock and qword [rsi], rbx + lock and qword [r11], rbx +%endif + + ; + ; BTC + ; + ; 0f bb /r BTC reg/memX, regX (X != 8) - sans reg dst + lock btc word [20cch], bx + lock btc word [xBX], bx + lock btc word [xDI], bx + lock btc dword [20cch], ebx + lock btc dword [xBX], ebx + lock btc dword [xDI], ebx +%ifdef WITH_64_BIT_TESTS + lock btc qword [20cch], rbx + lock btc qword [rdx], rbx + lock btc qword [rdi], r10 + lock btc qword [r8], r12 +%endif + ; 0f ba /7 ib BTC reg/memX, imm8 (X != 8) - sans reg dst + lock btc word [20cch], 15 + lock btc word [xBX], 15 + lock btc word [xDI], 15 + lock btc dword [20cch], 30 + lock btc dword [xBX], 30 + lock btc dword [xDI], 30 +%ifdef WITH_64_BIT_TESTS + lock btc qword [20cch], 60 + lock btc qword [rdx], 60 + lock btc qword [rdi], 60 + lock btc qword [r9], 60 + lock btc qword [r12], 60 +%endif + + ; + ; BTR + ; + ; 0f b3 /r BTR reg/memX, regX (X != 8) - sans reg dst + lock btr word [20cch], bx + lock btr word [xBX], bx + lock btr word [xDI], bx + lock btr dword [20cch], ebx + lock btr dword [xBX], ebx + lock btr dword [xDI], ebx +%ifdef WITH_64_BIT_TESTS + lock btr qword [20cch], rbx + lock btr qword [rdx], rbx + lock btr qword [rdi], r10 + lock btr qword [r8], r12 +%endif + ; 0f ba /6 ib BTR reg/memX, imm8 (X != 8) - sans reg dst + lock btr word [20cch], 15 + lock btr word [xBX], 15 + lock btr word [xDI], 15 + lock btr dword [20cch], 30 + lock btr dword [xBX], 30 + lock btr dword [xDI], 30 +%ifdef WITH_64_BIT_TESTS + lock btr qword [20cch], 60 + lock btr qword [rdx], 60 + lock btr qword [rdi], 60 + lock btr qword [r9], 60 + lock btr qword [r12], 60 +%endif + + ; + ; BTS + ; + ; 0f ab /r BTS reg/memX, regX (X != 8) - sans reg dst + lock bts word [20cch], bx + lock bts word [xBX], bx + lock bts word [xDI], bx + lock bts dword [20cch], ebx + lock bts dword [xBX], ebx + lock bts dword [xDI], ebx +%if TEST_BITS == 64 + lock bts qword [20cch], rbx + lock bts qword [rdx], rbx + lock bts qword [rdi], r10 + lock bts qword [r8], r12 +%endif + ; 0f ba /5 ib BTS reg/memX, imm8 (X != 8) - sans reg dst + lock bts word [20cch], 15 + lock bts word [xBX], 15 + lock bts word [xDI], 15 + lock bts dword [20cch], 30 + lock bts dword [xBX], 30 + lock bts dword [xDI], 30 +%if TEST_BITS == 64 + lock bts qword [20cch], 60 + lock bts qword [rdx], 60 + lock bts qword [rdi], 60 + lock bts qword [r9], 60 + lock bts qword [r12], 60 +%endif + + ; + ; CMPXCHG + ; + ; 0f b0 /r CMPXCHG reg8/mem8, regX - with reg dst + lock cmpxchg byte [30cch], cl + lock cmpxchg byte [xBX], cl + lock cmpxchg byte [xSI], cl + ; 0f b1 /r CMPXCHG regX/memX, regX - with reg dst + lock cmpxchg word [30cch], cx + lock cmpxchg word [xBX], cx + lock cmpxchg word [xSI], cx + lock cmpxchg dword [30cch], ecx + lock cmpxchg dword [xBX], ecx + lock cmpxchg dword [xSI], ecx +%ifdef WITH_64_BIT_TESTS + lock cmpxchg qword [30cch], rcx + lock cmpxchg qword [xBX], rcx + lock cmpxchg qword [xSI], rcx + lock cmpxchg qword [rdi], r8 + lock cmpxchg qword [r12], r9 +%endif + + ; + ; CMPXCHG8B + ; CMPXCHG16B + ; + ;; @todo get back to cmpxchg8b and cmpxchg16b. + lock cmpxchg8b qword [1000h] + lock cmpxchg8b qword [xDI] + lock cmpxchg8b qword [xDI+xBX] +%ifdef WITH_64_BIT_TESTS_CMPXCHG16B + lock cmpxchg16b [1000h] + lock cmpxchg16b [xDI] + lock cmpxchg16b [xDI+xBX] +%endif + + ; + ; DEC + ; + ; fe /1 DEC reg8/mem8 - sans reg dst + lock dec byte [40cch] + lock dec byte [xBX] + lock dec byte [xSI] + ; ff /1 DEC regX/memX - sans reg dst + lock dec word [40cch] + lock dec word [xBX] + lock dec word [xSI] + lock dec dword [40cch] + lock dec dword [xBX] + lock dec dword [xSI] +%ifdef WITH_64_BIT_TESTS + lock dec qword [40cch] + lock dec qword [xBX] + lock dec qword [xSI] + lock dec qword [r8] + lock dec qword [r12] +%endif + + ; + ; INC + ; + ; fe /0 INC reg8/mem8 - sans reg dst + lock inc byte [40cch] + lock inc byte [xBX] + lock inc byte [xSI] + ; ff /0 INC regX/memX - sans reg dst + lock inc word [40cch] + lock inc word [xBX] + lock inc word [xSI] + lock inc dword [40cch] + lock inc dword [xBX] + lock inc dword [xSI] +%ifdef WITH_64_BIT_TESTS + lock inc qword [40cch] + lock inc qword [xBX] + lock inc qword [xSI] + lock inc qword [r8] + lock inc qword [r12] +%endif + + ; + ; NEG + ; + ; f6 /3 NEG reg8/mem8 - sans reg dst + lock neg byte [40cch] + lock neg byte [xBX] + lock neg byte [xSI] + ; f7 /3 NEG regX/memX - sans reg dst + lock neg word [40cch] + lock neg word [xBX] + lock neg word [xSI] + lock neg dword [40cch] + lock neg dword [xBX] + lock neg dword [xSI] +%ifdef WITH_64_BIT_TESTS + lock neg qword [40cch] + lock neg qword [xBX] + lock neg qword [xSI] + lock neg qword [r8] + lock neg qword [r12] +%endif + + ; + ; NOT + ; + ; f6 /2 NOT reg8/mem8 - sans reg dst + lock not byte [40cch] + lock not byte [xBX] + lock not byte [xSI] + ; f7 /2 NOT regX/memX - sans reg dst + lock not word [40cch] + lock not word [xBX] + lock not word [xSI] + lock not dword [40cch] + lock not dword [xBX] + lock not dword [xSI] +%ifdef WITH_64_BIT_TESTS + lock not qword [40cch] + lock not qword [xBX] + lock not qword [xSI] + lock not qword [r8] + lock not qword [r12] +%endif + + ; + ; OR + ; + ; 80 /1 ib OR reg/mem8, imm8 - sans reg dst + lock or byte [1000h], byte 8 + lock or byte [xBX], byte 8 + lock or byte [xDI], byte 8 + ; 81 /1 i[wd] OR reg/memX, immX - sans reg dst + lock or word [1000h], word 090cch + lock or word [xBX], word 090cch + lock or word [xDI], word 090cch + lock or dword [1000h], dword 0cc90cc90h + lock or dword [xBX], dword 0cc90cc90h + lock or dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock or qword [1000h], dword 0cc90cc90h + lock or qword [rbx], dword 0cc90cc90h + lock or qword [rdi], dword 0cc90cc90h + lock or qword [r9], dword 0cc90cc90h +%endif + ; 83 /1 ib OR reg/memX, imm8 - sans reg dst + lock or word [1000h], byte 07fh + lock or word [xBX], byte 07fh + lock or word [xDI], byte 07fh + lock or dword [1000h], byte 07fh + lock or dword [xBX], byte 07fh + lock or dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock or qword [1000h], byte 07fh + lock or qword [rbx], byte 07fh + lock or qword [rdi], byte 07fh + lock or qword [r10], byte 07fh +%endif + + ; 08 /r OR reg/mem8, reg8 - sans reg dst + lock or byte [1000h], bl + lock or byte [xBX], bl + lock or byte [xSI], bl + ; 09 /r OR reg/memX, regX - sans reg dst + lock or word [1000h], bx + lock or word [xBX], bx + lock or word [xSI], bx + lock or dword [1000h], ebx + lock or dword [xBX], ebx + lock or dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock or qword [1000h], rbx + lock or qword [rbx], rbx + lock or qword [rsi], rbx + lock or qword [r11], rbx +%endif + + ; + ; SBB + ; + ; 80 /3 ib SBB reg/mem8, imm8 - sans reg dst + lock sbb byte [1000h], byte 8 + lock sbb byte [xBX], byte 8 + lock sbb byte [xDI], byte 8 + ; 81 /3 i[wd] SBB reg/memX, immX - sans reg dst + lock sbb word [1000h], word 090cch + lock sbb word [xBX], word 090cch + lock sbb word [xDI], word 090cch + lock sbb dword [1000h], dword 0cc90cc90h + lock sbb dword [xBX], dword 0cc90cc90h + lock sbb dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sbb qword [1000h], dword 0cc90cc90h + lock sbb qword [rbx], dword 0cc90cc90h + lock sbb qword [rdi], dword 0cc90cc90h + lock sbb qword [r9], dword 0cc90cc90h +%endif + ; 83 /3 ib SBB reg/memX, imm8 - sans reg dst + lock sbb word [1000h], byte 07fh + lock sbb word [xBX], byte 07fh + lock sbb word [xDI], byte 07fh + lock sbb dword [1000h], byte 07fh + lock sbb dword [xBX], byte 07fh + lock sbb dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock sbb qword [1000h], byte 07fh + lock sbb qword [rbx], byte 07fh + lock sbb qword [rdi], byte 07fh + lock sbb qword [r10], byte 07fh +%endif + + ; 18 /r SBB reg/mem8, reg8 - sans reg dst + lock sbb byte [1000h], bl + lock sbb byte [xBX], bl + lock sbb byte [xSI], bl + ; 19 /r SBB reg/memX, regX - sans reg dst + lock sbb word [1000h], bx + lock sbb word [xBX], bx + lock sbb word [xSI], bx + lock sbb dword [1000h], ebx + lock sbb dword [xBX], ebx + lock sbb dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock sbb qword [1000h], rbx + lock sbb qword [rbx], rbx + lock sbb qword [rsi], rbx + lock sbb qword [r11], rbx +%endif + + ; + ; SUB + ; + ; 80 /5 ib SUB reg/mem8, imm8 - sans reg dst + lock sub byte [1000h], byte 8 + lock sub byte [xBX], byte 8 + lock sub byte [xDI], byte 8 + ; 81 /5 i[wd] SUB reg/memX, immX - sans reg dst + lock sub word [1000h], word 090cch + lock sub word [xBX], word 090cch + lock sub word [xDI], word 090cch + lock sub dword [1000h], dword 0cc90cc90h + lock sub dword [xBX], dword 0cc90cc90h + lock sub dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sub qword [1000h], dword 0cc90cc90h + lock sub qword [rbx], dword 0cc90cc90h + lock sub qword [rdi], dword 0cc90cc90h + lock sub qword [r9], dword 0cc90cc90h +%endif + ; 83 /5 ib SUB reg/memX, imm8 - sans reg dst + lock sub word [1000h], byte 07fh + lock sub word [xBX], byte 07fh + lock sub word [xDI], byte 07fh + lock sub dword [1000h], byte 07fh + lock sub dword [xBX], byte 07fh + lock sub dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock sub qword [1000h], byte 07fh + lock sub qword [rbx], byte 07fh + lock sub qword [rdi], byte 07fh + lock sub qword [r10], byte 07fh +%endif + + ; 28 /r SUB reg/mem8, reg8 - sans reg dst + lock sub byte [1000h], bl + lock sub byte [xBX], bl + lock sub byte [xSI], bl + ; 29 /r SUB reg/memX, regX - sans reg dst + lock sub word [1000h], bx + lock sub word [xBX], bx + lock sub word [xSI], bx + lock sub dword [1000h], ebx + lock sub dword [xBX], ebx + lock sub dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock sub qword [1000h], rbx + lock sub qword [rbx], rbx + lock sub qword [rsi], rbx + lock sub qword [r11], rbx +%endif + + ; + ; XADD + ; + ; 0f c0 /r XADD reg/mem8, reg8 - sans reg dst + lock xadd byte [1000h], bl + lock xadd byte [xBX], bl + lock xadd byte [xDI], bl + ; 0f c1 /r XADD reg/memX, immX - sans reg dst + lock xadd word [1000h], cx + lock xadd word [xBX], cx + lock xadd word [xDI], cx + lock xadd dword [1000h], edx + lock xadd dword [xBX], edx + lock xadd dword [xDI], edx +%ifdef WITH_64_BIT_TESTS + lock xadd qword [1000h], rbx + lock xadd qword [xBX], rbx + lock xadd qword [xDI], rbx + lock xadd qword [r8], rbx + lock xadd qword [r12], r8 +%endif + + ; + ; XCHG + ; + ; Note: The operands can be switched around but the + ; encoding is the same. + ; + ; 86 /r XCHG reg/mem8, imm8 - sans reg dst + lock xchg byte [80cch], bl + lock xchg byte [xBX], bl + lock xchg byte [xSI], bl +%ifdef WITH_64_BIT_TESTS_BORKED_REGS + lock xchg byte [rsi], r15b ; turns into r15l which yasm doesn't grok + lock xchg byte [r8], r15b ; ditto +%endif + ; 87 /r XCHG reg/memX, immX - sans reg dst + lock xchg word [80cch], bx + lock xchg word [xBX], bx + lock xchg word [xSI], bx + lock xchg dword [80cch], ebx + lock xchg dword [xBX], ebx + lock xchg dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock xchg qword [80cch], rbx + lock xchg qword [xBX], rbx + lock xchg qword [xSI], rbx + lock xchg qword [xSI], r15 + %ifdef WITH_64_BIT_TESTS_BORKED_REGS + lock xchg dword [xSI], r15d ; turns into rdi + lock xchg word [xSI], r15w ; turns into rdi + %endif +%endif + + ; + ; XOR + ; + ; 80 /6 ib XOR reg/mem8, imm8 - sans reg dst + lock xor byte [1000h], byte 8 + lock xor byte [xBX], byte 8 + lock xor byte [xDI], byte 8 + ; 81 /6 i[wd] XOR reg/memX, immX - sans reg dst + lock xor word [1000h], word 090cch + lock xor word [xBX], word 090cch + lock xor word [xDI], word 090cch + lock xor dword [1000h], dword 0cc90cc90h + lock xor dword [xBX], dword 0cc90cc90h + lock xor dword [xDI], dword 0cc90cc90h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock xor qword [1000h], dword 0cc90cc90h + lock xor qword [rbx], dword 0cc90cc90h + lock xor qword [rdi], dword 0cc90cc90h + lock xor qword [r9], dword 0cc90cc90h +%endif + ; 83 /6 ib XOR reg/memX, imm8 - sans reg dst + lock xor word [1000h], byte 07fh + lock xor word [xBX], byte 07fh + lock xor word [xDI], byte 07fh + lock xor dword [1000h], byte 07fh + lock xor dword [xBX], byte 07fh + lock xor dword [xDI], byte 07fh +%ifdef WITH_64_BIT_TESTS + lock xor qword [1000h], byte 07fh + lock xor qword [rbx], byte 07fh + lock xor qword [rdi], byte 07fh + lock xor qword [r10], byte 07fh +%endif + + ; 30 /r XOR reg/mem8, reg8 - sans reg dst + lock xor byte [1000h], bl + lock xor byte [xBX], bl + lock xor byte [xSI], bl + ; 31 /r XOR reg/memX, regX - sans reg dst + lock xor word [1000h], bx + lock xor word [xBX], bx + lock xor word [xSI], bx + lock xor dword [1000h], ebx + lock xor dword [xBX], ebx + lock xor dword [xSI], ebx +%ifdef WITH_64_BIT_TESTS + lock xor qword [1000h], rbx + lock xor qword [rbx], rbx + lock xor qword [rsi], rbx + lock xor qword [r11], rbx +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmLock-2.asm b/src/VBox/Disassembler/testcase/tstAsmLock-2.asm new file mode 100644 index 00000000..f1e38b3a --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmLock-2.asm @@ -0,0 +1,547 @@ +; $Id: tstAsmLock-2.asm $ +;; @file +; Disassembly testcase - Invalid invariants. +; +; The intention is to check in a binary using the --all-invalid mode +; of tstDisasm-2. +; +; There are some regX, reg/memX variations that aren't tested as +; they would require db'ing out the instructions (12 /r and 13 /r +; for instance). +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" +%if TEST_BITS == 64 +; The disassembler doesn't do imm32 right for 64-bit stuff, so disable it for now. +; %define WITH_64_BIT_TESTS_IMM32 + %define WITH_64_BIT_TESTS +%endif + + BITS TEST_BITS + + ; + ; ADC + ; + ; 14 ib ADC AL, imm8 + lock adc al, byte 8 + ; 15 i[wd] ADC [ER]AX, immX + lock adc ax, word 16 + lock adc eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock adc rax, dword 256 + lock adc rax, dword 0cc90cc90h +%endif + ; 80 /2 ib ADC reg/mem8, imm8 - with reg dst + lock adc cl, byte 8 + ; 81 /2 i[wd] ADC reg/memX, immX - with reg dst + lock adc cx, word 1000h + lock adc ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock adc rcx, dword 100000h +%endif + ; 83 /2 ib ADC reg/memX, imm8 - with reg dst + lock adc cx, byte 07fh + lock adc ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS_IMM32 + lock adc rcx, byte 07fh +%endif + + ; 10 /r ADC reg/mem8, reg8 - with reg dst + lock adc cl, bl + ; 11 /r ADC reg/memX, regX - with reg dst + lock adc cx, bx + lock adc ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock adc rcx, rbx +%endif + ; 12 /r ADC reg8, reg/mem8 + lock adc cl, [0badh] + ; 13 /r ADC regX, reg/memX + lock adc cx, [0badh] + lock adc ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock adc rcx, [0badh] +%endif + + ; + ; ADD + ; + ; 04 ib ADD AL, imm8 + lock add al, byte 8 + ; 05 i[wd] ADD [ER]AX, immX + lock add ax, word 16 + lock add eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock add rax, dword 256 + lock add rax, dword 0cc90cc90h +%endif + ; 80 /0 ib ADD reg/mem8, imm8 - with reg dst + lock add cl, byte 8 + ; 81 /0 i[wd] ADD reg/memX, immX - with reg dst + lock add cx, word 1000h + lock add ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock add rcx, dword 100000h +%endif + ; 83 /0 ib ADD reg/memX, imm8 - with reg dst + lock add cx, byte 07fh + lock add ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS + lock add rcx, byte 07fh +%endif + + ; 00 /r ADD reg/mem8, reg8 - with reg dst + lock add cl, bl + ; 01 /r ADD reg/memX, regX - with reg dst + lock add cx, bx + lock add ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock add rcx, rbx +%endif + ; 02 /r ADD reg8, reg/mem8 + lock add cl, [0badh] + ; 03 /r ADD regX, reg/memX + lock add cx, [0badh] + lock add ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock add rcx, [0badh] +%endif + + ; + ; AND + ; + ; 24 ib AND AL, imm8 + lock and al, byte 8 + ; 25 i[wd] AND [ER]AX, immX + lock and ax, word 16 + lock and eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock and rax, dword 256 + lock and rax, dword 0cc90cc90h +%endif + ; 80 /4 ib AND reg/mem8, imm8 - with reg dst + lock and cl, byte 8 + ; 81 /4 i[wd] AND reg/memX, immX - with reg dst + lock and cx, word 1000h + lock and ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock and rcx, dword 100000h +%endif + ; 83 /4 ib AND reg/memX, imm8 - with reg dst + lock and cx, byte 07fh + lock and ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS + lock and rcx, byte 07fh +%endif + + ; 20 /r AND reg/mem8, reg8 - with reg dst + lock and cl, bl + ; 21 /r AND reg/memX, regX - with reg dst + lock and cx, bx + lock and ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock and rcx, rbx +%endif + ; 22 /r AND reg8, reg/mem8 + lock and cl, [0badh] + ; 23 /r AND regX, reg/memX + lock and cx, [0badh] + lock and ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock and rcx, [0badh] +%endif + + ; + ; BTC + ; + ; 0f bb /r BTC reg/memX, regX (X != 8) - with reg dst + lock btc cx, bx + lock btc ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock btc rcx, rbx + lock btc r8, rbx + lock btc r10, r8 +%endif + ; 0f ba /7 ib BTC reg/memX, imm8 (X != 8) - with reg dst + lock btc cx, 15 + lock btc ecx, 30 +%ifdef WITH_64_BIT_TESTS + lock btc rcx, 60 + lock btc r8, 61 + lock btc r10, 3 +%endif + + ; + ; BTR + ; + ; 0f b3 /r BTR reg/memX, regX (X != 8) - with reg dst + lock btr cx, bx + lock btr ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock btr rcx, rbx + lock btr r8, rbx + lock btr r10, r8 +%endif + ; 0f ba /6 ib BTR reg/memX, imm8 (X != 8) - with reg dst + lock btr cx, 15 + lock btr ecx, 30 +%ifdef WITH_64_BIT_TESTS + lock btr rcx, 60 + lock btr r8, 61 + lock btr r10, 3 +%endif + + ; + ; BTS + ; + ; 0f ab /r BTS reg/memX, regX (X != 8) - with reg dst + lock bts cx, bx + lock bts ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock bts rcx, rbx + lock bts r8, rbx + lock bts r10, r8 +%endif + ; 0f ba /5 ib BTS reg/memX, imm8 (X != 8) - with reg dst + lock bts cx, 15 + lock bts ecx, 30 +%ifdef WITH_64_BIT_TESTS + lock bts rcx, 60 + lock bts r8, 61 + lock bts r10, 3 +%endif + + ; + ; CMPXCHG + ; + ; 0f b0 /r CMPXCHG reg8/mem8, regX - with reg dst + lock cmpxchg bl, cl + ; 0f b1 /r CMPXCHG regX/memX, regX - with reg dst + lock cmpxchg bx, cx + lock cmpxchg ebx, ecx +%ifdef WITH_64_BIT_TESTS + lock cmpxchg rbx, rcx +%endif + + ; + ; CMPXCHG8B + ; CMPXCHG16B + ; + ; all valid. + + ; + ; DEC + ; + ; fe /1 DEC reg8/mem8 - with reg dst + lock dec bl + ; ff /1 DEC regX/memX - with reg dst + +%if TEST_BITS != 64 ; cannot force these two in 32 and 16 bit mode. + db 066h, 0f0h, 0ffh, 0cbh + db 0f0h, 0ffh, 0cbh +%else + lock dec bx + lock dec ebx + %ifdef WITH_64_BIT_TESTS + lock dec rbx + lock dec r8 + lock dec r14 + %endif +%endif +%if TEST_BITS != 64 + ; 48 +rw DEC reg16 + lock dec dx + ; 48 +rd DEC reg32 + lock dec edx +%endif + + ; + ; INC + ; + ; fe /1 INC reg8/mem8 - with reg dst + lock inc bl + ; ff /1 INC regX/memX - with reg dst + +%if TEST_BITS != 64 ; cannot force these two in 32 and 16 bit mode. + db 066h, 0f0h, 0ffh, 0c3h + db 0f0h, 0ffh, 0c3h +%else + lock inc bx + lock inc ebx + %ifdef WITH_64_BIT_TESTS + lock inc rbx + lock inc r8 + lock inc r14 + %endif +%endif +%if TEST_BITS != 64 + ; 48 +rw INC reg16 + lock inc dx + ; 48 +rd INC reg32 + lock inc edx +%endif + + ; + ; NEG + ; + ; f6 /3 NEG reg8/mem8 - with reg dst + lock neg bl + ; f7 /3 NEG regX/memX - with reg dst + lock neg bx + lock neg ebx +%ifdef WITH_64_BIT_TESTS + lock neg rbx + lock neg r8 + lock neg r14 +%endif + + ; + ; NOT + ; + ; f6 /2 NOT reg8/mem8 - with reg dst + lock not bl + ; f7 /2 NOT regX/memX - with reg dst + lock not bx + lock not ebx +%ifdef WITH_64_BIT_TESTS + lock not rbx + lock not r8 + lock not r14 +%endif + + ; + ; OR + ; + ; 0C ib OR AL, imm8 + lock or al, byte 8 + ; 0D i[wd] OR [ER]AX, immX + lock or ax, word 16 + lock or eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock or rax, dword 256 + lock or rax, dword 0cc90cc90h +%endif + ; 80 /1 ib OR reg/mem8, imm8 - with reg dst + lock or cl, byte 8 + ; 81 /1 i[wd] OR reg/memX, immX - with reg dst + lock or cx, word 1000h + lock or ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock or rcx, dword 100000h +%endif + ; 83 /1 ib OR reg/memX, imm8 - with reg dst + lock or cx, byte 07fh + lock or ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS_IMM32 + lock or rcx, byte 07fh +%endif + ; 08 /r OR reg/mem8, reg8 - with reg dst + lock or cl, bl + ; 09 /r OR reg/memX, regX - with reg dst + lock or cx, bx + lock or ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock or rcx, rbx +%endif + ; 0A /r OR reg8, reg/mem8 + lock or cl, [0badh] + ; 0B /r OR regX, reg/memX + lock or cx, [0badh] + lock or ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock or rcx, [0badh] +%endif + + ; + ; SBB + ; + ; 1C ib SBB AL, imm8 + lock sbb al, byte 8 + ; 1D i[wd] SBB [ER]AX, immX + lock sbb ax, word 16 + lock sbb eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sbb rax, dword 256 + lock sbb rax, dword 0cc90cc90h +%endif + ; 80 /3 ib SBB reg/mem8, imm8 - with reg dst + lock sbb cl, byte 8 + ; 81 /3 i[wd] SBB reg/memX, immX - with reg dst + lock sbb cx, word 1000h + lock sbb ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sbb rcx, dword 100000h +%endif + ; 83 /3 ib SBB reg/memX, imm8 - with reg dst + lock sbb cx, byte 07fh + lock sbb ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sbb rcx, byte 07fh +%endif + ; 18 /r SBB reg/mem8, reg8 - with reg dst + lock sbb cl, bl + ; 19 /r SBB reg/memX, regX - with reg dst + lock sbb cx, bx + lock sbb ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock sbb rcx, rbx +%endif + ; 1A /r SBB reg8, reg/mem8 + lock sbb cl, [0badh] + ; 1B /r SBB regX, reg/memX + lock sbb cx, [0badh] + lock sbb ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock sbb rcx, [0badh] +%endif + + ; + ; SUB + ; + ; 2C ib SUB AL, imm8 + lock sub al, byte 8 + ; 2D i[wd] SUB [ER]AX, immX + lock sub ax, word 16 + lock sub eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sub rax, dword 256 + lock sub rax, dword 0cc90cc90h +%endif + ; 80 /5 ib SUB reg/mem8, imm8 - with reg dst + lock sub cl, byte 8 + ; 81 /5 i[wd] SUB reg/memX, immX - with reg dst + lock sub cx, word 1000h + lock sub ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sub rcx, dword 100000h +%endif + ; 83 /5 ib SUB reg/memX, imm8 - with reg dst + lock sub cx, byte 07fh + lock sub ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS_IMM32 + lock sub rcx, byte 07fh +%endif + ; 28 /r SUB reg/mem8, reg8 - with reg dst + lock sub cl, bl + ; 29 /r SUB reg/memX, regX - with reg dst + lock sub cx, bx + lock sub ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock sub rcx, rbx +%endif + ; 2A /r SUB reg8, reg/mem8 + lock sub cl, [0badh] + ; 2B /r SUB regX, reg/memX + lock sub cx, [0badh] + lock sub ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock sub rcx, [0badh] +%endif + + ; + ; XADD + ; + ; 0f c0 /r XADD reg/mem8, reg8 - with reg dst + lock xadd al, bl + ; 0f c1 /r XADD reg/memX, immX - with reg dst + lock xadd cx, bx + lock xadd ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock xadd rcx, rbx + lock xadd r8, rbx + lock xadd r10, r8 +%endif + + ; + ; XCHG + ; + ; Note: The operands can be switched around but the + ; encoding is the same. + ; + ; 90 +r[wdq] XCHG [RE]ax, regX + lock xchg ax, bx + lock xchg eax, ecx +%ifdef WITH_64_BIT_TESTS + lock xchg rax, rcx + lock xchg rax, r10 +%endif + ; 86 /r XCHG reg/mem8, imm8 - with reg dst + lock xchg al, bl +%ifdef WITH_64_BIT_TESTS + lock xchg r10b, cl + lock xchg r10b, r15b +%endif + ; 87 /r XCHG reg/memX, immX - with reg dst + lock xchg ax, bx + lock xchg eax, ebx +%ifdef WITH_64_BIT_TESTS_IMM32 + lock xchg rax, rbx + lock xchg r12, rbx + lock xchg r14, r8 +%endif + + ; + ; XOR + ; + ; 34 ib XOR AL, imm8 + lock xor al, byte 8 + ; 35 i[wd] XOR [ER]AX, immX + lock xor ax, word 16 + lock xor eax, dword 128 +%ifdef WITH_64_BIT_TESTS_IMM32 + lock xor rax, dword 256 + lock xor rax, dword 0cc90cc90h +%endif + ; 80 /6 ib XOR reg/mem8, imm8 - with reg dst + lock xor cl, byte 8 + ; 81 /6 i[wd] XOR reg/memX, immX - with reg dst + lock xor cx, word 1000h + lock xor ecx, dword 100000h +%ifdef WITH_64_BIT_TESTS_IMM32 + lock xor rcx, dword 100000h +%endif + ; 83 /6 ib XOR reg/memX, imm8 - with reg dst + lock xor cx, byte 07fh + lock xor ecx, byte 07fh +%ifdef WITH_64_BIT_TESTS_IMM32 + lock xor rcx, byte 07fh +%endif + ; 30 /r XOR reg/mem8, reg8 - with reg dst + lock xor cl, bl + ; 31 /r XOR reg/memX, regX - with reg dst + lock xor cx, bx + lock xor ecx, ebx +%ifdef WITH_64_BIT_TESTS + lock xor rcx, rbx +%endif + ; 32 /r XOR reg8, reg/mem8 + lock xor cl, [0badh] + ; 33 /r XOR regX, reg/memX + lock xor cx, [0badh] + lock xor ecx, [0badh] +%ifdef WITH_64_BIT_TESTS + lock xor rcx, [0badh] +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmLock-3.asm b/src/VBox/Disassembler/testcase/tstAsmLock-3.asm new file mode 100644 index 00000000..508be5e8 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmLock-3.asm @@ -0,0 +1,56 @@ +; $Id: tstAsmLock-3.asm $ +;; @file +; Disassembly testcase - Invalid lock sequences for non-locking instructions. +; +; The intention is to check in a binary using the --all-invalid mode +; of tstDisasm-2. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" + + BITS TEST_BITS + + lock mov ebp, esp + lock mov byte [0], 0 + lock mov word [0], 0 + lock mov dword [0], 0 + lock mov word [0], 01234h + lock mov dword [0], 012348765h + lock mov byte [ebx], 0 + lock mov [ebx], eax + lock mov [ebx], ax + lock mov [ebx], al + lock mov [ebx], edx + lock mov [ebx], dx + lock mov [ebx], dl + lock ret +%if TEST_BITS != 64 + lock pop ebp + lock push esp +%else + lock pop rbp + lock push rsp +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmMovFixedReg-1.asm b/src/VBox/Disassembler/testcase/tstAsmMovFixedReg-1.asm new file mode 100644 index 00000000..571994a4 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmMovFixedReg-1.asm @@ -0,0 +1,113 @@ +; $Id: tstAsmMovFixedReg-1.asm $ +;; @file +; Disassembly testcase - Valid mov immediate to fixed registers. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2013-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + + BITS TEST_BITS + + mov al, 01h + mov cl, 02h + mov dl, 03h + mov bl, 04h + mov ah, 05h + mov ch, 06h + mov dh, 07h + mov bh, 08h +%if TEST_BITS == 64 + mov spl, 09h + mov bpl, 0ah + mov sil, 0bh + mov dil, 0ch + mov r8b, 0dh + mov r9b, 0eh + mov r10b, 0fh + mov r11b, 010h + mov r12b, 011h + mov r13b, 012h + mov r14b, 013h + mov r15b, 014h +%endif + + mov ax, 0f701h + mov cx, 0f702h + mov dx, 0f703h + mov bx, 0f704h + mov sp, 0f705h + mov bp, 0f706h + mov si, 0f707h + mov di, 0f708h +%if TEST_BITS == 64 + mov r8w, 0f709h + mov r9w, 0f70ah + mov r10w, 0f70bh + mov r11w, 0f70ch + mov r12w, 0f70dh + mov r13w, 0f70eh + mov r14w, 0f70fh + mov r15w, 0f710h +%endif + + mov eax, 0beeff701h + mov ecx, 0beeff702h + mov edx, 0beeff703h + mov ebx, 0beeff704h + mov esp, 0beeff705h + mov ebp, 0beeff706h + mov esi, 0beeff707h + mov edi, 0beeff708h +%if TEST_BITS == 64 + mov r8d, 0beeff709h + mov r9d, 0beeff70ah + mov r10d, 0beeff70bh + mov r11d, 0beeff70ch + mov r12d, 0beeff70dh + mov r13d, 0beeff70eh + mov r14d, 0beeff70fh + mov r15d, 0beeff710h +%endif + +%if TEST_BITS == 64 + mov rax, 0feedbabef00df701h + mov rcx, 0feedbabef00df702h + mov rdx, 0feedbabef00df703h + mov rbx, 0feedbabef00df704h + mov rsp, 0feedbabef00df705h + mov rbp, 0feedbabef00df706h + mov rsi, 0feedbabef00df707h + mov rdi, 0feedbabef00df708h + mov r8, 0feedbabef00df709h + mov r9, 0feedbabef00df70ah + mov r10, 0feedbabef00df70bh + mov r11, 0feedbabef00df70ch + mov r12, 0feedbabef00df70dh + mov r13, 0feedbabef00df70eh + mov r14, 0feedbabef00df70fh + mov r15, 0feedbabef00df710h +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmMovSeg-1.asm b/src/VBox/Disassembler/testcase/tstAsmMovSeg-1.asm new file mode 100644 index 00000000..f4df41cf --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmMovSeg-1.asm @@ -0,0 +1,58 @@ +; $Id: tstAsmMovSeg-1.asm $ +;; @file +; Disassembly testcase - Valid mov from/to segment instructions. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + + BITS TEST_BITS + + mov fs, eax + mov fs, ax +%if TEST_BITS == 64 + mov fs, rax +%endif + + mov fs, [ebx] +%if TEST_BITS != 64 + mov fs, [bx] +%else + mov fs, [rbx] +%endif + + mov ax, fs + mov eax, fs +%if TEST_BITS == 64 + mov rax, fs +%endif + + mov [ebx], fs +%if TEST_BITS != 64 + mov [bx], fs +%else + mov [rbx], fs +%endif diff --git a/src/VBox/Disassembler/testcase/tstAsmMovzx-1.asm b/src/VBox/Disassembler/testcase/tstAsmMovzx-1.asm new file mode 100644 index 00000000..910c8900 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmMovzx-1.asm @@ -0,0 +1,49 @@ +; $Id: tstAsmMovzx-1.asm $ +;; @file +; Disassembly testcase - Valid movzx sequences and related instructions. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + + BITS TEST_BITS + + movzx ax, al + movzx eax, al + movzx ax, [ebx] + movzx eax, byte [ebx] + movzx eax, word [ebx] +%if TEST_BITS != 64 + movzx ax, [bx+si+8] + movzx eax, byte [bx+si+8] + movzx eax, word [bx+si+8] +%else + movzx rax, al + movzx rax, ax + movzx rax, byte [rsi] + movzx rax, word [rsi] +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmPop-1.asm b/src/VBox/Disassembler/testcase/tstAsmPop-1.asm new file mode 100644 index 00000000..7cc44fa2 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmPop-1.asm @@ -0,0 +1,46 @@ +; $Id: tstAsmPop-1.asm $ +;; @file +; Disassembly testcase - Valid pop sequences and related instructions. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + + BITS TEST_BITS +%if TEST_BITS != 64 + pop bp + pop ebp + pop word [bp] + pop dword [bp] + pop word [ebp] + pop dword [ebp] +%else + %if 0 ; doesn't work yet + pop rbp + pop qword [rbp] + %endif +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmPush-1.asm b/src/VBox/Disassembler/testcase/tstAsmPush-1.asm new file mode 100644 index 00000000..a87e86c8 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmPush-1.asm @@ -0,0 +1,46 @@ +; $Id: tstAsmPush-1.asm $ +;; @file +; Disassembly testcase - Valid push sequences and related instructions. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + + BITS TEST_BITS +%if TEST_BITS != 64 + push bp + push ebp + push word [bp] + push dword [bp] + push word [ebp] + push dword [ebp] +%else + %if 0 ; doesn't work yet - default operand size is wrong? + push rbp + push qword [rbp] + %endif +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmRegs-1.asm b/src/VBox/Disassembler/testcase/tstAsmRegs-1.asm new file mode 100644 index 00000000..eecfd879 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmRegs-1.asm @@ -0,0 +1,119 @@ +; $Id: tstAsmRegs-1.asm $ +;; @file +; Disassembly testcase - Accessing all the registers +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" + + BITS TEST_BITS + + ;; @todo + ; Missing a bunch of permutations and encoding variants + ; + + mov al, al + mov al, ah + mov al, bl + mov al, bh + mov al, cl + mov al, ch + mov al, dl + mov al, dh +%if TEST_BITS == 64 + mov al, dil + mov al, sil + mov al, bpl + mov al, spl + mov al, r8b + mov al, r9b + mov al, r10b + mov al, r11b + mov al, r12b + mov al, r13b + mov al, r14b + mov al, r15b +%endif + + mov ax, ax + mov ax, bx + mov ax, cx + mov ax, dx + mov ax, si + mov ax, di + mov ax, bp + mov ax, sp +%if TEST_BITS == 64 + mov ax, r8w + mov ax, r9w + mov ax, r10w + mov ax, r11w + mov ax, r12w + mov ax, r13w + mov ax, r14w + mov ax, r15w +%endif + + mov eax, eax + mov eax, ebx + mov eax, ecx + mov eax, edx + mov eax, esi + mov eax, edi + mov eax, ebp + mov eax, esp +%if TEST_BITS == 64 + mov eax, r8d + mov eax, r9d + mov eax, r10d + mov eax, r11d + mov eax, r12d + mov eax, r13d + mov eax, r14d + mov eax, r15d +%endif + +%if TEST_BITS == 64 + mov rax, rax + mov rax, rbx + mov rax, rcx + mov rax, rdx + mov rax, rsi + mov rax, rdi + mov rax, rbp + mov rax, rsp + mov rax, r8 + mov rax, r9 + mov rax, r10 + mov rax, r11 + mov rax, r12 + mov rax, r13 + mov rax, r14 + mov rax, r15 +%endif + diff --git a/src/VBox/Disassembler/testcase/tstAsmSignExtend-1.asm b/src/VBox/Disassembler/testcase/tstAsmSignExtend-1.asm new file mode 100644 index 00000000..0b3228ca --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstAsmSignExtend-1.asm @@ -0,0 +1,63 @@ +; $Id: tstAsmSignExtend-1.asm $ +;; @file +; Disassembly testcase - Valid sign extension instructions. +; +; This is a build test, that means it will be assembled, disassembled, +; then the disassembly output will be assembled and the new binary will +; compared with the original. +; + +; +; Copyright (C) 2008-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +%include "tstAsm.mac" + BITS TEST_BITS + + movsx ax, al + movsx eax, al + movsx eax, ax + + ; + ; ParseImmByteSX + ; + + ; 83 /x + add eax, strict byte 8 + add eax, strict byte -1 + cmp ebx, strict byte -1 + + add ax, strict byte 8 + add ax, strict byte -1 + cmp bx, strict byte -1 + +%if TEST_BITS == 64 ; check that these come out with qword values and not words or dwords. + add rax, strict byte 8 + add rax, strict byte -1 + cmp rbx, strict byte -1 +%endif + + ; push %Ib + push strict byte -1 + push strict byte -128 + push strict byte 127 + + ;; @todo imul diff --git a/src/VBox/Disassembler/testcase/tstBinFnstsw-1.bin b/src/VBox/Disassembler/testcase/tstBinFnstsw-1.bin Binary files differnew file mode 100644 index 00000000..b23f6031 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstBinFnstsw-1.bin diff --git a/src/VBox/Disassembler/testcase/tstBinMovzx-1.bin b/src/VBox/Disassembler/testcase/tstBinMovzx-1.bin new file mode 100644 index 00000000..e6db7adf --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstBinMovzx-1.bin @@ -0,0 +1 @@ +·@
\ No newline at end of file diff --git a/src/VBox/Disassembler/testcase/tstDisasm-1.cpp b/src/VBox/Disassembler/testcase/tstDisasm-1.cpp new file mode 100644 index 00000000..015fdf58 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstDisasm-1.cpp @@ -0,0 +1,214 @@ +/* $Id: tstDisasm-1.cpp $ */ +/** @file + * VBox disassembler - Test application + */ + +/* + * Copyright (C) 2006-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/dis.h> +#include <iprt/test.h> +#include <iprt/ctype.h> +#include <iprt/string.h> +#include <iprt/errcore.h> +#include <iprt/time.h> + + +DECLASM(int) TestProc32(void); +DECLASM(int) TestProc32_EndProc(void); +#ifndef RT_OS_OS2 +DECLASM(int) TestProc64(void); +DECLASM(int) TestProc64_EndProc(void); +#endif +//uint8_t aCode16[] = { 0x66, 0x67, 0x89, 0x07 }; + +static void testDisas(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode) +{ + RTTestISub(pszSub); + size_t const cbInstrs = uEndPtr - (uintptr_t)pabInstrs; + for (size_t off = 0; off < cbInstrs;) + { + DISSTATE Dis; + uint32_t cb = 1; +#ifndef DIS_CORE_ONLY + uint32_t const cErrBefore = RTTestIErrorCount(); + char szOutput[256] = {0}; + int rc = DISInstrToStr(&pabInstrs[off], enmDisCpuMode, &Dis, &cb, szOutput, sizeof(szOutput)); + + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); + RTTESTI_CHECK(cb == Dis.cbInstr); + RTTESTI_CHECK(cb > 0); + RTTESTI_CHECK(cb <= 16); + RTStrStripR(szOutput); + RTTESTI_CHECK(szOutput[0]); + if (szOutput[0]) + { + char *pszBytes = strchr(szOutput, '['); + RTTESTI_CHECK(pszBytes); + if (pszBytes) + { + RTTESTI_CHECK(pszBytes[-1] == ' '); + RTTESTI_CHECK(RT_C_IS_XDIGIT(pszBytes[1])); + RTTESTI_CHECK(pszBytes[cb * 3] == ']'); + RTTESTI_CHECK(pszBytes[cb * 3 + 1] == ' '); + + size_t cch = strlen(szOutput); + RTTESTI_CHECK(szOutput[cch - 1] != ','); + } + } + if (cErrBefore != RTTestIErrorCount()) + RTTestIFailureDetails("rc=%Rrc, off=%#x (%u) cbInstr=%u enmDisCpuMode=%d\n", + rc, off, off, Dis.cbInstr, enmDisCpuMode); + RTTestIPrintf(RTTESTLVL_ALWAYS, "%s\n", szOutput); + + /* Check with size-only. */ + uint32_t cbOnly = 1; + DISSTATE DisOnly; + rc = DISInstrWithPrefetchedBytes((uintptr_t)&pabInstrs[off], enmDisCpuMode, 0 /*fFilter - none */, + Dis.abInstr, Dis.cbCachedInstr, NULL, NULL, &DisOnly, &cbOnly); + + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); + RTTESTI_CHECK(cbOnly == DisOnly.cbInstr); + RTTESTI_CHECK_MSG(cbOnly == cb, ("%#x vs %#x\n", cbOnly, cb)); + +#else /* DIS_CORE_ONLY */ + int rc = DISInstr(&pabInstrs[off], enmDisCpuMode, &Dis, &cb); + RTTESTI_CHECK_RC(rc, VINF_SUCCESS); + RTTESTI_CHECK(cb == Dis.cbInstr); +#endif /* DIS_CORE_ONLY */ + + off += cb; + } +} + + +static DECLCALLBACK(int) testReadBytes(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead) +{ + RT_NOREF1(cbMinRead); + memcpy(&pDis->abInstr[offInstr], (void *)((uintptr_t)pDis->uInstrAddr + offInstr), cbMaxRead); + pDis->cbCachedInstr = offInstr + cbMaxRead; + return VINF_SUCCESS; +} + + +static void testPerformance(const char *pszSub, uint8_t const *pabInstrs, uintptr_t uEndPtr, DISCPUMODE enmDisCpuMode) +{ + RTTestISubF("Performance - %s", pszSub); + + size_t const cbInstrs = uEndPtr - (uintptr_t)pabInstrs; + uint64_t cInstrs = 0; + uint64_t nsStart = RTTimeNanoTS(); + for (uint32_t i = 0; i < _512K; i++) /* the samples are way to small. :-) */ + { + for (size_t off = 0; off < cbInstrs; cInstrs++) + { + uint32_t cb = 1; + DISSTATE Dis; + DISInstrWithReader((uintptr_t)&pabInstrs[off], enmDisCpuMode, testReadBytes, NULL, &Dis, &cb); + off += cb; + } + } + uint64_t cNsElapsed = RTTimeNanoTS() - nsStart; + + RTTestIValueF(cNsElapsed, RTTESTUNIT_NS, "%s-Total", pszSub); + RTTestIValueF(cNsElapsed / cInstrs, RTTESTUNIT_NS_PER_CALL, "%s-per-instruction", pszSub); +} + +void testTwo(void) +{ + static const struct + { + DISCPUMODE enmMode; + uint8_t abInstr[24]; + uint8_t cbParam1; + uint8_t cbParam2; + uint8_t cbParam3; + } s_gInstrs[] = + { + { DISCPUMODE_64BIT, { 0x48, 0xc7, 0x03, 0x00, 0x00, 0x00, 0x00, }, 8, 8, 0, }, + }; + for (unsigned i = 0; i < RT_ELEMENTS(s_gInstrs); i++) + { + uint32_t cb = 1; + DISSTATE Dis; + int rc; + RTTESTI_CHECK_RC(rc = DISInstr(s_gInstrs[i].abInstr, s_gInstrs[i].enmMode, &Dis, &cb), VINF_SUCCESS); + if (rc == VINF_SUCCESS) + { + uint32_t cb2; + RTTESTI_CHECK_MSG((cb2 = DISGetParamSize(&Dis, &Dis.Param1)) == s_gInstrs[i].cbParam1, + ("%u: %#x vs %#x\n", i , cb2, s_gInstrs[i].cbParam1)); +#ifndef DIS_CORE_ONLY + RTTESTI_CHECK_MSG((cb2 = DISGetParamSize(&Dis, &Dis.Param2)) == s_gInstrs[i].cbParam2, + ("%u: %#x vs %#x (%s)\n", i , cb2, s_gInstrs[i].cbParam2, Dis.pCurInstr->pszOpcode)); +#else + RTTESTI_CHECK_MSG((cb2 = DISGetParamSize(&Dis, &Dis.Param2)) == s_gInstrs[i].cbParam2, + ("%u: %#x vs %#x\n", i , cb2, s_gInstrs[i].cbParam2)); +#endif + RTTESTI_CHECK_MSG((cb2 = DISGetParamSize(&Dis, &Dis.Param3)) == s_gInstrs[i].cbParam3, + ("%u: %#x vs %#x\n", i , cb2, s_gInstrs[i].cbParam3)); + } + } +} + + +int main(int argc, char **argv) +{ + RT_NOREF2(argc, argv); + RTTEST hTest; + RTEXITCODE rcExit = RTTestInitAndCreate("tstDisasm", &hTest); + if (rcExit) + return rcExit; + RTTestBanner(hTest); + + static const struct + { + const char *pszDesc; + uint8_t const *pbStart; + uintptr_t uEndPtr; + DISCPUMODE enmCpuMode; + } aSnippets[] = + { + { "32-bit", (uint8_t const *)(uintptr_t)TestProc32, (uintptr_t)&TestProc32_EndProc, DISCPUMODE_32BIT }, +#ifndef RT_OS_OS2 + { "64-bit", (uint8_t const *)(uintptr_t)TestProc64, (uintptr_t)&TestProc64_EndProc, DISCPUMODE_64BIT }, +#endif + }; + + for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++) + testDisas(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode); + + testTwo(); + + if (RTTestIErrorCount() == 0) + { + for (unsigned i = 0; i < RT_ELEMENTS(aSnippets); i++) + testPerformance(aSnippets[i].pszDesc, aSnippets[i].pbStart, aSnippets[i].uEndPtr, aSnippets[i].enmCpuMode); + } + + return RTTestSummaryAndDestroy(hTest); +} + diff --git a/src/VBox/Disassembler/testcase/tstDisasm-1A.asm b/src/VBox/Disassembler/testcase/tstDisasm-1A.asm new file mode 100644 index 00000000..112f7037 --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstDisasm-1A.asm @@ -0,0 +1,474 @@ +; $Id: tstDisasm-1A.asm $ +;; @file +; VBox disassembler: Assembler test routines +; + +; +; Copyright (C) 2006-2023 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see <https://www.gnu.org/licenses>. +; +; SPDX-License-Identifier: GPL-3.0-only +; + +;******************************************************************************* +;* Header Files * +;******************************************************************************* +%include "iprt/asmdefs.mac" +;%include "VBox/vmm/vm.mac" +;%include "VBox/err.mac" +;%include "VBox/vmm/stam.mac" +;%include "iprt/x86.mac" + +BITS 32 + +%ifndef __YASM_VERSION_ID__ + %define __YASM_VERSION_ID__ 001010000h ; v1.2.0.0 for OS/2 +%endif +%if __YASM_VERSION_ID__ >= 001020001h ; v1.2.0.1 and greater, make sure to exclude v1.2.0.0. + %define pmulhrwa pmulhrw +%endif + + +BEGINCODE + +align 16 +BEGINPROC TestProc32 + xor eax, eax + mov al, 4 + lea edx, [4] + mov edx, 4 + mov eax, 4 + shl eax, 4 + shl edx, 4 + shr edx, 4 + mov eax, edx + mov eax, ecx + mov edx, eax + mov ecx, eax + DB 0xF0, 0x0F, 0x22, 0xC0 + DB 0xF0, 0x0F, 0x20, 0xC0 + smsw word [edx+16] + ; invept eax, dqword [ecx] + DB 0x66, 0x0F, 0x38, 0x80, 0x1 + ; invept eax, dqword [ecx] + DB 0x66, 0x0F, 0x38, 0x81, 0x1 + mov eax, dword [ecx] + mov word [edi], 0123ah + movzx eax,byte [edx] + movzx eax,word [edx] + mov dword [es:ebx + 1234h], 0789h + mov word [fs:ebx + ecx], 0654h + mov byte [esi + eax*4], 054h + mov bl, byte [ds:ebp + 1234h] + mov al, [cs:1234h + ecx*8] + mov al, [cs:1234h] + mov ax, [cs:1234h] + mov eax, [cs:1234h] + lock cmpxchg [ecx], eax + lock cmpxchg [ecx], ax + lock cmpxchg [ecx], dl + movzx ESI,word [EAX] + in al, dx + in ax, dx + in eax, dx + mov ebx, [ecx + eax*4 + 17] + mov ebx, [ebp + eax*4 + 4] + mov ebx, [ebp + eax*4] + int 80h + in al, 60h + in ax, dx + out 64h, eax + + movss xmm0, xmm1 + movss xmm3, [eax] + movss [eax], xmm4 + movsd xmm6, xmm1 + + pause + nop + + ; 3Dnow! + pavgusb mm1, mm0 + pf2id mm5, mm4 + pf2iw mm6, mm3 + pfacc mm7, mm2 + pfadd mm5, mm4 + pfcmpeq mm6, mm3 + pfcmpge mm2, mm7 + pfcmpgt mm4, mm5 + pfmax mm3, mm6 + pfmin mm1, mm0 + pfmul mm5, mm4 + pmulhrwa mm3, mm6 + pfnacc mm4, mm5 + pfpnacc mm3, mm6 + pfrcp mm0, mm1 + pfrcpit1 mm2, mm7 + pfrcpit2 mm4, mm5 + pfrsqrt mm7, mm2 + pfrsqit1 mm1, mm0 + pfsub mm6, mm3 + pfsubr mm0, mm1 + pi2fd mm7, mm2 + pi2fw mm0, mm1 + pswapd mm2, mm7 + + pavgusb mm1, qword [es:eax+000000010h] + pf2id mm5, qword [ds:esi+000101010h] + pf2iw mm6, qword [fs:esi+000101010h] + pfacc mm7, qword [gs:esi+000101010h] + pfadd mm5, qword [ esi+000101010h] + pfcmpeq mm6, qword [ edi*8+000101010h] + pfcmpge mm2, qword [es:esi+000100010h] + pfcmpgt mm4, qword [es:esi+000101010h] + pfmax mm3, qword [es:esi+000101010h] + pfmin mm1, qword [es:esi+000101010h] + pfmul mm5, qword [es:esi+000101000h] +%ifndef RT_OS_OS2 ; nasm objects to this + pmulhrwa mm3, qword [es:eax+0ffffffffh] +%endif + pfnacc mm4, qword [es:ebx+000101010h] + pfpnacc mm3, qword [es:edx+000102900h] + pfrcp mm0, qword [es:ecx+000101020h] + pfrcpit1 mm2, qword [es:ebp+000101510h] + pfrcpit2 mm4, qword [es:esp+000101310h] + pfrsqrt mm7, qword [es:esi+0f0106010h] + pfrsqit1 mm1, qword [es:edi+0001f1010h] + pfsub mm6, qword [es:esi*2] + pfsubr mm0, qword [es:esi*3] + pi2fd mm7, qword [es:esi*4] + pi2fw mm0, qword [es:esi*5] + pswapd mm2, qword [es:esi*8] + + pmulhrwa mm0, qword [ds:ebp+edi*8+00f000001h] + + ; MMX + psubusb mm1, mm3 + cvtpi2pd xmm0, mm3 + paddd mm1, mm3 + paddd xmm1, xmm3 + +%if __YASM_VERSION_ID__ >= 001030000h ; Old yasm doesn't support the instructions below + adcx eax, ebx + adcx eax, [edi] + + adox eax, ebx + adox eax, [edi] + adox eax, [edi + 1000h] + + tzcnt ax, bx + tzcnt eax, ebx + tzcnt ax, [edi] + tzcnt eax, [edi] + tzcnt eax, [edi + 1000h] + vpmovsxbw ymm0, xmm1 + vpmovzxbq ymm1, [100h] + vgatherqps xmm0,dword [eax+xmm0*2],xmm0 + vgatherqpd xmm0,qword [eax+xmm0*2],xmm0 +%endif + + movbe eax, [edi] + movbe ebx, [edi + 1000h] + movbe ax, [edi] + movbe [edi], eax + + crc32 eax, bl + crc32 eax, bx + crc32 eax, ebx + crc32 eax, byte [edi] + crc32 eax, word [edi] + crc32 eax, dword [edi] + + popcnt ax, bx + popcnt eax, ebx + popcnt ax, [edi] + popcnt eax, [edi] + popcnt eax, [edi + 1000h] + + lzcnt ax, bx + lzcnt eax, ebx + lzcnt ax, [edi] + lzcnt eax, [edi] + lzcnt eax, [edi + 1000h] + + vmread eax, ebx + vmwrite eax, ebx + + movd mm0, [edi] + movq mm0, [edi] + movq mm0, mm1 + + vmovups xmm0, xmm1 + vmovaps ymm0, ymm1 + vunpcklps xmm0, xmm1, xmm2 + vunpcklps ymm0, ymm1, ymm2 + + lddqu xmm1, [ds:ebp+edi*8+00f000001h] + vlddqu xmm1, [ds:ebp+edi*8+00f000001h] + vlddqu ymm1, [ds:ebp+edi*8+00f000001h] + + vpmovsxbw xmm0,qword [0x100] + vbroadcastf128 ymm0,oword [0x100] + + palignr mm0, mm1, 1 + vpinsrb xmm0, xmm1, eax, 1 + vpinsrb xmm0, xmm1, [100h], 1 + vinsertps xmm0, xmm1, xmm2, 1 + vinsertps xmm0, xmm1, [100h], 1 + + vblendvps xmm0, xmm1, xmm2, xmm3 + vblendvps ymm0, ymm1, ymm2, ymm3 + + aesimc xmm0, xmm1 + + pmovzxbq xmm0, xmm1 + pmovzxbq xmm1, [100h] + + vfmaddsub132pd ymm1, ymm2, ymm3 + +%ifndef RT_OS_OS2 + blsr eax, ebx + blsi eax, [ebx] +%endif + db 0c4h, 0e2h, 0f8h, 0f3h, 01bh ; blsi rax, dword [ebx] - but VEX.W=1 is ignored, so same as previous +%ifndef RT_OS_OS2 + blsmsk eax, [ebx+edi*2] + shlx eax, ebx, ecx +%endif + + pmovmskb eax, mm2 + pmovmskb eax, xmm3 + vpmovmskb eax, xmm3 +%ifndef RT_OS_OS2 + vpmovmskb eax, ymm3 +%endif + +ENDPROC TestProc32 + + +%ifndef RT_OS_OS2 +BITS 64 +align 16 +BEGINPROC TestProc64 + mov cr8, rax + mov cr8, rbx + mov [0xfffe0080], rax + mov [0xfffe0080], rbx + mov rax, cr8 + mov rbx, cr8 + mov rax, [0xfffe0080] + mov rbx, [0xfffe0080] + divsd xmm1, xmm0 + ; invept rdi, dqword [rsi] + DB 0x66, 0x0F, 0x38, 0x80, 0x3E + ; invept rcx, dqword [rdx] + DB 0x66, 0x0F, 0x38, 0x80, 0xA + ;invvpid rdi, dqword [rsi] + DB 0x66, 0x0F, 0x38, 0x81, 0x3E + ; invvpid rcx, dqword [rdx] + DB 0x66, 0x0F, 0x38, 0x81, 0xA + mov rdi, [rsi] + mov rcx, [rdx] + db 48h + db 0c7h + db 42h + db 18h + db 20h + db 3eh + db 23h + db 80h + call qword [r8+10h] + ; test + db 48h + db 8bh + db 44h + db 0ah + db 0f8h + ;incorrectly assembled by yasm; REX.W should not be added! + ;test rax, dword 0cc90cc90h + db 8bh + db 04h + db 8dh + db 00h + db 00h + db 0feh + db 0ffh + mov qword [rcx+rdx], 0 + mov dword [rcx+rdx], 0 + and [r15], rax + movzx rcx, sil + and sil, 3 + movzx ecx, ah + and ah, 3 + + sub rcx, 1234h + mov rax, qword [0cc90cc90h] + mov rax, qword [00c90cc90h] + mov rax, dword 0cc90cc90h + mov rax, qword 0ffffcc90cc90h + + movzx rax,byte [edx] + movzx rax,word [edx] + movzx rax,byte [rdx] + lock cmpxchg [rcx], rax + lock cmpxchg [rcx], ax + lock cmpxchg [r15], dl + movzx RSI, word [R8] + in al, dx + in ax, dx + in eax, dx + mov rbx, [rcx + rax*4 + 17] + mov rbx, [rbp + rax*4 + 4] + mov rbx, [rbp + rax*4] + mov rbx, [ebp + eax*4] + int 80h + in al, 60h + in ax, dx + out 64h, eax + + movss xmm0, xmm14 + movsd xmm6, xmm1 + + movbe eax, [rdi] + movbe ax, [rdi] + movbe rax, [rdi] + + crc32 eax, bl + crc32 eax, bx + crc32 eax, ebx + crc32 eax, byte [edi] + crc32 eax, word [edi] + crc32 eax, dword [edi] + + crc32 rax, bl + crc32 rax, byte [rdi] + crc32 rax, qword [rdi] + +%if __YASM_VERSION_ID__ >= 001030000h ; Old yasm doesn't support the instructions below + + adcx eax, ebx + adcx rax, rbx + adcx r8, r11 + adcx r8d, edx + + adox eax, ebx + adox eax, [edi] + adox eax, [edi + 1000h] + + adox rax, rbx + adox rax, [rdi] + adox rax, [rdi + 1000h] + adox rax, [edi + 1000h] + + tzcnt ax, bx + tzcnt eax, ebx + tzcnt rax, rbx + tzcnt ax, [edi] + tzcnt eax, [edi] + tzcnt eax, [edi + 1000h] + + vpunpcklbw ymm1, ymm2, ymm3 + vpmovsxbw ymm4,[0x100] + vgatherqpd xmm0,qword [rbx+xmm11*2],xmm2 +%endif + + popcnt ax, bx + popcnt eax, ebx + popcnt rax, rbx + popcnt ax, [edi] + popcnt eax, [edi] + popcnt eax, [edi + 1000h] + popcnt rax, [rdi + 1000h] + + lzcnt ax, bx + lzcnt eax, ebx + lzcnt rax, rbx + lzcnt ax, [edi] + lzcnt eax, [edi] + lzcnt eax, [edi + 1000h] + lzcnt eax, [rdi] + lzcnt ax, [rdi] + lzcnt rax, [rdi] + lzcnt r8d, [rdi] + + vmread rax, rbx + vmwrite rax, rbx + + getsec + + movd mm0, [rdi] + movq mm0, [edi] + movq mm0, mm1 + + vmovups xmm0, xmm1 + vmovaps ymm0, ymm1 + vunpcklps xmm0, xmm1, xmm2 + vunpcklps ymm0, ymm1, ymm2 + vunpcklps ymm0, ymm10, ymm2 + + vmovups xmm5, xmm9 + + vcmpps xmm1, xmm2, xmm3, 12 + + lddqu xmm1, [ebp+edi*8+00f000001h] + vlddqu xmm1, [rbp+rdi*8+00f000001h] + vlddqu ymm1, [rbp+rdi*8+00f000001h] + + vbroadcastf128 ymm0,oword [0x100] + vmovlps xmm0, xmm1, [100h] + vmovlps xmm0, xmm1, [eax + ebx] + vmovlps xmm0, xmm1, [rax + rbx] + vmovlps xmm10, xmm1, [rax] + + vblendvpd xmm0, xmm1, [100h], xmm3 + + dpps xmm0, xmm1, 1 + + extractps eax, xmm2, 3 + vzeroupper + vzeroall + + movlps xmm0, [100h] + movlps xmm0, [eax + ebx] + movlps xmm10, [rax + rbx] + movhlps xmm0, xmm1 + + blsr eax, ebx + blsr rax, rbx + blsi eax, [rbx] + blsi rax, [rbx] + db 0c4h, 0e2h, 0f8h | 4, 0f3h, 01bh ; blsi rax, [rbx] with VEX.L=1 - should be invalid + blsmsk eax, [rbx+rdi*2] + blsmsk rax, [rbx+rdi*2] + blsmsk r8, [rbx+rdi*2] + + shlx eax, ebx, ecx + shlx r8, rax, r15 + + pmovmskb eax, mm2 + pmovmskb r9, mm2 + pmovmskb eax, xmm3 + pmovmskb r10, xmm3 + vpmovmskb eax, xmm3 + vpmovmskb rax, xmm3 + vpmovmskb r11, ymm9 + + ret +ENDPROC TestProc64 +%endif ; !OS2 + diff --git a/src/VBox/Disassembler/testcase/tstDisasm-2.cpp b/src/VBox/Disassembler/testcase/tstDisasm-2.cpp new file mode 100644 index 00000000..27ffc33b --- /dev/null +++ b/src/VBox/Disassembler/testcase/tstDisasm-2.cpp @@ -0,0 +1,693 @@ +/* $Id: tstDisasm-2.cpp $ */ +/** @file + * Testcase - Generic Disassembler Tool. + */ + +/* + * Copyright (C) 2008-2023 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see <https://www.gnu.org/licenses>. + * + * SPDX-License-Identifier: GPL-3.0-only + */ + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include <VBox/dis.h> +#include <VBox/err.h> +#include <iprt/alloc.h> +#include <iprt/assert.h> +#include <iprt/initterm.h> +#include <iprt/getopt.h> +#include <iprt/file.h> +#include <iprt/path.h> +#include <iprt/stream.h> +#include <iprt/string.h> +#include <iprt/ctype.h> + + +/********************************************************************************************************************************* +* Structures and Typedefs * +*********************************************************************************************************************************/ +typedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_gas, kAsmStyle_invalid } ASMSTYLE; +typedef enum { kUndefOp_Fail, kUndefOp_All, kUndefOp_DefineByte, kUndefOp_End } UNDEFOPHANDLING; + +typedef struct MYDISSTATE +{ + DISSTATE Dis; + uint64_t uAddress; /**< The current instruction address. */ + uint8_t *pbInstr; /**< The current instruction (pointer). */ + uint32_t cbInstr; /**< The size of the current instruction. */ + bool fUndefOp; /**< Whether the current instruction is really an undefined opcode.*/ + UNDEFOPHANDLING enmUndefOp; /**< How to treat undefined opcodes. */ + int rc; /**< Set if we hit EOF. */ + size_t cbLeft; /**< The number of bytes left. (read) */ + uint8_t *pbNext; /**< The next byte. (read) */ + uint64_t uNextAddr; /**< The address of the next byte. (read) */ + char szLine[256]; /**< The disassembler text output. */ +} MYDISSTATE; +typedef MYDISSTATE *PMYDISSTATE; + + + +/** + * Default style. + * + * @param pState The disassembler state. + */ +static void MyDisasDefaultFormatter(PMYDISSTATE pState) +{ + RTPrintf("%s", pState->szLine); +} + + +/** + * Yasm style. + * + * @param pState The disassembler state. + */ +static void MyDisasYasmFormatter(PMYDISSTATE pState) +{ + char szTmp[256]; +#if 0 + /* a very quick hack. */ + strcpy(szTmp, RTStrStripL(strchr(pState->szLine, ':') + 1)); + + char *psz = strrchr(szTmp, '['); + *psz = '\0'; + RTStrStripR(szTmp); + + psz = strstr(szTmp, " ptr "); + if (psz) + memset(psz, ' ', 5); + + char *pszEnd = strchr(szTmp, '\0'); + while (pszEnd - &szTmp[0] < 71) + *pszEnd++ = ' '; + *pszEnd = '\0'; + +#else + size_t cch = DISFormatYasmEx(&pState->Dis, szTmp, sizeof(szTmp), + DIS_FMT_FLAGS_STRICT | DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_COMMENT + | DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_SPACED, + NULL, NULL); + Assert(cch < sizeof(szTmp)); + while (cch < 71) + szTmp[cch++] = ' '; + szTmp[cch] = '\0'; +#endif + + RTPrintf(" %s ; %s", szTmp, pState->szLine); +} + + +/** + * Masm style. + * + * @param pState The disassembler state. + */ +static void MyDisasMasmFormatter(PMYDISSTATE pState) +{ + RTPrintf("masm not implemented: %s", pState->szLine); +} + + +/** + * This is a temporary workaround for catching a few illegal opcodes + * that the disassembler is currently letting thru, just enough to make + * the assemblers happy. + * + * We're too close to a release to dare mess with these things now as + * they may consequences for performance and let alone introduce bugs. + * + * @returns true if it's valid. false if it isn't. + * + * @param pDis The disassembler output. + */ +static bool MyDisasIsValidInstruction(DISSTATE const *pDis) +{ + switch (pDis->pCurInstr->uOpcode) + { + /* These doesn't take memory operands. */ + case OP_MOV_CR: + case OP_MOV_DR: + case OP_MOV_TR: + if (pDis->ModRM.Bits.Mod != 3) + return false; + break; + + /* The 0x8f /0 variant of this instruction doesn't get its /r value verified. */ + case OP_POP: + if ( pDis->bOpCode == 0x8f + && pDis->ModRM.Bits.Reg != 0) + return false; + break; + + /* The 0xc6 /0 and 0xc7 /0 variants of this instruction don't get their /r values verified. */ + case OP_MOV: + if ( ( pDis->bOpCode == 0xc6 + || pDis->bOpCode == 0xc7) + && pDis->ModRM.Bits.Reg != 0) + return false; + break; + + default: + break; + } + + return true; +} + + +/** + * @interface_method_impl{FNDISREADBYTES} + */ +static DECLCALLBACK(int) MyDisasInstrRead(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead) +{ + RT_NOREF1(cbMaxRead); + PMYDISSTATE pState = (PMYDISSTATE)pDis; + RTUINTPTR uSrcAddr = pState->Dis.uInstrAddr + offInstr; + if (RT_LIKELY( pState->uNextAddr == uSrcAddr + && pState->cbLeft >= cbMinRead)) + { + /* + * Straight forward reading. + */ + //size_t cbToRead = cbMaxRead; + size_t cbToRead = cbMinRead; + memcpy(&pState->Dis.abInstr[offInstr], pState->pbNext, cbToRead); + pState->Dis.cbCachedInstr = offInstr + (uint8_t)cbToRead; + pState->pbNext += cbToRead; + pState->cbLeft -= cbToRead; + pState->uNextAddr += cbToRead; + return VINF_SUCCESS; + } + + if (pState->uNextAddr == uSrcAddr) + { + /* + * Reading too much. + */ + if (pState->cbLeft > 0) + { + memcpy(&pState->Dis.abInstr[offInstr], pState->pbNext, pState->cbLeft); + offInstr += (uint8_t)pState->cbLeft; + cbMinRead -= (uint8_t)pState->cbLeft; + pState->pbNext += pState->cbLeft; + pState->uNextAddr += pState->cbLeft; + pState->cbLeft = 0; + } + memset(&pState->Dis.abInstr[offInstr], 0xcc, cbMinRead); + pState->rc = VERR_EOF; + } + else + { + /* + * Non-sequential read, that's an error. + */ + RTStrmPrintf(g_pStdErr, "Reading before current instruction!\n"); + memset(&pState->Dis.abInstr[offInstr], 0x90, cbMinRead); + pState->rc = VERR_INTERNAL_ERROR; + } + pState->Dis.cbCachedInstr = offInstr + cbMinRead; + return pState->rc; +} + + +/** + * Disassembles a block of memory. + * + * @returns VBox status code. + * @param argv0 Program name (for errors and warnings). + * @param enmCpuMode The cpu mode to disassemble in. + * @param uAddress The address we're starting to disassemble at. + * @param uHighlightAddr The address of the instruction that should be + * highlighted. Pass UINT64_MAX to keep quiet. + * @param pbFile Where to start disassemble. + * @param cbFile How much to disassemble. + * @param enmStyle The assembly output style. + * @param fListing Whether to print in a listing like mode. + * @param enmUndefOp How to deal with undefined opcodes. + */ +static int MyDisasmBlock(const char *argv0, DISCPUMODE enmCpuMode, uint64_t uAddress, + uint64_t uHighlightAddr, uint8_t *pbFile, size_t cbFile, + ASMSTYLE enmStyle, bool fListing, UNDEFOPHANDLING enmUndefOp) +{ + RT_NOREF1(fListing); + + /* + * Initialize the CPU context. + */ + MYDISSTATE State; + State.uAddress = uAddress; + State.pbInstr = pbFile; + State.cbInstr = 0; + State.enmUndefOp = enmUndefOp; + State.rc = VINF_SUCCESS; + State.cbLeft = cbFile; + State.pbNext = pbFile; + State.uNextAddr = uAddress; + + void (*pfnFormatter)(PMYDISSTATE pState); + switch (enmStyle) + { + case kAsmStyle_Default: + pfnFormatter = MyDisasDefaultFormatter; + break; + + case kAsmStyle_yasm: + RTPrintf(" BITS %d\n", enmCpuMode == DISCPUMODE_16BIT ? 16 : enmCpuMode == DISCPUMODE_32BIT ? 32 : 64); + pfnFormatter = MyDisasYasmFormatter; + break; + + case kAsmStyle_masm: + pfnFormatter = MyDisasMasmFormatter; + break; + + default: + AssertFailedReturn(VERR_INTERNAL_ERROR); + } + + /* + * The loop. + */ + int rcRet = VINF_SUCCESS; + while (State.cbLeft > 0) + { + /* + * Disassemble it. + */ + State.cbInstr = 0; + State.cbLeft += State.pbNext - State.pbInstr; + State.uNextAddr = State.uAddress; + State.pbNext = State.pbInstr; + + int rc = DISInstrToStrWithReader(State.uAddress, enmCpuMode, MyDisasInstrRead, &State, + &State.Dis, &State.cbInstr, State.szLine, sizeof(State.szLine)); + if ( RT_SUCCESS(rc) + || ( ( rc == VERR_DIS_INVALID_OPCODE + || rc == VERR_DIS_GEN_FAILURE) + && State.enmUndefOp == kUndefOp_DefineByte)) + { + State.fUndefOp = rc == VERR_DIS_INVALID_OPCODE + || rc == VERR_DIS_GEN_FAILURE + || State.Dis.pCurInstr->uOpcode == OP_INVALID + || State.Dis.pCurInstr->uOpcode == OP_ILLUD2 + || ( State.enmUndefOp == kUndefOp_DefineByte + && !MyDisasIsValidInstruction(&State.Dis)); + if (State.fUndefOp && State.enmUndefOp == kUndefOp_DefineByte) + { + if (!State.cbInstr) + { + State.Dis.abInstr[0] = 0; + State.Dis.pfnReadBytes(&State.Dis, 0, 1, 1); + State.cbInstr = 1; + } + RTPrintf(" db"); + for (unsigned off = 0; off < State.cbInstr; off++) + RTPrintf(off ? ", %03xh" : " %03xh", State.Dis.abInstr[off]); + RTPrintf(" ; %s\n", State.szLine); + } + else if (!State.fUndefOp && State.enmUndefOp == kUndefOp_All) + { + RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Dis.pCurInstr->uOpcode); + pfnFormatter(&State); + rcRet = VERR_GENERAL_FAILURE; + } + else if (State.fUndefOp && State.enmUndefOp == kUndefOp_Fail) + { + RTPrintf("%s: error at %#RX64: undefined opcode (op=%d)\n", argv0, State.uAddress, State.Dis.pCurInstr->uOpcode); + pfnFormatter(&State); + rcRet = VERR_GENERAL_FAILURE; + } + else + { + /* Use db for odd encodings that we can't make the assembler use. */ + if ( State.enmUndefOp == kUndefOp_DefineByte + && DISFormatYasmIsOddEncoding(&State.Dis)) + { + RTPrintf(" db"); + for (unsigned off = 0; off < State.cbInstr; off++) + RTPrintf(off ? ", %03xh" : " %03xh", State.Dis.abInstr[off]); + RTPrintf(" ; "); + } + + pfnFormatter(&State); + } + } + else + { + State.cbInstr = State.pbNext - State.pbInstr; + if (!State.cbLeft) + RTPrintf("%s: error at %#RX64: read beyond the end (%Rrc)\n", argv0, State.uAddress, rc); + else if (State.cbInstr) + RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d\n", argv0, State.uAddress, rc, State.cbInstr); + else + { + RTPrintf("%s: error at %#RX64: %Rrc cbInstr=%d!\n", argv0, State.uAddress, rc, State.cbInstr); + if (rcRet == VINF_SUCCESS) + rcRet = rc; + break; + } + } + + /* Highlight this instruction? */ + if (uHighlightAddr - State.uAddress < State.cbInstr) + RTPrintf("; ^^^^^^^^^^^^^^^^^^^^^\n"); + + /* Check that the size-only mode returns the smae size on success. */ + if (RT_SUCCESS(rc)) + { + uint32_t cbInstrOnly = 32; + uint8_t abInstr[sizeof(State.Dis.abInstr)]; + memcpy(abInstr, State.Dis.abInstr, sizeof(State.Dis.abInstr)); + int rcOnly = DISInstrWithPrefetchedBytes(State.uAddress, enmCpuMode, 0 /*fFilter - none */, + abInstr, State.Dis.cbCachedInstr, MyDisasInstrRead, &State, + &State.Dis, &cbInstrOnly); + if ( rcOnly != rc + || cbInstrOnly != State.cbInstr) + { + RTPrintf("; Instruction size only check failed rc=%Rrc cbInstrOnly=%#x exepcted %Rrc and %#x\n", + rcOnly, cbInstrOnly, rc, State.cbInstr); + rcRet = VERR_GENERAL_FAILURE; + break; + } + } + + /* next */ + State.uAddress += State.cbInstr; + State.pbInstr += State.cbInstr; + } + + return rcRet; +} + +/** + * Converts a hex char to a number. + * + * @returns 0..15 on success, -1 on failure. + * @param ch The character. + */ +static int HexDigitToNum(char ch) +{ + switch (ch) + { + case '0': return 0; + case '1': return 1; + case '2': return 2; + case '3': return 3; + case '4': return 4; + case '5': return 5; + case '6': return 6; + case '7': return 7; + case '8': return 8; + case '9': return 9; + case 'A': + case 'a': return 0xa; + case 'B': + case 'b': return 0xb; + case 'C': + case 'c': return 0xc; + case 'D': + case 'd': return 0xd; + case 'E': + case 'e': return 0xe; + case 'F': + case 'f': return 0xf; + default: + RTPrintf("error: Invalid hex digit '%c'\n", ch); + return -1; + } +} + +/** + * Prints usage info. + * + * @returns 1. + * @param argv0 The program name. + */ +static int Usage(const char *argv0) +{ + RTStrmPrintf(g_pStdErr, +"usage: %s [options] <file1> [file2..fileN]\n" +" or: %s [options] <-x|--hex-bytes> <hex byte> [more hex..]\n" +" or: %s <--help|-h>\n" +"\n" +"Options:\n" +" --address|-a <address>\n" +" The base address. Default: 0\n" +" --max-bytes|-b <bytes>\n" +" The maximum number of bytes to disassemble. Default: 1GB\n" +" --cpumode|-c <16|32|64>\n" +" The cpu mode. Default: 32\n" +" --listing|-l, --no-listing|-L\n" +" Enables or disables listing mode. Default: --no-listing\n" +" --offset|-o <offset>\n" +" The file offset at which to start disassembling. Default: 0\n" +" --style|-s <default|yasm|masm>\n" +" The assembly output style. Default: default\n" +" --undef-op|-u <fail|all|db>\n" +" How to treat undefined opcodes. Default: fail\n" + , argv0, argv0, argv0); + return 1; +} + + +int main(int argc, char **argv) +{ + RTR3InitExe(argc, &argv, 0); + const char * const argv0 = RTPathFilename(argv[0]); + + /* options */ + uint64_t uAddress = 0; + uint64_t uHighlightAddr = UINT64_MAX; + ASMSTYLE enmStyle = kAsmStyle_Default; + UNDEFOPHANDLING enmUndefOp = kUndefOp_Fail; + bool fListing = true; + DISCPUMODE enmCpuMode = DISCPUMODE_32BIT; + RTFOFF off = 0; + RTFOFF cbMax = _1G; + bool fHexBytes = false; + + /* + * Parse arguments. + */ + static const RTGETOPTDEF g_aOptions[] = + { + { "--address", 'a', RTGETOPT_REQ_UINT64 }, + { "--cpumode", 'c', RTGETOPT_REQ_UINT32 }, + { "--bytes", 'b', RTGETOPT_REQ_INT64 }, + { "--listing", 'l', RTGETOPT_REQ_NOTHING }, + { "--no-listing", 'L', RTGETOPT_REQ_NOTHING }, + { "--offset", 'o', RTGETOPT_REQ_INT64 }, + { "--style", 's', RTGETOPT_REQ_STRING }, + { "--undef-op", 'u', RTGETOPT_REQ_STRING }, + { "--hex-bytes", 'x', RTGETOPT_REQ_NOTHING }, + }; + + int ch; + RTGETOPTUNION ValueUnion; + RTGETOPTSTATE GetState; + RTGetOptInit(&GetState, argc, argv, g_aOptions, RT_ELEMENTS(g_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST); + while ( (ch = RTGetOpt(&GetState, &ValueUnion)) + && ch != VINF_GETOPT_NOT_OPTION) + { + switch (ch) + { + case 'a': + uAddress = ValueUnion.u64; + break; + + case 'b': + cbMax = ValueUnion.i64; + break; + + case 'c': + if (ValueUnion.u32 == 16) + enmCpuMode = DISCPUMODE_16BIT; + else if (ValueUnion.u32 == 32) + enmCpuMode = DISCPUMODE_32BIT; + else if (ValueUnion.u32 == 64) + enmCpuMode = DISCPUMODE_64BIT; + else + { + RTStrmPrintf(g_pStdErr, "%s: Invalid CPU mode value %RU32\n", argv0, ValueUnion.u32); + return 1; + } + break; + + case 'h': + return Usage(argv0); + + case 'l': + fListing = true; + break; + + case 'L': + fListing = false; + break; + + case 'o': + off = ValueUnion.i64; + break; + + case 's': + if (!strcmp(ValueUnion.psz, "default")) + enmStyle = kAsmStyle_Default; + else if (!strcmp(ValueUnion.psz, "yasm")) + enmStyle = kAsmStyle_yasm; + else if (!strcmp(ValueUnion.psz, "masm")) + { + enmStyle = kAsmStyle_masm; + RTStrmPrintf(g_pStdErr, "%s: masm style isn't implemented yet\n", argv0); + return 1; + } + else + { + RTStrmPrintf(g_pStdErr, "%s: unknown assembly style: %s\n", argv0, ValueUnion.psz); + return 1; + } + break; + + case 'u': + if (!strcmp(ValueUnion.psz, "fail")) + enmUndefOp = kUndefOp_Fail; + else if (!strcmp(ValueUnion.psz, "all")) + enmUndefOp = kUndefOp_All; + else if (!strcmp(ValueUnion.psz, "db")) + enmUndefOp = kUndefOp_DefineByte; + else + { + RTStrmPrintf(g_pStdErr, "%s: unknown undefined opcode handling method: %s\n", argv0, ValueUnion.psz); + return 1; + } + break; + + case 'x': + fHexBytes = true; + break; + + case 'V': + RTPrintf("$Revision: 155244 $\n"); + return 0; + + default: + return RTGetOptPrintError(ch, &ValueUnion); + } + } + int iArg = GetState.iNext - 1; /** @todo Not pretty, add RTGetOptInit flag for this. */ + if (iArg >= argc) + return Usage(argv0); + + int rc = VINF_SUCCESS; + if (fHexBytes) + { + /* + * Convert the remaining arguments from a hex byte string into + * a buffer that we disassemble. + */ + size_t cb = 0; + uint8_t *pb = NULL; + for ( ; iArg < argc; iArg++) + { + char ch2; + const char *psz = argv[iArg]; + while (*psz) + { + /** @todo this stuff belongs in IPRT, same stuff as mac address reading. Could be reused for IPv6 with a different item size.*/ + /* skip white space, and for the benefit of linux panics '<' and '>'. */ + while (RT_C_IS_SPACE(ch2 = *psz) || ch2 == '<' || ch2 == '>' || ch2 == ',' || ch2 == ';') + { + if (ch2 == '<') + uHighlightAddr = uAddress + cb; + psz++; + } + + if (ch2 == '0' && (psz[1] == 'x' || psz[1] == 'X')) + { + psz += 2; + ch2 = *psz; + } + + if (!ch2) + break; + + /* one digit followed by a space or EOS, or two digits. */ + int iNum = HexDigitToNum(*psz++); + if (iNum == -1) + return 1; + if (!RT_C_IS_SPACE(ch2 = *psz) && ch2 != '\0' && ch2 != '>' && ch2 != ',' && ch2 != ';') + { + int iDigit = HexDigitToNum(*psz++); + if (iDigit == -1) + return 1; + iNum = iNum * 16 + iDigit; + } + + /* add the byte */ + if (!(cb % 4 /*64*/)) + { + pb = (uint8_t *)RTMemRealloc(pb, cb + 64); + if (!pb) + { + RTPrintf("%s: error: RTMemRealloc failed\n", argv[0]); + return 1; + } + } + pb[cb++] = (uint8_t)iNum; + } + } + + /* + * Disassemble it. + */ + rc = MyDisasmBlock(argv0, enmCpuMode, uAddress, uHighlightAddr, pb, cb, enmStyle, fListing, enmUndefOp); + } + else + { + /* + * Process the files. + */ + for ( ; iArg < argc; iArg++) + { + /* + * Read the file into memory. + */ + void *pvFile; + size_t cbFile; + rc = RTFileReadAllEx(argv[iArg], off, cbMax, RTFILE_RDALL_O_DENY_NONE, &pvFile, &cbFile); + if (RT_FAILURE(rc)) + { + RTStrmPrintf(g_pStdErr, "%s: %s: %Rrc\n", argv0, argv[iArg], rc); + break; + } + + /* + * Disassemble it. + */ + rc = MyDisasmBlock(argv0, enmCpuMode, uAddress, uHighlightAddr, (uint8_t *)pvFile, cbFile, enmStyle, fListing, enmUndefOp); + RTFileReadAllFree(pvFile, cbFile); + if (RT_FAILURE(rc)) + break; + } + } + + return RT_SUCCESS(rc) ? 0 : 1; +} + |