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