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 #include "src/v8.h" 10 11 #if V8_TARGET_ARCH_X87 12 13 #include "src/disasm.h" 14 15 namespace disasm { 16 17 enum OperandOrder { 18 UNSET_OP_ORDER = 0, 19 REG_OPER_OP_ORDER, 20 OPER_REG_OP_ORDER 21 }; 22 23 24 //------------------------------------------------------------------ 25 // Tables 26 //------------------------------------------------------------------ 27 struct ByteMnemonic { 28 int b; // -1 terminates, otherwise must be in range (0..255) 29 const char* mnem; 30 OperandOrder op_order_; 31 }; 32 33 34 static const ByteMnemonic two_operands_instr[] = { 35 {0x01, "add", OPER_REG_OP_ORDER}, 36 {0x03, "add", REG_OPER_OP_ORDER}, 37 {0x09, "or", OPER_REG_OP_ORDER}, 38 {0x0B, "or", REG_OPER_OP_ORDER}, 39 {0x1B, "sbb", REG_OPER_OP_ORDER}, 40 {0x21, "and", OPER_REG_OP_ORDER}, 41 {0x23, "and", REG_OPER_OP_ORDER}, 42 {0x29, "sub", OPER_REG_OP_ORDER}, 43 {0x2A, "subb", REG_OPER_OP_ORDER}, 44 {0x2B, "sub", REG_OPER_OP_ORDER}, 45 {0x31, "xor", OPER_REG_OP_ORDER}, 46 {0x33, "xor", REG_OPER_OP_ORDER}, 47 {0x38, "cmpb", OPER_REG_OP_ORDER}, 48 {0x3A, "cmpb", REG_OPER_OP_ORDER}, 49 {0x3B, "cmp", REG_OPER_OP_ORDER}, 50 {0x84, "test_b", REG_OPER_OP_ORDER}, 51 {0x85, "test", REG_OPER_OP_ORDER}, 52 {0x87, "xchg", REG_OPER_OP_ORDER}, 53 {0x8A, "mov_b", REG_OPER_OP_ORDER}, 54 {0x8B, "mov", REG_OPER_OP_ORDER}, 55 {0x8D, "lea", REG_OPER_OP_ORDER}, 56 {-1, "", UNSET_OP_ORDER} 57 }; 58 59 60 static const ByteMnemonic zero_operands_instr[] = { 61 {0xC3, "ret", UNSET_OP_ORDER}, 62 {0xC9, "leave", UNSET_OP_ORDER}, 63 {0x90, "nop", UNSET_OP_ORDER}, 64 {0xF4, "hlt", UNSET_OP_ORDER}, 65 {0xCC, "int3", UNSET_OP_ORDER}, 66 {0x60, "pushad", UNSET_OP_ORDER}, 67 {0x61, "popad", UNSET_OP_ORDER}, 68 {0x9C, "pushfd", UNSET_OP_ORDER}, 69 {0x9D, "popfd", UNSET_OP_ORDER}, 70 {0x9E, "sahf", UNSET_OP_ORDER}, 71 {0x99, "cdq", UNSET_OP_ORDER}, 72 {0x9B, "fwait", UNSET_OP_ORDER}, 73 {0xFC, "cld", UNSET_OP_ORDER}, 74 {0xAB, "stos", UNSET_OP_ORDER}, 75 {-1, "", UNSET_OP_ORDER} 76 }; 77 78 79 static const ByteMnemonic call_jump_instr[] = { 80 {0xE8, "call", UNSET_OP_ORDER}, 81 {0xE9, "jmp", UNSET_OP_ORDER}, 82 {-1, "", UNSET_OP_ORDER} 83 }; 84 85 86 static const ByteMnemonic short_immediate_instr[] = { 87 {0x05, "add", UNSET_OP_ORDER}, 88 {0x0D, "or", UNSET_OP_ORDER}, 89 {0x15, "adc", UNSET_OP_ORDER}, 90 {0x25, "and", UNSET_OP_ORDER}, 91 {0x2D, "sub", UNSET_OP_ORDER}, 92 {0x35, "xor", UNSET_OP_ORDER}, 93 {0x3D, "cmp", UNSET_OP_ORDER}, 94 {-1, "", UNSET_OP_ORDER} 95 }; 96 97 98 // Generally we don't want to generate these because they are subject to partial 99 // register stalls. They are included for completeness and because the cmp 100 // variant is used by the RecordWrite stub. Because it does not update the 101 // register it is not subject to partial register stalls. 102 static ByteMnemonic byte_immediate_instr[] = { 103 {0x0c, "or", UNSET_OP_ORDER}, 104 {0x24, "and", UNSET_OP_ORDER}, 105 {0x34, "xor", UNSET_OP_ORDER}, 106 {0x3c, "cmp", UNSET_OP_ORDER}, 107 {-1, "", UNSET_OP_ORDER} 108 }; 109 110 111 static const char* const jump_conditional_mnem[] = { 112 /*0*/ "jo", "jno", "jc", "jnc", 113 /*4*/ "jz", "jnz", "jna", "ja", 114 /*8*/ "js", "jns", "jpe", "jpo", 115 /*12*/ "jl", "jnl", "jng", "jg" 116 }; 117 118 119 static const char* const set_conditional_mnem[] = { 120 /*0*/ "seto", "setno", "setc", "setnc", 121 /*4*/ "setz", "setnz", "setna", "seta", 122 /*8*/ "sets", "setns", "setpe", "setpo", 123 /*12*/ "setl", "setnl", "setng", "setg" 124 }; 125 126 127 static const char* const conditional_move_mnem[] = { 128 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc", 129 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova", 130 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo", 131 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg" 132 }; 133 134 135 enum InstructionType { 136 NO_INSTR, 137 ZERO_OPERANDS_INSTR, 138 TWO_OPERANDS_INSTR, 139 JUMP_CONDITIONAL_SHORT_INSTR, 140 REGISTER_INSTR, 141 MOVE_REG_INSTR, 142 CALL_JUMP_INSTR, 143 SHORT_IMMEDIATE_INSTR, 144 BYTE_IMMEDIATE_INSTR 145 }; 146 147 148 struct InstructionDesc { 149 const char* mnem; 150 InstructionType type; 151 OperandOrder op_order_; 152 }; 153 154 155 class InstructionTable { 156 public: 157 InstructionTable(); 158 const InstructionDesc& Get(byte x) const { return instructions_[x]; } 159 static InstructionTable* get_instance() { 160 static InstructionTable table; 161 return &table; 162 } 163 164 private: 165 InstructionDesc instructions_[256]; 166 void Clear(); 167 void Init(); 168 void CopyTable(const ByteMnemonic bm[], InstructionType type); 169 void SetTableRange(InstructionType type, 170 byte start, 171 byte end, 172 const char* mnem); 173 void AddJumpConditionalShort(); 174 }; 175 176 177 InstructionTable::InstructionTable() { 178 Clear(); 179 Init(); 180 } 181 182 183 void InstructionTable::Clear() { 184 for (int i = 0; i < 256; i++) { 185 instructions_[i].mnem = ""; 186 instructions_[i].type = NO_INSTR; 187 instructions_[i].op_order_ = UNSET_OP_ORDER; 188 } 189 } 190 191 192 void InstructionTable::Init() { 193 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); 194 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); 195 CopyTable(call_jump_instr, CALL_JUMP_INSTR); 196 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); 197 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR); 198 AddJumpConditionalShort(); 199 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc"); 200 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec"); 201 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push"); 202 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop"); 203 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. 204 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); 205 } 206 207 208 void InstructionTable::CopyTable(const ByteMnemonic bm[], 209 InstructionType type) { 210 for (int i = 0; bm[i].b >= 0; i++) { 211 InstructionDesc* id = &instructions_[bm[i].b]; 212 id->mnem = bm[i].mnem; 213 id->op_order_ = bm[i].op_order_; 214 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 215 id->type = type; 216 } 217 } 218 219 220 void InstructionTable::SetTableRange(InstructionType type, 221 byte start, 222 byte end, 223 const char* mnem) { 224 for (byte b = start; b <= end; b++) { 225 InstructionDesc* id = &instructions_[b]; 226 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 227 id->mnem = mnem; 228 id->type = type; 229 } 230 } 231 232 233 void InstructionTable::AddJumpConditionalShort() { 234 for (byte b = 0x70; b <= 0x7F; b++) { 235 InstructionDesc* id = &instructions_[b]; 236 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered. 237 id->mnem = jump_conditional_mnem[b & 0x0F]; 238 id->type = JUMP_CONDITIONAL_SHORT_INSTR; 239 } 240 } 241 242 243 // The X87 disassembler implementation. 244 class DisassemblerX87 { 245 public: 246 DisassemblerX87(const NameConverter& converter, 247 bool abort_on_unimplemented = true) 248 : converter_(converter), 249 instruction_table_(InstructionTable::get_instance()), 250 tmp_buffer_pos_(0), 251 abort_on_unimplemented_(abort_on_unimplemented) { 252 tmp_buffer_[0] = '\0'; 253 } 254 255 virtual ~DisassemblerX87() {} 256 257 // Writes one disassembled instruction into 'buffer' (0-terminated). 258 // Returns the length of the disassembled machine instruction in bytes. 259 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); 260 261 private: 262 const NameConverter& converter_; 263 InstructionTable* instruction_table_; 264 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; 265 unsigned int tmp_buffer_pos_; 266 bool abort_on_unimplemented_; 267 268 enum { 269 eax = 0, 270 ecx = 1, 271 edx = 2, 272 ebx = 3, 273 esp = 4, 274 ebp = 5, 275 esi = 6, 276 edi = 7 277 }; 278 279 280 enum ShiftOpcodeExtension { 281 kROL = 0, 282 kROR = 1, 283 kRCL = 2, 284 kRCR = 3, 285 kSHL = 4, 286 KSHR = 5, 287 kSAR = 7 288 }; 289 290 291 const char* NameOfCPURegister(int reg) const { 292 return converter_.NameOfCPURegister(reg); 293 } 294 295 296 const char* NameOfByteCPURegister(int reg) const { 297 return converter_.NameOfByteCPURegister(reg); 298 } 299 300 301 const char* NameOfXMMRegister(int reg) const { 302 return converter_.NameOfXMMRegister(reg); 303 } 304 305 306 const char* NameOfAddress(byte* addr) const { 307 return converter_.NameOfAddress(addr); 308 } 309 310 311 // Disassembler helper functions. 312 static void get_modrm(byte data, int* mod, int* regop, int* rm) { 313 *mod = (data >> 6) & 3; 314 *regop = (data & 0x38) >> 3; 315 *rm = data & 7; 316 } 317 318 319 static void get_sib(byte data, int* scale, int* index, int* base) { 320 *scale = (data >> 6) & 3; 321 *index = (data >> 3) & 7; 322 *base = data & 7; 323 } 324 325 typedef const char* (DisassemblerX87::*RegisterNameMapping)(int reg) const; 326 327 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); 328 int PrintRightOperand(byte* modrmp); 329 int PrintRightByteOperand(byte* modrmp); 330 int PrintRightXMMOperand(byte* modrmp); 331 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); 332 int PrintImmediateOp(byte* data); 333 int F7Instruction(byte* data); 334 int D1D3C1Instruction(byte* data); 335 int JumpShort(byte* data); 336 int JumpConditional(byte* data, const char* comment); 337 int JumpConditionalShort(byte* data, const char* comment); 338 int SetCC(byte* data); 339 int CMov(byte* data); 340 int FPUInstruction(byte* data); 341 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start); 342 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte); 343 void AppendToBuffer(const char* format, ...); 344 345 346 void UnimplementedInstruction() { 347 if (abort_on_unimplemented_) { 348 UNIMPLEMENTED(); 349 } else { 350 AppendToBuffer("'Unimplemented Instruction'"); 351 } 352 } 353 }; 354 355 356 void DisassemblerX87::AppendToBuffer(const char* format, ...) { 357 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; 358 va_list args; 359 va_start(args, format); 360 int result = v8::internal::VSNPrintF(buf, format, args); 361 va_end(args); 362 tmp_buffer_pos_ += result; 363 } 364 365 int DisassemblerX87::PrintRightOperandHelper( 366 byte* modrmp, 367 RegisterNameMapping direct_register_name) { 368 int mod, regop, rm; 369 get_modrm(*modrmp, &mod, ®op, &rm); 370 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : 371 &DisassemblerX87::NameOfCPURegister; 372 switch (mod) { 373 case 0: 374 if (rm == ebp) { 375 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); 376 AppendToBuffer("[0x%x]", disp); 377 return 5; 378 } else if (rm == esp) { 379 byte sib = *(modrmp + 1); 380 int scale, index, base; 381 get_sib(sib, &scale, &index, &base); 382 if (index == esp && base == esp && scale == 0 /*times_1*/) { 383 AppendToBuffer("[%s]", (this->*register_name)(rm)); 384 return 2; 385 } else if (base == ebp) { 386 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); 387 AppendToBuffer("[%s*%d%s0x%x]", 388 (this->*register_name)(index), 389 1 << scale, 390 disp < 0 ? "-" : "+", 391 disp < 0 ? -disp : disp); 392 return 6; 393 } else if (index != esp && base != ebp) { 394 // [base+index*scale] 395 AppendToBuffer("[%s+%s*%d]", 396 (this->*register_name)(base), 397 (this->*register_name)(index), 398 1 << scale); 399 return 2; 400 } else { 401 UnimplementedInstruction(); 402 return 1; 403 } 404 } else { 405 AppendToBuffer("[%s]", (this->*register_name)(rm)); 406 return 1; 407 } 408 break; 409 case 1: // fall through 410 case 2: 411 if (rm == esp) { 412 byte sib = *(modrmp + 1); 413 int scale, index, base; 414 get_sib(sib, &scale, &index, &base); 415 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) 416 : *reinterpret_cast<int8_t*>(modrmp + 2); 417 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { 418 AppendToBuffer("[%s%s0x%x]", 419 (this->*register_name)(rm), 420 disp < 0 ? "-" : "+", 421 disp < 0 ? -disp : disp); 422 } else { 423 AppendToBuffer("[%s+%s*%d%s0x%x]", 424 (this->*register_name)(base), 425 (this->*register_name)(index), 426 1 << scale, 427 disp < 0 ? "-" : "+", 428 disp < 0 ? -disp : disp); 429 } 430 return mod == 2 ? 6 : 3; 431 } else { 432 // No sib. 433 int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) 434 : *reinterpret_cast<int8_t*>(modrmp + 1); 435 AppendToBuffer("[%s%s0x%x]", 436 (this->*register_name)(rm), 437 disp < 0 ? "-" : "+", 438 disp < 0 ? -disp : disp); 439 return mod == 2 ? 5 : 2; 440 } 441 break; 442 case 3: 443 AppendToBuffer("%s", (this->*register_name)(rm)); 444 return 1; 445 default: 446 UnimplementedInstruction(); 447 return 1; 448 } 449 UNREACHABLE(); 450 } 451 452 453 int DisassemblerX87::PrintRightOperand(byte* modrmp) { 454 return PrintRightOperandHelper(modrmp, &DisassemblerX87::NameOfCPURegister); 455 } 456 457 458 int DisassemblerX87::PrintRightByteOperand(byte* modrmp) { 459 return PrintRightOperandHelper(modrmp, 460 &DisassemblerX87::NameOfByteCPURegister); 461 } 462 463 464 int DisassemblerX87::PrintRightXMMOperand(byte* modrmp) { 465 return PrintRightOperandHelper(modrmp, 466 &DisassemblerX87::NameOfXMMRegister); 467 } 468 469 470 // Returns number of bytes used including the current *data. 471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. 472 int DisassemblerX87::PrintOperands(const char* mnem, 473 OperandOrder op_order, 474 byte* data) { 475 byte modrm = *data; 476 int mod, regop, rm; 477 get_modrm(modrm, &mod, ®op, &rm); 478 int advance = 0; 479 switch (op_order) { 480 case REG_OPER_OP_ORDER: { 481 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 482 advance = PrintRightOperand(data); 483 break; 484 } 485 case OPER_REG_OP_ORDER: { 486 AppendToBuffer("%s ", mnem); 487 advance = PrintRightOperand(data); 488 AppendToBuffer(",%s", NameOfCPURegister(regop)); 489 break; 490 } 491 default: 492 UNREACHABLE(); 493 break; 494 } 495 return advance; 496 } 497 498 499 // Returns number of bytes used by machine instruction, including *data byte. 500 // Writes immediate instructions to 'tmp_buffer_'. 501 int DisassemblerX87::PrintImmediateOp(byte* data) { 502 bool sign_extension_bit = (*data & 0x02) != 0; 503 byte modrm = *(data+1); 504 int mod, regop, rm; 505 get_modrm(modrm, &mod, ®op, &rm); 506 const char* mnem = "Imm???"; 507 switch (regop) { 508 case 0: mnem = "add"; break; 509 case 1: mnem = "or"; break; 510 case 2: mnem = "adc"; break; 511 case 4: mnem = "and"; break; 512 case 5: mnem = "sub"; break; 513 case 6: mnem = "xor"; break; 514 case 7: mnem = "cmp"; break; 515 default: UnimplementedInstruction(); 516 } 517 AppendToBuffer("%s ", mnem); 518 int count = PrintRightOperand(data+1); 519 if (sign_extension_bit) { 520 AppendToBuffer(",0x%x", *(data + 1 + count)); 521 return 1 + count + 1 /*int8*/; 522 } else { 523 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); 524 return 1 + count + 4 /*int32_t*/; 525 } 526 } 527 528 529 // Returns number of bytes used, including *data. 530 int DisassemblerX87::F7Instruction(byte* data) { 531 DCHECK_EQ(0xF7, *data); 532 byte modrm = *++data; 533 int mod, regop, rm; 534 get_modrm(modrm, &mod, ®op, &rm); 535 const char* mnem = NULL; 536 switch (regop) { 537 case 0: 538 mnem = "test"; 539 break; 540 case 2: 541 mnem = "not"; 542 break; 543 case 3: 544 mnem = "neg"; 545 break; 546 case 4: 547 mnem = "mul"; 548 break; 549 case 5: 550 mnem = "imul"; 551 break; 552 case 6: 553 mnem = "div"; 554 break; 555 case 7: 556 mnem = "idiv"; 557 break; 558 default: 559 UnimplementedInstruction(); 560 } 561 AppendToBuffer("%s ", mnem); 562 int count = PrintRightOperand(data); 563 if (regop == 0) { 564 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count)); 565 count += 4; 566 } 567 return 1 + count; 568 } 569 570 571 int DisassemblerX87::D1D3C1Instruction(byte* data) { 572 byte op = *data; 573 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1); 574 byte modrm = *++data; 575 int mod, regop, rm; 576 get_modrm(modrm, &mod, ®op, &rm); 577 int imm8 = -1; 578 const char* mnem = NULL; 579 switch (regop) { 580 case kROL: 581 mnem = "rol"; 582 break; 583 case kROR: 584 mnem = "ror"; 585 break; 586 case kRCL: 587 mnem = "rcl"; 588 break; 589 case kRCR: 590 mnem = "rcr"; 591 break; 592 case kSHL: 593 mnem = "shl"; 594 break; 595 case KSHR: 596 mnem = "shr"; 597 break; 598 case kSAR: 599 mnem = "sar"; 600 break; 601 default: 602 UnimplementedInstruction(); 603 } 604 AppendToBuffer("%s ", mnem); 605 int count = PrintRightOperand(data); 606 if (op == 0xD1) { 607 imm8 = 1; 608 } else if (op == 0xC1) { 609 imm8 = *(data + 1); 610 count++; 611 } else if (op == 0xD3) { 612 // Shift/rotate by cl. 613 } 614 if (imm8 >= 0) { 615 AppendToBuffer(",%d", imm8); 616 } else { 617 AppendToBuffer(",cl"); 618 } 619 return 1 + count; 620 } 621 622 623 // Returns number of bytes used, including *data. 624 int DisassemblerX87::JumpShort(byte* data) { 625 DCHECK_EQ(0xEB, *data); 626 byte b = *(data+1); 627 byte* dest = data + static_cast<int8_t>(b) + 2; 628 AppendToBuffer("jmp %s", NameOfAddress(dest)); 629 return 2; 630 } 631 632 633 // Returns number of bytes used, including *data. 634 int DisassemblerX87::JumpConditional(byte* data, const char* comment) { 635 DCHECK_EQ(0x0F, *data); 636 byte cond = *(data+1) & 0x0F; 637 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; 638 const char* mnem = jump_conditional_mnem[cond]; 639 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 640 if (comment != NULL) { 641 AppendToBuffer(", %s", comment); 642 } 643 return 6; // includes 0x0F 644 } 645 646 647 // Returns number of bytes used, including *data. 648 int DisassemblerX87::JumpConditionalShort(byte* data, const char* comment) { 649 byte cond = *data & 0x0F; 650 byte b = *(data+1); 651 byte* dest = data + static_cast<int8_t>(b) + 2; 652 const char* mnem = jump_conditional_mnem[cond]; 653 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); 654 if (comment != NULL) { 655 AppendToBuffer(", %s", comment); 656 } 657 return 2; 658 } 659 660 661 // Returns number of bytes used, including *data. 662 int DisassemblerX87::SetCC(byte* data) { 663 DCHECK_EQ(0x0F, *data); 664 byte cond = *(data+1) & 0x0F; 665 const char* mnem = set_conditional_mnem[cond]; 666 AppendToBuffer("%s ", mnem); 667 PrintRightByteOperand(data+2); 668 return 3; // Includes 0x0F. 669 } 670 671 672 // Returns number of bytes used, including *data. 673 int DisassemblerX87::CMov(byte* data) { 674 DCHECK_EQ(0x0F, *data); 675 byte cond = *(data + 1) & 0x0F; 676 const char* mnem = conditional_move_mnem[cond]; 677 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); 678 return 2 + op_size; // includes 0x0F 679 } 680 681 682 // Returns number of bytes used, including *data. 683 int DisassemblerX87::FPUInstruction(byte* data) { 684 byte escape_opcode = *data; 685 DCHECK_EQ(0xD8, escape_opcode & 0xF8); 686 byte modrm_byte = *(data+1); 687 688 if (modrm_byte >= 0xC0) { 689 return RegisterFPUInstruction(escape_opcode, modrm_byte); 690 } else { 691 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); 692 } 693 } 694 695 int DisassemblerX87::MemoryFPUInstruction(int escape_opcode, 696 int modrm_byte, 697 byte* modrm_start) { 698 const char* mnem = "?"; 699 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. 700 switch (escape_opcode) { 701 case 0xD9: switch (regop) { 702 case 0: mnem = "fld_s"; break; 703 case 2: mnem = "fst_s"; break; 704 case 3: mnem = "fstp_s"; break; 705 case 5: 706 mnem = "fldcw"; 707 break; 708 case 7: 709 mnem = "fnstcw"; 710 break; 711 default: UnimplementedInstruction(); 712 } 713 break; 714 715 case 0xDB: switch (regop) { 716 case 0: mnem = "fild_s"; break; 717 case 1: mnem = "fisttp_s"; break; 718 case 2: mnem = "fist_s"; break; 719 case 3: mnem = "fistp_s"; break; 720 default: UnimplementedInstruction(); 721 } 722 break; 723 724 case 0xDC: 725 switch (regop) { 726 case 0: 727 mnem = "fadd_d"; 728 break; 729 default: 730 UnimplementedInstruction(); 731 } 732 break; 733 734 case 0xDD: switch (regop) { 735 case 0: mnem = "fld_d"; break; 736 case 1: mnem = "fisttp_d"; break; 737 case 2: mnem = "fst_d"; break; 738 case 3: mnem = "fstp_d"; break; 739 case 4: 740 mnem = "frstor"; 741 break; 742 case 6: 743 mnem = "fnsave"; 744 break; 745 default: UnimplementedInstruction(); 746 } 747 break; 748 749 case 0xDF: switch (regop) { 750 case 5: mnem = "fild_d"; break; 751 case 7: mnem = "fistp_d"; break; 752 default: UnimplementedInstruction(); 753 } 754 break; 755 756 default: UnimplementedInstruction(); 757 } 758 AppendToBuffer("%s ", mnem); 759 int count = PrintRightOperand(modrm_start); 760 return count + 1; 761 } 762 763 int DisassemblerX87::RegisterFPUInstruction(int escape_opcode, 764 byte modrm_byte) { 765 bool has_register = false; // Is the FPU register encoded in modrm_byte? 766 const char* mnem = "?"; 767 768 switch (escape_opcode) { 769 case 0xD8: 770 has_register = true; 771 switch (modrm_byte & 0xF8) { 772 case 0xC0: mnem = "fadd_i"; break; 773 case 0xE0: mnem = "fsub_i"; break; 774 case 0xC8: mnem = "fmul_i"; break; 775 case 0xF0: mnem = "fdiv_i"; break; 776 default: UnimplementedInstruction(); 777 } 778 break; 779 780 case 0xD9: 781 switch (modrm_byte & 0xF8) { 782 case 0xC0: 783 mnem = "fld"; 784 has_register = true; 785 break; 786 case 0xC8: 787 mnem = "fxch"; 788 has_register = true; 789 break; 790 default: 791 switch (modrm_byte) { 792 case 0xE0: mnem = "fchs"; break; 793 case 0xE1: mnem = "fabs"; break; 794 case 0xE4: mnem = "ftst"; break; 795 case 0xE8: mnem = "fld1"; break; 796 case 0xEB: mnem = "fldpi"; break; 797 case 0xED: mnem = "fldln2"; break; 798 case 0xEE: mnem = "fldz"; break; 799 case 0xF0: mnem = "f2xm1"; break; 800 case 0xF1: mnem = "fyl2x"; break; 801 case 0xF4: mnem = "fxtract"; break; 802 case 0xF5: mnem = "fprem1"; break; 803 case 0xF7: mnem = "fincstp"; break; 804 case 0xF8: mnem = "fprem"; break; 805 case 0xFC: mnem = "frndint"; break; 806 case 0xFD: mnem = "fscale"; break; 807 case 0xFE: mnem = "fsin"; break; 808 case 0xFF: mnem = "fcos"; break; 809 default: UnimplementedInstruction(); 810 } 811 } 812 break; 813 814 case 0xDA: 815 if (modrm_byte == 0xE9) { 816 mnem = "fucompp"; 817 } else { 818 UnimplementedInstruction(); 819 } 820 break; 821 822 case 0xDB: 823 if ((modrm_byte & 0xF8) == 0xE8) { 824 mnem = "fucomi"; 825 has_register = true; 826 } else if (modrm_byte == 0xE2) { 827 mnem = "fclex"; 828 } else if (modrm_byte == 0xE3) { 829 mnem = "fninit"; 830 } else { 831 UnimplementedInstruction(); 832 } 833 break; 834 835 case 0xDC: 836 has_register = true; 837 switch (modrm_byte & 0xF8) { 838 case 0xC0: mnem = "fadd"; break; 839 case 0xE8: mnem = "fsub"; break; 840 case 0xC8: mnem = "fmul"; break; 841 case 0xF8: mnem = "fdiv"; break; 842 default: UnimplementedInstruction(); 843 } 844 break; 845 846 case 0xDD: 847 has_register = true; 848 switch (modrm_byte & 0xF8) { 849 case 0xC0: mnem = "ffree"; break; 850 case 0xD0: mnem = "fst"; break; 851 case 0xD8: mnem = "fstp"; break; 852 default: UnimplementedInstruction(); 853 } 854 break; 855 856 case 0xDE: 857 if (modrm_byte == 0xD9) { 858 mnem = "fcompp"; 859 } else { 860 has_register = true; 861 switch (modrm_byte & 0xF8) { 862 case 0xC0: mnem = "faddp"; break; 863 case 0xE8: mnem = "fsubp"; break; 864 case 0xC8: mnem = "fmulp"; break; 865 case 0xF8: mnem = "fdivp"; break; 866 default: UnimplementedInstruction(); 867 } 868 } 869 break; 870 871 case 0xDF: 872 if (modrm_byte == 0xE0) { 873 mnem = "fnstsw_ax"; 874 } else if ((modrm_byte & 0xF8) == 0xE8) { 875 mnem = "fucomip"; 876 has_register = true; 877 } 878 break; 879 880 default: UnimplementedInstruction(); 881 } 882 883 if (has_register) { 884 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); 885 } else { 886 AppendToBuffer("%s", mnem); 887 } 888 return 2; 889 } 890 891 892 // Mnemonics for instructions 0xF0 byte. 893 // Returns NULL if the instruction is not handled here. 894 static const char* F0Mnem(byte f0byte) { 895 switch (f0byte) { 896 case 0x18: return "prefetch"; 897 case 0xA2: return "cpuid"; 898 case 0xBE: return "movsx_b"; 899 case 0xBF: return "movsx_w"; 900 case 0xB6: return "movzx_b"; 901 case 0xB7: return "movzx_w"; 902 case 0xAF: return "imul"; 903 case 0xA5: return "shld"; 904 case 0xAD: return "shrd"; 905 case 0xAC: return "shrd"; // 3-operand version. 906 case 0xAB: return "bts"; 907 case 0xBD: return "bsr"; 908 default: return NULL; 909 } 910 } 911 912 913 // Disassembled instruction '*instr' and writes it into 'out_buffer'. 914 int DisassemblerX87::InstructionDecode(v8::internal::Vector<char> out_buffer, 915 byte* instr) { 916 tmp_buffer_pos_ = 0; // starting to write as position 0 917 byte* data = instr; 918 // Check for hints. 919 const char* branch_hint = NULL; 920 // We use these two prefixes only with branch prediction 921 if (*data == 0x3E /*ds*/) { 922 branch_hint = "predicted taken"; 923 data++; 924 } else if (*data == 0x2E /*cs*/) { 925 branch_hint = "predicted not taken"; 926 data++; 927 } 928 bool processed = true; // Will be set to false if the current instruction 929 // is not in 'instructions' table. 930 const InstructionDesc& idesc = instruction_table_->Get(*data); 931 switch (idesc.type) { 932 case ZERO_OPERANDS_INSTR: 933 AppendToBuffer(idesc.mnem); 934 data++; 935 break; 936 937 case TWO_OPERANDS_INSTR: 938 data++; 939 data += PrintOperands(idesc.mnem, idesc.op_order_, data); 940 break; 941 942 case JUMP_CONDITIONAL_SHORT_INSTR: 943 data += JumpConditionalShort(data, branch_hint); 944 break; 945 946 case REGISTER_INSTR: 947 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); 948 data++; 949 break; 950 951 case MOVE_REG_INSTR: { 952 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); 953 AppendToBuffer("mov %s,%s", 954 NameOfCPURegister(*data & 0x07), 955 NameOfAddress(addr)); 956 data += 5; 957 break; 958 } 959 960 case CALL_JUMP_INSTR: { 961 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5; 962 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); 963 data += 5; 964 break; 965 } 966 967 case SHORT_IMMEDIATE_INSTR: { 968 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); 969 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); 970 data += 5; 971 break; 972 } 973 974 case BYTE_IMMEDIATE_INSTR: { 975 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); 976 data += 2; 977 break; 978 } 979 980 case NO_INSTR: 981 processed = false; 982 break; 983 984 default: 985 UNIMPLEMENTED(); // This type is not implemented. 986 } 987 //---------------------------- 988 if (!processed) { 989 switch (*data) { 990 case 0xC2: 991 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); 992 data += 3; 993 break; 994 995 case 0x6B: { 996 data++; 997 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 998 AppendToBuffer(",%d", *data); 999 data++; 1000 } break; 1001 1002 case 0x69: { 1003 data++; 1004 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 1005 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data)); 1006 data += 4; 1007 } 1008 break; 1009 1010 case 0xF6: 1011 { data++; 1012 int mod, regop, rm; 1013 get_modrm(*data, &mod, ®op, &rm); 1014 if (regop == eax) { 1015 AppendToBuffer("test_b "); 1016 data += PrintRightByteOperand(data); 1017 int32_t imm = *data; 1018 AppendToBuffer(",0x%x", imm); 1019 data++; 1020 } else { 1021 UnimplementedInstruction(); 1022 } 1023 } 1024 break; 1025 1026 case 0x81: // fall through 1027 case 0x83: // 0x81 with sign extension bit set 1028 data += PrintImmediateOp(data); 1029 break; 1030 1031 case 0x0F: 1032 { byte f0byte = data[1]; 1033 const char* f0mnem = F0Mnem(f0byte); 1034 if (f0byte == 0x18) { 1035 data += 2; 1036 int mod, regop, rm; 1037 get_modrm(*data, &mod, ®op, &rm); 1038 const char* suffix[] = {"nta", "1", "2", "3"}; 1039 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]); 1040 data += PrintRightOperand(data); 1041 } else if (f0byte == 0x1F && data[2] == 0) { 1042 AppendToBuffer("nop"); // 3 byte nop. 1043 data += 3; 1044 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) { 1045 AppendToBuffer("nop"); // 4 byte nop. 1046 data += 4; 1047 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 && 1048 data[4] == 0) { 1049 AppendToBuffer("nop"); // 5 byte nop. 1050 data += 5; 1051 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 && 1052 data[4] == 0 && data[5] == 0 && data[6] == 0) { 1053 AppendToBuffer("nop"); // 7 byte nop. 1054 data += 7; 1055 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 && 1056 data[4] == 0 && data[5] == 0 && data[6] == 0 && 1057 data[7] == 0) { 1058 AppendToBuffer("nop"); // 8 byte nop. 1059 data += 8; 1060 } else if (f0byte == 0xA2 || f0byte == 0x31) { 1061 AppendToBuffer("%s", f0mnem); 1062 data += 2; 1063 } else if (f0byte == 0x28) { 1064 data += 2; 1065 int mod, regop, rm; 1066 get_modrm(*data, &mod, ®op, &rm); 1067 AppendToBuffer("movaps %s,%s", 1068 NameOfXMMRegister(regop), 1069 NameOfXMMRegister(rm)); 1070 data++; 1071 } else if (f0byte >= 0x53 && f0byte <= 0x5F) { 1072 const char* const pseudo_op[] = { 1073 "rcpps", 1074 "andps", 1075 "andnps", 1076 "orps", 1077 "xorps", 1078 "addps", 1079 "mulps", 1080 "cvtps2pd", 1081 "cvtdq2ps", 1082 "subps", 1083 "minps", 1084 "divps", 1085 "maxps", 1086 }; 1087 1088 data += 2; 1089 int mod, regop, rm; 1090 get_modrm(*data, &mod, ®op, &rm); 1091 AppendToBuffer("%s %s,", 1092 pseudo_op[f0byte - 0x53], 1093 NameOfXMMRegister(regop)); 1094 data += PrintRightXMMOperand(data); 1095 } else if (f0byte == 0x50) { 1096 data += 2; 1097 int mod, regop, rm; 1098 get_modrm(*data, &mod, ®op, &rm); 1099 AppendToBuffer("movmskps %s,%s", 1100 NameOfCPURegister(regop), 1101 NameOfXMMRegister(rm)); 1102 data++; 1103 } else if (f0byte== 0xC6) { 1104 // shufps xmm, xmm/m128, imm8 1105 data += 2; 1106 int mod, regop, rm; 1107 get_modrm(*data, &mod, ®op, &rm); 1108 int8_t imm8 = static_cast<int8_t>(data[1]); 1109 AppendToBuffer("shufps %s,%s,%d", 1110 NameOfXMMRegister(rm), 1111 NameOfXMMRegister(regop), 1112 static_cast<int>(imm8)); 1113 data += 2; 1114 } else if ((f0byte & 0xF0) == 0x80) { 1115 data += JumpConditional(data, branch_hint); 1116 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || 1117 f0byte == 0xB7 || f0byte == 0xAF) { 1118 data += 2; 1119 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); 1120 } else if ((f0byte & 0xF0) == 0x90) { 1121 data += SetCC(data); 1122 } else if ((f0byte & 0xF0) == 0x40) { 1123 data += CMov(data); 1124 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { 1125 // shrd, shld, bts 1126 data += 2; 1127 AppendToBuffer("%s ", f0mnem); 1128 int mod, regop, rm; 1129 get_modrm(*data, &mod, ®op, &rm); 1130 data += PrintRightOperand(data); 1131 if (f0byte == 0xAB) { 1132 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1133 } else { 1134 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); 1135 } 1136 } else if (f0byte == 0xBD) { 1137 data += 2; 1138 int mod, regop, rm; 1139 get_modrm(*data, &mod, ®op, &rm); 1140 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); 1141 data += PrintRightOperand(data); 1142 } else { 1143 UnimplementedInstruction(); 1144 } 1145 } 1146 break; 1147 1148 case 0x8F: 1149 { data++; 1150 int mod, regop, rm; 1151 get_modrm(*data, &mod, ®op, &rm); 1152 if (regop == eax) { 1153 AppendToBuffer("pop "); 1154 data += PrintRightOperand(data); 1155 } 1156 } 1157 break; 1158 1159 case 0xFF: 1160 { data++; 1161 int mod, regop, rm; 1162 get_modrm(*data, &mod, ®op, &rm); 1163 const char* mnem = NULL; 1164 switch (regop) { 1165 case esi: mnem = "push"; break; 1166 case eax: mnem = "inc"; break; 1167 case ecx: mnem = "dec"; break; 1168 case edx: mnem = "call"; break; 1169 case esp: mnem = "jmp"; break; 1170 default: mnem = "???"; 1171 } 1172 AppendToBuffer("%s ", mnem); 1173 data += PrintRightOperand(data); 1174 } 1175 break; 1176 1177 case 0xC7: // imm32, fall through 1178 case 0xC6: // imm8 1179 { bool is_byte = *data == 0xC6; 1180 data++; 1181 if (is_byte) { 1182 AppendToBuffer("%s ", "mov_b"); 1183 data += PrintRightByteOperand(data); 1184 int32_t imm = *data; 1185 AppendToBuffer(",0x%x", imm); 1186 data++; 1187 } else { 1188 AppendToBuffer("%s ", "mov"); 1189 data += PrintRightOperand(data); 1190 int32_t imm = *reinterpret_cast<int32_t*>(data); 1191 AppendToBuffer(",0x%x", imm); 1192 data += 4; 1193 } 1194 } 1195 break; 1196 1197 case 0x80: 1198 { data++; 1199 int mod, regop, rm; 1200 get_modrm(*data, &mod, ®op, &rm); 1201 const char* mnem = NULL; 1202 switch (regop) { 1203 case 5: mnem = "subb"; break; 1204 case 7: mnem = "cmpb"; break; 1205 default: UnimplementedInstruction(); 1206 } 1207 AppendToBuffer("%s ", mnem); 1208 data += PrintRightByteOperand(data); 1209 int32_t imm = *data; 1210 AppendToBuffer(",0x%x", imm); 1211 data++; 1212 } 1213 break; 1214 1215 case 0x88: // 8bit, fall through 1216 case 0x89: // 32bit 1217 { bool is_byte = *data == 0x88; 1218 int mod, regop, rm; 1219 data++; 1220 get_modrm(*data, &mod, ®op, &rm); 1221 if (is_byte) { 1222 AppendToBuffer("%s ", "mov_b"); 1223 data += PrintRightByteOperand(data); 1224 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1225 } else { 1226 AppendToBuffer("%s ", "mov"); 1227 data += PrintRightOperand(data); 1228 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1229 } 1230 } 1231 break; 1232 1233 case 0x66: // prefix 1234 while (*data == 0x66) data++; 1235 if (*data == 0xf && data[1] == 0x1f) { 1236 AppendToBuffer("nop"); // 0x66 prefix 1237 } else if (*data == 0x90) { 1238 AppendToBuffer("nop"); // 0x66 prefix 1239 } else if (*data == 0x8B) { 1240 data++; 1241 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); 1242 } else if (*data == 0x89) { 1243 data++; 1244 int mod, regop, rm; 1245 get_modrm(*data, &mod, ®op, &rm); 1246 AppendToBuffer("mov_w "); 1247 data += PrintRightOperand(data); 1248 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1249 } else if (*data == 0xC7) { 1250 data++; 1251 AppendToBuffer("%s ", "mov_w"); 1252 data += PrintRightOperand(data); 1253 int imm = *reinterpret_cast<int16_t*>(data); 1254 AppendToBuffer(",0x%x", imm); 1255 data += 2; 1256 } else if (*data == 0x0F) { 1257 data++; 1258 if (*data == 0x38) { 1259 data++; 1260 if (*data == 0x17) { 1261 data++; 1262 int mod, regop, rm; 1263 get_modrm(*data, &mod, ®op, &rm); 1264 AppendToBuffer("ptest %s,%s", 1265 NameOfXMMRegister(regop), 1266 NameOfXMMRegister(rm)); 1267 data++; 1268 } else if (*data == 0x2A) { 1269 // movntdqa 1270 data++; 1271 int mod, regop, rm; 1272 get_modrm(*data, &mod, ®op, &rm); 1273 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop)); 1274 data += PrintRightOperand(data); 1275 } else { 1276 UnimplementedInstruction(); 1277 } 1278 } else if (*data == 0x3A) { 1279 data++; 1280 if (*data == 0x0B) { 1281 data++; 1282 int mod, regop, rm; 1283 get_modrm(*data, &mod, ®op, &rm); 1284 int8_t imm8 = static_cast<int8_t>(data[1]); 1285 AppendToBuffer("roundsd %s,%s,%d", 1286 NameOfXMMRegister(regop), 1287 NameOfXMMRegister(rm), 1288 static_cast<int>(imm8)); 1289 data += 2; 1290 } else if (*data == 0x16) { 1291 data++; 1292 int mod, regop, rm; 1293 get_modrm(*data, &mod, ®op, &rm); 1294 int8_t imm8 = static_cast<int8_t>(data[1]); 1295 AppendToBuffer("pextrd %s,%s,%d", 1296 NameOfCPURegister(regop), 1297 NameOfXMMRegister(rm), 1298 static_cast<int>(imm8)); 1299 data += 2; 1300 } else if (*data == 0x17) { 1301 data++; 1302 int mod, regop, rm; 1303 get_modrm(*data, &mod, ®op, &rm); 1304 int8_t imm8 = static_cast<int8_t>(data[1]); 1305 AppendToBuffer("extractps %s,%s,%d", 1306 NameOfCPURegister(rm), 1307 NameOfXMMRegister(regop), 1308 static_cast<int>(imm8)); 1309 data += 2; 1310 } else if (*data == 0x22) { 1311 data++; 1312 int mod, regop, rm; 1313 get_modrm(*data, &mod, ®op, &rm); 1314 int8_t imm8 = static_cast<int8_t>(data[1]); 1315 AppendToBuffer("pinsrd %s,%s,%d", 1316 NameOfXMMRegister(regop), 1317 NameOfCPURegister(rm), 1318 static_cast<int>(imm8)); 1319 data += 2; 1320 } else { 1321 UnimplementedInstruction(); 1322 } 1323 } else if (*data == 0x2E || *data == 0x2F) { 1324 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd"; 1325 data++; 1326 int mod, regop, rm; 1327 get_modrm(*data, &mod, ®op, &rm); 1328 if (mod == 0x3) { 1329 AppendToBuffer("%s %s,%s", mnem, 1330 NameOfXMMRegister(regop), 1331 NameOfXMMRegister(rm)); 1332 data++; 1333 } else { 1334 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1335 data += PrintRightOperand(data); 1336 } 1337 } else if (*data == 0x50) { 1338 data++; 1339 int mod, regop, rm; 1340 get_modrm(*data, &mod, ®op, &rm); 1341 AppendToBuffer("movmskpd %s,%s", 1342 NameOfCPURegister(regop), 1343 NameOfXMMRegister(rm)); 1344 data++; 1345 } else if (*data == 0x54) { 1346 data++; 1347 int mod, regop, rm; 1348 get_modrm(*data, &mod, ®op, &rm); 1349 AppendToBuffer("andpd %s,%s", 1350 NameOfXMMRegister(regop), 1351 NameOfXMMRegister(rm)); 1352 data++; 1353 } else if (*data == 0x56) { 1354 data++; 1355 int mod, regop, rm; 1356 get_modrm(*data, &mod, ®op, &rm); 1357 AppendToBuffer("orpd %s,%s", 1358 NameOfXMMRegister(regop), 1359 NameOfXMMRegister(rm)); 1360 data++; 1361 } else if (*data == 0x57) { 1362 data++; 1363 int mod, regop, rm; 1364 get_modrm(*data, &mod, ®op, &rm); 1365 AppendToBuffer("xorpd %s,%s", 1366 NameOfXMMRegister(regop), 1367 NameOfXMMRegister(rm)); 1368 data++; 1369 } else if (*data == 0x6E) { 1370 data++; 1371 int mod, regop, rm; 1372 get_modrm(*data, &mod, ®op, &rm); 1373 AppendToBuffer("movd %s,", NameOfXMMRegister(regop)); 1374 data += PrintRightOperand(data); 1375 } else if (*data == 0x6F) { 1376 data++; 1377 int mod, regop, rm; 1378 get_modrm(*data, &mod, ®op, &rm); 1379 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop)); 1380 data += PrintRightXMMOperand(data); 1381 } else if (*data == 0x70) { 1382 data++; 1383 int mod, regop, rm; 1384 get_modrm(*data, &mod, ®op, &rm); 1385 int8_t imm8 = static_cast<int8_t>(data[1]); 1386 AppendToBuffer("pshufd %s,%s,%d", 1387 NameOfXMMRegister(regop), 1388 NameOfXMMRegister(rm), 1389 static_cast<int>(imm8)); 1390 data += 2; 1391 } else if (*data == 0x76) { 1392 data++; 1393 int mod, regop, rm; 1394 get_modrm(*data, &mod, ®op, &rm); 1395 AppendToBuffer("pcmpeqd %s,%s", 1396 NameOfXMMRegister(regop), 1397 NameOfXMMRegister(rm)); 1398 data++; 1399 } else if (*data == 0x90) { 1400 data++; 1401 AppendToBuffer("nop"); // 2 byte nop. 1402 } else if (*data == 0xF3) { 1403 data++; 1404 int mod, regop, rm; 1405 get_modrm(*data, &mod, ®op, &rm); 1406 AppendToBuffer("psllq %s,%s", 1407 NameOfXMMRegister(regop), 1408 NameOfXMMRegister(rm)); 1409 data++; 1410 } else if (*data == 0x73) { 1411 data++; 1412 int mod, regop, rm; 1413 get_modrm(*data, &mod, ®op, &rm); 1414 int8_t imm8 = static_cast<int8_t>(data[1]); 1415 DCHECK(regop == esi || regop == edx); 1416 AppendToBuffer("%s %s,%d", 1417 (regop == esi) ? "psllq" : "psrlq", 1418 NameOfXMMRegister(rm), 1419 static_cast<int>(imm8)); 1420 data += 2; 1421 } else if (*data == 0xD3) { 1422 data++; 1423 int mod, regop, rm; 1424 get_modrm(*data, &mod, ®op, &rm); 1425 AppendToBuffer("psrlq %s,%s", 1426 NameOfXMMRegister(regop), 1427 NameOfXMMRegister(rm)); 1428 data++; 1429 } else if (*data == 0x7F) { 1430 AppendToBuffer("movdqa "); 1431 data++; 1432 int mod, regop, rm; 1433 get_modrm(*data, &mod, ®op, &rm); 1434 data += PrintRightXMMOperand(data); 1435 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1436 } else if (*data == 0x7E) { 1437 data++; 1438 int mod, regop, rm; 1439 get_modrm(*data, &mod, ®op, &rm); 1440 AppendToBuffer("movd "); 1441 data += PrintRightOperand(data); 1442 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1443 } else if (*data == 0xDB) { 1444 data++; 1445 int mod, regop, rm; 1446 get_modrm(*data, &mod, ®op, &rm); 1447 AppendToBuffer("pand %s,%s", 1448 NameOfXMMRegister(regop), 1449 NameOfXMMRegister(rm)); 1450 data++; 1451 } else if (*data == 0xE7) { 1452 data++; 1453 int mod, regop, rm; 1454 get_modrm(*data, &mod, ®op, &rm); 1455 if (mod == 3) { 1456 AppendToBuffer("movntdq "); 1457 data += PrintRightOperand(data); 1458 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1459 } else { 1460 UnimplementedInstruction(); 1461 } 1462 } else if (*data == 0xEF) { 1463 data++; 1464 int mod, regop, rm; 1465 get_modrm(*data, &mod, ®op, &rm); 1466 AppendToBuffer("pxor %s,%s", 1467 NameOfXMMRegister(regop), 1468 NameOfXMMRegister(rm)); 1469 data++; 1470 } else if (*data == 0xEB) { 1471 data++; 1472 int mod, regop, rm; 1473 get_modrm(*data, &mod, ®op, &rm); 1474 AppendToBuffer("por %s,%s", 1475 NameOfXMMRegister(regop), 1476 NameOfXMMRegister(rm)); 1477 data++; 1478 } else { 1479 UnimplementedInstruction(); 1480 } 1481 } else { 1482 UnimplementedInstruction(); 1483 } 1484 break; 1485 1486 case 0xFE: 1487 { data++; 1488 int mod, regop, rm; 1489 get_modrm(*data, &mod, ®op, &rm); 1490 if (regop == ecx) { 1491 AppendToBuffer("dec_b "); 1492 data += PrintRightOperand(data); 1493 } else { 1494 UnimplementedInstruction(); 1495 } 1496 } 1497 break; 1498 1499 case 0x68: 1500 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1)); 1501 data += 5; 1502 break; 1503 1504 case 0x6A: 1505 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); 1506 data += 2; 1507 break; 1508 1509 case 0xA8: 1510 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1)); 1511 data += 2; 1512 break; 1513 1514 case 0xA9: 1515 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1)); 1516 data += 5; 1517 break; 1518 1519 case 0xD1: // fall through 1520 case 0xD3: // fall through 1521 case 0xC1: 1522 data += D1D3C1Instruction(data); 1523 break; 1524 1525 case 0xD8: // fall through 1526 case 0xD9: // fall through 1527 case 0xDA: // fall through 1528 case 0xDB: // fall through 1529 case 0xDC: // fall through 1530 case 0xDD: // fall through 1531 case 0xDE: // fall through 1532 case 0xDF: 1533 data += FPUInstruction(data); 1534 break; 1535 1536 case 0xEB: 1537 data += JumpShort(data); 1538 break; 1539 1540 case 0xF2: 1541 if (*(data+1) == 0x0F) { 1542 byte b2 = *(data+2); 1543 if (b2 == 0x11) { 1544 AppendToBuffer("movsd "); 1545 data += 3; 1546 int mod, regop, rm; 1547 get_modrm(*data, &mod, ®op, &rm); 1548 data += PrintRightXMMOperand(data); 1549 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1550 } else if (b2 == 0x10) { 1551 data += 3; 1552 int mod, regop, rm; 1553 get_modrm(*data, &mod, ®op, &rm); 1554 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); 1555 data += PrintRightXMMOperand(data); 1556 } else if (b2 == 0x5A) { 1557 data += 3; 1558 int mod, regop, rm; 1559 get_modrm(*data, &mod, ®op, &rm); 1560 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop)); 1561 data += PrintRightXMMOperand(data); 1562 } else { 1563 const char* mnem = "?"; 1564 switch (b2) { 1565 case 0x2A: mnem = "cvtsi2sd"; break; 1566 case 0x2C: mnem = "cvttsd2si"; break; 1567 case 0x2D: mnem = "cvtsd2si"; break; 1568 case 0x51: mnem = "sqrtsd"; break; 1569 case 0x58: mnem = "addsd"; break; 1570 case 0x59: mnem = "mulsd"; break; 1571 case 0x5C: mnem = "subsd"; break; 1572 case 0x5E: mnem = "divsd"; break; 1573 } 1574 data += 3; 1575 int mod, regop, rm; 1576 get_modrm(*data, &mod, ®op, &rm); 1577 if (b2 == 0x2A) { 1578 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1579 data += PrintRightOperand(data); 1580 } else if (b2 == 0x2C || b2 == 0x2D) { 1581 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 1582 data += PrintRightXMMOperand(data); 1583 } else if (b2 == 0xC2) { 1584 // Intel manual 2A, Table 3-18. 1585 const char* const pseudo_op[] = { 1586 "cmpeqsd", 1587 "cmpltsd", 1588 "cmplesd", 1589 "cmpunordsd", 1590 "cmpneqsd", 1591 "cmpnltsd", 1592 "cmpnlesd", 1593 "cmpordsd" 1594 }; 1595 AppendToBuffer("%s %s,%s", 1596 pseudo_op[data[1]], 1597 NameOfXMMRegister(regop), 1598 NameOfXMMRegister(rm)); 1599 data += 2; 1600 } else { 1601 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1602 data += PrintRightXMMOperand(data); 1603 } 1604 } 1605 } else { 1606 UnimplementedInstruction(); 1607 } 1608 break; 1609 1610 case 0xF3: 1611 if (*(data+1) == 0x0F) { 1612 byte b2 = *(data+2); 1613 if (b2 == 0x11) { 1614 AppendToBuffer("movss "); 1615 data += 3; 1616 int mod, regop, rm; 1617 get_modrm(*data, &mod, ®op, &rm); 1618 data += PrintRightXMMOperand(data); 1619 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1620 } else if (b2 == 0x10) { 1621 data += 3; 1622 int mod, regop, rm; 1623 get_modrm(*data, &mod, ®op, &rm); 1624 AppendToBuffer("movss %s,", NameOfXMMRegister(regop)); 1625 data += PrintRightXMMOperand(data); 1626 } else if (b2 == 0x2C) { 1627 data += 3; 1628 int mod, regop, rm; 1629 get_modrm(*data, &mod, ®op, &rm); 1630 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop)); 1631 data += PrintRightXMMOperand(data); 1632 } else if (b2 == 0x5A) { 1633 data += 3; 1634 int mod, regop, rm; 1635 get_modrm(*data, &mod, ®op, &rm); 1636 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); 1637 data += PrintRightXMMOperand(data); 1638 } else if (b2 == 0x6F) { 1639 data += 3; 1640 int mod, regop, rm; 1641 get_modrm(*data, &mod, ®op, &rm); 1642 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop)); 1643 data += PrintRightXMMOperand(data); 1644 } else if (b2 == 0x7F) { 1645 AppendToBuffer("movdqu "); 1646 data += 3; 1647 int mod, regop, rm; 1648 get_modrm(*data, &mod, ®op, &rm); 1649 data += PrintRightXMMOperand(data); 1650 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1651 } else { 1652 UnimplementedInstruction(); 1653 } 1654 } else if (*(data+1) == 0xA5) { 1655 data += 2; 1656 AppendToBuffer("rep_movs"); 1657 } else if (*(data+1) == 0xAB) { 1658 data += 2; 1659 AppendToBuffer("rep_stos"); 1660 } else { 1661 UnimplementedInstruction(); 1662 } 1663 break; 1664 1665 case 0xF7: 1666 data += F7Instruction(data); 1667 break; 1668 1669 default: 1670 UnimplementedInstruction(); 1671 } 1672 } 1673 1674 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { 1675 tmp_buffer_[tmp_buffer_pos_] = '\0'; 1676 } 1677 1678 int instr_len = data - instr; 1679 if (instr_len == 0) { 1680 printf("%02x", *data); 1681 } 1682 DCHECK(instr_len > 0); // Ensure progress. 1683 1684 int outp = 0; 1685 // Instruction bytes. 1686 for (byte* bp = instr; bp < data; bp++) { 1687 outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp); 1688 } 1689 for (int i = 6 - instr_len; i >= 0; i--) { 1690 outp += v8::internal::SNPrintF(out_buffer + outp, " "); 1691 } 1692 1693 outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.start()); 1694 return instr_len; 1695 } // NOLINT (function is too long) 1696 1697 1698 //------------------------------------------------------------------------------ 1699 1700 1701 static const char* cpu_regs[8] = { 1702 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 1703 }; 1704 1705 1706 static const char* byte_cpu_regs[8] = { 1707 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 1708 }; 1709 1710 1711 static const char* xmm_regs[8] = { 1712 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" 1713 }; 1714 1715 1716 const char* NameConverter::NameOfAddress(byte* addr) const { 1717 v8::internal::SNPrintF(tmp_buffer_, "%p", addr); 1718 return tmp_buffer_.start(); 1719 } 1720 1721 1722 const char* NameConverter::NameOfConstant(byte* addr) const { 1723 return NameOfAddress(addr); 1724 } 1725 1726 1727 const char* NameConverter::NameOfCPURegister(int reg) const { 1728 if (0 <= reg && reg < 8) return cpu_regs[reg]; 1729 return "noreg"; 1730 } 1731 1732 1733 const char* NameConverter::NameOfByteCPURegister(int reg) const { 1734 if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; 1735 return "noreg"; 1736 } 1737 1738 1739 const char* NameConverter::NameOfXMMRegister(int reg) const { 1740 if (0 <= reg && reg < 8) return xmm_regs[reg]; 1741 return "noxmmreg"; 1742 } 1743 1744 1745 const char* NameConverter::NameInCode(byte* addr) const { 1746 // X87 does not embed debug strings at the moment. 1747 UNREACHABLE(); 1748 return ""; 1749 } 1750 1751 1752 //------------------------------------------------------------------------------ 1753 1754 Disassembler::Disassembler(const NameConverter& converter) 1755 : converter_(converter) {} 1756 1757 1758 Disassembler::~Disassembler() {} 1759 1760 1761 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 1762 byte* instruction) { 1763 DisassemblerX87 d(converter_, false /*do not crash if unimplemented*/); 1764 return d.InstructionDecode(buffer, instruction); 1765 } 1766 1767 1768 // The IA-32 assembler does not currently use constant pools. 1769 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } 1770 1771 1772 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { 1773 NameConverter converter; 1774 Disassembler d(converter); 1775 for (byte* pc = begin; pc < end;) { 1776 v8::internal::EmbeddedVector<char, 128> buffer; 1777 buffer[0] = '\0'; 1778 byte* prev_pc = pc; 1779 pc += d.InstructionDecode(buffer, pc); 1780 fprintf(f, "%p", prev_pc); 1781 fprintf(f, " "); 1782 1783 for (byte* bp = prev_pc; bp < pc; bp++) { 1784 fprintf(f, "%02x", *bp); 1785 } 1786 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { 1787 fprintf(f, " "); 1788 } 1789 fprintf(f, " %s\n", buffer.start()); 1790 } 1791 } 1792 1793 1794 } // namespace disasm 1795 1796 #endif // V8_TARGET_ARCH_X87 1797