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