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