| 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 |
| (...skipping 13 matching lines...) Expand all Loading... |
| 24 // Writes one disassembled instruction into 'buffer' (0-terminated). | 24 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 25 // Returns true if the instruction was successfully decoded, false otherwise. | 25 // Returns true if the instruction was successfully decoded, false otherwise. |
| 26 void InstructionDecode(Instr* instr); | 26 void InstructionDecode(Instr* instr); |
| 27 | 27 |
| 28 private: | 28 private: |
| 29 // Bottleneck functions to print into the out_buffer. | 29 // Bottleneck functions to print into the out_buffer. |
| 30 void Print(const char* str); | 30 void Print(const char* str); |
| 31 | 31 |
| 32 // Printing of common values. | 32 // Printing of common values. |
| 33 void PrintRegister(Register reg); | 33 void PrintRegister(Register reg); |
| 34 void PrintFRegister(FRegister reg); |
| 35 void PrintFormat(Instr* instr); |
| 34 | 36 |
| 35 int FormatRegister(Instr* instr, const char* format); | 37 int FormatRegister(Instr* instr, const char* format); |
| 38 int FormatFRegister(Instr* instr, const char* format); |
| 36 int FormatOption(Instr* instr, const char* format); | 39 int FormatOption(Instr* instr, const char* format); |
| 37 void Format(Instr* instr, const char* format); | 40 void Format(Instr* instr, const char* format); |
| 38 void Unknown(Instr* instr); | 41 void Unknown(Instr* instr); |
| 39 | 42 |
| 40 void DecodeSpecial(Instr* instr); | 43 void DecodeSpecial(Instr* instr); |
| 41 void DecodeSpecial2(Instr* instr); | 44 void DecodeSpecial2(Instr* instr); |
| 42 void DecodeRegImm(Instr* instr); | 45 void DecodeRegImm(Instr* instr); |
| 46 void DecodeCop1(Instr* instr); |
| 43 | 47 |
| 44 // Convenience functions. | 48 // Convenience functions. |
| 45 char* get_buffer() const { return buffer_; } | 49 char* get_buffer() const { return buffer_; } |
| 46 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 50 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| 47 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 51 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| 48 | 52 |
| 49 char* buffer_; // Decode instructions into this buffer. | 53 char* buffer_; // Decode instructions into this buffer. |
| 50 size_t buffer_size_; // The size of the character buffer. | 54 size_t buffer_size_; // The size of the character buffer. |
| 51 size_t buffer_pos_; // Current character position in buffer. | 55 size_t buffer_pos_; // Current character position in buffer. |
| 52 | 56 |
| (...skipping 19 matching lines...) Expand all Loading... |
| 72 | 76 |
| 73 | 77 |
| 74 static const char* reg_names[kNumberOfCpuRegisters] = { | 78 static const char* reg_names[kNumberOfCpuRegisters] = { |
| 75 "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7" , | 79 "r0" , "r1" , "r2" , "r3" , "r4" , "r5" , "r6" , "r7" , |
| 76 "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", | 80 "r8" , "r9" , "r10", "r11", "r12", "r13", "r14", "r15", |
| 77 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", | 81 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", |
| 78 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", | 82 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31", |
| 79 }; | 83 }; |
| 80 | 84 |
| 81 | 85 |
| 86 static const char* freg_names[kNumberOfFRegisters] = { |
| 87 "f0" , "f1" , "f2" , "f3" , "f4" , "f5" , "f6" , "f7" , |
| 88 "f8" , "f9" , "f10", "f11", "f12", "f13", "f14", "f15", |
| 89 "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", |
| 90 "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31", |
| 91 }; |
| 92 |
| 93 |
| 82 void MIPSDecoder::PrintRegister(Register reg) { | 94 void MIPSDecoder::PrintRegister(Register reg) { |
| 83 ASSERT(0 <= reg); | 95 ASSERT(0 <= reg); |
| 84 ASSERT(reg < kNumberOfCpuRegisters); | 96 ASSERT(reg < kNumberOfCpuRegisters); |
| 85 Print(reg_names[reg]); | 97 Print(reg_names[reg]); |
| 86 } | 98 } |
| 87 | 99 |
| 88 | 100 |
| 101 void MIPSDecoder::PrintFRegister(FRegister reg) { |
| 102 ASSERT(0 <= reg); |
| 103 ASSERT(reg < kNumberOfFRegisters); |
| 104 Print(freg_names[reg]); |
| 105 } |
| 106 |
| 107 |
| 89 // Handle all register based formatting in these functions to reduce the | 108 // Handle all register based formatting in these functions to reduce the |
| 90 // complexity of FormatOption. | 109 // complexity of FormatOption. |
| 91 int MIPSDecoder::FormatRegister(Instr* instr, const char* format) { | 110 int MIPSDecoder::FormatRegister(Instr* instr, const char* format) { |
| 92 ASSERT(format[0] == 'r'); | 111 ASSERT(format[0] == 'r'); |
| 93 switch (format[1]) { | 112 switch (format[1]) { |
| 94 case 's': { // 'rs: Rs register | 113 case 's': { // 'rs: Rs register |
| 95 PrintRegister(instr->RsField()); | 114 PrintRegister(instr->RsField()); |
| 96 return 2; | 115 return 2; |
| 97 } | 116 } |
| 98 case 't': { // 'rt: Rt register | 117 case 't': { // 'rt: Rt register |
| 99 PrintRegister(instr->RtField()); | 118 PrintRegister(instr->RtField()); |
| 100 return 2; | 119 return 2; |
| 101 } | 120 } |
| 102 case 'd': { // 'rd: Rd register | 121 case 'd': { // 'rd: Rd register |
| 103 PrintRegister(instr->RdField()); | 122 PrintRegister(instr->RdField()); |
| 104 return 2; | 123 return 2; |
| 105 } | 124 } |
| 106 } | 125 } |
| 107 UNREACHABLE(); | 126 UNREACHABLE(); |
| 108 return -1; | 127 return -1; |
| 109 } | 128 } |
| 110 | 129 |
| 111 | 130 |
| 131 int MIPSDecoder::FormatFRegister(Instr* instr, const char* format) { |
| 132 ASSERT(format[0] == 'f'); |
| 133 switch (format[1]) { |
| 134 case 's': { // 'fs: Fs register |
| 135 PrintFRegister(instr->FsField()); |
| 136 return 2; |
| 137 } |
| 138 case 't': { // 'ft: Ft register |
| 139 PrintFRegister(instr->FtField()); |
| 140 return 2; |
| 141 } |
| 142 case 'd': { // 'fd: Fd register |
| 143 PrintFRegister(instr->FdField()); |
| 144 return 2; |
| 145 } |
| 146 } |
| 147 UNREACHABLE(); |
| 148 return -1; |
| 149 } |
| 150 |
| 151 |
| 152 void MIPSDecoder::PrintFormat(Instr *instr) { |
| 153 switch (instr->FormatField()) { |
| 154 case FMT_S: { |
| 155 Print("s"); |
| 156 break; |
| 157 } |
| 158 case FMT_D: { |
| 159 Print("d"); |
| 160 break; |
| 161 } |
| 162 case FMT_W: { |
| 163 Print("w"); |
| 164 break; |
| 165 } |
| 166 case FMT_L: { |
| 167 Print("l"); |
| 168 break; |
| 169 } |
| 170 case FMT_PS: { |
| 171 Print("ps"); |
| 172 break; |
| 173 } |
| 174 default: { |
| 175 Print("unknown"); |
| 176 break; |
| 177 } |
| 178 } |
| 179 } |
| 180 |
| 181 |
| 112 // FormatOption takes a formatting string and interprets it based on | 182 // FormatOption takes a formatting string and interprets it based on |
| 113 // the current instructions. The format string points to the first | 183 // the current instructions. The format string points to the first |
| 114 // character of the option string (the option escape has already been | 184 // character of the option string (the option escape has already been |
| 115 // consumed by the caller.) FormatOption returns the number of | 185 // consumed by the caller.) FormatOption returns the number of |
| 116 // characters that were consumed from the formatting string. | 186 // characters that were consumed from the formatting string. |
| 117 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { | 187 int MIPSDecoder::FormatOption(Instr* instr, const char* format) { |
| 118 switch (format[0]) { | 188 switch (format[0]) { |
| 119 case 'c': { | 189 case 'c': { |
| 120 ASSERT(STRING_STARTS_WITH(format, "code")); | 190 ASSERT(STRING_STARTS_WITH(format, "code")); |
| 121 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 191 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 163 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 233 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 164 remaining_size_in_buffer(), | 234 remaining_size_in_buffer(), |
| 165 "%d", | 235 "%d", |
| 166 imm); | 236 imm); |
| 167 } | 237 } |
| 168 return 4; | 238 return 4; |
| 169 } | 239 } |
| 170 case 'r': { | 240 case 'r': { |
| 171 return FormatRegister(instr, format); | 241 return FormatRegister(instr, format); |
| 172 } | 242 } |
| 243 case 'f': { |
| 244 if (format[1] == 'm') { |
| 245 ASSERT(STRING_STARTS_WITH(format, "fmt")); |
| 246 PrintFormat(instr); |
| 247 return 3; |
| 248 } else { |
| 249 return FormatFRegister(instr, format); |
| 250 } |
| 251 } |
| 173 case 's': { | 252 case 's': { |
| 174 ASSERT(STRING_STARTS_WITH(format, "sa")); | 253 ASSERT(STRING_STARTS_WITH(format, "sa")); |
| 175 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 254 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 176 remaining_size_in_buffer(), | 255 remaining_size_in_buffer(), |
| 177 "%d", | 256 "%d", |
| 178 instr->SaField()); | 257 instr->SaField()); |
| 179 return 2; | 258 return 2; |
| 180 } | 259 } |
| 181 default: { | 260 default: { |
| 182 UNREACHABLE(); | 261 UNREACHABLE(); |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 Format(instr, "bltzl 'rs, 'dest"); | 469 Format(instr, "bltzl 'rs, 'dest"); |
| 391 break; | 470 break; |
| 392 } | 471 } |
| 393 default: { | 472 default: { |
| 394 Unknown(instr); | 473 Unknown(instr); |
| 395 break; | 474 break; |
| 396 } | 475 } |
| 397 } | 476 } |
| 398 } | 477 } |
| 399 | 478 |
| 479 void MIPSDecoder::DecodeCop1(Instr* instr) { |
| 480 ASSERT(instr->OpcodeField() == COP1); |
| 481 if (instr->HasFormat()) { |
| 482 // If the rs field is a valid format, then the function field identifies |
| 483 // the instruction. |
| 484 switch (instr->Cop1FunctionField()) { |
| 485 case COP1_ADD: { |
| 486 Format(instr, "add.'fmt 'fd, 'fs, 'ft"); |
| 487 break; |
| 488 } |
| 489 case COP1_MOV: { |
| 490 Format(instr, "mov.'fmt 'fd, 'fs"); |
| 491 break; |
| 492 } |
| 493 default: { |
| 494 Unknown(instr); |
| 495 break; |
| 496 } |
| 497 } |
| 498 } else { |
| 499 // If the rs field isn't a valid format, then it must be a sub-opcode. |
| 500 switch (instr->Cop1SubField()) { |
| 501 case COP1_MF: { |
| 502 if (instr->Bits(0, 11) != 0) { |
| 503 Unknown(instr); |
| 504 } else { |
| 505 Format(instr, "mfc1 'rt, 'fs"); |
| 506 } |
| 507 break; |
| 508 } |
| 509 case COP1_MT: { |
| 510 if (instr->Bits(0, 11) != 0) { |
| 511 Unknown(instr); |
| 512 } else { |
| 513 Format(instr, "mtc1 'rt, 'fs"); |
| 514 } |
| 515 break; |
| 516 } |
| 517 default: { |
| 518 Unknown(instr); |
| 519 break; |
| 520 } |
| 521 } |
| 522 } |
| 523 } |
| 400 | 524 |
| 401 void MIPSDecoder::InstructionDecode(Instr* instr) { | 525 void MIPSDecoder::InstructionDecode(Instr* instr) { |
| 402 switch (instr->OpcodeField()) { | 526 switch (instr->OpcodeField()) { |
| 403 case SPECIAL: { | 527 case SPECIAL: { |
| 404 DecodeSpecial(instr); | 528 DecodeSpecial(instr); |
| 405 break; | 529 break; |
| 406 } | 530 } |
| 407 case SPECIAL2: { | 531 case SPECIAL2: { |
| 408 DecodeSpecial2(instr); | 532 DecodeSpecial2(instr); |
| 409 break; | 533 break; |
| 410 } | 534 } |
| 411 case REGIMM: { | 535 case REGIMM: { |
| 412 DecodeRegImm(instr); | 536 DecodeRegImm(instr); |
| 413 break; | 537 break; |
| 414 } | 538 } |
| 539 case COP1: { |
| 540 DecodeCop1(instr); |
| 541 break; |
| 542 } |
| 415 case ADDIU: { | 543 case ADDIU: { |
| 416 Format(instr, "addiu 'rt, 'rs, 'imms"); | 544 Format(instr, "addiu 'rt, 'rs, 'imms"); |
| 417 break; | 545 break; |
| 418 } | 546 } |
| 419 case ANDI: { | 547 case ANDI: { |
| 420 Format(instr, "andi 'rt, 'rs, 'immu"); | 548 Format(instr, "andi 'rt, 'rs, 'immu"); |
| 421 break; | 549 break; |
| 422 } | 550 } |
| 423 case BEQ: { | 551 case BEQ: { |
| 424 Format(instr, "beq 'rs, 'rt, 'dest"); | 552 Format(instr, "beq 'rs, 'rt, 'dest"); |
| (...skipping 28 matching lines...) Expand all Loading... |
| 453 break; | 581 break; |
| 454 } | 582 } |
| 455 case LB: { | 583 case LB: { |
| 456 Format(instr, "lb 'rt, 'imms('rs)"); | 584 Format(instr, "lb 'rt, 'imms('rs)"); |
| 457 break; | 585 break; |
| 458 } | 586 } |
| 459 case LBU: { | 587 case LBU: { |
| 460 Format(instr, "lbu 'rt, 'imms('rs)"); | 588 Format(instr, "lbu 'rt, 'imms('rs)"); |
| 461 break; | 589 break; |
| 462 } | 590 } |
| 591 case LDC1: { |
| 592 Format(instr, "ldc1 'ft, 'imms('rs)"); |
| 593 break; |
| 594 } |
| 463 case LH: { | 595 case LH: { |
| 464 Format(instr, "lh 'rt, 'imms('rs)"); | 596 Format(instr, "lh 'rt, 'imms('rs)"); |
| 465 break; | 597 break; |
| 466 } | 598 } |
| 467 case LUI: { | 599 case LUI: { |
| 468 Format(instr, "lui 'rt, 'immu"); | 600 Format(instr, "lui 'rt, 'immu"); |
| 469 break; | 601 break; |
| 470 } | 602 } |
| 471 case LW: { | 603 case LW: { |
| 472 Format(instr, "lw 'rt, 'imms('rs)"); | 604 Format(instr, "lw 'rt, 'imms('rs)"); |
| 473 break; | 605 break; |
| 474 } | 606 } |
| 607 case LWC1: { |
| 608 Format(instr, "lwc1 'ft, 'imms('rs)"); |
| 609 break; |
| 610 } |
| 475 case ORI: { | 611 case ORI: { |
| 476 Format(instr, "ori 'rt, 'rs, 'immu"); | 612 Format(instr, "ori 'rt, 'rs, 'immu"); |
| 477 break; | 613 break; |
| 478 } | 614 } |
| 479 case SB: { | 615 case SB: { |
| 480 Format(instr, "sb 'rt, 'imms('rs)"); | 616 Format(instr, "sb 'rt, 'imms('rs)"); |
| 481 break; | 617 break; |
| 482 } | 618 } |
| 483 case SH: { | 619 case SH: { |
| 484 Format(instr, "sh 'rt, 'imms('rs)"); | 620 Format(instr, "sh 'rt, 'imms('rs)"); |
| 485 break; | 621 break; |
| 486 } | 622 } |
| 623 case SDC1: { |
| 624 Format(instr, "sdc1 'ft, 'imms('rs)"); |
| 625 break; |
| 626 } |
| 487 case SW: { | 627 case SW: { |
| 488 Format(instr, "sw 'rt, 'imms('rs)"); | 628 Format(instr, "sw 'rt, 'imms('rs)"); |
| 489 break; | 629 break; |
| 490 } | 630 } |
| 631 case SWC1: { |
| 632 Format(instr, "swc1 'ft, 'imms('rs)"); |
| 633 break; |
| 634 } |
| 491 default: { | 635 default: { |
| 492 Unknown(instr); | 636 Unknown(instr); |
| 493 break; | 637 break; |
| 494 } | 638 } |
| 495 } | 639 } |
| 496 } | 640 } |
| 497 | 641 |
| 498 | 642 |
| 499 void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 643 void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, |
| 500 char* human_buffer, intptr_t human_size, | 644 char* human_buffer, intptr_t human_size, |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 539 pc); | 683 pc); |
| 540 pc += instruction_length; | 684 pc += instruction_length; |
| 541 } | 685 } |
| 542 | 686 |
| 543 return; | 687 return; |
| 544 } | 688 } |
| 545 | 689 |
| 546 } // namespace dart | 690 } // namespace dart |
| 547 | 691 |
| 548 #endif // defined TARGET_ARCH_MIPS | 692 #endif // defined TARGET_ARCH_MIPS |
| OLD | NEW |