| 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 |
| 11 namespace dart { | 11 namespace dart { |
| 12 | 12 |
| 13 class ARMDecoder : public ValueObject { |
| 14 public: |
| 15 ARMDecoder(char* buffer, size_t buffer_size) |
| 16 : buffer_(buffer), |
| 17 buffer_size_(buffer_size), |
| 18 buffer_pos_(0) { |
| 19 buffer_[buffer_pos_] = '\0'; |
| 20 } |
| 21 |
| 22 ~ARMDecoder() {} |
| 23 |
| 24 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 25 void InstructionDecode(uword pc); |
| 26 |
| 27 private: |
| 28 // Bottleneck functions to print into the out_buffer. |
| 29 void Print(const char* str); |
| 30 |
| 31 // Printing of common values. |
| 32 void PrintRegister(int reg); |
| 33 void PrintSRegister(int reg); |
| 34 void PrintDRegister(int reg); |
| 35 void PrintCondition(Instr* instr); |
| 36 void PrintShiftRm(Instr* instr); |
| 37 void PrintShiftImm(Instr* instr); |
| 38 void PrintPU(Instr* instr); |
| 39 |
| 40 // Handle formatting of instructions and their options. |
| 41 int FormatRegister(Instr* instr, const char* option); |
| 42 int FormatSRegister(Instr* instr, const char* option); |
| 43 int FormatDRegister(Instr* instr, const char* option); |
| 44 int FormatOption(Instr* instr, const char* option); |
| 45 void Format(Instr* instr, const char* format); |
| 46 void Unknown(Instr* instr); |
| 47 |
| 48 // Each of these functions decodes one particular instruction type, a 3-bit |
| 49 // field in the instruction encoding. |
| 50 // Types 0 and 1 are combined as they are largely the same except for the way |
| 51 // they interpret the shifter operand. |
| 52 void DecodeType01(Instr* instr); |
| 53 void DecodeType2(Instr* instr); |
| 54 void DecodeType3(Instr* instr); |
| 55 void DecodeType4(Instr* instr); |
| 56 void DecodeType5(Instr* instr); |
| 57 void DecodeType6(Instr* instr); |
| 58 void DecodeType7(Instr* instr); |
| 59 |
| 60 // Convenience functions. |
| 61 char* get_buffer() const { return buffer_; } |
| 62 char* current_position_in_buffer() { return buffer_ + buffer_pos_; } |
| 63 size_t remaining_size_in_buffer() { return buffer_size_ - buffer_pos_; } |
| 64 |
| 65 char* buffer_; // Decode instructions into this buffer. |
| 66 size_t buffer_size_; // The size of the character buffer. |
| 67 size_t buffer_pos_; // Current character position in buffer. |
| 68 |
| 69 DISALLOW_COPY_AND_ASSIGN(ARMDecoder); |
| 70 }; |
| 71 |
| 72 |
| 73 // Support for assertions in the ARMDecoder formatting functions. |
| 74 #define STRING_STARTS_WITH(string, compare_string) \ |
| 75 (strncmp(string, compare_string, strlen(compare_string)) == 0) |
| 76 |
| 77 |
| 78 // Append the str to the output buffer. |
| 79 void ARMDecoder::Print(const char* str) { |
| 80 char cur = *str++; |
| 81 while (cur != '\0' && (buffer_pos_ < (buffer_size_ - 1))) { |
| 82 buffer_[buffer_pos_++] = cur; |
| 83 cur = *str++; |
| 84 } |
| 85 buffer_[buffer_pos_] = '\0'; |
| 86 } |
| 87 |
| 88 |
| 89 // These condition names are defined in a way to match the native disassembler |
| 90 // formatting. See for example the command "objdump -d <binary file>". |
| 91 static const char* cond_names[kMaxCondition] = { |
| 92 "eq", "ne", "cs" , "cc" , "mi" , "pl" , "vs" , "vc" , |
| 93 "hi", "ls", "ge", "lt", "gt", "le", "", "invalid", |
| 94 }; |
| 95 |
| 96 |
| 97 // Print the condition guarding the instruction. |
| 98 void ARMDecoder::PrintCondition(Instr* instr) { |
| 99 Print(cond_names[instr->ConditionField()]); |
| 100 } |
| 101 |
| 102 |
| 103 // These register names are defined in a way to match the native disassembler |
| 104 // formatting. See for example the command "objdump -d <binary file>". |
| 105 static const char* reg_names[kNumberOfCpuRegisters] = { |
| 106 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", |
| 107 "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", |
| 108 }; |
| 109 |
| 110 |
| 111 // Print the register name according to the active name converter. |
| 112 void ARMDecoder::PrintRegister(int reg) { |
| 113 ASSERT(0 <= reg); |
| 114 ASSERT(reg < kNumberOfCpuRegisters); |
| 115 Print(reg_names[reg]); |
| 116 } |
| 117 |
| 118 |
| 119 void ARMDecoder::PrintSRegister(int reg) { |
| 120 ASSERT(0 <= reg); |
| 121 ASSERT(reg < kNumberOfSRegisters); |
| 122 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 123 remaining_size_in_buffer(), |
| 124 "s%d", reg); |
| 125 } |
| 126 |
| 127 |
| 128 void ARMDecoder::PrintDRegister(int reg) { |
| 129 ASSERT(0 <= reg); |
| 130 ASSERT(reg < kNumberOfDRegisters); |
| 131 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 132 remaining_size_in_buffer(), |
| 133 "d%d", reg); |
| 134 } |
| 135 |
| 136 |
| 137 // These shift names are defined in a way to match the native disassembler |
| 138 // formatting. See for example the command "objdump -d <binary file>". |
| 139 static const char* shift_names[kMaxShift] = { |
| 140 "lsl", "lsr", "asr", "ror" |
| 141 }; |
| 142 |
| 143 |
| 144 // Print the register shift operands for the instruction. Generally used for |
| 145 // data processing instructions. |
| 146 void ARMDecoder::PrintShiftRm(Instr* instr) { |
| 147 Shift shift = instr->ShiftField(); |
| 148 int shift_amount = instr->ShiftAmountField(); |
| 149 int rm = instr->RmField(); |
| 150 |
| 151 PrintRegister(rm); |
| 152 |
| 153 if ((instr->RegShiftField() == 0) && (shift == LSL) && (shift_amount == 0)) { |
| 154 // Special case for using rm only. |
| 155 return; |
| 156 } |
| 157 if (instr->RegShiftField() == 0) { |
| 158 // by immediate |
| 159 if ((shift == ROR) && (shift_amount == 0)) { |
| 160 Print(", RRX"); |
| 161 return; |
| 162 } else if (((shift == LSR) || (shift == ASR)) && (shift_amount == 0)) { |
| 163 shift_amount = 32; |
| 164 } |
| 165 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 166 remaining_size_in_buffer(), |
| 167 ", %s #%d", |
| 168 shift_names[shift], |
| 169 shift_amount); |
| 170 } else { |
| 171 // by register |
| 172 int rs = instr->RsField(); |
| 173 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 174 remaining_size_in_buffer(), |
| 175 ", %s ", |
| 176 shift_names[shift]); |
| 177 PrintRegister(rs); |
| 178 } |
| 179 } |
| 180 |
| 181 |
| 182 // Print the immediate operand for the instruction. Generally used for data |
| 183 // processing instructions. |
| 184 void ARMDecoder::PrintShiftImm(Instr* instr) { |
| 185 int rotate = instr->RotateField() * 2; |
| 186 int immed8 = instr->Immed8Field(); |
| 187 int imm = (immed8 >> rotate) | (immed8 << (32 - rotate)); |
| 188 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 189 remaining_size_in_buffer(), |
| 190 "#%d", |
| 191 imm); |
| 192 } |
| 193 |
| 194 |
| 195 // Print PU formatting to reduce complexity of FormatOption. |
| 196 void ARMDecoder::PrintPU(Instr* instr) { |
| 197 switch (instr->PUField()) { |
| 198 case 0: { |
| 199 Print("da"); |
| 200 break; |
| 201 } |
| 202 case 1: { |
| 203 Print("ia"); |
| 204 break; |
| 205 } |
| 206 case 2: { |
| 207 Print("db"); |
| 208 break; |
| 209 } |
| 210 case 3: { |
| 211 Print("ib"); |
| 212 break; |
| 213 } |
| 214 default: { |
| 215 UNREACHABLE(); |
| 216 break; |
| 217 } |
| 218 } |
| 219 } |
| 220 |
| 221 |
| 222 // Handle all register based formatting in these functions to reduce the |
| 223 // complexity of FormatOption. |
| 224 int ARMDecoder::FormatRegister(Instr* instr, const char* format) { |
| 225 ASSERT(format[0] == 'r'); |
| 226 if (format[1] == 'n') { // 'rn: Rn register |
| 227 int reg = instr->RnField(); |
| 228 PrintRegister(reg); |
| 229 return 2; |
| 230 } else if (format[1] == 'd') { // 'rd: Rd register |
| 231 int reg = instr->RdField(); |
| 232 PrintRegister(reg); |
| 233 if (format[2] == '2') { // 'rd2: possibly Rd, Rd+1 register pair |
| 234 if (instr->HasSign() && !instr->HasL()) { |
| 235 if ((reg % 2) != 0) { |
| 236 Print(" *** unknown (odd register pair) ***"); |
| 237 } else { |
| 238 Print(", "); |
| 239 PrintRegister(reg + 1); |
| 240 } |
| 241 } |
| 242 return 3; |
| 243 } |
| 244 return 2; |
| 245 } else if (format[1] == 's') { // 'rs: Rs register |
| 246 int reg = instr->RsField(); |
| 247 PrintRegister(reg); |
| 248 return 2; |
| 249 } else if (format[1] == 'm') { // 'rm: Rm register |
| 250 int reg = instr->RmField(); |
| 251 PrintRegister(reg); |
| 252 return 2; |
| 253 } else if (format[1] == 'l') { |
| 254 // 'rlist: register list for load and store multiple instructions |
| 255 ASSERT(STRING_STARTS_WITH(format, "rlist")); |
| 256 int rlist = instr->RlistField(); |
| 257 int reg = 0; |
| 258 Print("{"); |
| 259 // Print register list in ascending order, by scanning the bit mask. |
| 260 while (rlist != 0) { |
| 261 if ((rlist & 1) != 0) { |
| 262 PrintRegister(reg); |
| 263 if ((rlist >> 1) != 0) { |
| 264 Print(", "); |
| 265 } |
| 266 } |
| 267 reg++; |
| 268 rlist >>= 1; |
| 269 } |
| 270 Print("}"); |
| 271 return 5; |
| 272 } |
| 273 UNREACHABLE(); |
| 274 return -1; |
| 275 } |
| 276 |
| 277 |
| 278 int ARMDecoder::FormatSRegister(Instr* instr, const char* format) { |
| 279 ASSERT(format[0] == 's'); |
| 280 if (format[1] == 'n') { // 'sn: Sn register |
| 281 int reg = instr->SnField(); |
| 282 PrintSRegister(reg); |
| 283 return 2; |
| 284 } else if (format[1] == 'd') { // 'sd: Sd register |
| 285 int reg = instr->SdField(); |
| 286 PrintSRegister(reg); |
| 287 return 2; |
| 288 } else if (format[1] == 'm') { |
| 289 int reg = instr->SmField(); |
| 290 if (format[2] == '1') { // 'sm1: S[m+1] register |
| 291 reg++; |
| 292 ASSERT(reg < kNumberOfSRegisters); |
| 293 PrintSRegister(reg); |
| 294 return 3; |
| 295 } else { // 'sm: Sm register |
| 296 PrintSRegister(reg); |
| 297 return 2; |
| 298 } |
| 299 } |
| 300 UNREACHABLE(); |
| 301 return -1; |
| 302 } |
| 303 |
| 304 |
| 305 int ARMDecoder::FormatDRegister(Instr* instr, const char* format) { |
| 306 ASSERT(format[0] == 'd'); |
| 307 if (format[1] == 'n') { // 'dn: Dn register |
| 308 int reg = instr->DnField(); |
| 309 PrintDRegister(reg); |
| 310 return 2; |
| 311 } else if (format[1] == 'd') { // 'dd: Dd register |
| 312 int reg = instr->DdField(); |
| 313 PrintDRegister(reg); |
| 314 return 2; |
| 315 } else if (format[1] == 'm') { // 'dm: Dm register |
| 316 int reg = instr->DmField(); |
| 317 PrintDRegister(reg); |
| 318 return 2; |
| 319 } |
| 320 UNREACHABLE(); |
| 321 return -1; |
| 322 } |
| 323 |
| 324 |
| 325 // FormatOption takes a formatting string and interprets it based on |
| 326 // the current instructions. The format string points to the first |
| 327 // character of the option string (the option escape has already been |
| 328 // consumed by the caller.) FormatOption returns the number of |
| 329 // characters that were consumed from the formatting string. |
| 330 int ARMDecoder::FormatOption(Instr* instr, const char* format) { |
| 331 switch (format[0]) { |
| 332 case 'a': { // 'a: accumulate multiplies |
| 333 if (instr->Bit(21) == 0) { |
| 334 Print("ul"); |
| 335 } else { |
| 336 Print("la"); |
| 337 } |
| 338 return 1; |
| 339 } |
| 340 case 'b': { // 'b: byte loads or stores |
| 341 if (instr->HasB()) { |
| 342 Print("b"); |
| 343 } |
| 344 return 1; |
| 345 } |
| 346 case 'c': { // 'cond: conditional execution |
| 347 ASSERT(STRING_STARTS_WITH(format, "cond")); |
| 348 PrintCondition(instr); |
| 349 return 4; |
| 350 } |
| 351 case 'd': { |
| 352 if (format[1] == 'e') { // 'dest: branch destination |
| 353 ASSERT(STRING_STARTS_WITH(format, "dest")); |
| 354 int off = (instr->SImmed24Field() << 2) + 8; |
| 355 uword destination = reinterpret_cast<uword>(instr) + off; |
| 356 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 357 remaining_size_in_buffer(), |
| 358 "%#"Px"", |
| 359 destination); |
| 360 return 4; |
| 361 } else { |
| 362 return FormatDRegister(instr, format); |
| 363 } |
| 364 } |
| 365 case 'i': { // 'imm12_4, imm4_12, immf, or immd |
| 366 uint16_t immed16; |
| 367 if (format[3] == 'f') { |
| 368 ASSERT(STRING_STARTS_WITH(format, "immf")); |
| 369 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 370 remaining_size_in_buffer(), |
| 371 "%f", |
| 372 instr->ImmFloatField()); |
| 373 return 4; |
| 374 } else if (format[3] == 'd') { |
| 375 ASSERT(STRING_STARTS_WITH(format, "immd")); |
| 376 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 377 remaining_size_in_buffer(), |
| 378 "%g", |
| 379 instr->ImmDoubleField()); |
| 380 return 4; |
| 381 } else if (format[3] == '1') { |
| 382 ASSERT(STRING_STARTS_WITH(format, "imm12_4")); |
| 383 immed16 = instr->BkptField(); |
| 384 } else { |
| 385 ASSERT(STRING_STARTS_WITH(format, "imm4_12")); |
| 386 immed16 = instr->MovwField(); |
| 387 } |
| 388 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 389 remaining_size_in_buffer(), |
| 390 "0x%x", |
| 391 immed16); |
| 392 return 7; |
| 393 } |
| 394 case 'l': { // 'l: branch and link |
| 395 if (instr->HasLink()) { |
| 396 Print("l"); |
| 397 } |
| 398 return 1; |
| 399 } |
| 400 case 'm': { // 'memop: load/store instructions |
| 401 ASSERT(STRING_STARTS_WITH(format, "memop")); |
| 402 if (instr->HasL() || |
| 403 // Extra load/store instructions. |
| 404 ((instr->TypeField() == 0) && instr->HasSign() && !instr->HasH())) { |
| 405 Print("ldr"); |
| 406 } else { |
| 407 Print("str"); |
| 408 } |
| 409 return 5; |
| 410 } |
| 411 case 'o': { |
| 412 if (format[3] == '1') { |
| 413 if (format[4] == '0') { |
| 414 // 'off10: 10-bit offset for VFP load and store instructions |
| 415 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 416 remaining_size_in_buffer(), |
| 417 "%d", |
| 418 instr->Bits(0, 8) << 2); |
| 419 } else { |
| 420 // 'off12: 12-bit offset for load and store instructions |
| 421 ASSERT(STRING_STARTS_WITH(format, "off12")); |
| 422 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 423 remaining_size_in_buffer(), |
| 424 "%d", |
| 425 instr->Offset12Field()); |
| 426 } |
| 427 return 5; |
| 428 } |
| 429 // 'off8: 8-bit offset for extra load and store instructions |
| 430 ASSERT(STRING_STARTS_WITH(format, "off8")); |
| 431 int offs8 = (instr->ImmedHField() << 4) | instr->ImmedLField(); |
| 432 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 433 remaining_size_in_buffer(), |
| 434 "%d", |
| 435 offs8); |
| 436 return 4; |
| 437 } |
| 438 case 'p': { // 'pu: P and U bits for load and store instructions |
| 439 ASSERT(STRING_STARTS_WITH(format, "pu")); |
| 440 PrintPU(instr); |
| 441 return 2; |
| 442 } |
| 443 case 'r': { |
| 444 return FormatRegister(instr, format); |
| 445 } |
| 446 case 's': { |
| 447 if (format[1] == 'h') { // 'shift_op or 'shift_rm |
| 448 if (format[6] == 'o') { // 'shift_op |
| 449 ASSERT(STRING_STARTS_WITH(format, "shift_op")); |
| 450 if (instr->TypeField() == 0) { |
| 451 PrintShiftRm(instr); |
| 452 } else { |
| 453 ASSERT(instr->TypeField() == 1); |
| 454 PrintShiftImm(instr); |
| 455 } |
| 456 return 8; |
| 457 } else { // 'shift_rm |
| 458 ASSERT(STRING_STARTS_WITH(format, "shift_rm")); |
| 459 PrintShiftRm(instr); |
| 460 return 8; |
| 461 } |
| 462 } else if (format[1] == 'v') { // 'svc |
| 463 ASSERT(STRING_STARTS_WITH(format, "svc")); |
| 464 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 465 remaining_size_in_buffer(), |
| 466 "0x%x", |
| 467 instr->SvcField()); |
| 468 return 3; |
| 469 } else if (format[1] == ' ') { |
| 470 // 's: S field of data processing instructions |
| 471 if (instr->HasS()) { |
| 472 Print("s"); |
| 473 } |
| 474 return 1; |
| 475 } else { |
| 476 return FormatSRegister(instr, format); |
| 477 } |
| 478 } |
| 479 case 't': { // 'target: target of branch instructions |
| 480 ASSERT(STRING_STARTS_WITH(format, "target")); |
| 481 int off = (instr->SImmed24Field() << 2) + 8; |
| 482 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 483 remaining_size_in_buffer(), |
| 484 "%+d", |
| 485 off); |
| 486 return 6; |
| 487 } |
| 488 case 'u': { // 'u: signed or unsigned multiplies |
| 489 if (instr->Bit(22) == 0) { |
| 490 Print("u"); |
| 491 } else { |
| 492 Print("s"); |
| 493 } |
| 494 return 1; |
| 495 } |
| 496 case 'w': { // 'w: W field of load and store instructions |
| 497 if (instr->HasW()) { |
| 498 Print("!"); |
| 499 } |
| 500 return 1; |
| 501 } |
| 502 case 'x': { // 'x: type of extra load/store instructions |
| 503 if (!instr->HasSign()) { |
| 504 Print("h"); |
| 505 } else if (instr->HasL()) { |
| 506 if (instr->HasH()) { |
| 507 Print("sh"); |
| 508 } else { |
| 509 Print("sb"); |
| 510 } |
| 511 } else { |
| 512 Print("d"); |
| 513 } |
| 514 return 1; |
| 515 } |
| 516 default: { |
| 517 UNREACHABLE(); |
| 518 break; |
| 519 } |
| 520 } |
| 521 UNREACHABLE(); |
| 522 return -1; |
| 523 } |
| 524 |
| 525 |
| 526 // Format takes a formatting string for a whole instruction and prints it into |
| 527 // the output buffer. All escaped options are handed to FormatOption to be |
| 528 // parsed further. |
| 529 void ARMDecoder::Format(Instr* instr, const char* format) { |
| 530 char cur = *format++; |
| 531 while ((cur != 0) && (buffer_pos_ < (buffer_size_ - 1))) { |
| 532 if (cur == '\'') { // Single quote is used as the formatting escape. |
| 533 format += FormatOption(instr, format); |
| 534 } else { |
| 535 buffer_[buffer_pos_++] = cur; |
| 536 } |
| 537 cur = *format++; |
| 538 } |
| 539 buffer_[buffer_pos_] = '\0'; |
| 540 } |
| 541 |
| 542 |
| 543 // For currently unimplemented decodings the disassembler calls Unknown(instr) |
| 544 // which will just print "unknown" of the instruction bits. |
| 545 void ARMDecoder::Unknown(Instr* instr) { |
| 546 Format(instr, "unknown"); |
| 547 } |
| 548 |
| 549 |
| 550 void ARMDecoder::DecodeType01(Instr* instr) { |
| 551 if (!instr->IsDataProcessing()) { |
| 552 // miscellaneous, multiply, sync primitives, extra loads and stores. |
| 553 if (instr->IsMiscellaneous()) { |
| 554 switch (instr->Bits(4, 3)) { |
| 555 case 1: { |
| 556 if (instr->Bits(21, 2) == 0x3) { |
| 557 Format(instr, "clz'cond 'rd, 'rm"); |
| 558 } else { |
| 559 Unknown(instr); |
| 560 } |
| 561 break; |
| 562 } |
| 563 case 3: { |
| 564 if (instr->Bits(21, 2) == 0x1) { |
| 565 Format(instr, "blx'cond 'rm"); |
| 566 } else { |
| 567 // Could be inlined constant. |
| 568 Unknown(instr); |
| 569 } |
| 570 break; |
| 571 } |
| 572 case 7: { |
| 573 if (instr->Bits(21, 2) == 0x1) { |
| 574 Format(instr, "bkpt #'imm12_4"); |
| 575 } else { |
| 576 // Format(instr, "smc'cond"); |
| 577 Unknown(instr); // Not used. |
| 578 } |
| 579 break; |
| 580 } |
| 581 default: { |
| 582 Unknown(instr); // Not used. |
| 583 break; |
| 584 } |
| 585 } |
| 586 } else if (instr->IsMultiplyOrSyncPrimitive()) { |
| 587 if (instr->Bit(24) == 0) { |
| 588 // multiply instructions |
| 589 switch (instr->Bits(21, 3)) { |
| 590 case 0: { |
| 591 // Assembler registers rd, rn, rm are encoded as rn, rm, rs. |
| 592 Format(instr, "mul'cond's 'rn, 'rm, 'rs"); |
| 593 break; |
| 594 } |
| 595 case 1: { |
| 596 // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
| 597 Format(instr, "mla'cond's 'rn, 'rm, 'rs, 'rd"); |
| 598 break; |
| 599 } |
| 600 case 3: { |
| 601 // Assembler registers rd, rn, rm, ra are encoded as rn, rm, rs, rd. |
| 602 Format(instr, "mls'cond's 'rn, 'rm, 'rs, 'rd"); |
| 603 break; |
| 604 } |
| 605 case 4: { |
| 606 // Registers rd_lo, rd_hi, rn, rm are encoded as rd, rn, rm, rs. |
| 607 Format(instr, "umull'cond's 'rd, 'rn, 'rm, 'rs"); |
| 608 break; |
| 609 } |
| 610 default: { |
| 611 Unknown(instr); // Not used. |
| 612 break; |
| 613 } |
| 614 } |
| 615 } else { |
| 616 // synchronization primitives |
| 617 switch (instr->Bits(20, 4)) { |
| 618 case 8: { |
| 619 Format(instr, "strex'cond 'rd, 'rm, ['rn]"); |
| 620 break; |
| 621 } |
| 622 case 9: { |
| 623 Format(instr, "ldrex'cond 'rd, ['rn]"); |
| 624 break; |
| 625 } |
| 626 default: { |
| 627 Unknown(instr); // Not used. |
| 628 break; |
| 629 } |
| 630 } |
| 631 } |
| 632 } else if (instr->Bit(25) == 1) { |
| 633 // 16-bit immediate loads, msr (immediate), and hints |
| 634 switch (instr->Bits(20, 5)) { |
| 635 case 16: { |
| 636 Format(instr, "movw'cond 'rd, #'imm4_12"); |
| 637 break; |
| 638 } |
| 639 case 18: { |
| 640 if ((instr->Bits(16, 4) == 0) && (instr->Bits(0, 8) == 0)) { |
| 641 Format(instr, "nop'cond"); |
| 642 } else { |
| 643 Unknown(instr); // Not used. |
| 644 } |
| 645 break; |
| 646 } |
| 647 case 20: { |
| 648 Format(instr, "movt'cond 'rd, #'imm4_12"); |
| 649 break; |
| 650 } |
| 651 default: { |
| 652 Unknown(instr); // Not used. |
| 653 break; |
| 654 } |
| 655 } |
| 656 } else { |
| 657 // extra load/store instructions |
| 658 switch (instr->PUField()) { |
| 659 case 0: { |
| 660 if (instr->Bit(22) == 0) { |
| 661 Format(instr, "'memop'cond'x 'rd2, ['rn], -'rm"); |
| 662 } else { |
| 663 Format(instr, "'memop'cond'x 'rd2, ['rn], #-'off8"); |
| 664 } |
| 665 break; |
| 666 } |
| 667 case 1: { |
| 668 if (instr->Bit(22) == 0) { |
| 669 Format(instr, "'memop'cond'x 'rd2, ['rn], +'rm"); |
| 670 } else { |
| 671 Format(instr, "'memop'cond'x 'rd2, ['rn], #+'off8"); |
| 672 } |
| 673 break; |
| 674 } |
| 675 case 2: { |
| 676 if (instr->Bit(22) == 0) { |
| 677 Format(instr, "'memop'cond'x 'rd2, ['rn, -'rm]'w"); |
| 678 } else { |
| 679 Format(instr, "'memop'cond'x 'rd2, ['rn, #-'off8]'w"); |
| 680 } |
| 681 break; |
| 682 } |
| 683 case 3: { |
| 684 if (instr->Bit(22) == 0) { |
| 685 Format(instr, "'memop'cond'x 'rd2, ['rn, +'rm]'w"); |
| 686 } else { |
| 687 Format(instr, "'memop'cond'x 'rd2, ['rn, #+'off8]'w"); |
| 688 } |
| 689 break; |
| 690 } |
| 691 default: { |
| 692 // The PU field is a 2-bit field. |
| 693 UNREACHABLE(); |
| 694 break; |
| 695 } |
| 696 } |
| 697 } |
| 698 } else { |
| 699 switch (instr->OpcodeField()) { |
| 700 case AND: { |
| 701 Format(instr, "and'cond's 'rd, 'rn, 'shift_op"); |
| 702 break; |
| 703 } |
| 704 case EOR: { |
| 705 Format(instr, "eor'cond's 'rd, 'rn, 'shift_op"); |
| 706 break; |
| 707 } |
| 708 case SUB: { |
| 709 Format(instr, "sub'cond's 'rd, 'rn, 'shift_op"); |
| 710 break; |
| 711 } |
| 712 case RSB: { |
| 713 Format(instr, "rsb'cond's 'rd, 'rn, 'shift_op"); |
| 714 break; |
| 715 } |
| 716 case ADD: { |
| 717 Format(instr, "add'cond's 'rd, 'rn, 'shift_op"); |
| 718 break; |
| 719 } |
| 720 case ADC: { |
| 721 Format(instr, "adc'cond's 'rd, 'rn, 'shift_op"); |
| 722 break; |
| 723 } |
| 724 case SBC: { |
| 725 Format(instr, "sbc'cond's 'rd, 'rn, 'shift_op"); |
| 726 break; |
| 727 } |
| 728 case RSC: { |
| 729 Format(instr, "rsc'cond's 'rd, 'rn, 'shift_op"); |
| 730 break; |
| 731 } |
| 732 case TST: { |
| 733 if (instr->HasS()) { |
| 734 Format(instr, "tst'cond 'rn, 'shift_op"); |
| 735 } else { |
| 736 Unknown(instr); // Not used. |
| 737 } |
| 738 break; |
| 739 } |
| 740 case TEQ: { |
| 741 if (instr->HasS()) { |
| 742 Format(instr, "teq'cond 'rn, 'shift_op"); |
| 743 } else { |
| 744 Unknown(instr); // Not used. |
| 745 } |
| 746 break; |
| 747 } |
| 748 case CMP: { |
| 749 if (instr->HasS()) { |
| 750 Format(instr, "cmp'cond 'rn, 'shift_op"); |
| 751 } else { |
| 752 Unknown(instr); // Not used. |
| 753 } |
| 754 break; |
| 755 } |
| 756 case CMN: { |
| 757 if (instr->HasS()) { |
| 758 Format(instr, "cmn'cond 'rn, 'shift_op"); |
| 759 } else { |
| 760 Unknown(instr); // Not used. |
| 761 } |
| 762 break; |
| 763 } |
| 764 case ORR: { |
| 765 Format(instr, "orr'cond's 'rd, 'rn, 'shift_op"); |
| 766 break; |
| 767 } |
| 768 case MOV: { |
| 769 Format(instr, "mov'cond's 'rd, 'shift_op"); |
| 770 break; |
| 771 } |
| 772 case BIC: { |
| 773 Format(instr, "bic'cond's 'rd, 'rn, 'shift_op"); |
| 774 break; |
| 775 } |
| 776 case MVN: { |
| 777 Format(instr, "mvn'cond's 'rd, 'shift_op"); |
| 778 break; |
| 779 } |
| 780 default: { |
| 781 // The Opcode field is a 4-bit field. |
| 782 UNREACHABLE(); |
| 783 break; |
| 784 } |
| 785 } |
| 786 } |
| 787 } |
| 788 |
| 789 |
| 790 void ARMDecoder::DecodeType2(Instr* instr) { |
| 791 switch (instr->PUField()) { |
| 792 case 0: { |
| 793 if (instr->HasW()) { |
| 794 Unknown(instr); // Not used. |
| 795 } else { |
| 796 Format(instr, "'memop'cond'b 'rd, ['rn], #-'off12"); |
| 797 } |
| 798 break; |
| 799 } |
| 800 case 1: { |
| 801 if (instr->HasW()) { |
| 802 Unknown(instr); // Not used. |
| 803 } else { |
| 804 Format(instr, "'memop'cond'b 'rd, ['rn], #+'off12"); |
| 805 } |
| 806 break; |
| 807 } |
| 808 case 2: { |
| 809 Format(instr, "'memop'cond'b 'rd, ['rn, #-'off12]'w"); |
| 810 break; |
| 811 } |
| 812 case 3: { |
| 813 Format(instr, "'memop'cond'b 'rd, ['rn, #+'off12]'w"); |
| 814 break; |
| 815 } |
| 816 default: { |
| 817 // The PU field is a 2-bit field. |
| 818 UNREACHABLE(); |
| 819 break; |
| 820 } |
| 821 } |
| 822 } |
| 823 |
| 824 |
| 825 void ARMDecoder::DecodeType3(Instr* instr) { |
| 826 switch (instr->PUField()) { |
| 827 case 0: { |
| 828 if (instr->HasW()) { |
| 829 Unknown(instr); |
| 830 } else { |
| 831 Format(instr, "'memop'cond'b 'rd, ['rn], -'shift_rm"); |
| 832 } |
| 833 break; |
| 834 } |
| 835 case 1: { |
| 836 if (instr->HasW()) { |
| 837 Unknown(instr); |
| 838 } else { |
| 839 Format(instr, "'memop'cond'b 'rd, ['rn], +'shift_rm"); |
| 840 } |
| 841 break; |
| 842 } |
| 843 case 2: { |
| 844 Format(instr, "'memop'cond'b 'rd, ['rn, -'shift_rm]'w"); |
| 845 break; |
| 846 } |
| 847 case 3: { |
| 848 Format(instr, "'memop'cond'b 'rd, ['rn, +'shift_rm]'w"); |
| 849 break; |
| 850 } |
| 851 default: { |
| 852 // The PU field is a 2-bit field. |
| 853 UNREACHABLE(); |
| 854 break; |
| 855 } |
| 856 } |
| 857 } |
| 858 |
| 859 |
| 860 void ARMDecoder::DecodeType4(Instr* instr) { |
| 861 if (instr->Bit(22) == 1) { |
| 862 Unknown(instr); // Privileged mode currently not supported. |
| 863 } else if (instr->HasL()) { |
| 864 Format(instr, "ldm'cond'pu 'rn'w, 'rlist"); |
| 865 } else { |
| 866 Format(instr, "stm'cond'pu 'rn'w, 'rlist"); |
| 867 } |
| 868 } |
| 869 |
| 870 |
| 871 void ARMDecoder::DecodeType5(Instr* instr) { |
| 872 Format(instr, "b'l'cond 'target ; 'dest"); |
| 873 } |
| 874 |
| 875 |
| 876 void ARMDecoder::DecodeType6(Instr* instr) { |
| 877 if (instr->IsVFPDoubleTransfer()) { |
| 878 if (instr->Bit(8) == 0) { |
| 879 if (instr->Bit(20) == 1) { |
| 880 Format(instr, "vmovrrs'cond 'rd, 'rn, {'sm, 'sm1}"); |
| 881 } else { |
| 882 Format(instr, "vmovsrr'cond {'sm, 'sm1}, 'rd, 'rn"); |
| 883 } |
| 884 } else { |
| 885 if (instr->Bit(20) == 1) { |
| 886 Format(instr, "vmovrrd'cond 'rd, 'rn, 'dm"); |
| 887 } else { |
| 888 Format(instr, "vmovdrr'cond 'dm, 'rd, 'rn"); |
| 889 } |
| 890 } |
| 891 } else if (instr-> IsVFPLoadStore()) { |
| 892 if (instr->Bit(8) == 0) { |
| 893 if (instr->Bit(20) == 1) { // vldrs |
| 894 if (instr->Bit(23) == 1) { |
| 895 Format(instr, "vldrs'cond 'sd, ['rn, #+'off10]"); |
| 896 } else { |
| 897 Format(instr, "vldrs'cond 'sd, ['rn, #-'off10]"); |
| 898 } |
| 899 } else { // vstrs |
| 900 if (instr->Bit(23) == 1) { |
| 901 Format(instr, "vstrs'cond 'sd, ['rn, #+'off10]"); |
| 902 } else { |
| 903 Format(instr, "vstrs'cond 'sd, ['rn, #-'off10]"); |
| 904 } |
| 905 } |
| 906 } else { |
| 907 if (instr->Bit(20) == 1) { // vldrd |
| 908 if (instr->Bit(23) == 1) { |
| 909 Format(instr, "vldrd'cond 'dd, ['rn, #+'off10]"); |
| 910 } else { |
| 911 Format(instr, "vldrd'cond 'dd, ['rn, #-'off10]"); |
| 912 } |
| 913 } else { // vstrd |
| 914 if (instr->Bit(23) == 1) { |
| 915 Format(instr, "vstrd'cond 'dd, ['rn, #+'off10]"); |
| 916 } else { |
| 917 Format(instr, "vstrd'cond 'dd, ['rn, #-'off10]"); |
| 918 } |
| 919 } |
| 920 } |
| 921 } else { |
| 922 Unknown(instr); |
| 923 } |
| 924 } |
| 925 |
| 926 |
| 927 void ARMDecoder::DecodeType7(Instr* instr) { |
| 928 if (instr->Bit(24) == 1) { |
| 929 Format(instr, "svc'cond #'svc"); |
| 930 if (instr->SvcField() == kStopMessageSvcCode) { |
| 931 const char* message = *reinterpret_cast<const char**>( |
| 932 reinterpret_cast<intptr_t>(instr) - Instr::kInstrSize); |
| 933 buffer_pos_ += OS::SNPrint(current_position_in_buffer(), |
| 934 remaining_size_in_buffer(), |
| 935 " ; \"%s\"", |
| 936 message); |
| 937 } |
| 938 } else if (instr->IsVFPDataProcessingOrSingleTransfer()) { |
| 939 if (instr->Bit(4) == 0) { |
| 940 // VFP Data Processing |
| 941 switch (instr->Bits(20, 4) & 0xb) { |
| 942 case 0: { // vmla, vmls floating-point |
| 943 if (instr->Bit(8) == 0) { |
| 944 if (instr->Bit(6) == 0) { |
| 945 Format(instr, "vmlas'cond 'sd, 'sn, 'sm"); |
| 946 } else { |
| 947 Format(instr, "vmlss'cond 'sd, 'sn, 'sm"); |
| 948 } |
| 949 } else { |
| 950 if (instr->Bit(6) == 0) { |
| 951 Format(instr, "vmlad'cond 'dd, 'dn, 'dm"); |
| 952 } else { |
| 953 Format(instr, "vmlsd'cond 'dd, 'dn, 'dm"); |
| 954 } |
| 955 } |
| 956 break; |
| 957 } |
| 958 case 1: // vnmla, vnmls, vnmul |
| 959 default: { |
| 960 Unknown(instr); |
| 961 break; |
| 962 } |
| 963 case 2: { // vmul |
| 964 if (instr->Bit(8) == 0) { |
| 965 Format(instr, "vmuls'cond 'sd, 'sn, 'sm"); |
| 966 } else { |
| 967 Format(instr, "vmuld'cond 'dd, 'dn, 'dm"); |
| 968 } |
| 969 break; |
| 970 } |
| 971 case 8: { // vdiv |
| 972 if (instr->Bit(8) == 0) { |
| 973 Format(instr, "vdivs'cond 'sd, 'sn, 'sm"); |
| 974 } else { |
| 975 Format(instr, "vdivd'cond 'dd, 'dn, 'dm"); |
| 976 } |
| 977 break; |
| 978 } |
| 979 case 3: { // vadd, vsub floating-point |
| 980 if (instr->Bit(8) == 0) { |
| 981 if (instr->Bit(6) == 0) { |
| 982 Format(instr, "vadds'cond 'sd, 'sn, 'sm"); |
| 983 } else { |
| 984 Format(instr, "vsubs'cond 'sd, 'sn, 'sm"); |
| 985 } |
| 986 } else { |
| 987 if (instr->Bit(6) == 0) { |
| 988 Format(instr, "vaddd'cond 'dd, 'dn, 'dm"); |
| 989 } else { |
| 990 Format(instr, "vsubd'cond 'dd, 'dn, 'dm"); |
| 991 } |
| 992 } |
| 993 break; |
| 994 } |
| 995 case 0xb: { // Other VFP data-processing instructions |
| 996 if (instr->Bit(6) == 0) { // vmov immediate |
| 997 if (instr->Bit(8) == 0) { |
| 998 Format(instr, "vmovs'cond 'sd, #'immf"); |
| 999 } else { |
| 1000 Format(instr, "vmovd'cond 'dd, #'immd"); |
| 1001 } |
| 1002 break; |
| 1003 } |
| 1004 switch (instr->Bits(16, 4)) { |
| 1005 case 0: { // vmov register, vabs |
| 1006 switch (instr->Bits(6, 2)) { |
| 1007 case 1: { // vmov register |
| 1008 if (instr->Bit(8) == 0) { |
| 1009 Format(instr, "vmovs'cond 'sd, 'sm"); |
| 1010 } else { |
| 1011 Format(instr, "vmovd'cond 'dd, 'dm"); |
| 1012 } |
| 1013 break; |
| 1014 } |
| 1015 case 3: { // vabs |
| 1016 if (instr->Bit(8) == 0) { |
| 1017 Format(instr, "vabss'cond 'sd, 'sm"); |
| 1018 } else { |
| 1019 Format(instr, "vabsd'cond 'dd, 'dm"); |
| 1020 } |
| 1021 break; |
| 1022 } |
| 1023 default: { |
| 1024 Unknown(instr); |
| 1025 break; |
| 1026 } |
| 1027 } |
| 1028 break; |
| 1029 } |
| 1030 case 1: { // vneg, vsqrt |
| 1031 switch (instr->Bits(6, 2)) { |
| 1032 case 1: { // vneg |
| 1033 if (instr->Bit(8) == 0) { |
| 1034 Format(instr, "vnegs'cond 'sd, 'sm"); |
| 1035 } else { |
| 1036 Format(instr, "vnegd'cond 'dd, 'dm"); |
| 1037 } |
| 1038 break; |
| 1039 } |
| 1040 case 3: { // vsqrt |
| 1041 if (instr->Bit(8) == 0) { |
| 1042 Format(instr, "vsqrts'cond 'sd, 'sm"); |
| 1043 } else { |
| 1044 Format(instr, "vsqrtd'cond 'dd, 'dm"); |
| 1045 } |
| 1046 break; |
| 1047 } |
| 1048 default: { |
| 1049 Unknown(instr); |
| 1050 break; |
| 1051 } |
| 1052 } |
| 1053 break; |
| 1054 } |
| 1055 case 4: // vcmp, vcmpe |
| 1056 case 5: { // vcmp #0.0, vcmpe #0.0 |
| 1057 if (instr->Bit(7) == 1) { // vcmpe |
| 1058 Unknown(instr); |
| 1059 } else { |
| 1060 if (instr->Bit(8) == 0) { // vcmps |
| 1061 if (instr->Bit(16) == 0) { |
| 1062 Format(instr, "vcmps'cond 'sd, 'sm"); |
| 1063 } else { |
| 1064 Format(instr, "vcmps'cond 'sd, #0.0"); |
| 1065 } |
| 1066 } else { // vcmpd |
| 1067 if (instr->Bit(16) == 0) { |
| 1068 Format(instr, "vcmpd'cond 'dd, 'dm"); |
| 1069 } else { |
| 1070 Format(instr, "vcmpd'cond 'dd, #0.0"); |
| 1071 } |
| 1072 } |
| 1073 } |
| 1074 break; |
| 1075 } |
| 1076 case 7: { // vcvt between double-precision and single-precision |
| 1077 if (instr->Bit(8) == 0) { |
| 1078 Format(instr, "vcvtds'cond 'dd, 'sm"); |
| 1079 } else { |
| 1080 Format(instr, "vcvtsd'cond 'sd, 'dm"); |
| 1081 } |
| 1082 break; |
| 1083 } |
| 1084 case 8: { // vcvt, vcvtr between floating-point and integer |
| 1085 if (instr->Bit(8) == 0) { |
| 1086 if (instr->Bit(7) == 0) { |
| 1087 Format(instr, "vcvtsu'cond 'sd, 'sm"); |
| 1088 } else { |
| 1089 Format(instr, "vcvtsi'cond 'sd, 'sm"); |
| 1090 } |
| 1091 } else { |
| 1092 if (instr->Bit(7) == 0) { |
| 1093 Format(instr, "vcvtdu'cond 'dd, 'sm"); |
| 1094 } else { |
| 1095 Format(instr, "vcvtdi'cond 'dd, 'sm"); |
| 1096 } |
| 1097 } |
| 1098 break; |
| 1099 } |
| 1100 case 12: |
| 1101 case 13: { // vcvt, vcvtr between floating-point and integer |
| 1102 if (instr->Bit(7) == 0) { |
| 1103 // We only support round-to-zero mode |
| 1104 Unknown(instr); |
| 1105 break; |
| 1106 } |
| 1107 if (instr->Bit(8) == 0) { |
| 1108 if (instr->Bit(16) == 0) { |
| 1109 Format(instr, "vcvtus'cond 'sd, 'sm"); |
| 1110 } else { |
| 1111 Format(instr, "vcvtis'cond 'sd, 'sm"); |
| 1112 } |
| 1113 } else { |
| 1114 if (instr->Bit(16) == 0) { |
| 1115 Format(instr, "vcvtud'cond 'sd, 'dm"); |
| 1116 } else { |
| 1117 Format(instr, "vcvtid'cond 'sd, 'dm"); |
| 1118 } |
| 1119 } |
| 1120 break; |
| 1121 } |
| 1122 case 2: // vcvtb, vcvtt |
| 1123 case 3: // vcvtb, vcvtt |
| 1124 case 9: // undefined |
| 1125 case 10: // vcvt between floating-point and fixed-point |
| 1126 case 11: // vcvt between floating-point and fixed-point |
| 1127 case 14: // vcvt between floating-point and fixed-point |
| 1128 case 15: // vcvt between floating-point and fixed-point |
| 1129 default: { |
| 1130 Unknown(instr); |
| 1131 break; |
| 1132 } |
| 1133 } |
| 1134 } |
| 1135 break; |
| 1136 } |
| 1137 } else { |
| 1138 // 8, 16, or 32-bit Transfer between ARM Core and VFP |
| 1139 if ((instr->Bits(21, 3) == 0) && (instr->Bit(8) == 0)) { |
| 1140 if (instr->Bit(20) == 0) { |
| 1141 Format(instr, "vmovs'cond 'sn, 'rd"); |
| 1142 } else { |
| 1143 Format(instr, "vmovr'cond 'rd, 'sn"); |
| 1144 } |
| 1145 } else if ((instr->Bits(20, 4) == 0xf) && (instr->Bit(8) == 0) && |
| 1146 (instr->Bits(12, 4) == 0xf)) { |
| 1147 Format(instr, "vmstat'cond"); |
| 1148 } else { |
| 1149 Unknown(instr); |
| 1150 } |
| 1151 } |
| 1152 } else { |
| 1153 Unknown(instr); |
| 1154 } |
| 1155 } |
| 1156 |
| 1157 |
| 1158 void ARMDecoder::InstructionDecode(uword pc) { |
| 1159 Instr* instr = Instr::At(pc); |
| 1160 if (instr->ConditionField() == kSpecialCondition) { |
| 1161 if (instr->InstructionBits() == static_cast<int32_t>(0xf57ff01f)) { |
| 1162 Format(instr, "clrex"); |
| 1163 } else { |
| 1164 Unknown(instr); |
| 1165 } |
| 1166 } else { |
| 1167 switch (instr->TypeField()) { |
| 1168 case 0: |
| 1169 case 1: { |
| 1170 DecodeType01(instr); |
| 1171 break; |
| 1172 } |
| 1173 case 2: { |
| 1174 DecodeType2(instr); |
| 1175 break; |
| 1176 } |
| 1177 case 3: { |
| 1178 DecodeType3(instr); |
| 1179 break; |
| 1180 } |
| 1181 case 4: { |
| 1182 DecodeType4(instr); |
| 1183 break; |
| 1184 } |
| 1185 case 5: { |
| 1186 DecodeType5(instr); |
| 1187 break; |
| 1188 } |
| 1189 case 6: { |
| 1190 DecodeType6(instr); |
| 1191 break; |
| 1192 } |
| 1193 case 7: { |
| 1194 DecodeType7(instr); |
| 1195 break; |
| 1196 } |
| 1197 default: { |
| 1198 // The type field is 3-bits in the ARM encoding. |
| 1199 UNREACHABLE(); |
| 1200 break; |
| 1201 } |
| 1202 } |
| 1203 } |
| 1204 } |
| 1205 |
| 1206 |
| 13 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, | 1207 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size, |
| 14 char* human_buffer, intptr_t human_size, | 1208 char* human_buffer, intptr_t human_size, |
| 15 uword pc) { | 1209 uword pc) { |
| 16 UNIMPLEMENTED(); | 1210 ARMDecoder decoder(human_buffer, human_size); |
| 17 return 0; | 1211 decoder.InstructionDecode(pc); |
| 18 } | 1212 int32_t instruction_bits = Instr::At(pc)->InstructionBits(); |
| 19 | 1213 OS::SNPrint(hex_buffer, hex_size, "%08x", instruction_bits); |
| 20 | 1214 return Instr::kInstrSize; |
| 1215 } |
| 1216 |
| 1217 |
| 21 void Disassembler::Disassemble(uword start, | 1218 void Disassembler::Disassemble(uword start, |
| 22 uword end, | 1219 uword end, |
| 23 DisassemblyFormatter* formatter, | 1220 DisassemblyFormatter* formatter, |
| 24 const Code::Comments& comments) { | 1221 const Code::Comments& comments) { |
| 25 UNIMPLEMENTED(); | 1222 ASSERT(formatter != NULL); |
| 1223 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form. |
| 1224 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction. |
| 1225 uword pc = start; |
| 1226 intptr_t comment_finger = 0; |
| 1227 while (pc < end) { |
| 1228 const intptr_t offset = pc - start; |
| 1229 while (comment_finger < comments.Length() && |
| 1230 comments.PCOffsetAt(comment_finger) <= offset) { |
| 1231 formatter->Print( |
| 1232 " ;; %s\n", |
| 1233 String::Handle(comments.CommentAt(comment_finger)).ToCString()); |
| 1234 comment_finger++; |
| 1235 } |
| 1236 int instruction_length = DecodeInstruction(hex_buffer, |
| 1237 sizeof(hex_buffer), |
| 1238 human_buffer, |
| 1239 sizeof(human_buffer), |
| 1240 pc); |
| 1241 formatter->ConsumeInstruction(hex_buffer, |
| 1242 sizeof(hex_buffer), |
| 1243 human_buffer, |
| 1244 sizeof(human_buffer), |
| 1245 pc); |
| 1246 pc += instruction_length; |
| 1247 } |
| 26 } | 1248 } |
| 27 | 1249 |
| 28 } // namespace dart | 1250 } // namespace dart |
| 29 | 1251 |
| 30 #endif // defined TARGET_ARCH_ARM | 1252 #endif // defined TARGET_ARCH_ARM |
| OLD | NEW |