| OLD | NEW |
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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_ARM64. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64. |
| 8 #if defined(TARGET_ARCH_ARM64) | 8 #if defined(TARGET_ARCH_ARM64) |
| 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(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, R31Type r31t); | 33 void PrintRegister(int reg, R31Type r31t); |
| 34 void PrintVRegister(int reg); |
| 34 void PrintShiftExtendRm(Instr* instr); | 35 void PrintShiftExtendRm(Instr* instr); |
| 35 void PrintMemOperand(Instr* instr); | 36 void PrintMemOperand(Instr* instr); |
| 36 void PrintS(Instr* instr); | 37 void PrintS(Instr* instr); |
| 37 void PrintCondition(Instr* instr); | 38 void PrintCondition(Instr* instr); |
| 38 | 39 |
| 39 // Handle formatting of instructions and their options. | 40 // Handle formatting of instructions and their options. |
| 40 int FormatRegister(Instr* instr, const char* option); | 41 int FormatRegister(Instr* instr, const char* option); |
| 42 int FormatVRegister(Instr*instr, const char* option); |
| 41 int FormatOption(Instr* instr, const char* format); | 43 int FormatOption(Instr* instr, const char* format); |
| 42 void Format(Instr* instr, const char* format); | 44 void Format(Instr* instr, const char* format); |
| 43 void Unknown(Instr* instr); | 45 void Unknown(Instr* instr); |
| 44 | 46 |
| 45 // Decode instructions. | 47 // Decode instructions. |
| 46 #define DECODE_OP(op) \ | 48 #define DECODE_OP(op) \ |
| 47 void Decode##op(Instr* instr); | 49 void Decode##op(Instr* instr); |
| 48 APPLY_OP_LIST(DECODE_OP) | 50 APPLY_OP_LIST(DECODE_OP) |
| 49 #undef DECODE_OP | 51 #undef DECODE_OP |
| 50 | 52 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 96 ASSERT(reg < kNumberOfCpuRegisters); | 98 ASSERT(reg < kNumberOfCpuRegisters); |
| 97 if (reg == 31) { | 99 if (reg == 31) { |
| 98 const char* rstr = (r31t == R31IsZR) ? "zr" : "sp"; | 100 const char* rstr = (r31t == R31IsZR) ? "zr" : "sp"; |
| 99 Print(rstr); | 101 Print(rstr); |
| 100 } else { | 102 } else { |
| 101 Print(reg_names[reg]); | 103 Print(reg_names[reg]); |
| 102 } | 104 } |
| 103 } | 105 } |
| 104 | 106 |
| 105 | 107 |
| 108 void ARM64Decoder::PrintVRegister(int reg) { |
| 109 ASSERT(0 <= reg); |
| 110 ASSERT(reg < kNumberOfVRegisters); |
| 111 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 112 remaining_size_in_buffer(), |
| 113 "v%d", reg); |
| 114 } |
| 115 |
| 116 |
| 106 // These shift names are defined in a way to match the native disassembler | 117 // These shift names are defined in a way to match the native disassembler |
| 107 // formatting. See for example the command "objdump -d <binary file>". | 118 // formatting. See for example the command "objdump -d <binary file>". |
| 108 static const char* shift_names[kMaxShift] = { | 119 static const char* shift_names[kMaxShift] = { |
| 109 "lsl", "lsr", "asr", "ror" | 120 "lsl", "lsr", "asr", "ror" |
| 110 }; | 121 }; |
| 111 | 122 |
| 112 | 123 |
| 113 static const char* extend_names[kMaxExtend] = { | 124 static const char* extend_names[kMaxExtend] = { |
| 114 "uxtb", "uxth", "uxtw", "uxtx", | 125 "uxtb", "uxth", "uxtw", "uxtx", |
| 115 "sxtb", "sxth", "sxtw", "sxtx", | 126 "sxtb", "sxth", "sxtw", "sxtx", |
| (...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 } else if (format[1] == 'a') { // 'ra: Ra register | 295 } else if (format[1] == 'a') { // 'ra: Ra register |
| 285 int reg = instr->RaField(); | 296 int reg = instr->RaField(); |
| 286 PrintRegister(reg, R31IsZR); | 297 PrintRegister(reg, R31IsZR); |
| 287 return 2; | 298 return 2; |
| 288 } | 299 } |
| 289 UNREACHABLE(); | 300 UNREACHABLE(); |
| 290 return -1; | 301 return -1; |
| 291 } | 302 } |
| 292 | 303 |
| 293 | 304 |
| 305 int ARM64Decoder::FormatVRegister(Instr* instr, const char* format) { |
| 306 ASSERT(format[0] == 'v'); |
| 307 if (format[1] == 'd') { |
| 308 int reg = instr->VdField(); |
| 309 PrintVRegister(reg); |
| 310 return 2; |
| 311 } else if (format[1] == 'n') { |
| 312 int reg = instr->VnField(); |
| 313 PrintVRegister(reg); |
| 314 return 2; |
| 315 } |
| 316 UNREACHABLE(); |
| 317 return -1; |
| 318 } |
| 319 |
| 320 |
| 294 // FormatOption takes a formatting string and interprets it based on | 321 // FormatOption takes a formatting string and interprets it based on |
| 295 // the current instructions. The format string points to the first | 322 // the current instructions. The format string points to the first |
| 296 // character of the option string (the option escape has already been | 323 // character of the option string (the option escape has already been |
| 297 // consumed by the caller.) FormatOption returns the number of | 324 // consumed by the caller.) FormatOption returns the number of |
| 298 // characters that were consumed from the formatting string. | 325 // characters that were consumed from the formatting string. |
| 299 int ARM64Decoder::FormatOption(Instr* instr, const char* format) { | 326 int ARM64Decoder::FormatOption(Instr* instr, const char* format) { |
| 300 switch (format[0]) { | 327 switch (format[0]) { |
| 301 case 'b': { | 328 case 'b': { |
| 302 if (format[3] == 'i') { | 329 if (format[3] == 'i') { |
| 303 ASSERT(STRING_STARTS_WITH(format, "bitimm")); | 330 ASSERT(STRING_STARTS_WITH(format, "bitimm")); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 ASSERT(STRING_STARTS_WITH(format, "hw")); | 383 ASSERT(STRING_STARTS_WITH(format, "hw")); |
| 357 const int shift = instr->HWField() << 4; | 384 const int shift = instr->HWField() << 4; |
| 358 if (shift != 0) { | 385 if (shift != 0) { |
| 359 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 386 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 360 remaining_size_in_buffer(), | 387 remaining_size_in_buffer(), |
| 361 "lsl %d", | 388 "lsl %d", |
| 362 shift); | 389 shift); |
| 363 } | 390 } |
| 364 return 2; | 391 return 2; |
| 365 } | 392 } |
| 366 case 'i': { // 'imm12, imm16 | 393 case 'i': { // 'imm12, 'imm16, 'immd |
| 367 uint64_t imm; | 394 if (format[3] == '1') { |
| 368 int ret = 5; | 395 uint64_t imm; |
| 369 if (format[4] == '2') { | 396 int ret = 5; |
| 370 ASSERT(STRING_STARTS_WITH(format, "imm12")); | 397 if (format[4] == '2') { |
| 371 imm = instr->Imm12Field(); | 398 ASSERT(STRING_STARTS_WITH(format, "imm12")); |
| 372 if (format[5] == 's') { | 399 imm = instr->Imm12Field(); |
| 373 // shifted immediate. | 400 if (format[5] == 's') { |
| 374 if (instr->Imm12ShiftField() == 1) { | 401 // shifted immediate. |
| 375 imm = imm << 12; | 402 if (instr->Imm12ShiftField() == 1) { |
| 376 } else if ((instr->Imm12ShiftField() & 0x2) != 0) { | 403 imm = imm << 12; |
| 377 Print("Unknown Shift"); | 404 } else if ((instr->Imm12ShiftField() & 0x2) != 0) { |
| 405 Print("Unknown Shift"); |
| 406 } |
| 407 ret = 6; |
| 378 } | 408 } |
| 379 ret = 6; | 409 } else { |
| 410 ASSERT(STRING_STARTS_WITH(format, "imm16")); |
| 411 imm = instr->Imm16Field(); |
| 380 } | 412 } |
| 413 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 414 remaining_size_in_buffer(), |
| 415 "0x%"Px64, |
| 416 imm); |
| 417 return ret; |
| 381 } else { | 418 } else { |
| 382 ASSERT(STRING_STARTS_WITH(format, "imm16")); | 419 ASSERT(STRING_STARTS_WITH(format, "immd")); |
| 383 imm = instr->Imm16Field(); | 420 double dimm = bit_cast<double, int64_t>( |
| 421 Instr::VFPExpandImm(instr->Imm8Field())); |
| 422 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 423 remaining_size_in_buffer(), |
| 424 "%f", |
| 425 dimm); |
| 426 return 4; |
| 384 } | 427 } |
| 385 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | |
| 386 remaining_size_in_buffer(), | |
| 387 "0x%"Px64, | |
| 388 imm); | |
| 389 return ret; | |
| 390 } | 428 } |
| 391 case 'm': { | 429 case 'm': { |
| 392 ASSERT(STRING_STARTS_WITH(format, "memop")); | 430 ASSERT(STRING_STARTS_WITH(format, "memop")); |
| 393 PrintMemOperand(instr); | 431 PrintMemOperand(instr); |
| 394 return 5; | 432 return 5; |
| 395 } | 433 } |
| 396 case 'p': { | 434 case 'p': { |
| 397 if (format[2] == 'a') { | 435 if (format[2] == 'a') { |
| 398 ASSERT(STRING_STARTS_WITH(format, "pcadr")); | 436 ASSERT(STRING_STARTS_WITH(format, "pcadr")); |
| 399 const int64_t immhi = instr->SImm19Field(); | 437 const int64_t immhi = instr->SImm19Field(); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 413 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), | 451 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 414 remaining_size_in_buffer(), | 452 remaining_size_in_buffer(), |
| 415 "0x%"Px64, | 453 "0x%"Px64, |
| 416 dest); | 454 dest); |
| 417 } | 455 } |
| 418 return 5; | 456 return 5; |
| 419 } | 457 } |
| 420 case 'r': { | 458 case 'r': { |
| 421 return FormatRegister(instr, format); | 459 return FormatRegister(instr, format); |
| 422 } | 460 } |
| 461 case 'v': { |
| 462 return FormatVRegister(instr, format); |
| 463 } |
| 423 case 's': { // 's: S flag. | 464 case 's': { // 's: S flag. |
| 424 if (format[1] == 'h') { | 465 if (format[1] == 'h') { |
| 425 ASSERT(STRING_STARTS_WITH(format, "shift_op")); | 466 ASSERT(STRING_STARTS_WITH(format, "shift_op")); |
| 426 PrintShiftExtendRm(instr); | 467 PrintShiftExtendRm(instr); |
| 427 return 8; | 468 return 8; |
| 428 } else if (format[1] == 'f') { | 469 } else if (format[1] == 'f') { |
| 429 ASSERT(STRING_STARTS_WITH(format, "sf")); | 470 ASSERT(STRING_STARTS_WITH(format, "sf")); |
| 430 if (instr->SFField() == 1) { | 471 if (instr->SFField() == 1) { |
| 431 // TODO(zra): If we don't use the w form much, we can omit printing | 472 // TODO(zra): If we don't use the w form much, we can omit printing |
| 432 // this x. | 473 // this x. |
| (...skipping 439 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 872 Unknown(instr); | 913 Unknown(instr); |
| 873 } | 914 } |
| 874 } | 915 } |
| 875 | 916 |
| 876 | 917 |
| 877 void ARM64Decoder::DecodeDPSimd1(Instr* instr) { | 918 void ARM64Decoder::DecodeDPSimd1(Instr* instr) { |
| 878 Unknown(instr); | 919 Unknown(instr); |
| 879 } | 920 } |
| 880 | 921 |
| 881 | 922 |
| 923 void ARM64Decoder::DecodeFPImm(Instr* instr) { |
| 924 if ((instr->Bit(31) != 0) || (instr->Bit(29) != 0) || (instr->Bit(23) != 0) || |
| 925 (instr->Bits(5, 5) != 0)) { |
| 926 Unknown(instr); |
| 927 return; |
| 928 } |
| 929 if (instr->Bit(22) == 1) { |
| 930 // Double. |
| 931 Format(instr, "fmovd 'vd, 'immd"); |
| 932 } else { |
| 933 // Single. |
| 934 Unknown(instr); |
| 935 } |
| 936 } |
| 937 |
| 938 |
| 939 void ARM64Decoder::DecodeFPIntCvt(Instr* instr) { |
| 940 if ((instr->SFField() != 1) || (instr->Bit(29) != 0) || |
| 941 (instr->Bits(22, 2) != 1)) { |
| 942 Unknown(instr); |
| 943 return; |
| 944 } |
| 945 if (instr->Bits(16, 3) == 6) { |
| 946 Format(instr, "fmovrd 'rd, 'vn"); |
| 947 } else if (instr->Bits(16, 3) == 7) { |
| 948 Format(instr, "fmovdr 'vd, 'rn"); |
| 949 } else { |
| 950 Unknown(instr); |
| 951 } |
| 952 } |
| 953 |
| 954 |
| 955 void ARM64Decoder::DecodeFP(Instr* instr) { |
| 956 if (instr->IsFPImmOp()) { |
| 957 DecodeFPImm(instr); |
| 958 } else if (instr->IsFPIntCvtOp()) { |
| 959 DecodeFPIntCvt(instr); |
| 960 } else { |
| 961 Unknown(instr); |
| 962 } |
| 963 } |
| 964 |
| 965 |
| 882 void ARM64Decoder::DecodeDPSimd2(Instr* instr) { | 966 void ARM64Decoder::DecodeDPSimd2(Instr* instr) { |
| 883 Unknown(instr); | 967 if (instr->IsFPOp()) { |
| 968 DecodeFP(instr); |
| 969 } else { |
| 970 Unknown(instr); |
| 971 } |
| 884 } | 972 } |
| 885 | 973 |
| 886 | 974 |
| 887 void ARM64Decoder::InstructionDecode(uword pc) { | 975 void ARM64Decoder::InstructionDecode(uword pc) { |
| 888 Instr* instr = Instr::At(pc); | 976 Instr* instr = Instr::At(pc); |
| 889 | 977 |
| 890 if (instr->IsDPImmediateOp()) { | 978 if (instr->IsDPImmediateOp()) { |
| 891 DecodeDPImmediate(instr); | 979 DecodeDPImmediate(instr); |
| 892 } else if (instr->IsCompareBranchOp()) { | 980 } else if (instr->IsCompareBranchOp()) { |
| 893 DecodeCompareBranch(instr); | 981 DecodeCompareBranch(instr); |
| (...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 human_buffer, | 1034 human_buffer, |
| 947 sizeof(human_buffer), | 1035 sizeof(human_buffer), |
| 948 pc); | 1036 pc); |
| 949 pc += instruction_length; | 1037 pc += instruction_length; |
| 950 } | 1038 } |
| 951 } | 1039 } |
| 952 | 1040 |
| 953 } // namespace dart | 1041 } // namespace dart |
| 954 | 1042 |
| 955 #endif // defined TARGET_ARCH_ARM | 1043 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |