📄 disasm-ia32.cc.svn-base
字号:
// 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}, {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"};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(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* 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; } int PrintRightOperand(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 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;}// Returns number of bytes used including the current *modrmp.// Writes instruction's right operand to 'tmp_buffer_'.int DisassemblerIA32::PrintRightOperand(byte* modrmp) { 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]", NameOfCPURegister(rm)); return 2; } else if (base == ebp) { int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); AppendToBuffer("[%s*%d+0x%x]", NameOfCPURegister(index), 1 << scale, disp); return 6; } else if (index != esp && base != ebp) { // [base+index*scale] AppendToBuffer("[%s+%s*%d]", NameOfCPURegister(base), NameOfCPURegister(index), 1 << scale); return 2; } else { UnimplementedInstruction(); return 1; } } else { AppendToBuffer("[%s]", NameOfCPURegister(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]", NameOfCPURegister(rm), disp); } else { AppendToBuffer("[%s+%s*%d+0x%x]", NameOfCPURegister(base), NameOfCPURegister(index), 1 << scale, disp); } return mod == 2 ? 6 : 3; } else { // No sib. int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -