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 #include "vm/instructions.h" | 10 #include "vm/instructions.h" |
11 | 11 |
12 namespace dart { | 12 namespace dart { |
13 | 13 |
14 #ifndef PRODUCT | 14 #ifndef PRODUCT |
15 | 15 |
16 class MIPSDecoder : public ValueObject { | 16 class MIPSDecoder : public ValueObject { |
17 public: | 17 public: |
18 MIPSDecoder(char* buffer, size_t buffer_size) | 18 MIPSDecoder(char* buffer, size_t buffer_size) |
19 : buffer_(buffer), | 19 : buffer_(buffer), buffer_size_(buffer_size), buffer_pos_(0) { |
20 buffer_size_(buffer_size), | |
21 buffer_pos_(0) { | |
22 buffer_[buffer_pos_] = '\0'; | 20 buffer_[buffer_pos_] = '\0'; |
23 } | 21 } |
24 | 22 |
25 ~MIPSDecoder() {} | 23 ~MIPSDecoder() {} |
26 | 24 |
27 // Writes one disassembled instruction into 'buffer' (0-terminated). | 25 // Writes one disassembled instruction into 'buffer' (0-terminated). |
28 // Returns true if the instruction was successfully decoded, false otherwise. | 26 // Returns true if the instruction was successfully decoded, false otherwise. |
29 void InstructionDecode(Instr* instr); | 27 void InstructionDecode(Instr* instr); |
30 | 28 |
31 private: | 29 private: |
(...skipping 14 matching lines...) Expand all Loading... |
46 void DecodeSpecial(Instr* instr); | 44 void DecodeSpecial(Instr* instr); |
47 void DecodeSpecial2(Instr* instr); | 45 void DecodeSpecial2(Instr* instr); |
48 void DecodeRegImm(Instr* instr); | 46 void DecodeRegImm(Instr* instr); |
49 void DecodeCop1(Instr* instr); | 47 void DecodeCop1(Instr* instr); |
50 | 48 |
51 // Convenience functions. | 49 // Convenience functions. |
52 char* get_buffer() const { return buffer_; } | 50 char* get_buffer() const { return buffer_; } |
53 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 51 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
54 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 52 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
55 | 53 |
56 char* buffer_; // Decode instructions into this buffer. | 54 char* buffer_; // Decode instructions into this buffer. |
57 size_t buffer_size_; // The size of the character buffer. | 55 size_t buffer_size_; // The size of the character buffer. |
58 size_t buffer_pos_; // Current character position in buffer. | 56 size_t buffer_pos_; // Current character position in buffer. |
59 | 57 |
60 DISALLOW_ALLOCATION(); | 58 DISALLOW_ALLOCATION(); |
61 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); | 59 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); |
62 }; | 60 }; |
63 | 61 |
64 | 62 |
65 // Support for assertions in the MIPSDecoder formatting functions. | 63 // Support for assertions in the MIPSDecoder formatting functions. |
66 #define STRING_STARTS_WITH(string, compare_string) \ | 64 #define STRING_STARTS_WITH(string, compare_string) \ |
67 (strncmp(string, compare_string, strlen(compare_string)) == 0) | 65 (strncmp(string, compare_string, strlen(compare_string)) == 0) |
68 | 66 |
69 | 67 |
70 // Append the str to the output buffer. | 68 // Append the str to the output buffer. |
71 void MIPSDecoder::Print(const char* str) { | 69 void MIPSDecoder::Print(const char* str) { |
72 char cur = *str++; | 70 char cur = *str++; |
73 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { | 71 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { |
74 buffer_[buffer_pos_++] = cur; | 72 buffer_[buffer_pos_++] = cur; |
75 cur = *str++; | 73 cur = *str++; |
76 } | 74 } |
77 buffer_[buffer_pos_] = '\0'; | 75 buffer_[buffer_pos_] = '\0'; |
78 } | 76 } |
79 | 77 |
80 | 78 |
81 static const char* reg_names[kNumberOfCpuRegisters] = { | 79 static const char* reg_names[kNumberOfCpuRegisters] = { |
82 "zr", "at", "v0", "v1" , "a0", "a1", "a2", "a3", | 80 "zr", "at", "v0", "v1", "a0", "a1", "a2", "a3", "t0", "t1", "t2", |
83 "t0", "t1", "t2", "t3" , "t4", "t5", "t6", "t7", | 81 "t3", "t4", "t5", "t6", "t7", "s0", "s1", "s2", "thr", "s4", "s5", |
84 "s0", "s1", "s2", "thr", "s4", "s5", "s6", "pp", | 82 "s6", "pp", "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra", |
85 "t8", "t9", "k0", "k1" , "gp", "sp", "fp", "ra", | |
86 }; | 83 }; |
87 | 84 |
88 | 85 |
89 static const char* freg_names[kNumberOfFRegisters] = { | 86 static const char* freg_names[kNumberOfFRegisters] = { |
90 "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , | 87 "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", "f8", "f9", "f10", |
91 "f8" , "f9" , "f10", "f11", "f12", "f13", "f14", "f15", | 88 "f11", "f12", "f13", "f14", "f15", "f16", "f17", "f18", "f19", "f20", "f21", |
92 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", | 89 "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
93 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", | |
94 }; | 90 }; |
95 | 91 |
96 | 92 |
97 void MIPSDecoder::PrintRegister(Register reg) { | 93 void MIPSDecoder::PrintRegister(Register reg) { |
98 ASSERT(0 <= reg); | 94 ASSERT(0 <= reg); |
99 ASSERT(reg < kNumberOfCpuRegisters); | 95 ASSERT(reg < kNumberOfCpuRegisters); |
100 Print(reg_names[reg]); | 96 Print(reg_names[reg]); |
101 } | 97 } |
102 | 98 |
103 | 99 |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 case 'd': { // 'fd: Fd register | 141 case 'd': { // 'fd: Fd register |
146 PrintFRegister(instr->FdField()); | 142 PrintFRegister(instr->FdField()); |
147 return 2; | 143 return 2; |
148 } | 144 } |
149 } | 145 } |
150 UNREACHABLE(); | 146 UNREACHABLE(); |
151 return -1; | 147 return -1; |
152 } | 148 } |
153 | 149 |
154 | 150 |
155 void MIPSDecoder::PrintFormat(Instr *instr) { | 151 void MIPSDecoder::PrintFormat(Instr* instr) { |
156 switch (instr->FormatField()) { | 152 switch (instr->FormatField()) { |
157 case FMT_S: { | 153 case FMT_S: { |
158 Print("s"); | 154 Print("s"); |
159 break; | 155 break; |
160 } | 156 } |
161 case FMT_D: { | 157 case FMT_D: { |
162 Print("d"); | 158 Print("d"); |
163 break; | 159 break; |
164 } | 160 } |
165 case FMT_W: { | 161 case FMT_W: { |
(...skipping 18 matching lines...) Expand all Loading... |
184 | 180 |
185 // FormatOption takes a formatting string and interprets it based on | 181 // FormatOption takes a formatting string and interprets it based on |
186 // the current instructions. The format string points to the first | 182 // the current instructions. The format string points to the first |
187 // character of the option string (the option escape has already been | 183 // character of the option string (the option escape has already been |
188 // consumed by the caller.) FormatOption returns the number of | 184 // consumed by the caller.) FormatOption returns the number of |
189 // characters that were consumed from the formatting string. | 185 // characters that were consumed from the formatting string. |
190 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | 186 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { |
191 switch (format[0]) { | 187 switch (format[0]) { |
192 case 'c': { | 188 case 'c': { |
193 ASSERT(STRING_STARTS_WITH(format, "code")); | 189 ASSERT(STRING_STARTS_WITH(format, "code")); |
194 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 190 buffer_pos_ += |
195 remaining_size_in_buffer(), | 191 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
196 "0x%x", | 192 "0x%x", instr->BreakCodeField()); |
197 instr->BreakCodeField()); | |
198 return 4; | 193 return 4; |
199 } | 194 } |
200 case 'h': { | 195 case 'h': { |
201 ASSERT(STRING_STARTS_WITH(format, "hint")); | 196 ASSERT(STRING_STARTS_WITH(format, "hint")); |
202 if (instr->SaField() == 0x10) { | 197 if (instr->SaField() == 0x10) { |
203 // The high bit of the SA field is the only one that means something for | 198 // The high bit of the SA field is the only one that means something for |
204 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. | 199 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. |
205 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 200 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
206 remaining_size_in_buffer(), | 201 remaining_size_in_buffer(), ".hb"); |
207 ".hb"); | |
208 } else if (instr->SaField() != 0) { | 202 } else if (instr->SaField() != 0) { |
209 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 203 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
210 remaining_size_in_buffer(), | 204 remaining_size_in_buffer(), ".unknown"); |
211 ".unknown"); | |
212 } | 205 } |
213 return 4; | 206 return 4; |
214 } | 207 } |
215 case 'd': { | 208 case 'd': { |
216 ASSERT(STRING_STARTS_WITH(format, "dest")); | 209 ASSERT(STRING_STARTS_WITH(format, "dest")); |
217 int off = instr->SImmField() << 2; | 210 int off = instr->SImmField() << 2; |
218 uword destination = | 211 uword destination = |
219 reinterpret_cast<uword>(instr) + off + Instr::kInstrSize; | 212 reinterpret_cast<uword>(instr) + off + Instr::kInstrSize; |
220 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 213 buffer_pos_ += |
221 remaining_size_in_buffer(), | 214 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
222 "%#" Px "", | 215 "%#" Px "", destination); |
223 destination); | |
224 return 4; | 216 return 4; |
225 } | 217 } |
226 case 'i': { | 218 case 'i': { |
227 ASSERT(STRING_STARTS_WITH(format, "imm")); | 219 ASSERT(STRING_STARTS_WITH(format, "imm")); |
228 if (format[3] == 'u') { | 220 if (format[3] == 'u') { |
229 int32_t imm = instr->UImmField(); | 221 int32_t imm = instr->UImmField(); |
230 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 222 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
231 remaining_size_in_buffer(), | 223 remaining_size_in_buffer(), "0x%x", imm); |
232 "0x%x", | |
233 imm); | |
234 } else { | 224 } else { |
235 ASSERT(STRING_STARTS_WITH(format, "imms")); | 225 ASSERT(STRING_STARTS_WITH(format, "imms")); |
236 int32_t imm = instr->SImmField(); | 226 int32_t imm = instr->SImmField(); |
237 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 227 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
238 remaining_size_in_buffer(), | 228 remaining_size_in_buffer(), "%d", imm); |
239 "%d", | |
240 imm); | |
241 } | 229 } |
242 return 4; | 230 return 4; |
243 } | 231 } |
244 case 'r': { | 232 case 'r': { |
245 return FormatRegister(instr, format); | 233 return FormatRegister(instr, format); |
246 } | 234 } |
247 case 'f': { | 235 case 'f': { |
248 if (format[1] == 'm') { | 236 if (format[1] == 'm') { |
249 ASSERT(STRING_STARTS_WITH(format, "fmt")); | 237 ASSERT(STRING_STARTS_WITH(format, "fmt")); |
250 PrintFormat(instr); | 238 PrintFormat(instr); |
251 return 3; | 239 return 3; |
252 } else { | 240 } else { |
253 return FormatFRegister(instr, format); | 241 return FormatFRegister(instr, format); |
254 } | 242 } |
255 } | 243 } |
256 case 's': { | 244 case 's': { |
257 ASSERT(STRING_STARTS_WITH(format, "sa")); | 245 ASSERT(STRING_STARTS_WITH(format, "sa")); |
258 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 246 buffer_pos_ += |
259 remaining_size_in_buffer(), | 247 OS::SNPrint(current_position_in_buffer(), remaining_size_in_buffer(), |
260 "%d", | 248 "%d", instr->SaField()); |
261 instr->SaField()); | |
262 return 2; | 249 return 2; |
263 } | 250 } |
264 default: { | 251 default: { UNREACHABLE(); } |
265 UNREACHABLE(); | |
266 } | |
267 } | 252 } |
268 UNREACHABLE(); | 253 UNREACHABLE(); |
269 return -1; | 254 return -1; |
270 } | 255 } |
271 | 256 |
272 | 257 |
273 // Format takes a formatting string for a whole instruction and prints it into | 258 // Format takes a formatting string for a whole instruction and prints it into |
274 // the output buffer. All escaped options are handed to FormatOption to be | 259 // the output buffer. All escaped options are handed to FormatOption to be |
275 // parsed further. | 260 // parsed further. |
276 void MIPSDecoder::Format(Instr* instr, const char* format) { | 261 void MIPSDecoder::Format(Instr* instr, const char* format) { |
277 char cur = *format++; | 262 char cur = *format++; |
278 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { | 263 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { |
279 if (cur == '\'') { // Single quote is used as the formatting escape. | 264 if (cur == '\'') { // Single quote is used as the formatting escape. |
280 format += FormatOption(instr, format); | 265 format += FormatOption(instr, format); |
281 } else { | 266 } else { |
282 buffer_[buffer_pos_++] = cur; | 267 buffer_[buffer_pos_++] = cur; |
283 } | 268 } |
284 cur = *format++; | 269 cur = *format++; |
285 } | 270 } |
286 buffer_[buffer_pos_] = '\0'; | 271 buffer_[buffer_pos_] = '\0'; |
287 } | 272 } |
288 | 273 |
289 | 274 |
290 // For currently unimplemented decodings the disassembler calls Unknown(instr) | 275 // For currently unimplemented decodings the disassembler calls Unknown(instr) |
291 // which will just print "unknown" of the instruction bits. | 276 // which will just print "unknown" of the instruction bits. |
292 void MIPSDecoder::Unknown(Instr* instr) { | 277 void MIPSDecoder::Unknown(Instr* instr) { |
293 Format(instr, "unknown"); | 278 Format(instr, "unknown"); |
294 } | 279 } |
295 | 280 |
296 | 281 |
297 void MIPSDecoder::DecodeSpecial(Instr* instr) { | 282 void MIPSDecoder::DecodeSpecial(Instr* instr) { |
298 ASSERT(instr->OpcodeField() == SPECIAL); | 283 ASSERT(instr->OpcodeField() == SPECIAL); |
299 switch (instr->FunctionField()) { | 284 switch (instr->FunctionField()) { |
300 case ADDU: { | 285 case ADDU: { |
301 Format(instr, "addu 'rd, 'rs, 'rt"); | 286 Format(instr, "addu 'rd, 'rs, 'rt"); |
302 break; | 287 break; |
303 } | 288 } |
304 case AND: { | 289 case AND: { |
305 Format(instr, "and 'rd, 'rs, 'rt"); | 290 Format(instr, "and 'rd, 'rs, 'rt"); |
306 break; | 291 break; |
307 } | 292 } |
308 case BREAK: { | 293 case BREAK: { |
309 Format(instr, "break 'code"); | 294 Format(instr, "break 'code"); |
310 if (instr->BreakCodeField() == Instr::kStopMessageCode) { | 295 if (instr->BreakCodeField() == Instr::kStopMessageCode) { |
311 const char* message = *reinterpret_cast<const char**>( | 296 const char* message = *reinterpret_cast<const char**>( |
312 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); | 297 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); |
313 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 298 buffer_pos_ += |
314 remaining_size_in_buffer(), | 299 OS::SNPrint(current_position_in_buffer(), |
315 " ; \"%s\"", | 300 remaining_size_in_buffer(), " ; \"%s\"", message); |
316 message); | |
317 } | 301 } |
318 break; | 302 break; |
319 } | 303 } |
320 case DIV: { | 304 case DIV: { |
321 Format(instr, "div 'rs, 'rt"); | 305 Format(instr, "div 'rs, 'rt"); |
322 break; | 306 break; |
323 } | 307 } |
324 case DIVU: { | 308 case DIVU: { |
325 Format(instr, "divu 'rs, 'rt"); | 309 Format(instr, "divu 'rs, 'rt"); |
326 break; | 310 break; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
383 } else if (instr->RsField() == R0) { | 367 } else if (instr->RsField() == R0) { |
384 Format(instr, "mov 'rd, 'rt"); | 368 Format(instr, "mov 'rd, 'rt"); |
385 } else if (instr->RtField() == R0) { | 369 } else if (instr->RtField() == R0) { |
386 Format(instr, "mov 'rd, 'rs"); | 370 Format(instr, "mov 'rd, 'rs"); |
387 } else { | 371 } else { |
388 Format(instr, "or 'rd, 'rs, 'rt"); | 372 Format(instr, "or 'rd, 'rs, 'rt"); |
389 } | 373 } |
390 break; | 374 break; |
391 } | 375 } |
392 case SLL: { | 376 case SLL: { |
393 if ((instr->RdField() == R0) && | 377 if ((instr->RdField() == R0) && (instr->RtField() == R0) && |
394 (instr->RtField() == R0) && | |
395 (instr->SaField() == 0)) { | 378 (instr->SaField() == 0)) { |
396 Format(instr, "nop"); | 379 Format(instr, "nop"); |
397 } else { | 380 } else { |
398 Format(instr, "sll 'rd, 'rt, 'sa"); | 381 Format(instr, "sll 'rd, 'rt, 'sa"); |
399 } | 382 } |
400 break; | 383 break; |
401 } | 384 } |
402 case SLLV: { | 385 case SLLV: { |
403 Format(instr, "sllv 'rd, 'rt, 'rs"); | 386 Format(instr, "sllv 'rd, 'rt, 'rs"); |
404 break; | 387 break; |
(...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
770 break; | 753 break; |
771 } | 754 } |
772 default: { | 755 default: { |
773 Unknown(instr); | 756 Unknown(instr); |
774 break; | 757 break; |
775 } | 758 } |
776 } | 759 } |
777 } | 760 } |
778 | 761 |
779 | 762 |
780 void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 763 void Disassembler::DecodeInstruction(char* hex_buffer, |
781 char* human_buffer, intptr_t human_size, | 764 intptr_t hex_size, |
782 int* out_instr_len, const Code& code, | 765 char* human_buffer, |
783 Object** object, uword pc) { | 766 intptr_t human_size, |
| 767 int* out_instr_len, |
| 768 const Code& code, |
| 769 Object** object, |
| 770 uword pc) { |
784 MIPSDecoder decoder(human_buffer, human_size); | 771 MIPSDecoder decoder(human_buffer, human_size); |
785 Instr* instr = Instr::At(pc); | 772 Instr* instr = Instr::At(pc); |
786 decoder.InstructionDecode(instr); | 773 decoder.InstructionDecode(instr); |
787 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); | 774 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); |
788 if (out_instr_len) { | 775 if (out_instr_len) { |
789 *out_instr_len = Instr::kInstrSize; | 776 *out_instr_len = Instr::kInstrSize; |
790 } | 777 } |
791 | 778 |
792 *object = NULL; | 779 *object = NULL; |
793 if (!code.IsNull()) { | 780 if (!code.IsNull()) { |
794 *object = &Object::Handle(); | 781 *object = &Object::Handle(); |
795 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { | 782 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) { |
796 *object = NULL; | 783 *object = NULL; |
797 } | 784 } |
798 } | 785 } |
799 } | 786 } |
800 | 787 |
801 #endif // !PRODUCT | 788 #endif // !PRODUCT |
802 | 789 |
803 } // namespace dart | 790 } // namespace dart |
804 | 791 |
805 #endif // defined TARGET_ARCH_MIPS | 792 #endif // defined TARGET_ARCH_MIPS |
OLD | NEW |