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