DisasmFormatYasm.cpp revision d3cb168f4c128e4477c3f791d983f84075fb2835
537680a235921a9a53f5040185a15cdcf228c217vboxsync * VBox Disassembler - Yasm(/Nasm) Style Formatter.
e64031e20c39650a7bc902a3e1aba613b9415deevboxsync * Copyright (C) 2008 Sun Microsystems, Inc.
537680a235921a9a53f5040185a15cdcf228c217vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
537680a235921a9a53f5040185a15cdcf228c217vboxsync * available from http://www.virtualbox.org. This file is free software;
537680a235921a9a53f5040185a15cdcf228c217vboxsync * you can redistribute it and/or modify it under the terms of the GNU
537680a235921a9a53f5040185a15cdcf228c217vboxsync * General Public License (GPL) as published by the Free Software
537680a235921a9a53f5040185a15cdcf228c217vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
537680a235921a9a53f5040185a15cdcf228c217vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
537680a235921a9a53f5040185a15cdcf228c217vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
537680a235921a9a53f5040185a15cdcf228c217vboxsync * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
537680a235921a9a53f5040185a15cdcf228c217vboxsync * Clara, CA 95054 USA or visit http://www.sun.com if you need
537680a235921a9a53f5040185a15cdcf228c217vboxsync * additional information or have any questions.
537680a235921a9a53f5040185a15cdcf228c217vboxsync/*******************************************************************************
537680a235921a9a53f5040185a15cdcf228c217vboxsync* Header Files *
537680a235921a9a53f5040185a15cdcf228c217vboxsync*******************************************************************************/
537680a235921a9a53f5040185a15cdcf228c217vboxsync/*******************************************************************************
537680a235921a9a53f5040185a15cdcf228c217vboxsync* Global Variables *
4de6100f39be6c66ee61c3208181b8f9086f4cb6vboxsync*******************************************************************************/
537680a235921a9a53f5040185a15cdcf228c217vboxsyncstatic const char g_szSpaces[] =
537680a235921a9a53f5040185a15cdcf228c217vboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8\0", "r9\0", "r10", "r11", "r12", "r13", "r14", "r15"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync "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"
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync * Gets the base register name for the given parameter.
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync * @returns Pointer to the register name.
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync * @param pCpu The disassembler cpu state.
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync * @param pParam The parameter.
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync * @param pcchReg Where to store the length of the name.
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsyncstatic const char *disasmFormatYasmBaseReg(PCDISCPUSTATE pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync switch (pParam->flags & ( USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32 | USE_REG_GEN64
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync | USE_REG_FP | USE_REG_MMX | USE_REG_XMM | USE_REG_CR
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen8));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegGen8[pParam->base.reg_gen];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegGen16[pParam->base.reg_gen];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegGen32[pParam->base.reg_gen];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegGen64[pParam->base.reg_gen];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_fp < RT_ELEMENTS(g_aszYasmRegFP));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegFP[pParam->base.reg_fp];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_mmx < RT_ELEMENTS(g_aszYasmRegMMX));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegMMX[pParam->base.reg_mmx];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_xmm < RT_ELEMENTS(g_aszYasmRegXMM));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegXMM[pParam->base.reg_mmx];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_ctrl < RT_ELEMENTS(g_aszYasmRegCRx));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegCRx[pParam->base.reg_ctrl];
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync Assert(pParam->base.reg_dbg < RT_ELEMENTS(g_aszYasmRegDRx));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegDRx[pParam->base.reg_dbg];
537680a235921a9a53f5040185a15cdcf228c217vboxsync Assert(pParam->base.reg_seg < (DIS_SELREG)RT_ELEMENTS(g_aszYasmRegCRx));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegSeg[pParam->base.reg_seg];
537680a235921a9a53f5040185a15cdcf228c217vboxsync Assert(pParam->base.reg_test < RT_ELEMENTS(g_aszYasmRegTRx));
148b03bcfa337a0e994b1f7297662c972b77ac3avboxsync const char *psz = g_aszYasmRegTRx[pParam->base.reg_test];
f6aff34d987eb8063700c4c26456df4e70f3721cvboxsync return "r??";
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * Gets the index register name for the given parameter.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @returns The index register name.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @param pCpu The disassembler cpu state.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @param pParam The parameter.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @param pcchReg Where to store the length of the name.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsyncstatic const char *disasmFormatYasmIndexReg(PCDISCPUSTATE pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync const char *psz = g_aszYasmRegGen16[pParam->index.reg_gen];
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync const char *psz = g_aszYasmRegGen32[pParam->index.reg_gen];
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
e7fd455c7cf734fefff2b0bd4c620eebe2ce3777vboxsync const char *psz = g_aszYasmRegGen64[pParam->index.reg_gen];
e7fd455c7cf734fefff2b0bd4c620eebe2ce3777vboxsync AssertMsgFailed(("%#x %#x\n", pParam->flags, pCpu->addrmode));
7153a94e631ff3ba3ae93aa08299b4819cbd1501vboxsync return "r??";
164345b1ba852b4467082e8a57c8cb793304802evboxsync * Formats the current instruction in Yasm (/ Nasm) style.
7153a94e631ff3ba3ae93aa08299b4819cbd1501vboxsync * @returns The number of output characters. If this is >= cchBuf, then the content
164345b1ba852b4467082e8a57c8cb793304802evboxsync * of pszBuf will be truncated.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @param pCpu Pointer to the disassembler CPU state.
4de6100f39be6c66ee61c3208181b8f9086f4cb6vboxsync * @param pszBuf The output buffer.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @param cchBuf The size of the output buffer.
b9f55d08827aba9a80f57ca6af945abf6b725abcvboxsync * @param fFlags Format flags, see DIS_FORMAT_FLAGS_*.
b9f55d08827aba9a80f57ca6af945abf6b725abcvboxsync * @param pfnGetSymbol Get symbol name for a jmp or call target address. Optional.
b929f4d04ad2a9b1cf968da876979367430c5efavboxsync * @param pvUser User argument for pfnGetSymbol.
4de6100f39be6c66ee61c3208181b8f9086f4cb6vboxsyncDISDECL(size_t) DISFormatYasmEx(PCDISCPUSTATE pCpu, char *pszBuf, size_t cchBuf, uint32_t fFlags,
7153a94e631ff3ba3ae93aa08299b4819cbd1501vboxsync * Input validation and massaging.
1141858ff8cf4c97d7ade2d43cb111f053182dd2vboxsync AssertMsg(DIS_FMT_FLAGS_IS_VALID(fFlags), ("%#x\n", fFlags));
1141858ff8cf4c97d7ade2d43cb111f053182dd2vboxsync fFlags = (fFlags & ~DIS_FMT_FLAGS_ADDR_LEFT) | DIS_FMT_FLAGS_ADDR_RIGHT;
1141858ff8cf4c97d7ade2d43cb111f053182dd2vboxsync fFlags = (fFlags & ~DIS_FMT_FLAGS_BYTES_LEFT) | DIS_FMT_FLAGS_BYTES_RIGHT;
1141858ff8cf4c97d7ade2d43cb111f053182dd2vboxsync * Output macros
e7fd455c7cf734fefff2b0bd4c620eebe2ce3777vboxsync } while (0)
e7fd455c7cf734fefff2b0bd4c620eebe2ce3777vboxsync } while (0)
case OP_JECXZ:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "jcxz %Jb" : pCpu->opmode == CPUMODE_32BIT ? "jecxz %Jb" : "jrcxz %Jb";
case OP_PUSHF:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "pushfw" : pCpu->opmode == CPUMODE_32BIT ? "pushfd" : "pushfq";
case OP_POPF:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "popfw" : pCpu->opmode == CPUMODE_32BIT ? "popfd" : "popfq";
case OP_PUSHA:
case OP_POPA:
case OP_INSB:
case OP_INSWD:
case OP_OUTSB:
case OP_OUTSWD:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "outsw" : pCpu->opmode == CPUMODE_32BIT ? "outsd" : "outsq";
case OP_MOVSB:
case OP_MOVSWD:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "movsw" : pCpu->opmode == CPUMODE_32BIT ? "movsd" : "movsq";
case OP_CMPSB:
case OP_CMPWD:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "cmpsw" : pCpu->opmode == CPUMODE_32BIT ? "cmpsd" : "cmpsq";
case OP_SCASB:
case OP_SCASWD:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "scasw" : pCpu->opmode == CPUMODE_32BIT ? "scasd" : "scasq";
case OP_LODSB:
case OP_LODSWD:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "lodsw" : pCpu->opmode == CPUMODE_32BIT ? "lodsd" : "lodsq";
case OP_STOSB:
case OP_STOSWD:
pszFmt = pCpu->opmode == CPUMODE_16BIT ? "stosw" : pCpu->opmode == CPUMODE_32BIT ? "stosd" : "stosq";
case OP_CBW:
case OP_CWD:
case OP_SHL:
case OP_XLAT:
case OP_INT3:
case OP_NOP:
char ch;
case OP_FLD:
#define PUT_FAR() \
/** @todo drop the work/dword/qword override when the src/dst is a register (except for movsx/movzx). */
#define PUT_SIZE_OVERRIDE() \
case OP_PARM_v: \
case OP_PARM_dq: \
if (OP_PARM_VTYPE(pParam->param) != OP_PARM_W) /* these are 128 bit, pray they are all unambiguous.. */ \
case OP_PARM_z: break; \
case OP_PARM_NONE: \
#define PUT_SEGMENT_OVERRIDE() \
char ch;
switch (ch)
Assert(!(pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32)));
PUT_FAR();
&& (pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32)))
bool fBase = (pParam->flags & USE_BASE) /* When exactly is USE_BASE supposed to be set? disasmModRMReg doesn't set it. */
if (fBase)
if (fBase)
if (pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32))
if (off < 0)
AssertFailed();
case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */
case USE_IMMEDIATE8:
case USE_IMMEDIATE16:
case USE_IMMEDIATE16_SX8:
case USE_IMMEDIATE32:
if ( pCpu->opmode != (pCpu->mode == CPUMODE_16BIT ? CPUMODE_16BIT : CPUMODE_32BIT) /* not perfect */
case USE_IMMEDIATE32_SX8:
case USE_IMMEDIATE64:
AssertFailed();
if (fPrefix)
if (fPrefix)
if (fPrefix)
if (pfnGetSymbol)
int rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), uTrgAddr, szSymbol, sizeof(szSymbol), &off, pvUser);
if (off != 0)
PUT_FAR();
int rc;
switch (pParam->flags & (USE_IMMEDIATE_ADDR_16_16 | USE_IMMEDIATE_ADDR_16_32 | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16))
case USE_IMMEDIATE_ADDR_16_16:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_IMMEDIATE_ADDR_16_32:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_DISPLACEMENT16:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_DISPLACEMENT32:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_DISPLACEMENT64:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint64_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
AssertFailed();
if (off != 0)
PUT_FAR();
int rc;
switch (pParam->flags & (USE_IMMEDIATE_ADDR_16_16 | USE_IMMEDIATE_ADDR_16_32 | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16))
case USE_IMMEDIATE_ADDR_16_16:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint16_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_IMMEDIATE_ADDR_16_32:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_VALUE(pParam->parval >> 16), (uint32_t)pParam->parval, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_DISPLACEMENT16:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint16_t)pParam->disp16, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_DISPLACEMENT32:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint32_t)pParam->disp32, szSymbol, sizeof(szSymbol), &off, pvUser);
case USE_DISPLACEMENT64:
if (pfnGetSymbol)
rc = pfnGetSymbol(pCpu, DIS_FMT_SEL_FROM_REG(DIS_SELREG_CS), (uint64_t)pParam->disp64, 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;