| 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_ARM. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM. |
| 8 #if defined(TARGET_ARCH_ARM) | 8 #if defined(TARGET_ARCH_ARM) |
| 9 #include "platform/assert.h" | 9 #include "platform/assert.h" |
| 10 | 10 |
| (...skipping 15 matching lines...) Expand all Loading... |
| 26 void InstructionDecode(uword pc); | 26 void InstructionDecode(uword pc); |
| 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(int reg); | 33 void PrintRegister(int reg); |
| 34 void PrintSRegister(int reg); | 34 void PrintSRegister(int reg); |
| 35 void PrintDRegister(int reg); | 35 void PrintDRegister(int reg); |
| 36 void PrintQRegister(int reg); |
| 36 void PrintCondition(Instr* instr); | 37 void PrintCondition(Instr* instr); |
| 37 void PrintShiftRm(Instr* instr); | 38 void PrintShiftRm(Instr* instr); |
| 38 void PrintShiftImm(Instr* instr); | 39 void PrintShiftImm(Instr* instr); |
| 39 void PrintPU(Instr* instr); | 40 void PrintPU(Instr* instr); |
| 40 | 41 |
| 41 // Handle formatting of instructions and their options. | 42 // Handle formatting of instructions and their options. |
| 42 int FormatRegister(Instr* instr, const char* option); | 43 int FormatRegister(Instr* instr, const char* option); |
| 43 int FormatSRegister(Instr* instr, const char* option); | 44 int FormatSRegister(Instr* instr, const char* option); |
| 44 int FormatDRegister(Instr* instr, const char* option); | 45 int FormatDRegister(Instr* instr, const char* option); |
| 46 int FormatQRegister(Instr* instr, const char* option); |
| 45 int FormatOption(Instr* instr, const char* option); | 47 int FormatOption(Instr* instr, const char* option); |
| 46 void Format(Instr* instr, const char* format); | 48 void Format(Instr* instr, const char* format); |
| 47 void Unknown(Instr* instr); | 49 void Unknown(Instr* instr); |
| 48 | 50 |
| 49 // Each of these functions decodes one particular instruction type, a 3-bit | 51 // Each of these functions decodes one particular instruction type, a 3-bit |
| 50 // field in the instruction encoding. | 52 // field in the instruction encoding. |
| 51 // Types 0 and 1 are combined as they are largely the same except for the way | 53 // Types 0 and 1 are combined as they are largely the same except for the way |
| 52 // they interpret the shifter operand. | 54 // they interpret the shifter operand. |
| 53 void DecodeType01(Instr* instr); | 55 void DecodeType01(Instr* instr); |
| 54 void DecodeType2(Instr* instr); | 56 void DecodeType2(Instr* instr); |
| 55 void DecodeType3(Instr* instr); | 57 void DecodeType3(Instr* instr); |
| 56 void DecodeType4(Instr* instr); | 58 void DecodeType4(Instr* instr); |
| 57 void DecodeType5(Instr* instr); | 59 void DecodeType5(Instr* instr); |
| 58 void DecodeType6(Instr* instr); | 60 void DecodeType6(Instr* instr); |
| 59 void DecodeType7(Instr* instr); | 61 void DecodeType7(Instr* instr); |
| 62 void DecodeSIMDDataProcessing(Instr* instr); |
| 60 | 63 |
| 61 // Convenience functions. | 64 // Convenience functions. |
| 62 char* get_buffer() const { return buffer_; } | 65 char* get_buffer() const { return buffer_; } |
| 63 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } | 66 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| 64 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } | 67 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| 65 | 68 |
| 66 char* buffer_; // Decode instructions into this buffer. | 69 char* buffer_; // Decode instructions into this buffer. |
| 67 size_t buffer_size_; // The size of the character buffer. | 70 size_t buffer_size_; // The size of the character buffer. |
| 68 size_t buffer_pos_; // Current character position in buffer. | 71 size_t buffer_pos_; // Current character position in buffer. |
| 69 | 72 |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 130 | 133 |
| 131 void ARMDecoder::PrintDRegister(int reg) { | 134 void ARMDecoder::PrintDRegister(int reg) { |
| 132 ASSERT(0 <= reg); | 135 ASSERT(0 <= reg); |
| 133 ASSERT(reg < kNumberOfDRegisters); | 136 ASSERT(reg < kNumberOfDRegisters); |
| 134 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 137 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 135 remaining_size_in_buffer(), | 138 remaining_size_in_buffer(), |
| 136 "d%d", reg); | 139 "d%d", reg); |
| 137 } | 140 } |
| 138 | 141 |
| 139 | 142 |
| 143 void ARMDecoder::PrintQRegister(int reg) { |
| 144 ASSERT(0 <= reg); |
| 145 ASSERT(reg < kNumberOfQRegisters); |
| 146 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 147 remaining_size_in_buffer(), |
| 148 "q%d", reg); |
| 149 } |
| 150 |
| 151 |
| 140 // These shift names are defined in a way to match the native disassembler | 152 // These shift names are defined in a way to match the native disassembler |
| 141 // formatting. See for example the command "objdump -d <binary file>". | 153 // formatting. See for example the command "objdump -d <binary file>". |
| 142 static const char* shift_names[kMaxShift] = { | 154 static const char* shift_names[kMaxShift] = { |
| 143 "lsl", "lsr", "asr", "ror" | 155 "lsl", "lsr", "asr", "ror" |
| 144 }; | 156 }; |
| 145 | 157 |
| 146 | 158 |
| 147 // Print the register shift operands for the instruction. Generally used for | 159 // Print the register shift operands for the instruction. Generally used for |
| 148 // data processing instructions. | 160 // data processing instructions. |
| 149 void ARMDecoder::PrintShiftRm(Instr* instr) { | 161 void ARMDecoder::PrintShiftRm(Instr* instr) { |
| (...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 } | 356 } |
| 345 } | 357 } |
| 346 Print("}"); | 358 Print("}"); |
| 347 return 5; | 359 return 5; |
| 348 } | 360 } |
| 349 UNREACHABLE(); | 361 UNREACHABLE(); |
| 350 return -1; | 362 return -1; |
| 351 } | 363 } |
| 352 | 364 |
| 353 | 365 |
| 366 int ARMDecoder::FormatQRegister(Instr* instr, const char* format) { |
| 367 ASSERT(format[0] == 'q'); |
| 368 if (format[1] == 'n') { // 'qn: Qn register |
| 369 int reg = instr->QnField(); |
| 370 PrintQRegister(reg); |
| 371 return 2; |
| 372 } else if (format[1] == 'd') { // 'qd: Qd register |
| 373 int reg = instr->QdField(); |
| 374 PrintQRegister(reg); |
| 375 return 2; |
| 376 } else if (format[1] == 'm') { // 'qm: Qm register |
| 377 int reg = instr->QmField(); |
| 378 PrintQRegister(reg); |
| 379 return 2; |
| 380 } |
| 381 UNREACHABLE(); |
| 382 return -1; |
| 383 } |
| 384 |
| 385 |
| 354 // FormatOption takes a formatting string and interprets it based on | 386 // FormatOption takes a formatting string and interprets it based on |
| 355 // the current instructions. The format string points to the first | 387 // the current instructions. The format string points to the first |
| 356 // character of the option string (the option escape has already been | 388 // character of the option string (the option escape has already been |
| 357 // consumed by the caller.) FormatOption returns the number of | 389 // consumed by the caller.) FormatOption returns the number of |
| 358 // characters that were consumed from the formatting string. | 390 // characters that were consumed from the formatting string. |
| 359 int ARMDecoder::FormatOption(Instr* instr, const char* format) { | 391 int ARMDecoder::FormatOption(Instr* instr, const char* format) { |
| 360 switch (format[0]) { | 392 switch (format[0]) { |
| 361 case 'a': { // 'a: accumulate multiplies | 393 case 'a': { // 'a: accumulate multiplies |
| 362 if (instr->Bit(21) == 0) { | 394 if (instr->Bit(21) == 0) { |
| 363 Print("ul"); | 395 Print("ul"); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 384 uword destination = reinterpret_cast<uword>(instr) + off; | 416 uword destination = reinterpret_cast<uword>(instr) + off; |
| 385 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 417 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 386 remaining_size_in_buffer(), | 418 remaining_size_in_buffer(), |
| 387 "%#"Px"", | 419 "%#"Px"", |
| 388 destination); | 420 destination); |
| 389 return 4; | 421 return 4; |
| 390 } else { | 422 } else { |
| 391 return FormatDRegister(instr, format); | 423 return FormatDRegister(instr, format); |
| 392 } | 424 } |
| 393 } | 425 } |
| 426 case 'q': { |
| 427 return FormatQRegister(instr, format); |
| 428 } |
| 394 case 'i': { // 'imm12_4, imm4_12, immf, or immd | 429 case 'i': { // 'imm12_4, imm4_12, immf, or immd |
| 395 uint16_t immed16; | 430 uint16_t immed16; |
| 396 if (format[3] == 'f') { | 431 if (format[3] == 'f') { |
| 397 ASSERT(STRING_STARTS_WITH(format, "immf")); | 432 ASSERT(STRING_STARTS_WITH(format, "immf")); |
| 398 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 433 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 399 remaining_size_in_buffer(), | 434 remaining_size_in_buffer(), |
| 400 "%f", | 435 "%f", |
| 401 instr->ImmFloatField()); | 436 instr->ImmFloatField()); |
| 402 return 4; | 437 return 4; |
| 403 } else if (format[3] == 'd') { | 438 } else if (format[3] == 'd') { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 439 } | 474 } |
| 440 case 'o': { | 475 case 'o': { |
| 441 if (format[3] == '1') { | 476 if (format[3] == '1') { |
| 442 if (format[4] == '0') { | 477 if (format[4] == '0') { |
| 443 // 'off10: 10-bit offset for VFP load and store instructions | 478 // 'off10: 10-bit offset for VFP load and store instructions |
| 444 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 479 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 445 remaining_size_in_buffer(), | 480 remaining_size_in_buffer(), |
| 446 "%d", | 481 "%d", |
| 447 instr->Bits(0, 8) << 2); | 482 instr->Bits(0, 8) << 2); |
| 448 } else { | 483 } else { |
| 449 // 'off12: 12-bit offset for load and store instructions | 484 // 'off12: 12-bit offset for load and store instructions. |
| 450 ASSERT(STRING_STARTS_WITH(format, "off12")); | 485 ASSERT(STRING_STARTS_WITH(format, "off12")); |
| 451 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 486 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 452 remaining_size_in_buffer(), | 487 remaining_size_in_buffer(), |
| 453 "%d", | 488 "%d", |
| 454 instr->Offset12Field()); | 489 instr->Offset12Field()); |
| 455 } | 490 } |
| 456 return 5; | 491 return 5; |
| 457 } | 492 } |
| 458 // 'off8: 8-bit offset for extra load and store instructions | 493 // 'off8: 8-bit offset for extra load and store instructions. |
| 459 ASSERT(STRING_STARTS_WITH(format, "off8")); | 494 ASSERT(STRING_STARTS_WITH(format, "off8")); |
| 460 int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); | 495 int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
| 461 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 496 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 462 remaining_size_in_buffer(), | 497 remaining_size_in_buffer(), |
| 463 "%d", | 498 "%d", |
| 464 offs8); | 499 offs8); |
| 465 return 4; | 500 return 4; |
| 466 } | 501 } |
| 467 case 'p': { // 'pu: P and U bits for load and store instructions | 502 case 'p': { // 'pu: P and U bits for load and store instructions. |
| 468 ASSERT(STRING_STARTS_WITH(format, "pu")); | 503 ASSERT(STRING_STARTS_WITH(format, "pu")); |
| 469 PrintPU(instr); | 504 PrintPU(instr); |
| 470 return 2; | 505 return 2; |
| 471 } | 506 } |
| 472 case 'r': { | 507 case 'r': { |
| 473 return FormatRegister(instr, format); | 508 return FormatRegister(instr, format); |
| 474 } | 509 } |
| 475 case 's': { | 510 case 's': { |
| 476 if (format[1] == 'h') { // 'shift_op or 'shift_rm | 511 if (format[1] == 'h') { // 'shift_op or 'shift_rm |
| 477 if (format[6] == 'o') { // 'shift_op | 512 if (format[6] == 'o') { // 'shift_op |
| (...skipping 10 matching lines...) Expand all Loading... |
| 488 PrintShiftRm(instr); | 523 PrintShiftRm(instr); |
| 489 return 8; | 524 return 8; |
| 490 } | 525 } |
| 491 } else if (format[1] == 'v') { // 'svc | 526 } else if (format[1] == 'v') { // 'svc |
| 492 ASSERT(STRING_STARTS_WITH(format, "svc")); | 527 ASSERT(STRING_STARTS_WITH(format, "svc")); |
| 493 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 528 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 494 remaining_size_in_buffer(), | 529 remaining_size_in_buffer(), |
| 495 "0x%x", | 530 "0x%x", |
| 496 instr->SvcField()); | 531 instr->SvcField()); |
| 497 return 3; | 532 return 3; |
| 533 } else if (format[1] == 'z') { |
| 534 // 'sz: Size field of SIMD instruction. |
| 535 int sz = 8 << (instr->Bits(20, 2)); |
| 536 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 537 remaining_size_in_buffer(), |
| 538 "I%d", |
| 539 sz); |
| 540 return 2; |
| 498 } else if (format[1] == ' ') { | 541 } else if (format[1] == ' ') { |
| 499 // 's: S field of data processing instructions | 542 // 's: S field of data processing instructions. |
| 500 if (instr->HasS()) { | 543 if (instr->HasS()) { |
| 501 Print("s"); | 544 Print("s"); |
| 502 } | 545 } |
| 503 return 1; | 546 return 1; |
| 504 } else { | 547 } else { |
| 505 return FormatSRegister(instr, format); | 548 return FormatSRegister(instr, format); |
| 506 } | 549 } |
| 507 } | 550 } |
| 508 case 't': { // 'target: target of branch instructions | 551 case 't': { // 'target: target of branch instructions. |
| 509 ASSERT(STRING_STARTS_WITH(format, "target")); | 552 ASSERT(STRING_STARTS_WITH(format, "target")); |
| 510 int off = (instr->SImmed24Field() << 2) + 8; | 553 int off = (instr->SImmed24Field() << 2) + 8; |
| 511 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 554 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 512 remaining_size_in_buffer(), | 555 remaining_size_in_buffer(), |
| 513 "%+d", | 556 "%+d", |
| 514 off); | 557 off); |
| 515 return 6; | 558 return 6; |
| 516 } | 559 } |
| 517 case 'u': { // 'u: signed or unsigned multiplies | 560 case 'u': { // 'u: signed or unsigned multiplies. |
| 518 if (instr->Bit(22) == 0) { | 561 if (instr->Bit(22) == 0) { |
| 519 Print("u"); | 562 Print("u"); |
| 520 } else { | 563 } else { |
| 521 Print("s"); | 564 Print("s"); |
| 522 } | 565 } |
| 523 return 1; | 566 return 1; |
| 524 } | 567 } |
| 525 case 'w': { // 'w: W field of load and store instructions | 568 case 'w': { // 'w: W field of load and store instructions. |
| 526 if (instr->HasW()) { | 569 if (instr->HasW()) { |
| 527 Print("!"); | 570 Print("!"); |
| 528 } | 571 } |
| 529 return 1; | 572 return 1; |
| 530 } | 573 } |
| 531 case 'x': { // 'x: type of extra load/store instructions | 574 case 'x': { // 'x: type of extra load/store instructions. |
| 532 if (!instr->HasSign()) { | 575 if (!instr->HasSign()) { |
| 533 Print("h"); | 576 Print("h"); |
| 534 } else if (instr->HasL()) { | 577 } else if (instr->HasL()) { |
| 535 if (instr->HasH()) { | 578 if (instr->HasH()) { |
| 536 Print("sh"); | 579 Print("sh"); |
| 537 } else { | 580 } else { |
| 538 Print("sb"); | 581 Print("sb"); |
| 539 } | 582 } |
| 540 } else { | 583 } else { |
| 541 Print("d"); | 584 Print("d"); |
| (...skipping 674 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1216 } else { | 1259 } else { |
| 1217 Unknown(instr); | 1260 Unknown(instr); |
| 1218 } | 1261 } |
| 1219 } | 1262 } |
| 1220 } else { | 1263 } else { |
| 1221 Unknown(instr); | 1264 Unknown(instr); |
| 1222 } | 1265 } |
| 1223 } | 1266 } |
| 1224 | 1267 |
| 1225 | 1268 |
| 1269 void ARMDecoder::DecodeSIMDDataProcessing(Instr* instr) { |
| 1270 ASSERT(instr->ConditionField() == kSpecialCondition); |
| 1271 if (instr->Bit(6) == 1) { |
| 1272 if ((instr->Bits(8, 4) == 8) && (instr->Bit(4) == 0) && |
| 1273 (instr->Bit(24) == 0)) { |
| 1274 Format(instr, "vadd.'sz 'qd, 'qn, 'qm"); |
| 1275 } else if ((instr->Bits(8, 4) == 13) && (instr->Bit(4) == 0) && |
| 1276 (instr->Bit(24) == 0)) { |
| 1277 Format(instr, "vadd.F32 'qd, 'qn, 'qm"); |
| 1278 } else { |
| 1279 Unknown(instr); |
| 1280 } |
| 1281 } else { |
| 1282 Unknown(instr); |
| 1283 } |
| 1284 } |
| 1285 |
| 1286 |
| 1226 void ARMDecoder::InstructionDecode(uword pc) { | 1287 void ARMDecoder::InstructionDecode(uword pc) { |
| 1227 Instr* instr = Instr::At(pc); | 1288 Instr* instr = Instr::At(pc); |
| 1228 | 1289 |
| 1229 if (instr->ConditionField() == kSpecialCondition) { | 1290 if (instr->ConditionField() == kSpecialCondition) { |
| 1230 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { | 1291 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { |
| 1231 Format(instr, "clrex"); | 1292 Format(instr, "clrex"); |
| 1232 } else { | 1293 } else { |
| 1233 Unknown(instr); | 1294 if (instr->IsSIMDDataProcessing()) { |
| 1295 DecodeSIMDDataProcessing(instr); |
| 1296 } else { |
| 1297 Unknown(instr); |
| 1298 } |
| 1234 } | 1299 } |
| 1235 } else { | 1300 } else { |
| 1236 switch (instr->TypeField()) { | 1301 switch (instr->TypeField()) { |
| 1237 case 0: | 1302 case 0: |
| 1238 case 1: { | 1303 case 1: { |
| 1239 DecodeType01(instr); | 1304 DecodeType01(instr); |
| 1240 break; | 1305 break; |
| 1241 } | 1306 } |
| 1242 case 2: { | 1307 case 2: { |
| 1243 DecodeType2(instr); | 1308 DecodeType2(instr); |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1314 human_buffer, | 1379 human_buffer, |
| 1315 sizeof(human_buffer), | 1380 sizeof(human_buffer), |
| 1316 pc); | 1381 pc); |
| 1317 pc += instruction_length; | 1382 pc += instruction_length; |
| 1318 } | 1383 } |
| 1319 } | 1384 } |
| 1320 | 1385 |
| 1321 } // namespace dart | 1386 } // namespace dart |
| 1322 | 1387 |
| 1323 #endif // defined TARGET_ARCH_ARM | 1388 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |