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 25 namespace art { 26 namespace x86 { 27 28 DisassemblerX86::DisassemblerX86() {} 29 30 size_t DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin) { 31 return DumpInstruction(os, begin); 32 } 33 34 void DisassemblerX86::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) { 35 size_t length = 0; 36 for (const uint8_t* cur = begin; cur < end; cur += length) { 37 length = DumpInstruction(os, cur); 38 } 39 } 40 41 static const char* gReg8Names[] = { "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" }; 42 static const char* gReg16Names[] = { "ax", "cx", "dx", "bx", "sp", "bp", "si", "di" }; 43 static const char* gReg32Names[] = { "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" }; 44 45 static void DumpReg0(std::ostream& os, uint8_t /*rex*/, size_t reg, 46 bool byte_operand, uint8_t size_override) { 47 DCHECK_LT(reg, 8u); 48 // TODO: combine rex into size 49 size_t size = byte_operand ? 1 : (size_override == 0x66 ? 2 : 4); 50 switch (size) { 51 case 1: os << gReg8Names[reg]; break; 52 case 2: os << gReg16Names[reg]; break; 53 case 4: os << gReg32Names[reg]; break; 54 default: LOG(FATAL) << "unexpected size " << size; 55 } 56 } 57 58 enum RegFile { GPR, MMX, SSE }; 59 60 static void DumpReg(std::ostream& os, uint8_t rex, uint8_t reg, 61 bool byte_operand, uint8_t size_override, RegFile reg_file) { 62 size_t reg_num = reg; // TODO: combine with REX.R on 64bit 63 if (reg_file == GPR) { 64 DumpReg0(os, rex, reg_num, byte_operand, size_override); 65 } else if (reg_file == SSE) { 66 os << "xmm" << reg_num; 67 } else { 68 os << "mm" << reg_num; 69 } 70 } 71 72 static void DumpBaseReg(std::ostream& os, uint8_t rex, uint8_t reg) { 73 size_t reg_num = reg; // TODO: combine with REX.B on 64bit 74 DumpReg0(os, rex, reg_num, false, 0); 75 } 76 77 static void DumpIndexReg(std::ostream& os, uint8_t rex, uint8_t reg) { 78 int reg_num = reg; // TODO: combine with REX.X on 64bit 79 DumpReg0(os, rex, reg_num, false, 0); 80 } 81 82 enum SegmentPrefix { 83 kCs = 0x2e, 84 kSs = 0x36, 85 kDs = 0x3e, 86 kEs = 0x26, 87 kFs = 0x64, 88 kGs = 0x65, 89 }; 90 91 static void DumpSegmentOverride(std::ostream& os, uint8_t segment_prefix) { 92 switch (segment_prefix) { 93 case kCs: os << "cs:"; break; 94 case kSs: os << "ss:"; break; 95 case kDs: os << "ds:"; break; 96 case kEs: os << "es:"; break; 97 case kFs: os << "fs:"; break; 98 case kGs: os << "gs:"; break; 99 default: break; 100 } 101 } 102 103 size_t DisassemblerX86::DumpInstruction(std::ostream& os, const uint8_t* instr) { 104 const uint8_t* begin_instr = instr; 105 bool have_prefixes = true; 106 uint8_t prefix[4] = {0, 0, 0, 0}; 107 const char** modrm_opcodes = NULL; 108 do { 109 switch (*instr) { 110 // Group 1 - lock and repeat prefixes: 111 case 0xF0: 112 case 0xF2: 113 case 0xF3: 114 prefix[0] = *instr; 115 break; 116 // Group 2 - segment override prefixes: 117 case kCs: 118 case kSs: 119 case kDs: 120 case kEs: 121 case kFs: 122 case kGs: 123 prefix[1] = *instr; 124 break; 125 // Group 3 - operand size override: 126 case 0x66: 127 prefix[2] = *instr; 128 break; 129 // Group 4 - address size override: 130 case 0x67: 131 prefix[3] = *instr; 132 break; 133 default: 134 have_prefixes = false; 135 break; 136 } 137 if (have_prefixes) { 138 instr++; 139 } 140 } while (have_prefixes); 141 uint8_t rex = (*instr >= 0x40 && *instr <= 0x4F) ? *instr : 0; 142 bool has_modrm = false; 143 bool reg_is_opcode = false; 144 size_t immediate_bytes = 0; 145 size_t branch_bytes = 0; 146 std::ostringstream opcode; 147 bool store = false; // stores to memory (ie rm is on the left) 148 bool load = false; // loads from memory (ie rm is on the right) 149 bool byte_operand = false; 150 bool ax = false; // implicit use of ax 151 bool cx = false; // implicit use of cx 152 bool reg_in_opcode = false; // low 3-bits of opcode encode register parameter 153 bool no_ops = false; 154 RegFile src_reg_file = GPR; 155 RegFile dst_reg_file = GPR; 156 switch (*instr) { 157 #define DISASSEMBLER_ENTRY(opname, \ 158 rm8_r8, rm32_r32, \ 159 r8_rm8, r32_rm32, \ 160 ax8_i8, ax32_i32) \ 161 case rm8_r8: opcode << #opname; store = true; has_modrm = true; byte_operand = true; break; \ 162 case rm32_r32: opcode << #opname; store = true; has_modrm = true; break; \ 163 case r8_rm8: opcode << #opname; load = true; has_modrm = true; byte_operand = true; break; \ 164 case r32_rm32: opcode << #opname; load = true; has_modrm = true; break; \ 165 case ax8_i8: opcode << #opname; ax = true; immediate_bytes = 1; byte_operand = true; break; \ 166 case ax32_i32: opcode << #opname; ax = true; immediate_bytes = 4; break; 167 168 DISASSEMBLER_ENTRY(add, 169 0x00 /* RegMem8/Reg8 */, 0x01 /* RegMem32/Reg32 */, 170 0x02 /* Reg8/RegMem8 */, 0x03 /* Reg32/RegMem32 */, 171 0x04 /* Rax8/imm8 opcode */, 0x05 /* Rax32/imm32 */) 172 DISASSEMBLER_ENTRY(or, 173 0x08 /* RegMem8/Reg8 */, 0x09 /* RegMem32/Reg32 */, 174 0x0A /* Reg8/RegMem8 */, 0x0B /* Reg32/RegMem32 */, 175 0x0C /* Rax8/imm8 opcode */, 0x0D /* Rax32/imm32 */) 176 DISASSEMBLER_ENTRY(adc, 177 0x10 /* RegMem8/Reg8 */, 0x11 /* RegMem32/Reg32 */, 178 0x12 /* Reg8/RegMem8 */, 0x13 /* Reg32/RegMem32 */, 179 0x14 /* Rax8/imm8 opcode */, 0x15 /* Rax32/imm32 */) 180 DISASSEMBLER_ENTRY(sbb, 181 0x18 /* RegMem8/Reg8 */, 0x19 /* RegMem32/Reg32 */, 182 0x1A /* Reg8/RegMem8 */, 0x1B /* Reg32/RegMem32 */, 183 0x1C /* Rax8/imm8 opcode */, 0x1D /* Rax32/imm32 */) 184 DISASSEMBLER_ENTRY(and, 185 0x20 /* RegMem8/Reg8 */, 0x21 /* RegMem32/Reg32 */, 186 0x22 /* Reg8/RegMem8 */, 0x23 /* Reg32/RegMem32 */, 187 0x24 /* Rax8/imm8 opcode */, 0x25 /* Rax32/imm32 */) 188 DISASSEMBLER_ENTRY(sub, 189 0x28 /* RegMem8/Reg8 */, 0x29 /* RegMem32/Reg32 */, 190 0x2A /* Reg8/RegMem8 */, 0x2B /* Reg32/RegMem32 */, 191 0x2C /* Rax8/imm8 opcode */, 0x2D /* Rax32/imm32 */) 192 DISASSEMBLER_ENTRY(xor, 193 0x30 /* RegMem8/Reg8 */, 0x31 /* RegMem32/Reg32 */, 194 0x32 /* Reg8/RegMem8 */, 0x33 /* Reg32/RegMem32 */, 195 0x34 /* Rax8/imm8 opcode */, 0x35 /* Rax32/imm32 */) 196 DISASSEMBLER_ENTRY(cmp, 197 0x38 /* RegMem8/Reg8 */, 0x39 /* RegMem32/Reg32 */, 198 0x3A /* Reg8/RegMem8 */, 0x3B /* Reg32/RegMem32 */, 199 0x3C /* Rax8/imm8 opcode */, 0x3D /* Rax32/imm32 */) 200 201 #undef DISASSEMBLER_ENTRY 202 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 203 opcode << "push"; 204 reg_in_opcode = true; 205 break; 206 case 0x58: case 0x59: case 0x5A: case 0x5B: case 0x5C: case 0x5D: case 0x5E: case 0x5F: 207 opcode << "pop"; 208 reg_in_opcode = true; 209 break; 210 case 0x68: opcode << "push"; immediate_bytes = 4; break; 211 case 0x6A: opcode << "push"; immediate_bytes = 1; break; 212 case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: 213 case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F: 214 static const char* condition_codes[] = 215 {"o", "no", "b/nae/c", "nb/ae/nc", "z/eq", "nz/ne", "be/na", "nbe/a", 216 "s", "ns", "p/pe", "np/po", "l/nge", "nl/ge", "le/ng", "nle/g" 217 }; 218 opcode << "j" << condition_codes[*instr & 0xF]; 219 branch_bytes = 1; 220 break; 221 case 0x88: opcode << "mov"; store = true; has_modrm = true; byte_operand = true; break; 222 case 0x89: opcode << "mov"; store = true; has_modrm = true; break; 223 case 0x8A: opcode << "mov"; load = true; has_modrm = true; byte_operand = true; break; 224 case 0x8B: opcode << "mov"; load = true; has_modrm = true; break; 225 226 case 0x0F: // 2 byte extended opcode 227 instr++; 228 switch (*instr) { 229 case 0x10: case 0x11: 230 if (prefix[0] == 0xF2) { 231 opcode << "movsd"; 232 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 233 } else if (prefix[0] == 0xF3) { 234 opcode << "movss"; 235 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 236 } else if (prefix[2] == 0x66) { 237 opcode << "movupd"; 238 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 239 } else { 240 opcode << "movups"; 241 } 242 has_modrm = true; 243 src_reg_file = dst_reg_file = SSE; 244 load = *instr == 0x10; 245 store = !load; 246 break; 247 case 0x2A: 248 if (prefix[2] == 0x66) { 249 opcode << "cvtpi2pd"; 250 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 251 } else if (prefix[0] == 0xF2) { 252 opcode << "cvtsi2sd"; 253 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 254 } else if (prefix[0] == 0xF3) { 255 opcode << "cvtsi2ss"; 256 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 257 } else { 258 opcode << "cvtpi2ps"; 259 } 260 load = true; 261 has_modrm = true; 262 dst_reg_file = SSE; 263 break; 264 case 0x2C: 265 if (prefix[2] == 0x66) { 266 opcode << "cvttpd2pi"; 267 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 268 } else if (prefix[0] == 0xF2) { 269 opcode << "cvttsd2si"; 270 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 271 } else if (prefix[0] == 0xF3) { 272 opcode << "cvttss2si"; 273 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 274 } else { 275 opcode << "cvttps2pi"; 276 } 277 load = true; 278 has_modrm = true; 279 src_reg_file = SSE; 280 break; 281 case 0x2D: 282 if (prefix[2] == 0x66) { 283 opcode << "cvtpd2pi"; 284 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 285 } else if (prefix[0] == 0xF2) { 286 opcode << "cvtsd2si"; 287 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 288 } else if (prefix[0] == 0xF3) { 289 opcode << "cvtss2si"; 290 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 291 } else { 292 opcode << "cvtps2pi"; 293 } 294 load = true; 295 has_modrm = true; 296 src_reg_file = SSE; 297 break; 298 case 0x2E: 299 opcode << "u"; 300 // FALLTHROUGH 301 case 0x2F: 302 if (prefix[2] == 0x66) { 303 opcode << "comisd"; 304 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 305 } else { 306 opcode << "comiss"; 307 } 308 has_modrm = true; 309 load = true; 310 src_reg_file = dst_reg_file = SSE; 311 break; 312 case 0x38: // 3 byte extended opcode 313 opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr); 314 break; 315 case 0x3A: // 3 byte extended opcode 316 opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr); 317 break; 318 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 319 case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { 320 switch (*instr) { 321 case 0x50: opcode << "movmsk"; break; 322 case 0x51: opcode << "sqrt"; break; 323 case 0x52: opcode << "rsqrt"; break; 324 case 0x53: opcode << "rcp"; break; 325 case 0x54: opcode << "and"; break; 326 case 0x55: opcode << "andn"; break; 327 case 0x56: opcode << "or"; break; 328 case 0x57: opcode << "xor"; break; 329 case 0x58: opcode << "add"; break; 330 case 0x59: opcode << "mul"; break; 331 case 0x5C: opcode << "sub"; break; 332 case 0x5D: opcode << "min"; break; 333 case 0x5E: opcode << "div"; break; 334 case 0x5F: opcode << "max"; break; 335 default: LOG(FATAL) << "Unreachable"; 336 } 337 if (prefix[2] == 0x66) { 338 opcode << "pd"; 339 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 340 } else if (prefix[0] == 0xF2) { 341 opcode << "sd"; 342 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 343 } else if (prefix[0] == 0xF3) { 344 opcode << "ss"; 345 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 346 } else { 347 opcode << "ps"; 348 } 349 load = true; 350 has_modrm = true; 351 src_reg_file = dst_reg_file = SSE; 352 break; 353 } 354 case 0x5A: 355 if (prefix[2] == 0x66) { 356 opcode << "cvtpd2ps"; 357 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 358 } else if (prefix[0] == 0xF2) { 359 opcode << "cvtsd2ss"; 360 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 361 } else if (prefix[0] == 0xF3) { 362 opcode << "cvtss2sd"; 363 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 364 } else { 365 opcode << "cvtps2pd"; 366 } 367 load = true; 368 has_modrm = true; 369 src_reg_file = dst_reg_file = SSE; 370 break; 371 case 0x5B: 372 if (prefix[2] == 0x66) { 373 opcode << "cvtps2dq"; 374 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 375 } else if (prefix[0] == 0xF2) { 376 opcode << "bad opcode F2 0F 5B"; 377 } else if (prefix[0] == 0xF3) { 378 opcode << "cvttps2dq"; 379 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 380 } else { 381 opcode << "cvtdq2ps"; 382 } 383 load = true; 384 has_modrm = true; 385 src_reg_file = dst_reg_file = SSE; 386 break; 387 case 0x6E: 388 if (prefix[2] == 0x66) { 389 dst_reg_file = SSE; 390 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 391 } else { 392 dst_reg_file = MMX; 393 } 394 opcode << "movd"; 395 load = true; 396 has_modrm = true; 397 break; 398 case 0x6F: 399 if (prefix[2] == 0x66) { 400 dst_reg_file = SSE; 401 opcode << "movdqa"; 402 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 403 } else if (prefix[0] == 0xF3) { 404 dst_reg_file = SSE; 405 opcode << "movdqu"; 406 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 407 } else { 408 dst_reg_file = MMX; 409 opcode << "movq"; 410 } 411 load = true; 412 has_modrm = true; 413 break; 414 case 0x71: 415 if (prefix[2] == 0x66) { 416 dst_reg_file = SSE; 417 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 418 } else { 419 dst_reg_file = MMX; 420 } 421 static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"}; 422 modrm_opcodes = x71_opcodes; 423 reg_is_opcode = true; 424 has_modrm = true; 425 store = true; 426 immediate_bytes = 1; 427 break; 428 case 0x72: 429 if (prefix[2] == 0x66) { 430 dst_reg_file = SSE; 431 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 432 } else { 433 dst_reg_file = MMX; 434 } 435 static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"}; 436 modrm_opcodes = x72_opcodes; 437 reg_is_opcode = true; 438 has_modrm = true; 439 store = true; 440 immediate_bytes = 1; 441 break; 442 case 0x73: 443 if (prefix[2] == 0x66) { 444 dst_reg_file = SSE; 445 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 446 } else { 447 dst_reg_file = MMX; 448 } 449 static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"}; 450 modrm_opcodes = x73_opcodes; 451 reg_is_opcode = true; 452 has_modrm = true; 453 store = true; 454 immediate_bytes = 1; 455 break; 456 case 0x7E: 457 if (prefix[2] == 0x66) { 458 src_reg_file = SSE; 459 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 460 } else { 461 src_reg_file = MMX; 462 } 463 opcode << "movd"; 464 has_modrm = true; 465 store = true; 466 break; 467 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: 468 case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: 469 opcode << "j" << condition_codes[*instr & 0xF]; 470 branch_bytes = 4; 471 break; 472 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: 473 case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: 474 opcode << "set" << condition_codes[*instr & 0xF]; 475 modrm_opcodes = NULL; 476 reg_is_opcode = true; 477 has_modrm = true; 478 store = true; 479 break; 480 case 0xAE: 481 if (prefix[0] == 0xF3) { 482 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 483 static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"}; 484 modrm_opcodes = xAE_opcodes; 485 reg_is_opcode = true; 486 has_modrm = true; 487 uint8_t reg_or_opcode = (instr[1] >> 3) & 7; 488 switch (reg_or_opcode) { 489 case 0: 490 prefix[1] = kFs; 491 load = true; 492 break; 493 case 1: 494 prefix[1] = kGs; 495 load = true; 496 break; 497 case 2: 498 prefix[1] = kFs; 499 store = true; 500 break; 501 case 3: 502 prefix[1] = kGs; 503 store = true; 504 break; 505 default: 506 load = true; 507 break; 508 } 509 } else { 510 static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"}; 511 modrm_opcodes = xAE_opcodes; 512 reg_is_opcode = true; 513 has_modrm = true; 514 load = true; 515 no_ops = true; 516 } 517 break; 518 case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break; 519 case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break; 520 case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break; 521 case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break; 522 case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break; 523 default: 524 opcode << StringPrintf("unknown opcode '0F %02X'", *instr); 525 break; 526 } 527 break; 528 case 0x80: case 0x81: case 0x82: case 0x83: 529 static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; 530 modrm_opcodes = x80_opcodes; 531 has_modrm = true; 532 reg_is_opcode = true; 533 store = true; 534 byte_operand = (*instr & 1) == 0; 535 immediate_bytes = *instr == 0x81 ? 4 : 1; 536 break; 537 case 0x84: case 0x85: 538 opcode << "test"; 539 has_modrm = true; 540 load = true; 541 byte_operand = (*instr & 1) == 0; 542 break; 543 case 0x8D: 544 opcode << "lea"; 545 has_modrm = true; 546 load = true; 547 break; 548 case 0x8F: 549 opcode << "pop"; 550 has_modrm = true; 551 reg_is_opcode = true; 552 store = true; 553 break; 554 case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: 555 opcode << "mov"; 556 immediate_bytes = 1; 557 reg_in_opcode = true; 558 break; 559 case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: 560 opcode << "mov"; 561 immediate_bytes = 4; 562 reg_in_opcode = true; 563 break; 564 case 0xC0: case 0xC1: 565 case 0xD0: case 0xD1: case 0xD2: case 0xD3: 566 static const char* shift_opcodes[] = 567 {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"}; 568 modrm_opcodes = shift_opcodes; 569 has_modrm = true; 570 reg_is_opcode = true; 571 store = true; 572 immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0; 573 cx = (*instr == 0xD2) || (*instr == 0xD3); 574 byte_operand = (*instr == 0xC0); 575 break; 576 case 0xC3: opcode << "ret"; break; 577 case 0xC7: 578 static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"}; 579 modrm_opcodes = c7_opcodes; 580 store = true; 581 immediate_bytes = 4; 582 has_modrm = true; 583 reg_is_opcode = true; 584 break; 585 case 0xCC: opcode << "int 3"; break; 586 case 0xE8: opcode << "call"; branch_bytes = 4; break; 587 case 0xE9: opcode << "jmp"; branch_bytes = 4; break; 588 case 0xEB: opcode << "jmp"; branch_bytes = 1; break; 589 case 0xF5: opcode << "cmc"; break; 590 case 0xF6: case 0xF7: 591 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 /"}; 592 modrm_opcodes = f7_opcodes; 593 has_modrm = true; 594 reg_is_opcode = true; 595 store = true; 596 immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; 597 break; 598 case 0xFF: 599 static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"}; 600 modrm_opcodes = ff_opcodes; 601 has_modrm = true; 602 reg_is_opcode = true; 603 load = true; 604 break; 605 default: 606 opcode << StringPrintf("unknown opcode '%02X'", *instr); 607 break; 608 } 609 std::ostringstream args; 610 if (reg_in_opcode) { 611 DCHECK(!has_modrm); 612 DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR); 613 } 614 instr++; 615 uint32_t address_bits = 0; 616 if (has_modrm) { 617 uint8_t modrm = *instr; 618 instr++; 619 uint8_t mod = modrm >> 6; 620 uint8_t reg_or_opcode = (modrm >> 3) & 7; 621 uint8_t rm = modrm & 7; 622 std::ostringstream address; 623 if (mod == 0 && rm == 5) { // fixed address 624 address_bits = *reinterpret_cast<const uint32_t*>(instr); 625 address << StringPrintf("[0x%x]", address_bits); 626 instr += 4; 627 } else if (rm == 4 && mod != 3) { // SIB 628 uint8_t sib = *instr; 629 instr++; 630 uint8_t ss = (sib >> 6) & 3; 631 uint8_t index = (sib >> 3) & 7; 632 uint8_t base = sib & 7; 633 address << "["; 634 if (base != 5 || mod != 0) { 635 DumpBaseReg(address, rex, base); 636 if (index != 4) { 637 address << " + "; 638 } 639 } 640 if (index != 4) { 641 DumpIndexReg(address, rex, index); 642 if (ss != 0) { 643 address << StringPrintf(" * %d", 1 << ss); 644 } 645 } 646 if (mod == 1) { 647 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr)); 648 instr++; 649 } else if (mod == 2) { 650 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 651 instr += 4; 652 } 653 address << "]"; 654 } else { 655 if (mod == 3) { 656 if (!no_ops) { 657 DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file); 658 } 659 } else { 660 address << "["; 661 DumpBaseReg(address, rex, rm); 662 if (mod == 1) { 663 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr)); 664 instr++; 665 } else if (mod == 2) { 666 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 667 instr += 4; 668 } 669 address << "]"; 670 } 671 } 672 673 if (reg_is_opcode && modrm_opcodes != NULL) { 674 opcode << modrm_opcodes[reg_or_opcode]; 675 } 676 if (load) { 677 if (!reg_is_opcode) { 678 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file); 679 args << ", "; 680 } 681 DumpSegmentOverride(args, prefix[1]); 682 args << address.str(); 683 } else { 684 DCHECK(store); 685 DumpSegmentOverride(args, prefix[1]); 686 args << address.str(); 687 if (!reg_is_opcode) { 688 args << ", "; 689 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file); 690 } 691 } 692 } 693 if (ax) { 694 // If this opcode implicitly uses ax, ax is always the first arg. 695 DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR); 696 } 697 if (cx) { 698 args << ", "; 699 DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR); 700 } 701 if (immediate_bytes > 0) { 702 if (has_modrm || reg_in_opcode || ax || cx) { 703 args << ", "; 704 } 705 if (immediate_bytes == 1) { 706 args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr)); 707 instr++; 708 } else { 709 CHECK_EQ(immediate_bytes, 4u); 710 args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr)); 711 instr += 4; 712 } 713 } else if (branch_bytes > 0) { 714 DCHECK(!has_modrm); 715 int32_t displacement; 716 if (branch_bytes == 1) { 717 displacement = *reinterpret_cast<const int8_t*>(instr); 718 instr++; 719 } else { 720 CHECK_EQ(branch_bytes, 4u); 721 displacement = *reinterpret_cast<const int32_t*>(instr); 722 instr += 4; 723 } 724 args << StringPrintf("%+d (%p)", displacement, instr + displacement); 725 } 726 if (prefix[1] == kFs) { 727 args << " ; "; 728 Thread::DumpThreadOffset(args, address_bits, 4); 729 } 730 std::stringstream hex; 731 for (size_t i = 0; begin_instr + i < instr; ++i) { 732 hex << StringPrintf("%02X", begin_instr[i]); 733 } 734 std::stringstream prefixed_opcode; 735 switch (prefix[0]) { 736 case 0xF0: prefixed_opcode << "lock "; break; 737 case 0xF2: prefixed_opcode << "repne "; break; 738 case 0xF3: prefixed_opcode << "repe "; break; 739 case 0: break; 740 default: LOG(FATAL) << "Unreachable"; 741 } 742 prefixed_opcode << opcode.str(); 743 os << StringPrintf("%p: %22s \t%-7s ", begin_instr, hex.str().c_str(), 744 prefixed_opcode.str().c_str()) 745 << args.str() << '\n'; 746 return instr - begin_instr; 747 } // NOLINT(readability/fn_size) 748 749 } // namespace x86 750 } // namespace art 751