DisasmFormatYasm.cpp revision 1a5d2d9ef8cf8eeec5649664cf88c7fd55c968d2
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * VBox Disassembler - Yasm(/Nasm) Style Formatter.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2008-2012 Oracle Corporation
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * available from http://www.virtualbox.org. This file is free software;
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * you can redistribute it and/or modify it under the terms of the GNU
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * General Public License (GPL) as published by the Free Software
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
6ec4e1827eab6a424d672ef0e5a17b065e52db20vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Header Files *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync/*******************************************************************************
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync* Global Variables *
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync*******************************************************************************/
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsyncstatic const char g_szSpaces[] =
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "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"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "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"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "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"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8\0", "r9\0", "r10", "r11", "r12", "r13", "r14", "r15"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync "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"
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync "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"
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync "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"
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync "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"
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * Gets the base register name for the given parameter.
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * @returns Pointer to the register name.
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * @param pCpu The disassembler cpu state.
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * @param pParam The parameter.
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * @param pcchReg Where to store the length of the name.
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsyncstatic const char *disasmFormatYasmBaseReg(PCDISCPUSTATE pCpu, PCDISOPPARAM pParam, size_t *pcchReg)
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync switch (pParam->fUse & ( DISUSE_REG_GEN8 | DISUSE_REG_GEN16 | DISUSE_REG_GEN32 | DISUSE_REG_GEN64
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync | DISUSE_REG_FP | DISUSE_REG_MMX | DISUSE_REG_XMM | DISUSE_REG_CR
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync | DISUSE_REG_DBG | DISUSE_REG_SEG | DISUSE_REG_TEST))
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen8));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegGen8[pParam->Base.idxGenReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen16));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegGen16[pParam->Base.idxGenReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen32));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegGen32[pParam->Base.idxGenReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen64));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegGen64[pParam->Base.idxGenReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxFpuReg < RT_ELEMENTS(g_aszYasmRegFP));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegFP[pParam->Base.idxFpuReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxMmxReg < RT_ELEMENTS(g_aszYasmRegMMX));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegMMX[pParam->Base.idxMmxReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxXmmReg < RT_ELEMENTS(g_aszYasmRegXMM));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegXMM[pParam->Base.idxMmxReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxCtrlReg < RT_ELEMENTS(g_aszYasmRegCRx));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegCRx[pParam->Base.idxCtrlReg];
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync Assert(pParam->Base.idxDbgReg < RT_ELEMENTS(g_aszYasmRegDRx));
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync const char *psz = g_aszYasmRegDRx[pParam->Base.idxDbgReg];
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pParam->Base.idxSegReg < RT_ELEMENTS(g_aszYasmRegCRx));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync const char *psz = g_aszYasmRegSeg[pParam->Base.idxSegReg];
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pParam->Base.idxTestReg < RT_ELEMENTS(g_aszYasmRegTRx));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync const char *psz = g_aszYasmRegTRx[pParam->Base.idxTestReg];
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync return "r??";
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * Gets the index register name for the given parameter.
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync * @returns The index register name.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pCpu The disassembler cpu state.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pParam The parameter.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pcchReg Where to store the length of the name.
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsyncstatic const char *disasmFormatYasmIndexReg(PCDISCPUSTATE pCpu, PCDISOPPARAM pParam, size_t *pcchReg)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen16));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync const char *psz = g_aszYasmRegGen16[pParam->Index.idxGenReg];
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen32));
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync const char *psz = g_aszYasmRegGen32[pParam->Index.idxGenReg];
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync Assert(pParam->Index.idxGenReg < RT_ELEMENTS(g_aszYasmRegGen64));
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync const char *psz = g_aszYasmRegGen64[pParam->Index.idxGenReg];
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync AssertMsgFailed(("%#x %#x\n", pParam->fUse, pCpu->uAddrMode));
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync return "r??";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Formats the current instruction in Yasm (/ Nasm) style.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @returns The number of output characters. If this is >= cchBuf, then the content
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * of pszBuf will be truncated.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pCpu Pointer to the disassembler CPU state.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pszBuf The output buffer.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param cchBuf The size of the output buffer.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * @param pvUser User argument for pfnGetSymbol.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsyncDISDECL(size_t) DISFormatYasmEx(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags,
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Input validation and massaging.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Output macros
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync } while (0)
7119da12ccdef5319114169b35259e542806c62cvboxsync } while (0)
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0)
7119da12ccdef5319114169b35259e542806c62cvboxsync do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \
7119da12ccdef5319114169b35259e542806c62cvboxsync } while (0)
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync/** @todo add two flags for choosing between %X / %x and h / 0x. */
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync#define PUT_NUM_8(num) PUT_NUM(4, "0%02xh", (uint8_t)(num))
7119da12ccdef5319114169b35259e542806c62cvboxsync#define PUT_NUM_16(num) PUT_NUM(6, "0%04xh", (uint16_t)(num))
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync#define PUT_NUM_32(num) PUT_NUM(10, "0%08xh", (uint32_t)(num))
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync#define PUT_NUM_64(num) PUT_NUM(18, "0%016RX64h", (uint64_t)(num))
aaed284a3d84d1fa100786d9e3d4c73f13b10cfevboxsync } while (0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0%02xh", num, int8_t, uint8_t)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0%04xh", num, int16_t, uint16_t)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0%08xh", num, int32_t, uint32_t)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0%016RX64h", num, int64_t, uint64_t)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * The address?
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync PUT_NUM(9, "%08x`", (uint32_t)(pCpu->uInstrAddr >> 32));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * The opcode bytes?
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync size_t cchTmp = disFormatBytes(pCpu, pszDst, cchDst, fFlags);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Some padding to align the instruction. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED)))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Filter out invalid opcodes first as they need special
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * treatment. UD2 is an exception and should be handled normally.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Adjust the format string to the correct mnemonic
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * or to avoid things the assembler cannot handle correctly.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "jcxz %Jb" : pCpu->uOpMode == DISCPUMODE_32BIT ? "jecxz %Jb" : "jrcxz %Jb";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "pushfw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "pushfd" : "pushfq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "popfw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "popfd" : "popfq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "pushaw" : "pushad";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "popaw" : "popad";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "insw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "insd" : "insq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "outsw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "outsd" : "outsq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "movsw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "movsd" : "movsq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "cmpsw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "cmpsd" : "cmpsq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "scasw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "scasd" : "scasq";
eb64ee0abd56a8f7d9b102e00294404f96398a82vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "lodsw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "lodsd" : "lodsq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "stosw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "stosd" : "stosq";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "cbw" : pCpu->uOpMode == DISCPUMODE_32BIT ? "cwde" : "cdqe";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt = pCpu->uOpMode == DISCPUMODE_16BIT ? "cwd" : pCpu->uOpMode == DISCPUMODE_32BIT ? "cdq" : "cqo";
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Don't know how to tell yasm to generate complicated nop stuff, so 'db' it.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* fine, fine */;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (pszFmt[sizeof("nop %Ev") - 1] == '/' && pszFmt[sizeof("nop %Ev")] == 'p')
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* ST(X) -> stX (floating point) */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (ch == 'S' && pszFmt[0] == 'T' && pszFmt[1] == '(')
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Horrible hacks.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync *(int *)&pCpu->Param1.fParam &= ~0x1f; /* make it pure OP_PARM_M */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case OP_LAR: /* hack w -> v, probably not correct. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Formatting context and associated macros.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_p \
364a14c85c5b8ae00f21b1dfc9fab2d7fffaca21vboxsync } while (0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** @todo mov ah,ch ends up with a byte 'override'... - check if this wasn't fixed. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /** @todo drop the work/dword/qword override when the src/dst is a register (except for movsx/movzx). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync default: break; \
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (OP_PARM_VTYPE(pParam->fParam) != OP_PARM_W) /* these are 128 bit, pray they are all unambiguous.. */ \
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case OP_PARM_s: if (pParam->fUse & DISUSE_REG_FP) PUT_SZ("tword "); break; /* ?? */ \
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case OP_PARM_z: break; \
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && ((pParam->fUse & DISUSE_REG_FP) || pOp->uOpcode == OP_FLD)) \
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync default: break; /*no pointer type specified/necessary*/ \
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync } while (0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync static const char s_szSegPrefix[6][4] = { "es:", "cs:", "ss:", "ds:", "fs:", "gs:" };
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync } while (0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * Segment prefixing for instructions that doesn't do memory access.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * The formatting loop.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * ModRM - Register only.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'C': /* Control register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'D': /* Debug register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'G': /* ModRM selects general register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'S': /* ModRM byte selects a segment register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'T': /* ModRM byte selects a test register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'V': /* ModRM byte selects an XMM/SSE register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'P': /* ModRM byte selects MMX register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(pParam->fUse & (DISUSE_INDEX | DISUSE_SCALE) /* No SIB here... */));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(!(pParam->fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)));
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync * ModRM - Register or memory.
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'E': /* ModRM specifies parameter (ParseModRM / UseModRM / UseSIB). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'Q': /* ModRM byte selects MMX register or memory address (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'R': /* ModRM byte may only refer to a general register (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'W': /* ModRM byte selects an XMM/SSE register or a memory address (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'M': /* ModRM may only refer to memory (ParseModRM / UseModRM). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync /* Work around mov seg,[mem16] and mov [mem16],seg as these always make a 16-bit mem
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync while the register variants deals with 16, 32 & 64 in the normal fashion. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && (fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32)))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && (int8_t)pParam->uDisp.i16 == (int16_t)pParam->uDisp.i16)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && (int16_t)pParam->uDisp.i32 == (int32_t)pParam->uDisp.i32) //??
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && (pCpu->SIB.Bits.Base != 5 || pCpu->ModRM.Bits.Mod != 0)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && (int32_t)pParam->uDisp.i64 == (int64_t)pParam->uDisp.i64) //??
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync bool fBase = (fUse & DISUSE_BASE) /* When exactly is DISUSE_BASE supposed to be set? disasmModRMReg doesn't set it. */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync const char *pszReg = disasmFormatYasmIndexReg(pCpu, pParam, &cchReg);
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if (fUse & (DISUSE_DISPLACEMENT8 | DISUSE_DISPLACEMENT16 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT64 | DISUSE_RIPDISPLACEMENT32))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if (fUse & (DISUSE_DISPLACEMENT32 | DISUSE_RIPDISPLACEMENT32))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'F': /* Eflags register (0 - popf/pushf only, avoided in adjustments above). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync Assert(*pszFmt == 'b' || *pszFmt == 'v' || *pszFmt == 'w' || *pszFmt == 'z'); pszFmt++;
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync switch (pParam->fUse & ( DISUSE_IMMEDIATE8 | DISUSE_IMMEDIATE16 | DISUSE_IMMEDIATE32 | DISUSE_IMMEDIATE64
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync | DISUSE_IMMEDIATE16_SX8 | DISUSE_IMMEDIATE32_SX8 | DISUSE_IMMEDIATE64_SX8))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && ( (pOp->fParam1 >= OP_PARM_REG_GEN8_START && pOp->fParam1 <= OP_PARM_REG_GEN8_END)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || (pOp->fParam2 >= OP_PARM_REG_GEN8_START && pOp->fParam2 <= OP_PARM_REG_GEN8_END))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && ( (int8_t)pParam->uValue == (int16_t)pParam->uValue
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || (pOp->fParam1 >= OP_PARM_REG_GEN16_START && pOp->fParam1 <= OP_PARM_REG_GEN16_END)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || (pOp->fParam2 >= OP_PARM_REG_GEN16_START && pOp->fParam2 <= OP_PARM_REG_GEN16_END))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_v
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync if ( pCpu->uOpMode != (pCpu->uCpuMode == DISCPUMODE_16BIT ? DISCPUMODE_16BIT : DISCPUMODE_32BIT) /* not perfect */
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync && ( (int8_t)pParam->uValue == (int32_t)pParam->uValue
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || (pOp->fParam1 >= OP_PARM_REG_GEN32_START && pOp->fParam1 <= OP_PARM_REG_GEN32_END)
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync || (pOp->fParam2 >= OP_PARM_REG_GEN32_START && pOp->fParam2 <= OP_PARM_REG_GEN32_END))
a33af978add1a03aab11b2895f441af5cb2a11a6vboxsync else if ( OP_PARM_VSUBTYPE(pParam->fParam) == OP_PARM_v
case DISUSE_IMMEDIATE64:
AssertFailed();
if (fPrefix)
if (fPrefix)
if (fPrefix)
if (pfnGetSymbol)
int rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), uTrgAddr, szSymbol, sizeof(szSymbol), &off, pvUser);
if (off != 0)
PUT_FAR();
switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16))
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
case DISUSE_DISPLACEMENT16:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
case DISUSE_DISPLACEMENT32:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
case DISUSE_DISPLACEMENT64:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), (uint64_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
AssertFailed();
if (off != 0)
PUT_FAR();
switch (pParam->fUse & (DISUSE_IMMEDIATE_ADDR_16_16 | DISUSE_IMMEDIATE_ADDR_16_32 | DISUSE_DISPLACEMENT64 | DISUSE_DISPLACEMENT32 | DISUSE_DISPLACEMENT16))
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint16_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->uValue >> 16), (uint32_t)pParam->uValue, szSymbol, sizeof(szSymbol), &off, pvUser);
case DISUSE_DISPLACEMENT16:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u16, szSymbol, sizeof(szSymbol), &off, pvUser);
case DISUSE_DISPLACEMENT32:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u32, szSymbol, sizeof(szSymbol), &off, pvUser);
case DISUSE_DISPLACEMENT64:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DISSELREG_CS), pParam->uDisp.u64, szSymbol, sizeof(szSymbol), &off, pvUser);
AssertFailed();
if (off != 0)
PUT_FAR();
Assert(RT_C_IS_ALPHA(pszFmt[0]) && RT_C_IS_ALPHA(pszFmt[1]) && !RT_C_IS_ALPHA(pszFmt[2])); pszFmt += 2;
switch (++iParam)
if (cchDst > 0)
return cchOutput;
return DISFormatYasmEx(pCpu, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */);
uint32_t f;
f = DISPREFIX_LOCK;
f = DISPREFIX_SEG;
f = DISPREFIX_OPSIZE;
f = DISPREFIX_ADDRSIZE;
if (fPrefixes & f)
fPrefixes |= f;
if (fPrefixes)
case OP_NOP:
case OP_JMP:
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:
case OP_POP:
case OP_PUSH:
case OP_POPA:
case OP_POPF:
case OP_PUSHA:
case OP_PUSHF:
case OP_ADD:
case OP_OR:
case OP_ADC:
case OP_SBB:
case OP_AND:
case OP_SUB:
case OP_XOR:
case OP_CMP:
case OP_ADD:
case OP_OR:
case OP_ADC:
case OP_SBB:
case OP_AND:
case OP_SUB:
case OP_XOR:
case OP_CMP:
case OP_DEC:
case OP_INC:
case OP_POP:
case OP_PUSH:
case OP_MOV:
case OP_SHL:
case OP_SHR:
case OP_SAR:
case OP_RCL:
case OP_RCR:
case OP_ROL:
case OP_ROR:
case OP_ADD:
case OP_OR:
case OP_ADC:
case OP_SBB:
case OP_AND:
case OP_SUB:
case OP_XOR:
case OP_CMP:
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: