Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/disassembler.h" | 5 #include "vm/disassembler.h" |
| 6 | 6 |
| 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS. |
| 8 #if defined(TARGET_ARCH_MIPS) | 8 #if defined(TARGET_ARCH_MIPS) |
| 9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
| 10 | 10 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 class MIPSDecoder : public ValueObject { | |
| 14 public: | |
| 15 MIPSDecoder(char* buffer, size_t buffer_size) | |
| 16 : buffer_(buffer), | |
| 17 buffer_size_(buffer_size), | |
| 18 buffer_pos_(0), | |
| 19 delay_slot_(false) { | |
| 20 buffer_[buffer_pos_] = '\0'; | |
| 21 } | |
| 22 | |
| 23 ~MIPSDecoder() {} | |
| 24 | |
| 25 // Writes one disassembled instruction into 'buffer' (0-terminated). | |
| 26 void InstructionDecode(Instr* instr); | |
| 27 | |
| 28 private: | |
| 29 // Bottleneck functions to print into the out_buffer. | |
| 30 void Print(const char* str); | |
| 31 | |
| 32 // Printing of common values. | |
| 33 void PrintRegister(Register reg); | |
| 34 | |
| 35 int FormatRegister(Instr* instr, const char* format); | |
| 36 int FormatOption(Instr* instr, const char* format); | |
| 37 void Format(Instr* instr, const char* format); | |
| 38 | |
| 39 void DecodeSpecial(Instr* instr); | |
| 40 | |
| 41 // Convenience functions. | |
| 42 char* get_buffer() const { return buffer_; } | |
| 43 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | |
| 44 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | |
| 45 | |
| 46 char* buffer_; // Decode instructions into this buffer. | |
| 47 size_t buffer_size_; // The size of the character buffer. | |
| 48 size_t buffer_pos_; // Current character position in buffer. | |
| 49 | |
| 50 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
| |
| 51 | |
| 52 DISALLOW_ALLOCATION(); | |
| 53 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); | |
| 54 }; | |
| 55 | |
| 56 | |
| 57 // Support for assertions in the MIPSDecoder formatting functions. | |
| 58 #define STRING_STARTS_WITH(string, compare_string) \ | |
| 59 (strncmp(string, compare_string, strlen(compare_string)) == 0) | |
| 60 | |
| 61 | |
| 62 // Append the str to the output buffer. | |
| 63 void MIPSDecoder::Print(const char* str) { | |
| 64 char cur = *str++; | |
| 65 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { | |
| 66 buffer_[buffer_pos_++] = cur; | |
| 67 cur = *str++; | |
| 68 } | |
| 69 buffer_[buffer_pos_] = '\0'; | |
| 70 } | |
| 71 | |
| 72 | |
| 73 static const char* reg_names[kNumberOfCpuRegisters] = { | |
| 74 "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7" , | |
| 75 "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", | |
| 76 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | |
| 77 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | |
| 78 }; | |
|
regis
2013/03/06 21:18:42
For better readability of disassembly, we should u
| |
| 79 | |
| 80 | |
| 81 void MIPSDecoder::PrintRegister(Register reg) { | |
| 82 ASSERT(0 <= reg); | |
| 83 ASSERT(reg < kNumberOfCpuRegisters); | |
| 84 Print(reg_names[reg]); | |
| 85 } | |
| 86 | |
| 87 | |
| 88 // Handle all register based formatting in these functions to reduce the | |
| 89 // complexity of FormatOption. | |
| 90 int MIPSDecoder::FormatRegister(Instr* instr, const char* format) { | |
| 91 ASSERT(format[0] == 'r'); | |
| 92 switch (format[1]) { | |
| 93 case 's': { // 'rs: Rs register | |
| 94 PrintRegister(instr->RsField()); | |
| 95 return 2; | |
| 96 } | |
| 97 case 't': { // 'rt: Rt register | |
| 98 PrintRegister(instr->RtField()); | |
| 99 return 2; | |
| 100 } | |
| 101 case 'd': { // 'rd: Rd register | |
| 102 PrintRegister(instr->RdField()); | |
| 103 return 2; | |
| 104 } | |
| 105 } | |
| 106 UNREACHABLE(); | |
| 107 return -1; | |
| 108 } | |
| 109 | |
| 110 | |
| 111 // FormatOption takes a formatting string and interprets it based on | |
| 112 // the current instructions. The format string points to the first | |
| 113 // character of the option string (the option escape has already been | |
| 114 // consumed by the caller.) FormatOption returns the number of | |
| 115 // characters that were consumed from the formatting string. | |
| 116 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | |
| 117 switch (format[0]) { | |
| 118 case 'h': { | |
| 119 ASSERT(STRING_STARTS_WITH(format, "hint")); | |
| 120 if (instr->SaField() != 0) { | |
| 121 UNIMPLEMENTED(); | |
| 122 } | |
| 123 return 4; | |
| 124 } | |
| 125 case 'i': { | |
| 126 ASSERT(STRING_STARTS_WITH(format, "imm")); | |
| 127 int32_t imm = instr->ImmField(); | |
| 128 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 129 remaining_size_in_buffer(), | |
| 130 "0x%x", | |
| 131 imm); | |
| 132 return 3; | |
| 133 } | |
| 134 case 'r': { | |
| 135 return FormatRegister(instr, format); | |
| 136 } | |
| 137 case 's': { | |
| 138 ASSERT(STRING_STARTS_WITH(format, "sa")); | |
| 139 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 140 remaining_size_in_buffer(), | |
| 141 "%d", | |
| 142 instr->SaField()); | |
| 143 return 2; | |
| 144 } | |
| 145 default: { | |
| 146 UNREACHABLE(); | |
| 147 } | |
| 148 } | |
| 149 UNREACHABLE(); | |
| 150 return -1; | |
| 151 } | |
| 152 | |
| 153 | |
| 154 // Format takes a formatting string for a whole instruction and prints it into | |
| 155 // the output buffer. All escaped options are handed to FormatOption to be | |
| 156 // parsed further. | |
| 157 void MIPSDecoder::Format(Instr* instr, const char* format) { | |
| 158 if (delay_slot_) { | |
| 159 delay_slot_ = false; | |
| 160 // 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
| |
| 161 buffer_[buffer_pos_++] = '*'; | |
| 162 // } | |
| 163 } | |
| 164 char cur = *format++; | |
| 165 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { | |
| 166 if (cur == '\'') { // Single quote is used as the formatting escape. | |
| 167 format += FormatOption(instr, format); | |
| 168 } else { | |
| 169 buffer_[buffer_pos_++] = cur; | |
| 170 } | |
| 171 cur = *format++; | |
| 172 } | |
| 173 buffer_[buffer_pos_] = '\0'; | |
| 174 } | |
| 175 | |
| 176 | |
| 177 void MIPSDecoder::DecodeSpecial(Instr* instr) { | |
| 178 switch (instr->FunctionField()) { | |
| 179 case SLL: { | |
| 180 if ((instr->RdField() == R0) && | |
| 181 (instr->RtField() == R0) && | |
| 182 (instr->SaField() == 0)) { | |
| 183 Format(instr, "nop"); | |
| 184 } else { | |
| 185 Format(instr, "sll 'rd, 'rt, 'sa"); | |
| 186 } | |
| 187 break; | |
| 188 } | |
| 189 case JR: { | |
| 190 ASSERT(instr->RtField() == R0); | |
| 191 ASSERT(instr->RdField() == R0); | |
| 192 Format(instr, "jr'hint 'rs"); | |
| 193 delay_slot_ = true; | |
| 194 break; | |
| 195 } | |
| 196 default: { | |
| 197 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); | |
| 198 UNREACHABLE(); | |
| 199 break; | |
| 200 } | |
| 201 } | |
| 202 } | |
| 203 | |
| 204 | |
| 205 void MIPSDecoder::InstructionDecode(Instr* instr) { | |
| 206 switch (instr->OpcodeField()) { | |
| 207 case SPECIAL: { | |
| 208 DecodeSpecial(instr); | |
| 209 break; | |
| 210 } | |
| 211 case ORI: { | |
| 212 Format(instr, "ori 'rt, 'rs, 'imm"); | |
| 213 break; | |
| 214 } | |
| 215 default: { | |
| 216 OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); | |
| 217 UNREACHABLE(); | |
| 218 break; | |
| 219 } | |
| 220 } | |
| 221 } | |
| 222 | |
| 223 | |
| 13 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 224 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, |
| 14 char* human_buffer, intptr_t human_size, | 225 char* human_buffer, intptr_t human_size, |
| 15 uword pc) { | 226 uword pc) { |
| 16 UNIMPLEMENTED(); | 227 MIPSDecoder decoder(human_buffer, human_size); |
| 17 return 0; | 228 Instr* instr = Instr::At(pc); |
| 18 } | 229 decoder.InstructionDecode(instr); |
| 19 | 230 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); |
| 20 | 231 return Instr::kInstrSize; |
| 232 } | |
| 233 | |
| 234 | |
| 21 void Disassembler::Disassemble(uword start, | 235 void Disassembler::Disassemble(uword start, |
| 22 uword end, | 236 uword end, |
| 23 DisassemblyFormatter* formatter, | 237 DisassemblyFormatter* formatter, |
| 24 const Code::Comments& comments) { | 238 const Code::Comments& comments) { |
| 25 UNIMPLEMENTED(); | 239 ASSERT(formatter != NULL); |
| 240 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. | |
| 241 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. | |
| 242 uword pc = start; | |
| 243 intptr_t comment_finger = 0; | |
| 244 while (pc < end) { | |
| 245 const intptr_t offset = pc - start; | |
| 246 while (comment_finger < comments.Length() && | |
| 247 comments.PCOffsetAt(comment_finger) <= offset) { | |
| 248 formatter->Print( | |
| 249 " ;; %s\n", | |
| 250 String::Handle(comments.CommentAt(comment_finger)).ToCString()); | |
| 251 comment_finger++; | |
| 252 } | |
| 253 int instruction_length = DecodeInstruction(hex_buffer, | |
| 254 sizeof(hex_buffer), | |
| 255 human_buffer, | |
| 256 sizeof(human_buffer), | |
| 257 pc); | |
| 258 formatter->ConsumeInstruction(hex_buffer, | |
| 259 sizeof(hex_buffer), | |
| 260 human_buffer, | |
| 261 sizeof(human_buffer), | |
| 262 pc); | |
| 263 pc += instruction_length; | |
| 264 } | |
| 26 } | 265 } |
| 27 | 266 |
| 28 } // namespace dart | 267 } // namespace dart |
| 29 | 268 |
| 30 #endif // defined TARGET_ARCH_MIPS | 269 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |