| 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 { | 13 class MIPSDecoder : public ValueObject { |
| 14 public: | 14 public: |
| 15 MIPSDecoder(char* buffer, size_t buffer_size) | 15 MIPSDecoder(char* buffer, size_t buffer_size) |
| 16 : buffer_(buffer), | 16 : buffer_(buffer), |
| 17 buffer_size_(buffer_size), | 17 buffer_size_(buffer_size), |
| 18 buffer_pos_(0) { | 18 buffer_pos_(0), |
| 19 decode_failure_(false) { |
| 19 buffer_[buffer_pos_] = '\0'; | 20 buffer_[buffer_pos_] = '\0'; |
| 20 } | 21 } |
| 21 | 22 |
| 22 ~MIPSDecoder() {} | 23 ~MIPSDecoder() {} |
| 23 | 24 |
| 24 // Writes one disassembled instruction into 'buffer' (0-terminated). | 25 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 26 // Returns true if the instruction was successfully decoded, false otherwise. |
| 25 void InstructionDecode(Instr* instr); | 27 void InstructionDecode(Instr* instr); |
| 26 | 28 |
| 29 void set_decode_failure(bool b) { decode_failure_ = b; } |
| 30 bool decode_failure() const { return decode_failure_; } |
| 31 |
| 27 private: | 32 private: |
| 28 // Bottleneck functions to print into the out_buffer. | 33 // Bottleneck functions to print into the out_buffer. |
| 29 void Print(const char* str); | 34 void Print(const char* str); |
| 30 | 35 |
| 31 // Printing of common values. | 36 // Printing of common values. |
| 32 void PrintRegister(Register reg); | 37 void PrintRegister(Register reg); |
| 33 | 38 |
| 34 int FormatRegister(Instr* instr, const char* format); | 39 int FormatRegister(Instr* instr, const char* format); |
| 35 int FormatOption(Instr* instr, const char* format); | 40 int FormatOption(Instr* instr, const char* format); |
| 36 void Format(Instr* instr, const char* format); | 41 void Format(Instr* instr, const char* format); |
| 42 void Unknown(Instr* instr); |
| 37 | 43 |
| 38 void DecodeSpecial(Instr* instr); | 44 void DecodeSpecial(Instr* instr); |
| 39 void DecodeSpecial2(Instr* instr); | 45 void DecodeSpecial2(Instr* instr); |
| 40 void DecodeSpecial3(Instr* instr); | |
| 41 | 46 |
| 42 // Convenience functions. | 47 // Convenience functions. |
| 43 char* get_buffer() const { return buffer_; } | 48 char* get_buffer() const { return buffer_; } |
| 44 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 49 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| 45 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 50 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| 46 | 51 |
| 47 char* buffer_; // Decode instructions into this buffer. | 52 char* buffer_; // Decode instructions into this buffer. |
| 48 size_t buffer_size_; // The size of the character buffer. | 53 size_t buffer_size_; // The size of the character buffer. |
| 49 size_t buffer_pos_; // Current character position in buffer. | 54 size_t buffer_pos_; // Current character position in buffer. |
| 50 | 55 |
| 56 bool decode_failure_; // Set to true when a failure to decode is detected. |
| 57 |
| 51 DISALLOW_ALLOCATION(); | 58 DISALLOW_ALLOCATION(); |
| 52 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); | 59 DISALLOW_COPY_AND_ASSIGN(MIPSDecoder); |
| 53 }; | 60 }; |
| 54 | 61 |
| 55 | 62 |
| 56 // Support for assertions in the MIPSDecoder formatting functions. | 63 // Support for assertions in the MIPSDecoder formatting functions. |
| 57 #define STRING_STARTS_WITH(string, compare_string) \ | 64 #define STRING_STARTS_WITH(string, compare_string) \ |
| 58 (strncmp(string, compare_string, strlen(compare_string)) == 0) | 65 (strncmp(string, compare_string, strlen(compare_string)) == 0) |
| 59 | 66 |
| 60 | 67 |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 } | 114 } |
| 108 | 115 |
| 109 | 116 |
| 110 // FormatOption takes a formatting string and interprets it based on | 117 // FormatOption takes a formatting string and interprets it based on |
| 111 // the current instructions. The format string points to the first | 118 // the current instructions. The format string points to the first |
| 112 // character of the option string (the option escape has already been | 119 // character of the option string (the option escape has already been |
| 113 // consumed by the caller.) FormatOption returns the number of | 120 // consumed by the caller.) FormatOption returns the number of |
| 114 // characters that were consumed from the formatting string. | 121 // characters that were consumed from the formatting string. |
| 115 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | 122 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { |
| 116 switch (format[0]) { | 123 switch (format[0]) { |
| 124 case 'c': { |
| 125 ASSERT(STRING_STARTS_WITH(format, "code")); |
| 126 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 127 remaining_size_in_buffer(), |
| 128 "%d", instr->BreakCodeField()); |
| 129 return 4; |
| 130 } |
| 117 case 'h': { | 131 case 'h': { |
| 118 ASSERT(STRING_STARTS_WITH(format, "hint")); | 132 ASSERT(STRING_STARTS_WITH(format, "hint")); |
| 119 if (instr->SaField() != 0) { | 133 if (instr->SaField() == 0x10) { |
| 120 UNIMPLEMENTED(); | 134 // The high bit of the SA field is the only one that means something for |
| 135 // JALR and JR. TODO(zra): Fill in the other cases for PREF if needed. |
| 136 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 137 remaining_size_in_buffer(), |
| 138 ".hb"); |
| 139 } else if (instr->SaField() != 0) { |
| 140 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 141 remaining_size_in_buffer(), |
| 142 ".unknown"); |
| 121 } | 143 } |
| 122 return 4; | 144 return 4; |
| 123 } | 145 } |
| 124 case 'i': { | 146 case 'i': { |
| 125 ASSERT(STRING_STARTS_WITH(format, "imm")); | 147 ASSERT(STRING_STARTS_WITH(format, "imm")); |
| 126 if (format[3] == 'u') { | 148 if (format[3] == 'u') { |
| 127 int32_t imm = instr->UImmField(); | 149 int32_t imm = instr->UImmField(); |
| 128 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 150 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 129 remaining_size_in_buffer(), | 151 remaining_size_in_buffer(), |
| 130 "0x%x", | 152 "0x%x", |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 169 format += FormatOption(instr, format); | 191 format += FormatOption(instr, format); |
| 170 } else { | 192 } else { |
| 171 buffer_[buffer_pos_++] = cur; | 193 buffer_[buffer_pos_++] = cur; |
| 172 } | 194 } |
| 173 cur = *format++; | 195 cur = *format++; |
| 174 } | 196 } |
| 175 buffer_[buffer_pos_] = '\0'; | 197 buffer_[buffer_pos_] = '\0'; |
| 176 } | 198 } |
| 177 | 199 |
| 178 | 200 |
| 201 // For currently unimplemented decodings the disassembler calls Unknown(instr) |
| 202 // which will just print "unknown" of the instruction bits. |
| 203 void MIPSDecoder::Unknown(Instr* instr) { |
| 204 Format(instr, "unknown"); |
| 205 set_decode_failure(true); |
| 206 } |
| 207 |
| 208 |
| 179 void MIPSDecoder::DecodeSpecial(Instr* instr) { | 209 void MIPSDecoder::DecodeSpecial(Instr* instr) { |
| 180 ASSERT(instr->OpcodeField() == SPECIAL); | 210 ASSERT(instr->OpcodeField() == SPECIAL); |
| 181 switch (instr->FunctionField()) { | 211 switch (instr->FunctionField()) { |
| 182 case ADDU: { | 212 case ADDU: { |
| 183 Format(instr, "addu 'rd, 'rs, 'rt"); | 213 Format(instr, "addu 'rd, 'rs, 'rt"); |
| 184 break; | 214 break; |
| 185 } | 215 } |
| 186 case AND: { | 216 case AND: { |
| 187 Format(instr, "and 'rd, 'rs, 'rt"); | 217 Format(instr, "and 'rd, 'rs, 'rt"); |
| 188 break; | 218 break; |
| 189 } | 219 } |
| 220 case BREAK: { |
| 221 Format(instr, "break 'code"); |
| 222 break; |
| 223 } |
| 190 case DIV: { | 224 case DIV: { |
| 191 Format(instr, "div 'rs, 'rt"); | 225 Format(instr, "div 'rs, 'rt"); |
| 192 break; | 226 break; |
| 193 } | 227 } |
| 194 case DIVU: { | 228 case DIVU: { |
| 195 Format(instr, "divu 'rs, 'rt"); | 229 Format(instr, "divu 'rs, 'rt"); |
| 196 break; | 230 break; |
| 197 } | 231 } |
| 198 case MFHI: { | 232 case MFHI: { |
| 199 Format(instr, "mfhi 'rd"); | 233 Format(instr, "mfhi 'rd"); |
| 200 break; | 234 break; |
| 201 } | 235 } |
| 202 case MFLO: { | 236 case MFLO: { |
| 203 Format(instr, "mflo 'rd"); | 237 Format(instr, "mflo 'rd"); |
| 204 break; | 238 break; |
| 205 } | 239 } |
| 206 case SLL: { | 240 case SLL: { |
| 207 if ((instr->RdField() == R0) && | 241 if ((instr->RdField() == R0) && |
| 208 (instr->RtField() == R0) && | 242 (instr->RtField() == R0) && |
| 209 (instr->SaField() == 0)) { | 243 (instr->SaField() == 0)) { |
| 210 Format(instr, "nop"); | 244 Format(instr, "nop"); |
| 211 } else { | 245 } else { |
| 212 Format(instr, "sll 'rd, 'rt, 'sa"); | 246 Format(instr, "sll 'rd, 'rt, 'sa"); |
| 213 } | 247 } |
| 214 break; | 248 break; |
| 215 } | 249 } |
| 216 case JR: { | 250 case JR: { |
| 217 ASSERT(instr->RtField() == R0); | |
| 218 ASSERT(instr->RdField() == R0); | |
| 219 Format(instr, "jr'hint 'rs"); | 251 Format(instr, "jr'hint 'rs"); |
| 220 break; | 252 break; |
| 221 } | 253 } |
| 222 default: { | 254 default: { |
| 223 OS::PrintErr("DecodeSpecial: 0x%x\n", instr->InstructionBits()); | 255 Unknown(instr); |
| 224 UNREACHABLE(); | |
| 225 break; | 256 break; |
| 226 } | 257 } |
| 227 } | 258 } |
| 228 } | 259 } |
| 229 | 260 |
| 230 | 261 |
| 231 void MIPSDecoder::DecodeSpecial2(Instr* instr) { | 262 void MIPSDecoder::DecodeSpecial2(Instr* instr) { |
| 232 ASSERT(instr->OpcodeField() == SPECIAL2); | 263 ASSERT(instr->OpcodeField() == SPECIAL2); |
| 233 switch (instr->FunctionField()) { | 264 switch (instr->FunctionField()) { |
| 234 case CLO: { | 265 case CLO: { |
| 235 Format(instr, "clo 'rd, 'rs"); | 266 Format(instr, "clo 'rd, 'rs"); |
| 236 break; | 267 break; |
| 237 } | 268 } |
| 238 case CLZ: { | 269 case CLZ: { |
| 239 Format(instr, "clz 'rd, 'rs"); | 270 Format(instr, "clz 'rd, 'rs"); |
| 240 break; | 271 break; |
| 241 } | 272 } |
| 242 default: { | 273 default: { |
| 243 OS::PrintErr("DecodeSpecial2: 0x%x\n", instr->InstructionBits()); | 274 Unknown(instr); |
| 244 UNREACHABLE(); | |
| 245 break; | |
| 246 } | |
| 247 } | |
| 248 } | |
| 249 | |
| 250 | |
| 251 void MIPSDecoder::DecodeSpecial3(Instr* instr) { | |
| 252 ASSERT(instr->OpcodeField() == SPECIAL3); | |
| 253 switch (instr->FunctionField()) { | |
| 254 default: { | |
| 255 OS::PrintErr("DecodeSpecial3: 0x%x\n", instr->InstructionBits()); | |
| 256 UNREACHABLE(); | |
| 257 break; | 275 break; |
| 258 } | 276 } |
| 259 } | 277 } |
| 260 } | 278 } |
| 261 | 279 |
| 262 | 280 |
| 263 void MIPSDecoder::InstructionDecode(Instr* instr) { | 281 void MIPSDecoder::InstructionDecode(Instr* instr) { |
| 264 switch (instr->OpcodeField()) { | 282 switch (instr->OpcodeField()) { |
| 265 case SPECIAL: { | 283 case SPECIAL: { |
| 266 DecodeSpecial(instr); | 284 DecodeSpecial(instr); |
| 267 break; | 285 break; |
| 268 } | 286 } |
| 269 case SPECIAL2: { | 287 case SPECIAL2: { |
| 270 DecodeSpecial2(instr); | 288 DecodeSpecial2(instr); |
| 271 break; | 289 break; |
| 272 } | 290 } |
| 273 case SPECIAL3: { | |
| 274 DecodeSpecial3(instr); | |
| 275 break; | |
| 276 } | |
| 277 case ADDIU: { | 291 case ADDIU: { |
| 278 Format(instr, "addiu 'rt, 'rs, 'imms"); | 292 Format(instr, "addiu 'rt, 'rs, 'imms"); |
| 279 break; | 293 break; |
| 280 } | 294 } |
| 281 case ANDI: { | 295 case ANDI: { |
| 282 Format(instr, "andi 'rt, 'rs, 'immu"); | 296 Format(instr, "andi 'rt, 'rs, 'immu"); |
| 283 break; | 297 break; |
| 284 } | 298 } |
| 285 case LB: { | 299 case LB: { |
| 286 Format(instr, "lb 'rt, 'imms('rs)"); | 300 Format(instr, "lb 'rt, 'imms('rs)"); |
| (...skipping 25 matching lines...) Expand all Loading... |
| 312 } | 326 } |
| 313 case SH: { | 327 case SH: { |
| 314 Format(instr, "sh 'rt, 'imms('rs)"); | 328 Format(instr, "sh 'rt, 'imms('rs)"); |
| 315 break; | 329 break; |
| 316 } | 330 } |
| 317 case SW: { | 331 case SW: { |
| 318 Format(instr, "sw 'rt, 'imms('rs)"); | 332 Format(instr, "sw 'rt, 'imms('rs)"); |
| 319 break; | 333 break; |
| 320 } | 334 } |
| 321 default: { | 335 default: { |
| 322 OS::PrintErr("Undecoded instruction: 0x%x\n", instr->InstructionBits()); | 336 Unknown(instr); |
| 323 UNREACHABLE(); | |
| 324 break; | 337 break; |
| 325 } | 338 } |
| 326 } | 339 } |
| 327 } | 340 } |
| 328 | 341 |
| 329 | 342 |
| 330 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 343 bool Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, |
| 331 char* human_buffer, intptr_t human_size, | 344 char* human_buffer, intptr_t human_size, |
| 332 uword pc) { | 345 int *out_instr_len, uword pc) { |
| 333 MIPSDecoder decoder(human_buffer, human_size); | 346 MIPSDecoder decoder(human_buffer, human_size); |
| 334 Instr* instr = Instr::At(pc); | 347 Instr* instr = Instr::At(pc); |
| 335 decoder.InstructionDecode(instr); | 348 decoder.InstructionDecode(instr); |
| 336 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); | 349 OS::SNPrint(hex_buffer, hex_size, "%08x", instr->InstructionBits()); |
| 337 return Instr::kInstrSize; | 350 if (out_instr_len) { |
| 351 *out_instr_len = Instr::kInstrSize; |
| 352 } |
| 353 return !decoder.decode_failure(); |
| 338 } | 354 } |
| 339 | 355 |
| 340 | 356 |
| 341 void Disassembler::Disassemble(uword start, | 357 bool Disassembler::Disassemble(uword start, |
| 342 uword end, | 358 uword end, |
| 343 DisassemblyFormatter* formatter, | 359 DisassemblyFormatter* formatter, |
| 344 const Code::Comments& comments) { | 360 const Code::Comments& comments) { |
| 345 ASSERT(formatter != NULL); | 361 ASSERT(formatter != NULL); |
| 362 bool success = true; |
| 346 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. | 363 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. |
| 347 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. | 364 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. |
| 348 uword pc = start; | 365 uword pc = start; |
| 349 intptr_t comment_finger = 0; | 366 intptr_t comment_finger = 0; |
| 350 while (pc < end) { | 367 while (pc < end) { |
| 351 const intptr_t offset = pc - start; | 368 const intptr_t offset = pc - start; |
| 352 while (comment_finger < comments.Length() && | 369 while (comment_finger < comments.Length() && |
| 353 comments.PCOffsetAt(comment_finger) <= offset) { | 370 comments.PCOffsetAt(comment_finger) <= offset) { |
| 354 formatter->Print( | 371 formatter->Print( |
| 355 " ;; %s\n", | 372 " ;; %s\n", |
| 356 String::Handle(comments.CommentAt(comment_finger)).ToCString()); | 373 String::Handle(comments.CommentAt(comment_finger)).ToCString()); |
| 357 comment_finger++; | 374 comment_finger++; |
| 358 } | 375 } |
| 359 int instruction_length = DecodeInstruction(hex_buffer, | 376 int instruction_length; |
| 360 sizeof(hex_buffer), | 377 bool res = DecodeInstruction(hex_buffer, sizeof(hex_buffer), |
| 361 human_buffer, | 378 human_buffer, sizeof(human_buffer), |
| 362 sizeof(human_buffer), | 379 &instruction_length, pc); |
| 363 pc); | 380 if (!res) { |
| 381 success = false; |
| 382 } |
| 364 formatter->ConsumeInstruction(hex_buffer, | 383 formatter->ConsumeInstruction(hex_buffer, |
| 365 sizeof(hex_buffer), | 384 sizeof(hex_buffer), |
| 366 human_buffer, | 385 human_buffer, |
| 367 sizeof(human_buffer), | 386 sizeof(human_buffer), |
| 368 pc); | 387 pc); |
| 369 pc += instruction_length; | 388 pc += instruction_length; |
| 370 } | 389 } |
| 390 |
| 391 return success; |
| 371 } | 392 } |
| 372 | 393 |
| 373 } // namespace dart | 394 } // namespace dart |
| 374 | 395 |
| 375 #endif // defined TARGET_ARCH_MIPS | 396 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |