diff options
Diffstat (limited to 'V8Binding/v8/src/ia32/disasm-ia32.cc')
-rw-r--r-- | V8Binding/v8/src/ia32/disasm-ia32.cc | 1202 |
1 files changed, 0 insertions, 1202 deletions
diff --git a/V8Binding/v8/src/ia32/disasm-ia32.cc b/V8Binding/v8/src/ia32/disasm-ia32.cc deleted file mode 100644 index 458844e..0000000 --- a/V8Binding/v8/src/ia32/disasm-ia32.cc +++ /dev/null @@ -1,1202 +0,0 @@ -// Copyright 2007-2008 the V8 project authors. All rights reserved. -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following -// disclaimer in the documentation and/or other materials provided -// with the distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived -// from this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include <assert.h> -#include <stdio.h> -#include <stdarg.h> - -#include "v8.h" -#include "disasm.h" - -namespace disasm { - -enum OperandOrder { - UNSET_OP_ORDER = 0, - REG_OPER_OP_ORDER, - OPER_REG_OP_ORDER -}; - - -//------------------------------------------------------------------ -// Tables -//------------------------------------------------------------------ -struct ByteMnemonic { - int b; // -1 terminates, otherwise must be in range (0..255) - const char* mnem; - OperandOrder op_order_; -}; - - -static ByteMnemonic two_operands_instr[] = { - {0x03, "add", REG_OPER_OP_ORDER}, - {0x21, "and", OPER_REG_OP_ORDER}, - {0x23, "and", REG_OPER_OP_ORDER}, - {0x3B, "cmp", REG_OPER_OP_ORDER}, - {0x8D, "lea", REG_OPER_OP_ORDER}, - {0x09, "or", OPER_REG_OP_ORDER}, - {0x0B, "or", REG_OPER_OP_ORDER}, - {0x1B, "sbb", REG_OPER_OP_ORDER}, - {0x29, "sub", OPER_REG_OP_ORDER}, - {0x2B, "sub", REG_OPER_OP_ORDER}, - {0x85, "test", REG_OPER_OP_ORDER}, - {0x31, "xor", OPER_REG_OP_ORDER}, - {0x33, "xor", REG_OPER_OP_ORDER}, - {0x87, "xchg", REG_OPER_OP_ORDER}, - {0x8A, "mov_b", REG_OPER_OP_ORDER}, - {0x8B, "mov", REG_OPER_OP_ORDER}, - {-1, "", UNSET_OP_ORDER} -}; - - -static ByteMnemonic zero_operands_instr[] = { - {0xC3, "ret", UNSET_OP_ORDER}, - {0xC9, "leave", UNSET_OP_ORDER}, - {0x90, "nop", UNSET_OP_ORDER}, - {0xF4, "hlt", UNSET_OP_ORDER}, - {0xCC, "int3", UNSET_OP_ORDER}, - {0x60, "pushad", UNSET_OP_ORDER}, - {0x61, "popad", UNSET_OP_ORDER}, - {0x9C, "pushfd", UNSET_OP_ORDER}, - {0x9D, "popfd", UNSET_OP_ORDER}, - {0x9E, "sahf", UNSET_OP_ORDER}, - {0x99, "cdq", UNSET_OP_ORDER}, - {0x9B, "fwait", UNSET_OP_ORDER}, - {-1, "", UNSET_OP_ORDER} -}; - - -static ByteMnemonic call_jump_instr[] = { - {0xE8, "call", UNSET_OP_ORDER}, - {0xE9, "jmp", UNSET_OP_ORDER}, - {-1, "", UNSET_OP_ORDER} -}; - - -static ByteMnemonic short_immediate_instr[] = { - {0x05, "add", UNSET_OP_ORDER}, - {0x0D, "or", UNSET_OP_ORDER}, - {0x15, "adc", UNSET_OP_ORDER}, - {0x25, "and", UNSET_OP_ORDER}, - {0x2D, "sub", UNSET_OP_ORDER}, - {0x35, "xor", UNSET_OP_ORDER}, - {0x3D, "cmp", UNSET_OP_ORDER}, - {-1, "", UNSET_OP_ORDER} -}; - - -static const char* jump_conditional_mnem[] = { - /*0*/ "jo", "jno", "jc", "jnc", - /*4*/ "jz", "jnz", "jna", "ja", - /*8*/ "js", "jns", "jpe", "jpo", - /*12*/ "jl", "jnl", "jng", "jg" -}; - - -static const char* set_conditional_mnem[] = { - /*0*/ "seto", "setno", "setc", "setnc", - /*4*/ "setz", "setnz", "setna", "seta", - /*8*/ "sets", "setns", "setpe", "setpo", - /*12*/ "setl", "setnl", "setng", "setg" -}; - - -enum InstructionType { - NO_INSTR, - ZERO_OPERANDS_INSTR, - TWO_OPERANDS_INSTR, - JUMP_CONDITIONAL_SHORT_INSTR, - REGISTER_INSTR, - MOVE_REG_INSTR, - CALL_JUMP_INSTR, - SHORT_IMMEDIATE_INSTR -}; - - -struct InstructionDesc { - const char* mnem; - InstructionType type; - OperandOrder op_order_; -}; - - -class InstructionTable { - public: - InstructionTable(); - const InstructionDesc& Get(byte x) const { return instructions_[x]; } - - private: - InstructionDesc instructions_[256]; - void Clear(); - void Init(); - void CopyTable(ByteMnemonic bm[], InstructionType type); - void SetTableRange(InstructionType type, - byte start, - byte end, - const char* mnem); - void AddJumpConditionalShort(); -}; - - -InstructionTable::InstructionTable() { - Clear(); - Init(); -} - - -void InstructionTable::Clear() { - for (int i = 0; i < 256; i++) { - instructions_[i].mnem = ""; - instructions_[i].type = NO_INSTR; - instructions_[i].op_order_ = UNSET_OP_ORDER; - } -} - - -void InstructionTable::Init() { - CopyTable(two_operands_instr, TWO_OPERANDS_INSTR); - CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR); - CopyTable(call_jump_instr, CALL_JUMP_INSTR); - CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR); - AddJumpConditionalShort(); - SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc"); - SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec"); - SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push"); - SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop"); - SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop. - SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov"); -} - - -void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) { - for (int i = 0; bm[i].b >= 0; i++) { - InstructionDesc* id = &instructions_[bm[i].b]; - id->mnem = bm[i].mnem; - id->op_order_ = bm[i].op_order_; - assert(id->type == NO_INSTR); // Information already entered - id->type = type; - } -} - - -void InstructionTable::SetTableRange(InstructionType type, - byte start, - byte end, - const char* mnem) { - for (byte b = start; b <= end; b++) { - InstructionDesc* id = &instructions_[b]; - assert(id->type == NO_INSTR); // Information already entered - id->mnem = mnem; - id->type = type; - } -} - - -void InstructionTable::AddJumpConditionalShort() { - for (byte b = 0x70; b <= 0x7F; b++) { - InstructionDesc* id = &instructions_[b]; - assert(id->type == NO_INSTR); // Information already entered - id->mnem = jump_conditional_mnem[b & 0x0F]; - id->type = JUMP_CONDITIONAL_SHORT_INSTR; - } -} - - -static InstructionTable instruction_table; - - -// The IA32 disassembler implementation. -class DisassemblerIA32 { - public: - DisassemblerIA32(const NameConverter& converter, - bool abort_on_unimplemented = true) - : converter_(converter), - tmp_buffer_pos_(0), - abort_on_unimplemented_(abort_on_unimplemented) { - tmp_buffer_[0] = '\0'; - } - - virtual ~DisassemblerIA32() {} - - // Writes one disassembled instruction into 'buffer' (0-terminated). - // Returns the length of the disassembled machine instruction in bytes. - int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); - - private: - const NameConverter& converter_; - v8::internal::EmbeddedVector<char, 128> tmp_buffer_; - unsigned int tmp_buffer_pos_; - bool abort_on_unimplemented_; - - - enum { - eax = 0, - ecx = 1, - edx = 2, - ebx = 3, - esp = 4, - ebp = 5, - esi = 6, - edi = 7 - }; - - - const char* NameOfCPURegister(int reg) const { - return converter_.NameOfCPURegister(reg); - } - - - const char* NameOfByteCPURegister(int reg) const { - return converter_.NameOfByteCPURegister(reg); - } - - - const char* NameOfXMMRegister(int reg) const { - return converter_.NameOfXMMRegister(reg); - } - - - const char* NameOfAddress(byte* addr) const { - return converter_.NameOfAddress(addr); - } - - - // Disassembler helper functions. - static void get_modrm(byte data, int* mod, int* regop, int* rm) { - *mod = (data >> 6) & 3; - *regop = (data & 0x38) >> 3; - *rm = data & 7; - } - - - static void get_sib(byte data, int* scale, int* index, int* base) { - *scale = (data >> 6) & 3; - *index = (data >> 3) & 7; - *base = data & 7; - } - - typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const; - - int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); - int PrintRightOperand(byte* modrmp); - int PrintRightByteOperand(byte* modrmp); - int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); - int PrintImmediateOp(byte* data); - int F7Instruction(byte* data); - int D1D3C1Instruction(byte* data); - int JumpShort(byte* data); - int JumpConditional(byte* data, const char* comment); - int JumpConditionalShort(byte* data, const char* comment); - int SetCC(byte* data); - int FPUInstruction(byte* data); - void AppendToBuffer(const char* format, ...); - - - void UnimplementedInstruction() { - if (abort_on_unimplemented_) { - UNIMPLEMENTED(); - } else { - AppendToBuffer("'Unimplemented Instruction'"); - } - } -}; - - -void DisassemblerIA32::AppendToBuffer(const char* format, ...) { - v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; - va_list args; - va_start(args, format); - int result = v8::internal::OS::VSNPrintF(buf, format, args); - va_end(args); - tmp_buffer_pos_ += result; -} - -int DisassemblerIA32::PrintRightOperandHelper( - byte* modrmp, - RegisterNameMapping register_name) { - int mod, regop, rm; - get_modrm(*modrmp, &mod, ®op, &rm); - switch (mod) { - case 0: - if (rm == ebp) { - int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); - AppendToBuffer("[0x%x]", disp); - return 5; - } else if (rm == esp) { - byte sib = *(modrmp + 1); - int scale, index, base; - get_sib(sib, &scale, &index, &base); - if (index == esp && base == esp && scale == 0 /*times_1*/) { - AppendToBuffer("[%s]", (this->*register_name)(rm)); - return 2; - } else if (base == ebp) { - int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); - AppendToBuffer("[%s*%d+0x%x]", - (this->*register_name)(index), - 1 << scale, - disp); - return 6; - } else if (index != esp && base != ebp) { - // [base+index*scale] - AppendToBuffer("[%s+%s*%d]", - (this->*register_name)(base), - (this->*register_name)(index), - 1 << scale); - return 2; - } else { - UnimplementedInstruction(); - return 1; - } - } else { - AppendToBuffer("[%s]", (this->*register_name)(rm)); - return 1; - } - break; - case 1: // fall through - case 2: - if (rm == esp) { - byte sib = *(modrmp + 1); - int scale, index, base; - get_sib(sib, &scale, &index, &base); - int disp = - mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2); - if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) { - AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); - } else { - AppendToBuffer("[%s+%s*%d+0x%x]", - (this->*register_name)(base), - (this->*register_name)(index), - 1 << scale, - disp); - } - return mod == 2 ? 6 : 3; - } else { - // No sib. - int disp = - mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1); - AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp); - return mod == 2 ? 5 : 2; - } - break; - case 3: - AppendToBuffer("%s", (this->*register_name)(rm)); - return 1; - default: - UnimplementedInstruction(); - return 1; - } - UNREACHABLE(); -} - - -int DisassemblerIA32::PrintRightOperand(byte* modrmp) { - return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); -} - - -int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { - return PrintRightOperandHelper(modrmp, - &DisassemblerIA32::NameOfByteCPURegister); -} - - -// Returns number of bytes used including the current *data. -// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. -int DisassemblerIA32::PrintOperands(const char* mnem, - OperandOrder op_order, - byte* data) { - byte modrm = *data; - int mod, regop, rm; - get_modrm(modrm, &mod, ®op, &rm); - int advance = 0; - switch (op_order) { - case REG_OPER_OP_ORDER: { - AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); - advance = PrintRightOperand(data); - break; - } - case OPER_REG_OP_ORDER: { - AppendToBuffer("%s ", mnem); - advance = PrintRightOperand(data); - AppendToBuffer(",%s", NameOfCPURegister(regop)); - break; - } - default: - UNREACHABLE(); - break; - } - return advance; -} - - -// Returns number of bytes used by machine instruction, including *data byte. -// Writes immediate instructions to 'tmp_buffer_'. -int DisassemblerIA32::PrintImmediateOp(byte* data) { - bool sign_extension_bit = (*data & 0x02) != 0; - byte modrm = *(data+1); - int mod, regop, rm; - get_modrm(modrm, &mod, ®op, &rm); - const char* mnem = "Imm???"; - switch (regop) { - case 0: mnem = "add"; break; - case 1: mnem = "or"; break; - case 2: mnem = "adc"; break; - case 4: mnem = "and"; break; - case 5: mnem = "sub"; break; - case 6: mnem = "xor"; break; - case 7: mnem = "cmp"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data+1); - if (sign_extension_bit) { - AppendToBuffer(",0x%x", *(data + 1 + count)); - return 1 + count + 1 /*int8*/; - } else { - AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); - return 1 + count + 4 /*int32_t*/; - } -} - - -// Returns number of bytes used, including *data. -int DisassemblerIA32::F7Instruction(byte* data) { - assert(*data == 0xF7); - byte modrm = *(data+1); - int mod, regop, rm; - get_modrm(modrm, &mod, ®op, &rm); - if (mod == 3 && regop != 0) { - const char* mnem = NULL; - switch (regop) { - case 2: mnem = "not"; break; - case 3: mnem = "neg"; break; - case 4: mnem = "mul"; break; - case 7: mnem = "idiv"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm)); - return 2; - } else if (mod == 3 && regop == eax) { - int32_t imm = *reinterpret_cast<int32_t*>(data+2); - AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm); - return 6; - } else if (regop == eax) { - AppendToBuffer("test "); - int count = PrintRightOperand(data+1); - int32_t imm = *reinterpret_cast<int32_t*>(data+1+count); - AppendToBuffer(",0x%x", imm); - return 1+count+4 /*int32_t*/; - } else { - UnimplementedInstruction(); - return 2; - } -} - -int DisassemblerIA32::D1D3C1Instruction(byte* data) { - byte op = *data; - assert(op == 0xD1 || op == 0xD3 || op == 0xC1); - byte modrm = *(data+1); - int mod, regop, rm; - get_modrm(modrm, &mod, ®op, &rm); - int imm8 = -1; - int num_bytes = 2; - if (mod == 3) { - const char* mnem = NULL; - if (op == 0xD1) { - imm8 = 1; - switch (regop) { - case edx: mnem = "rcl"; break; - case edi: mnem = "sar"; break; - case esp: mnem = "shl"; break; - default: UnimplementedInstruction(); - } - } else if (op == 0xC1) { - imm8 = *(data+2); - num_bytes = 3; - switch (regop) { - case edx: mnem = "rcl"; break; - case esp: mnem = "shl"; break; - case ebp: mnem = "shr"; break; - case edi: mnem = "sar"; break; - default: UnimplementedInstruction(); - } - } else if (op == 0xD3) { - switch (regop) { - case esp: mnem = "shl"; break; - case ebp: mnem = "shr"; break; - case edi: mnem = "sar"; break; - default: UnimplementedInstruction(); - } - } - assert(mnem != NULL); - AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm)); - if (imm8 > 0) { - AppendToBuffer("%d", imm8); - } else { - AppendToBuffer("cl"); - } - } else { - UnimplementedInstruction(); - } - return num_bytes; -} - - -// Returns number of bytes used, including *data. -int DisassemblerIA32::JumpShort(byte* data) { - assert(*data == 0xEB); - byte b = *(data+1); - byte* dest = data + static_cast<int8_t>(b) + 2; - AppendToBuffer("jmp %s", NameOfAddress(dest)); - return 2; -} - - -// Returns number of bytes used, including *data. -int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { - assert(*data == 0x0F); - byte cond = *(data+1) & 0x0F; - byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; - const char* mnem = jump_conditional_mnem[cond]; - AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); - if (comment != NULL) { - AppendToBuffer(", %s", comment); - } - return 6; // includes 0x0F -} - - -// Returns number of bytes used, including *data. -int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { - byte cond = *data & 0x0F; - byte b = *(data+1); - byte* dest = data + static_cast<int8_t>(b) + 2; - const char* mnem = jump_conditional_mnem[cond]; - AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); - if (comment != NULL) { - AppendToBuffer(", %s", comment); - } - return 2; -} - - -// Returns number of bytes used, including *data. -int DisassemblerIA32::SetCC(byte* data) { - assert(*data == 0x0F); - byte cond = *(data+1) & 0x0F; - const char* mnem = set_conditional_mnem[cond]; - AppendToBuffer("%s ", mnem); - PrintRightByteOperand(data+2); - return 3; // includes 0x0F -} - - -// Returns number of bytes used, including *data. -int DisassemblerIA32::FPUInstruction(byte* data) { - byte b1 = *data; - byte b2 = *(data + 1); - if (b1 == 0xD9) { - const char* mnem = NULL; - switch (b2) { - case 0xE8: mnem = "fld1"; break; - case 0xEE: mnem = "fldz"; break; - case 0xE1: mnem = "fabs"; break; - case 0xE0: mnem = "fchs"; break; - case 0xF8: mnem = "fprem"; break; - case 0xF5: mnem = "fprem1"; break; - case 0xF7: mnem = "fincstp"; break; - case 0xE4: mnem = "ftst"; break; - } - if (mnem != NULL) { - AppendToBuffer("%s", mnem); - return 2; - } else if ((b2 & 0xF8) == 0xC8) { - AppendToBuffer("fxch st%d", b2 & 0x7); - return 2; - } else { - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case eax: mnem = "fld_s"; break; - case ebx: mnem = "fstp_s"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } - } else if (b1 == 0xDD) { - if ((b2 & 0xF8) == 0xC0) { - AppendToBuffer("ffree st%d", b2 & 0x7); - return 2; - } else { - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case eax: mnem = "fld_d"; break; - case ebx: mnem = "fstp_d"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } - } else if (b1 == 0xDB) { - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case eax: mnem = "fild_s"; break; - case edx: mnem = "fist_s"; break; - case ebx: mnem = "fistp_s"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } else if (b1 == 0xDF) { - if (b2 == 0xE0) { - AppendToBuffer("fnstsw_ax"); - return 2; - } - int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - const char* mnem = "?"; - switch (regop) { - case ebp: mnem = "fild_d"; break; - case edi: mnem = "fistp_d"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s ", mnem); - int count = PrintRightOperand(data + 1); - return count + 1; - } else if (b1 == 0xDC || b1 == 0xDE) { - bool is_pop = (b1 == 0xDE); - if (is_pop && b2 == 0xD9) { - AppendToBuffer("fcompp"); - return 2; - } - const char* mnem = "FP0xDC"; - switch (b2 & 0xF8) { - case 0xC0: mnem = "fadd"; break; - case 0xE8: mnem = "fsub"; break; - case 0xC8: mnem = "fmul"; break; - case 0xF8: mnem = "fdiv"; break; - default: UnimplementedInstruction(); - } - AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7); - return 2; - } else if (b1 == 0xDA && b2 == 0xE9) { - const char* mnem = "fucompp"; - AppendToBuffer("%s", mnem); - return 2; - } - AppendToBuffer("Unknown FP instruction"); - return 2; -} - - -// Mnemonics for instructions 0xF0 byte. -// Returns NULL if the instruction is not handled here. -static const char* F0Mnem(byte f0byte) { - switch (f0byte) { - case 0xA2: return "cpuid"; - case 0x31: return "rdtsc"; - case 0xBE: return "movsx_b"; - case 0xBF: return "movsx_w"; - case 0xB6: return "movzx_b"; - case 0xB7: return "movzx_w"; - case 0xAF: return "imul"; - case 0xA5: return "shld"; - case 0xAD: return "shrd"; - case 0xAB: return "bts"; - default: return NULL; - } -} - - -// Disassembled instruction '*instr' and writes it into 'out_buffer'. -int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, - byte* instr) { - tmp_buffer_pos_ = 0; // starting to write as position 0 - byte* data = instr; - // Check for hints. - const char* branch_hint = NULL; - // We use these two prefixes only with branch prediction - if (*data == 0x3E /*ds*/) { - branch_hint = "predicted taken"; - data++; - } else if (*data == 0x2E /*cs*/) { - branch_hint = "predicted not taken"; - data++; - } - bool processed = true; // Will be set to false if the current instruction - // is not in 'instructions' table. - const InstructionDesc& idesc = instruction_table.Get(*data); - switch (idesc.type) { - case ZERO_OPERANDS_INSTR: - AppendToBuffer(idesc.mnem); - data++; - break; - - case TWO_OPERANDS_INSTR: - data++; - data += PrintOperands(idesc.mnem, idesc.op_order_, data); - break; - - case JUMP_CONDITIONAL_SHORT_INSTR: - data += JumpConditionalShort(data, branch_hint); - break; - - case REGISTER_INSTR: - AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07)); - data++; - break; - - case MOVE_REG_INSTR: { - byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); - AppendToBuffer("mov %s,%s", - NameOfCPURegister(*data & 0x07), - NameOfAddress(addr)); - data += 5; - break; - } - - case CALL_JUMP_INSTR: { - byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5; - AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); - data += 5; - break; - } - - case SHORT_IMMEDIATE_INSTR: { - byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1)); - AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr)); - data += 5; - break; - } - - case NO_INSTR: - processed = false; - break; - - default: - UNIMPLEMENTED(); // This type is not implemented. - } - //---------------------------- - if (!processed) { - switch (*data) { - case 0xC2: - AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1)); - data += 3; - break; - - case 0x69: // fall through - case 0x6B: - { int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - int32_t imm = - *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2); - AppendToBuffer("imul %s,%s,0x%x", - NameOfCPURegister(regop), - NameOfCPURegister(rm), - imm); - data += 2 + (*data == 0x6B ? 1 : 4); - } - break; - - case 0xF6: - { int mod, regop, rm; - get_modrm(*(data+1), &mod, ®op, &rm); - if (mod == 3 && regop == eax) { - AppendToBuffer("test_b %s,%d", NameOfCPURegister(rm), *(data+2)); - } else { - UnimplementedInstruction(); - } - data += 3; - } - break; - - case 0x81: // fall through - case 0x83: // 0x81 with sign extension bit set - data += PrintImmediateOp(data); - break; - - case 0x0F: - { byte f0byte = *(data+1); - const char* f0mnem = F0Mnem(f0byte); - if (f0byte == 0xA2 || f0byte == 0x31) { - AppendToBuffer("%s", f0mnem); - data += 2; - } else if ((f0byte & 0xF0) == 0x80) { - data += JumpConditional(data, branch_hint); - } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || - f0byte == 0xB7 || f0byte == 0xAF) { - data += 2; - data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data); - } else if ((f0byte & 0xF0) == 0x90) { - data += SetCC(data); - } else { - data += 2; - if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) { - // shrd, shld, bts - AppendToBuffer("%s ", f0mnem); - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - data += PrintRightOperand(data); - if (f0byte == 0xAB) { - AppendToBuffer(",%s", NameOfCPURegister(regop)); - } else { - AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); - } - } else { - UnimplementedInstruction(); - } - } - } - break; - - case 0x8F: - { data++; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - if (regop == eax) { - AppendToBuffer("pop "); - data += PrintRightOperand(data); - } - } - break; - - case 0xFF: - { data++; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - const char* mnem = NULL; - switch (regop) { - case esi: mnem = "push"; break; - case eax: mnem = "inc"; break; - case ecx: mnem = "dec"; break; - case edx: mnem = "call"; break; - case esp: mnem = "jmp"; break; - default: mnem = "???"; - } - AppendToBuffer("%s ", mnem); - data += PrintRightOperand(data); - } - break; - - case 0xC7: // imm32, fall through - case 0xC6: // imm8 - { bool is_byte = *data == 0xC6; - data++; - AppendToBuffer("%s ", is_byte ? "mov_b" : "mov"); - data += PrintRightOperand(data); - int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data); - AppendToBuffer(",0x%x", imm); - data += is_byte ? 1 : 4; - } - break; - - case 0x80: - { data++; - AppendToBuffer("%s ", "cmpb"); - data += PrintRightOperand(data); - int32_t imm = *data; - AppendToBuffer(",0x%x", imm); - data++; - } - break; - - case 0x88: // 8bit, fall through - case 0x89: // 32bit - { bool is_byte = *data == 0x88; - int mod, regop, rm; - data++; - get_modrm(*data, &mod, ®op, &rm); - AppendToBuffer("%s ", is_byte ? "mov_b" : "mov"); - data += PrintRightOperand(data); - AppendToBuffer(",%s", NameOfCPURegister(regop)); - } - break; - - case 0x66: // prefix - data++; - if (*data == 0x8B) { - data++; - data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data); - } else if (*data == 0x89) { - data++; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - AppendToBuffer("mov_w "); - data += PrintRightOperand(data); - AppendToBuffer(",%s", NameOfCPURegister(regop)); - } else { - UnimplementedInstruction(); - } - break; - - case 0xFE: - { data++; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - if (mod == 3 && regop == ecx) { - AppendToBuffer("dec_b %s", NameOfCPURegister(rm)); - } else { - UnimplementedInstruction(); - } - data++; - } - break; - - case 0x68: - AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1)); - data += 5; - break; - - case 0x6A: - AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); - data += 2; - break; - - case 0xA8: - AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1)); - data += 2; - break; - - case 0xA9: - AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1)); - data += 5; - break; - - case 0xD1: // fall through - case 0xD3: // fall through - case 0xC1: - data += D1D3C1Instruction(data); - break; - - case 0xD9: // fall through - case 0xDA: // fall through - case 0xDB: // fall through - case 0xDC: // fall through - case 0xDD: // fall through - case 0xDE: // fall through - case 0xDF: - data += FPUInstruction(data); - break; - - case 0xEB: - data += JumpShort(data); - break; - - case 0xF2: - if (*(data+1) == 0x0F) { - byte b2 = *(data+2); - if (b2 == 0x11) { - AppendToBuffer("movsd "); - data += 3; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - data += PrintRightOperand(data); - AppendToBuffer(",%s", NameOfXMMRegister(regop)); - } else if (b2 == 0x10) { - data += 3; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - AppendToBuffer("movsd %s,", NameOfXMMRegister(regop)); - data += PrintRightOperand(data); - } else { - const char* mnem = "?"; - switch (b2) { - case 0x2A: mnem = "cvtsi2sd"; break; - case 0x58: mnem = "addsd"; break; - case 0x59: mnem = "mulsd"; break; - case 0x5C: mnem = "subsd"; break; - case 0x5E: mnem = "divsd"; break; - } - data += 3; - int mod, regop, rm; - get_modrm(*data, &mod, ®op, &rm); - if (b2 == 0x2A) { - AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop)); - data += PrintRightOperand(data); - } else { - AppendToBuffer("%s %s,%s", - mnem, - NameOfXMMRegister(regop), - NameOfXMMRegister(rm)); - data++; - } - } - } else { - UnimplementedInstruction(); - } - break; - - case 0xF3: - if (*(data+1) == 0x0F && *(data+2) == 0x2C) { - data += 3; - data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data); - } else { - UnimplementedInstruction(); - } - break; - - case 0xF7: - data += F7Instruction(data); - break; - - default: - UnimplementedInstruction(); - } - } - - if (tmp_buffer_pos_ < sizeof tmp_buffer_) { - tmp_buffer_[tmp_buffer_pos_] = '\0'; - } - - int instr_len = data - instr; - ASSERT(instr_len > 0); // Ensure progress. - - int outp = 0; - // Instruction bytes. - for (byte* bp = instr; bp < data; bp++) { - outp += v8::internal::OS::SNPrintF(out_buffer + outp, - "%02x", - *bp); - } - for (int i = 6 - instr_len; i >= 0; i--) { - outp += v8::internal::OS::SNPrintF(out_buffer + outp, - " "); - } - - outp += v8::internal::OS::SNPrintF(out_buffer + outp, - " %s", - tmp_buffer_.start()); - return instr_len; -} - - -//------------------------------------------------------------------------------ - - -static const char* cpu_regs[8] = { - "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi" -}; - - -static const char* byte_cpu_regs[8] = { - "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh" -}; - - -static const char* xmm_regs[8] = { - "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7" -}; - - -const char* NameConverter::NameOfAddress(byte* addr) const { - static v8::internal::EmbeddedVector<char, 32> tmp_buffer; - v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr); - return tmp_buffer.start(); -} - - -const char* NameConverter::NameOfConstant(byte* addr) const { - return NameOfAddress(addr); -} - - -const char* NameConverter::NameOfCPURegister(int reg) const { - if (0 <= reg && reg < 8) return cpu_regs[reg]; - return "noreg"; -} - - -const char* NameConverter::NameOfByteCPURegister(int reg) const { - if (0 <= reg && reg < 8) return byte_cpu_regs[reg]; - return "noreg"; -} - - -const char* NameConverter::NameOfXMMRegister(int reg) const { - if (0 <= reg && reg < 8) return xmm_regs[reg]; - return "noxmmreg"; -} - - -const char* NameConverter::NameInCode(byte* addr) const { - // IA32 does not embed debug strings at the moment. - UNREACHABLE(); - return ""; -} - - -//------------------------------------------------------------------------------ - -Disassembler::Disassembler(const NameConverter& converter) - : converter_(converter) {} - - -Disassembler::~Disassembler() {} - - -int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, - byte* instruction) { - DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/); - return d.InstructionDecode(buffer, instruction); -} - - -// The IA-32 assembler does not currently use constant pools. -int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } - - -/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { - NameConverter converter; - Disassembler d(converter); - for (byte* pc = begin; pc < end;) { - v8::internal::EmbeddedVector<char, 128> buffer; - buffer[0] = '\0'; - byte* prev_pc = pc; - pc += d.InstructionDecode(buffer, pc); - fprintf(f, "%p", prev_pc); - fprintf(f, " "); - - for (byte* bp = prev_pc; bp < pc; bp++) { - fprintf(f, "%02x", *bp); - } - for (int i = 6 - (pc - prev_pc); i >= 0; i--) { - fprintf(f, " "); - } - fprintf(f, " %s\n", buffer.start()); - } -} - - -} // namespace disasm |