VirtualBox

Changeset 9098 in vbox for trunk/src/VBox


Ignore:
Timestamp:
May 25, 2008 10:16:58 PM (17 years ago)
Author:
vboxsync
Message:

More or less working yasm formatter. Added some disassembler testcases.

Location:
trunk/src/VBox/Disassembler/testcase
Files:
6 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Disassembler/testcase/Makefile.kmk

    r8989 r9098  
    3737VBOX_DISAS_TESTS_BUILD = \
    3838        tstAsmLock-1.asm \
     39        tstAsmMovSeg-1.asm \
     40        tstAsmMovzx-1.asm \
     41        tstAsmPop-1.asm \
     42        tstAsmPush-1.asm \
     43        tstAsmSignExtend-1.asm \
    3944
    4045# Tests that only contains invalid/undefined instructions.
     
    4247        tstAsmLock-2.asm \
    4348        tstAsmLock-3.asm
     49
     50# Tests that will be disassembled and re-build from disassembly (list of binaries).
     51VBOX_DISAS_TESTS_BINARIES := \
     52        $(PATH_SUB_CURRENT)/tstBinMovzx-1.bin
     53#       $(PATH_SUB_CURRENT)/tstBin-1.bin \
     54#       $(PATH_BIN)/testcase/tstDisasm-2$(SUFF_EXEC)
    4455
    4556
     
    120131        $(CMP) $(@:.tst=.bin) $<
    121132        @$(APPEND) $@ "done"
    122         @$(ECHO) "PASSED:  $(<F) [re-assembled]"
     133        @$(ECHO) " PASSED:  $(<F) [re-assembled]"
    123134
    124135
     
    132143        $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(INSTARGET_tstDisasm-2) --undef-op=all --cpumode=16 $<
    133144        @$(APPEND) $@ "done"
    134         @$(ECHO) "PASSED:  $(@F) [--undef-op=all]"
     145        @$(ECHO) " PASSED:  $(@F) [--undef-op=all]"
    135146
    136147$(addprefix $(VBOX_DISAS_TEST_PATH)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-32.tst)): $$(patsubst %.tst,%.bin,$$@) $$(INSTARGET_tstDisasm-2) | $$(call DIRDEP,$$(@D))
     
    139150        $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(INSTARGET_tstDisasm-2) --undef-op=all --cpumode=32 $<
    140151        @$(APPEND) $@ "done"
    141         @$(ECHO) "PASSED:  $(@F) [--undef-op=all]"
     152        @$(ECHO) " PASSED:  $(@F) [--undef-op=all]"
    142153
    143154$(addprefix $(VBOX_DISAS_TEST_PATH)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-64.tst)): $$(patsubst %.tst,%.bin,$$@) $$(INSTARGET_tstDisasm-2) | $$(call DIRDEP,$$(@D))
     
    146157        $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(INSTARGET_tstDisasm-2) --undef-op=all --cpumode=64 $<
    147158        @$(APPEND) $@ "done"
    148         @$(ECHO) "PASSED:  $(@F) [--undef-op=all]"
     159        @$(ECHO) " PASSED:  $(@F) [--undef-op=all]"
     160
     161
     162# Generate the rules for the binary tests.
     163define def_vbox_disas_binary_rules
     164$(outbase).asm: $(binary) $$$$(INSTARGET_tstDisasm-2) | $(VBOX_DISAS_TEST_PATH)/
     165        @$$(ECHO) "Generating: $$(@F) from $$(<F)"
     166        $$(REDIRECT) -E VBOX_LOG_DEST=nofile -o $$@ -- $$(INSTARGET_tstDisasm-2) --style=yasm --cpumode=$(bits) --undef-op=db $$<
     167
     168$(outbase).bin + $(outbase).lst: $(outbase).asm
     169        @$$(ECHO) "Re-assembling: $$(<F) into $$(@F)"
     170        $$(TOOL_YASM_AS) -f bin -a x86 --force-strict -l $(outbase).lst -o $$@ $$<
     171
     172$(outbase).tst: $(outbase).bin
     173        @$$(ECHO) "Verifying build: $$(<F) against $(not-dir $(binary))"
     174        @$$(RM) -f $$@
     175        $$(CMP) -l $(binary) $$<
     176        @$$(APPEND) $@ "done"
     177        @$$(ECHO) " PASSED:  $$(<F) [binary]"
     178
     179$(name).tst:: $(outbase).tst
     180VBOX_DISAS_TEST_CLEAN += $(outbase).tst $(outbase).bin $(outbase).asm
     181endef # def_vbox_disas_binary_rules
     182
     183define def_vbox_disas_binary
     184local name := $(notdir $(basename $(binary)))
     185local name := $(notdir $(basename $(binary)))
     186local outbase := $(VBOX_DISAS_TEST_PATH)/$(name)-rebuild-$(bits)
     187$(eval $(def_vbox_disas_binary_rules))
     188endef # def_vbox_disas_binary
     189
     190## @todo 64-bit is problematic because of POP RDI ending up as POP EDI (incorrect default opmode), and the unused REX.X bit when mod != 3.
     191#$(foreach bits, 32 16 64, $(foreach binary, $(VBOX_DISAS_TESTS_BINARIES), $(evalvalctx def_vbox_disas_binary)))
     192$(foreach bits, 32 16, $(foreach binary, $(VBOX_DISAS_TESTS_BINARIES), $(evalvalctx def_vbox_disas_binary)))
     193
    149194
    150195# Add the .tst to the clean up.
  • trunk/src/VBox/Disassembler/testcase/tstDisasm-2.cpp

    r8986 r9098  
    2929#include <iprt/string.h>
    3030#include <iprt/runtime.h>
    31 #include <iprt/err.h>
     31#include <VBox/err.h>
     32#include <iprt/ctype.h>
    3233
    3334
     
    3536*   Structures and Typedefs                                                    *
    3637*******************************************************************************/
    37 typedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_invalid } ASMSTYLE;
     38typedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_gas, kAsmStyle_invalid } ASMSTYLE;
    3839typedef enum { kUndefOp_Fail, kUndefOp_All, kUndefOp_DefineByte, kUndefOp_End } UNDEFOPHANDLING;
    3940
     
    5556
    5657
     58/*
     59 * Non-logging builds doesn't to full formatting so we must do it on our own.
     60 * This should probably be moved into the disassembler later as it's needed for
     61 * the vbox debugger as well.
     62 *
     63 * Comment in USE_MY_FORMATTER to enable it.
     64 */
     65#define USE_MY_FORMATTER
     66
     67#ifdef USE_MY_FORMATTER
     68static const char g_aszYasmRegGen8x86[8][4] =
     69{
     70    "al\0",   "cl\0",   "dl\0",   "bl\0",   "ah\0",   "ch\0",   "dh\0",   "bh\0"
     71};
     72static const char g_aszYasmRegGen8Amd64[16][5] =
     73{
     74    "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"
     75};
     76static const char g_aszYasmRegGen16[16][5] =
     77{
     78    "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"
     79};
     80static const char g_aszYasmRegGen1616[8][6] =
     81{
     82    "bx+si", "bx+di", "bp+si", "bp+di", "si\0\0\0", "di\0\0\0", "bp\0\0\0", "bx\0\0\0"
     83};
     84static const char g_aszYasmRegGen32[16][5] =
     85{
     86    "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"
     87};
     88static const char g_aszYasmRegGen64[16][4] =
     89{
     90    "rax",    "rcx",    "rdx",    "rbx",    "rsp",    "rbp",    "rsi",    "rdi",    "r8\0",   "r9\0",   "r10",   "r11",   "r12",   "r13",   "r14",   "r15"
     91};
     92static const char g_aszYasmRegSeg[6][3] =
     93{
     94    "es",     "cs",     "ss",      "ds",    "fs",     "gs"
     95};
     96static const char g_aszYasmRegFP[8][4] =
     97{
     98    "st0",    "st1",    "st2",    "st3",    "st4",    "st5",    "st6",    "st7"
     99};
     100static const char g_aszYasmRegMMX[8][4] =
     101{
     102    "mm0",    "mm1",    "mm2",    "mm3",    "mm4",    "mm5",    "mm6",    "mm7"
     103};
     104static const char g_aszYasmRegXMM[16][6] =
     105{
     106    "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"
     107};
     108static const char g_aszYasmRegCRx[16][5] =
     109{
     110    "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"
     111};
     112static const char g_aszYasmRegDRx[16][5] =
     113{
     114    "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"
     115};
     116static const char g_aszYasmRegTRx[16][5] =
     117{
     118    "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"
     119};
     120
     121
     122DECLINLINE(const char *) MyDisasYasmFormatBaseReg(DISCPUSTATE const *pCpu, PCOP_PARAMETER pParam, size_t *pcchReg, bool fReg1616)
     123{
     124    switch (pParam->flags & (  USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32 | USE_REG_GEN64
     125                             | USE_REG_FP   | USE_REG_MMX   | USE_REG_XMM   | USE_REG_CR
     126                             | USE_REG_DBG  | USE_REG_SEG   | USE_REG_TEST))
     127
     128    {
     129        case USE_REG_GEN8:
     130            if (pCpu->opmode == CPUMODE_64BIT)
     131            {
     132                Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen8Amd64));
     133                const char *psz = g_aszYasmRegGen8Amd64[pParam->base.reg_gen];
     134                *pcchReg = 2 + !!psz[2] + !!psz[3];
     135                return psz;
     136            }
     137            *pcchReg = 2;
     138            Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen8x86));
     139            return g_aszYasmRegGen8x86[pParam->base.reg_gen];
     140
     141        case USE_REG_GEN16:
     142        {
     143            if (fReg1616)
     144            {
     145                Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen1616));
     146                const char *psz = g_aszYasmRegGen1616[pParam->base.reg_gen];
     147                *pcchReg = psz[2] ? 5 : 2;
     148                return psz;
     149            }
     150
     151            Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
     152            const char *psz = g_aszYasmRegGen16[pParam->base.reg_gen];
     153            *pcchReg = 2 + !!psz[2] + !!psz[3];
     154            return psz;
     155        }
     156
     157        case USE_REG_GEN32:
     158        {
     159            Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
     160            const char *psz = g_aszYasmRegGen32[pParam->base.reg_gen];
     161            *pcchReg = 2 + !!psz[2] + !!psz[3];
     162            return psz;
     163        }
     164
     165        case USE_REG_GEN64:
     166        {
     167            Assert(pParam->base.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
     168            const char *psz = g_aszYasmRegGen64[pParam->base.reg_gen];
     169            *pcchReg = 2 + !!psz[2] + !!psz[3];
     170            return psz;
     171        }
     172
     173        case USE_REG_FP:
     174        {
     175            Assert(pParam->base.reg_fp < RT_ELEMENTS(g_aszYasmRegFP));
     176            const char *psz = g_aszYasmRegFP[pParam->base.reg_fp];
     177            *pcchReg = 3;
     178            return psz;
     179        }
     180
     181        case USE_REG_MMX:
     182        {
     183            Assert(pParam->base.reg_mmx < RT_ELEMENTS(g_aszYasmRegMMX));
     184            const char *psz = g_aszYasmRegMMX[pParam->base.reg_mmx];
     185            *pcchReg = 3;
     186            return psz;
     187        }
     188
     189        case USE_REG_XMM:
     190        {
     191            Assert(pParam->base.reg_xmm < RT_ELEMENTS(g_aszYasmRegXMM));
     192            const char *psz = g_aszYasmRegXMM[pParam->base.reg_mmx];
     193            *pcchReg = 4 + !!psz[4];
     194            return psz;
     195        }
     196
     197        case USE_REG_CR:
     198        {
     199            Assert(pParam->base.reg_ctrl < RT_ELEMENTS(g_aszYasmRegCRx));
     200            const char *psz = g_aszYasmRegCRx[pParam->base.reg_ctrl];
     201            *pcchReg = 3;
     202            return psz;
     203        }
     204
     205        case USE_REG_DBG:
     206        {
     207            Assert(pParam->base.reg_dbg < RT_ELEMENTS(g_aszYasmRegDRx));
     208            const char *psz = g_aszYasmRegDRx[pParam->base.reg_dbg];
     209            *pcchReg = 3;
     210            return psz;
     211        }
     212
     213        case USE_REG_SEG:
     214        {
     215            Assert(pParam->base.reg_seg < RT_ELEMENTS(g_aszYasmRegCRx));
     216            const char *psz = g_aszYasmRegSeg[pParam->base.reg_seg];
     217            *pcchReg = 2;
     218            return psz;
     219        }
     220
     221        case USE_REG_TEST:
     222        {
     223            Assert(pParam->base.reg_test < RT_ELEMENTS(g_aszYasmRegTRx));
     224            const char *psz = g_aszYasmRegTRx[pParam->base.reg_test];
     225            *pcchReg = 3;
     226            return psz;
     227        }
     228
     229        default:
     230            AssertMsgFailed(("%#x\n", pParam->flags));
     231            *pcchReg = 3;
     232            return "r??";
     233    }
     234}
     235
     236DECLINLINE(const char *) MyDisasYasmFormatIndexReg(DISCPUSTATE const *pCpu, PCOP_PARAMETER pParam, size_t *pcchReg)
     237{
     238    switch (pCpu->addrmode)
     239    {
     240        case CPUMODE_16BIT:
     241        {
     242            Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen16));
     243            const char *psz = g_aszYasmRegGen16[pParam->index.reg_gen];
     244            *pcchReg = 2 + !!psz[2] + !!psz[3];
     245            return psz;
     246        }
     247
     248        case CPUMODE_32BIT:
     249        {
     250            Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen32));
     251            const char *psz = g_aszYasmRegGen32[pParam->index.reg_gen];
     252            *pcchReg = 2 + !!psz[2] + !!psz[3];
     253            return psz;
     254        }
     255
     256        case CPUMODE_64BIT:
     257        {
     258            Assert(pParam->index.reg_gen < RT_ELEMENTS(g_aszYasmRegGen64));
     259            const char *psz = g_aszYasmRegGen64[pParam->index.reg_gen];
     260            *pcchReg = 2 + !!psz[2] + !!psz[3];
     261            return psz;
     262        }
     263
     264        default:
     265            AssertMsgFailed(("%#x %#x\n", pParam->flags, pCpu->addrmode));
     266            *pcchReg = 3;
     267            return "r??";
     268    }
     269}
     270
     271static size_t MyDisasYasmFormat(DISCPUSTATE const *pCpu, char *pszBuf, size_t cchBuf)
     272{
     273    PCOPCODE const  pOp = pCpu->pCurInstr;
     274    size_t          cchOutput = 0;
     275    char           *pszDst = pszBuf;
     276    size_t          cchDst = cchBuf;
     277
     278    /* output macros */
     279#define PUT_C(ch)       \
     280            do { \
     281                cchOutput++; \
     282                if (cchDst > 1) \
     283                { \
     284                    cchDst--; \
     285                    *pszDst++ = (ch); \
     286                } \
     287            } while (0)
     288#define PUT_STR(pszSrc, cchSrc) \
     289            do { \
     290                cchOutput += (cchSrc); \
     291                if (cchDst > (cchSrc)) \
     292                { \
     293                    memcpy(pszDst, (pszSrc), (cchSrc)); \
     294                    pszDst += (cchSrc); \
     295                    cchDst -= (cchSrc); \
     296                } \
     297                else if (cchDst > 1) \
     298                { \
     299                    memcpy(pszDst, (pszSrc), cchDst - 1); \
     300                    pszDst += cchDst - 1; \
     301                    cchDst = 1; \
     302                } \
     303            } while (0)
     304#define PUT_SZ(sz) \
     305            PUT_STR((sz), sizeof(sz) - 1)
     306#define PUT_PSZ(psz) \
     307            do { const size_t cchTmp = strlen(psz); PUT_STR((psz), cchTmp); } while (0)
     308#define PUT_NUM(cch, fmt, num) \
     309            do { \
     310                 cchOutput += (cch); \
     311                 if (cchBuf > 1) \
     312                 { \
     313                    const size_t cchTmp = RTStrPrintf(pszDst, cchBuf, fmt, (num)); \
     314                    pszDst += cchTmp; \
     315                    cchBuf -= cchTmp; \
     316                    Assert(cchTmp == (cch) || cchBuf == 1); \
     317                 } \
     318            } while (0)
     319#define PUT_NUM_8(num)  PUT_NUM(4,  "0%02xh", (uint8_t)(num))
     320#define PUT_NUM_16(num) PUT_NUM(6,  "0%04xh", (uint16_t)(num))
     321#define PUT_NUM_32(num) PUT_NUM(10, "0%08xh", (uint32_t)(num))
     322#define PUT_NUM_64(num) PUT_NUM(18, "0%08xh", (uint64_t)(num))
     323
     324    /*
     325     * Filter out invalid opcodes first as they need special
     326     * treatment. UD2 is an exception and should be handled normally.
     327     */
     328    if (    pOp->opcode == OP_INVALID
     329        ||  (   pOp->opcode == OP_ILLUD2
     330             && (pCpu->prefix & PREFIX_LOCK)))
     331    {
     332
     333    }
     334    else
     335    {
     336        /*
     337         * Prefixes
     338         */
     339        if (pCpu->prefix & PREFIX_LOCK)
     340            PUT_SZ("lock ");
     341        if(pCpu->prefix & PREFIX_REP)
     342            PUT_SZ("rep ");
     343        else if(pCpu->prefix & PREFIX_REPNE)
     344            PUT_SZ("repne ");
     345
     346        /*
     347         * Adjust the format string to avoid stuff the assembler cannot handle.
     348         */
     349        char szTmpFmt[48];
     350        const char *pszFmt = pOp->pszOpcode;
     351        switch (pOp->opcode)
     352        {
     353            case OP_JECXZ:
     354                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "jcxz %Jb" : pCpu->opmode == CPUMODE_32BIT ? "jecxz %Jb"   : "jrcxz %Jb";
     355                break;
     356            case OP_PUSHF:
     357                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "pushfw"   : pCpu->opmode == CPUMODE_32BIT ? "pushfd"      : "pushfq";
     358                break;
     359            case OP_POPF:
     360                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "popfw"    : pCpu->opmode == CPUMODE_32BIT ? "popfd"       : "popfq";
     361                break;
     362            case OP_INSB:
     363                pszFmt = "insb";
     364                break;
     365            case OP_INSWD:
     366                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "insw"     : pCpu->opmode == CPUMODE_32BIT ? "insd"  : "insq";
     367                break;
     368            case OP_OUTSB:
     369                pszFmt = "outsb";
     370                break;
     371            case OP_OUTSWD:
     372                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "outsw"    : pCpu->opmode == CPUMODE_32BIT ? "outsd" : "outsq";
     373                break;
     374            case OP_MOVSB:
     375                pszFmt = "movsb";
     376                break;
     377            case OP_MOVSWD:
     378                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "movsw"    : pCpu->opmode == CPUMODE_32BIT ? "movsd" : "movsq";
     379                break;
     380            case OP_CMPSB:
     381                pszFmt = "cmpsb";
     382                break;
     383            case OP_CMPWD:
     384                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "cmpsw"    : pCpu->opmode == CPUMODE_32BIT ? "cmpsd" : "cmpsq";
     385                break;
     386            case OP_SCASB:
     387                pszFmt = "scasb";
     388                break;
     389            case OP_SCASWD:
     390                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "scasw"    : pCpu->opmode == CPUMODE_32BIT ? "scasd" : "scasq";
     391                break;
     392            case OP_LODSB:
     393                pszFmt = "lodsb";
     394                break;
     395            case OP_LODSWD:
     396                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "lodsw"    : pCpu->opmode == CPUMODE_32BIT ? "lodsd" : "lodsq";
     397                break;
     398            case OP_STOSB:
     399                pszFmt = "stosb";
     400                break;
     401            case OP_STOSWD:
     402                pszFmt = pCpu->opmode == CPUMODE_16BIT ? "stosw"    : pCpu->opmode == CPUMODE_32BIT ? "stosd" : "stosq";
     403                break;
     404            case OP_SHL:
     405                Assert(pszFmt[3] == '/');
     406                pszFmt += 4;
     407                break;
     408            case OP_XLAT:
     409                pszFmt = "xlatb";
     410                break;
     411            case OP_INT3:
     412                pszFmt = "int3";
     413                break;
     414
     415            /*
     416             * Don't know how to tell yasm to generate complicated nop stuff, so 'db' it.
     417             */
     418            case OP_NOP:
     419                if (pCpu->opcode == 0x90)
     420                    /* fine, fine */;
     421                else if (pszFmt[sizeof("nop %Ev")] == '/' && pszFmt[sizeof("nop %Ev") + 1] == 'p')
     422                    pszFmt = "prefetch %Eb";
     423                else if (pCpu->opcode == 0x1f)
     424                {
     425                    PUT_SZ("db 01fh,");
     426                    PUT_NUM_8(pCpu->ModRM.u);
     427                    for (unsigned i = 2; i < pCpu->opsize; i++)
     428                    {
     429                        PUT_C(',');
     430                        PUT_NUM_8(0x90); ///@todo fixme.
     431                    }
     432                    pszFmt = "";
     433                }
     434                break;
     435
     436            default:
     437                /* ST(X) -> stX  (floating point) */
     438                if (*pszFmt == 'f' && strchr(pszFmt, '('))
     439                {
     440                    char *pszFmtDst = szTmpFmt;
     441                    char ch;
     442                    do
     443                    {
     444                        ch = *pszFmt++;
     445                        if (ch == 'S' && pszFmt[0] == 'T' && pszFmt[1] == '(')
     446                        {
     447                            *pszFmtDst++ = 's';
     448                            *pszFmtDst++ = 't';
     449                            pszFmt += 2;
     450                            ch = *pszFmt;
     451                            Assert(pszFmt[1] == ')');
     452                            pszFmt += 2;
     453                            *pszFmtDst++ = ch;
     454                        }
     455                        else
     456                            *pszFmtDst++ = ch;
     457                    } while (ch != '\0');
     458                    pszFmt = szTmpFmt;
     459                }
     460                break;
     461
     462            /*
     463             * Horrible hacks.
     464             */
     465            case OP_FLD:
     466                if (pCpu->opcode == 0xdb) /* m80fp workaround. */
     467                    *(int *)&pCpu->param1.param &= ~0x1f; /* make it pure OP_PARM_M */
     468                break;
     469            case OP_LAR: /* hack w -> v, probably not correct. */
     470                *(int *)&pCpu->param2.param &= ~0x1f;
     471                *(int *)&pCpu->param2.param |= OP_PARM_v;
     472                break;
     473        }
     474
     475        /*
     476         * Formatting context and associated macros.
     477         */
     478        PCOP_PARAMETER pParam = &pCpu->param1;
     479        int iParam = 1;
     480
     481#define PUT_FAR() \
     482            do { \
     483                if (    OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_p \
     484                    &&  pOp->opcode != OP_LDS /* table bugs? */ \
     485                    &&  pOp->opcode != OP_LES \
     486                    &&  pOp->opcode != OP_LFS \
     487                    &&  pOp->opcode != OP_LGS \
     488                    &&  pOp->opcode != OP_LSS ) \
     489                    PUT_SZ("far "); \
     490            } while (0)
     491        /** @todo mov ah,ch ends up with a byte 'override'... */
     492#define PUT_SIZE_OVERRIDE() \
     493            do { \
     494                switch (OP_PARM_VSUBTYPE(pParam->param)) \
     495                { \
     496                    case OP_PARM_v: \
     497                        switch (pCpu->opmode) \
     498                        { \
     499                            case CPUMODE_16BIT: PUT_SZ("word "); break; \
     500                            case CPUMODE_32BIT: PUT_SZ("dword "); break; \
     501                            case CPUMODE_64BIT: PUT_SZ("qword "); break; \
     502                            default: break; \
     503                        } \
     504                        break; \
     505                    case OP_PARM_b: PUT_SZ("byte "); break; \
     506                    case OP_PARM_w: PUT_SZ("word "); break; \
     507                    case OP_PARM_d: PUT_SZ("dword "); break; \
     508                    case OP_PARM_q: PUT_SZ("qword "); break; \
     509                    case OP_PARM_dq: \
     510                        if (OP_PARM_VTYPE(pParam->param) != OP_PARM_W) /* these are 128 bit, pray they are all unambiguous.. */ \
     511                            PUT_SZ("qword "); \
     512                        break; \
     513                    case OP_PARM_p: break; /* see PUT_FAR */ \
     514                    case OP_PARM_s: if (pParam->flags & USE_REG_FP) PUT_SZ("tword "); break; /* ?? */ \
     515                    case OP_PARM_z: break; \
     516                    case OP_PARM_NONE: \
     517                        if (    OP_PARM_VTYPE(pParam->param) == OP_PARM_M \
     518                            &&  ((pParam->flags & USE_REG_FP) || pOp->opcode == OP_FLD)) \
     519                            PUT_SZ("tword "); \
     520                        break; \
     521                    default:        break; /*no pointer type specified/necessary*/ \
     522                } \
     523            } while (0)
     524        static const char s_szSegPrefix[6][4] = { "es:", "cs:", "ss:", "ds:", "fs:", "gs:" };
     525#define PUT_SEGMENT_OVERRIDE() \
     526        do { \
     527            if (pCpu->prefix & PREFIX_SEG) \
     528                PUT_STR(s_szSegPrefix[pCpu->prefix_seg], 3); \
     529        } while (0)
     530
     531
     532        /*
     533         * The formatting loop.
     534         */
     535        char ch;
     536        while ((ch = *pszFmt++) != '\0')
     537        {
     538            if (ch == '%')
     539            {
     540                ch = *pszFmt++;
     541                switch (ch)
     542                {
     543                    /*
     544                     * ModRM - Register only.
     545                     */
     546                    case 'C': /* Control register (ParseModRM / UseModRM). */
     547                    case 'D': /* Debug register (ParseModRM / UseModRM). */
     548                    case 'G': /* ModRM selects general register (ParseModRM / UseModRM). */
     549                    case 'S': /* ModRM byte selects a segment register (ParseModRM / UseModRM). */
     550                    case 'T': /* ModRM byte selects a test register (ParseModRM / UseModRM). */
     551                    case 'V': /* ModRM byte selects an XMM/SSE register (ParseModRM / UseModRM). */
     552                    case 'P': /* ModRM byte selects MMX register (ParseModRM / UseModRM). */
     553                    {
     554                        pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
     555                        Assert(!(pParam->flags & (USE_INDEX | USE_SCALE) /* No SIB here... */));
     556                        Assert(!(pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32)));
     557
     558                        size_t cchReg;
     559                        const char *pszReg = MyDisasYasmFormatBaseReg(pCpu, pParam, &cchReg, 0 /* pCpu->addrmode == CPUMODE_16BIT */);
     560                        PUT_STR(pszReg, cchReg);
     561                        break;
     562                    }
     563
     564                    /*
     565                     * ModRM - Register or memory.
     566                     */
     567                    case 'E': /* ModRM specifies parameter (ParseModRM / UseModRM / UseSIB). */
     568                    case 'Q': /* ModRM byte selects MMX register or memory address (ParseModRM / UseModRM). */
     569                    case 'R': /* ModRM byte may only refer to a general register (ParseModRM / UseModRM). */
     570                    case 'W': /* ModRM byte selects an XMM/SSE register or a memory address (ParseModRM / UseModRM). */
     571                    case 'M': /* ModRM may only refer to memory (ParseModRM / UseModRM). */
     572                    {
     573                        pszFmt += RT_C_IS_ALPHA(pszFmt[0]) ? RT_C_IS_ALPHA(pszFmt[1]) ? 2 : 1 : 0;
     574
     575                        PUT_FAR();
     576                        if (pParam->flags & USE_EFFICIENT_ADDRESS)
     577                        {
     578                            /* Work around mov seg,[mem16]  and mov [mem16],seg as these always make a 16-bit mem
     579                               while the register variants deals with 16, 32 & 64 in the normal fashion. */
     580                            if (    pParam->param != OP_PARM_Ev
     581                                ||  pOp->opcode != OP_MOV
     582                                ||  (   pOp->param1 != OP_PARM_Sw
     583                                     && pOp->param2 != OP_PARM_Sw))
     584                                PUT_SIZE_OVERRIDE();
     585                            PUT_C('[');
     586                        }
     587                        if (pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32))
     588                        {
     589                            if (   (pParam->flags & USE_DISPLACEMENT8)
     590                                && !pParam->disp8)
     591                                PUT_SZ("byte ");
     592                            else if (   (pParam->flags & USE_DISPLACEMENT16)
     593                                     && (int8_t)pParam->disp16 == (int16_t)pParam->disp16)
     594                                PUT_SZ("word ");
     595                            else if (   (pParam->flags & USE_DISPLACEMENT32)
     596                                     && (int8_t)pParam->disp32 == (int32_t)pParam->disp32)
     597                                PUT_SZ("dword ");
     598                        }
     599                        if (pParam->flags & USE_EFFICIENT_ADDRESS)
     600                            PUT_SEGMENT_OVERRIDE();
     601
     602                        bool fBase =  (pParam->flags & USE_BASE) /* When exactly is USE_BASE supposed to be set? disasmModRMReg doesn't set it. */
     603                                   || (   (pParam->flags & (USE_REG_GEN8 | USE_REG_GEN16 | USE_REG_GEN32 | USE_REG_GEN64))
     604                                       && !(pParam->flags & USE_EFFICIENT_ADDRESS));
     605                        if (fBase)
     606                        {
     607                            size_t cchReg;
     608                            const char *pszReg = MyDisasYasmFormatBaseReg(pCpu, pParam, &cchReg, 0 /*pCpu->addrmode == CPUMODE_16BIT*/);
     609                            PUT_STR(pszReg, cchReg);
     610                        }
     611
     612                        if (pParam->flags & USE_INDEX)
     613                        {
     614                            if (fBase)
     615                                PUT_C('+');
     616
     617                            size_t cchReg;
     618                            const char *pszReg = MyDisasYasmFormatIndexReg(pCpu, pParam, &cchReg);
     619                            PUT_STR(pszReg, cchReg);
     620
     621                            if (pParam->flags & USE_SCALE)
     622                            {
     623                                PUT_C('*');
     624                                PUT_C('0' + pParam->scale);
     625                            }
     626                        }
     627                        else
     628                            Assert(!(pParam->flags & USE_SCALE));
     629
     630                        if (pParam->flags & (USE_DISPLACEMENT8 | USE_DISPLACEMENT16 | USE_DISPLACEMENT32 | USE_DISPLACEMENT64 | USE_RIPDISPLACEMENT32))
     631                        {
     632                            Assert(!(pParam->flags & USE_DISPLACEMENT64));
     633                            int32_t off;
     634                            if (pParam->flags & USE_DISPLACEMENT8)
     635                                off = pParam->disp8;
     636                            else if (pParam->flags & USE_DISPLACEMENT16)
     637                                off = pParam->disp16;
     638                            else if (pParam->flags & (USE_DISPLACEMENT32 | USE_RIPDISPLACEMENT32))
     639                                off = pParam->disp32;
     640
     641                            if (fBase || (pParam->flags & USE_INDEX))
     642                                PUT_C(off >= 0 ? '+' : '-');
     643
     644                            if (off < 0)
     645                                off = -off;
     646                            if (pParam->flags & USE_DISPLACEMENT8)
     647                                PUT_NUM_8( off);
     648                            else if (pParam->flags & USE_DISPLACEMENT16)
     649                                PUT_NUM_16(off);
     650                            else if (pParam->flags & USE_DISPLACEMENT32)
     651                                PUT_NUM_32(off);
     652                            else
     653                            {
     654                                PUT_NUM_32(off);
     655                                PUT_SZ(" wrt rip"); //??
     656                            }
     657                        }
     658
     659                        if (pParam->flags & USE_EFFICIENT_ADDRESS)
     660                            PUT_C(']');
     661                        break;
     662                    }
     663
     664                    case 'F': /* Eflags register (0 - popf/pushf only, avoided in adjustments above). */
     665                        AssertFailed();
     666                        break;
     667
     668                    case 'I': /* Immediate data (ParseImmByte, ParseImmByteSX, ParseImmV, ParseImmUshort, ParseImmZ). */
     669                        Assert(*pszFmt == 'b' || *pszFmt == 'v' || *pszFmt == 'w' || *pszFmt == 'z'); pszFmt++;
     670                        switch (pParam->flags & (  USE_IMMEDIATE8 | USE_IMMEDIATE16 | USE_IMMEDIATE32 | USE_IMMEDIATE64
     671                                                 | USE_IMMEDIATE16_SX8 | USE_IMMEDIATE32_SX8))
     672                        {
     673                            case USE_IMMEDIATE8:
     674                                if (    (pOp->param1 >= OP_PARM_REG_GEN8_START && pOp->param1 <= OP_PARM_REG_GEN8_END)
     675                                    ||  (pOp->param2 >= OP_PARM_REG_GEN8_START && pOp->param2 <= OP_PARM_REG_GEN8_END)
     676                                    )
     677                                    PUT_SZ("strict byte ");
     678                                PUT_NUM_8(pParam->parval);
     679                                break;
     680
     681                            case USE_IMMEDIATE16:
     682                                if (    (int8_t)pParam->parval == (int16_t)pParam->parval
     683                                    ||  (pOp->param1 >= OP_PARM_REG_GEN16_START && pOp->param1 <= OP_PARM_REG_GEN16_END)
     684                                    ||  (pOp->param2 >= OP_PARM_REG_GEN16_START && pOp->param2 <= OP_PARM_REG_GEN16_END)
     685                                    )
     686                                {
     687                                    if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_b)
     688                                        PUT_SZ("strict byte ");
     689                                    else if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_v)
     690                                        PUT_SZ("strict word ");
     691                                }
     692                                PUT_NUM_16(pParam->parval);
     693                                break;
     694
     695                            case USE_IMMEDIATE16_SX8:
     696                                PUT_SZ("strict byte ");
     697                                PUT_NUM_16(pParam->parval);
     698                                break;
     699
     700                            case USE_IMMEDIATE32:
     701                                if (    (int8_t)pParam->parval == (int32_t)pParam->parval
     702                                    ||  (pOp->param1 >= OP_PARM_REG_GEN32_START && pOp->param1 <= OP_PARM_REG_GEN32_END)
     703                                    ||  (pOp->param2 >= OP_PARM_REG_GEN32_START && pOp->param2 <= OP_PARM_REG_GEN32_END)
     704                                    )
     705                                {
     706                                    if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_b)
     707                                        PUT_SZ("strict byte ");
     708                                    else if (OP_PARM_VSUBTYPE(pParam->param) == OP_PARM_v)
     709                                        PUT_SZ("strict dword ");
     710                                }
     711                                PUT_NUM_32(pParam->parval);
     712                                break;
     713
     714                            case USE_IMMEDIATE32_SX8:
     715                                PUT_SZ("strict byte ");
     716                                PUT_NUM_32(pParam->parval);
     717                                break;
     718
     719                            case USE_IMMEDIATE64:
     720                                PUT_NUM_64(pParam->parval);
     721                                break;
     722
     723                            default:
     724                                AssertFailed();
     725                                break;
     726                        }
     727                        break;
     728
     729                    case 'J': /* Relative jump offset (ParseImmBRel + ParseImmVRel). */
     730                    {
     731                        int32_t offDisplacement;
     732                        Assert(iParam == 1);
     733                        bool fPrefix = pOp->opcode != OP_CALL
     734                                    && pOp->opcode != OP_LOOP
     735                                    && pOp->opcode != OP_LOOPE
     736                                    && pOp->opcode != OP_LOOPNE
     737                                    && pOp->opcode != OP_JECXZ;
     738
     739                        if (pParam->flags & USE_IMMEDIATE8_REL)
     740                        {
     741                            if (fPrefix)
     742                                PUT_SZ("short ");
     743                            offDisplacement = (int8_t)pParam->parval;
     744                            Assert(*pszFmt == 'b'); pszFmt++;
     745                        }
     746                        else if (pParam->flags & USE_IMMEDIATE16_REL)
     747                        {
     748                            if (fPrefix)
     749                                PUT_SZ("near ");
     750                            offDisplacement = (int16_t)pParam->parval;
     751                            Assert(*pszFmt == 'v'); pszFmt++;
     752                        }
     753                        else
     754                        {
     755                            if (fPrefix)
     756                                PUT_SZ("near ");
     757                            offDisplacement = (int32_t)pParam->parval;
     758                            Assert(pParam->flags & USE_IMMEDIATE32_REL);
     759                            Assert(*pszFmt == 'v'); pszFmt++;
     760                        }
     761
     762                        RTUINTPTR uTrgAddr = pCpu->opaddr + pCpu->opsize + offDisplacement;
     763                        if (pCpu->mode == CPUMODE_16BIT)
     764                            PUT_NUM_16(uTrgAddr);
     765                        else if (pCpu->mode == CPUMODE_32BIT)
     766                            PUT_NUM_32(uTrgAddr);
     767                        else
     768                            PUT_NUM_64(uTrgAddr);
     769                        break;
     770                    }
     771
     772                    case 'A': /* Direct (jump/call) address (ParseImmAddr). */
     773                        Assert(*pszFmt == 'p'); pszFmt++;
     774                        PUT_FAR();
     775                        PUT_SIZE_OVERRIDE();
     776                        PUT_SEGMENT_OVERRIDE();
     777                        switch (pParam->flags & (USE_IMMEDIATE_ADDR_16_16 | USE_IMMEDIATE_ADDR_16_32 | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16))
     778                        {
     779                            case USE_IMMEDIATE_ADDR_16_16:
     780                                PUT_NUM_16(pParam->parval >> 16);
     781                                PUT_C(':');
     782                                PUT_NUM_16(pParam->parval);
     783                                break;
     784                            case USE_IMMEDIATE_ADDR_16_32:
     785                                PUT_NUM_16(pParam->parval >> 32);
     786                                PUT_C(':');
     787                                PUT_NUM_32(pParam->parval);
     788                                break;
     789                            case USE_DISPLACEMENT16:
     790                                PUT_NUM_16(pParam->parval);
     791                                break;
     792                            case USE_DISPLACEMENT32:
     793                                PUT_NUM_32(pParam->parval);
     794                                break;
     795                            case USE_DISPLACEMENT64:
     796                                PUT_NUM_64(pParam->parval);
     797                                break;
     798                            default:
     799                                AssertFailed();
     800                                break;
     801                        }
     802                        break;
     803
     804                    case 'O': /* No ModRM byte (ParseImmAddr). */
     805                        Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
     806                        PUT_FAR();
     807                        PUT_SIZE_OVERRIDE();
     808                        PUT_C('[');
     809                        PUT_SEGMENT_OVERRIDE();
     810                        switch (pParam->flags & (USE_IMMEDIATE_ADDR_16_16 | USE_IMMEDIATE_ADDR_16_32 | USE_DISPLACEMENT64 | USE_DISPLACEMENT32 | USE_DISPLACEMENT16))
     811                        {
     812                            case USE_IMMEDIATE_ADDR_16_16:
     813                                PUT_NUM_16(pParam->parval >> 16);
     814                                PUT_C(':');
     815                                PUT_NUM_16(pParam->parval);
     816                                break;
     817                            case USE_IMMEDIATE_ADDR_16_32:
     818                                PUT_NUM_16(pParam->parval >> 32);
     819                                PUT_C(':');
     820                                PUT_NUM_32(pParam->parval);
     821                                break;
     822                            case USE_DISPLACEMENT16:
     823                                PUT_NUM_16(pParam->disp16);
     824                                break;
     825                            case USE_DISPLACEMENT32:
     826                                PUT_NUM_32(pParam->disp32);
     827                                break;
     828                            case USE_DISPLACEMENT64:
     829                                PUT_NUM_64(pParam->disp64);
     830                                break;
     831                            default:
     832                                AssertFailed();
     833                                break;
     834                        }
     835                        PUT_C(']');
     836                        break;
     837
     838                    case 'X': /* DS:SI (ParseXb, ParseXv). */
     839                    case 'Y': /* ES:DI (ParseYb, ParseYv). */
     840                    {
     841                        Assert(*pszFmt == 'b' || *pszFmt == 'v'); pszFmt++;
     842                        PUT_FAR();
     843                        PUT_SIZE_OVERRIDE();
     844                        PUT_C('[');
     845                        if (pParam->flags & USE_POINTER_DS_BASED)
     846                            PUT_SZ("ds:");
     847                        else
     848                            PUT_SZ("es:");
     849
     850                        size_t cchReg;
     851                        const char *pszReg = MyDisasYasmFormatBaseReg(pCpu, pParam, &cchReg, 0);
     852                        PUT_STR(pszReg, cchReg);
     853                        PUT_C(']');
     854                        break;
     855                    }
     856
     857                    case 'e': /* Register based on operand size (e.g. %eAX) (ParseFixedReg). */
     858                    {
     859                        Assert(RT_C_IS_ALPHA(pszFmt[0]) && RT_C_IS_ALPHA(pszFmt[1]) && !RT_C_IS_ALPHA(pszFmt[2])); pszFmt += 2;
     860                        size_t cchReg;
     861                        const char *pszReg = MyDisasYasmFormatBaseReg(pCpu, pParam, &cchReg, 0);
     862                        PUT_STR(pszReg, cchReg);
     863                        break;
     864                    }
     865
     866                    default:
     867                        AssertMsgFailed(("%c%s!\n", ch, pszFmt));
     868                        break;
     869                }
     870                AssertMsg(*pszFmt == ',' || *pszFmt == '\0', ("%c%s\n", ch, pszFmt));
     871            }
     872            else
     873            {
     874                PUT_C(ch);
     875                if (ch == ',')
     876                {
     877                    Assert(*pszFmt != ' ');
     878                    PUT_C(' ');
     879                    switch (++iParam)
     880                    {
     881                        case 2: pParam = &pCpu->param2; break;
     882                        case 3: pParam = &pCpu->param3; break;
     883                        default: pParam = NULL; break;
     884                    }
     885                }
     886            }
     887        } /* while more to format */
     888    }
     889
     890
     891    /* Terminate it - on overflow we'll have reserved one byte for this. */
     892    if (cchDst > 0)
     893        *pszDst = '\0';
     894
     895    /* clean up macros */
     896#undef PUT_PSZ
     897#undef PUT_SZ
     898#undef PUT_STR
     899#undef PUT_C
     900    return cchOutput;
     901}
     902#endif
     903
     904
    57905/**
    58906 * Default style.
     
    73921static void MyDisasYasmFormatter(PMYDISSTATE pState)
    74922{
     923    char szTmp[256];
     924#ifndef USE_MY_FORMATTER
    75925    /* a very quick hack. */
    76     char szTmp[256];
    77926    strcpy(szTmp, RTStrStripL(strchr(pState->szLine, ':') + 1));
    78927
     
    90939    *pszEnd = '\0';
    91940
    92     RTPrintf("    %s ; %s", szTmp, pState->szLine);
     941#else  /* USE_MY_FORMATTER */
     942    size_t cch = MyDisasYasmFormat(&pState->Cpu, szTmp, sizeof(szTmp));
     943    Assert(cch < sizeof(szTmp));
     944    while (cch < 71)
     945        szTmp[cch++] = ' ';
     946    szTmp[cch] = '\0';
     947#endif /* USE_MY_FORMATTER */
     948
     949    RTPrintf("    %s ; %08llu %s", szTmp, pState->uAddress, pState->szLine);
     950}
     951
     952
     953/**
     954 * Checks if the encoding of the current instruction is something
     955 * we can never get the assembler to produce.
     956 *
     957 * @returns true if it's odd, false if it isn't.
     958 * @param   pCpu        The disassembler output.
     959 */
     960static bool MyDisasYasmFormatterIsOddEncoding(PMYDISSTATE pState)
     961{
     962    /*
     963     * Mod rm + SIB: Check for duplicate EBP encodings that yasm won't use for very good reasons.
     964     */
     965    if (    pState->Cpu.addrmode != CPUMODE_16BIT ///@todo correct?
     966        &&  pState->Cpu.ModRM.Bits.Rm == 4
     967        &&  pState->Cpu.ModRM.Bits.Mod != 3)
     968    {
     969        /* No scaled index SIB (index=4), except for ESP. */
     970        if (    pState->Cpu.SIB.Bits.Index == 4
     971            &&  pState->Cpu.SIB.Bits.Base != 4)
     972            return true;
     973
     974        /* EBP + displacement */
     975        if (    pState->Cpu.ModRM.Bits.Mod != 0
     976             && pState->Cpu.SIB.Bits.Base == 5
     977             && pState->Cpu.SIB.Bits.Scale == 0)
     978            return true;
     979    }
     980
     981    /*
     982     * Seems to be an instruction alias here, but I cannot find any docs on it... hrmpf!
     983     */
     984    if (    pState->Cpu.pCurInstr->opcode == OP_SHL
     985        &&  pState->Cpu.ModRM.Bits.Reg == 6)
     986        return true;
     987
     988    /*
     989     * Check for multiple prefixes of the same kind.
     990     */
     991    bool fSegmentPrefix = false;
     992    bool fLockPrefix = false;
     993    bool fAddressSize = false;
     994    bool fOperandSize = false;
     995    bool fRepPrefix = false;
     996    bool fRex = false;
     997    for (uint8_t const *pu8 = pState->pbInstr;; pu8++)
     998    {
     999        bool *pf;
     1000        switch (*pu8)
     1001        {
     1002            case 0xf0:
     1003                pf = &fLockPrefix;
     1004                break;
     1005
     1006            case 0xf2:
     1007            case 0xf3:
     1008                pf = &fRepPrefix;
     1009                break;
     1010
     1011            case 0x2e:
     1012            case 0x3e:
     1013            case 0x26:
     1014            case 0x36:
     1015            case 0x64:
     1016            case 0x65:
     1017                pf = &fSegmentPrefix;
     1018                break;
     1019
     1020            case 0x66:
     1021                pf = &fOperandSize;
     1022                break;
     1023
     1024            case 0x67:
     1025                pf = &fAddressSize;
     1026                break;
     1027
     1028            case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47:
     1029            case 0x48: case 0x49: case 0x4a: case 0x4b: case 0x4c: case 0x4d: case 0x4e: case 0x4f:
     1030                pf = pState->Cpu.mode == CPUMODE_64BIT ? &fRex : NULL;
     1031                break;
     1032
     1033            default:
     1034                pf = NULL;
     1035                break;
     1036        }
     1037        if (!pf)
     1038            break; /* done */
     1039        if (*pf)
     1040            return true;
     1041        *pf = true;
     1042    }
     1043
     1044    /* segment overrides are fun */
     1045    if (fSegmentPrefix)
     1046    {
     1047        /* no efficient address which it may apply to. */
     1048        Assert((pState->Cpu.prefix & PREFIX_SEG) || pState->Cpu.mode == CPUMODE_64BIT);
     1049        if (    !(pState->Cpu.param1.flags & USE_EFFICIENT_ADDRESS)
     1050            &&  !(pState->Cpu.param2.flags & USE_EFFICIENT_ADDRESS)
     1051            &&  !(pState->Cpu.param3.flags & USE_EFFICIENT_ADDRESS))
     1052            return true;
     1053    }
     1054
     1055    /* fixed register + addr override doesn't go down all that well. */
     1056    if (fAddressSize)
     1057    {
     1058        Assert(pState->Cpu.prefix & PREFIX_ADDRSIZE);
     1059        if (    pState->Cpu.pCurInstr->param3 == OP_PARM_NONE
     1060            &&  pState->Cpu.pCurInstr->param2 == OP_PARM_NONE
     1061            &&  (   pState->Cpu.pCurInstr->param1 >= OP_PARM_REG_GEN32_START
     1062                 && pState->Cpu.pCurInstr->param1 <= OP_PARM_REG_GEN32_END))
     1063            return true;
     1064    }
     1065
     1066
     1067    /* check for the version of xyz reg,reg instruction that the assembler doesn't use.
     1068        expected: 1aee   sbb ch, dh     ; SBB r8, r/m8
     1069        yasm:     18F5   sbb ch, dh     ; SBB r/m8, r8 */
     1070    if (pState->Cpu.ModRM.Bits.Mod == 3 /* reg,reg */)
     1071    {
     1072        switch (pState->Cpu.pCurInstr->opcode)
     1073        {
     1074            case OP_ADC:
     1075            case OP_ADD:
     1076            case OP_AND:
     1077            case OP_OR:
     1078            case OP_SUB:
     1079            case OP_SBB:
     1080            case OP_XOR:
     1081                if (    (    pState->Cpu.pCurInstr->param1 == OP_PARM_Gb /* r8 */
     1082                         && pState->Cpu.pCurInstr->param2 == OP_PARM_Eb /* r8/mem8 */)
     1083                    ||  (    pState->Cpu.pCurInstr->param1 == OP_PARM_Gv /* rX */
     1084                         && pState->Cpu.pCurInstr->param2 == OP_PARM_Ev /* rX/memX */))
     1085                    return true;
     1086                break;
     1087
     1088            /* ff /0, fe /0, ff /1, fe /0 */
     1089            case OP_DEC:
     1090            case OP_INC:
     1091                return true;
     1092
     1093            default:
     1094                break;
     1095        }
     1096    }
     1097
     1098    /* check for REX.X = 1 without SIB. */
     1099
     1100    /* Yasm encodes setnbe al with /2 instead of /0 like the AMD manual
     1101       says (intel doesn't appear to care). */
     1102    switch (pState->Cpu.pCurInstr->opcode)
     1103    {
     1104        case OP_SETO:
     1105        case OP_SETNO:
     1106        case OP_SETC:
     1107        case OP_SETNC:
     1108        case OP_SETE:
     1109        case OP_SETNE:
     1110        case OP_SETBE:
     1111        case OP_SETNBE:
     1112        case OP_SETS:
     1113        case OP_SETNS:
     1114        case OP_SETP:
     1115        case OP_SETNP:
     1116        case OP_SETL:
     1117        case OP_SETNL:
     1118        case OP_SETLE:
     1119        case OP_SETNLE:
     1120            AssertMsg(pState->Cpu.opcode >= 0x90 && pState->Cpu.opcode <= 0x9f, ("%#x\n", pState->Cpu.opcode));
     1121            if (pState->Cpu.ModRM.Bits.Reg != 2)
     1122                return true;
     1123            break;
     1124    }
     1125
     1126    return false;
    931127}
    941128
     
    1051139
    1061140
     1141/**
     1142 * This is a temporary workaround for catching a few illegal opcodes
     1143 * that the disassembler is currently letting thru, just enough to make
     1144 * the assemblers happy.
     1145 *
     1146 * We're too close to a release to dare mess with these things now as
     1147 * they may consequences for performance and let alone introduce bugs.
     1148 *
     1149 * @returns true if it's valid. false if it isn't.
     1150 *
     1151 * @param   pCpu        The disassembler output.
     1152 */
     1153static bool MyDisasIsValidInstruction(DISCPUSTATE const *pCpu)
     1154{
     1155    switch (pCpu->pCurInstr->opcode)
     1156    {
     1157        /* These doesn't take memory operands. */
     1158        case OP_MOV_CR:
     1159        case OP_MOV_DR:
     1160        case OP_MOV_TR:
     1161            if (pCpu->ModRM.Bits.Mod != 3)
     1162                return false;
     1163            break;
     1164
     1165         /* The 0x8f /0 variant of this instruction doesn't get its /r value verified. */
     1166        case OP_POP:
     1167            if (    pCpu->opcode == 0x8f
     1168                &&  pCpu->ModRM.Bits.Reg != 0)
     1169                return false;
     1170            break;
     1171
     1172        /* The 0xc6 /0 and 0xc7 /0 variants of this instruction don't get their /r values verified. */
     1173        case OP_MOV:
     1174            if (    (   pCpu->opcode == 0xc6
     1175                     || pCpu->opcode == 0xc7)
     1176                &&  pCpu->ModRM.Bits.Reg != 0)
     1177                return false;
     1178            break;
     1179
     1180        default:
     1181            break;
     1182    }
     1183
     1184    return true;
     1185}
     1186
    1071187
    1081188/**
    1091189 * Callback for reading bytes.
     1190 *
     1191 * @todo This should check that the disassembler doesn't do unnecessary reads,
     1192 *       however the current doesn't do this and is just complicated...
    1101193 */
    1111194static DECLCALLBACK(int) MyDisasInstrRead(RTUINTPTR uSrcAddr, uint8_t *pbDst, uint32_t cbRead, void *pvDisCpu)
     
    2671350
    2681351        int rc = DISInstr(&State.Cpu, State.uAddress, 0, &State.cbInstr, State.szLine);
    269         if (RT_SUCCESS(rc))
    270         {
    271             State.fUndefOp = State.Cpu.pCurInstr->opcode == OP_INVALID
    272                           || State.Cpu.pCurInstr->opcode == OP_ILLUD2;
    273             if (!State.fUndefOp && State.enmUndefOp == kUndefOp_All)
     1352        if (    RT_SUCCESS(rc)
     1353            ||  (   (   rc == VERR_DIS_INVALID_OPCODE
     1354                     || rc == VERR_DIS_GEN_FAILURE)
     1355                 &&  State.enmUndefOp == kUndefOp_DefineByte))
     1356        {
     1357            State.fUndefOp = rc == VERR_DIS_INVALID_OPCODE
     1358                          || rc == VERR_DIS_GEN_FAILURE
     1359                          || State.Cpu.pCurInstr->opcode == OP_INVALID
     1360                          || State.Cpu.pCurInstr->opcode == OP_ILLUD2
     1361                          || (    State.enmUndefOp == kUndefOp_DefineByte
     1362                              && !MyDisasIsValidInstruction(&State.Cpu));
     1363            if (State.fUndefOp && State.enmUndefOp == kUndefOp_DefineByte)
     1364            {
     1365                RTPrintf("    db");
     1366                if (!State.cbInstr)
     1367                    State.cbInstr = 1;
     1368                for (unsigned off = 0; off < State.cbInstr; off++)
     1369                {
     1370                    uint8_t b;
     1371                    State.Cpu.pfnReadBytes(State.uAddress + off, &b, 1, &State.Cpu);
     1372                    RTPrintf(off ? ", %03xh" : " %03xh", b);
     1373                }
     1374                RTPrintf("    ; %s\n", State.szLine);
     1375            }
     1376            else if (!State.fUndefOp && State.enmUndefOp == kUndefOp_All)
    2741377            {
    2751378                RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode);
     
    2841387            }
    2851388            else
     1389            {
     1390                /* Use db for odd encodings that we can't make the assembler use. */
     1391                if (    State.enmUndefOp == kUndefOp_DefineByte
     1392                    &&  MyDisasYasmFormatterIsOddEncoding(&State))
     1393                {
     1394                    RTPrintf("    db");
     1395                    for (unsigned off = 0; off < State.cbInstr; off++)
     1396                    {
     1397                        uint8_t b;
     1398                        State.Cpu.pfnReadBytes(State.uAddress + off, &b, 1, &State.Cpu);
     1399                        RTPrintf(off ? ", %03xh" : " %03xh", b);
     1400                    }
     1401                    RTPrintf(" ; ");
     1402                }
     1403
    2861404                pfnFormatter(&State);
     1405            }
    2871406        }
    2881407        else
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette