1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "disassembler_x86.h" 18 19 #include <inttypes.h> 20 21 #include <ostream> 22 #include <sstream> 23 24 #include "base/logging.h" 25 #include "base/stringprintf.h" 26 #include "thread.h" 27 28 namespace art { 29 namespace x86 { 30 31 size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) { 32 return DumpInstruction(os, begin); 33 } 34 35 void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { 36 size_t length = 0; 37 for (const uint8_t* cur = begin; cur < end; cur += length) { 38 length = DumpInstruction(os, cur); 39 } 40 } 41 42 static const char* gReg8Names[] = { 43 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 44 }; 45 static const char* gExtReg8Names[] = { 46 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", 47 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l" 48 }; 49 static const char* gReg16Names[] = { 50 "ax", "cx", "dx", "bx", "sp", "bp", "si", "di", 51 "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w" 52 }; 53 static const char* gReg32Names[] = { 54 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", 55 "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d" 56 }; 57 static const char* gReg64Names[] = { 58 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", 59 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" 60 }; 61 62 // 64-bit opcode REX modifier. 63 constexpr uint8_t REX_W = 8U /* 0b1000 */; 64 constexpr uint8_t REX_R = 4U /* 0b0100 */; 65 constexpr uint8_t REX_X = 2U /* 0b0010 */; 66 constexpr uint8_t REX_B = 1U /* 0b0001 */; 67 68 static void DumpReg0(std::ostream& os, uint8_t rex, size_t reg, 69 bool byte_operand, uint8_t size_override) { 70 DCHECK_LT(reg, (rex == 0) ? 8u : 16u); 71 bool rex_w = (rex & REX_W) != 0; 72 if (byte_operand) { 73 os << ((rex == 0) ? gReg8Names[reg] : gExtReg8Names[reg]); 74 } else if (rex_w) { 75 os << gReg64Names[reg]; 76 } else if (size_override == 0x66) { 77 os << gReg16Names[reg]; 78 } else { 79 os << gReg32Names[reg]; 80 } 81 } 82 83 static void DumpAnyReg(std::ostream& os, uint8_t rex, size_t reg, 84 bool byte_operand, uint8_t size_override, RegFile reg_file) { 85 if (reg_file == GPR) { 86 DumpReg0(os, rex, reg, byte_operand, size_override); 87 } else if (reg_file == SSE) { 88 os << "xmm" << reg; 89 } else { 90 os << "mm" << reg; 91 } 92 } 93 94 static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg, 95 bool byte_operand, uint8_t size_override, RegFile reg_file) { 96 bool rex_r = (rex & REX_R) != 0; 97 size_t reg_num = rex_r ? (reg + 8) : reg; 98 DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file); 99 } 100 101 static void DumpRmReg(std::ostream& os, uint8_t rex, uint8_t reg, 102 bool byte_operand, uint8_t size_override, RegFile reg_file) { 103 bool rex_b = (rex & REX_B) != 0; 104 size_t reg_num = rex_b ? (reg + 8) : reg; 105 DumpAnyReg(os, rex, reg_num, byte_operand, size_override, reg_file); 106 } 107 108 static void DumpAddrReg(std::ostream& os, uint8_t rex, uint8_t reg) { 109 if (rex != 0) { 110 os << gReg64Names[reg]; 111 } else { 112 os << gReg32Names[reg]; 113 } 114 } 115 116 static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) { 117 bool rex_b = (rex & REX_B) != 0; 118 size_t reg_num = rex_b ? (reg + 8) : reg; 119 DumpAddrReg(os, rex, reg_num); 120 } 121 122 static void DumpOpcodeReg(std::ostream& os, uint8_t rex, uint8_t reg, 123 bool byte_operand, uint8_t size_override) { 124 bool rex_b = (rex & REX_B) != 0; 125 size_t reg_num = rex_b ? (reg + 8) : reg; 126 DumpReg0(os, rex, reg_num, byte_operand, size_override); 127 } 128 129 enum SegmentPrefix { 130 kCs = 0x2e, 131 kSs = 0x36, 132 kDs = 0x3e, 133 kEs = 0x26, 134 kFs = 0x64, 135 kGs = 0x65, 136 }; 137 138 static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) { 139 switch (segment_prefix) { 140 case kCs: os << "cs:"; break; 141 case kSs: os << "ss:"; break; 142 case kDs: os << "ds:"; break; 143 case kEs: os << "es:"; break; 144 case kFs: os << "fs:"; break; 145 case kGs: os << "gs:"; break; 146 default: break; 147 } 148 } 149 150 // Do not inline to avoid Clang stack frame problems. b/18733806 151 NO_INLINE 152 static std::string DumpCodeHex(const uint8_t* begin, const uint8_t* end) { 153 std::stringstream hex; 154 for (size_t i = 0; begin + i < end; ++i) { 155 hex << StringPrintf("%02X", begin[i]); 156 } 157 return hex.str(); 158 } 159 160 std::string DisassemblerX86::DumpAddress(uint8_t mod, uint8_t rm, uint8_t rex64, uint8_t rex_w, 161 bool no_ops, bool byte_operand, bool byte_second_operand, 162 uint8_t* prefix, bool load, RegFile src_reg_file, 163 RegFile dst_reg_file, const uint8_t** instr, 164 uint32_t* address_bits) { 165 std::ostringstream address; 166 if (mod == 0 && rm == 5) { 167 if (!supports_rex_) { // Absolute address. 168 *address_bits = *reinterpret_cast<const uint32_t*>(*instr); 169 address << StringPrintf("[0x%x]", *address_bits); 170 } else { // 64-bit RIP relative addressing. 171 address << StringPrintf("[RIP + 0x%x]", *reinterpret_cast<const uint32_t*>(*instr)); 172 } 173 (*instr) += 4; 174 } else if (rm == 4 && mod != 3) { // SIB 175 uint8_t sib = **instr; 176 (*instr)++; 177 uint8_t scale = (sib >> 6) & 3; 178 uint8_t index = (sib >> 3) & 7; 179 uint8_t base = sib & 7; 180 address << "["; 181 182 // REX.x is bit 3 of index. 183 if ((rex64 & REX_X) != 0) { 184 index += 8; 185 } 186 187 // Mod = 0 && base = 5 (ebp): no base (ignores REX.b). 188 bool has_base = false; 189 if (base != 5 || mod != 0) { 190 has_base = true; 191 DumpBaseReg(address, rex64, base); 192 } 193 194 // Index = 4 (esp/rsp) is disallowed. 195 if (index != 4) { 196 if (has_base) { 197 address << " + "; 198 } 199 DumpAddrReg(address, rex64, index); 200 if (scale != 0) { 201 address << StringPrintf(" * %d", 1 << scale); 202 } 203 } 204 205 if (mod == 0) { 206 if (base == 5) { 207 if (index != 4) { 208 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr)); 209 } else { 210 // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit. 211 *address_bits = *reinterpret_cast<const uint32_t*>(*instr); 212 address << StringPrintf("%d", *address_bits); 213 } 214 (*instr) += 4; 215 } 216 } else if (mod == 1) { 217 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr)); 218 (*instr)++; 219 } else if (mod == 2) { 220 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr)); 221 (*instr) += 4; 222 } 223 address << "]"; 224 } else { 225 if (mod == 3) { 226 if (!no_ops) { 227 DumpRmReg(address, rex_w, rm, byte_operand || byte_second_operand, 228 prefix[2], load ? src_reg_file : dst_reg_file); 229 } 230 } else { 231 address << "["; 232 DumpBaseReg(address, rex64, rm); 233 if (mod == 1) { 234 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(*instr)); 235 (*instr)++; 236 } else if (mod == 2) { 237 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(*instr)); 238 (*instr) += 4; 239 } 240 address << "]"; 241 } 242 } 243 return address.str(); 244 } 245 246 size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) { 247 const uint8_t* begin_instr = instr; 248 bool have_prefixes = true; 249 uint8_t prefix[4] = {0, 0, 0, 0}; 250 do { 251 switch (*instr) { 252 // Group 1 - lock and repeat prefixes: 253 case 0xF0: 254 case 0xF2: 255 case 0xF3: 256 prefix[0] = *instr; 257 break; 258 // Group 2 - segment override prefixes: 259 case kCs: 260 case kSs: 261 case kDs: 262 case kEs: 263 case kFs: 264 case kGs: 265 prefix[1] = *instr; 266 break; 267 // Group 3 - operand size override: 268 case 0x66: 269 prefix[2] = *instr; 270 break; 271 // Group 4 - address size override: 272 case 0x67: 273 prefix[3] = *instr; 274 break; 275 default: 276 have_prefixes = false; 277 break; 278 } 279 if (have_prefixes) { 280 instr++; 281 } 282 } while (have_prefixes); 283 uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0; 284 if (rex != 0) { 285 instr++; 286 } 287 const char** modrm_opcodes = nullptr; 288 bool has_modrm = false; 289 bool reg_is_opcode = false; 290 size_t immediate_bytes = 0; 291 size_t branch_bytes = 0; 292 std::string opcode_tmp; // Storage to keep StringPrintf result alive. 293 const char* opcode0 = ""; // Prefix part. 294 const char* opcode1 = ""; // Main opcode. 295 const char* opcode2 = ""; // Sub-opcode. E.g., jump type. 296 const char* opcode3 = ""; // Mod-rm part. 297 const char* opcode4 = ""; // Suffix part. 298 bool store = false; // stores to memory (ie rm is on the left) 299 bool load = false; // loads from memory (ie rm is on the right) 300 bool byte_operand = false; // true when the opcode is dealing with byte operands 301 // true when the source operand is a byte register but the target register isn't 302 // (ie movsxb/movzxb). 303 bool byte_second_operand = false; 304 bool target_specific = false; // register name depends on target (64 vs 32 bits). 305 bool ax = false; // implicit use of ax 306 bool cx = false; // implicit use of cx 307 bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter 308 bool no_ops = false; 309 RegFile src_reg_file = GPR; 310 RegFile dst_reg_file = GPR; 311 switch (*instr) { 312 #define DISASSEMBLER_ENTRY(opname, \ 313 rm8_r8, rm32_r32, \ 314 r8_rm8, r32_rm32, \ 315 ax8_i8, ax32_i32) \ 316 case rm8_r8: opcode1 = #opname; store = true; has_modrm = true; byte_operand = true; break; \ 317 case rm32_r32: opcode1 = #opname; store = true; has_modrm = true; break; \ 318 case r8_rm8: opcode1 = #opname; load = true; has_modrm = true; byte_operand = true; break; \ 319 case r32_rm32: opcode1 = #opname; load = true; has_modrm = true; break; \ 320 case ax8_i8: opcode1 = #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \ 321 case ax32_i32: opcode1 = #opname; ax = true; immediate_bytes = 4; break; 322 323 DISASSEMBLER_ENTRY(add, 324 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */, 325 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */, 326 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */) 327 DISASSEMBLER_ENTRY(or, 328 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */, 329 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */, 330 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */) 331 DISASSEMBLER_ENTRY(adc, 332 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */, 333 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */, 334 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */) 335 DISASSEMBLER_ENTRY(sbb, 336 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */, 337 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */, 338 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */) 339 DISASSEMBLER_ENTRY(and, 340 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */, 341 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */, 342 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */) 343 DISASSEMBLER_ENTRY(sub, 344 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */, 345 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */, 346 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */) 347 DISASSEMBLER_ENTRY(xor, 348 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */, 349 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */, 350 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */) 351 DISASSEMBLER_ENTRY(cmp, 352 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */, 353 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */, 354 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */) 355 356 #undef DISASSEMBLER_ENTRY 357 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 358 opcode1 = "push"; 359 reg_in_opcode = true; 360 target_specific = true; 361 break; 362 case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: 363 opcode1 = "pop"; 364 reg_in_opcode = true; 365 target_specific = true; 366 break; 367 case 0x63: 368 if ((rex & REX_W) != 0) { 369 opcode1 = "movsxd"; 370 has_modrm = true; 371 load = true; 372 } else { 373 // In 32-bit mode (!supports_rex_) this is ARPL, with no REX prefix the functionality is the 374 // same as 'mov' but the use of the instruction is discouraged. 375 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr); 376 opcode1 = opcode_tmp.c_str(); 377 } 378 break; 379 case 0x68: opcode1 = "push"; immediate_bytes = 4; break; 380 case 0x69: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 4; break; 381 case 0x6A: opcode1 = "push"; immediate_bytes = 1; break; 382 case 0x6B: opcode1 = "imul"; load = true; has_modrm = true; immediate_bytes = 1; break; 383 case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: 384 case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: 385 static const char* condition_codes[] = 386 {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a", 387 "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g" 388 }; 389 opcode1 = "j"; 390 opcode2 = condition_codes[*instr & 0xF]; 391 branch_bytes = 1; 392 break; 393 case 0x86: case 0x87: 394 opcode1 = "xchg"; 395 store = true; 396 has_modrm = true; 397 byte_operand = (*instr == 0x86); 398 break; 399 case 0x88: opcode1 = "mov"; store = true; has_modrm = true; byte_operand = true; break; 400 case 0x89: opcode1 = "mov"; store = true; has_modrm = true; break; 401 case 0x8A: opcode1 = "mov"; load = true; has_modrm = true; byte_operand = true; break; 402 case 0x8B: opcode1 = "mov"; load = true; has_modrm = true; break; 403 404 case 0x0F: // 2 byte extended opcode 405 instr++; 406 switch (*instr) { 407 case 0x10: case 0x11: 408 if (prefix[0] == 0xF2) { 409 opcode1 = "movsd"; 410 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 411 } else if (prefix[0] == 0xF3) { 412 opcode1 = "movss"; 413 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 414 } else if (prefix[2] == 0x66) { 415 opcode1 = "movupd"; 416 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 417 } else { 418 opcode1 = "movups"; 419 } 420 has_modrm = true; 421 src_reg_file = dst_reg_file = SSE; 422 load = *instr == 0x10; 423 store = !load; 424 break; 425 case 0x12: case 0x13: 426 if (prefix[2] == 0x66) { 427 opcode1 = "movlpd"; 428 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 429 } else if (prefix[0] == 0) { 430 opcode1 = "movlps"; 431 } 432 has_modrm = true; 433 src_reg_file = dst_reg_file = SSE; 434 load = *instr == 0x12; 435 store = !load; 436 break; 437 case 0x16: case 0x17: 438 if (prefix[2] == 0x66) { 439 opcode1 = "movhpd"; 440 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 441 } else if (prefix[0] == 0) { 442 opcode1 = "movhps"; 443 } 444 has_modrm = true; 445 src_reg_file = dst_reg_file = SSE; 446 load = *instr == 0x16; 447 store = !load; 448 break; 449 case 0x28: case 0x29: 450 if (prefix[2] == 0x66) { 451 opcode1 = "movapd"; 452 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 453 } else if (prefix[0] == 0) { 454 opcode1 = "movaps"; 455 } 456 has_modrm = true; 457 src_reg_file = dst_reg_file = SSE; 458 load = *instr == 0x28; 459 store = !load; 460 break; 461 case 0x2A: 462 if (prefix[2] == 0x66) { 463 opcode1 = "cvtpi2pd"; 464 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 465 } else if (prefix[0] == 0xF2) { 466 opcode1 = "cvtsi2sd"; 467 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 468 } else if (prefix[0] == 0xF3) { 469 opcode1 = "cvtsi2ss"; 470 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 471 } else { 472 opcode1 = "cvtpi2ps"; 473 } 474 load = true; 475 has_modrm = true; 476 dst_reg_file = SSE; 477 break; 478 case 0x2C: 479 if (prefix[2] == 0x66) { 480 opcode1 = "cvttpd2pi"; 481 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 482 } else if (prefix[0] == 0xF2) { 483 opcode1 = "cvttsd2si"; 484 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 485 } else if (prefix[0] == 0xF3) { 486 opcode1 = "cvttss2si"; 487 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 488 } else { 489 opcode1 = "cvttps2pi"; 490 } 491 load = true; 492 has_modrm = true; 493 src_reg_file = SSE; 494 break; 495 case 0x2D: 496 if (prefix[2] == 0x66) { 497 opcode1 = "cvtpd2pi"; 498 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 499 } else if (prefix[0] == 0xF2) { 500 opcode1 = "cvtsd2si"; 501 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 502 } else if (prefix[0] == 0xF3) { 503 opcode1 = "cvtss2si"; 504 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 505 } else { 506 opcode1 = "cvtps2pi"; 507 } 508 load = true; 509 has_modrm = true; 510 src_reg_file = SSE; 511 break; 512 case 0x2E: 513 opcode0 = "u"; 514 FALLTHROUGH_INTENDED; 515 case 0x2F: 516 if (prefix[2] == 0x66) { 517 opcode1 = "comisd"; 518 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 519 } else { 520 opcode1 = "comiss"; 521 } 522 has_modrm = true; 523 load = true; 524 src_reg_file = dst_reg_file = SSE; 525 break; 526 case 0x38: // 3 byte extended opcode 527 instr++; 528 if (prefix[2] == 0x66) { 529 switch (*instr) { 530 case 0x01: 531 opcode1 = "phaddw"; 532 prefix[2] = 0; 533 has_modrm = true; 534 load = true; 535 src_reg_file = dst_reg_file = SSE; 536 break; 537 case 0x02: 538 opcode1 = "phaddd"; 539 prefix[2] = 0; 540 has_modrm = true; 541 load = true; 542 src_reg_file = dst_reg_file = SSE; 543 break; 544 case 0x40: 545 opcode1 = "pmulld"; 546 prefix[2] = 0; 547 has_modrm = true; 548 load = true; 549 src_reg_file = dst_reg_file = SSE; 550 break; 551 default: 552 opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr); 553 opcode1 = opcode_tmp.c_str(); 554 } 555 } else { 556 opcode_tmp = StringPrintf("unknown opcode '0F 38 %02X'", *instr); 557 opcode1 = opcode_tmp.c_str(); 558 } 559 break; 560 case 0x3A: // 3 byte extended opcode 561 instr++; 562 if (prefix[2] == 0x66) { 563 switch (*instr) { 564 case 0x0A: 565 opcode1 = "roundss"; 566 prefix[2] = 0; 567 has_modrm = true; 568 store = true; 569 src_reg_file = SSE; 570 dst_reg_file = SSE; 571 immediate_bytes = 1; 572 break; 573 case 0x0B: 574 opcode1 = "roundsd"; 575 prefix[2] = 0; 576 has_modrm = true; 577 store = true; 578 src_reg_file = SSE; 579 dst_reg_file = SSE; 580 immediate_bytes = 1; 581 break; 582 case 0x14: 583 opcode1 = "pextrb"; 584 prefix[2] = 0; 585 has_modrm = true; 586 store = true; 587 src_reg_file = SSE; 588 immediate_bytes = 1; 589 break; 590 case 0x15: 591 opcode1 = "pextrw"; 592 prefix[2] = 0; 593 has_modrm = true; 594 store = true; 595 src_reg_file = SSE; 596 immediate_bytes = 1; 597 break; 598 case 0x16: 599 opcode1 = "pextrd"; 600 prefix[2] = 0; 601 has_modrm = true; 602 store = true; 603 src_reg_file = SSE; 604 immediate_bytes = 1; 605 break; 606 default: 607 opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr); 608 opcode1 = opcode_tmp.c_str(); 609 } 610 } else { 611 opcode_tmp = StringPrintf("unknown opcode '0F 3A %02X'", *instr); 612 opcode1 = opcode_tmp.c_str(); 613 } 614 break; 615 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: 616 case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: 617 opcode1 = "cmov"; 618 opcode2 = condition_codes[*instr & 0xF]; 619 has_modrm = true; 620 load = true; 621 break; 622 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 623 case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { 624 switch (*instr) { 625 case 0x50: opcode1 = "movmsk"; break; 626 case 0x51: opcode1 = "sqrt"; break; 627 case 0x52: opcode1 = "rsqrt"; break; 628 case 0x53: opcode1 = "rcp"; break; 629 case 0x54: opcode1 = "and"; break; 630 case 0x55: opcode1 = "andn"; break; 631 case 0x56: opcode1 = "or"; break; 632 case 0x57: opcode1 = "xor"; break; 633 case 0x58: opcode1 = "add"; break; 634 case 0x59: opcode1 = "mul"; break; 635 case 0x5C: opcode1 = "sub"; break; 636 case 0x5D: opcode1 = "min"; break; 637 case 0x5E: opcode1 = "div"; break; 638 case 0x5F: opcode1 = "max"; break; 639 default: LOG(FATAL) << "Unreachable"; UNREACHABLE(); 640 } 641 if (prefix[2] == 0x66) { 642 opcode2 = "pd"; 643 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 644 } else if (prefix[0] == 0xF2) { 645 opcode2 = "sd"; 646 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 647 } else if (prefix[0] == 0xF3) { 648 opcode2 = "ss"; 649 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 650 } else { 651 opcode2 = "ps"; 652 } 653 load = true; 654 has_modrm = true; 655 src_reg_file = dst_reg_file = SSE; 656 break; 657 } 658 case 0x5A: 659 if (prefix[2] == 0x66) { 660 opcode1 = "cvtpd2ps"; 661 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 662 } else if (prefix[0] == 0xF2) { 663 opcode1 = "cvtsd2ss"; 664 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 665 } else if (prefix[0] == 0xF3) { 666 opcode1 = "cvtss2sd"; 667 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 668 } else { 669 opcode1 = "cvtps2pd"; 670 } 671 load = true; 672 has_modrm = true; 673 src_reg_file = dst_reg_file = SSE; 674 break; 675 case 0x5B: 676 if (prefix[2] == 0x66) { 677 opcode1 = "cvtps2dq"; 678 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 679 } else if (prefix[0] == 0xF2) { 680 opcode1 = "bad opcode F2 0F 5B"; 681 } else if (prefix[0] == 0xF3) { 682 opcode1 = "cvttps2dq"; 683 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 684 } else { 685 opcode1 = "cvtdq2ps"; 686 } 687 load = true; 688 has_modrm = true; 689 src_reg_file = dst_reg_file = SSE; 690 break; 691 case 0x60: case 0x61: case 0x62: case 0x6C: 692 if (prefix[2] == 0x66) { 693 src_reg_file = dst_reg_file = SSE; 694 prefix[2] = 0; // Clear prefix now. It has served its purpose as part of the opcode. 695 } else { 696 src_reg_file = dst_reg_file = MMX; 697 } 698 switch (*instr) { 699 case 0x60: opcode1 = "punpcklbw"; break; 700 case 0x61: opcode1 = "punpcklwd"; break; 701 case 0x62: opcode1 = "punpckldq"; break; 702 case 0x6c: opcode1 = "punpcklqdq"; break; 703 } 704 load = true; 705 has_modrm = true; 706 break; 707 case 0x6E: 708 if (prefix[2] == 0x66) { 709 dst_reg_file = SSE; 710 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 711 } else { 712 dst_reg_file = MMX; 713 } 714 opcode1 = "movd"; 715 load = true; 716 has_modrm = true; 717 break; 718 case 0x6F: 719 if (prefix[2] == 0x66) { 720 src_reg_file = dst_reg_file = SSE; 721 opcode1 = "movdqa"; 722 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 723 } else if (prefix[0] == 0xF3) { 724 src_reg_file = dst_reg_file = SSE; 725 opcode1 = "movdqu"; 726 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 727 } else { 728 dst_reg_file = MMX; 729 opcode1 = "movq"; 730 } 731 load = true; 732 has_modrm = true; 733 break; 734 case 0x70: 735 if (prefix[2] == 0x66) { 736 opcode1 = "pshufd"; 737 prefix[2] = 0; 738 has_modrm = true; 739 store = true; 740 src_reg_file = dst_reg_file = SSE; 741 immediate_bytes = 1; 742 } else if (prefix[0] == 0xF2) { 743 opcode1 = "pshuflw"; 744 prefix[0] = 0; 745 has_modrm = true; 746 store = true; 747 src_reg_file = dst_reg_file = SSE; 748 immediate_bytes = 1; 749 } else { 750 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr); 751 opcode1 = opcode_tmp.c_str(); 752 } 753 break; 754 case 0x71: 755 if (prefix[2] == 0x66) { 756 dst_reg_file = SSE; 757 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 758 } else { 759 dst_reg_file = MMX; 760 } 761 static const char* x71_opcodes[] = { 762 "unknown-71", "unknown-71", "psrlw", "unknown-71", 763 "psraw", "unknown-71", "psllw", "unknown-71"}; 764 modrm_opcodes = x71_opcodes; 765 reg_is_opcode = true; 766 has_modrm = true; 767 store = true; 768 immediate_bytes = 1; 769 break; 770 case 0x72: 771 if (prefix[2] == 0x66) { 772 dst_reg_file = SSE; 773 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 774 } else { 775 dst_reg_file = MMX; 776 } 777 static const char* x72_opcodes[] = { 778 "unknown-72", "unknown-72", "psrld", "unknown-72", 779 "psrad", "unknown-72", "pslld", "unknown-72"}; 780 modrm_opcodes = x72_opcodes; 781 reg_is_opcode = true; 782 has_modrm = true; 783 store = true; 784 immediate_bytes = 1; 785 break; 786 case 0x73: 787 if (prefix[2] == 0x66) { 788 dst_reg_file = SSE; 789 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 790 } else { 791 dst_reg_file = MMX; 792 } 793 static const char* x73_opcodes[] = { 794 "unknown-73", "unknown-73", "psrlq", "psrldq", 795 "unknown-73", "unknown-73", "psllq", "unknown-73"}; 796 modrm_opcodes = x73_opcodes; 797 reg_is_opcode = true; 798 has_modrm = true; 799 store = true; 800 immediate_bytes = 1; 801 break; 802 case 0x7C: 803 if (prefix[0] == 0xF2) { 804 opcode1 = "haddps"; 805 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 806 } else if (prefix[2] == 0x66) { 807 opcode1 = "haddpd"; 808 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 809 } else { 810 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr); 811 opcode1 = opcode_tmp.c_str(); 812 break; 813 } 814 src_reg_file = dst_reg_file = SSE; 815 has_modrm = true; 816 load = true; 817 break; 818 case 0x7E: 819 if (prefix[2] == 0x66) { 820 src_reg_file = SSE; 821 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 822 } else { 823 src_reg_file = MMX; 824 } 825 opcode1 = "movd"; 826 has_modrm = true; 827 store = true; 828 break; 829 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: 830 case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: 831 opcode1 = "j"; 832 opcode2 = condition_codes[*instr & 0xF]; 833 branch_bytes = 4; 834 break; 835 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: 836 case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: 837 opcode1 = "set"; 838 opcode2 = condition_codes[*instr & 0xF]; 839 modrm_opcodes = nullptr; 840 reg_is_opcode = true; 841 has_modrm = true; 842 store = true; 843 break; 844 case 0xA4: 845 opcode1 = "shld"; 846 has_modrm = true; 847 load = true; 848 immediate_bytes = 1; 849 break; 850 case 0xA5: 851 opcode1 = "shld"; 852 has_modrm = true; 853 load = true; 854 cx = true; 855 break; 856 case 0xAC: 857 opcode1 = "shrd"; 858 has_modrm = true; 859 load = true; 860 immediate_bytes = 1; 861 break; 862 case 0xAD: 863 opcode1 = "shrd"; 864 has_modrm = true; 865 load = true; 866 cx = true; 867 break; 868 case 0xAE: 869 if (prefix[0] == 0xF3) { 870 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 871 static const char* xAE_opcodes[] = { 872 "rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", 873 "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"}; 874 modrm_opcodes = xAE_opcodes; 875 reg_is_opcode = true; 876 has_modrm = true; 877 uint8_t reg_or_opcode = (instr[1] >> 3) & 7; 878 switch (reg_or_opcode) { 879 case 0: 880 prefix[1] = kFs; 881 load = true; 882 break; 883 case 1: 884 prefix[1] = kGs; 885 load = true; 886 break; 887 case 2: 888 prefix[1] = kFs; 889 store = true; 890 break; 891 case 3: 892 prefix[1] = kGs; 893 store = true; 894 break; 895 default: 896 load = true; 897 break; 898 } 899 } else { 900 static const char* xAE_opcodes[] = { 901 "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", 902 "unknown-AE", "lfence", "mfence", "sfence"}; 903 modrm_opcodes = xAE_opcodes; 904 reg_is_opcode = true; 905 has_modrm = true; 906 load = true; 907 no_ops = true; 908 } 909 break; 910 case 0xAF: 911 opcode1 = "imul"; 912 has_modrm = true; 913 load = true; 914 break; 915 case 0xB1: 916 opcode1 = "cmpxchg"; 917 has_modrm = true; 918 store = true; 919 break; 920 case 0xB6: 921 opcode1 = "movzxb"; 922 has_modrm = true; 923 load = true; 924 byte_second_operand = true; 925 break; 926 case 0xB7: 927 opcode1 = "movzxw"; 928 has_modrm = true; 929 load = true; 930 break; 931 case 0xBE: 932 opcode1 = "movsxb"; 933 has_modrm = true; 934 load = true; 935 byte_second_operand = true; 936 rex |= (rex == 0 ? 0 : REX_W); 937 break; 938 case 0xBF: 939 opcode1 = "movsxw"; 940 has_modrm = true; 941 load = true; 942 break; 943 case 0xC3: 944 opcode1 = "movnti"; 945 store = true; 946 has_modrm = true; 947 break; 948 case 0xC5: 949 if (prefix[2] == 0x66) { 950 opcode1 = "pextrw"; 951 prefix[2] = 0; 952 has_modrm = true; 953 load = true; 954 src_reg_file = SSE; 955 immediate_bytes = 1; 956 } else { 957 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr); 958 opcode1 = opcode_tmp.c_str(); 959 } 960 break; 961 case 0xC6: 962 if (prefix[2] == 0x66) { 963 opcode1 = "shufpd"; 964 prefix[2] = 0; 965 } else { 966 opcode1 = "shufps"; 967 } 968 has_modrm = true; 969 store = true; 970 src_reg_file = dst_reg_file = SSE; 971 immediate_bytes = 1; 972 break; 973 case 0xC7: 974 static const char* x0FxC7_opcodes[] = { 975 "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", 976 "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7"}; 977 modrm_opcodes = x0FxC7_opcodes; 978 has_modrm = true; 979 reg_is_opcode = true; 980 store = true; 981 break; 982 case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: 983 opcode1 = "bswap"; 984 reg_in_opcode = true; 985 break; 986 case 0xD4: 987 if (prefix[2] == 0x66) { 988 src_reg_file = dst_reg_file = SSE; 989 prefix[2] = 0; 990 } else { 991 src_reg_file = dst_reg_file = MMX; 992 } 993 opcode1 = "paddq"; 994 prefix[2] = 0; 995 has_modrm = true; 996 load = true; 997 break; 998 case 0xDB: 999 if (prefix[2] == 0x66) { 1000 src_reg_file = dst_reg_file = SSE; 1001 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 1002 } else { 1003 src_reg_file = dst_reg_file = MMX; 1004 } 1005 opcode1 = "pand"; 1006 prefix[2] = 0; 1007 has_modrm = true; 1008 load = true; 1009 break; 1010 case 0xD5: 1011 if (prefix[2] == 0x66) { 1012 opcode1 = "pmullw"; 1013 prefix[2] = 0; 1014 has_modrm = true; 1015 load = true; 1016 src_reg_file = dst_reg_file = SSE; 1017 } else { 1018 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr); 1019 opcode1 = opcode_tmp.c_str(); 1020 } 1021 break; 1022 case 0xEB: 1023 if (prefix[2] == 0x66) { 1024 src_reg_file = dst_reg_file = SSE; 1025 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 1026 } else { 1027 src_reg_file = dst_reg_file = MMX; 1028 } 1029 opcode1 = "por"; 1030 prefix[2] = 0; 1031 has_modrm = true; 1032 load = true; 1033 break; 1034 case 0xEF: 1035 if (prefix[2] == 0x66) { 1036 src_reg_file = dst_reg_file = SSE; 1037 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 1038 } else { 1039 src_reg_file = dst_reg_file = MMX; 1040 } 1041 opcode1 = "pxor"; 1042 prefix[2] = 0; 1043 has_modrm = true; 1044 load = true; 1045 break; 1046 case 0xF4: 1047 case 0xF6: 1048 case 0xF8: 1049 case 0xF9: 1050 case 0xFA: 1051 case 0xFB: 1052 case 0xFC: 1053 case 0xFD: 1054 case 0xFE: 1055 if (prefix[2] == 0x66) { 1056 src_reg_file = dst_reg_file = SSE; 1057 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 1058 } else { 1059 src_reg_file = dst_reg_file = MMX; 1060 } 1061 switch (*instr) { 1062 case 0xF4: opcode1 = "pmuludq"; break; 1063 case 0xF6: opcode1 = "psadbw"; break; 1064 case 0xF8: opcode1 = "psubb"; break; 1065 case 0xF9: opcode1 = "psubw"; break; 1066 case 0xFA: opcode1 = "psubd"; break; 1067 case 0xFB: opcode1 = "psubq"; break; 1068 case 0xFC: opcode1 = "paddb"; break; 1069 case 0xFD: opcode1 = "paddw"; break; 1070 case 0xFE: opcode1 = "paddd"; break; 1071 } 1072 prefix[2] = 0; 1073 has_modrm = true; 1074 load = true; 1075 break; 1076 default: 1077 opcode_tmp = StringPrintf("unknown opcode '0F %02X'", *instr); 1078 opcode1 = opcode_tmp.c_str(); 1079 break; 1080 } 1081 break; 1082 case 0x80: case 0x81: case 0x82: case 0x83: 1083 static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; 1084 modrm_opcodes = x80_opcodes; 1085 has_modrm = true; 1086 reg_is_opcode = true; 1087 store = true; 1088 byte_operand = (*instr & 1) == 0; 1089 immediate_bytes = *instr == 0x81 ? 4 : 1; 1090 break; 1091 case 0x84: case 0x85: 1092 opcode1 = "test"; 1093 has_modrm = true; 1094 load = true; 1095 byte_operand = (*instr & 1) == 0; 1096 break; 1097 case 0x8D: 1098 opcode1 = "lea"; 1099 has_modrm = true; 1100 load = true; 1101 break; 1102 case 0x8F: 1103 opcode1 = "pop"; 1104 has_modrm = true; 1105 reg_is_opcode = true; 1106 store = true; 1107 break; 1108 case 0x99: 1109 opcode1 = "cdq"; 1110 break; 1111 case 0x9B: 1112 if (instr[1] == 0xDF && instr[2] == 0xE0) { 1113 opcode1 = "fstsw\tax"; 1114 instr += 2; 1115 } else { 1116 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr); 1117 opcode1 = opcode_tmp.c_str(); 1118 } 1119 break; 1120 case 0xAF: 1121 opcode1 = (prefix[2] == 0x66 ? "scasw" : "scasl"); 1122 break; 1123 case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: 1124 opcode1 = "mov"; 1125 immediate_bytes = 1; 1126 byte_operand = true; 1127 reg_in_opcode = true; 1128 byte_operand = true; 1129 break; 1130 case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: 1131 if ((rex & REX_W) != 0) { 1132 opcode1 = "movabsq"; 1133 immediate_bytes = 8; 1134 reg_in_opcode = true; 1135 break; 1136 } 1137 opcode1 = "mov"; 1138 immediate_bytes = 4; 1139 reg_in_opcode = true; 1140 break; 1141 case 0xC0: case 0xC1: 1142 case 0xD0: case 0xD1: case 0xD2: case 0xD3: 1143 static const char* shift_opcodes[] = 1144 {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"}; 1145 modrm_opcodes = shift_opcodes; 1146 has_modrm = true; 1147 reg_is_opcode = true; 1148 store = true; 1149 immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0; 1150 cx = (*instr == 0xD2) || (*instr == 0xD3); 1151 byte_operand = (*instr == 0xC0); 1152 break; 1153 case 0xC3: opcode1 = "ret"; break; 1154 case 0xC6: 1155 static const char* c6_opcodes[] = {"mov", "unknown-c6", "unknown-c6", 1156 "unknown-c6", "unknown-c6", "unknown-c6", 1157 "unknown-c6", "unknown-c6"}; 1158 modrm_opcodes = c6_opcodes; 1159 store = true; 1160 immediate_bytes = 1; 1161 has_modrm = true; 1162 reg_is_opcode = true; 1163 byte_operand = true; 1164 break; 1165 case 0xC7: 1166 static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", 1167 "unknown-c7", "unknown-c7", "unknown-c7", 1168 "unknown-c7", "unknown-c7"}; 1169 modrm_opcodes = c7_opcodes; 1170 store = true; 1171 immediate_bytes = 4; 1172 has_modrm = true; 1173 reg_is_opcode = true; 1174 break; 1175 case 0xCC: opcode1 = "int 3"; break; 1176 case 0xD9: 1177 if (instr[1] == 0xF8) { 1178 opcode1 = "fprem"; 1179 instr++; 1180 } else { 1181 static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw", 1182 "fnstenv", "fnstcw"}; 1183 modrm_opcodes = d9_opcodes; 1184 store = true; 1185 has_modrm = true; 1186 reg_is_opcode = true; 1187 } 1188 break; 1189 case 0xDA: 1190 if (instr[1] == 0xE9) { 1191 opcode1 = "fucompp"; 1192 instr++; 1193 } else { 1194 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr); 1195 opcode1 = opcode_tmp.c_str(); 1196 } 1197 break; 1198 case 0xDB: 1199 static const char* db_opcodes[] = {"fildl", "unknown-db", "unknown-db", 1200 "unknown-db", "unknown-db", "unknown-db", 1201 "unknown-db", "unknown-db"}; 1202 modrm_opcodes = db_opcodes; 1203 load = true; 1204 has_modrm = true; 1205 reg_is_opcode = true; 1206 break; 1207 case 0xDD: 1208 static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl", 1209 "fstpl", "frstor", "unknown-dd", 1210 "fnsave", "fnstsw"}; 1211 modrm_opcodes = dd_opcodes; 1212 store = true; 1213 has_modrm = true; 1214 reg_is_opcode = true; 1215 break; 1216 case 0xDF: 1217 static const char* df_opcodes[] = {"fild", "unknown-df", "unknown-df", 1218 "unknown-df", "unknown-df", "fildll", 1219 "unknown-df", "unknown-df"}; 1220 modrm_opcodes = df_opcodes; 1221 load = true; 1222 has_modrm = true; 1223 reg_is_opcode = true; 1224 break; 1225 case 0xE3: opcode1 = "jecxz"; branch_bytes = 1; break; 1226 case 0xE8: opcode1 = "call"; branch_bytes = 4; break; 1227 case 0xE9: opcode1 = "jmp"; branch_bytes = 4; break; 1228 case 0xEB: opcode1 = "jmp"; branch_bytes = 1; break; 1229 case 0xF5: opcode1 = "cmc"; break; 1230 case 0xF6: case 0xF7: 1231 static const char* f7_opcodes[] = { 1232 "test", "unknown-f7", "not", "neg", "mul edx:eax, eax *", 1233 "imul edx:eax, eax *", "div edx:eax, edx:eax /", 1234 "idiv edx:eax, edx:eax /"}; 1235 modrm_opcodes = f7_opcodes; 1236 has_modrm = true; 1237 reg_is_opcode = true; 1238 store = true; 1239 immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; 1240 break; 1241 case 0xFF: 1242 { 1243 static const char* ff_opcodes[] = { 1244 "inc", "dec", "call", "call", 1245 "jmp", "jmp", "push", "unknown-ff"}; 1246 modrm_opcodes = ff_opcodes; 1247 has_modrm = true; 1248 reg_is_opcode = true; 1249 load = true; 1250 const uint8_t opcode_digit = (instr[1] >> 3) & 7; 1251 // 'call', 'jmp' and 'push' are target specific instructions 1252 if (opcode_digit == 2 || opcode_digit == 4 || opcode_digit == 6) { 1253 target_specific = true; 1254 } 1255 } 1256 break; 1257 default: 1258 opcode_tmp = StringPrintf("unknown opcode '%02X'", *instr); 1259 opcode1 = opcode_tmp.c_str(); 1260 break; 1261 } 1262 std::ostringstream args; 1263 // We force the REX prefix to be available for 64-bit target 1264 // in order to dump addr (base/index) registers correctly. 1265 uint8_t rex64 = supports_rex_ ? (rex | 0x40) : rex; 1266 // REX.W should be forced for 64-target and target-specific instructions (i.e., push or pop). 1267 uint8_t rex_w = (supports_rex_ && target_specific) ? (rex | 0x48) : rex; 1268 if (reg_in_opcode) { 1269 DCHECK(!has_modrm); 1270 DumpOpcodeReg(args, rex_w, *instr & 0x7, byte_operand, prefix[2]); 1271 } 1272 instr++; 1273 uint32_t address_bits = 0; 1274 if (has_modrm) { 1275 uint8_t modrm = *instr; 1276 instr++; 1277 uint8_t mod = modrm >> 6; 1278 uint8_t reg_or_opcode = (modrm >> 3) & 7; 1279 uint8_t rm = modrm & 7; 1280 std::string address = DumpAddress(mod, rm, rex64, rex_w, no_ops, byte_operand, 1281 byte_second_operand, prefix, load, src_reg_file, dst_reg_file, 1282 &instr, &address_bits); 1283 1284 if (reg_is_opcode && modrm_opcodes != nullptr) { 1285 opcode3 = modrm_opcodes[reg_or_opcode]; 1286 } 1287 1288 // Add opcode suffixes to indicate size. 1289 if (byte_operand) { 1290 opcode4 = "b"; 1291 } else if ((rex & REX_W) != 0) { 1292 opcode4 = "q"; 1293 } else if (prefix[2] == 0x66) { 1294 opcode4 = "w"; 1295 } 1296 1297 if (load) { 1298 if (!reg_is_opcode) { 1299 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file); 1300 args << ", "; 1301 } 1302 DumpSegmentOverride(args, prefix[1]); 1303 args << address; 1304 } else { 1305 DCHECK(store); 1306 DumpSegmentOverride(args, prefix[1]); 1307 args << address; 1308 if (!reg_is_opcode) { 1309 args << ", "; 1310 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file); 1311 } 1312 } 1313 } 1314 if (ax) { 1315 // If this opcode implicitly uses ax, ax is always the first arg. 1316 DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR); 1317 } 1318 if (cx) { 1319 args << ", "; 1320 DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR); 1321 } 1322 if (immediate_bytes > 0) { 1323 if (has_modrm || reg_in_opcode || ax || cx) { 1324 args << ", "; 1325 } 1326 if (immediate_bytes == 1) { 1327 args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr)); 1328 instr++; 1329 } else if (immediate_bytes == 4) { 1330 if (prefix[2] == 0x66) { // Operand size override from 32-bit to 16-bit. 1331 args << StringPrintf("%d", *reinterpret_cast<const int16_t*>(instr)); 1332 instr += 2; 1333 } else { 1334 args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr)); 1335 instr += 4; 1336 } 1337 } else { 1338 CHECK_EQ(immediate_bytes, 8u); 1339 args << StringPrintf("%" PRId64, *reinterpret_cast<const int64_t*>(instr)); 1340 instr += 8; 1341 } 1342 } else if (branch_bytes > 0) { 1343 DCHECK(!has_modrm); 1344 int32_t displacement; 1345 if (branch_bytes == 1) { 1346 displacement = *reinterpret_cast<const int8_t*>(instr); 1347 instr++; 1348 } else { 1349 CHECK_EQ(branch_bytes, 4u); 1350 displacement = *reinterpret_cast<const int32_t*>(instr); 1351 instr += 4; 1352 } 1353 args << StringPrintf("%+d (", displacement) 1354 << FormatInstructionPointer(instr + displacement) 1355 << ")"; 1356 } 1357 if (prefix[1] == kFs && !supports_rex_) { 1358 args << " ; "; 1359 Thread::DumpThreadOffset<4>(args, address_bits); 1360 } 1361 if (prefix[1] == kGs && supports_rex_) { 1362 args << " ; "; 1363 Thread::DumpThreadOffset<8>(args, address_bits); 1364 } 1365 const char* prefix_str; 1366 switch (prefix[0]) { 1367 case 0xF0: prefix_str = "lock "; break; 1368 case 0xF2: prefix_str = "repne "; break; 1369 case 0xF3: prefix_str = "repe "; break; 1370 case 0: prefix_str = ""; break; 1371 default: LOG(FATAL) << "Unreachable"; UNREACHABLE(); 1372 } 1373 os << FormatInstructionPointer(begin_instr) 1374 << StringPrintf(": %22s \t%-7s%s%s%s%s%s ", DumpCodeHex(begin_instr, instr).c_str(), 1375 prefix_str, opcode0, opcode1, opcode2, opcode3, opcode4) 1376 << args.str() << '\n'; 1377 return instr - begin_instr; 1378 } // NOLINT(readability/fn_size) 1379 1380 } // namespace x86 1381 } // namespace art 1382