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 |