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 |