Chromium Code Reviews| Index: runtime/vm/disassembler_mips.cc |
| =================================================================== |
| --- runtime/vm/disassembler_mips.cc (revision 19556) |
| +++ runtime/vm/disassembler_mips.cc (working copy) |
| @@ -10,11 +10,225 @@ |
| namespace dart { |
| +class MIPSDecoder : public ValueObject { |
| + public: |
| + MIPSDecoder(char* buffer, size_t buffer_size) |
| + : buffer_(buffer), |
| + buffer_size_(buffer_size), |
| + buffer_pos_(0), |
| + delay_slot_(false) { |
| + buffer_[buffer_pos_] = '\0'; |
| + } |
| + |
| + ~MIPSDecoder() {} |
| + |
| + // Writes one disassembled instruction into 'buffer' (0-terminated). |
| + void InstructionDecode(Instr* instr); |
| + |
| + private: |
| + // Bottleneck functions to print into the out_buffer. |
| + void Print(const char* str); |
| + |
| + // Printing of common values. |
| + void PrintRegister(Register reg); |
| + |
| + int FormatRegister(Instr* instr, const char* format); |
| + int FormatOption(Instr* instr, const char* format); |
| + void Format(Instr* instr, const char* format); |
| + |
| + void DecodeSpecial(Instr* instr); |
| + |
| + // Convenience functions. |
| + char* get_buffer() const { return buffer_; } |
| + char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| + size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| + |
| + char* buffer_; // Decode instructions into this buffer. |
| + size_t buffer_size_; // The size of the character buffer. |
| + size_t buffer_pos_; // Current character position in buffer. |
| + |
| + bool delay_slot_; // Previous instruction uses a delay slot. |
|
regis
2013/03/06 21:18:42
How will you use this info in the disassembler?
I
Ivan Posva
2013/03/07 11:03:22
I was toying with the idea of not creating an inst
|
| + |
| + DISALLOW_ALLOCATION(); |
| + DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); |
| +}; |
| + |
| + |
| +// Support for assertions in the MIPSDecoder formatting functions. |
| +#define STRING_STARTS_WITH(string, compare_string) \ |
| + (strncmp(string, compare_string, strlen(compare_string)) == 0) |
| + |
| + |
| +// Append the str to the output buffer. |
| +void MIPSDecoder::Print(const char* str) { |
| + char cur = *str++; |
| + while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { |
| + buffer_[buffer_pos_++] = cur; |
| + cur = *str++; |
| + } |
| + buffer_[buffer_pos_] = '\0'; |
| +} |
| + |
| + |
| +static const char* reg_names[kNumberOfCpuRegisters] = { |
| + "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7" , |
| + "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", |
| + "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
| + "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", |
| +}; |
|
regis
2013/03/06 21:18:42
For better readability of disassembly, we should u
|
| + |
| + |
| +void MIPSDecoder::PrintRegister(Register reg) { |
| + ASSERT(0 <= reg); |
| + ASSERT(reg < kNumberOfCpuRegisters); |
| + Print(reg_names[reg]); |
| +} |
| + |
| + |
| +// Handle all register based formatting in these functions to reduce the |
| +// complexity of FormatOption. |
| +int MIPSDecoder::FormatRegister(Instr* instr, const char* format) { |
| + ASSERT(format[0] == 'r'); |
| + switch (format[1]) { |
| + case 's': { // 'rs: Rs register |
| + PrintRegister(instr->RsField()); |
| + return 2; |
| + } |
| + case 't': { // 'rt: Rt register |
| + PrintRegister(instr->RtField()); |
| + return 2; |
| + } |
| + case 'd': { // 'rd: Rd register |
| + PrintRegister(instr->RdField()); |
| + 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 MIPSDecoder::FormatOption(Instr* instr, const char* format) { |
| + switch (format[0]) { |
| + case 'h': { |
| + ASSERT(STRING_STARTS_WITH(format, "hint")); |
| + if (instr->SaField() != 0) { |
| + UNIMPLEMENTED(); |
| + } |
| + return 4; |
| + } |
| + case 'i': { |
| + ASSERT(STRING_STARTS_WITH(format, "imm")); |
| + int32_t imm = instr->ImmField(); |
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| + remaining_size_in_buffer(), |
| + "0x%x", |
| + imm); |
| + return 3; |
| + } |
| + case 'r': { |
| + return FormatRegister(instr, format); |
| + } |
| + case 's': { |
| + ASSERT(STRING_STARTS_WITH(format, "sa")); |
| + buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| + remaining_size_in_buffer(), |
| + "%d", |
| + instr->SaField()); |
| + return 2; |
| + } |
| + default: { |
| + UNREACHABLE(); |
| + } |
| + } |
| + 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 MIPSDecoder::Format(Instr* instr, const char* format) { |
| + if (delay_slot_) { |
| + delay_slot_ = false; |
| + // if (buffer_pos_ < (buffer_size_ - 1)) { |
|
regis
2013/03/06 21:18:42
Commented out code?
Ivan Posva
2013/03/07 11:03:22
Yes, another left over from the experiment with pr
|
| + buffer_[buffer_pos_++] = '*'; |
| + // } |
| + } |
| + char cur = *format++; |
| + while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { |
| + if (cur == '\'') { // Single quote is used as the formatting escape. |
| + format += FormatOption(instr, format); |
| + } else { |
| + buffer_[buffer_pos_++] = cur; |
| + } |
| + cur = *format++; |
| + } |
| + buffer_[buffer_pos_] = '\0'; |
| +} |
| + |
| + |
| +void MIPSDecoder::DecodeSpecial(Instr* instr) { |
| + switch (instr->FunctionField()) { |
| + case SLL: { |
| + if ((instr->RdField() == R0) && |
| + (instr->RtField() == R0) && |
| + (instr->SaField() == 0)) { |
| + Format(instr, "nop"); |
| + } else { |
| + Format(instr, "sll 'rd, 'rt, 'sa"); |
| + } |
| + break; |
| + } |
| + case JR: { |
| + ASSERT(instr->RtField() == R0); |
| + ASSERT(instr->RdField() == R0); |
| + Format(instr, "jr'hint 'rs"); |
| + delay_slot_ = true; |
| + break; |
| + } |
| + default: { |
| + OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); |
| + UNREACHABLE(); |
| + break; |
| + } |
| + } |
| +} |
| + |
| + |
| +void MIPSDecoder::InstructionDecode(Instr* instr) { |
| + switch (instr->OpcodeField()) { |
| + case SPECIAL: { |
| + DecodeSpecial(instr); |
| + break; |
| + } |
| + case ORI: { |
| + Format(instr, "ori 'rt, 'rs, 'imm"); |
| + break; |
| + } |
| + default: { |
| + OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); |
| + UNREACHABLE(); |
| + break; |
| + } |
| + } |
| +} |
| + |
| + |
| int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, |
| char* human_buffer, intptr_t human_size, |
| uword pc) { |
| - UNIMPLEMENTED(); |
| - return 0; |
| + MIPSDecoder decoder(human_buffer, human_size); |
| + Instr* instr = Instr::At(pc); |
| + decoder.InstructionDecode(instr); |
| + OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); |
| + return Instr::kInstrSize; |
| } |
| @@ -22,7 +236,32 @@ |
| uword end, |
| DisassemblyFormatter* formatter, |
| const Code::Comments& comments) { |
| - UNIMPLEMENTED(); |
| + ASSERT(formatter != NULL); |
| + char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. |
| + char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. |
| + uword pc = start; |
| + intptr_t comment_finger = 0; |
| + while (pc < end) { |
| + const intptr_t offset = pc - start; |
| + while (comment_finger < comments.Length() && |
| + comments.PCOffsetAt(comment_finger) <= offset) { |
| + formatter->Print( |
| + " ;; %s\n", |
| + String::Handle(comments.CommentAt(comment_finger)).ToCString()); |
| + comment_finger++; |
| + } |
| + int instruction_length = DecodeInstruction(hex_buffer, |
| + sizeof(hex_buffer), |
| + human_buffer, |
| + sizeof(human_buffer), |
| + pc); |
| + formatter->ConsumeInstruction(hex_buffer, |
| + sizeof(hex_buffer), |
| + human_buffer, |
| + sizeof(human_buffer), |
| + pc); |
| + pc += instruction_length; |
| + } |
| } |
| } // namespace dart |