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