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