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 |