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