1 // Copyright 2011 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <assert.h> 6 #include <stdarg.h> 7 #include <stdio.h> 8 9 #if V8_TARGET_ARCH_IA32 10 11 #include "src/base/compiler-specific.h" 12 #include "src/disasm.h" 13 14 namespace disasm { 15 16 enum OperandOrder { 17 UNSET_OP_ORDER = 0, 18 REG_OPER_OP_ORDER, 19 OPER_REG_OP_ORDER 20 }; 21 22 23 //------------------------------------------------------------------ 24 // Tables 25 //------------------------------------------------------------------ 26 struct ByteMnemonic { 27 int b; // -1 terminates, otherwise must be in range (0..255) 28 const char* mnem; 29 OperandOrder op_order_; 30 }; 31 32 static const ByteMnemonic two_operands_instr[] = { 33 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER}, 34 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER}, 35 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER}, 36 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER}, 37 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER}, 38 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER}, 39 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER}, 40 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER}, 41 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER}, 42 {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER}, 43 {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER}, 44 {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER}, 45 {-1, "", UNSET_OP_ORDER}}; 46 47 static const ByteMnemonic zero_operands_instr[] = { 48 {0xC3, "ret", UNSET_OP_ORDER}, 49 {0xC9, "leave", UNSET_OP_ORDER}, 50 {0x90, "nop", UNSET_OP_ORDER}, 51 {0xF4, "hlt", UNSET_OP_ORDER}, 52 {0xCC, "int3", UNSET_OP_ORDER}, 53 {0x60, "pushad", UNSET_OP_ORDER}, 54 {0x61, "popad", UNSET_OP_ORDER}, 55 {0x9C, "pushfd", UNSET_OP_ORDER}, 56 {0x9D, "popfd", UNSET_OP_ORDER}, 57 {0x9E, "sahf", UNSET_OP_ORDER}, 58 {0x99, "cdq", UNSET_OP_ORDER}, 59 {0x9B, "fwait", UNSET_OP_ORDER}, 60 {0xFC, "cld", UNSET_OP_ORDER}, 61 {0xAB, "stos", UNSET_OP_ORDER}, 62 {-1, "", UNSET_OP_ORDER} 63 }; 64 65 66 static const ByteMnemonic call_jump_instr[] = { 67 {0xE8, "call", UNSET_OP_ORDER}, 68 {0xE9, "jmp", UNSET_OP_ORDER}, 69 {-1, "", UNSET_OP_ORDER} 70 }; 71 72 73 static const ByteMnemonic short_immediate_instr[] = { 74 {0x05, "add", UNSET_OP_ORDER}, 75 {0x0D, "or", UNSET_OP_ORDER}, 76 {0x15, "adc", UNSET_OP_ORDER}, 77 {0x25, "and", UNSET_OP_ORDER}, 78 {0x2D, "sub", UNSET_OP_ORDER}, 79 {0x35, "xor", UNSET_OP_ORDER}, 80 {0x3D, "cmp", UNSET_OP_ORDER}, 81 {-1, "", UNSET_OP_ORDER} 82 }; 83 84 85 // Generally we don't want to generate these because they are subject to partial 86 // register stalls. They are included for completeness and because the cmp 87 // variant is used by the RecordWrite stub. Because it does not update the 88 // register it is not subject to partial register stalls. 89 static ByteMnemonic byte_immediate_instr[] = { 90 {0x0c, "or", UNSET_OP_ORDER}, 91 {0x24, "and", UNSET_OP_ORDER}, 92 {0x34, "xor", UNSET_OP_ORDER}, 93 {0x3c, "cmp", UNSET_OP_ORDER}, 94 {-1, "", UNSET_OP_ORDER} 95 }; 96 97 98 static const char* const jump_conditional_mnem[] = { 99 /*0*/ "jo", "jno", "jc", "jnc", 100 /*4*/ "jz", "jnz", "jna", "ja", 101 /*8*/ "js", "jns", "jpe", "jpo", 102 /*12*/ "jl", "jnl", "jng", "jg" 103 }; 104 105 106 static const char* const set_conditional_mnem[] = { 107 /*0*/ "seto", "setno", "setc", "setnc", 108 /*4*/ "setz", "setnz", "setna", "seta", 109 /*8*/ "sets", "setns", "setpe", "setpo", 110 /*12*/ "setl", "setnl", "setng", "setg" 111 }; 112 113 114 static const char* const conditional_move_mnem[] = { 115 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc", 116 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova", 117 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo", 118 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg" 119 }; 120 121 122 enum InstructionType { 123 NO_INSTR, 124 ZERO_OPERANDS_INSTR, 125 TWO_OPERANDS_INSTR, 126 JUMP_CONDITIONAL_SHORT_INSTR, 127 REGISTER_INSTR, 128 MOVE_REG_INSTR, 129 CALL_JUMP_INSTR, 130 SHORT_IMMEDIATE_INSTR, 131 BYTE_IMMEDIATE_INSTR 132 }; 133 134 135 struct InstructionDesc { 136 const char* mnem; 137 InstructionType type; 138 OperandOrder op_order_; 139 }; 140 141 142 class InstructionTable { 143 public: 144 InstructionTable(); 145 const InstructionDesc& Get(byte x) const { return instructions_[x]; } 146 static InstructionTable* get_instance() { 147 static InstructionTable table; 148 return &table; 149 } 150 151 private: 152 InstructionDesc instructions_[256]; 153 void Clear(); 154 void Init(); 155 void CopyTable(const ByteMnemonic bm[], InstructionType type); 156 void SetTableRange(InstructionType type, 157 byte start, 158 byte end, 159 const char* mnem); 160 void AddJumpConditionalShort(); 161 }; 162 163 164 InstructionTable::InstructionTable() { 165 Clear(); 166 Init(); 167 } 168 169 170 void InstructionTable::Clear() { 171 for (int i = 0; i < 256; i++) { 172 instructions_[i].mnem = ""; 173 instructions_[i].type = NO_INSTR; 174 instructions_[i].op_order_ = UNSET_OP_ORDER; 175 } 176 } 177 178 179 void InstructionTable::Init() { 180 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); 181 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); 182 CopyTable(call_jump_instr, CALL_JUMP_INSTR); 183 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); 184 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR); 185 AddJumpConditionalShort(); 186 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc"); 187 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec"); 188 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push"); 189 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop"); 190 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. 191 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); 192 } 193 194 195 void InstructionTable::CopyTable(const ByteMnemonic bm[], 196 InstructionType type) { 197 for (int i = 0; bm[i].b >= 0; i++) { 198 InstructionDesc* id = &instructions_[bm[i].b]; 199 id->mnem = bm[i].mnem; 200 id->op_order_ = bm[i].op_order_; 201 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 202 id->type = type; 203 } 204 } 205 206 207 void InstructionTable::SetTableRange(InstructionType type, 208 byte start, 209 byte end, 210 const char* mnem) { 211 for (byte b = start; b <= end; b++) { 212 InstructionDesc* id = &instructions_[b]; 213 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 214 id->mnem = mnem; 215 id->type = type; 216 } 217 } 218 219 220 void InstructionTable::AddJumpConditionalShort() { 221 for (byte b = 0x70; b <= 0x7F; b++) { 222 InstructionDesc* id = &instructions_[b]; 223 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 224 id->mnem = jump_conditional_mnem[b & 0x0F]; 225 id->type = JUMP_CONDITIONAL_SHORT_INSTR; 226 } 227 } 228 229 230 // The IA32 disassembler implementation. 231 class DisassemblerIA32 { 232 public: 233 DisassemblerIA32(const NameConverter& converter, 234 bool abort_on_unimplemented = true) 235 : converter_(converter), 236 vex_byte0_(0), 237 vex_byte1_(0), 238 vex_byte2_(0), 239 instruction_table_(InstructionTable::get_instance()), 240 tmp_buffer_pos_(0), 241 abort_on_unimplemented_(abort_on_unimplemented) { 242 tmp_buffer_[0] = '\0'; 243 } 244 245 virtual ~DisassemblerIA32() {} 246 247 // Writes one disassembled instruction into 'buffer' (0-terminated). 248 // Returns the length of the disassembled machine instruction in bytes. 249 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); 250 251 private: 252 const NameConverter& converter_; 253 byte vex_byte0_; // 0xc4 or 0xc5 254 byte vex_byte1_; 255 byte vex_byte2_; // only for 3 bytes vex prefix 256 InstructionTable* instruction_table_; 257 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; 258 unsigned int tmp_buffer_pos_; 259 bool abort_on_unimplemented_; 260 261 enum { 262 eax = 0, 263 ecx = 1, 264 edx = 2, 265 ebx = 3, 266 esp = 4, 267 ebp = 5, 268 esi = 6, 269 edi = 7 270 }; 271 272 273 enum ShiftOpcodeExtension { 274 kROL = 0, 275 kROR = 1, 276 kRCL = 2, 277 kRCR = 3, 278 kSHL = 4, 279 KSHR = 5, 280 kSAR = 7 281 }; 282 283 bool vex_128() { 284 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 285 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 286 return (checked & 4) == 0; 287 } 288 289 bool vex_none() { 290 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 291 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 292 return (checked & 3) == 0; 293 } 294 295 bool vex_66() { 296 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 297 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 298 return (checked & 3) == 1; 299 } 300 301 bool vex_f3() { 302 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 303 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 304 return (checked & 3) == 2; 305 } 306 307 bool vex_f2() { 308 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 309 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 310 return (checked & 3) == 3; 311 } 312 313 bool vex_w() { 314 if (vex_byte0_ == 0xc5) return false; 315 return (vex_byte2_ & 0x80) != 0; 316 } 317 318 bool vex_0f() { 319 if (vex_byte0_ == 0xc5) return true; 320 return (vex_byte1_ & 3) == 1; 321 } 322 323 bool vex_0f38() { 324 if (vex_byte0_ == 0xc5) return false; 325 return (vex_byte1_ & 3) == 2; 326 } 327 328 bool vex_0f3a() { 329 if (vex_byte0_ == 0xc5) return false; 330 return (vex_byte1_ & 3) == 3; 331 } 332 333 int vex_vreg() { 334 DCHECK(vex_byte0_ == 0xc4 || vex_byte0_ == 0xc5); 335 byte checked = vex_byte0_ == 0xc4 ? vex_byte2_ : vex_byte1_; 336 return ~(checked >> 3) & 0xf; 337 } 338 339 char float_size_code() { return "sd"[vex_w()]; } 340 341 const char* NameOfCPURegister(int reg) const { 342 return converter_.NameOfCPURegister(reg); 343 } 344 345 346 const char* NameOfByteCPURegister(int reg) const { 347 return converter_.NameOfByteCPURegister(reg); 348 } 349 350 351 const char* NameOfXMMRegister(int reg) const { 352 return converter_.NameOfXMMRegister(reg); 353 } 354 355 356 const char* NameOfAddress(byte* addr) const { 357 return converter_.NameOfAddress(addr); 358 } 359 360 361 // Disassembler helper functions. 362 static void get_modrm(byte data, int* mod, int* regop, int* rm) { 363 *mod = (data >> 6) & 3; 364 *regop = (data & 0x38) >> 3; 365 *rm = data & 7; 366 } 367 368 369 static void get_sib(byte data, int* scale, int* index, int* base) { 370 *scale = (data >> 6) & 3; 371 *index = (data >> 3) & 7; 372 *base = data & 7; 373 } 374 375 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const; 376 377 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); 378 int PrintRightOperand(byte* modrmp); 379 int PrintRightByteOperand(byte* modrmp); 380 int PrintRightXMMOperand(byte* modrmp); 381 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); 382 int PrintImmediateOp(byte* data); 383 int F7Instruction(byte* data); 384 int D1D3C1Instruction(byte* data); 385 int JumpShort(byte* data); 386 int JumpConditional(byte* data, const char* comment); 387 int JumpConditionalShort(byte* data, const char* comment); 388 int SetCC(byte* data); 389 int CMov(byte* data); 390 int FPUInstruction(byte* data); 391 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); 392 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); 393 int AVXInstruction(byte* data); 394 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...); 395 396 void UnimplementedInstruction() { 397 if (abort_on_unimplemented_) { 398 UNIMPLEMENTED(); 399 } else { 400 AppendToBuffer("'Unimplemented Instruction'"); 401 } 402 } 403 }; 404 405 406 void DisassemblerIA32::AppendToBuffer(const char* format, ...) { 407 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; 408 va_list args; 409 va_start(args, format); 410 int result = v8::internal::VSNPrintF(buf, format, args); 411 va_end(args); 412 tmp_buffer_pos_ += result; 413 } 414 415 int DisassemblerIA32::PrintRightOperandHelper( 416 byte* modrmp, 417 RegisterNameMapping direct_register_name) { 418 int mod, regop, rm; 419 get_modrm(*modrmp, &mod, ®op, &rm); 420 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : 421 &DisassemblerIA32::NameOfCPURegister; 422 switch (mod) { 423 case 0: 424 if (rm == ebp) { 425 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); 426 AppendToBuffer("[0x%x]", disp); 427 return 5; 428 } else if (rm == esp) { 429 byte sib = *(modrmp + 1); 430 int scale, index, base; 431 get_sib(sib, &scale, &index, &base); 432 if (index == esp && base == esp && scale == 0 /*times_1*/) { 433 AppendToBuffer("[%s]", (this->*register_name)(rm)); 434 return 2; 435 } else if (base == ebp) { 436 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); 437 AppendToBuffer("[%s*%d%s0x%x]", 438 (this->*register_name)(index), 439 1 << scale, 440 disp < 0 ? "-" : "+", 441 disp < 0 ? -disp : disp); 442 return 6; 443 } else if (index != esp && base != ebp) { 444 // [base+index*scale] 445 AppendToBuffer("[%s+%s*%d]", 446 (this->*register_name)(base), 447 (this->*register_name)(index), 448 1 << scale); 449 return 2; 450 } else { 451 UnimplementedInstruction(); 452 return 1; 453 } 454 } else { 455 AppendToBuffer("[%s]", (this->*register_name)(rm)); 456 return 1; 457 } 458 break; 459 case 1: // fall through 460 case 2: 461 if (rm == esp) { 462 byte sib = *(modrmp + 1); 463 int scale, index, base; 464 get_sib(sib, &scale, &index, &base); 465 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) 466 : *reinterpret_cast<int8_t*>(modrmp + 2); 467 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { 468 AppendToBuffer("[%s%s0x%x]", 469 (this->*register_name)(rm), 470 disp < 0 ? "-" : "+", 471 disp < 0 ? -disp : disp); 472 } else { 473 AppendToBuffer("[%s+%s*%d%s0x%x]", 474 (this->*register_name)(base), 475 (this->*register_name)(index), 476 1 << scale, 477 disp < 0 ? "-" : "+", 478 disp < 0 ? -disp : disp); 479 } 480 return mod == 2 ? 6 : 3; 481 } else { 482 // No sib. 483 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) 484 : *reinterpret_cast<int8_t*>(modrmp + 1); 485 AppendToBuffer("[%s%s0x%x]", 486 (this->*register_name)(rm), 487 disp < 0 ? "-" : "+", 488 disp < 0 ? -disp : disp); 489 return mod == 2 ? 5 : 2; 490 } 491 break; 492 case 3: 493 AppendToBuffer("%s", (this->*register_name)(rm)); 494 return 1; 495 default: 496 UnimplementedInstruction(); 497 return 1; 498 } 499 UNREACHABLE(); 500 } 501 502 503 int DisassemblerIA32::PrintRightOperand(byte* modrmp) { 504 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); 505 } 506 507 508 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { 509 return PrintRightOperandHelper(modrmp, 510 &DisassemblerIA32::NameOfByteCPURegister); 511 } 512 513 514 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) { 515 return PrintRightOperandHelper(modrmp, 516 &DisassemblerIA32::NameOfXMMRegister); 517 } 518 519 520 // Returns number of bytes used including the current *data. 521 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. 522 int DisassemblerIA32::PrintOperands(const char* mnem, 523 OperandOrder op_order, 524 byte* data) { 525 byte modrm = *data; 526 int mod, regop, rm; 527 get_modrm(modrm, &mod, ®op, &rm); 528 int advance = 0; 529 switch (op_order) { 530 case REG_OPER_OP_ORDER: { 531 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 532 advance = PrintRightOperand(data); 533 break; 534 } 535 case OPER_REG_OP_ORDER: { 536 AppendToBuffer("%s ", mnem); 537 advance = PrintRightOperand(data); 538 AppendToBuffer(",%s", NameOfCPURegister(regop)); 539 break; 540 } 541 default: 542 UNREACHABLE(); 543 break; 544 } 545 return advance; 546 } 547 548 549 // Returns number of bytes used by machine instruction, including *data byte. 550 // Writes immediate instructions to 'tmp_buffer_'. 551 int DisassemblerIA32::PrintImmediateOp(byte* data) { 552 bool sign_extension_bit = (*data & 0x02) != 0; 553 byte modrm = *(data+1); 554 int mod, regop, rm; 555 get_modrm(modrm, &mod, ®op, &rm); 556 const char* mnem = "Imm???"; 557 switch (regop) { 558 case 0: mnem = "add"; break; 559 case 1: mnem = "or"; break; 560 case 2: mnem = "adc"; break; 561 case 4: mnem = "and"; break; 562 case 5: mnem = "sub"; break; 563 case 6: mnem = "xor"; break; 564 case 7: mnem = "cmp"; break; 565 default: UnimplementedInstruction(); 566 } 567 AppendToBuffer("%s ", mnem); 568 int count = PrintRightOperand(data+1); 569 if (sign_extension_bit) { 570 AppendToBuffer(",0x%x", *(data + 1 + count)); 571 return 1 + count + 1 /*int8*/; 572 } else { 573 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); 574 return 1 + count + 4 /*int32_t*/; 575 } 576 } 577 578 579 // Returns number of bytes used, including *data. 580 int DisassemblerIA32::F7Instruction(byte* data) { 581 DCHECK_EQ(0xF7, *data); 582 byte modrm = *++data; 583 int mod, regop, rm; 584 get_modrm(modrm, &mod, ®op, &rm); 585 const char* mnem = NULL; 586 switch (regop) { 587 case 0: 588 mnem = "test"; 589 break; 590 case 2: 591 mnem = "not"; 592 break; 593 case 3: 594 mnem = "neg"; 595 break; 596 case 4: 597 mnem = "mul"; 598 break; 599 case 5: 600 mnem = "imul"; 601 break; 602 case 6: 603 mnem = "div"; 604 break; 605 case 7: 606 mnem = "idiv"; 607 break; 608 default: 609 UnimplementedInstruction(); 610 } 611 AppendToBuffer("%s ", mnem); 612 int count = PrintRightOperand(data); 613 if (regop == 0) { 614 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count)); 615 count += 4; 616 } 617 return 1 + count; 618 } 619 620 621 int DisassemblerIA32::D1D3C1Instruction(byte* data) { 622 byte op = *data; 623 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1); 624 byte modrm = *++data; 625 int mod, regop, rm; 626 get_modrm(modrm, &mod, ®op, &rm); 627 int imm8 = -1; 628 const char* mnem = NULL; 629 switch (regop) { 630 case kROL: 631 mnem = "rol"; 632 break; 633 case kROR: 634 mnem = "ror"; 635 break; 636 case kRCL: 637 mnem = "rcl"; 638 break; 639 case kRCR: 640 mnem = "rcr"; 641 break; 642 case kSHL: 643 mnem = "shl"; 644 break; 645 case KSHR: 646 mnem = "shr"; 647 break; 648 case kSAR: 649 mnem = "sar"; 650 break; 651 default: 652 UnimplementedInstruction(); 653 } 654 AppendToBuffer("%s ", mnem); 655 int count = PrintRightOperand(data); 656 if (op == 0xD1) { 657 imm8 = 1; 658 } else if (op == 0xC1) { 659 imm8 = *(data + 1); 660 count++; 661 } else if (op == 0xD3) { 662 // Shift/rotate by cl. 663 } 664 if (imm8 >= 0) { 665 AppendToBuffer(",%d", imm8); 666 } else { 667 AppendToBuffer(",cl"); 668 } 669 return 1 + count; 670 } 671 672 673 // Returns number of bytes used, including *data. 674 int DisassemblerIA32::JumpShort(byte* data) { 675 DCHECK_EQ(0xEB, *data); 676 byte b = *(data+1); 677 byte* dest = data + static_cast<int8_t>(b) + 2; 678 AppendToBuffer("jmp %s", NameOfAddress(dest)); 679 return 2; 680 } 681 682 683 // Returns number of bytes used, including *data. 684 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { 685 DCHECK_EQ(0x0F, *data); 686 byte cond = *(data+1) & 0x0F; 687 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; 688 const char* mnem = jump_conditional_mnem[cond]; 689 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 690 if (comment != NULL) { 691 AppendToBuffer(", %s", comment); 692 } 693 return 6; // includes 0x0F 694 } 695 696 697 // Returns number of bytes used, including *data. 698 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { 699 byte cond = *data & 0x0F; 700 byte b = *(data+1); 701 byte* dest = data + static_cast<int8_t>(b) + 2; 702 const char* mnem = jump_conditional_mnem[cond]; 703 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 704 if (comment != NULL) { 705 AppendToBuffer(", %s", comment); 706 } 707 return 2; 708 } 709 710 711 // Returns number of bytes used, including *data. 712 int DisassemblerIA32::SetCC(byte* data) { 713 DCHECK_EQ(0x0F, *data); 714 byte cond = *(data+1) & 0x0F; 715 const char* mnem = set_conditional_mnem[cond]; 716 AppendToBuffer("%s ", mnem); 717 PrintRightByteOperand(data+2); 718 return 3; // Includes 0x0F. 719 } 720 721 722 // Returns number of bytes used, including *data. 723 int DisassemblerIA32::CMov(byte* data) { 724 DCHECK_EQ(0x0F, *data); 725 byte cond = *(data + 1) & 0x0F; 726 const char* mnem = conditional_move_mnem[cond]; 727 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); 728 return 2 + op_size; // includes 0x0F 729 } 730 731 732 int DisassemblerIA32::AVXInstruction(byte* data) { 733 byte opcode = *data; 734 byte* current = data + 1; 735 if (vex_66() && vex_0f38()) { 736 int mod, regop, rm, vvvv = vex_vreg(); 737 get_modrm(*current, &mod, ®op, &rm); 738 switch (opcode) { 739 case 0x99: 740 AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(), 741 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 742 current += PrintRightXMMOperand(current); 743 break; 744 case 0xa9: 745 AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(), 746 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 747 current += PrintRightXMMOperand(current); 748 break; 749 case 0xb9: 750 AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(), 751 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 752 current += PrintRightXMMOperand(current); 753 break; 754 case 0x9b: 755 AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(), 756 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 757 current += PrintRightXMMOperand(current); 758 break; 759 case 0xab: 760 AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(), 761 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 762 current += PrintRightXMMOperand(current); 763 break; 764 case 0xbb: 765 AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(), 766 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 767 current += PrintRightXMMOperand(current); 768 break; 769 case 0x9d: 770 AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(), 771 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 772 current += PrintRightXMMOperand(current); 773 break; 774 case 0xad: 775 AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(), 776 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 777 current += PrintRightXMMOperand(current); 778 break; 779 case 0xbd: 780 AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(), 781 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 782 current += PrintRightXMMOperand(current); 783 break; 784 case 0x9f: 785 AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(), 786 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 787 current += PrintRightXMMOperand(current); 788 break; 789 case 0xaf: 790 AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(), 791 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 792 current += PrintRightXMMOperand(current); 793 break; 794 case 0xbf: 795 AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(), 796 NameOfXMMRegister(regop), NameOfXMMRegister(vvvv)); 797 current += PrintRightXMMOperand(current); 798 break; 799 case 0xf7: 800 AppendToBuffer("shlx %s,", NameOfCPURegister(regop)); 801 current += PrintRightOperand(current); 802 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 803 break; 804 default: 805 UnimplementedInstruction(); 806 } 807 } else if (vex_f2() && vex_0f()) { 808 int mod, regop, rm, vvvv = vex_vreg(); 809 get_modrm(*current, &mod, ®op, &rm); 810 switch (opcode) { 811 case 0x58: 812 AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop), 813 NameOfXMMRegister(vvvv)); 814 current += PrintRightXMMOperand(current); 815 break; 816 case 0x59: 817 AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop), 818 NameOfXMMRegister(vvvv)); 819 current += PrintRightXMMOperand(current); 820 break; 821 case 0x5c: 822 AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop), 823 NameOfXMMRegister(vvvv)); 824 current += PrintRightXMMOperand(current); 825 break; 826 case 0x5d: 827 AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop), 828 NameOfXMMRegister(vvvv)); 829 current += PrintRightXMMOperand(current); 830 break; 831 case 0x5e: 832 AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop), 833 NameOfXMMRegister(vvvv)); 834 current += PrintRightXMMOperand(current); 835 break; 836 case 0x5f: 837 AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop), 838 NameOfXMMRegister(vvvv)); 839 current += PrintRightXMMOperand(current); 840 break; 841 default: 842 UnimplementedInstruction(); 843 } 844 } else if (vex_f3() && vex_0f()) { 845 int mod, regop, rm, vvvv = vex_vreg(); 846 get_modrm(*current, &mod, ®op, &rm); 847 switch (opcode) { 848 case 0x58: 849 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop), 850 NameOfXMMRegister(vvvv)); 851 current += PrintRightXMMOperand(current); 852 break; 853 case 0x59: 854 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop), 855 NameOfXMMRegister(vvvv)); 856 current += PrintRightXMMOperand(current); 857 break; 858 case 0x5c: 859 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop), 860 NameOfXMMRegister(vvvv)); 861 current += PrintRightXMMOperand(current); 862 break; 863 case 0x5d: 864 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop), 865 NameOfXMMRegister(vvvv)); 866 current += PrintRightXMMOperand(current); 867 break; 868 case 0x5e: 869 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop), 870 NameOfXMMRegister(vvvv)); 871 current += PrintRightXMMOperand(current); 872 break; 873 case 0x5f: 874 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop), 875 NameOfXMMRegister(vvvv)); 876 current += PrintRightXMMOperand(current); 877 break; 878 default: 879 UnimplementedInstruction(); 880 } 881 } else if (vex_none() && vex_0f38()) { 882 int mod, regop, rm, vvvv = vex_vreg(); 883 get_modrm(*current, &mod, ®op, &rm); 884 const char* mnem = "?"; 885 switch (opcode) { 886 case 0xf2: 887 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop), 888 NameOfCPURegister(vvvv)); 889 current += PrintRightOperand(current); 890 break; 891 case 0xf5: 892 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop)); 893 current += PrintRightOperand(current); 894 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 895 break; 896 case 0xf7: 897 AppendToBuffer("bextr %s,", NameOfCPURegister(regop)); 898 current += PrintRightOperand(current); 899 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 900 break; 901 case 0xf3: 902 switch (regop) { 903 case 1: 904 mnem = "blsr"; 905 break; 906 case 2: 907 mnem = "blsmsk"; 908 break; 909 case 3: 910 mnem = "blsi"; 911 break; 912 default: 913 UnimplementedInstruction(); 914 } 915 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv)); 916 current += PrintRightOperand(current); 917 mnem = "?"; 918 break; 919 default: 920 UnimplementedInstruction(); 921 } 922 } else if (vex_f2() && vex_0f38()) { 923 int mod, regop, rm, vvvv = vex_vreg(); 924 get_modrm(*current, &mod, ®op, &rm); 925 switch (opcode) { 926 case 0xf5: 927 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop), 928 NameOfCPURegister(vvvv)); 929 current += PrintRightOperand(current); 930 break; 931 case 0xf6: 932 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop), 933 NameOfCPURegister(vvvv)); 934 current += PrintRightOperand(current); 935 break; 936 case 0xf7: 937 AppendToBuffer("shrx %s,", NameOfCPURegister(regop)); 938 current += PrintRightOperand(current); 939 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 940 break; 941 default: 942 UnimplementedInstruction(); 943 } 944 } else if (vex_f3() && vex_0f38()) { 945 int mod, regop, rm, vvvv = vex_vreg(); 946 get_modrm(*current, &mod, ®op, &rm); 947 switch (opcode) { 948 case 0xf5: 949 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop), 950 NameOfCPURegister(vvvv)); 951 current += PrintRightOperand(current); 952 break; 953 case 0xf7: 954 AppendToBuffer("sarx %s,", NameOfCPURegister(regop)); 955 current += PrintRightOperand(current); 956 AppendToBuffer(",%s", NameOfCPURegister(vvvv)); 957 break; 958 default: 959 UnimplementedInstruction(); 960 } 961 } else if (vex_f2() && vex_0f3a()) { 962 int mod, regop, rm; 963 get_modrm(*current, &mod, ®op, &rm); 964 switch (opcode) { 965 case 0xf0: 966 AppendToBuffer("rorx %s,", NameOfCPURegister(regop)); 967 current += PrintRightOperand(current); 968 AppendToBuffer(",%d", *current & 0x1f); 969 current += 1; 970 break; 971 default: 972 UnimplementedInstruction(); 973 } 974 } else if (vex_none() && vex_0f()) { 975 int mod, regop, rm, vvvv = vex_vreg(); 976 get_modrm(*current, &mod, ®op, &rm); 977 switch (opcode) { 978 case 0x54: 979 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop), 980 NameOfXMMRegister(vvvv)); 981 current += PrintRightXMMOperand(current); 982 break; 983 case 0x57: 984 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop), 985 NameOfXMMRegister(vvvv)); 986 current += PrintRightXMMOperand(current); 987 break; 988 default: 989 UnimplementedInstruction(); 990 } 991 } else if (vex_66() && vex_0f()) { 992 int mod, regop, rm, vvvv = vex_vreg(); 993 get_modrm(*current, &mod, ®op, &rm); 994 switch (opcode) { 995 case 0x54: 996 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop), 997 NameOfXMMRegister(vvvv)); 998 current += PrintRightXMMOperand(current); 999 break; 1000 case 0x57: 1001 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop), 1002 NameOfXMMRegister(vvvv)); 1003 current += PrintRightXMMOperand(current); 1004 break; 1005 default: 1006 UnimplementedInstruction(); 1007 } 1008 } else { 1009 UnimplementedInstruction(); 1010 } 1011 1012 return static_cast<int>(current - data); 1013 } 1014 1015 1016 // Returns number of bytes used, including *data. 1017 int DisassemblerIA32::FPUInstruction(byte* data) { 1018 byte escape_opcode = *data; 1019 DCHECK_EQ(0xD8, escape_opcode & 0xF8); 1020 byte modrm_byte = *(data+1); 1021 1022 if (modrm_byte >= 0xC0) { 1023 return RegisterFPUInstruction(escape_opcode, modrm_byte); 1024 } else { 1025 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); 1026 } 1027 } 1028 1029 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, 1030 int modrm_byte, 1031 byte* modrm_start) { 1032 const char* mnem = "?"; 1033 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. 1034 switch (escape_opcode) { 1035 case 0xD9: switch (regop) { 1036 case 0: mnem = "fld_s"; break; 1037 case 2: mnem = "fst_s"; break; 1038 case 3: mnem = "fstp_s"; break; 1039 case 7: mnem = "fstcw"; break; 1040 default: UnimplementedInstruction(); 1041 } 1042 break; 1043 1044 case 0xDB: switch (regop) { 1045 case 0: mnem = "fild_s"; break; 1046 case 1: mnem = "fisttp_s"; break; 1047 case 2: mnem = "fist_s"; break; 1048 case 3: mnem = "fistp_s"; break; 1049 default: UnimplementedInstruction(); 1050 } 1051 break; 1052 1053 case 0xDD: switch (regop) { 1054 case 0: mnem = "fld_d"; break; 1055 case 1: mnem = "fisttp_d"; break; 1056 case 2: mnem = "fst_d"; break; 1057 case 3: mnem = "fstp_d"; break; 1058 default: UnimplementedInstruction(); 1059 } 1060 break; 1061 1062 case 0xDF: switch (regop) { 1063 case 5: mnem = "fild_d"; break; 1064 case 7: mnem = "fistp_d"; break; 1065 default: UnimplementedInstruction(); 1066 } 1067 break; 1068 1069 default: UnimplementedInstruction(); 1070 } 1071 AppendToBuffer("%s ", mnem); 1072 int count = PrintRightOperand(modrm_start); 1073 return count + 1; 1074 } 1075 1076 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, 1077 byte modrm_byte) { 1078 bool has_register = false; // Is the FPU register encoded in modrm_byte? 1079 const char* mnem = "?"; 1080 1081 switch (escape_opcode) { 1082 case 0xD8: 1083 has_register = true; 1084 switch (modrm_byte & 0xF8) { 1085 case 0xC0: mnem = "fadd_i"; break; 1086 case 0xE0: mnem = "fsub_i"; break; 1087 case 0xC8: mnem = "fmul_i"; break; 1088 case 0xF0: mnem = "fdiv_i"; break; 1089 default: UnimplementedInstruction(); 1090 } 1091 break; 1092 1093 case 0xD9: 1094 switch (modrm_byte & 0xF8) { 1095 case 0xC0: 1096 mnem = "fld"; 1097 has_register = true; 1098 break; 1099 case 0xC8: 1100 mnem = "fxch"; 1101 has_register = true; 1102 break; 1103 default: 1104 switch (modrm_byte) { 1105 case 0xE0: mnem = "fchs"; break; 1106 case 0xE1: mnem = "fabs"; break; 1107 case 0xE4: mnem = "ftst"; break; 1108 case 0xE8: mnem = "fld1"; break; 1109 case 0xEB: mnem = "fldpi"; break; 1110 case 0xED: mnem = "fldln2"; break; 1111 case 0xEE: mnem = "fldz"; break; 1112 case 0xF0: mnem = "f2xm1"; break; 1113 case 0xF1: mnem = "fyl2x"; break; 1114 case 0xF4: mnem = "fxtract"; break; 1115 case 0xF5: mnem = "fprem1"; break; 1116 case 0xF7: mnem = "fincstp"; break; 1117 case 0xF8: mnem = "fprem"; break; 1118 case 0xFC: mnem = "frndint"; break; 1119 case 0xFD: mnem = "fscale"; break; 1120 case 0xFE: mnem = "fsin"; break; 1121 case 0xFF: mnem = "fcos"; break; 1122 default: UnimplementedInstruction(); 1123 } 1124 } 1125 break; 1126 1127 case 0xDA: 1128 if (modrm_byte == 0xE9) { 1129 mnem = "fucompp"; 1130 } else { 1131 UnimplementedInstruction(); 1132 } 1133 break; 1134 1135 case 0xDB: 1136 if ((modrm_byte & 0xF8) == 0xE8) { 1137 mnem = "fucomi"; 1138 has_register = true; 1139 } else if (modrm_byte == 0xE2) { 1140 mnem = "fclex"; 1141 } else if (modrm_byte == 0xE3) { 1142 mnem = "fninit"; 1143 } else { 1144 UnimplementedInstruction(); 1145 } 1146 break; 1147 1148 case 0xDC: 1149 has_register = true; 1150 switch (modrm_byte & 0xF8) { 1151 case 0xC0: mnem = "fadd"; break; 1152 case 0xE8: mnem = "fsub"; break; 1153 case 0xC8: mnem = "fmul"; break; 1154 case 0xF8: mnem = "fdiv"; break; 1155 default: UnimplementedInstruction(); 1156 } 1157 break; 1158 1159 case 0xDD: 1160 has_register = true; 1161 switch (modrm_byte & 0xF8) { 1162 case 0xC0: mnem = "ffree"; break; 1163 case 0xD0: mnem = "fst"; break; 1164 case 0xD8: mnem = "fstp"; break; 1165 default: UnimplementedInstruction(); 1166 } 1167 break; 1168 1169 case 0xDE: 1170 if (modrm_byte == 0xD9) { 1171 mnem = "fcompp"; 1172 } else { 1173 has_register = true; 1174 switch (modrm_byte & 0xF8) { 1175 case 0xC0: mnem = "faddp"; break; 1176 case 0xE8: mnem = "fsubp"; break; 1177 case 0xC8: mnem = "fmulp"; break; 1178 case 0xF8: mnem = "fdivp"; break; 1179 default: UnimplementedInstruction(); 1180 } 1181 } 1182 break; 1183 1184 case 0xDF: 1185 if (modrm_byte == 0xE0) { 1186 mnem = "fnstsw_ax"; 1187 } else if ((modrm_byte & 0xF8) == 0xE8) { 1188 mnem = "fucomip"; 1189 has_register = true; 1190 } 1191 break; 1192 1193 default: UnimplementedInstruction(); 1194 } 1195 1196 if (has_register) { 1197 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); 1198 } else { 1199 AppendToBuffer("%s", mnem); 1200 } 1201 return 2; 1202 } 1203 1204 1205 // Mnemonics for instructions 0xF0 byte. 1206 // Returns NULL if the instruction is not handled here. 1207 static const char* F0Mnem(byte f0byte) { 1208 switch (f0byte) { 1209 case 0x0B: 1210 return "ud2"; 1211 case 0x18: 1212 return "prefetch"; 1213 case 0xA2: 1214 return "cpuid"; 1215 case 0xBE: 1216 return "movsx_b"; 1217 case 0xBF: 1218 return "movsx_w"; 1219 case 0xB6: 1220 return "movzx_b"; 1221 case 0xB7: 1222 return "movzx_w"; 1223 case 0xAF: 1224 return "imul"; 1225 case 0xA4: 1226 return "shld"; 1227 case 0xA5: 1228 return "shld"; 1229 case 0xAD: 1230 return "shrd"; 1231 case 0xAC: 1232 return "shrd"; // 3-operand version. 1233 case 0xAB: 1234 return "bts"; 1235 case 0xB0: 1236 return "cmpxchg_b"; 1237 case 0xB1: 1238 return "cmpxchg"; 1239 case 0xBC: 1240 return "bsf"; 1241 case 0xBD: 1242 return "bsr"; 1243 default: return NULL; 1244 } 1245 } 1246 1247 1248 // Disassembled instruction '*instr' and writes it into 'out_buffer'. 1249 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, 1250 byte* instr) { 1251 tmp_buffer_pos_ = 0; // starting to write as position 0 1252 byte* data = instr; 1253 // Check for hints. 1254 const char* branch_hint = NULL; 1255 // We use these two prefixes only with branch prediction 1256 if (*data == 0x3E /*ds*/) { 1257 branch_hint = "predicted taken"; 1258 data++; 1259 } else if (*data == 0x2E /*cs*/) { 1260 branch_hint = "predicted not taken"; 1261 data++; 1262 } else if (*data == 0xC4 && *(data + 1) >= 0xc0) { 1263 vex_byte0_ = *data; 1264 vex_byte1_ = *(data + 1); 1265 vex_byte2_ = *(data + 2); 1266 data += 3; 1267 } else if (*data == 0xC5 && *(data + 1) >= 0xc0) { 1268 vex_byte0_ = *data; 1269 vex_byte1_ = *(data + 1); 1270 data += 2; 1271 } else if (*data == 0xF0 /*lock*/) { 1272 AppendToBuffer("lock "); 1273 data++; 1274 } 1275 1276 bool processed = true; // Will be set to false if the current instruction 1277 // is not in 'instructions' table. 1278 // Decode AVX instructions. 1279 if (vex_byte0_ != 0) { 1280 data += AVXInstruction(data); 1281 } else { 1282 const InstructionDesc& idesc = instruction_table_->Get(*data); 1283 switch (idesc.type) { 1284 case ZERO_OPERANDS_INSTR: 1285 AppendToBuffer("%s", idesc.mnem); 1286 data++; 1287 break; 1288 1289 case TWO_OPERANDS_INSTR: 1290 data++; 1291 data += PrintOperands(idesc.mnem, idesc.op_order_, data); 1292 break; 1293 1294 case JUMP_CONDITIONAL_SHORT_INSTR: 1295 data += JumpConditionalShort(data, branch_hint); 1296 break; 1297 1298 case REGISTER_INSTR: 1299 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); 1300 data++; 1301 break; 1302 1303 case MOVE_REG_INSTR: { 1304 byte* addr = 1305 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); 1306 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07), 1307 NameOfAddress(addr)); 1308 data += 5; 1309 break; 1310 } 1311 1312 case CALL_JUMP_INSTR: { 1313 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5; 1314 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); 1315 data += 5; 1316 break; 1317 } 1318 1319 case SHORT_IMMEDIATE_INSTR: { 1320 byte* addr = 1321 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); 1322 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); 1323 data += 5; 1324 break; 1325 } 1326 1327 case BYTE_IMMEDIATE_INSTR: { 1328 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); 1329 data += 2; 1330 break; 1331 } 1332 1333 case NO_INSTR: 1334 processed = false; 1335 break; 1336 1337 default: 1338 UNIMPLEMENTED(); // This type is not implemented. 1339 } 1340 } 1341 //---------------------------- 1342 if (!processed) { 1343 switch (*data) { 1344 case 0xC2: 1345 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); 1346 data += 3; 1347 break; 1348 1349 case 0x6B: { 1350 data++; 1351 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 1352 AppendToBuffer(",%d", *data); 1353 data++; 1354 } break; 1355 1356 case 0x69: { 1357 data++; 1358 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 1359 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data)); 1360 data += 4; 1361 } 1362 break; 1363 1364 case 0xF6: 1365 { data++; 1366 int mod, regop, rm; 1367 get_modrm(*data, &mod, ®op, &rm); 1368 if (regop == eax) { 1369 AppendToBuffer("test_b "); 1370 data += PrintRightByteOperand(data); 1371 int32_t imm = *data; 1372 AppendToBuffer(",0x%x", imm); 1373 data++; 1374 } else { 1375 UnimplementedInstruction(); 1376 } 1377 } 1378 break; 1379 1380 case 0x81: // fall through 1381 case 0x83: // 0x81 with sign extension bit set 1382 data += PrintImmediateOp(data); 1383 break; 1384 1385 case 0x0F: 1386 { byte f0byte = data[1]; 1387 const char* f0mnem = F0Mnem(f0byte); 1388 if (f0byte == 0x18) { 1389 data += 2; 1390 int mod, regop, rm; 1391 get_modrm(*data, &mod, ®op, &rm); 1392 const char* suffix[] = {"nta", "1", "2", "3"}; 1393 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]); 1394 data += PrintRightOperand(data); 1395 } else if (f0byte == 0x1F && data[2] == 0) { 1396 AppendToBuffer("nop"); // 3 byte nop. 1397 data += 3; 1398 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) { 1399 AppendToBuffer("nop"); // 4 byte nop. 1400 data += 4; 1401 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 && 1402 data[4] == 0) { 1403 AppendToBuffer("nop"); // 5 byte nop. 1404 data += 5; 1405 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 && 1406 data[4] == 0 && data[5] == 0 && data[6] == 0) { 1407 AppendToBuffer("nop"); // 7 byte nop. 1408 data += 7; 1409 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 && 1410 data[4] == 0 && data[5] == 0 && data[6] == 0 && 1411 data[7] == 0) { 1412 AppendToBuffer("nop"); // 8 byte nop. 1413 data += 8; 1414 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) { 1415 AppendToBuffer("%s", f0mnem); 1416 data += 2; 1417 } else if (f0byte == 0x28) { 1418 data += 2; 1419 int mod, regop, rm; 1420 get_modrm(*data, &mod, ®op, &rm); 1421 AppendToBuffer("movaps %s,%s", 1422 NameOfXMMRegister(regop), 1423 NameOfXMMRegister(rm)); 1424 data++; 1425 } else if (f0byte == 0x10 || f0byte == 0x11) { 1426 data += 2; 1427 // movups xmm, xmm/m128 1428 // movups xmm/m128, xmm 1429 int mod, regop, rm; 1430 get_modrm(*data, &mod, ®op, &rm); 1431 AppendToBuffer("movups "); 1432 if (f0byte == 0x11) { 1433 data += PrintRightXMMOperand(data); 1434 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1435 } else { 1436 AppendToBuffer("%s,", NameOfXMMRegister(regop)); 1437 data += PrintRightXMMOperand(data); 1438 } 1439 } else if (f0byte == 0x2e) { 1440 data += 2; 1441 int mod, regop, rm; 1442 get_modrm(*data, &mod, ®op, &rm); 1443 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop)); 1444 data += PrintRightXMMOperand(data); 1445 } else if (f0byte >= 0x53 && f0byte <= 0x5F) { 1446 const char* const pseudo_op[] = { 1447 "rcpps", 1448 "andps", 1449 "andnps", 1450 "orps", 1451 "xorps", 1452 "addps", 1453 "mulps", 1454 "cvtps2pd", 1455 "cvtdq2ps", 1456 "subps", 1457 "minps", 1458 "divps", 1459 "maxps", 1460 }; 1461 1462 data += 2; 1463 int mod, regop, rm; 1464 get_modrm(*data, &mod, ®op, &rm); 1465 AppendToBuffer("%s %s,", 1466 pseudo_op[f0byte - 0x53], 1467 NameOfXMMRegister(regop)); 1468 data += PrintRightXMMOperand(data); 1469 } else if (f0byte == 0x50) { 1470 data += 2; 1471 int mod, regop, rm; 1472 get_modrm(*data, &mod, ®op, &rm); 1473 AppendToBuffer("movmskps %s,%s", 1474 NameOfCPURegister(regop), 1475 NameOfXMMRegister(rm)); 1476 data++; 1477 } else if (f0byte== 0xC6) { 1478 // shufps xmm, xmm/m128, imm8 1479 data += 2; 1480 int mod, regop, rm; 1481 get_modrm(*data, &mod, ®op, &rm); 1482 int8_t imm8 = static_cast<int8_t>(data[1]); 1483 AppendToBuffer("shufps %s,%s,%d", 1484 NameOfXMMRegister(rm), 1485 NameOfXMMRegister(regop), 1486 static_cast<int>(imm8)); 1487 data += 2; 1488 } else if ((f0byte & 0xF0) == 0x80) { 1489 data += JumpConditional(data, branch_hint); 1490 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || 1491 f0byte == 0xB7 || f0byte == 0xAF) { 1492 data += 2; 1493 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); 1494 } else if ((f0byte & 0xF0) == 0x90) { 1495 data += SetCC(data); 1496 } else if ((f0byte & 0xF0) == 0x40) { 1497 data += CMov(data); 1498 } else if (f0byte == 0xA4 || f0byte == 0xAC) { 1499 // shld, shrd 1500 data += 2; 1501 AppendToBuffer("%s ", f0mnem); 1502 int mod, regop, rm; 1503 get_modrm(*data, &mod, ®op, &rm); 1504 int8_t imm8 = static_cast<int8_t>(data[1]); 1505 data += 2; 1506 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm), 1507 NameOfCPURegister(regop), static_cast<int>(imm8)); 1508 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { 1509 // shrd_cl, shld_cl, bts 1510 data += 2; 1511 AppendToBuffer("%s ", f0mnem); 1512 int mod, regop, rm; 1513 get_modrm(*data, &mod, ®op, &rm); 1514 data += PrintRightOperand(data); 1515 if (f0byte == 0xAB) { 1516 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1517 } else { 1518 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); 1519 } 1520 } else if (f0byte == 0xB0) { 1521 // cmpxchg_b 1522 data += 2; 1523 AppendToBuffer("%s ", f0mnem); 1524 int mod, regop, rm; 1525 get_modrm(*data, &mod, ®op, &rm); 1526 data += PrintRightOperand(data); 1527 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1528 } else if (f0byte == 0xB1) { 1529 // cmpxchg 1530 data += 2; 1531 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data); 1532 } else if (f0byte == 0xBC) { 1533 data += 2; 1534 int mod, regop, rm; 1535 get_modrm(*data, &mod, ®op, &rm); 1536 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); 1537 data += PrintRightOperand(data); 1538 } else if (f0byte == 0xBD) { 1539 data += 2; 1540 int mod, regop, rm; 1541 get_modrm(*data, &mod, ®op, &rm); 1542 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); 1543 data += PrintRightOperand(data); 1544 } else { 1545 UnimplementedInstruction(); 1546 } 1547 } 1548 break; 1549 1550 case 0x8F: 1551 { data++; 1552 int mod, regop, rm; 1553 get_modrm(*data, &mod, ®op, &rm); 1554 if (regop == eax) { 1555 AppendToBuffer("pop "); 1556 data += PrintRightOperand(data); 1557 } 1558 } 1559 break; 1560 1561 case 0xFF: 1562 { data++; 1563 int mod, regop, rm; 1564 get_modrm(*data, &mod, ®op, &rm); 1565 const char* mnem = NULL; 1566 switch (regop) { 1567 case esi: mnem = "push"; break; 1568 case eax: mnem = "inc"; break; 1569 case ecx: mnem = "dec"; break; 1570 case edx: mnem = "call"; break; 1571 case esp: mnem = "jmp"; break; 1572 default: mnem = "???"; 1573 } 1574 AppendToBuffer("%s ", mnem); 1575 data += PrintRightOperand(data); 1576 } 1577 break; 1578 1579 case 0xC7: // imm32, fall through 1580 case 0xC6: // imm8 1581 { bool is_byte = *data == 0xC6; 1582 data++; 1583 if (is_byte) { 1584 AppendToBuffer("%s ", "mov_b"); 1585 data += PrintRightByteOperand(data); 1586 int32_t imm = *data; 1587 AppendToBuffer(",0x%x", imm); 1588 data++; 1589 } else { 1590 AppendToBuffer("%s ", "mov"); 1591 data += PrintRightOperand(data); 1592 int32_t imm = *reinterpret_cast<int32_t*>(data); 1593 AppendToBuffer(",0x%x", imm); 1594 data += 4; 1595 } 1596 } 1597 break; 1598 1599 case 0x80: 1600 { data++; 1601 int mod, regop, rm; 1602 get_modrm(*data, &mod, ®op, &rm); 1603 const char* mnem = NULL; 1604 switch (regop) { 1605 case 5: mnem = "subb"; break; 1606 case 7: mnem = "cmpb"; break; 1607 default: UnimplementedInstruction(); 1608 } 1609 AppendToBuffer("%s ", mnem); 1610 data += PrintRightByteOperand(data); 1611 int32_t imm = *data; 1612 AppendToBuffer(",0x%x", imm); 1613 data++; 1614 } 1615 break; 1616 1617 case 0x88: // 8bit, fall through 1618 case 0x89: // 32bit 1619 { bool is_byte = *data == 0x88; 1620 int mod, regop, rm; 1621 data++; 1622 get_modrm(*data, &mod, ®op, &rm); 1623 if (is_byte) { 1624 AppendToBuffer("%s ", "mov_b"); 1625 data += PrintRightByteOperand(data); 1626 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1627 } else { 1628 AppendToBuffer("%s ", "mov"); 1629 data += PrintRightOperand(data); 1630 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1631 } 1632 } 1633 break; 1634 1635 case 0x66: // prefix 1636 while (*data == 0x66) data++; 1637 if (*data == 0xf && data[1] == 0x1f) { 1638 AppendToBuffer("nop"); // 0x66 prefix 1639 } else if (*data == 0x39) { 1640 data++; 1641 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data); 1642 } else if (*data == 0x3B) { 1643 data++; 1644 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data); 1645 } else if (*data == 0x81) { 1646 data++; 1647 AppendToBuffer("cmpw "); 1648 data += PrintRightOperand(data); 1649 int imm = *reinterpret_cast<int16_t*>(data); 1650 AppendToBuffer(",0x%x", imm); 1651 data += 2; 1652 } else if (*data == 0x87) { 1653 data++; 1654 int mod, regop, rm; 1655 get_modrm(*data, &mod, ®op, &rm); 1656 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop)); 1657 data += PrintRightOperand(data); 1658 } else if (*data == 0x89) { 1659 data++; 1660 int mod, regop, rm; 1661 get_modrm(*data, &mod, ®op, &rm); 1662 AppendToBuffer("mov_w "); 1663 data += PrintRightOperand(data); 1664 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1665 } else if (*data == 0x8B) { 1666 data++; 1667 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); 1668 } else if (*data == 0x90) { 1669 AppendToBuffer("nop"); // 0x66 prefix 1670 } else if (*data == 0xC7) { 1671 data++; 1672 AppendToBuffer("%s ", "mov_w"); 1673 data += PrintRightOperand(data); 1674 int imm = *reinterpret_cast<int16_t*>(data); 1675 AppendToBuffer(",0x%x", imm); 1676 data += 2; 1677 } else if (*data == 0xF7) { 1678 data++; 1679 AppendToBuffer("%s ", "test_w"); 1680 data += PrintRightOperand(data); 1681 int imm = *reinterpret_cast<int16_t*>(data); 1682 AppendToBuffer(",0x%x", imm); 1683 data += 2; 1684 } else if (*data == 0x0F) { 1685 data++; 1686 if (*data == 0x38) { 1687 data++; 1688 if (*data == 0x17) { 1689 data++; 1690 int mod, regop, rm; 1691 get_modrm(*data, &mod, ®op, &rm); 1692 AppendToBuffer("ptest %s,%s", 1693 NameOfXMMRegister(regop), 1694 NameOfXMMRegister(rm)); 1695 data++; 1696 } else if (*data == 0x2A) { 1697 // movntdqa 1698 UnimplementedInstruction(); 1699 } else { 1700 UnimplementedInstruction(); 1701 } 1702 } else if (*data == 0x3A) { 1703 data++; 1704 if (*data == 0x0A) { 1705 data++; 1706 int mod, regop, rm; 1707 get_modrm(*data, &mod, ®op, &rm); 1708 int8_t imm8 = static_cast<int8_t>(data[1]); 1709 AppendToBuffer("roundss %s,%s,%d", NameOfXMMRegister(regop), 1710 NameOfXMMRegister(rm), static_cast<int>(imm8)); 1711 data += 2; 1712 } else if (*data == 0x0B) { 1713 data++; 1714 int mod, regop, rm; 1715 get_modrm(*data, &mod, ®op, &rm); 1716 int8_t imm8 = static_cast<int8_t>(data[1]); 1717 AppendToBuffer("roundsd %s,%s,%d", 1718 NameOfXMMRegister(regop), 1719 NameOfXMMRegister(rm), 1720 static_cast<int>(imm8)); 1721 data += 2; 1722 } else if (*data == 0x16) { 1723 data++; 1724 int mod, regop, rm; 1725 get_modrm(*data, &mod, &rm, ®op); 1726 int8_t imm8 = static_cast<int8_t>(data[1]); 1727 AppendToBuffer("pextrd %s,%s,%d", 1728 NameOfCPURegister(regop), 1729 NameOfXMMRegister(rm), 1730 static_cast<int>(imm8)); 1731 data += 2; 1732 } else if (*data == 0x17) { 1733 data++; 1734 int mod, regop, rm; 1735 get_modrm(*data, &mod, ®op, &rm); 1736 int8_t imm8 = static_cast<int8_t>(data[1]); 1737 AppendToBuffer("extractps %s,%s,%d", 1738 NameOfCPURegister(rm), 1739 NameOfXMMRegister(regop), 1740 static_cast<int>(imm8)); 1741 data += 2; 1742 } else if (*data == 0x22) { 1743 data++; 1744 int mod, regop, rm; 1745 get_modrm(*data, &mod, ®op, &rm); 1746 int8_t imm8 = static_cast<int8_t>(data[1]); 1747 AppendToBuffer("pinsrd %s,%s,%d", 1748 NameOfXMMRegister(regop), 1749 NameOfCPURegister(rm), 1750 static_cast<int>(imm8)); 1751 data += 2; 1752 } else { 1753 UnimplementedInstruction(); 1754 } 1755 } else if (*data == 0x2E || *data == 0x2F) { 1756 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd"; 1757 data++; 1758 int mod, regop, rm; 1759 get_modrm(*data, &mod, ®op, &rm); 1760 if (mod == 0x3) { 1761 AppendToBuffer("%s %s,%s", mnem, 1762 NameOfXMMRegister(regop), 1763 NameOfXMMRegister(rm)); 1764 data++; 1765 } else { 1766 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1767 data += PrintRightOperand(data); 1768 } 1769 } else if (*data == 0x50) { 1770 data++; 1771 int mod, regop, rm; 1772 get_modrm(*data, &mod, ®op, &rm); 1773 AppendToBuffer("movmskpd %s,%s", 1774 NameOfCPURegister(regop), 1775 NameOfXMMRegister(rm)); 1776 data++; 1777 } else if (*data == 0x54) { 1778 data++; 1779 int mod, regop, rm; 1780 get_modrm(*data, &mod, ®op, &rm); 1781 AppendToBuffer("andpd %s,%s", 1782 NameOfXMMRegister(regop), 1783 NameOfXMMRegister(rm)); 1784 data++; 1785 } else if (*data == 0x56) { 1786 data++; 1787 int mod, regop, rm; 1788 get_modrm(*data, &mod, ®op, &rm); 1789 AppendToBuffer("orpd %s,%s", 1790 NameOfXMMRegister(regop), 1791 NameOfXMMRegister(rm)); 1792 data++; 1793 } else if (*data == 0x57) { 1794 data++; 1795 int mod, regop, rm; 1796 get_modrm(*data, &mod, ®op, &rm); 1797 AppendToBuffer("xorpd %s,%s", 1798 NameOfXMMRegister(regop), 1799 NameOfXMMRegister(rm)); 1800 data++; 1801 } else if (*data == 0x6E) { 1802 data++; 1803 int mod, regop, rm; 1804 get_modrm(*data, &mod, ®op, &rm); 1805 AppendToBuffer("movd %s,", NameOfXMMRegister(regop)); 1806 data += PrintRightOperand(data); 1807 } else if (*data == 0x6F) { 1808 data++; 1809 int mod, regop, rm; 1810 get_modrm(*data, &mod, ®op, &rm); 1811 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop)); 1812 data += PrintRightXMMOperand(data); 1813 } else if (*data == 0x70) { 1814 data++; 1815 int mod, regop, rm; 1816 get_modrm(*data, &mod, ®op, &rm); 1817 int8_t imm8 = static_cast<int8_t>(data[1]); 1818 AppendToBuffer("pshufd %s,%s,%d", 1819 NameOfXMMRegister(regop), 1820 NameOfXMMRegister(rm), 1821 static_cast<int>(imm8)); 1822 data += 2; 1823 } else if (*data == 0x62) { 1824 data++; 1825 int mod, regop, rm; 1826 get_modrm(*data, &mod, ®op, &rm); 1827 AppendToBuffer("punpckldq %s,%s", NameOfXMMRegister(regop), 1828 NameOfXMMRegister(rm)); 1829 data++; 1830 } else if (*data == 0x6A) { 1831 data++; 1832 int mod, regop, rm; 1833 get_modrm(*data, &mod, ®op, &rm); 1834 AppendToBuffer("punpckhdq %s,%s", NameOfXMMRegister(regop), 1835 NameOfXMMRegister(rm)); 1836 data++; 1837 } else if (*data == 0x76) { 1838 data++; 1839 int mod, regop, rm; 1840 get_modrm(*data, &mod, ®op, &rm); 1841 AppendToBuffer("pcmpeqd %s,%s", 1842 NameOfXMMRegister(regop), 1843 NameOfXMMRegister(rm)); 1844 data++; 1845 } else if (*data == 0x90) { 1846 data++; 1847 AppendToBuffer("nop"); // 2 byte nop. 1848 } else if (*data == 0xF3) { 1849 data++; 1850 int mod, regop, rm; 1851 get_modrm(*data, &mod, ®op, &rm); 1852 AppendToBuffer("psllq %s,%s", 1853 NameOfXMMRegister(regop), 1854 NameOfXMMRegister(rm)); 1855 data++; 1856 } else if (*data == 0x72) { 1857 data++; 1858 int mod, regop, rm; 1859 get_modrm(*data, &mod, ®op, &rm); 1860 int8_t imm8 = static_cast<int8_t>(data[1]); 1861 DCHECK(regop == esi || regop == edx); 1862 AppendToBuffer("%s %s,%d", (regop == esi) ? "pslld" : "psrld", 1863 NameOfXMMRegister(rm), static_cast<int>(imm8)); 1864 data += 2; 1865 } else if (*data == 0x73) { 1866 data++; 1867 int mod, regop, rm; 1868 get_modrm(*data, &mod, ®op, &rm); 1869 int8_t imm8 = static_cast<int8_t>(data[1]); 1870 DCHECK(regop == esi || regop == edx); 1871 AppendToBuffer("%s %s,%d", 1872 (regop == esi) ? "psllq" : "psrlq", 1873 NameOfXMMRegister(rm), 1874 static_cast<int>(imm8)); 1875 data += 2; 1876 } else if (*data == 0xD3) { 1877 data++; 1878 int mod, regop, rm; 1879 get_modrm(*data, &mod, ®op, &rm); 1880 AppendToBuffer("psrlq %s,%s", 1881 NameOfXMMRegister(regop), 1882 NameOfXMMRegister(rm)); 1883 data++; 1884 } else if (*data == 0x7F) { 1885 AppendToBuffer("movdqa "); 1886 data++; 1887 int mod, regop, rm; 1888 get_modrm(*data, &mod, ®op, &rm); 1889 data += PrintRightXMMOperand(data); 1890 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1891 } else if (*data == 0x7E) { 1892 data++; 1893 int mod, regop, rm; 1894 get_modrm(*data, &mod, ®op, &rm); 1895 AppendToBuffer("movd "); 1896 data += PrintRightOperand(data); 1897 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1898 } else if (*data == 0xDB) { 1899 data++; 1900 int mod, regop, rm; 1901 get_modrm(*data, &mod, ®op, &rm); 1902 AppendToBuffer("pand %s,%s", 1903 NameOfXMMRegister(regop), 1904 NameOfXMMRegister(rm)); 1905 data++; 1906 } else if (*data == 0xE7) { 1907 data++; 1908 int mod, regop, rm; 1909 get_modrm(*data, &mod, ®op, &rm); 1910 if (mod == 3) { 1911 // movntdq 1912 UnimplementedInstruction(); 1913 } else { 1914 UnimplementedInstruction(); 1915 } 1916 } else if (*data == 0xEF) { 1917 data++; 1918 int mod, regop, rm; 1919 get_modrm(*data, &mod, ®op, &rm); 1920 AppendToBuffer("pxor %s,%s", 1921 NameOfXMMRegister(regop), 1922 NameOfXMMRegister(rm)); 1923 data++; 1924 } else if (*data == 0xEB) { 1925 data++; 1926 int mod, regop, rm; 1927 get_modrm(*data, &mod, ®op, &rm); 1928 AppendToBuffer("por %s,%s", 1929 NameOfXMMRegister(regop), 1930 NameOfXMMRegister(rm)); 1931 data++; 1932 } else if (*data == 0xB1) { 1933 data++; 1934 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data); 1935 } else { 1936 UnimplementedInstruction(); 1937 } 1938 } else { 1939 UnimplementedInstruction(); 1940 } 1941 break; 1942 1943 case 0xFE: 1944 { data++; 1945 int mod, regop, rm; 1946 get_modrm(*data, &mod, ®op, &rm); 1947 if (regop == ecx) { 1948 AppendToBuffer("dec_b "); 1949 data += PrintRightOperand(data); 1950 } else { 1951 UnimplementedInstruction(); 1952 } 1953 } 1954 break; 1955 1956 case 0x68: 1957 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1)); 1958 data += 5; 1959 break; 1960 1961 case 0x6A: 1962 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); 1963 data += 2; 1964 break; 1965 1966 case 0xA8: 1967 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1)); 1968 data += 2; 1969 break; 1970 1971 case 0xA9: 1972 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1)); 1973 data += 5; 1974 break; 1975 1976 case 0xD1: // fall through 1977 case 0xD3: // fall through 1978 case 0xC1: 1979 data += D1D3C1Instruction(data); 1980 break; 1981 1982 case 0xD8: // fall through 1983 case 0xD9: // fall through 1984 case 0xDA: // fall through 1985 case 0xDB: // fall through 1986 case 0xDC: // fall through 1987 case 0xDD: // fall through 1988 case 0xDE: // fall through 1989 case 0xDF: 1990 data += FPUInstruction(data); 1991 break; 1992 1993 case 0xEB: 1994 data += JumpShort(data); 1995 break; 1996 1997 case 0xF2: 1998 if (*(data+1) == 0x0F) { 1999 byte b2 = *(data+2); 2000 if (b2 == 0x11) { 2001 AppendToBuffer("movsd "); 2002 data += 3; 2003 int mod, regop, rm; 2004 get_modrm(*data, &mod, ®op, &rm); 2005 data += PrintRightXMMOperand(data); 2006 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 2007 } else if (b2 == 0x10) { 2008 data += 3; 2009 int mod, regop, rm; 2010 get_modrm(*data, &mod, ®op, &rm); 2011 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); 2012 data += PrintRightXMMOperand(data); 2013 } else if (b2 == 0x5A) { 2014 data += 3; 2015 int mod, regop, rm; 2016 get_modrm(*data, &mod, ®op, &rm); 2017 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop)); 2018 data += PrintRightXMMOperand(data); 2019 } else { 2020 const char* mnem = "?"; 2021 switch (b2) { 2022 case 0x2A: 2023 mnem = "cvtsi2sd"; 2024 break; 2025 case 0x2C: 2026 mnem = "cvttsd2si"; 2027 break; 2028 case 0x2D: 2029 mnem = "cvtsd2si"; 2030 break; 2031 case 0x51: 2032 mnem = "sqrtsd"; 2033 break; 2034 case 0x58: 2035 mnem = "addsd"; 2036 break; 2037 case 0x59: 2038 mnem = "mulsd"; 2039 break; 2040 case 0x5C: 2041 mnem = "subsd"; 2042 break; 2043 case 0x5D: 2044 mnem = "minsd"; 2045 break; 2046 case 0x5E: 2047 mnem = "divsd"; 2048 break; 2049 case 0x5F: 2050 mnem = "maxsd"; 2051 break; 2052 } 2053 data += 3; 2054 int mod, regop, rm; 2055 get_modrm(*data, &mod, ®op, &rm); 2056 if (b2 == 0x2A) { 2057 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2058 data += PrintRightOperand(data); 2059 } else if (b2 == 0x2C || b2 == 0x2D) { 2060 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 2061 data += PrintRightXMMOperand(data); 2062 } else if (b2 == 0xC2) { 2063 // Intel manual 2A, Table 3-18. 2064 const char* const pseudo_op[] = { 2065 "cmpeqsd", 2066 "cmpltsd", 2067 "cmplesd", 2068 "cmpunordsd", 2069 "cmpneqsd", 2070 "cmpnltsd", 2071 "cmpnlesd", 2072 "cmpordsd" 2073 }; 2074 AppendToBuffer("%s %s,%s", 2075 pseudo_op[data[1]], 2076 NameOfXMMRegister(regop), 2077 NameOfXMMRegister(rm)); 2078 data += 2; 2079 } else { 2080 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2081 data += PrintRightXMMOperand(data); 2082 } 2083 } 2084 } else { 2085 UnimplementedInstruction(); 2086 } 2087 break; 2088 2089 case 0xF3: 2090 if (*(data+1) == 0x0F) { 2091 byte b2 = *(data+2); 2092 if (b2 == 0x11) { 2093 AppendToBuffer("movss "); 2094 data += 3; 2095 int mod, regop, rm; 2096 get_modrm(*data, &mod, ®op, &rm); 2097 data += PrintRightXMMOperand(data); 2098 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 2099 } else if (b2 == 0x10) { 2100 data += 3; 2101 int mod, regop, rm; 2102 get_modrm(*data, &mod, ®op, &rm); 2103 AppendToBuffer("movss %s,", NameOfXMMRegister(regop)); 2104 data += PrintRightXMMOperand(data); 2105 } else if (b2 == 0x5A) { 2106 data += 3; 2107 int mod, regop, rm; 2108 get_modrm(*data, &mod, ®op, &rm); 2109 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); 2110 data += PrintRightXMMOperand(data); 2111 } else if (b2 == 0x6F) { 2112 data += 3; 2113 int mod, regop, rm; 2114 get_modrm(*data, &mod, ®op, &rm); 2115 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop)); 2116 data += PrintRightXMMOperand(data); 2117 } else if (b2 == 0x7F) { 2118 AppendToBuffer("movdqu "); 2119 data += 3; 2120 int mod, regop, rm; 2121 get_modrm(*data, &mod, ®op, &rm); 2122 data += PrintRightXMMOperand(data); 2123 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 2124 } else if (b2 == 0xB8) { 2125 data += 3; 2126 int mod, regop, rm; 2127 get_modrm(*data, &mod, ®op, &rm); 2128 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop)); 2129 data += PrintRightOperand(data); 2130 } else if (b2 == 0xBC) { 2131 data += 3; 2132 int mod, regop, rm; 2133 get_modrm(*data, &mod, ®op, &rm); 2134 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop)); 2135 data += PrintRightOperand(data); 2136 } else if (b2 == 0xBD) { 2137 data += 3; 2138 int mod, regop, rm; 2139 get_modrm(*data, &mod, ®op, &rm); 2140 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop)); 2141 data += PrintRightOperand(data); 2142 } else { 2143 const char* mnem = "?"; 2144 switch (b2) { 2145 case 0x2A: 2146 mnem = "cvtsi2ss"; 2147 break; 2148 case 0x2C: 2149 mnem = "cvttss2si"; 2150 break; 2151 case 0x2D: 2152 mnem = "cvtss2si"; 2153 break; 2154 case 0x51: 2155 mnem = "sqrtss"; 2156 break; 2157 case 0x58: 2158 mnem = "addss"; 2159 break; 2160 case 0x59: 2161 mnem = "mulss"; 2162 break; 2163 case 0x5C: 2164 mnem = "subss"; 2165 break; 2166 case 0x5D: 2167 mnem = "minss"; 2168 break; 2169 case 0x5E: 2170 mnem = "divss"; 2171 break; 2172 case 0x5F: 2173 mnem = "maxss"; 2174 break; 2175 } 2176 data += 3; 2177 int mod, regop, rm; 2178 get_modrm(*data, &mod, ®op, &rm); 2179 if (b2 == 0x2A) { 2180 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2181 data += PrintRightOperand(data); 2182 } else if (b2 == 0x2C || b2 == 0x2D) { 2183 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 2184 data += PrintRightXMMOperand(data); 2185 } else if (b2 == 0xC2) { 2186 // Intel manual 2A, Table 3-18. 2187 const char* const pseudo_op[] = { 2188 "cmpeqss", "cmpltss", "cmpless", "cmpunordss", 2189 "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"}; 2190 AppendToBuffer("%s %s,%s", pseudo_op[data[1]], 2191 NameOfXMMRegister(regop), NameOfXMMRegister(rm)); 2192 data += 2; 2193 } else { 2194 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 2195 data += PrintRightXMMOperand(data); 2196 } 2197 } 2198 } else if (*(data+1) == 0xA5) { 2199 data += 2; 2200 AppendToBuffer("rep_movs"); 2201 } else if (*(data+1) == 0xAB) { 2202 data += 2; 2203 AppendToBuffer("rep_stos"); 2204 } else { 2205 UnimplementedInstruction(); 2206 } 2207 break; 2208 2209 case 0xF7: 2210 data += F7Instruction(data); 2211 break; 2212 2213 default: 2214 UnimplementedInstruction(); 2215 } 2216 } 2217 2218 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { 2219 tmp_buffer_[tmp_buffer_pos_] = '\0'; 2220 } 2221 2222 int instr_len = data - instr; 2223 if (instr_len == 0) { 2224 printf("%02x", *data); 2225 } 2226 DCHECK(instr_len > 0); // Ensure progress. 2227 2228 int outp = 0; 2229 // Instruction bytes. 2230 for (byte* bp = instr; bp < data; bp++) { 2231 outp += v8::internal::SNPrintF(out_buffer + outp, 2232 "%02x", 2233 *bp); 2234 } 2235 for (int i = 6 - instr_len; i >= 0; i--) { 2236 outp += v8::internal::SNPrintF(out_buffer + outp, " "); 2237 } 2238 2239 outp += v8::internal::SNPrintF(out_buffer + outp, 2240 " %s", 2241 tmp_buffer_.start()); 2242 return instr_len; 2243 } // NOLINT (function is too long) 2244 2245 2246 //------------------------------------------------------------------------------ 2247 2248 2249 static const char* const cpu_regs[8] = { 2250 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 2251 }; 2252 2253 2254 static const char* const byte_cpu_regs[8] = { 2255 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 2256 }; 2257 2258 2259 static const char* const xmm_regs[8] = { 2260 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" 2261 }; 2262 2263 2264 const char* NameConverter::NameOfAddress(byte* addr) const { 2265 v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr)); 2266 return tmp_buffer_.start(); 2267 } 2268 2269 2270 const char* NameConverter::NameOfConstant(byte* addr) const { 2271 return NameOfAddress(addr); 2272 } 2273 2274 2275 const char* NameConverter::NameOfCPURegister(int reg) const { 2276 if (0 <= reg && reg < 8) return cpu_regs[reg]; 2277 return "noreg"; 2278 } 2279 2280 2281 const char* NameConverter::NameOfByteCPURegister(int reg) const { 2282 if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; 2283 return "noreg"; 2284 } 2285 2286 2287 const char* NameConverter::NameOfXMMRegister(int reg) const { 2288 if (0 <= reg && reg < 8) return xmm_regs[reg]; 2289 return "noxmmreg"; 2290 } 2291 2292 2293 const char* NameConverter::NameInCode(byte* addr) const { 2294 // IA32 does not embed debug strings at the moment. 2295 UNREACHABLE(); 2296 return ""; 2297 } 2298 2299 2300 //------------------------------------------------------------------------------ 2301 2302 Disassembler::Disassembler(const NameConverter& converter) 2303 : converter_(converter) {} 2304 2305 2306 Disassembler::~Disassembler() {} 2307 2308 2309 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 2310 byte* instruction) { 2311 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/); 2312 return d.InstructionDecode(buffer, instruction); 2313 } 2314 2315 2316 // The IA-32 assembler does not currently use constant pools. 2317 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } 2318 2319 2320 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { 2321 NameConverter converter; 2322 Disassembler d(converter); 2323 for (byte* pc = begin; pc < end;) { 2324 v8::internal::EmbeddedVector<char, 128> buffer; 2325 buffer[0] = '\0'; 2326 byte* prev_pc = pc; 2327 pc += d.InstructionDecode(buffer, pc); 2328 fprintf(f, "%p", static_cast<void*>(prev_pc)); 2329 fprintf(f, " "); 2330 2331 for (byte* bp = prev_pc; bp < pc; bp++) { 2332 fprintf(f, "%02x", *bp); 2333 } 2334 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { 2335 fprintf(f, " "); 2336 } 2337 fprintf(f, " %s\n", buffer.start()); 2338 } 2339 } 2340 2341 2342 } // namespace disasm 2343 2344 #endif // V8_TARGET_ARCH_IA32 2345