Changeset 9098 in vbox for trunk/src/VBox
- Timestamp:
- May 25, 2008 10:16:58 PM (17 years ago)
- Location:
- trunk/src/VBox/Disassembler/testcase
- Files:
-
- 6 added
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Disassembler/testcase/Makefile.kmk
r8989 r9098 37 37 VBOX_DISAS_TESTS_BUILD = \ 38 38 tstAsmLock-1.asm \ 39 tstAsmMovSeg-1.asm \ 40 tstAsmMovzx-1.asm \ 41 tstAsmPop-1.asm \ 42 tstAsmPush-1.asm \ 43 tstAsmSignExtend-1.asm \ 39 44 40 45 # Tests that only contains invalid/undefined instructions. … … 42 47 tstAsmLock-2.asm \ 43 48 tstAsmLock-3.asm 49 50 # Tests that will be disassembled and re-build from disassembly (list of binaries). 51 VBOX_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) 44 55 45 56 … … 120 131 $(CMP) $(@:.tst=.bin) $< 121 132 @$(APPEND) $@ "done" 122 @$(ECHO) " PASSED: $(<F) [re-assembled]"133 @$(ECHO) " PASSED: $(<F) [re-assembled]" 123 134 124 135 … … 132 143 $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(INSTARGET_tstDisasm-2) --undef-op=all --cpumode=16 $< 133 144 @$(APPEND) $@ "done" 134 @$(ECHO) " PASSED: $(@F) [--undef-op=all]"145 @$(ECHO) " PASSED: $(@F) [--undef-op=all]" 135 146 136 147 $(addprefix $(VBOX_DISAS_TEST_PATH)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-32.tst)): $$(patsubst %.tst,%.bin,$$@) $$(INSTARGET_tstDisasm-2) | $$(call DIRDEP,$$(@D)) … … 139 150 $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(INSTARGET_tstDisasm-2) --undef-op=all --cpumode=32 $< 140 151 @$(APPEND) $@ "done" 141 @$(ECHO) " PASSED: $(@F) [--undef-op=all]"152 @$(ECHO) " PASSED: $(@F) [--undef-op=all]" 142 153 143 154 $(addprefix $(VBOX_DISAS_TEST_PATH)/, $(VBOX_DISAS_TESTS_INVALID:.asm=-64.tst)): $$(patsubst %.tst,%.bin,$$@) $$(INSTARGET_tstDisasm-2) | $$(call DIRDEP,$$(@D)) … … 146 157 $(REDIRECT) -E VBOX_LOG_DEST=nofile -- $(INSTARGET_tstDisasm-2) --undef-op=all --cpumode=64 $< 147 158 @$(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. 163 define 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 180 VBOX_DISAS_TEST_CLEAN += $(outbase).tst $(outbase).bin $(outbase).asm 181 endef # def_vbox_disas_binary_rules 182 183 define def_vbox_disas_binary 184 local name := $(notdir $(basename $(binary))) 185 local name := $(notdir $(basename $(binary))) 186 local outbase := $(VBOX_DISAS_TEST_PATH)/$(name)-rebuild-$(bits) 187 $(eval $(def_vbox_disas_binary_rules)) 188 endef # 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 149 194 150 195 # Add the .tst to the clean up. -
trunk/src/VBox/Disassembler/testcase/tstDisasm-2.cpp
r8986 r9098 29 29 #include <iprt/string.h> 30 30 #include <iprt/runtime.h> 31 #include <iprt/err.h> 31 #include <VBox/err.h> 32 #include <iprt/ctype.h> 32 33 33 34 … … 35 36 * Structures and Typedefs * 36 37 *******************************************************************************/ 37 typedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_ invalid } ASMSTYLE;38 typedef enum { kAsmStyle_Default, kAsmStyle_yasm, kAsmStyle_masm, kAsmStyle_gas, kAsmStyle_invalid } ASMSTYLE; 38 39 typedef enum { kUndefOp_Fail, kUndefOp_All, kUndefOp_DefineByte, kUndefOp_End } UNDEFOPHANDLING; 39 40 … … 55 56 56 57 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 68 static 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 }; 72 static 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 }; 76 static 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 }; 80 static 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 }; 84 static 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 }; 88 static 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 }; 92 static const char g_aszYasmRegSeg[6][3] = 93 { 94 "es", "cs", "ss", "ds", "fs", "gs" 95 }; 96 static const char g_aszYasmRegFP[8][4] = 97 { 98 "st0", "st1", "st2", "st3", "st4", "st5", "st6", "st7" 99 }; 100 static const char g_aszYasmRegMMX[8][4] = 101 { 102 "mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7" 103 }; 104 static 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 }; 108 static 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 }; 112 static 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 }; 116 static 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 122 DECLINLINE(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 236 DECLINLINE(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 271 static 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 57 905 /** 58 906 * Default style. … … 73 921 static void MyDisasYasmFormatter(PMYDISSTATE pState) 74 922 { 923 char szTmp[256]; 924 #ifndef USE_MY_FORMATTER 75 925 /* a very quick hack. */ 76 char szTmp[256];77 926 strcpy(szTmp, RTStrStripL(strchr(pState->szLine, ':') + 1)); 78 927 … … 90 939 *pszEnd = '\0'; 91 940 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 */ 960 static 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; 93 1127 } 94 1128 … … 105 1139 106 1140 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 */ 1153 static 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 107 1187 108 1188 /** 109 1189 * 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... 110 1193 */ 111 1194 static DECLCALLBACK(int) MyDisasInstrRead(RTUINTPTR uSrcAddr, uint8_t *pbDst, uint32_t cbRead, void *pvDisCpu) … … 267 1350 268 1351 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) 274 1377 { 275 1378 RTPrintf("%s: error at %#RX64: unexpected valid instruction (op=%d)\n", argv0, State.uAddress, State.Cpu.pCurInstr->opcode); … … 284 1387 } 285 1388 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 286 1404 pfnFormatter(&State); 1405 } 287 1406 } 288 1407 else
Note:
See TracChangeset
for help on using the changeset viewer.