disassembler_x86.cc revision 2c498d1f28e62e81fbdb477ff93ca7454e7493d7
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 0x12: case 0x13: 250 if (prefix[2] == 0x66) { 251 opcode << "movlpd"; 252 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 253 } else if (prefix[0] == 0) { 254 opcode << "movlps"; 255 } 256 has_modrm = true; 257 src_reg_file = dst_reg_file = SSE; 258 load = *instr == 0x12; 259 store = !load; 260 break; 261 case 0x16: case 0x17: 262 if (prefix[2] == 0x66) { 263 opcode << "movhpd"; 264 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 265 } else if (prefix[0] == 0) { 266 opcode << "movhps"; 267 } 268 has_modrm = true; 269 src_reg_file = dst_reg_file = SSE; 270 load = *instr == 0x16; 271 store = !load; 272 break; 273 case 0x28: case 0x29: 274 if (prefix[2] == 0x66) { 275 opcode << "movapd"; 276 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 277 } else if (prefix[0] == 0) { 278 opcode << "movaps"; 279 } 280 has_modrm = true; 281 src_reg_file = dst_reg_file = SSE; 282 load = *instr == 0x28; 283 store = !load; 284 break; 285 case 0x2A: 286 if (prefix[2] == 0x66) { 287 opcode << "cvtpi2pd"; 288 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 289 } else if (prefix[0] == 0xF2) { 290 opcode << "cvtsi2sd"; 291 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 292 } else if (prefix[0] == 0xF3) { 293 opcode << "cvtsi2ss"; 294 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 295 } else { 296 opcode << "cvtpi2ps"; 297 } 298 load = true; 299 has_modrm = true; 300 dst_reg_file = SSE; 301 break; 302 case 0x2C: 303 if (prefix[2] == 0x66) { 304 opcode << "cvttpd2pi"; 305 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 306 } else if (prefix[0] == 0xF2) { 307 opcode << "cvttsd2si"; 308 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 309 } else if (prefix[0] == 0xF3) { 310 opcode << "cvttss2si"; 311 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 312 } else { 313 opcode << "cvttps2pi"; 314 } 315 load = true; 316 has_modrm = true; 317 src_reg_file = SSE; 318 break; 319 case 0x2D: 320 if (prefix[2] == 0x66) { 321 opcode << "cvtpd2pi"; 322 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 323 } else if (prefix[0] == 0xF2) { 324 opcode << "cvtsd2si"; 325 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 326 } else if (prefix[0] == 0xF3) { 327 opcode << "cvtss2si"; 328 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 329 } else { 330 opcode << "cvtps2pi"; 331 } 332 load = true; 333 has_modrm = true; 334 src_reg_file = SSE; 335 break; 336 case 0x2E: 337 opcode << "u"; 338 // FALLTHROUGH 339 case 0x2F: 340 if (prefix[2] == 0x66) { 341 opcode << "comisd"; 342 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 343 } else { 344 opcode << "comiss"; 345 } 346 has_modrm = true; 347 load = true; 348 src_reg_file = dst_reg_file = SSE; 349 break; 350 case 0x38: // 3 byte extended opcode 351 opcode << StringPrintf("unknown opcode '0F 38 %02X'", *instr); 352 break; 353 case 0x3A: // 3 byte extended opcode 354 opcode << StringPrintf("unknown opcode '0F 3A %02X'", *instr); 355 break; 356 case 0x40: case 0x41: case 0x42: case 0x43: case 0x44: case 0x45: case 0x46: case 0x47: 357 case 0x48: case 0x49: case 0x4A: case 0x4B: case 0x4C: case 0x4D: case 0x4E: case 0x4F: 358 opcode << "cmov" << condition_codes[*instr & 0xF]; 359 has_modrm = true; 360 load = true; 361 break; 362 case 0x50: case 0x51: case 0x52: case 0x53: case 0x54: case 0x55: case 0x56: case 0x57: 363 case 0x58: case 0x59: case 0x5C: case 0x5D: case 0x5E: case 0x5F: { 364 switch (*instr) { 365 case 0x50: opcode << "movmsk"; break; 366 case 0x51: opcode << "sqrt"; break; 367 case 0x52: opcode << "rsqrt"; break; 368 case 0x53: opcode << "rcp"; break; 369 case 0x54: opcode << "and"; break; 370 case 0x55: opcode << "andn"; break; 371 case 0x56: opcode << "or"; break; 372 case 0x57: opcode << "xor"; break; 373 case 0x58: opcode << "add"; break; 374 case 0x59: opcode << "mul"; break; 375 case 0x5C: opcode << "sub"; break; 376 case 0x5D: opcode << "min"; break; 377 case 0x5E: opcode << "div"; break; 378 case 0x5F: opcode << "max"; break; 379 default: LOG(FATAL) << "Unreachable"; 380 } 381 if (prefix[2] == 0x66) { 382 opcode << "pd"; 383 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 384 } else if (prefix[0] == 0xF2) { 385 opcode << "sd"; 386 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 387 } else if (prefix[0] == 0xF3) { 388 opcode << "ss"; 389 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 390 } else { 391 opcode << "ps"; 392 } 393 load = true; 394 has_modrm = true; 395 src_reg_file = dst_reg_file = SSE; 396 break; 397 } 398 case 0x5A: 399 if (prefix[2] == 0x66) { 400 opcode << "cvtpd2ps"; 401 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 402 } else if (prefix[0] == 0xF2) { 403 opcode << "cvtsd2ss"; 404 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 405 } else if (prefix[0] == 0xF3) { 406 opcode << "cvtss2sd"; 407 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 408 } else { 409 opcode << "cvtps2pd"; 410 } 411 load = true; 412 has_modrm = true; 413 src_reg_file = dst_reg_file = SSE; 414 break; 415 case 0x5B: 416 if (prefix[2] == 0x66) { 417 opcode << "cvtps2dq"; 418 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 419 } else if (prefix[0] == 0xF2) { 420 opcode << "bad opcode F2 0F 5B"; 421 } else if (prefix[0] == 0xF3) { 422 opcode << "cvttps2dq"; 423 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 424 } else { 425 opcode << "cvtdq2ps"; 426 } 427 load = true; 428 has_modrm = true; 429 src_reg_file = dst_reg_file = SSE; 430 break; 431 case 0x62: 432 if (prefix[2] == 0x66) { 433 src_reg_file = dst_reg_file = SSE; 434 prefix[2] = 0; // Clear prefix now. It has served its purpose as part of the opcode. 435 } else { 436 src_reg_file = dst_reg_file = MMX; 437 } 438 opcode << "punpckldq"; 439 load = true; 440 has_modrm = true; 441 break; 442 case 0x6E: 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 opcode << "movd"; 450 load = true; 451 has_modrm = true; 452 break; 453 case 0x6F: 454 if (prefix[2] == 0x66) { 455 dst_reg_file = SSE; 456 opcode << "movdqa"; 457 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 458 } else if (prefix[0] == 0xF3) { 459 dst_reg_file = SSE; 460 opcode << "movdqu"; 461 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 462 } else { 463 dst_reg_file = MMX; 464 opcode << "movq"; 465 } 466 load = true; 467 has_modrm = true; 468 break; 469 case 0x71: 470 if (prefix[2] == 0x66) { 471 dst_reg_file = SSE; 472 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 473 } else { 474 dst_reg_file = MMX; 475 } 476 static const char* x71_opcodes[] = {"unknown-71", "unknown-71", "psrlw", "unknown-71", "psraw", "unknown-71", "psllw", "unknown-71"}; 477 modrm_opcodes = x71_opcodes; 478 reg_is_opcode = true; 479 has_modrm = true; 480 store = true; 481 immediate_bytes = 1; 482 break; 483 case 0x72: 484 if (prefix[2] == 0x66) { 485 dst_reg_file = SSE; 486 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 487 } else { 488 dst_reg_file = MMX; 489 } 490 static const char* x72_opcodes[] = {"unknown-72", "unknown-72", "psrld", "unknown-72", "psrad", "unknown-72", "pslld", "unknown-72"}; 491 modrm_opcodes = x72_opcodes; 492 reg_is_opcode = true; 493 has_modrm = true; 494 store = true; 495 immediate_bytes = 1; 496 break; 497 case 0x73: 498 if (prefix[2] == 0x66) { 499 dst_reg_file = SSE; 500 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 501 } else { 502 dst_reg_file = MMX; 503 } 504 static const char* x73_opcodes[] = {"unknown-73", "unknown-73", "psrlq", "unknown-73", "unknown-73", "unknown-73", "psllq", "unknown-73"}; 505 modrm_opcodes = x73_opcodes; 506 reg_is_opcode = true; 507 has_modrm = true; 508 store = true; 509 immediate_bytes = 1; 510 break; 511 case 0x7E: 512 if (prefix[2] == 0x66) { 513 src_reg_file = SSE; 514 prefix[2] = 0; // clear prefix now it's served its purpose as part of the opcode 515 } else { 516 src_reg_file = MMX; 517 } 518 opcode << "movd"; 519 has_modrm = true; 520 store = true; 521 break; 522 case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: 523 case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F: 524 opcode << "j" << condition_codes[*instr & 0xF]; 525 branch_bytes = 4; 526 break; 527 case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97: 528 case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F: 529 opcode << "set" << condition_codes[*instr & 0xF]; 530 modrm_opcodes = NULL; 531 reg_is_opcode = true; 532 has_modrm = true; 533 store = true; 534 break; 535 case 0xA4: 536 opcode << "shld"; 537 has_modrm = true; 538 load = true; 539 immediate_bytes = 1; 540 break; 541 case 0xAC: 542 opcode << "shrd"; 543 has_modrm = true; 544 load = true; 545 immediate_bytes = 1; 546 break; 547 case 0xAE: 548 if (prefix[0] == 0xF3) { 549 prefix[0] = 0; // clear prefix now it's served its purpose as part of the opcode 550 static const char* xAE_opcodes[] = {"rdfsbase", "rdgsbase", "wrfsbase", "wrgsbase", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE"}; 551 modrm_opcodes = xAE_opcodes; 552 reg_is_opcode = true; 553 has_modrm = true; 554 uint8_t reg_or_opcode = (instr[1] >> 3) & 7; 555 switch (reg_or_opcode) { 556 case 0: 557 prefix[1] = kFs; 558 load = true; 559 break; 560 case 1: 561 prefix[1] = kGs; 562 load = true; 563 break; 564 case 2: 565 prefix[1] = kFs; 566 store = true; 567 break; 568 case 3: 569 prefix[1] = kGs; 570 store = true; 571 break; 572 default: 573 load = true; 574 break; 575 } 576 } else { 577 static const char* xAE_opcodes[] = {"unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "unknown-AE", "lfence", "mfence", "sfence"}; 578 modrm_opcodes = xAE_opcodes; 579 reg_is_opcode = true; 580 has_modrm = true; 581 load = true; 582 no_ops = true; 583 } 584 break; 585 case 0xAF: opcode << "imul"; has_modrm = true; load = true; break; 586 case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break; 587 case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break; 588 case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break; 589 case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break; 590 case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break; 591 case 0xC7: 592 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" }; 593 modrm_opcodes = x0FxC7_opcodes; 594 has_modrm = true; 595 reg_is_opcode = true; 596 store = true; 597 break; 598 case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF: 599 opcode << "bswap"; 600 reg_in_opcode = true; 601 break; 602 default: 603 opcode << StringPrintf("unknown opcode '0F %02X'", *instr); 604 break; 605 } 606 break; 607 case 0x80: case 0x81: case 0x82: case 0x83: 608 static const char* x80_opcodes[] = {"add", "or", "adc", "sbb", "and", "sub", "xor", "cmp"}; 609 modrm_opcodes = x80_opcodes; 610 has_modrm = true; 611 reg_is_opcode = true; 612 store = true; 613 byte_operand = (*instr & 1) == 0; 614 immediate_bytes = *instr == 0x81 ? 4 : 1; 615 break; 616 case 0x84: case 0x85: 617 opcode << "test"; 618 has_modrm = true; 619 load = true; 620 byte_operand = (*instr & 1) == 0; 621 break; 622 case 0x8D: 623 opcode << "lea"; 624 has_modrm = true; 625 load = true; 626 break; 627 case 0x8F: 628 opcode << "pop"; 629 has_modrm = true; 630 reg_is_opcode = true; 631 store = true; 632 break; 633 case 0x99: 634 opcode << "cdq"; 635 break; 636 case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7: 637 opcode << "mov"; 638 immediate_bytes = 1; 639 reg_in_opcode = true; 640 break; 641 case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF: 642 opcode << "mov"; 643 immediate_bytes = 4; 644 reg_in_opcode = true; 645 break; 646 case 0xC0: case 0xC1: 647 case 0xD0: case 0xD1: case 0xD2: case 0xD3: 648 static const char* shift_opcodes[] = 649 {"rol", "ror", "rcl", "rcr", "shl", "shr", "unknown-shift", "sar"}; 650 modrm_opcodes = shift_opcodes; 651 has_modrm = true; 652 reg_is_opcode = true; 653 store = true; 654 immediate_bytes = ((*instr & 0xf0) == 0xc0) ? 1 : 0; 655 cx = (*instr == 0xD2) || (*instr == 0xD3); 656 byte_operand = (*instr == 0xC0); 657 break; 658 case 0xC3: opcode << "ret"; break; 659 case 0xC7: 660 static const char* c7_opcodes[] = {"mov", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7", "unknown-c7"}; 661 modrm_opcodes = c7_opcodes; 662 store = true; 663 immediate_bytes = 4; 664 has_modrm = true; 665 reg_is_opcode = true; 666 break; 667 case 0xCC: opcode << "int 3"; break; 668 case 0xD9: 669 static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw", "fnstenv", "fnstcw"}; 670 modrm_opcodes = d9_opcodes; 671 store = true; 672 has_modrm = true; 673 reg_is_opcode = true; 674 break; 675 case 0xDD: 676 static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl", "fstpl", "frstor", "unknown-dd", "fnsave", "fnstsw"}; 677 modrm_opcodes = dd_opcodes; 678 store = true; 679 has_modrm = true; 680 reg_is_opcode = true; 681 break; 682 case 0xE8: opcode << "call"; branch_bytes = 4; break; 683 case 0xE9: opcode << "jmp"; branch_bytes = 4; break; 684 case 0xEB: opcode << "jmp"; branch_bytes = 1; break; 685 case 0xF5: opcode << "cmc"; break; 686 case 0xF6: case 0xF7: 687 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 /"}; 688 modrm_opcodes = f7_opcodes; 689 has_modrm = true; 690 reg_is_opcode = true; 691 store = true; 692 immediate_bytes = ((instr[1] & 0x38) == 0) ? 1 : 0; 693 break; 694 case 0xFF: 695 static const char* ff_opcodes[] = {"inc", "dec", "call", "call", "jmp", "jmp", "push", "unknown-ff"}; 696 modrm_opcodes = ff_opcodes; 697 has_modrm = true; 698 reg_is_opcode = true; 699 load = true; 700 break; 701 default: 702 opcode << StringPrintf("unknown opcode '%02X'", *instr); 703 break; 704 } 705 std::ostringstream args; 706 if (reg_in_opcode) { 707 DCHECK(!has_modrm); 708 DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR); 709 } 710 instr++; 711 uint32_t address_bits = 0; 712 if (has_modrm) { 713 uint8_t modrm = *instr; 714 instr++; 715 uint8_t mod = modrm >> 6; 716 uint8_t reg_or_opcode = (modrm >> 3) & 7; 717 uint8_t rm = modrm & 7; 718 std::ostringstream address; 719 if (mod == 0 && rm == 5) { // fixed address 720 address_bits = *reinterpret_cast<const uint32_t*>(instr); 721 address << StringPrintf("[0x%x]", address_bits); 722 instr += 4; 723 } else if (rm == 4 && mod != 3) { // SIB 724 uint8_t sib = *instr; 725 instr++; 726 uint8_t ss = (sib >> 6) & 3; 727 uint8_t index = (sib >> 3) & 7; 728 uint8_t base = sib & 7; 729 address << "["; 730 if (base != 5 || mod != 0) { 731 DumpBaseReg(address, rex, base); 732 if (index != 4) { 733 address << " + "; 734 } 735 } 736 if (index != 4) { 737 DumpIndexReg(address, rex, index); 738 if (ss != 0) { 739 address << StringPrintf(" * %d", 1 << ss); 740 } 741 } 742 if (mod == 1) { 743 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr)); 744 instr++; 745 } else if (mod == 2) { 746 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 747 instr += 4; 748 } 749 address << "]"; 750 } else { 751 if (mod == 3) { 752 if (!no_ops) { 753 DumpReg(address, rex, rm, byte_operand, prefix[2], load ? src_reg_file : dst_reg_file); 754 } 755 } else { 756 address << "["; 757 DumpBaseReg(address, rex, rm); 758 if (mod == 1) { 759 address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr)); 760 instr++; 761 } else if (mod == 2) { 762 address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr)); 763 instr += 4; 764 } 765 address << "]"; 766 } 767 } 768 769 if (reg_is_opcode && modrm_opcodes != NULL) { 770 opcode << modrm_opcodes[reg_or_opcode]; 771 } 772 if (load) { 773 if (!reg_is_opcode) { 774 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], dst_reg_file); 775 args << ", "; 776 } 777 DumpSegmentOverride(args, prefix[1]); 778 args << address.str(); 779 } else { 780 DCHECK(store); 781 DumpSegmentOverride(args, prefix[1]); 782 args << address.str(); 783 if (!reg_is_opcode) { 784 args << ", "; 785 DumpReg(args, rex, reg_or_opcode, byte_operand, prefix[2], src_reg_file); 786 } 787 } 788 } 789 if (ax) { 790 // If this opcode implicitly uses ax, ax is always the first arg. 791 DumpReg(args, rex, 0 /* EAX */, byte_operand, prefix[2], GPR); 792 } 793 if (cx) { 794 args << ", "; 795 DumpReg(args, rex, 1 /* ECX */, true, prefix[2], GPR); 796 } 797 if (immediate_bytes > 0) { 798 if (has_modrm || reg_in_opcode || ax || cx) { 799 args << ", "; 800 } 801 if (immediate_bytes == 1) { 802 args << StringPrintf("%d", *reinterpret_cast<const int8_t*>(instr)); 803 instr++; 804 } else { 805 CHECK_EQ(immediate_bytes, 4u); 806 args << StringPrintf("%d", *reinterpret_cast<const int32_t*>(instr)); 807 instr += 4; 808 } 809 } else if (branch_bytes > 0) { 810 DCHECK(!has_modrm); 811 int32_t displacement; 812 if (branch_bytes == 1) { 813 displacement = *reinterpret_cast<const int8_t*>(instr); 814 instr++; 815 } else { 816 CHECK_EQ(branch_bytes, 4u); 817 displacement = *reinterpret_cast<const int32_t*>(instr); 818 instr += 4; 819 } 820 args << StringPrintf("%+d (%p)", displacement, instr + displacement); 821 } 822 if (prefix[1] == kFs) { 823 args << " ; "; 824 Thread::DumpThreadOffset(args, address_bits, 4); 825 } 826 std::stringstream hex; 827 for (size_t i = 0; begin_instr + i < instr; ++i) { 828 hex << StringPrintf("%02X", begin_instr[i]); 829 } 830 std::stringstream prefixed_opcode; 831 switch (prefix[0]) { 832 case 0xF0: prefixed_opcode << "lock "; break; 833 case 0xF2: prefixed_opcode << "repne "; break; 834 case 0xF3: prefixed_opcode << "repe "; break; 835 case 0: break; 836 default: LOG(FATAL) << "Unreachable"; 837 } 838 prefixed_opcode << opcode.str(); 839 os << StringPrintf("%p: %22s \t%-7s ", begin_instr, hex.str().c_str(), 840 prefixed_opcode.str().c_str()) 841 << args.str() << '\n'; 842 return instr - begin_instr; 843} // NOLINT(readability/fn_size) 844 845} // namespace x86 846} // namespace art 847