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_IA32 12 13#include "src/disasm.h" 14 15namespace disasm { 16 17enum OperandOrder { 18 UNSET_OP_ORDER = 0, 19 REG_OPER_OP_ORDER, 20 OPER_REG_OP_ORDER 21}; 22 23 24//------------------------------------------------------------------ 25// Tables 26//------------------------------------------------------------------ 27struct ByteMnemonic { 28 int b; // -1 terminates, otherwise must be in range (0..255) 29 const char* mnem; 30 OperandOrder op_order_; 31}; 32 33 34static 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 60static 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 79static 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 86static 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. 102static 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 111static 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 119static 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 127static 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 135enum 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 148struct InstructionDesc { 149 const char* mnem; 150 InstructionType type; 151 OperandOrder op_order_; 152}; 153 154 155class 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 177InstructionTable::InstructionTable() { 178 Clear(); 179 Init(); 180} 181 182 183void 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 192void 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 208void 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 220void 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 233void 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 IA32 disassembler implementation. 244class DisassemblerIA32 { 245 public: 246 DisassemblerIA32(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 ~DisassemblerIA32() {} 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* (DisassemblerIA32::*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 356void DisassemblerIA32::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 365int DisassemblerIA32::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 &DisassemblerIA32::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 453int DisassemblerIA32::PrintRightOperand(byte* modrmp) { 454 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); 455} 456 457 458int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { 459 return PrintRightOperandHelper(modrmp, 460 &DisassemblerIA32::NameOfByteCPURegister); 461} 462 463 464int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) { 465 return PrintRightOperandHelper(modrmp, 466 &DisassemblerIA32::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_'. 472int DisassemblerIA32::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_'. 501int DisassemblerIA32::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. 530int DisassemblerIA32::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 571int DisassemblerIA32::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. 624int DisassemblerIA32::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. 634int DisassemblerIA32::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. 648int DisassemblerIA32::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. 662int DisassemblerIA32::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. 673int DisassemblerIA32::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. 683int DisassemblerIA32::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 695int DisassemblerIA32::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 7: mnem = "fstcw"; break; 706 default: UnimplementedInstruction(); 707 } 708 break; 709 710 case 0xDB: switch (regop) { 711 case 0: mnem = "fild_s"; break; 712 case 1: mnem = "fisttp_s"; break; 713 case 2: mnem = "fist_s"; break; 714 case 3: mnem = "fistp_s"; break; 715 default: UnimplementedInstruction(); 716 } 717 break; 718 719 case 0xDD: switch (regop) { 720 case 0: mnem = "fld_d"; break; 721 case 1: mnem = "fisttp_d"; break; 722 case 2: mnem = "fst_d"; break; 723 case 3: mnem = "fstp_d"; break; 724 default: UnimplementedInstruction(); 725 } 726 break; 727 728 case 0xDF: switch (regop) { 729 case 5: mnem = "fild_d"; break; 730 case 7: mnem = "fistp_d"; break; 731 default: UnimplementedInstruction(); 732 } 733 break; 734 735 default: UnimplementedInstruction(); 736 } 737 AppendToBuffer("%s ", mnem); 738 int count = PrintRightOperand(modrm_start); 739 return count + 1; 740} 741 742int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, 743 byte modrm_byte) { 744 bool has_register = false; // Is the FPU register encoded in modrm_byte? 745 const char* mnem = "?"; 746 747 switch (escape_opcode) { 748 case 0xD8: 749 has_register = true; 750 switch (modrm_byte & 0xF8) { 751 case 0xC0: mnem = "fadd_i"; break; 752 case 0xE0: mnem = "fsub_i"; break; 753 case 0xC8: mnem = "fmul_i"; break; 754 case 0xF0: mnem = "fdiv_i"; break; 755 default: UnimplementedInstruction(); 756 } 757 break; 758 759 case 0xD9: 760 switch (modrm_byte & 0xF8) { 761 case 0xC0: 762 mnem = "fld"; 763 has_register = true; 764 break; 765 case 0xC8: 766 mnem = "fxch"; 767 has_register = true; 768 break; 769 default: 770 switch (modrm_byte) { 771 case 0xE0: mnem = "fchs"; break; 772 case 0xE1: mnem = "fabs"; break; 773 case 0xE4: mnem = "ftst"; break; 774 case 0xE8: mnem = "fld1"; break; 775 case 0xEB: mnem = "fldpi"; break; 776 case 0xED: mnem = "fldln2"; break; 777 case 0xEE: mnem = "fldz"; break; 778 case 0xF0: mnem = "f2xm1"; break; 779 case 0xF1: mnem = "fyl2x"; break; 780 case 0xF4: mnem = "fxtract"; break; 781 case 0xF5: mnem = "fprem1"; break; 782 case 0xF7: mnem = "fincstp"; break; 783 case 0xF8: mnem = "fprem"; break; 784 case 0xFC: mnem = "frndint"; break; 785 case 0xFD: mnem = "fscale"; break; 786 case 0xFE: mnem = "fsin"; break; 787 case 0xFF: mnem = "fcos"; break; 788 default: UnimplementedInstruction(); 789 } 790 } 791 break; 792 793 case 0xDA: 794 if (modrm_byte == 0xE9) { 795 mnem = "fucompp"; 796 } else { 797 UnimplementedInstruction(); 798 } 799 break; 800 801 case 0xDB: 802 if ((modrm_byte & 0xF8) == 0xE8) { 803 mnem = "fucomi"; 804 has_register = true; 805 } else if (modrm_byte == 0xE2) { 806 mnem = "fclex"; 807 } else if (modrm_byte == 0xE3) { 808 mnem = "fninit"; 809 } else { 810 UnimplementedInstruction(); 811 } 812 break; 813 814 case 0xDC: 815 has_register = true; 816 switch (modrm_byte & 0xF8) { 817 case 0xC0: mnem = "fadd"; break; 818 case 0xE8: mnem = "fsub"; break; 819 case 0xC8: mnem = "fmul"; break; 820 case 0xF8: mnem = "fdiv"; break; 821 default: UnimplementedInstruction(); 822 } 823 break; 824 825 case 0xDD: 826 has_register = true; 827 switch (modrm_byte & 0xF8) { 828 case 0xC0: mnem = "ffree"; break; 829 case 0xD0: mnem = "fst"; break; 830 case 0xD8: mnem = "fstp"; break; 831 default: UnimplementedInstruction(); 832 } 833 break; 834 835 case 0xDE: 836 if (modrm_byte == 0xD9) { 837 mnem = "fcompp"; 838 } else { 839 has_register = true; 840 switch (modrm_byte & 0xF8) { 841 case 0xC0: mnem = "faddp"; break; 842 case 0xE8: mnem = "fsubp"; break; 843 case 0xC8: mnem = "fmulp"; break; 844 case 0xF8: mnem = "fdivp"; break; 845 default: UnimplementedInstruction(); 846 } 847 } 848 break; 849 850 case 0xDF: 851 if (modrm_byte == 0xE0) { 852 mnem = "fnstsw_ax"; 853 } else if ((modrm_byte & 0xF8) == 0xE8) { 854 mnem = "fucomip"; 855 has_register = true; 856 } 857 break; 858 859 default: UnimplementedInstruction(); 860 } 861 862 if (has_register) { 863 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); 864 } else { 865 AppendToBuffer("%s", mnem); 866 } 867 return 2; 868} 869 870 871// Mnemonics for instructions 0xF0 byte. 872// Returns NULL if the instruction is not handled here. 873static const char* F0Mnem(byte f0byte) { 874 switch (f0byte) { 875 case 0x18: return "prefetch"; 876 case 0xA2: return "cpuid"; 877 case 0xBE: return "movsx_b"; 878 case 0xBF: return "movsx_w"; 879 case 0xB6: return "movzx_b"; 880 case 0xB7: return "movzx_w"; 881 case 0xAF: return "imul"; 882 case 0xA5: return "shld"; 883 case 0xAD: return "shrd"; 884 case 0xAC: return "shrd"; // 3-operand version. 885 case 0xAB: return "bts"; 886 case 0xBD: return "bsr"; 887 default: return NULL; 888 } 889} 890 891 892// Disassembled instruction '*instr' and writes it into 'out_buffer'. 893int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, 894 byte* instr) { 895 tmp_buffer_pos_ = 0; // starting to write as position 0 896 byte* data = instr; 897 // Check for hints. 898 const char* branch_hint = NULL; 899 // We use these two prefixes only with branch prediction 900 if (*data == 0x3E /*ds*/) { 901 branch_hint = "predicted taken"; 902 data++; 903 } else if (*data == 0x2E /*cs*/) { 904 branch_hint = "predicted not taken"; 905 data++; 906 } 907 bool processed = true; // Will be set to false if the current instruction 908 // is not in 'instructions' table. 909 const InstructionDesc& idesc = instruction_table_->Get(*data); 910 switch (idesc.type) { 911 case ZERO_OPERANDS_INSTR: 912 AppendToBuffer(idesc.mnem); 913 data++; 914 break; 915 916 case TWO_OPERANDS_INSTR: 917 data++; 918 data += PrintOperands(idesc.mnem, idesc.op_order_, data); 919 break; 920 921 case JUMP_CONDITIONAL_SHORT_INSTR: 922 data += JumpConditionalShort(data, branch_hint); 923 break; 924 925 case REGISTER_INSTR: 926 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); 927 data++; 928 break; 929 930 case MOVE_REG_INSTR: { 931 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); 932 AppendToBuffer("mov %s,%s", 933 NameOfCPURegister(*data & 0x07), 934 NameOfAddress(addr)); 935 data += 5; 936 break; 937 } 938 939 case CALL_JUMP_INSTR: { 940 byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5; 941 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); 942 data += 5; 943 break; 944 } 945 946 case SHORT_IMMEDIATE_INSTR: { 947 byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); 948 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr)); 949 data += 5; 950 break; 951 } 952 953 case BYTE_IMMEDIATE_INSTR: { 954 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]); 955 data += 2; 956 break; 957 } 958 959 case NO_INSTR: 960 processed = false; 961 break; 962 963 default: 964 UNIMPLEMENTED(); // This type is not implemented. 965 } 966 //---------------------------- 967 if (!processed) { 968 switch (*data) { 969 case 0xC2: 970 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); 971 data += 3; 972 break; 973 974 case 0x6B: { 975 data++; 976 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 977 AppendToBuffer(",%d", *data); 978 data++; 979 } break; 980 981 case 0x69: { 982 data++; 983 data += PrintOperands("imul", REG_OPER_OP_ORDER, data); 984 AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data)); 985 data += 4; 986 } 987 break; 988 989 case 0xF6: 990 { data++; 991 int mod, regop, rm; 992 get_modrm(*data, &mod, ®op, &rm); 993 if (regop == eax) { 994 AppendToBuffer("test_b "); 995 data += PrintRightByteOperand(data); 996 int32_t imm = *data; 997 AppendToBuffer(",0x%x", imm); 998 data++; 999 } else { 1000 UnimplementedInstruction(); 1001 } 1002 } 1003 break; 1004 1005 case 0x81: // fall through 1006 case 0x83: // 0x81 with sign extension bit set 1007 data += PrintImmediateOp(data); 1008 break; 1009 1010 case 0x0F: 1011 { byte f0byte = data[1]; 1012 const char* f0mnem = F0Mnem(f0byte); 1013 if (f0byte == 0x18) { 1014 data += 2; 1015 int mod, regop, rm; 1016 get_modrm(*data, &mod, ®op, &rm); 1017 const char* suffix[] = {"nta", "1", "2", "3"}; 1018 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]); 1019 data += PrintRightOperand(data); 1020 } else if (f0byte == 0x1F && data[2] == 0) { 1021 AppendToBuffer("nop"); // 3 byte nop. 1022 data += 3; 1023 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) { 1024 AppendToBuffer("nop"); // 4 byte nop. 1025 data += 4; 1026 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 && 1027 data[4] == 0) { 1028 AppendToBuffer("nop"); // 5 byte nop. 1029 data += 5; 1030 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 && 1031 data[4] == 0 && data[5] == 0 && data[6] == 0) { 1032 AppendToBuffer("nop"); // 7 byte nop. 1033 data += 7; 1034 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 && 1035 data[4] == 0 && data[5] == 0 && data[6] == 0 && 1036 data[7] == 0) { 1037 AppendToBuffer("nop"); // 8 byte nop. 1038 data += 8; 1039 } else if (f0byte == 0xA2 || f0byte == 0x31) { 1040 AppendToBuffer("%s", f0mnem); 1041 data += 2; 1042 } else if (f0byte == 0x28) { 1043 data += 2; 1044 int mod, regop, rm; 1045 get_modrm(*data, &mod, ®op, &rm); 1046 AppendToBuffer("movaps %s,%s", 1047 NameOfXMMRegister(regop), 1048 NameOfXMMRegister(rm)); 1049 data++; 1050 } else if (f0byte >= 0x53 && f0byte <= 0x5F) { 1051 const char* const pseudo_op[] = { 1052 "rcpps", 1053 "andps", 1054 "andnps", 1055 "orps", 1056 "xorps", 1057 "addps", 1058 "mulps", 1059 "cvtps2pd", 1060 "cvtdq2ps", 1061 "subps", 1062 "minps", 1063 "divps", 1064 "maxps", 1065 }; 1066 1067 data += 2; 1068 int mod, regop, rm; 1069 get_modrm(*data, &mod, ®op, &rm); 1070 AppendToBuffer("%s %s,", 1071 pseudo_op[f0byte - 0x53], 1072 NameOfXMMRegister(regop)); 1073 data += PrintRightXMMOperand(data); 1074 } else if (f0byte == 0x50) { 1075 data += 2; 1076 int mod, regop, rm; 1077 get_modrm(*data, &mod, ®op, &rm); 1078 AppendToBuffer("movmskps %s,%s", 1079 NameOfCPURegister(regop), 1080 NameOfXMMRegister(rm)); 1081 data++; 1082 } else if (f0byte== 0xC6) { 1083 // shufps xmm, xmm/m128, imm8 1084 data += 2; 1085 int mod, regop, rm; 1086 get_modrm(*data, &mod, ®op, &rm); 1087 int8_t imm8 = static_cast<int8_t>(data[1]); 1088 AppendToBuffer("shufps %s,%s,%d", 1089 NameOfXMMRegister(rm), 1090 NameOfXMMRegister(regop), 1091 static_cast<int>(imm8)); 1092 data += 2; 1093 } else if ((f0byte & 0xF0) == 0x80) { 1094 data += JumpConditional(data, branch_hint); 1095 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || 1096 f0byte == 0xB7 || f0byte == 0xAF) { 1097 data += 2; 1098 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); 1099 } else if ((f0byte & 0xF0) == 0x90) { 1100 data += SetCC(data); 1101 } else if ((f0byte & 0xF0) == 0x40) { 1102 data += CMov(data); 1103 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { 1104 // shrd, shld, bts 1105 data += 2; 1106 AppendToBuffer("%s ", f0mnem); 1107 int mod, regop, rm; 1108 get_modrm(*data, &mod, ®op, &rm); 1109 data += PrintRightOperand(data); 1110 if (f0byte == 0xAB) { 1111 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1112 } else { 1113 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); 1114 } 1115 } else if (f0byte == 0xBD) { 1116 data += 2; 1117 int mod, regop, rm; 1118 get_modrm(*data, &mod, ®op, &rm); 1119 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop)); 1120 data += PrintRightOperand(data); 1121 } else { 1122 UnimplementedInstruction(); 1123 } 1124 } 1125 break; 1126 1127 case 0x8F: 1128 { data++; 1129 int mod, regop, rm; 1130 get_modrm(*data, &mod, ®op, &rm); 1131 if (regop == eax) { 1132 AppendToBuffer("pop "); 1133 data += PrintRightOperand(data); 1134 } 1135 } 1136 break; 1137 1138 case 0xFF: 1139 { data++; 1140 int mod, regop, rm; 1141 get_modrm(*data, &mod, ®op, &rm); 1142 const char* mnem = NULL; 1143 switch (regop) { 1144 case esi: mnem = "push"; break; 1145 case eax: mnem = "inc"; break; 1146 case ecx: mnem = "dec"; break; 1147 case edx: mnem = "call"; break; 1148 case esp: mnem = "jmp"; break; 1149 default: mnem = "???"; 1150 } 1151 AppendToBuffer("%s ", mnem); 1152 data += PrintRightOperand(data); 1153 } 1154 break; 1155 1156 case 0xC7: // imm32, fall through 1157 case 0xC6: // imm8 1158 { bool is_byte = *data == 0xC6; 1159 data++; 1160 if (is_byte) { 1161 AppendToBuffer("%s ", "mov_b"); 1162 data += PrintRightByteOperand(data); 1163 int32_t imm = *data; 1164 AppendToBuffer(",0x%x", imm); 1165 data++; 1166 } else { 1167 AppendToBuffer("%s ", "mov"); 1168 data += PrintRightOperand(data); 1169 int32_t imm = *reinterpret_cast<int32_t*>(data); 1170 AppendToBuffer(",0x%x", imm); 1171 data += 4; 1172 } 1173 } 1174 break; 1175 1176 case 0x80: 1177 { data++; 1178 int mod, regop, rm; 1179 get_modrm(*data, &mod, ®op, &rm); 1180 const char* mnem = NULL; 1181 switch (regop) { 1182 case 5: mnem = "subb"; break; 1183 case 7: mnem = "cmpb"; break; 1184 default: UnimplementedInstruction(); 1185 } 1186 AppendToBuffer("%s ", mnem); 1187 data += PrintRightByteOperand(data); 1188 int32_t imm = *data; 1189 AppendToBuffer(",0x%x", imm); 1190 data++; 1191 } 1192 break; 1193 1194 case 0x88: // 8bit, fall through 1195 case 0x89: // 32bit 1196 { bool is_byte = *data == 0x88; 1197 int mod, regop, rm; 1198 data++; 1199 get_modrm(*data, &mod, ®op, &rm); 1200 if (is_byte) { 1201 AppendToBuffer("%s ", "mov_b"); 1202 data += PrintRightByteOperand(data); 1203 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1204 } else { 1205 AppendToBuffer("%s ", "mov"); 1206 data += PrintRightOperand(data); 1207 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1208 } 1209 } 1210 break; 1211 1212 case 0x66: // prefix 1213 while (*data == 0x66) data++; 1214 if (*data == 0xf && data[1] == 0x1f) { 1215 AppendToBuffer("nop"); // 0x66 prefix 1216 } else if (*data == 0x90) { 1217 AppendToBuffer("nop"); // 0x66 prefix 1218 } else if (*data == 0x8B) { 1219 data++; 1220 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); 1221 } else if (*data == 0x89) { 1222 data++; 1223 int mod, regop, rm; 1224 get_modrm(*data, &mod, ®op, &rm); 1225 AppendToBuffer("mov_w "); 1226 data += PrintRightOperand(data); 1227 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1228 } else if (*data == 0xC7) { 1229 data++; 1230 AppendToBuffer("%s ", "mov_w"); 1231 data += PrintRightOperand(data); 1232 int imm = *reinterpret_cast<int16_t*>(data); 1233 AppendToBuffer(",0x%x", imm); 1234 data += 2; 1235 } else if (*data == 0x0F) { 1236 data++; 1237 if (*data == 0x38) { 1238 data++; 1239 if (*data == 0x17) { 1240 data++; 1241 int mod, regop, rm; 1242 get_modrm(*data, &mod, ®op, &rm); 1243 AppendToBuffer("ptest %s,%s", 1244 NameOfXMMRegister(regop), 1245 NameOfXMMRegister(rm)); 1246 data++; 1247 } else if (*data == 0x2A) { 1248 // movntdqa 1249 data++; 1250 int mod, regop, rm; 1251 get_modrm(*data, &mod, ®op, &rm); 1252 AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop)); 1253 data += PrintRightOperand(data); 1254 } else { 1255 UnimplementedInstruction(); 1256 } 1257 } else if (*data == 0x3A) { 1258 data++; 1259 if (*data == 0x0B) { 1260 data++; 1261 int mod, regop, rm; 1262 get_modrm(*data, &mod, ®op, &rm); 1263 int8_t imm8 = static_cast<int8_t>(data[1]); 1264 AppendToBuffer("roundsd %s,%s,%d", 1265 NameOfXMMRegister(regop), 1266 NameOfXMMRegister(rm), 1267 static_cast<int>(imm8)); 1268 data += 2; 1269 } else if (*data == 0x16) { 1270 data++; 1271 int mod, regop, rm; 1272 get_modrm(*data, &mod, ®op, &rm); 1273 int8_t imm8 = static_cast<int8_t>(data[1]); 1274 AppendToBuffer("pextrd %s,%s,%d", 1275 NameOfCPURegister(regop), 1276 NameOfXMMRegister(rm), 1277 static_cast<int>(imm8)); 1278 data += 2; 1279 } else if (*data == 0x17) { 1280 data++; 1281 int mod, regop, rm; 1282 get_modrm(*data, &mod, ®op, &rm); 1283 int8_t imm8 = static_cast<int8_t>(data[1]); 1284 AppendToBuffer("extractps %s,%s,%d", 1285 NameOfCPURegister(rm), 1286 NameOfXMMRegister(regop), 1287 static_cast<int>(imm8)); 1288 data += 2; 1289 } else if (*data == 0x22) { 1290 data++; 1291 int mod, regop, rm; 1292 get_modrm(*data, &mod, ®op, &rm); 1293 int8_t imm8 = static_cast<int8_t>(data[1]); 1294 AppendToBuffer("pinsrd %s,%s,%d", 1295 NameOfXMMRegister(regop), 1296 NameOfCPURegister(rm), 1297 static_cast<int>(imm8)); 1298 data += 2; 1299 } else { 1300 UnimplementedInstruction(); 1301 } 1302 } else if (*data == 0x2E || *data == 0x2F) { 1303 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd"; 1304 data++; 1305 int mod, regop, rm; 1306 get_modrm(*data, &mod, ®op, &rm); 1307 if (mod == 0x3) { 1308 AppendToBuffer("%s %s,%s", mnem, 1309 NameOfXMMRegister(regop), 1310 NameOfXMMRegister(rm)); 1311 data++; 1312 } else { 1313 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1314 data += PrintRightOperand(data); 1315 } 1316 } else if (*data == 0x50) { 1317 data++; 1318 int mod, regop, rm; 1319 get_modrm(*data, &mod, ®op, &rm); 1320 AppendToBuffer("movmskpd %s,%s", 1321 NameOfCPURegister(regop), 1322 NameOfXMMRegister(rm)); 1323 data++; 1324 } else if (*data == 0x54) { 1325 data++; 1326 int mod, regop, rm; 1327 get_modrm(*data, &mod, ®op, &rm); 1328 AppendToBuffer("andpd %s,%s", 1329 NameOfXMMRegister(regop), 1330 NameOfXMMRegister(rm)); 1331 data++; 1332 } else if (*data == 0x56) { 1333 data++; 1334 int mod, regop, rm; 1335 get_modrm(*data, &mod, ®op, &rm); 1336 AppendToBuffer("orpd %s,%s", 1337 NameOfXMMRegister(regop), 1338 NameOfXMMRegister(rm)); 1339 data++; 1340 } else if (*data == 0x57) { 1341 data++; 1342 int mod, regop, rm; 1343 get_modrm(*data, &mod, ®op, &rm); 1344 AppendToBuffer("xorpd %s,%s", 1345 NameOfXMMRegister(regop), 1346 NameOfXMMRegister(rm)); 1347 data++; 1348 } else if (*data == 0x6E) { 1349 data++; 1350 int mod, regop, rm; 1351 get_modrm(*data, &mod, ®op, &rm); 1352 AppendToBuffer("movd %s,", NameOfXMMRegister(regop)); 1353 data += PrintRightOperand(data); 1354 } else if (*data == 0x6F) { 1355 data++; 1356 int mod, regop, rm; 1357 get_modrm(*data, &mod, ®op, &rm); 1358 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop)); 1359 data += PrintRightXMMOperand(data); 1360 } else if (*data == 0x70) { 1361 data++; 1362 int mod, regop, rm; 1363 get_modrm(*data, &mod, ®op, &rm); 1364 int8_t imm8 = static_cast<int8_t>(data[1]); 1365 AppendToBuffer("pshufd %s,%s,%d", 1366 NameOfXMMRegister(regop), 1367 NameOfXMMRegister(rm), 1368 static_cast<int>(imm8)); 1369 data += 2; 1370 } else if (*data == 0x76) { 1371 data++; 1372 int mod, regop, rm; 1373 get_modrm(*data, &mod, ®op, &rm); 1374 AppendToBuffer("pcmpeqd %s,%s", 1375 NameOfXMMRegister(regop), 1376 NameOfXMMRegister(rm)); 1377 data++; 1378 } else if (*data == 0x90) { 1379 data++; 1380 AppendToBuffer("nop"); // 2 byte nop. 1381 } else if (*data == 0xF3) { 1382 data++; 1383 int mod, regop, rm; 1384 get_modrm(*data, &mod, ®op, &rm); 1385 AppendToBuffer("psllq %s,%s", 1386 NameOfXMMRegister(regop), 1387 NameOfXMMRegister(rm)); 1388 data++; 1389 } else if (*data == 0x73) { 1390 data++; 1391 int mod, regop, rm; 1392 get_modrm(*data, &mod, ®op, &rm); 1393 int8_t imm8 = static_cast<int8_t>(data[1]); 1394 DCHECK(regop == esi || regop == edx); 1395 AppendToBuffer("%s %s,%d", 1396 (regop == esi) ? "psllq" : "psrlq", 1397 NameOfXMMRegister(rm), 1398 static_cast<int>(imm8)); 1399 data += 2; 1400 } else if (*data == 0xD3) { 1401 data++; 1402 int mod, regop, rm; 1403 get_modrm(*data, &mod, ®op, &rm); 1404 AppendToBuffer("psrlq %s,%s", 1405 NameOfXMMRegister(regop), 1406 NameOfXMMRegister(rm)); 1407 data++; 1408 } else if (*data == 0x7F) { 1409 AppendToBuffer("movdqa "); 1410 data++; 1411 int mod, regop, rm; 1412 get_modrm(*data, &mod, ®op, &rm); 1413 data += PrintRightXMMOperand(data); 1414 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1415 } else if (*data == 0x7E) { 1416 data++; 1417 int mod, regop, rm; 1418 get_modrm(*data, &mod, ®op, &rm); 1419 AppendToBuffer("movd "); 1420 data += PrintRightOperand(data); 1421 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1422 } else if (*data == 0xDB) { 1423 data++; 1424 int mod, regop, rm; 1425 get_modrm(*data, &mod, ®op, &rm); 1426 AppendToBuffer("pand %s,%s", 1427 NameOfXMMRegister(regop), 1428 NameOfXMMRegister(rm)); 1429 data++; 1430 } else if (*data == 0xE7) { 1431 data++; 1432 int mod, regop, rm; 1433 get_modrm(*data, &mod, ®op, &rm); 1434 if (mod == 3) { 1435 AppendToBuffer("movntdq "); 1436 data += PrintRightOperand(data); 1437 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1438 } else { 1439 UnimplementedInstruction(); 1440 } 1441 } else if (*data == 0xEF) { 1442 data++; 1443 int mod, regop, rm; 1444 get_modrm(*data, &mod, ®op, &rm); 1445 AppendToBuffer("pxor %s,%s", 1446 NameOfXMMRegister(regop), 1447 NameOfXMMRegister(rm)); 1448 data++; 1449 } else if (*data == 0xEB) { 1450 data++; 1451 int mod, regop, rm; 1452 get_modrm(*data, &mod, ®op, &rm); 1453 AppendToBuffer("por %s,%s", 1454 NameOfXMMRegister(regop), 1455 NameOfXMMRegister(rm)); 1456 data++; 1457 } else { 1458 UnimplementedInstruction(); 1459 } 1460 } else { 1461 UnimplementedInstruction(); 1462 } 1463 break; 1464 1465 case 0xFE: 1466 { data++; 1467 int mod, regop, rm; 1468 get_modrm(*data, &mod, ®op, &rm); 1469 if (regop == ecx) { 1470 AppendToBuffer("dec_b "); 1471 data += PrintRightOperand(data); 1472 } else { 1473 UnimplementedInstruction(); 1474 } 1475 } 1476 break; 1477 1478 case 0x68: 1479 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1)); 1480 data += 5; 1481 break; 1482 1483 case 0x6A: 1484 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); 1485 data += 2; 1486 break; 1487 1488 case 0xA8: 1489 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1)); 1490 data += 2; 1491 break; 1492 1493 case 0xA9: 1494 AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1)); 1495 data += 5; 1496 break; 1497 1498 case 0xD1: // fall through 1499 case 0xD3: // fall through 1500 case 0xC1: 1501 data += D1D3C1Instruction(data); 1502 break; 1503 1504 case 0xD8: // fall through 1505 case 0xD9: // fall through 1506 case 0xDA: // fall through 1507 case 0xDB: // fall through 1508 case 0xDC: // fall through 1509 case 0xDD: // fall through 1510 case 0xDE: // fall through 1511 case 0xDF: 1512 data += FPUInstruction(data); 1513 break; 1514 1515 case 0xEB: 1516 data += JumpShort(data); 1517 break; 1518 1519 case 0xF2: 1520 if (*(data+1) == 0x0F) { 1521 byte b2 = *(data+2); 1522 if (b2 == 0x11) { 1523 AppendToBuffer("movsd "); 1524 data += 3; 1525 int mod, regop, rm; 1526 get_modrm(*data, &mod, ®op, &rm); 1527 data += PrintRightXMMOperand(data); 1528 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1529 } else if (b2 == 0x10) { 1530 data += 3; 1531 int mod, regop, rm; 1532 get_modrm(*data, &mod, ®op, &rm); 1533 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); 1534 data += PrintRightXMMOperand(data); 1535 } else if (b2 == 0x5A) { 1536 data += 3; 1537 int mod, regop, rm; 1538 get_modrm(*data, &mod, ®op, &rm); 1539 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop)); 1540 data += PrintRightXMMOperand(data); 1541 } else { 1542 const char* mnem = "?"; 1543 switch (b2) { 1544 case 0x2A: mnem = "cvtsi2sd"; break; 1545 case 0x2C: mnem = "cvttsd2si"; break; 1546 case 0x2D: mnem = "cvtsd2si"; break; 1547 case 0x51: mnem = "sqrtsd"; break; 1548 case 0x58: mnem = "addsd"; break; 1549 case 0x59: mnem = "mulsd"; break; 1550 case 0x5C: mnem = "subsd"; break; 1551 case 0x5E: mnem = "divsd"; break; 1552 } 1553 data += 3; 1554 int mod, regop, rm; 1555 get_modrm(*data, &mod, ®op, &rm); 1556 if (b2 == 0x2A) { 1557 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1558 data += PrintRightOperand(data); 1559 } else if (b2 == 0x2C || b2 == 0x2D) { 1560 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); 1561 data += PrintRightXMMOperand(data); 1562 } else if (b2 == 0xC2) { 1563 // Intel manual 2A, Table 3-18. 1564 const char* const pseudo_op[] = { 1565 "cmpeqsd", 1566 "cmpltsd", 1567 "cmplesd", 1568 "cmpunordsd", 1569 "cmpneqsd", 1570 "cmpnltsd", 1571 "cmpnlesd", 1572 "cmpordsd" 1573 }; 1574 AppendToBuffer("%s %s,%s", 1575 pseudo_op[data[1]], 1576 NameOfXMMRegister(regop), 1577 NameOfXMMRegister(rm)); 1578 data += 2; 1579 } else { 1580 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); 1581 data += PrintRightXMMOperand(data); 1582 } 1583 } 1584 } else { 1585 UnimplementedInstruction(); 1586 } 1587 break; 1588 1589 case 0xF3: 1590 if (*(data+1) == 0x0F) { 1591 byte b2 = *(data+2); 1592 if (b2 == 0x11) { 1593 AppendToBuffer("movss "); 1594 data += 3; 1595 int mod, regop, rm; 1596 get_modrm(*data, &mod, ®op, &rm); 1597 data += PrintRightXMMOperand(data); 1598 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1599 } else if (b2 == 0x10) { 1600 data += 3; 1601 int mod, regop, rm; 1602 get_modrm(*data, &mod, ®op, &rm); 1603 AppendToBuffer("movss %s,", NameOfXMMRegister(regop)); 1604 data += PrintRightXMMOperand(data); 1605 } else if (b2 == 0x2C) { 1606 data += 3; 1607 int mod, regop, rm; 1608 get_modrm(*data, &mod, ®op, &rm); 1609 AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop)); 1610 data += PrintRightXMMOperand(data); 1611 } else if (b2 == 0x5A) { 1612 data += 3; 1613 int mod, regop, rm; 1614 get_modrm(*data, &mod, ®op, &rm); 1615 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); 1616 data += PrintRightXMMOperand(data); 1617 } else if (b2 == 0x6F) { 1618 data += 3; 1619 int mod, regop, rm; 1620 get_modrm(*data, &mod, ®op, &rm); 1621 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop)); 1622 data += PrintRightXMMOperand(data); 1623 } else if (b2 == 0x7F) { 1624 AppendToBuffer("movdqu "); 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 { 1631 UnimplementedInstruction(); 1632 } 1633 } else if (*(data+1) == 0xA5) { 1634 data += 2; 1635 AppendToBuffer("rep_movs"); 1636 } else if (*(data+1) == 0xAB) { 1637 data += 2; 1638 AppendToBuffer("rep_stos"); 1639 } else { 1640 UnimplementedInstruction(); 1641 } 1642 break; 1643 1644 case 0xF7: 1645 data += F7Instruction(data); 1646 break; 1647 1648 default: 1649 UnimplementedInstruction(); 1650 } 1651 } 1652 1653 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { 1654 tmp_buffer_[tmp_buffer_pos_] = '\0'; 1655 } 1656 1657 int instr_len = data - instr; 1658 if (instr_len == 0) { 1659 printf("%02x", *data); 1660 } 1661 DCHECK(instr_len > 0); // Ensure progress. 1662 1663 int outp = 0; 1664 // Instruction bytes. 1665 for (byte* bp = instr; bp < data; bp++) { 1666 outp += v8::internal::SNPrintF(out_buffer + outp, 1667 "%02x", 1668 *bp); 1669 } 1670 for (int i = 6 - instr_len; i >= 0; i--) { 1671 outp += v8::internal::SNPrintF(out_buffer + outp, " "); 1672 } 1673 1674 outp += v8::internal::SNPrintF(out_buffer + outp, 1675 " %s", 1676 tmp_buffer_.start()); 1677 return instr_len; 1678} // NOLINT (function is too long) 1679 1680 1681//------------------------------------------------------------------------------ 1682 1683 1684static const char* cpu_regs[8] = { 1685 "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" 1686}; 1687 1688 1689static const char* byte_cpu_regs[8] = { 1690 "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" 1691}; 1692 1693 1694static const char* xmm_regs[8] = { 1695 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" 1696}; 1697 1698 1699const char* NameConverter::NameOfAddress(byte* addr) const { 1700 v8::internal::SNPrintF(tmp_buffer_, "%p", addr); 1701 return tmp_buffer_.start(); 1702} 1703 1704 1705const char* NameConverter::NameOfConstant(byte* addr) const { 1706 return NameOfAddress(addr); 1707} 1708 1709 1710const char* NameConverter::NameOfCPURegister(int reg) const { 1711 if (0 <= reg && reg < 8) return cpu_regs[reg]; 1712 return "noreg"; 1713} 1714 1715 1716const char* NameConverter::NameOfByteCPURegister(int reg) const { 1717 if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; 1718 return "noreg"; 1719} 1720 1721 1722const char* NameConverter::NameOfXMMRegister(int reg) const { 1723 if (0 <= reg && reg < 8) return xmm_regs[reg]; 1724 return "noxmmreg"; 1725} 1726 1727 1728const char* NameConverter::NameInCode(byte* addr) const { 1729 // IA32 does not embed debug strings at the moment. 1730 UNREACHABLE(); 1731 return ""; 1732} 1733 1734 1735//------------------------------------------------------------------------------ 1736 1737Disassembler::Disassembler(const NameConverter& converter) 1738 : converter_(converter) {} 1739 1740 1741Disassembler::~Disassembler() {} 1742 1743 1744int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 1745 byte* instruction) { 1746 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/); 1747 return d.InstructionDecode(buffer, instruction); 1748} 1749 1750 1751// The IA-32 assembler does not currently use constant pools. 1752int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } 1753 1754 1755/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { 1756 NameConverter converter; 1757 Disassembler d(converter); 1758 for (byte* pc = begin; pc < end;) { 1759 v8::internal::EmbeddedVector<char, 128> buffer; 1760 buffer[0] = '\0'; 1761 byte* prev_pc = pc; 1762 pc += d.InstructionDecode(buffer, pc); 1763 fprintf(f, "%p", prev_pc); 1764 fprintf(f, " "); 1765 1766 for (byte* bp = prev_pc; bp < pc; bp++) { 1767 fprintf(f, "%02x", *bp); 1768 } 1769 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { 1770 fprintf(f, " "); 1771 } 1772 fprintf(f, " %s\n", buffer.start()); 1773 } 1774} 1775 1776 1777} // namespace disasm 1778 1779#endif // V8_TARGET_ARCH_IA32 1780