| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 325 | 325 |
| 326 virtual ~DisassemblerX64() { | 326 virtual ~DisassemblerX64() { |
| 327 } | 327 } |
| 328 | 328 |
| 329 // Writes one disassembled instruction into 'buffer' (0-terminated). | 329 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 330 // Returns the length of the disassembled machine instruction in bytes. | 330 // Returns the length of the disassembled machine instruction in bytes. |
| 331 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 331 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
| 332 | 332 |
| 333 private: | 333 private: |
| 334 enum OperandSize { | 334 enum OperandSize { |
| 335 BYTE_SIZE = 0, | 335 OPERAND_BYTE_SIZE = 0, |
| 336 WORD_SIZE = 1, | 336 OPERAND_WORD_SIZE = 1, |
| 337 DOUBLEWORD_SIZE = 2, | 337 OPERAND_DOUBLEWORD_SIZE = 2, |
| 338 QUADWORD_SIZE = 3 | 338 OPERAND_QUADWORD_SIZE = 3 |
| 339 }; | 339 }; |
| 340 | 340 |
| 341 const NameConverter& converter_; | 341 const NameConverter& converter_; |
| 342 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 342 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
| 343 unsigned int tmp_buffer_pos_; | 343 unsigned int tmp_buffer_pos_; |
| 344 bool abort_on_unimplemented_; | 344 bool abort_on_unimplemented_; |
| 345 // Prefixes parsed | 345 // Prefixes parsed |
| 346 byte rex_; | 346 byte rex_; |
| 347 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. | 347 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
| 348 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. | 348 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
| (...skipping 13 matching lines...) Expand all Loading... |
| 362 // Actual number of base register given the low bits and the rex.b state. | 362 // Actual number of base register given the low bits and the rex.b state. |
| 363 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } | 363 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); } |
| 364 | 364 |
| 365 bool rex_x() { return (rex_ & 0x02) != 0; } | 365 bool rex_x() { return (rex_ & 0x02) != 0; } |
| 366 | 366 |
| 367 bool rex_r() { return (rex_ & 0x04) != 0; } | 367 bool rex_r() { return (rex_ & 0x04) != 0; } |
| 368 | 368 |
| 369 bool rex_w() { return (rex_ & 0x08) != 0; } | 369 bool rex_w() { return (rex_ & 0x08) != 0; } |
| 370 | 370 |
| 371 OperandSize operand_size() { | 371 OperandSize operand_size() { |
| 372 if (byte_size_operand_) return BYTE_SIZE; | 372 if (byte_size_operand_) return OPERAND_BYTE_SIZE; |
| 373 if (rex_w()) return QUADWORD_SIZE; | 373 if (rex_w()) return OPERAND_QUADWORD_SIZE; |
| 374 if (operand_size_ != 0) return WORD_SIZE; | 374 if (operand_size_ != 0) return OPERAND_WORD_SIZE; |
| 375 return DOUBLEWORD_SIZE; | 375 return OPERAND_DOUBLEWORD_SIZE; |
| 376 } | 376 } |
| 377 | 377 |
| 378 char operand_size_code() { | 378 char operand_size_code() { |
| 379 return "bwlq"[operand_size()]; | 379 return "bwlq"[operand_size()]; |
| 380 } | 380 } |
| 381 | 381 |
| 382 const char* NameOfCPURegister(int reg) const { | 382 const char* NameOfCPURegister(int reg) const { |
| 383 return converter_.NameOfCPURegister(reg); | 383 return converter_.NameOfCPURegister(reg); |
| 384 } | 384 } |
| 385 | 385 |
| (...skipping 169 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 555 return 1; | 555 return 1; |
| 556 } | 556 } |
| 557 UNREACHABLE(); | 557 UNREACHABLE(); |
| 558 } | 558 } |
| 559 | 559 |
| 560 | 560 |
| 561 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) { | 561 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) { |
| 562 int64_t value; | 562 int64_t value; |
| 563 int count; | 563 int count; |
| 564 switch (size) { | 564 switch (size) { |
| 565 case BYTE_SIZE: | 565 case OPERAND_BYTE_SIZE: |
| 566 value = *data; | 566 value = *data; |
| 567 count = 1; | 567 count = 1; |
| 568 break; | 568 break; |
| 569 case WORD_SIZE: | 569 case OPERAND_WORD_SIZE: |
| 570 value = *reinterpret_cast<int16_t*>(data); | 570 value = *reinterpret_cast<int16_t*>(data); |
| 571 count = 2; | 571 count = 2; |
| 572 break; | 572 break; |
| 573 case DOUBLEWORD_SIZE: | 573 case OPERAND_DOUBLEWORD_SIZE: |
| 574 value = *reinterpret_cast<uint32_t*>(data); | 574 value = *reinterpret_cast<uint32_t*>(data); |
| 575 count = 4; | 575 count = 4; |
| 576 break; | 576 break; |
| 577 case QUADWORD_SIZE: | 577 case OPERAND_QUADWORD_SIZE: |
| 578 value = *reinterpret_cast<int32_t*>(data); | 578 value = *reinterpret_cast<int32_t*>(data); |
| 579 count = 4; | 579 count = 4; |
| 580 break; | 580 break; |
| 581 default: | 581 default: |
| 582 UNREACHABLE(); | 582 UNREACHABLE(); |
| 583 value = 0; // Initialize variables on all paths to satisfy the compiler. | 583 value = 0; // Initialize variables on all paths to satisfy the compiler. |
| 584 count = 0; | 584 count = 0; |
| 585 } | 585 } |
| 586 AppendToBuffer("%" V8_PTR_PREFIX "x", value); | 586 AppendToBuffer("%" V8_PTR_PREFIX "x", value); |
| 587 return count; | 587 return count; |
| (...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 675 break; | 675 break; |
| 676 case 7: | 676 case 7: |
| 677 mnem = "cmp"; | 677 mnem = "cmp"; |
| 678 break; | 678 break; |
| 679 default: | 679 default: |
| 680 UnimplementedInstruction(); | 680 UnimplementedInstruction(); |
| 681 } | 681 } |
| 682 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 682 AppendToBuffer("%s%c ", mnem, operand_size_code()); |
| 683 int count = PrintRightOperand(data + 1); | 683 int count = PrintRightOperand(data + 1); |
| 684 AppendToBuffer(",0x"); | 684 AppendToBuffer(",0x"); |
| 685 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); | 685 OperandSize immediate_size = |
| 686 byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size(); |
| 686 count += PrintImmediate(data + 1 + count, immediate_size); | 687 count += PrintImmediate(data + 1 + count, immediate_size); |
| 687 return 1 + count; | 688 return 1 + count; |
| 688 } | 689 } |
| 689 | 690 |
| 690 | 691 |
| 691 // Returns number of bytes used, including *data. | 692 // Returns number of bytes used, including *data. |
| 692 int DisassemblerX64::F6F7Instruction(byte* data) { | 693 int DisassemblerX64::F6F7Instruction(byte* data) { |
| 693 ASSERT(*data == 0xF7 || *data == 0xF6); | 694 ASSERT(*data == 0xF7 || *data == 0xF6); |
| 694 byte modrm = *(data + 1); | 695 byte modrm = *(data + 1); |
| 695 int mod, regop, rm; | 696 int mod, regop, rm; |
| (...skipping 712 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1408 break; | 1409 break; |
| 1409 case PUSHPOP_INSTR: | 1410 case PUSHPOP_INSTR: |
| 1410 AppendToBuffer("%s %s", | 1411 AppendToBuffer("%s %s", |
| 1411 idesc.mnem, | 1412 idesc.mnem, |
| 1412 NameOfCPURegister(base_reg(current & 0x07))); | 1413 NameOfCPURegister(base_reg(current & 0x07))); |
| 1413 data++; | 1414 data++; |
| 1414 break; | 1415 break; |
| 1415 case MOVE_REG_INSTR: { | 1416 case MOVE_REG_INSTR: { |
| 1416 byte* addr = NULL; | 1417 byte* addr = NULL; |
| 1417 switch (operand_size()) { | 1418 switch (operand_size()) { |
| 1418 case WORD_SIZE: | 1419 case OPERAND_WORD_SIZE: |
| 1419 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); | 1420 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); |
| 1420 data += 3; | 1421 data += 3; |
| 1421 break; | 1422 break; |
| 1422 case DOUBLEWORD_SIZE: | 1423 case OPERAND_DOUBLEWORD_SIZE: |
| 1423 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); | 1424 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); |
| 1424 data += 5; | 1425 data += 5; |
| 1425 break; | 1426 break; |
| 1426 case QUADWORD_SIZE: | 1427 case OPERAND_QUADWORD_SIZE: |
| 1427 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); | 1428 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); |
| 1428 data += 9; | 1429 data += 9; |
| 1429 break; | 1430 break; |
| 1430 default: | 1431 default: |
| 1431 UNREACHABLE(); | 1432 UNREACHABLE(); |
| 1432 } | 1433 } |
| 1433 AppendToBuffer("mov%c %s,%s", | 1434 AppendToBuffer("mov%c %s,%s", |
| 1434 operand_size_code(), | 1435 operand_size_code(), |
| 1435 NameOfCPURegister(base_reg(current & 0x07)), | 1436 NameOfCPURegister(base_reg(current & 0x07)), |
| 1436 NameOfAddress(addr)); | 1437 NameOfAddress(addr)); |
| (...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1621 case 0xBF: { | 1622 case 0xBF: { |
| 1622 // mov reg8,imm8 or mov reg32,imm32 | 1623 // mov reg8,imm8 or mov reg32,imm32 |
| 1623 byte opcode = *data; | 1624 byte opcode = *data; |
| 1624 data++; | 1625 data++; |
| 1625 bool is_32bit = (opcode >= 0xB8); | 1626 bool is_32bit = (opcode >= 0xB8); |
| 1626 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0); | 1627 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0); |
| 1627 if (is_32bit) { | 1628 if (is_32bit) { |
| 1628 AppendToBuffer("mov%c %s, ", | 1629 AppendToBuffer("mov%c %s, ", |
| 1629 operand_size_code(), | 1630 operand_size_code(), |
| 1630 NameOfCPURegister(reg)); | 1631 NameOfCPURegister(reg)); |
| 1631 data += PrintImmediate(data, DOUBLEWORD_SIZE); | 1632 data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE); |
| 1632 } else { | 1633 } else { |
| 1633 AppendToBuffer("movb %s, ", | 1634 AppendToBuffer("movb %s, ", |
| 1634 NameOfByteCPURegister(reg)); | 1635 NameOfByteCPURegister(reg)); |
| 1635 data += PrintImmediate(data, BYTE_SIZE); | 1636 data += PrintImmediate(data, OPERAND_BYTE_SIZE); |
| 1636 } | 1637 } |
| 1637 break; | 1638 break; |
| 1638 } | 1639 } |
| 1639 case 0xFE: { | 1640 case 0xFE: { |
| 1640 data++; | 1641 data++; |
| 1641 int mod, regop, rm; | 1642 int mod, regop, rm; |
| 1642 get_modrm(*data, &mod, ®op, &rm); | 1643 get_modrm(*data, &mod, ®op, &rm); |
| 1643 if (regop == 1) { | 1644 if (regop == 1) { |
| 1644 AppendToBuffer("decb "); | 1645 AppendToBuffer("decb "); |
| 1645 data += PrintRightByteOperand(data); | 1646 data += PrintRightByteOperand(data); |
| 1646 } else { | 1647 } else { |
| 1647 UnimplementedInstruction(); | 1648 UnimplementedInstruction(); |
| 1648 } | 1649 } |
| 1649 break; | 1650 break; |
| 1650 } | 1651 } |
| 1651 case 0x68: | 1652 case 0x68: |
| 1652 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1)); | 1653 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1)); |
| 1653 data += 5; | 1654 data += 5; |
| 1654 break; | 1655 break; |
| 1655 | 1656 |
| 1656 case 0x6A: | 1657 case 0x6A: |
| 1657 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); | 1658 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); |
| 1658 data += 2; | 1659 data += 2; |
| 1659 break; | 1660 break; |
| 1660 | 1661 |
| 1661 case 0xA1: // Fall through. | 1662 case 0xA1: // Fall through. |
| 1662 case 0xA3: | 1663 case 0xA3: |
| 1663 switch (operand_size()) { | 1664 switch (operand_size()) { |
| 1664 case DOUBLEWORD_SIZE: { | 1665 case OPERAND_DOUBLEWORD_SIZE: { |
| 1665 const char* memory_location = NameOfAddress( | 1666 const char* memory_location = NameOfAddress( |
| 1666 reinterpret_cast<byte*>( | 1667 reinterpret_cast<byte*>( |
| 1667 *reinterpret_cast<int32_t*>(data + 1))); | 1668 *reinterpret_cast<int32_t*>(data + 1))); |
| 1668 if (*data == 0xA1) { // Opcode 0xA1 | 1669 if (*data == 0xA1) { // Opcode 0xA1 |
| 1669 AppendToBuffer("movzxlq rax,(%s)", memory_location); | 1670 AppendToBuffer("movzxlq rax,(%s)", memory_location); |
| 1670 } else { // Opcode 0xA3 | 1671 } else { // Opcode 0xA3 |
| 1671 AppendToBuffer("movzxlq (%s),rax", memory_location); | 1672 AppendToBuffer("movzxlq (%s),rax", memory_location); |
| 1672 } | 1673 } |
| 1673 data += 5; | 1674 data += 5; |
| 1674 break; | 1675 break; |
| 1675 } | 1676 } |
| 1676 case QUADWORD_SIZE: { | 1677 case OPERAND_QUADWORD_SIZE: { |
| 1677 // New x64 instruction mov rax,(imm_64). | 1678 // New x64 instruction mov rax,(imm_64). |
| 1678 const char* memory_location = NameOfAddress( | 1679 const char* memory_location = NameOfAddress( |
| 1679 *reinterpret_cast<byte**>(data + 1)); | 1680 *reinterpret_cast<byte**>(data + 1)); |
| 1680 if (*data == 0xA1) { // Opcode 0xA1 | 1681 if (*data == 0xA1) { // Opcode 0xA1 |
| 1681 AppendToBuffer("movq rax,(%s)", memory_location); | 1682 AppendToBuffer("movq rax,(%s)", memory_location); |
| 1682 } else { // Opcode 0xA3 | 1683 } else { // Opcode 0xA3 |
| 1683 AppendToBuffer("movq (%s),rax", memory_location); | 1684 AppendToBuffer("movq (%s),rax", memory_location); |
| 1684 } | 1685 } |
| 1685 data += 9; | 1686 data += 9; |
| 1686 break; | 1687 break; |
| 1687 } | 1688 } |
| 1688 default: | 1689 default: |
| 1689 UnimplementedInstruction(); | 1690 UnimplementedInstruction(); |
| 1690 data += 2; | 1691 data += 2; |
| 1691 } | 1692 } |
| 1692 break; | 1693 break; |
| 1693 | 1694 |
| 1694 case 0xA8: | 1695 case 0xA8: |
| 1695 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); | 1696 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); |
| 1696 data += 2; | 1697 data += 2; |
| 1697 break; | 1698 break; |
| 1698 | 1699 |
| 1699 case 0xA9: { | 1700 case 0xA9: { |
| 1700 int64_t value = 0; | 1701 int64_t value = 0; |
| 1701 switch (operand_size()) { | 1702 switch (operand_size()) { |
| 1702 case WORD_SIZE: | 1703 case OPERAND_WORD_SIZE: |
| 1703 value = *reinterpret_cast<uint16_t*>(data + 1); | 1704 value = *reinterpret_cast<uint16_t*>(data + 1); |
| 1704 data += 3; | 1705 data += 3; |
| 1705 break; | 1706 break; |
| 1706 case DOUBLEWORD_SIZE: | 1707 case OPERAND_DOUBLEWORD_SIZE: |
| 1707 value = *reinterpret_cast<uint32_t*>(data + 1); | 1708 value = *reinterpret_cast<uint32_t*>(data + 1); |
| 1708 data += 5; | 1709 data += 5; |
| 1709 break; | 1710 break; |
| 1710 case QUADWORD_SIZE: | 1711 case OPERAND_QUADWORD_SIZE: |
| 1711 value = *reinterpret_cast<int32_t*>(data + 1); | 1712 value = *reinterpret_cast<int32_t*>(data + 1); |
| 1712 data += 5; | 1713 data += 5; |
| 1713 break; | 1714 break; |
| 1714 default: | 1715 default: |
| 1715 UNREACHABLE(); | 1716 UNREACHABLE(); |
| 1716 } | 1717 } |
| 1717 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x", | 1718 AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x", |
| 1718 operand_size_code(), | 1719 operand_size_code(), |
| 1719 value); | 1720 value); |
| 1720 break; | 1721 break; |
| (...skipping 161 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1882 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) { | 1883 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) { |
| 1883 fprintf(f, " "); | 1884 fprintf(f, " "); |
| 1884 } | 1885 } |
| 1885 fprintf(f, " %s\n", buffer.start()); | 1886 fprintf(f, " %s\n", buffer.start()); |
| 1886 } | 1887 } |
| 1887 } | 1888 } |
| 1888 | 1889 |
| 1889 } // namespace disasm | 1890 } // namespace disasm |
| 1890 | 1891 |
| 1891 #endif // V8_TARGET_ARCH_X64 | 1892 #endif // V8_TARGET_ARCH_X64 |
| OLD | NEW |