DisasmFormatYasm.cpp revision 95ed338027d70aabb68eff2437bf0d08ebbdbea4
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * VBox Disassembler - Yasm(/Nasm) Style Formatter.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * available from http://www.virtualbox.org. This file is free software;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * you can redistribute it and/or modify it under the terms of the GNU
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * General Public License (GPL) as published by the Free Software
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * additional information or have any questions.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync/*******************************************************************************
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync* Header Files *
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync*******************************************************************************/
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync/*******************************************************************************
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync* Global Variables *
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync*******************************************************************************/
de6ba1989c812829372828f1801b232b3e7f09bfvboxsyncstatic const char g_szSpaces[] =
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "al\0", "cl\0", "dl\0", "bl\0", "ah\0", "ch\0", "dh\0", "bh\0"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "al\0\0", "cl\0\0", "dl\0\0", "bl\0\0", "spb\0", "bpb\0", "sib\0", "dib\0", "r8b\0", "r9b\0", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "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"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "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"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8\0", "r9\0", "r10", "r11", "r12", "r13", "r14", "r15"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "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"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "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"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "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"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync "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"
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Gets the base register name for the given parameter.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @returns Pointer to the register name.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pCpu The disassembler cpu state.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pParam The parameter.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pcchReg Where to store the length of the name.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsyncstatic const char *disasmFormatYasmBaseReg(PCDISCPUSTATE pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync switch (pParam->flags & ( USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32 | USE_REG_GEN64
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync | USE_REG_FP | USE_REG_MMX | USE_REG_XMM | USE_REG_CR
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen8Amd64));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen8Amd64[pParam->base.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen8x86));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen16[pParam->base.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen32[pParam->base.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen64[pParam->base.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_fp < RT_ELEMENTS(g_aszYasmRegFP));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegFP[pParam->base.reg_fp];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_mmx < RT_ELEMENTS(g_aszYasmRegMMX));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegMMX[pParam->base.reg_mmx];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_xmm < RT_ELEMENTS(g_aszYasmRegXMM));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegXMM[pParam->base.reg_mmx];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_ctrl < RT_ELEMENTS(g_aszYasmRegCRx));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegCRx[pParam->base.reg_ctrl];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_dbg < RT_ELEMENTS(g_aszYasmRegDRx));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegDRx[pParam->base.reg_dbg];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_seg < RT_ELEMENTS(g_aszYasmRegCRx));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegSeg[pParam->base.reg_seg];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->base.reg_test < RT_ELEMENTS(g_aszYasmRegTRx));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegTRx[pParam->base.reg_test];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync return "r??";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Gets the index register name for the given parameter.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @returns The index register name.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pCpu The disassembler cpu state.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pParam The parameter.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pcchReg Where to store the length of the name.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsyncstatic const char *disasmFormatYasmIndexReg(PCDISCPUSTATE pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen16[pParam->index.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen32[pParam->index.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *psz = g_aszYasmRegGen64[pParam->index.reg_gen];
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync AssertMsgFailed(("%#x %#x\n", pParam->flags, pCpu->addrmode));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync return "r??";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Formats the current instruction in Yasm (/ Nasm) style.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @returns The number of output characters. If this is >= cchBuf, then the content
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * of pszBuf will be truncated.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pCpu Pointer to the disassembler CPU state.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pszBuf The output buffer.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param cchBuf The size of the output buffer.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pvUser User argument for pfnGetSymbol.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsyncDISDECL(size_t) DISFormatYasmEx(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags,
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Input validation and massaging.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Output macros
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } while (0)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } while (0)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync do { if (fFlags & DIS_FMT_FLAGS_STRICT) PUT_SZ(szStrict); else PUT_SZ(szRelaxed); } while (0)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const size_t cchTmp = RTStrPrintf(pszDst, cchDst, fmt, (num)); \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } while (0)
95ed338027d70aabb68eff2437bf0d08ebbdbea4vboxsync/** @todo add two flags for choosing between %X / %x and h / 0x. */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync#define PUT_NUM_8(num) PUT_NUM(4, "0%02xh", (uint8_t)(num))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync#define PUT_NUM_16(num) PUT_NUM(6, "0%04xh", (uint16_t)(num))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync#define PUT_NUM_32(num) PUT_NUM(10, "0%08xh", (uint32_t)(num))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync#define PUT_NUM_64(num) PUT_NUM(18, "0%08xh", (uint64_t)(num))
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync } while (0)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync#define PUT_NUM_S8(num) PUT_NUM_SIGN(4, "0%02xh", num, int8_t, uint8_t)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync#define PUT_NUM_S16(num) PUT_NUM_SIGN(6, "0%04xh", num, int16_t, uint16_t)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync#define PUT_NUM_S32(num) PUT_NUM_SIGN(10, "0%08xh", num, int32_t, uint32_t)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync#define PUT_NUM_S64(num) PUT_NUM_SIGN(18, "0%08xh", num, int64_t, uint64_t)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * The address?
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync PUT_NUM(9, "%08x`", (uint32_t)(pCpu->opaddr >> 32));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * The opcode bytes?
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync size_t cchTmp = disFormatBytes(pCpu, pszDst, cchDst, fFlags);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* Some padding to align the instruction. */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync size_t cchPadding = (7 * (2 + !!(fFlags & DIS_FMT_FLAGS_BYTES_SPACED)))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync cchPadding = cchTmp + 1 >= cchPadding ? 1 : cchPadding - cchTmp;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Filter out invalid opcodes first as they need special
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * treatment. UD2 is an exception and should be handled normally.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Adjust the format string to the correct mnemonic
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * or to avoid things the assembler cannot handle correctly.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "jcxz %Jb" : pCpu->opmode == CPUMODE_32BIT ? "jecxz %Jb" : "jrcxz %Jb";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "pushfw" : pCpu->opmode == CPUMODE_32BIT ? "pushfd" : "pushfq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "popfw" : pCpu->opmode == CPUMODE_32BIT ? "popfd" : "popfq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "pushaw" : "pushad";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "popaw" : "popad";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "insw" : pCpu->opmode == CPUMODE_32BIT ? "insd" : "insq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "outsw" : pCpu->opmode == CPUMODE_32BIT ? "outsd" : "outsq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "movsw" : pCpu->opmode == CPUMODE_32BIT ? "movsd" : "movsq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "cmpsw" : pCpu->opmode == CPUMODE_32BIT ? "cmpsd" : "cmpsq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "scasw" : pCpu->opmode == CPUMODE_32BIT ? "scasd" : "scasq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "lodsw" : pCpu->opmode == CPUMODE_32BIT ? "lodsd" : "lodsq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "stosw" : pCpu->opmode == CPUMODE_32BIT ? "stosd" : "stosq";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "cbw" : pCpu->opmode == CPUMODE_32BIT ? "cwde" : "cdqe";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt = pCpu->opmode == CPUMODE_16BIT ? "cwd" : pCpu->opmode == CPUMODE_32BIT ? "cdq" : "cqo";
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Don't know how to tell yasm to generate complicated nop stuff, so 'db' it.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* fine, fine */;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync else if (pszFmt[sizeof("nop %Ev")] == '/' && pszFmt[sizeof("nop %Ev") + 1] == 'p')
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* ST(X) -> stX (floating point) */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync if (ch == 'S' && pszFmt[0] == 'T' && pszFmt[1] == '(')
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Horrible hacks.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync *(int *)&pCpu->param1.param &= ~0x1f; /* make it pure OP_PARM_M */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case OP_LAR: /* hack w -> v, probably not correct. */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Formatting context and associated macros.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync if ( OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } while (0)
95ed338027d70aabb68eff2437bf0d08ebbdbea4vboxsync /** @todo mov ah,ch ends up with a byte 'override'... - check if this wasn't fixed. */
95ed338027d70aabb68eff2437bf0d08ebbdbea4vboxsync /** @todo drop the work/dword/qword override when the src/dst is a register (except for movsx/movzx). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync default: break; \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync if (OP_PARM_VTYPE(pParam->param) != OP_PARM_W) /* these are 128 bit, pray they are all unambiguous.. */ \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case OP_PARM_s: if (pParam->flags & USE_REG_FP) PUT_SZ("tword "); break; /* ?? */ \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case OP_PARM_z: break; \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync && ((pParam->flags & USE_REG_FP) || pOp->opcode == OP_FLD)) \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync default: break; /*no pointer type specified/necessary*/ \
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } while (0)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync static const char s_szSegPrefix[6][4] = { "es:", "cs:", "ss:", "ds:", "fs:", "gs:" };
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } while (0)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Segment prefixing for instructions that doesn't do memory access.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * The formatting loop.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * ModRM - Register only.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'C': /* Control register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'D': /* Debug register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'G': /* ModRM selects general register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'S': /* ModRM byte selects a segment register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'T': /* ModRM byte selects a test register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'V': /* ModRM byte selects an XMM/SSE register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'P': /* ModRM byte selects MMX register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(!(pParam->flags & (USE_INDEX | USE_SCALE) /* No SIB here... */));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(!(pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32)));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * ModRM - Register or memory.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'E': /* ModRM specifies parameter (ParseModRM / UseModRM / UseSIB). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'Q': /* ModRM byte selects MMX register or memory address (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'R': /* ModRM byte may only refer to a general register (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'W': /* ModRM byte selects an XMM/SSE register or a memory address (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'M': /* ModRM may only refer to memory (ParseModRM / UseModRM). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* Work around mov seg,[mem16] and mov [mem16],seg as these always make a 16-bit mem
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync while the register variants deals with 16, 32 & 64 in the normal fashion. */
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync && (pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32)))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync && (int8_t)pParam->disp16 == (int16_t)pParam->disp16)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync && (int8_t)pParam->disp32 == (int32_t)pParam->disp32)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync bool fBase = (pParam->flags & USE_BASE) /* When exactly is USE_BASE supposed to be set? disasmModRMReg doesn't set it. */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync || ( (pParam->flags & (USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32 | USE_REG_GEN64))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *pszReg = disasmFormatYasmIndexReg(pCpu, pParam, &cchReg);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync if (pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync else if (pParam->flags & (USE_DISPLACEMENT32 | USE_RIPDISPLACEMENT32))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'F': /* Eflags register (0 - popf/pushf only, avoided in adjustments above). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(*pszFmt == 'b' || *pszFmt == 'v' || *pszFmt == 'w' || *pszFmt == 'z'); pszFmt++;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync switch (pParam->flags & ( USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE64
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync && ( (pOp->param1 >= OP_PARM_REG_GEN8_START && pOp->param1 <= OP_PARM_REG_GEN8_END)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync || (pOp->param2 >= OP_PARM_REG_GEN8_START && pOp->param2 <= OP_PARM_REG_GEN8_END))
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync && ( (int8_t)pParam->parval == (int16_t)pParam->parval
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync || (pOp->param1 >= OP_PARM_REG_GEN16_START && pOp->param1 <= OP_PARM_REG_GEN16_END)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync || (pOp->param2 >= OP_PARM_REG_GEN16_START && pOp->param2 <= OP_PARM_REG_GEN16_END))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync else if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_v)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync if ( pCpu->opmode != (pCpu->mode == CPUMODE_16BIT ? CPUMODE_16BIT : CPUMODE_32BIT) /* not perfect */
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync && ( (int8_t)pParam->parval == (int32_t)pParam->parval
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync || (pOp->param1 >= OP_PARM_REG_GEN32_START && pOp->param1 <= OP_PARM_REG_GEN32_END)
92473d1de9ab080ff886ad61a4d908f7c3429608vboxsync || (pOp->param2 >= OP_PARM_REG_GEN32_START && pOp->param2 <= OP_PARM_REG_GEN32_END))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync else if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_v)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'J': /* Relative jump offset (ParseImmBRel + ParseImmVRel). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync RTUINTPTR uTrgAddr = pCpu->opaddr + pCpu->opsize + offDisplacement;
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync int rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), uTrgAddr, szSymbol, sizeof(szSymbol), &off, pvUser);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'A': /* Direct (jump/call) address (ParseImmAddr). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync switch (pParam->flags & (USE_IMMEDIATE_ADDR_16_16 | USE_IMMEDIATE_ADDR_16_32 | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16))
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), (uint64_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync switch (pParam->flags & (USE_IMMEDIATE_ADDR_16_16 | USE_IMMEDIATE_ADDR_16_32 | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16))
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), (uint16_t)pParam->disp16, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), (uint32_t)pParam->disp32, szSymbol, sizeof(szSymbol), &off, pvUser);
1ec912d58b09f1e2eda06b788299d6157cd826b1vboxsync rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(USE_REG_CS), (uint64_t)pParam->disp64, szSymbol, sizeof(szSymbol), &off, pvUser);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync case 'e': /* Register based on operand size (e.g. %eAX) (ParseFixedReg). */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync Assert(RT_C_IS_ALPHA(pszFmt[0]) && RT_C_IS_ALPHA(pszFmt[1]) && !RT_C_IS_ALPHA(pszFmt[2])); pszFmt += 2;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync const char *pszReg = disasmFormatYasmBaseReg(pCpu, pParam, &cchReg);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync AssertMsg(*pszFmt == ',' || *pszFmt == '\0', ("%c%s\n", ch, pszFmt));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync } /* while more to format */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Any additional output to the right of the instruction?
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* some up front padding. */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync cchPadding = cchPadding + 1 >= 42 ? 1 : 42 - cchPadding;
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* comment? */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync if (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_ADDR_RIGHT))
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * The address?
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync PUT_NUM(9, "%08x`", (uint32_t)(pCpu->opaddr >> 32));
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Opcode bytes?
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync size_t cchTmp = disFormatBytes(pCpu, pszDst, cchDst, fFlags);
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Terminate it - on overflow we'll have reserved one byte for this.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync /* clean up macros */
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * Formats the current instruction in Yasm (/ Nasm) style.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * This is a simplified version of DISFormatYasmEx() provided for your convenience.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @returns The number of output characters. If this is >= cchBuf, then the content
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * of pszBuf will be truncated.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pCpu Pointer to the disassembler CPU state.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param pszBuf The output buffer.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync * @param cchBuf The size of the output buffer.
de6ba1989c812829372828f1801b232b3e7f09bfvboxsyncDISDECL(size_t) DISFormatYasm(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf)
de6ba1989c812829372828f1801b232b3e7f09bfvboxsync return DISFormatYasmEx(pCpu, pszBuf, cchBuf, 0 /* fFlags */, NULL /* pfnGetSymbol */, NULL /* pvUser */);