| Index: src/mips/disasm-mips.cc
|
| ===================================================================
|
| --- src/mips/disasm-mips.cc (revision 0)
|
| +++ src/mips/disasm-mips.cc (revision 0)
|
| @@ -0,0 +1,784 @@
|
| +// Copyright 2006-2010 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.
|
| +
|
| +// A Disassembler object is used to disassemble a block of code instruction by
|
| +// instruction. The default implementation of the NameConverter object can be
|
| +// overriden to modify register names or to do symbol lookup on addresses.
|
| +//
|
| +// The example below will disassemble a block of code and print it to stdout.
|
| +//
|
| +// NameConverter converter;
|
| +// Disassembler d(converter);
|
| +// for (byte_* pc = begin; pc < end;) {
|
| +// char buffer[128];
|
| +// buffer[0] = '\0';
|
| +// byte_* prev_pc = pc;
|
| +// pc += d.InstructionDecode(buffer, sizeof buffer, pc);
|
| +// printf("%p %08x %s\n",
|
| +// prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer);
|
| +// }
|
| +//
|
| +// The Disassembler class also has a convenience method to disassemble a block
|
| +// of code into a FILE*, meaning that the above functionality could also be
|
| +// achieved by just calling Disassembler::Disassemble(stdout, begin, end);
|
| +
|
| +
|
| +#include <assert.h>
|
| +#include <stdio.h>
|
| +#include <stdarg.h>
|
| +#include <string.h>
|
| +#ifndef WIN32
|
| +#include <stdint.h>
|
| +#endif
|
| +
|
| +#include "v8.h"
|
| +
|
| +#include "constants-mips.h"
|
| +#include "disasm.h"
|
| +#include "macro-assembler.h"
|
| +#include "platform.h"
|
| +
|
| +namespace assembler {
|
| +namespace mips {
|
| +
|
| +
|
| +namespace v8i = v8::internal;
|
| +
|
| +
|
| +//------------------------------------------------------------------------------
|
| +
|
| +// Decoder decodes and disassembles instructions into an output buffer.
|
| +// It uses the converter to convert register names and call destinations into
|
| +// more informative description.
|
| +class Decoder {
|
| + public:
|
| + Decoder(const disasm::NameConverter& converter,
|
| + v8::internal::Vector<char> out_buffer)
|
| + : converter_(converter),
|
| + out_buffer_(out_buffer),
|
| + out_buffer_pos_(0) {
|
| + out_buffer_[out_buffer_pos_] = '\0';
|
| + }
|
| +
|
| + ~Decoder() {}
|
| +
|
| + // Writes one disassembled instruction into 'buffer' (0-terminated).
|
| + // Returns the length of the disassembled machine instruction in bytes.
|
| + int InstructionDecode(byte_* instruction);
|
| +
|
| + private:
|
| + // Bottleneck functions to print into the out_buffer.
|
| + void PrintChar(const char ch);
|
| + void Print(const char* str);
|
| +
|
| + // Printing of common values.
|
| + void PrintRegister(int reg);
|
| + void PrintCRegister(int creg);
|
| + void PrintRs(Instruction* instr);
|
| + void PrintRt(Instruction* instr);
|
| + void PrintRd(Instruction* instr);
|
| + void PrintFs(Instruction* instr);
|
| + void PrintFt(Instruction* instr);
|
| + void PrintFd(Instruction* instr);
|
| + void PrintSa(Instruction* instr);
|
| + void PrintFunction(Instruction* instr);
|
| + void PrintSecondaryField(Instruction* instr);
|
| + void PrintUImm16(Instruction* instr);
|
| + void PrintSImm16(Instruction* instr);
|
| + void PrintXImm16(Instruction* instr);
|
| + void PrintImm26(Instruction* instr);
|
| + void PrintCode(Instruction* instr); // For break and trap instructions
|
| + // Printing of instruction name
|
| + void PrintInstructionName(Instruction* instr);
|
| +
|
| + // Handle formatting of instructions and their options.
|
| + int FormatRegister(Instruction* instr, const char* option);
|
| + int FormatCRegister(Instruction* instr, const char* option);
|
| + int FormatOption(Instruction* instr, const char* option);
|
| + void Format(Instruction* instr, const char* format);
|
| + void Unknown(Instruction* instr);
|
| +
|
| + // Each of these functions decodes one particular instruction type.
|
| + void DecodeTypeRegister(Instruction* instr);
|
| + void DecodeTypeImmediate(Instruction* instr);
|
| + void DecodeTypeJump(Instruction* instr);
|
| +
|
| + const disasm::NameConverter& converter_;
|
| + v8::internal::Vector<char> out_buffer_;
|
| + int out_buffer_pos_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(Decoder);
|
| +};
|
| +
|
| +
|
| +// Support for assertions in the Decoder formatting functions.
|
| +#define STRING_STARTS_WITH(string, compare_string) \
|
| + (strncmp(string, compare_string, strlen(compare_string)) == 0)
|
| +
|
| +
|
| +// Append the ch to the output buffer.
|
| +void Decoder::PrintChar(const char ch) {
|
| + out_buffer_[out_buffer_pos_++] = ch;
|
| +}
|
| +
|
| +
|
| +// Append the str to the output buffer.
|
| +void Decoder::Print(const char* str) {
|
| + char cur = *str++;
|
| + while (cur != '\0' && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
|
| + PrintChar(cur);
|
| + cur = *str++;
|
| + }
|
| + out_buffer_[out_buffer_pos_] = 0;
|
| +}
|
| +
|
| +
|
| +// Print the register name according to the active name converter.
|
| +void Decoder::PrintRegister(int reg) {
|
| + Print(converter_.NameOfCPURegister(reg));
|
| +}
|
| +
|
| +
|
| +void Decoder::PrintRs(Instruction* instr) {
|
| + int reg = instr->RsField();
|
| + PrintRegister(reg);
|
| +}
|
| +
|
| +
|
| +void Decoder::PrintRt(Instruction* instr) {
|
| + int reg = instr->RtField();
|
| + PrintRegister(reg);
|
| +}
|
| +
|
| +
|
| +void Decoder::PrintRd(Instruction* instr) {
|
| + int reg = instr->RdField();
|
| + PrintRegister(reg);
|
| +}
|
| +
|
| +
|
| +// Print the Cregister name according to the active name converter.
|
| +void Decoder::PrintCRegister(int creg) {
|
| + Print(converter_.NameOfXMMRegister(creg));
|
| +}
|
| +
|
| +
|
| +void Decoder::PrintFs(Instruction* instr) {
|
| + int creg = instr->RsField();
|
| + PrintCRegister(creg);
|
| +}
|
| +
|
| +
|
| +void Decoder::PrintFt(Instruction* instr) {
|
| + int creg = instr->RtField();
|
| + PrintCRegister(creg);
|
| +}
|
| +
|
| +
|
| +void Decoder::PrintFd(Instruction* instr) {
|
| + int creg = instr->RdField();
|
| + PrintCRegister(creg);
|
| +}
|
| +
|
| +
|
| +// Print the integer value of the sa field.
|
| +void Decoder::PrintSa(Instruction* instr) {
|
| + int sa = instr->SaField();
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "%d", sa);
|
| +}
|
| +
|
| +
|
| +// Print 16-bit unsigned immediate value.
|
| +void Decoder::PrintUImm16(Instruction* instr) {
|
| + int32_t imm = instr->Imm16Field();
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "%u", imm);
|
| +}
|
| +
|
| +
|
| +// Print 16-bit signed immediate value.
|
| +void Decoder::PrintSImm16(Instruction* instr) {
|
| + int32_t imm = ((instr->Imm16Field())<<16)>>16;
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "%d", imm);
|
| +}
|
| +
|
| +
|
| +// Print 16-bit hexa immediate value.
|
| +void Decoder::PrintXImm16(Instruction* instr) {
|
| + int32_t imm = instr->Imm16Field();
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "0x%x", imm);
|
| +}
|
| +
|
| +
|
| +// Print 26-bit immediate value.
|
| +void Decoder::PrintImm26(Instruction* instr) {
|
| + int32_t imm = instr->Imm26Field();
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "%d", imm);
|
| +}
|
| +
|
| +
|
| +// Print 26-bit immediate value.
|
| +void Decoder::PrintCode(Instruction* instr) {
|
| + if (instr->OpcodeFieldRaw() != SPECIAL)
|
| + return; // Not a break or trap instruction.
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case BREAK: {
|
| + int32_t code = instr->Bits(25, 6);
|
| + out_buffer_pos_ +=
|
| + v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%05x", code);
|
| + break;
|
| + }
|
| + case TGE:
|
| + case TGEU:
|
| + case TLT:
|
| + case TLTU:
|
| + case TEQ:
|
| + case TNE: {
|
| + int32_t code = instr->Bits(15, 6);
|
| + out_buffer_pos_ +=
|
| + v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_, "0x%03x", code);
|
| + break;
|
| + }
|
| + default: // Not a break or trap instruction.
|
| + break;
|
| + };
|
| +}
|
| +
|
| +
|
| +// Printing of instruction name
|
| +void Decoder::PrintInstructionName(Instruction* instr) {
|
| +}
|
| +
|
| +
|
| +// Handle all register based formatting in this function to reduce the
|
| +// complexity of FormatOption.
|
| +int Decoder::FormatRegister(Instruction* instr, const char* format) {
|
| + ASSERT(format[0] == 'r');
|
| + if (format[1] == 's') { // 'rs: Rs register
|
| + int reg = instr->RsField();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 't') { // 'rt: rt register
|
| + int reg = instr->RtField();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 'd') { // 'rd: rd register
|
| + int reg = instr->RdField();
|
| + PrintRegister(reg);
|
| + return 2;
|
| + }
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +// Handle all Cregister based formatting in this function to reduce the
|
| +// complexity of FormatOption.
|
| +int Decoder::FormatCRegister(Instruction* instr, const char* format) {
|
| + ASSERT(format[0] == 'f');
|
| + if (format[1] == 's') { // 'fs: fs register
|
| + int reg = instr->RsField();
|
| + PrintCRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 't') { // 'ft: ft register
|
| + int reg = instr->RtField();
|
| + PrintCRegister(reg);
|
| + return 2;
|
| + } else if (format[1] == 'd') { // 'fd: fd register
|
| + int reg = instr->RdField();
|
| + PrintCRegister(reg);
|
| + return 2;
|
| + }
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +// FormatOption takes a formatting string and interprets it based on
|
| +// the current instructions. The format string points to the first
|
| +// character of the option string (the option escape has already been
|
| +// consumed by the caller.) FormatOption returns the number of
|
| +// characters that were consumed from the formatting string.
|
| +int Decoder::FormatOption(Instruction* instr, const char* format) {
|
| + switch (format[0]) {
|
| + case 'c': { // 'code for break or trap instructions
|
| + ASSERT(STRING_STARTS_WITH(format, "code"));
|
| + PrintCode(instr);
|
| + return 4;
|
| + }
|
| + case 'i': { // 'imm16u or 'imm26
|
| + if (format[3] == '1') {
|
| + ASSERT(STRING_STARTS_WITH(format, "imm16"));
|
| + if (format[5] == 's') {
|
| + ASSERT(STRING_STARTS_WITH(format, "imm16s"));
|
| + PrintSImm16(instr);
|
| + } else if (format[5] == 'u') {
|
| + ASSERT(STRING_STARTS_WITH(format, "imm16u"));
|
| + PrintSImm16(instr);
|
| + } else {
|
| + ASSERT(STRING_STARTS_WITH(format, "imm16x"));
|
| + PrintXImm16(instr);
|
| + }
|
| + return 6;
|
| + } else {
|
| + ASSERT(STRING_STARTS_WITH(format, "imm26"));
|
| + PrintImm26(instr);
|
| + return 5;
|
| + }
|
| + }
|
| + case 'r': { // 'r: registers
|
| + return FormatRegister(instr, format);
|
| + }
|
| + case 'f': { // 'f: Cregisters
|
| + return FormatCRegister(instr, format);
|
| + }
|
| + case 's': { // 'sa
|
| + ASSERT(STRING_STARTS_WITH(format, "sa"));
|
| + PrintSa(instr);
|
| + return 2;
|
| + }
|
| + };
|
| + UNREACHABLE();
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +// Format takes a formatting string for a whole instruction and prints it into
|
| +// the output buffer. All escaped options are handed to FormatOption to be
|
| +// parsed further.
|
| +void Decoder::Format(Instruction* instr, const char* format) {
|
| + char cur = *format++;
|
| + while ((cur != 0) && (out_buffer_pos_ < (out_buffer_.length() - 1))) {
|
| + if (cur == '\'') { // Single quote is used as the formatting escape.
|
| + format += FormatOption(instr, format);
|
| + } else {
|
| + out_buffer_[out_buffer_pos_++] = cur;
|
| + }
|
| + cur = *format++;
|
| + }
|
| + out_buffer_[out_buffer_pos_] = '\0';
|
| +}
|
| +
|
| +
|
| +// For currently unimplemented decodings the disassembler calls Unknown(instr)
|
| +// which will just print "unknown" of the instruction bits.
|
| +void Decoder::Unknown(Instruction* instr) {
|
| + Format(instr, "unknown");
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeRegister(Instruction* instr) {
|
| + switch (instr->OpcodeFieldRaw()) {
|
| + case COP1: // Coprocessor instructions
|
| + switch (instr->RsFieldRaw()) {
|
| + case BC1: // branch on coprocessor condition
|
| + UNREACHABLE();
|
| + break;
|
| + case MFC1:
|
| + Format(instr, "mfc1 'rt, 'fs");
|
| + break;
|
| + case MFHC1:
|
| + Format(instr, "mfhc1 rt, 'fs");
|
| + break;
|
| + case MTC1:
|
| + Format(instr, "mtc1 'rt, 'fs");
|
| + break;
|
| + case MTHC1:
|
| + Format(instr, "mthc1 rt, 'fs");
|
| + break;
|
| + case S:
|
| + case D:
|
| + UNIMPLEMENTED_MIPS();
|
| + break;
|
| + case W:
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case CVT_S_W:
|
| + UNIMPLEMENTED_MIPS();
|
| + break;
|
| + case CVT_D_W: // Convert word to double.
|
| + Format(instr, "cvt.d.w 'fd, 'fs");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + };
|
| + break;
|
| + case L:
|
| + case PS:
|
| + UNIMPLEMENTED_MIPS();
|
| + break;
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + };
|
| + break;
|
| + case SPECIAL:
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case JR:
|
| + Format(instr, "jr 'rs");
|
| + break;
|
| + case JALR:
|
| + Format(instr, "jalr 'rs");
|
| + break;
|
| + case SLL:
|
| + if ( 0x0 == static_cast<int>(instr->InstructionBits()))
|
| + Format(instr, "nop");
|
| + else
|
| + Format(instr, "sll 'rd, 'rt, 'sa");
|
| + break;
|
| + case SRL:
|
| + Format(instr, "srl 'rd, 'rt, 'sa");
|
| + break;
|
| + case SRA:
|
| + Format(instr, "sra 'rd, 'rt, 'sa");
|
| + break;
|
| + case SLLV:
|
| + Format(instr, "sllv 'rd, 'rt, 'rs");
|
| + break;
|
| + case SRLV:
|
| + Format(instr, "srlv 'rd, 'rt, 'rs");
|
| + break;
|
| + case SRAV:
|
| + Format(instr, "srav 'rd, 'rt, 'rs");
|
| + break;
|
| + case MFHI:
|
| + Format(instr, "mfhi 'rd");
|
| + break;
|
| + case MFLO:
|
| + Format(instr, "mflo 'rd");
|
| + break;
|
| + case MULT:
|
| + Format(instr, "mult 'rs, 'rt");
|
| + break;
|
| + case MULTU:
|
| + Format(instr, "multu 'rs, 'rt");
|
| + break;
|
| + case DIV:
|
| + Format(instr, "div 'rs, 'rt");
|
| + break;
|
| + case DIVU:
|
| + Format(instr, "divu 'rs, 'rt");
|
| + break;
|
| + case ADD:
|
| + Format(instr, "add 'rd, 'rs, 'rt");
|
| + break;
|
| + case ADDU:
|
| + Format(instr, "addu 'rd, 'rs, 'rt");
|
| + break;
|
| + case SUB:
|
| + Format(instr, "sub 'rd, 'rs, 'rt");
|
| + break;
|
| + case SUBU:
|
| + Format(instr, "sub 'rd, 'rs, 'rt");
|
| + break;
|
| + case AND:
|
| + Format(instr, "and 'rd, 'rs, 'rt");
|
| + break;
|
| + case OR:
|
| + if (0 == instr->RsField()) {
|
| + Format(instr, "mov 'rd, 'rt");
|
| + } else if (0 == instr->RtField()) {
|
| + Format(instr, "mov 'rd, 'rs");
|
| + } else {
|
| + Format(instr, "or 'rd, 'rs, 'rt");
|
| + }
|
| + break;
|
| + case XOR:
|
| + Format(instr, "xor 'rd, 'rs, 'rt");
|
| + break;
|
| + case NOR:
|
| + Format(instr, "nor 'rd, 'rs, 'rt");
|
| + break;
|
| + case SLT:
|
| + Format(instr, "slt 'rd, 'rs, 'rt");
|
| + break;
|
| + case SLTU:
|
| + Format(instr, "sltu 'rd, 'rs, 'rt");
|
| + break;
|
| + case BREAK:
|
| + Format(instr, "break, code: 'code");
|
| + break;
|
| + case TGE:
|
| + Format(instr, "tge 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TGEU:
|
| + Format(instr, "tgeu 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TLT:
|
| + Format(instr, "tlt 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TLTU:
|
| + Format(instr, "tltu 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TEQ:
|
| + Format(instr, "teq 'rs, 'rt, code: 'code");
|
| + break;
|
| + case TNE:
|
| + Format(instr, "tne 'rs, 'rt, code: 'code");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + };
|
| + break;
|
| + case SPECIAL2:
|
| + switch (instr->FunctionFieldRaw()) {
|
| + case MUL:
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + };
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + };
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeImmediate(Instruction* instr) {
|
| + switch (instr->OpcodeFieldRaw()) {
|
| + // ------------- REGIMM class
|
| + case REGIMM:
|
| + switch (instr->RtFieldRaw()) {
|
| + case BLTZ:
|
| + Format(instr, "bltz 'rs, 'imm16u");
|
| + break;
|
| + case BLTZAL:
|
| + Format(instr, "bltzal 'rs, 'imm16u");
|
| + break;
|
| + case BGEZ:
|
| + Format(instr, "bgez 'rs, 'imm16u");
|
| + break;
|
| + case BGEZAL:
|
| + Format(instr, "bgezal 'rs, 'imm16u");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + };
|
| + break; // case REGIMM
|
| + // ------------- Branch instructions
|
| + case BEQ:
|
| + Format(instr, "beq 'rs, 'rt, 'imm16u");
|
| + break;
|
| + case BNE:
|
| + Format(instr, "bne 'rs, 'rt, 'imm16u");
|
| + break;
|
| + case BLEZ:
|
| + Format(instr, "blez 'rs, 'imm16u");
|
| + break;
|
| + case BGTZ:
|
| + Format(instr, "bgtz 'rs, 'imm16u");
|
| + break;
|
| + // ------------- Arithmetic instructions
|
| + case ADDI:
|
| + Format(instr, "addi 'rt, 'rs, 'imm16s");
|
| + break;
|
| + case ADDIU:
|
| + Format(instr, "addiu 'rt, 'rs, 'imm16s");
|
| + break;
|
| + case SLTI:
|
| + Format(instr, "slti 'rt, 'rs, 'imm16s");
|
| + break;
|
| + case SLTIU:
|
| + Format(instr, "sltiu 'rt, 'rs, 'imm16u");
|
| + break;
|
| + case ANDI:
|
| + Format(instr, "andi 'rt, 'rs, 'imm16x");
|
| + break;
|
| + case ORI:
|
| + Format(instr, "ori 'rt, 'rs, 'imm16x");
|
| + break;
|
| + case XORI:
|
| + Format(instr, "xori 'rt, 'rs, 'imm16x");
|
| + break;
|
| + case LUI:
|
| + Format(instr, "lui 'rt, 'imm16x");
|
| + break;
|
| + // ------------- Memory instructions
|
| + case LB:
|
| + Format(instr, "lb 'rt, 'imm16s('rs)");
|
| + break;
|
| + case LW:
|
| + Format(instr, "lw 'rt, 'imm16s('rs)");
|
| + break;
|
| + case LBU:
|
| + Format(instr, "lbu 'rt, 'imm16s('rs)");
|
| + break;
|
| + case SB:
|
| + Format(instr, "sb 'rt, 'imm16s('rs)");
|
| + break;
|
| + case SW:
|
| + Format(instr, "sw 'rt, 'imm16s('rs)");
|
| + break;
|
| + case LWC1:
|
| + Format(instr, "lwc1 'ft, 'imm16s('rs)");
|
| + break;
|
| + case LDC1:
|
| + Format(instr, "ldc1 'ft, 'imm16s('rs)");
|
| + break;
|
| + case SWC1:
|
| + Format(instr, "swc1 'rt, 'imm16s('fs)");
|
| + break;
|
| + case SDC1:
|
| + Format(instr, "sdc1 'rt, 'imm16s('fs)");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + break;
|
| + };
|
| +}
|
| +
|
| +
|
| +void Decoder::DecodeTypeJump(Instruction* instr) {
|
| + switch (instr->OpcodeFieldRaw()) {
|
| + case J:
|
| + Format(instr, "j 'imm26");
|
| + break;
|
| + case JAL:
|
| + Format(instr, "jal 'imm26");
|
| + break;
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| +}
|
| +
|
| +
|
| +// Disassemble the instruction at *instr_ptr into the output buffer.
|
| +int Decoder::InstructionDecode(byte_* instr_ptr) {
|
| + Instruction* instr = Instruction::At(instr_ptr);
|
| + // Print raw instruction bytes.
|
| + out_buffer_pos_ += v8i::OS::SNPrintF(out_buffer_ + out_buffer_pos_,
|
| + "%08x ",
|
| + instr->InstructionBits());
|
| + switch (instr->InstructionType()) {
|
| + case Instruction::kRegisterType: {
|
| + DecodeTypeRegister(instr);
|
| + break;
|
| + }
|
| + case Instruction::kImmediateType: {
|
| + DecodeTypeImmediate(instr);
|
| + break;
|
| + }
|
| + case Instruction::kJumpType: {
|
| + DecodeTypeJump(instr);
|
| + break;
|
| + }
|
| + default: {
|
| + UNSUPPORTED_MIPS();
|
| + }
|
| + }
|
| + return Instruction::kInstructionSize;
|
| +}
|
| +
|
| +
|
| +} } // namespace assembler::mips
|
| +
|
| +
|
| +
|
| +//------------------------------------------------------------------------------
|
| +
|
| +namespace disasm {
|
| +
|
| +namespace v8i = v8::internal;
|
| +
|
| +
|
| +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 {
|
| + return assembler::mips::Registers::Name(reg);
|
| +}
|
| +
|
| +
|
| +const char* NameConverter::NameOfXMMRegister(int reg) const {
|
| + return assembler::mips::FPURegister::Name(reg);
|
| +}
|
| +
|
| +
|
| +const char* NameConverter::NameOfByteCPURegister(int reg) const {
|
| + UNREACHABLE(); // MIPS does not have the concept of a byte register
|
| + return "nobytereg";
|
| +}
|
| +
|
| +
|
| +const char* NameConverter::NameInCode(byte_* addr) const {
|
| + // The default name converter is called for unknown code. So we will not try
|
| + // to access any memory.
|
| + return "";
|
| +}
|
| +
|
| +
|
| +//------------------------------------------------------------------------------
|
| +
|
| +Disassembler::Disassembler(const NameConverter& converter)
|
| + : converter_(converter) {}
|
| +
|
| +
|
| +Disassembler::~Disassembler() {}
|
| +
|
| +
|
| +int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
|
| + byte_* instruction) {
|
| + assembler::mips::Decoder d(converter_, buffer);
|
| + return d.InstructionDecode(instruction);
|
| +}
|
| +
|
| +
|
| +int Disassembler::ConstantPoolSizeAt(byte_* instruction) {
|
| + UNIMPLEMENTED_MIPS();
|
| + return -1;
|
| +}
|
| +
|
| +
|
| +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 %08x %s\n",
|
| + prev_pc, *reinterpret_cast<int32_t*>(prev_pc), buffer.start());
|
| + }
|
| +}
|
| +
|
| +#undef UNSUPPORTED
|
| +
|
| +} // namespace disasm
|
| +
|
|
|