1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include <assert.h> 6 #include <stdarg.h> 7 #include <stdio.h> 8 #include <string.h> 9 10 #include "src/v8.h" 11 12 #if V8_TARGET_ARCH_ARM64 13 14 #include "src/arm64/decoder-arm64-inl.h" 15 #include "src/arm64/disasm-arm64.h" 16 #include "src/base/platform/platform.h" 17 #include "src/disasm.h" 18 #include "src/macro-assembler.h" 19 20 namespace v8 { 21 namespace internal { 22 23 24 Disassembler::Disassembler() { 25 buffer_size_ = 256; 26 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_)); 27 buffer_pos_ = 0; 28 own_buffer_ = true; 29 } 30 31 32 Disassembler::Disassembler(char* text_buffer, int buffer_size) { 33 buffer_size_ = buffer_size; 34 buffer_ = text_buffer; 35 buffer_pos_ = 0; 36 own_buffer_ = false; 37 } 38 39 40 Disassembler::~Disassembler() { 41 if (own_buffer_) { 42 free(buffer_); 43 } 44 } 45 46 47 char* Disassembler::GetOutput() { 48 return buffer_; 49 } 50 51 52 void Disassembler::VisitAddSubImmediate(Instruction* instr) { 53 bool rd_is_zr = RdIsZROrSP(instr); 54 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) && 55 (instr->ImmAddSub() == 0) ? true : false; 56 const char *mnemonic = ""; 57 const char *form = "'Rds, 'Rns, 'IAddSub"; 58 const char *form_cmp = "'Rns, 'IAddSub"; 59 const char *form_mov = "'Rds, 'Rns"; 60 61 switch (instr->Mask(AddSubImmediateMask)) { 62 case ADD_w_imm: 63 case ADD_x_imm: { 64 mnemonic = "add"; 65 if (stack_op) { 66 mnemonic = "mov"; 67 form = form_mov; 68 } 69 break; 70 } 71 case ADDS_w_imm: 72 case ADDS_x_imm: { 73 mnemonic = "adds"; 74 if (rd_is_zr) { 75 mnemonic = "cmn"; 76 form = form_cmp; 77 } 78 break; 79 } 80 case SUB_w_imm: 81 case SUB_x_imm: mnemonic = "sub"; break; 82 case SUBS_w_imm: 83 case SUBS_x_imm: { 84 mnemonic = "subs"; 85 if (rd_is_zr) { 86 mnemonic = "cmp"; 87 form = form_cmp; 88 } 89 break; 90 } 91 default: UNREACHABLE(); 92 } 93 Format(instr, mnemonic, form); 94 } 95 96 97 void Disassembler::VisitAddSubShifted(Instruction* instr) { 98 bool rd_is_zr = RdIsZROrSP(instr); 99 bool rn_is_zr = RnIsZROrSP(instr); 100 const char *mnemonic = ""; 101 const char *form = "'Rd, 'Rn, 'Rm'HDP"; 102 const char *form_cmp = "'Rn, 'Rm'HDP"; 103 const char *form_neg = "'Rd, 'Rm'HDP"; 104 105 switch (instr->Mask(AddSubShiftedMask)) { 106 case ADD_w_shift: 107 case ADD_x_shift: mnemonic = "add"; break; 108 case ADDS_w_shift: 109 case ADDS_x_shift: { 110 mnemonic = "adds"; 111 if (rd_is_zr) { 112 mnemonic = "cmn"; 113 form = form_cmp; 114 } 115 break; 116 } 117 case SUB_w_shift: 118 case SUB_x_shift: { 119 mnemonic = "sub"; 120 if (rn_is_zr) { 121 mnemonic = "neg"; 122 form = form_neg; 123 } 124 break; 125 } 126 case SUBS_w_shift: 127 case SUBS_x_shift: { 128 mnemonic = "subs"; 129 if (rd_is_zr) { 130 mnemonic = "cmp"; 131 form = form_cmp; 132 } else if (rn_is_zr) { 133 mnemonic = "negs"; 134 form = form_neg; 135 } 136 break; 137 } 138 default: UNREACHABLE(); 139 } 140 Format(instr, mnemonic, form); 141 } 142 143 144 void Disassembler::VisitAddSubExtended(Instruction* instr) { 145 bool rd_is_zr = RdIsZROrSP(instr); 146 const char *mnemonic = ""; 147 Extend mode = static_cast<Extend>(instr->ExtendMode()); 148 const char *form = ((mode == UXTX) || (mode == SXTX)) ? 149 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext"; 150 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ? 151 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext"; 152 153 switch (instr->Mask(AddSubExtendedMask)) { 154 case ADD_w_ext: 155 case ADD_x_ext: mnemonic = "add"; break; 156 case ADDS_w_ext: 157 case ADDS_x_ext: { 158 mnemonic = "adds"; 159 if (rd_is_zr) { 160 mnemonic = "cmn"; 161 form = form_cmp; 162 } 163 break; 164 } 165 case SUB_w_ext: 166 case SUB_x_ext: mnemonic = "sub"; break; 167 case SUBS_w_ext: 168 case SUBS_x_ext: { 169 mnemonic = "subs"; 170 if (rd_is_zr) { 171 mnemonic = "cmp"; 172 form = form_cmp; 173 } 174 break; 175 } 176 default: UNREACHABLE(); 177 } 178 Format(instr, mnemonic, form); 179 } 180 181 182 void Disassembler::VisitAddSubWithCarry(Instruction* instr) { 183 bool rn_is_zr = RnIsZROrSP(instr); 184 const char *mnemonic = ""; 185 const char *form = "'Rd, 'Rn, 'Rm"; 186 const char *form_neg = "'Rd, 'Rm"; 187 188 switch (instr->Mask(AddSubWithCarryMask)) { 189 case ADC_w: 190 case ADC_x: mnemonic = "adc"; break; 191 case ADCS_w: 192 case ADCS_x: mnemonic = "adcs"; break; 193 case SBC_w: 194 case SBC_x: { 195 mnemonic = "sbc"; 196 if (rn_is_zr) { 197 mnemonic = "ngc"; 198 form = form_neg; 199 } 200 break; 201 } 202 case SBCS_w: 203 case SBCS_x: { 204 mnemonic = "sbcs"; 205 if (rn_is_zr) { 206 mnemonic = "ngcs"; 207 form = form_neg; 208 } 209 break; 210 } 211 default: UNREACHABLE(); 212 } 213 Format(instr, mnemonic, form); 214 } 215 216 217 void Disassembler::VisitLogicalImmediate(Instruction* instr) { 218 bool rd_is_zr = RdIsZROrSP(instr); 219 bool rn_is_zr = RnIsZROrSP(instr); 220 const char *mnemonic = ""; 221 const char *form = "'Rds, 'Rn, 'ITri"; 222 223 if (instr->ImmLogical() == 0) { 224 // The immediate encoded in the instruction is not in the expected format. 225 Format(instr, "unallocated", "(LogicalImmediate)"); 226 return; 227 } 228 229 switch (instr->Mask(LogicalImmediateMask)) { 230 case AND_w_imm: 231 case AND_x_imm: mnemonic = "and"; break; 232 case ORR_w_imm: 233 case ORR_x_imm: { 234 mnemonic = "orr"; 235 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits 236 : kWRegSizeInBits; 237 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) { 238 mnemonic = "mov"; 239 form = "'Rds, 'ITri"; 240 } 241 break; 242 } 243 case EOR_w_imm: 244 case EOR_x_imm: mnemonic = "eor"; break; 245 case ANDS_w_imm: 246 case ANDS_x_imm: { 247 mnemonic = "ands"; 248 if (rd_is_zr) { 249 mnemonic = "tst"; 250 form = "'Rn, 'ITri"; 251 } 252 break; 253 } 254 default: UNREACHABLE(); 255 } 256 Format(instr, mnemonic, form); 257 } 258 259 260 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) { 261 DCHECK((reg_size == kXRegSizeInBits) || 262 ((reg_size == kWRegSizeInBits) && (value <= 0xffffffff))); 263 264 // Test for movz: 16-bits set at positions 0, 16, 32 or 48. 265 if (((value & 0xffffffffffff0000UL) == 0UL) || 266 ((value & 0xffffffff0000ffffUL) == 0UL) || 267 ((value & 0xffff0000ffffffffUL) == 0UL) || 268 ((value & 0x0000ffffffffffffUL) == 0UL)) { 269 return true; 270 } 271 272 // Test for movn: NOT(16-bits set at positions 0, 16, 32 or 48). 273 if ((reg_size == kXRegSizeInBits) && 274 (((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) || 275 ((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) || 276 ((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) || 277 ((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) { 278 return true; 279 } 280 if ((reg_size == kWRegSizeInBits) && 281 (((value & 0xffff0000) == 0xffff0000) || 282 ((value & 0x0000ffff) == 0x0000ffff))) { 283 return true; 284 } 285 return false; 286 } 287 288 289 void Disassembler::VisitLogicalShifted(Instruction* instr) { 290 bool rd_is_zr = RdIsZROrSP(instr); 291 bool rn_is_zr = RnIsZROrSP(instr); 292 const char *mnemonic = ""; 293 const char *form = "'Rd, 'Rn, 'Rm'HLo"; 294 295 switch (instr->Mask(LogicalShiftedMask)) { 296 case AND_w: 297 case AND_x: mnemonic = "and"; break; 298 case BIC_w: 299 case BIC_x: mnemonic = "bic"; break; 300 case EOR_w: 301 case EOR_x: mnemonic = "eor"; break; 302 case EON_w: 303 case EON_x: mnemonic = "eon"; break; 304 case BICS_w: 305 case BICS_x: mnemonic = "bics"; break; 306 case ANDS_w: 307 case ANDS_x: { 308 mnemonic = "ands"; 309 if (rd_is_zr) { 310 mnemonic = "tst"; 311 form = "'Rn, 'Rm'HLo"; 312 } 313 break; 314 } 315 case ORR_w: 316 case ORR_x: { 317 mnemonic = "orr"; 318 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) { 319 mnemonic = "mov"; 320 form = "'Rd, 'Rm"; 321 } 322 break; 323 } 324 case ORN_w: 325 case ORN_x: { 326 mnemonic = "orn"; 327 if (rn_is_zr) { 328 mnemonic = "mvn"; 329 form = "'Rd, 'Rm'HLo"; 330 } 331 break; 332 } 333 default: UNREACHABLE(); 334 } 335 336 Format(instr, mnemonic, form); 337 } 338 339 340 void Disassembler::VisitConditionalCompareRegister(Instruction* instr) { 341 const char *mnemonic = ""; 342 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond"; 343 344 switch (instr->Mask(ConditionalCompareRegisterMask)) { 345 case CCMN_w: 346 case CCMN_x: mnemonic = "ccmn"; break; 347 case CCMP_w: 348 case CCMP_x: mnemonic = "ccmp"; break; 349 default: UNREACHABLE(); 350 } 351 Format(instr, mnemonic, form); 352 } 353 354 355 void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) { 356 const char *mnemonic = ""; 357 const char *form = "'Rn, 'IP, 'INzcv, 'Cond"; 358 359 switch (instr->Mask(ConditionalCompareImmediateMask)) { 360 case CCMN_w_imm: 361 case CCMN_x_imm: mnemonic = "ccmn"; break; 362 case CCMP_w_imm: 363 case CCMP_x_imm: mnemonic = "ccmp"; break; 364 default: UNREACHABLE(); 365 } 366 Format(instr, mnemonic, form); 367 } 368 369 370 void Disassembler::VisitConditionalSelect(Instruction* instr) { 371 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr)); 372 bool rn_is_rm = (instr->Rn() == instr->Rm()); 373 const char *mnemonic = ""; 374 const char *form = "'Rd, 'Rn, 'Rm, 'Cond"; 375 const char *form_test = "'Rd, 'CInv"; 376 const char *form_update = "'Rd, 'Rn, 'CInv"; 377 378 Condition cond = static_cast<Condition>(instr->Condition()); 379 bool invertible_cond = (cond != al) && (cond != nv); 380 381 switch (instr->Mask(ConditionalSelectMask)) { 382 case CSEL_w: 383 case CSEL_x: mnemonic = "csel"; break; 384 case CSINC_w: 385 case CSINC_x: { 386 mnemonic = "csinc"; 387 if (rnm_is_zr && invertible_cond) { 388 mnemonic = "cset"; 389 form = form_test; 390 } else if (rn_is_rm && invertible_cond) { 391 mnemonic = "cinc"; 392 form = form_update; 393 } 394 break; 395 } 396 case CSINV_w: 397 case CSINV_x: { 398 mnemonic = "csinv"; 399 if (rnm_is_zr && invertible_cond) { 400 mnemonic = "csetm"; 401 form = form_test; 402 } else if (rn_is_rm && invertible_cond) { 403 mnemonic = "cinv"; 404 form = form_update; 405 } 406 break; 407 } 408 case CSNEG_w: 409 case CSNEG_x: { 410 mnemonic = "csneg"; 411 if (rn_is_rm && invertible_cond) { 412 mnemonic = "cneg"; 413 form = form_update; 414 } 415 break; 416 } 417 default: UNREACHABLE(); 418 } 419 Format(instr, mnemonic, form); 420 } 421 422 423 void Disassembler::VisitBitfield(Instruction* instr) { 424 unsigned s = instr->ImmS(); 425 unsigned r = instr->ImmR(); 426 unsigned rd_size_minus_1 = 427 ((instr->SixtyFourBits() == 1) ? kXRegSizeInBits : kWRegSizeInBits) - 1; 428 const char *mnemonic = ""; 429 const char *form = ""; 430 const char *form_shift_right = "'Rd, 'Rn, 'IBr"; 431 const char *form_extend = "'Rd, 'Wn"; 432 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1"; 433 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1"; 434 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r"; 435 436 switch (instr->Mask(BitfieldMask)) { 437 case SBFM_w: 438 case SBFM_x: { 439 mnemonic = "sbfx"; 440 form = form_bfx; 441 if (r == 0) { 442 form = form_extend; 443 if (s == 7) { 444 mnemonic = "sxtb"; 445 } else if (s == 15) { 446 mnemonic = "sxth"; 447 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) { 448 mnemonic = "sxtw"; 449 } else { 450 form = form_bfx; 451 } 452 } else if (s == rd_size_minus_1) { 453 mnemonic = "asr"; 454 form = form_shift_right; 455 } else if (s < r) { 456 mnemonic = "sbfiz"; 457 form = form_bfiz; 458 } 459 break; 460 } 461 case UBFM_w: 462 case UBFM_x: { 463 mnemonic = "ubfx"; 464 form = form_bfx; 465 if (r == 0) { 466 form = form_extend; 467 if (s == 7) { 468 mnemonic = "uxtb"; 469 } else if (s == 15) { 470 mnemonic = "uxth"; 471 } else { 472 form = form_bfx; 473 } 474 } 475 if (s == rd_size_minus_1) { 476 mnemonic = "lsr"; 477 form = form_shift_right; 478 } else if (r == s + 1) { 479 mnemonic = "lsl"; 480 form = form_lsl; 481 } else if (s < r) { 482 mnemonic = "ubfiz"; 483 form = form_bfiz; 484 } 485 break; 486 } 487 case BFM_w: 488 case BFM_x: { 489 mnemonic = "bfxil"; 490 form = form_bfx; 491 if (s < r) { 492 mnemonic = "bfi"; 493 form = form_bfiz; 494 } 495 } 496 } 497 Format(instr, mnemonic, form); 498 } 499 500 501 void Disassembler::VisitExtract(Instruction* instr) { 502 const char *mnemonic = ""; 503 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract"; 504 505 switch (instr->Mask(ExtractMask)) { 506 case EXTR_w: 507 case EXTR_x: { 508 if (instr->Rn() == instr->Rm()) { 509 mnemonic = "ror"; 510 form = "'Rd, 'Rn, 'IExtract"; 511 } else { 512 mnemonic = "extr"; 513 } 514 break; 515 } 516 default: UNREACHABLE(); 517 } 518 Format(instr, mnemonic, form); 519 } 520 521 522 void Disassembler::VisitPCRelAddressing(Instruction* instr) { 523 switch (instr->Mask(PCRelAddressingMask)) { 524 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break; 525 // ADRP is not implemented. 526 default: Format(instr, "unimplemented", "(PCRelAddressing)"); 527 } 528 } 529 530 531 void Disassembler::VisitConditionalBranch(Instruction* instr) { 532 switch (instr->Mask(ConditionalBranchMask)) { 533 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break; 534 default: UNREACHABLE(); 535 } 536 } 537 538 539 void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) { 540 const char *mnemonic = "unimplemented"; 541 const char *form = "'Xn"; 542 543 switch (instr->Mask(UnconditionalBranchToRegisterMask)) { 544 case BR: mnemonic = "br"; break; 545 case BLR: mnemonic = "blr"; break; 546 case RET: { 547 mnemonic = "ret"; 548 if (instr->Rn() == kLinkRegCode) { 549 form = NULL; 550 } 551 break; 552 } 553 default: form = "(UnconditionalBranchToRegister)"; 554 } 555 Format(instr, mnemonic, form); 556 } 557 558 559 void Disassembler::VisitUnconditionalBranch(Instruction* instr) { 560 const char *mnemonic = ""; 561 const char *form = "'BImmUncn"; 562 563 switch (instr->Mask(UnconditionalBranchMask)) { 564 case B: mnemonic = "b"; break; 565 case BL: mnemonic = "bl"; break; 566 default: UNREACHABLE(); 567 } 568 Format(instr, mnemonic, form); 569 } 570 571 572 void Disassembler::VisitDataProcessing1Source(Instruction* instr) { 573 const char *mnemonic = ""; 574 const char *form = "'Rd, 'Rn"; 575 576 switch (instr->Mask(DataProcessing1SourceMask)) { 577 #define FORMAT(A, B) \ 578 case A##_w: \ 579 case A##_x: mnemonic = B; break; 580 FORMAT(RBIT, "rbit"); 581 FORMAT(REV16, "rev16"); 582 FORMAT(REV, "rev"); 583 FORMAT(CLZ, "clz"); 584 FORMAT(CLS, "cls"); 585 #undef FORMAT 586 case REV32_x: mnemonic = "rev32"; break; 587 default: UNREACHABLE(); 588 } 589 Format(instr, mnemonic, form); 590 } 591 592 593 void Disassembler::VisitDataProcessing2Source(Instruction* instr) { 594 const char *mnemonic = "unimplemented"; 595 const char *form = "'Rd, 'Rn, 'Rm"; 596 597 switch (instr->Mask(DataProcessing2SourceMask)) { 598 #define FORMAT(A, B) \ 599 case A##_w: \ 600 case A##_x: mnemonic = B; break; 601 FORMAT(UDIV, "udiv"); 602 FORMAT(SDIV, "sdiv"); 603 FORMAT(LSLV, "lsl"); 604 FORMAT(LSRV, "lsr"); 605 FORMAT(ASRV, "asr"); 606 FORMAT(RORV, "ror"); 607 #undef FORMAT 608 default: form = "(DataProcessing2Source)"; 609 } 610 Format(instr, mnemonic, form); 611 } 612 613 614 void Disassembler::VisitDataProcessing3Source(Instruction* instr) { 615 bool ra_is_zr = RaIsZROrSP(instr); 616 const char *mnemonic = ""; 617 const char *form = "'Xd, 'Wn, 'Wm, 'Xa"; 618 const char *form_rrr = "'Rd, 'Rn, 'Rm"; 619 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra"; 620 const char *form_xww = "'Xd, 'Wn, 'Wm"; 621 const char *form_xxx = "'Xd, 'Xn, 'Xm"; 622 623 switch (instr->Mask(DataProcessing3SourceMask)) { 624 case MADD_w: 625 case MADD_x: { 626 mnemonic = "madd"; 627 form = form_rrrr; 628 if (ra_is_zr) { 629 mnemonic = "mul"; 630 form = form_rrr; 631 } 632 break; 633 } 634 case MSUB_w: 635 case MSUB_x: { 636 mnemonic = "msub"; 637 form = form_rrrr; 638 if (ra_is_zr) { 639 mnemonic = "mneg"; 640 form = form_rrr; 641 } 642 break; 643 } 644 case SMADDL_x: { 645 mnemonic = "smaddl"; 646 if (ra_is_zr) { 647 mnemonic = "smull"; 648 form = form_xww; 649 } 650 break; 651 } 652 case SMSUBL_x: { 653 mnemonic = "smsubl"; 654 if (ra_is_zr) { 655 mnemonic = "smnegl"; 656 form = form_xww; 657 } 658 break; 659 } 660 case UMADDL_x: { 661 mnemonic = "umaddl"; 662 if (ra_is_zr) { 663 mnemonic = "umull"; 664 form = form_xww; 665 } 666 break; 667 } 668 case UMSUBL_x: { 669 mnemonic = "umsubl"; 670 if (ra_is_zr) { 671 mnemonic = "umnegl"; 672 form = form_xww; 673 } 674 break; 675 } 676 case SMULH_x: { 677 mnemonic = "smulh"; 678 form = form_xxx; 679 break; 680 } 681 case UMULH_x: { 682 mnemonic = "umulh"; 683 form = form_xxx; 684 break; 685 } 686 default: UNREACHABLE(); 687 } 688 Format(instr, mnemonic, form); 689 } 690 691 692 void Disassembler::VisitCompareBranch(Instruction* instr) { 693 const char *mnemonic = ""; 694 const char *form = "'Rt, 'BImmCmpa"; 695 696 switch (instr->Mask(CompareBranchMask)) { 697 case CBZ_w: 698 case CBZ_x: mnemonic = "cbz"; break; 699 case CBNZ_w: 700 case CBNZ_x: mnemonic = "cbnz"; break; 701 default: UNREACHABLE(); 702 } 703 Format(instr, mnemonic, form); 704 } 705 706 707 void Disassembler::VisitTestBranch(Instruction* instr) { 708 const char *mnemonic = ""; 709 // If the top bit of the immediate is clear, the tested register is 710 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is 711 // encoded in bit 31 of the instruction, we can reuse the Rt form, which 712 // uses bit 31 (normally "sf") to choose the register size. 713 const char *form = "'Rt, 'IS, 'BImmTest"; 714 715 switch (instr->Mask(TestBranchMask)) { 716 case TBZ: mnemonic = "tbz"; break; 717 case TBNZ: mnemonic = "tbnz"; break; 718 default: UNREACHABLE(); 719 } 720 Format(instr, mnemonic, form); 721 } 722 723 724 void Disassembler::VisitMoveWideImmediate(Instruction* instr) { 725 const char *mnemonic = ""; 726 const char *form = "'Rd, 'IMoveImm"; 727 728 // Print the shift separately for movk, to make it clear which half word will 729 // be overwritten. Movn and movz print the computed immediate, which includes 730 // shift calculation. 731 switch (instr->Mask(MoveWideImmediateMask)) { 732 case MOVN_w: 733 case MOVN_x: mnemonic = "movn"; break; 734 case MOVZ_w: 735 case MOVZ_x: mnemonic = "movz"; break; 736 case MOVK_w: 737 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break; 738 default: UNREACHABLE(); 739 } 740 Format(instr, mnemonic, form); 741 } 742 743 744 #define LOAD_STORE_LIST(V) \ 745 V(STRB_w, "strb", "'Wt") \ 746 V(STRH_w, "strh", "'Wt") \ 747 V(STR_w, "str", "'Wt") \ 748 V(STR_x, "str", "'Xt") \ 749 V(LDRB_w, "ldrb", "'Wt") \ 750 V(LDRH_w, "ldrh", "'Wt") \ 751 V(LDR_w, "ldr", "'Wt") \ 752 V(LDR_x, "ldr", "'Xt") \ 753 V(LDRSB_x, "ldrsb", "'Xt") \ 754 V(LDRSH_x, "ldrsh", "'Xt") \ 755 V(LDRSW_x, "ldrsw", "'Xt") \ 756 V(LDRSB_w, "ldrsb", "'Wt") \ 757 V(LDRSH_w, "ldrsh", "'Wt") \ 758 V(STR_s, "str", "'St") \ 759 V(STR_d, "str", "'Dt") \ 760 V(LDR_s, "ldr", "'St") \ 761 V(LDR_d, "ldr", "'Dt") 762 763 void Disassembler::VisitLoadStorePreIndex(Instruction* instr) { 764 const char *mnemonic = "unimplemented"; 765 const char *form = "(LoadStorePreIndex)"; 766 767 switch (instr->Mask(LoadStorePreIndexMask)) { 768 #define LS_PREINDEX(A, B, C) \ 769 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break; 770 LOAD_STORE_LIST(LS_PREINDEX) 771 #undef LS_PREINDEX 772 } 773 Format(instr, mnemonic, form); 774 } 775 776 777 void Disassembler::VisitLoadStorePostIndex(Instruction* instr) { 778 const char *mnemonic = "unimplemented"; 779 const char *form = "(LoadStorePostIndex)"; 780 781 switch (instr->Mask(LoadStorePostIndexMask)) { 782 #define LS_POSTINDEX(A, B, C) \ 783 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break; 784 LOAD_STORE_LIST(LS_POSTINDEX) 785 #undef LS_POSTINDEX 786 } 787 Format(instr, mnemonic, form); 788 } 789 790 791 void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) { 792 const char *mnemonic = "unimplemented"; 793 const char *form = "(LoadStoreUnsignedOffset)"; 794 795 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) { 796 #define LS_UNSIGNEDOFFSET(A, B, C) \ 797 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break; 798 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET) 799 #undef LS_UNSIGNEDOFFSET 800 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]"; 801 } 802 Format(instr, mnemonic, form); 803 } 804 805 806 void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) { 807 const char *mnemonic = "unimplemented"; 808 const char *form = "(LoadStoreRegisterOffset)"; 809 810 switch (instr->Mask(LoadStoreRegisterOffsetMask)) { 811 #define LS_REGISTEROFFSET(A, B, C) \ 812 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break; 813 LOAD_STORE_LIST(LS_REGISTEROFFSET) 814 #undef LS_REGISTEROFFSET 815 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]"; 816 } 817 Format(instr, mnemonic, form); 818 } 819 820 821 void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) { 822 const char *mnemonic = "unimplemented"; 823 const char *form = "'Wt, ['Xns'ILS]"; 824 const char *form_x = "'Xt, ['Xns'ILS]"; 825 const char *form_s = "'St, ['Xns'ILS]"; 826 const char *form_d = "'Dt, ['Xns'ILS]"; 827 828 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) { 829 case STURB_w: mnemonic = "sturb"; break; 830 case STURH_w: mnemonic = "sturh"; break; 831 case STUR_w: mnemonic = "stur"; break; 832 case STUR_x: mnemonic = "stur"; form = form_x; break; 833 case STUR_s: mnemonic = "stur"; form = form_s; break; 834 case STUR_d: mnemonic = "stur"; form = form_d; break; 835 case LDURB_w: mnemonic = "ldurb"; break; 836 case LDURH_w: mnemonic = "ldurh"; break; 837 case LDUR_w: mnemonic = "ldur"; break; 838 case LDUR_x: mnemonic = "ldur"; form = form_x; break; 839 case LDUR_s: mnemonic = "ldur"; form = form_s; break; 840 case LDUR_d: mnemonic = "ldur"; form = form_d; break; 841 case LDURSB_x: form = form_x; // Fall through. 842 case LDURSB_w: mnemonic = "ldursb"; break; 843 case LDURSH_x: form = form_x; // Fall through. 844 case LDURSH_w: mnemonic = "ldursh"; break; 845 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break; 846 default: form = "(LoadStoreUnscaledOffset)"; 847 } 848 Format(instr, mnemonic, form); 849 } 850 851 852 void Disassembler::VisitLoadLiteral(Instruction* instr) { 853 const char *mnemonic = "ldr"; 854 const char *form = "(LoadLiteral)"; 855 856 switch (instr->Mask(LoadLiteralMask)) { 857 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break; 858 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break; 859 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break; 860 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break; 861 default: mnemonic = "unimplemented"; 862 } 863 Format(instr, mnemonic, form); 864 } 865 866 867 #define LOAD_STORE_PAIR_LIST(V) \ 868 V(STP_w, "stp", "'Wt, 'Wt2", "4") \ 869 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \ 870 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \ 871 V(STP_x, "stp", "'Xt, 'Xt2", "8") \ 872 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \ 873 V(STP_s, "stp", "'St, 'St2", "4") \ 874 V(LDP_s, "ldp", "'St, 'St2", "4") \ 875 V(STP_d, "stp", "'Dt, 'Dt2", "8") \ 876 V(LDP_d, "ldp", "'Dt, 'Dt2", "8") 877 878 void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) { 879 const char *mnemonic = "unimplemented"; 880 const char *form = "(LoadStorePairPostIndex)"; 881 882 switch (instr->Mask(LoadStorePairPostIndexMask)) { 883 #define LSP_POSTINDEX(A, B, C, D) \ 884 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break; 885 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX) 886 #undef LSP_POSTINDEX 887 } 888 Format(instr, mnemonic, form); 889 } 890 891 892 void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) { 893 const char *mnemonic = "unimplemented"; 894 const char *form = "(LoadStorePairPreIndex)"; 895 896 switch (instr->Mask(LoadStorePairPreIndexMask)) { 897 #define LSP_PREINDEX(A, B, C, D) \ 898 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break; 899 LOAD_STORE_PAIR_LIST(LSP_PREINDEX) 900 #undef LSP_PREINDEX 901 } 902 Format(instr, mnemonic, form); 903 } 904 905 906 void Disassembler::VisitLoadStorePairOffset(Instruction* instr) { 907 const char *mnemonic = "unimplemented"; 908 const char *form = "(LoadStorePairOffset)"; 909 910 switch (instr->Mask(LoadStorePairOffsetMask)) { 911 #define LSP_OFFSET(A, B, C, D) \ 912 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break; 913 LOAD_STORE_PAIR_LIST(LSP_OFFSET) 914 #undef LSP_OFFSET 915 } 916 Format(instr, mnemonic, form); 917 } 918 919 920 void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) { 921 const char *mnemonic = "unimplemented"; 922 const char *form; 923 924 switch (instr->Mask(LoadStorePairNonTemporalMask)) { 925 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break; 926 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break; 927 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break; 928 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break; 929 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break; 930 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break; 931 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break; 932 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break; 933 default: form = "(LoadStorePairNonTemporal)"; 934 } 935 Format(instr, mnemonic, form); 936 } 937 938 939 void Disassembler::VisitFPCompare(Instruction* instr) { 940 const char *mnemonic = "unimplemented"; 941 const char *form = "'Fn, 'Fm"; 942 const char *form_zero = "'Fn, #0.0"; 943 944 switch (instr->Mask(FPCompareMask)) { 945 case FCMP_s_zero: 946 case FCMP_d_zero: form = form_zero; // Fall through. 947 case FCMP_s: 948 case FCMP_d: mnemonic = "fcmp"; break; 949 default: form = "(FPCompare)"; 950 } 951 Format(instr, mnemonic, form); 952 } 953 954 955 void Disassembler::VisitFPConditionalCompare(Instruction* instr) { 956 const char *mnemonic = "unimplemented"; 957 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond"; 958 959 switch (instr->Mask(FPConditionalCompareMask)) { 960 case FCCMP_s: 961 case FCCMP_d: mnemonic = "fccmp"; break; 962 case FCCMPE_s: 963 case FCCMPE_d: mnemonic = "fccmpe"; break; 964 default: form = "(FPConditionalCompare)"; 965 } 966 Format(instr, mnemonic, form); 967 } 968 969 970 void Disassembler::VisitFPConditionalSelect(Instruction* instr) { 971 const char *mnemonic = ""; 972 const char *form = "'Fd, 'Fn, 'Fm, 'Cond"; 973 974 switch (instr->Mask(FPConditionalSelectMask)) { 975 case FCSEL_s: 976 case FCSEL_d: mnemonic = "fcsel"; break; 977 default: UNREACHABLE(); 978 } 979 Format(instr, mnemonic, form); 980 } 981 982 983 void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) { 984 const char *mnemonic = "unimplemented"; 985 const char *form = "'Fd, 'Fn"; 986 987 switch (instr->Mask(FPDataProcessing1SourceMask)) { 988 #define FORMAT(A, B) \ 989 case A##_s: \ 990 case A##_d: mnemonic = B; break; 991 FORMAT(FMOV, "fmov"); 992 FORMAT(FABS, "fabs"); 993 FORMAT(FNEG, "fneg"); 994 FORMAT(FSQRT, "fsqrt"); 995 FORMAT(FRINTN, "frintn"); 996 FORMAT(FRINTP, "frintp"); 997 FORMAT(FRINTM, "frintm"); 998 FORMAT(FRINTZ, "frintz"); 999 FORMAT(FRINTA, "frinta"); 1000 FORMAT(FRINTX, "frintx"); 1001 FORMAT(FRINTI, "frinti"); 1002 #undef FORMAT 1003 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break; 1004 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break; 1005 default: form = "(FPDataProcessing1Source)"; 1006 } 1007 Format(instr, mnemonic, form); 1008 } 1009 1010 1011 void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) { 1012 const char *mnemonic = ""; 1013 const char *form = "'Fd, 'Fn, 'Fm"; 1014 1015 switch (instr->Mask(FPDataProcessing2SourceMask)) { 1016 #define FORMAT(A, B) \ 1017 case A##_s: \ 1018 case A##_d: mnemonic = B; break; 1019 FORMAT(FMUL, "fmul"); 1020 FORMAT(FDIV, "fdiv"); 1021 FORMAT(FADD, "fadd"); 1022 FORMAT(FSUB, "fsub"); 1023 FORMAT(FMAX, "fmax"); 1024 FORMAT(FMIN, "fmin"); 1025 FORMAT(FMAXNM, "fmaxnm"); 1026 FORMAT(FMINNM, "fminnm"); 1027 FORMAT(FNMUL, "fnmul"); 1028 #undef FORMAT 1029 default: UNREACHABLE(); 1030 } 1031 Format(instr, mnemonic, form); 1032 } 1033 1034 1035 void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) { 1036 const char *mnemonic = ""; 1037 const char *form = "'Fd, 'Fn, 'Fm, 'Fa"; 1038 1039 switch (instr->Mask(FPDataProcessing3SourceMask)) { 1040 #define FORMAT(A, B) \ 1041 case A##_s: \ 1042 case A##_d: mnemonic = B; break; 1043 FORMAT(FMADD, "fmadd"); 1044 FORMAT(FMSUB, "fmsub"); 1045 FORMAT(FNMADD, "fnmadd"); 1046 FORMAT(FNMSUB, "fnmsub"); 1047 #undef FORMAT 1048 default: UNREACHABLE(); 1049 } 1050 Format(instr, mnemonic, form); 1051 } 1052 1053 1054 void Disassembler::VisitFPImmediate(Instruction* instr) { 1055 const char *mnemonic = ""; 1056 const char *form = "(FPImmediate)"; 1057 1058 switch (instr->Mask(FPImmediateMask)) { 1059 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break; 1060 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break; 1061 default: UNREACHABLE(); 1062 } 1063 Format(instr, mnemonic, form); 1064 } 1065 1066 1067 void Disassembler::VisitFPIntegerConvert(Instruction* instr) { 1068 const char *mnemonic = "unimplemented"; 1069 const char *form = "(FPIntegerConvert)"; 1070 const char *form_rf = "'Rd, 'Fn"; 1071 const char *form_fr = "'Fd, 'Rn"; 1072 1073 switch (instr->Mask(FPIntegerConvertMask)) { 1074 case FMOV_ws: 1075 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break; 1076 case FMOV_sw: 1077 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break; 1078 case FCVTAS_ws: 1079 case FCVTAS_xs: 1080 case FCVTAS_wd: 1081 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break; 1082 case FCVTAU_ws: 1083 case FCVTAU_xs: 1084 case FCVTAU_wd: 1085 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break; 1086 case FCVTMS_ws: 1087 case FCVTMS_xs: 1088 case FCVTMS_wd: 1089 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break; 1090 case FCVTMU_ws: 1091 case FCVTMU_xs: 1092 case FCVTMU_wd: 1093 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break; 1094 case FCVTNS_ws: 1095 case FCVTNS_xs: 1096 case FCVTNS_wd: 1097 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break; 1098 case FCVTNU_ws: 1099 case FCVTNU_xs: 1100 case FCVTNU_wd: 1101 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break; 1102 case FCVTZU_xd: 1103 case FCVTZU_ws: 1104 case FCVTZU_wd: 1105 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break; 1106 case FCVTZS_xd: 1107 case FCVTZS_wd: 1108 case FCVTZS_xs: 1109 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break; 1110 case SCVTF_sw: 1111 case SCVTF_sx: 1112 case SCVTF_dw: 1113 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break; 1114 case UCVTF_sw: 1115 case UCVTF_sx: 1116 case UCVTF_dw: 1117 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break; 1118 } 1119 Format(instr, mnemonic, form); 1120 } 1121 1122 1123 void Disassembler::VisitFPFixedPointConvert(Instruction* instr) { 1124 const char *mnemonic = ""; 1125 const char *form = "'Rd, 'Fn, 'IFPFBits"; 1126 const char *form_fr = "'Fd, 'Rn, 'IFPFBits"; 1127 1128 switch (instr->Mask(FPFixedPointConvertMask)) { 1129 case FCVTZS_ws_fixed: 1130 case FCVTZS_xs_fixed: 1131 case FCVTZS_wd_fixed: 1132 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break; 1133 case FCVTZU_ws_fixed: 1134 case FCVTZU_xs_fixed: 1135 case FCVTZU_wd_fixed: 1136 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break; 1137 case SCVTF_sw_fixed: 1138 case SCVTF_sx_fixed: 1139 case SCVTF_dw_fixed: 1140 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break; 1141 case UCVTF_sw_fixed: 1142 case UCVTF_sx_fixed: 1143 case UCVTF_dw_fixed: 1144 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break; 1145 } 1146 Format(instr, mnemonic, form); 1147 } 1148 1149 1150 void Disassembler::VisitSystem(Instruction* instr) { 1151 // Some system instructions hijack their Op and Cp fields to represent a 1152 // range of immediates instead of indicating a different instruction. This 1153 // makes the decoding tricky. 1154 const char *mnemonic = "unimplemented"; 1155 const char *form = "(System)"; 1156 1157 if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) { 1158 switch (instr->Mask(SystemSysRegMask)) { 1159 case MRS: { 1160 mnemonic = "mrs"; 1161 switch (instr->ImmSystemRegister()) { 1162 case NZCV: form = "'Xt, nzcv"; break; 1163 case FPCR: form = "'Xt, fpcr"; break; 1164 default: form = "'Xt, (unknown)"; break; 1165 } 1166 break; 1167 } 1168 case MSR: { 1169 mnemonic = "msr"; 1170 switch (instr->ImmSystemRegister()) { 1171 case NZCV: form = "nzcv, 'Xt"; break; 1172 case FPCR: form = "fpcr, 'Xt"; break; 1173 default: form = "(unknown), 'Xt"; break; 1174 } 1175 break; 1176 } 1177 } 1178 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) { 1179 DCHECK(instr->Mask(SystemHintMask) == HINT); 1180 switch (instr->ImmHint()) { 1181 case NOP: { 1182 mnemonic = "nop"; 1183 form = NULL; 1184 break; 1185 } 1186 } 1187 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) { 1188 switch (instr->Mask(MemBarrierMask)) { 1189 case DMB: { 1190 mnemonic = "dmb"; 1191 form = "'M"; 1192 break; 1193 } 1194 case DSB: { 1195 mnemonic = "dsb"; 1196 form = "'M"; 1197 break; 1198 } 1199 case ISB: { 1200 mnemonic = "isb"; 1201 form = NULL; 1202 break; 1203 } 1204 } 1205 } 1206 1207 Format(instr, mnemonic, form); 1208 } 1209 1210 1211 void Disassembler::VisitException(Instruction* instr) { 1212 const char *mnemonic = "unimplemented"; 1213 const char *form = "'IDebug"; 1214 1215 switch (instr->Mask(ExceptionMask)) { 1216 case HLT: mnemonic = "hlt"; break; 1217 case BRK: mnemonic = "brk"; break; 1218 case SVC: mnemonic = "svc"; break; 1219 case HVC: mnemonic = "hvc"; break; 1220 case SMC: mnemonic = "smc"; break; 1221 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break; 1222 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break; 1223 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break; 1224 default: form = "(Exception)"; 1225 } 1226 Format(instr, mnemonic, form); 1227 } 1228 1229 1230 void Disassembler::VisitUnimplemented(Instruction* instr) { 1231 Format(instr, "unimplemented", "(Unimplemented)"); 1232 } 1233 1234 1235 void Disassembler::VisitUnallocated(Instruction* instr) { 1236 Format(instr, "unallocated", "(Unallocated)"); 1237 } 1238 1239 1240 void Disassembler::ProcessOutput(Instruction* /*instr*/) { 1241 // The base disasm does nothing more than disassembling into a buffer. 1242 } 1243 1244 1245 void Disassembler::Format(Instruction* instr, const char* mnemonic, 1246 const char* format) { 1247 // TODO(mcapewel) don't think I can use the instr address here - there needs 1248 // to be a base address too 1249 DCHECK(mnemonic != NULL); 1250 ResetOutput(); 1251 Substitute(instr, mnemonic); 1252 if (format != NULL) { 1253 buffer_[buffer_pos_++] = ' '; 1254 Substitute(instr, format); 1255 } 1256 buffer_[buffer_pos_] = 0; 1257 ProcessOutput(instr); 1258 } 1259 1260 1261 void Disassembler::Substitute(Instruction* instr, const char* string) { 1262 char chr = *string++; 1263 while (chr != '\0') { 1264 if (chr == '\'') { 1265 string += SubstituteField(instr, string); 1266 } else { 1267 buffer_[buffer_pos_++] = chr; 1268 } 1269 chr = *string++; 1270 } 1271 } 1272 1273 1274 int Disassembler::SubstituteField(Instruction* instr, const char* format) { 1275 switch (format[0]) { 1276 case 'R': // Register. X or W, selected by sf bit. 1277 case 'F': // FP Register. S or D, selected by type field. 1278 case 'W': 1279 case 'X': 1280 case 'S': 1281 case 'D': return SubstituteRegisterField(instr, format); 1282 case 'I': return SubstituteImmediateField(instr, format); 1283 case 'L': return SubstituteLiteralField(instr, format); 1284 case 'H': return SubstituteShiftField(instr, format); 1285 case 'P': return SubstitutePrefetchField(instr, format); 1286 case 'C': return SubstituteConditionField(instr, format); 1287 case 'E': return SubstituteExtendField(instr, format); 1288 case 'A': return SubstitutePCRelAddressField(instr, format); 1289 case 'B': return SubstituteBranchTargetField(instr, format); 1290 case 'O': return SubstituteLSRegOffsetField(instr, format); 1291 case 'M': return SubstituteBarrierField(instr, format); 1292 default: { 1293 UNREACHABLE(); 1294 return 1; 1295 } 1296 } 1297 } 1298 1299 1300 int Disassembler::SubstituteRegisterField(Instruction* instr, 1301 const char* format) { 1302 unsigned reg_num = 0; 1303 unsigned field_len = 2; 1304 switch (format[1]) { 1305 case 'd': reg_num = instr->Rd(); break; 1306 case 'n': reg_num = instr->Rn(); break; 1307 case 'm': reg_num = instr->Rm(); break; 1308 case 'a': reg_num = instr->Ra(); break; 1309 case 't': { 1310 if (format[2] == '2') { 1311 reg_num = instr->Rt2(); 1312 field_len = 3; 1313 } else { 1314 reg_num = instr->Rt(); 1315 } 1316 break; 1317 } 1318 default: UNREACHABLE(); 1319 } 1320 1321 // Increase field length for registers tagged as stack. 1322 if (format[2] == 's') { 1323 field_len = 3; 1324 } 1325 1326 char reg_type; 1327 if (format[0] == 'R') { 1328 // Register type is R: use sf bit to choose X and W. 1329 reg_type = instr->SixtyFourBits() ? 'x' : 'w'; 1330 } else if (format[0] == 'F') { 1331 // Floating-point register: use type field to choose S or D. 1332 reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd'; 1333 } else { 1334 // Register type is specified. Make it lower case. 1335 reg_type = format[0] + 0x20; 1336 } 1337 1338 if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) { 1339 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31. 1340 1341 // Filter special registers 1342 if ((reg_type == 'x') && (reg_num == 27)) { 1343 AppendToOutput("cp"); 1344 } else if ((reg_type == 'x') && (reg_num == 28)) { 1345 AppendToOutput("jssp"); 1346 } else if ((reg_type == 'x') && (reg_num == 29)) { 1347 AppendToOutput("fp"); 1348 } else if ((reg_type == 'x') && (reg_num == 30)) { 1349 AppendToOutput("lr"); 1350 } else { 1351 AppendToOutput("%c%d", reg_type, reg_num); 1352 } 1353 } else if (format[2] == 's') { 1354 // Disassemble w31/x31 as stack pointer wcsp/csp. 1355 AppendToOutput("%s", (reg_type == 'w') ? "wcsp" : "csp"); 1356 } else { 1357 // Disassemble w31/x31 as zero register wzr/xzr. 1358 AppendToOutput("%czr", reg_type); 1359 } 1360 1361 return field_len; 1362 } 1363 1364 1365 int Disassembler::SubstituteImmediateField(Instruction* instr, 1366 const char* format) { 1367 DCHECK(format[0] == 'I'); 1368 1369 switch (format[1]) { 1370 case 'M': { // IMoveImm or IMoveLSL. 1371 if (format[5] == 'I') { 1372 uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide()); 1373 AppendToOutput("#0x%" PRIx64, imm); 1374 } else { 1375 DCHECK(format[5] == 'L'); 1376 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide()); 1377 if (instr->ShiftMoveWide() > 0) { 1378 AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide()); 1379 } 1380 } 1381 return 8; 1382 } 1383 case 'L': { 1384 switch (format[2]) { 1385 case 'L': { // ILLiteral - Immediate Load Literal. 1386 AppendToOutput("pc%+" PRId64, 1387 instr->ImmLLiteral() << kLoadLiteralScaleLog2); 1388 return 9; 1389 } 1390 case 'S': { // ILS - Immediate Load/Store. 1391 if (instr->ImmLS() != 0) { 1392 AppendToOutput(", #%" PRId64, instr->ImmLS()); 1393 } 1394 return 3; 1395 } 1396 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size. 1397 if (instr->ImmLSPair() != 0) { 1398 // format[3] is the scale value. Convert to a number. 1399 int scale = format[3] - 0x30; 1400 AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale); 1401 } 1402 return 4; 1403 } 1404 case 'U': { // ILU - Immediate Load/Store Unsigned. 1405 if (instr->ImmLSUnsigned() != 0) { 1406 AppendToOutput(", #%" PRIu64, 1407 instr->ImmLSUnsigned() << instr->SizeLS()); 1408 } 1409 return 3; 1410 } 1411 } 1412 } 1413 case 'C': { // ICondB - Immediate Conditional Branch. 1414 int64_t offset = instr->ImmCondBranch() << 2; 1415 char sign = (offset >= 0) ? '+' : '-'; 1416 AppendToOutput("#%c0x%" PRIx64, sign, offset); 1417 return 6; 1418 } 1419 case 'A': { // IAddSub. 1420 DCHECK(instr->ShiftAddSub() <= 1); 1421 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub()); 1422 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm); 1423 return 7; 1424 } 1425 case 'F': { // IFPSingle, IFPDouble or IFPFBits. 1426 if (format[3] == 'F') { // IFPFBits. 1427 AppendToOutput("#%d", 64 - instr->FPScale()); 1428 return 8; 1429 } else { 1430 AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(), 1431 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64()); 1432 return 9; 1433 } 1434 } 1435 case 'T': { // ITri - Immediate Triangular Encoded. 1436 AppendToOutput("#0x%" PRIx64, instr->ImmLogical()); 1437 return 4; 1438 } 1439 case 'N': { // INzcv. 1440 int nzcv = (instr->Nzcv() << Flags_offset); 1441 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N', 1442 ((nzcv & ZFlag) == 0) ? 'z' : 'Z', 1443 ((nzcv & CFlag) == 0) ? 'c' : 'C', 1444 ((nzcv & VFlag) == 0) ? 'v' : 'V'); 1445 return 5; 1446 } 1447 case 'P': { // IP - Conditional compare. 1448 AppendToOutput("#%d", instr->ImmCondCmp()); 1449 return 2; 1450 } 1451 case 'B': { // Bitfields. 1452 return SubstituteBitfieldImmediateField(instr, format); 1453 } 1454 case 'E': { // IExtract. 1455 AppendToOutput("#%d", instr->ImmS()); 1456 return 8; 1457 } 1458 case 'S': { // IS - Test and branch bit. 1459 AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) | 1460 instr->ImmTestBranchBit40()); 1461 return 2; 1462 } 1463 case 'D': { // IDebug - HLT and BRK instructions. 1464 AppendToOutput("#0x%x", instr->ImmException()); 1465 return 6; 1466 } 1467 default: { 1468 UNREACHABLE(); 1469 return 0; 1470 } 1471 } 1472 } 1473 1474 1475 int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr, 1476 const char* format) { 1477 DCHECK((format[0] == 'I') && (format[1] == 'B')); 1478 unsigned r = instr->ImmR(); 1479 unsigned s = instr->ImmS(); 1480 1481 switch (format[2]) { 1482 case 'r': { // IBr. 1483 AppendToOutput("#%d", r); 1484 return 3; 1485 } 1486 case 's': { // IBs+1 or IBs-r+1. 1487 if (format[3] == '+') { 1488 AppendToOutput("#%d", s + 1); 1489 return 5; 1490 } else { 1491 DCHECK(format[3] == '-'); 1492 AppendToOutput("#%d", s - r + 1); 1493 return 7; 1494 } 1495 } 1496 case 'Z': { // IBZ-r. 1497 DCHECK((format[3] == '-') && (format[4] == 'r')); 1498 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSizeInBits 1499 : kWRegSizeInBits; 1500 AppendToOutput("#%d", reg_size - r); 1501 return 5; 1502 } 1503 default: { 1504 UNREACHABLE(); 1505 return 0; 1506 } 1507 } 1508 } 1509 1510 1511 int Disassembler::SubstituteLiteralField(Instruction* instr, 1512 const char* format) { 1513 DCHECK(strncmp(format, "LValue", 6) == 0); 1514 USE(format); 1515 1516 switch (instr->Mask(LoadLiteralMask)) { 1517 case LDR_w_lit: 1518 case LDR_x_lit: 1519 case LDR_s_lit: 1520 case LDR_d_lit: 1521 AppendToOutput("(addr 0x%016" PRIxPTR ")", instr->LiteralAddress()); 1522 break; 1523 default: UNREACHABLE(); 1524 } 1525 1526 return 6; 1527 } 1528 1529 1530 int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) { 1531 DCHECK(format[0] == 'H'); 1532 DCHECK(instr->ShiftDP() <= 0x3); 1533 1534 switch (format[1]) { 1535 case 'D': { // HDP. 1536 DCHECK(instr->ShiftDP() != ROR); 1537 } // Fall through. 1538 case 'L': { // HLo. 1539 if (instr->ImmDPShift() != 0) { 1540 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"}; 1541 AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()], 1542 instr->ImmDPShift()); 1543 } 1544 return 3; 1545 } 1546 default: 1547 UNREACHABLE(); 1548 return 0; 1549 } 1550 } 1551 1552 1553 int Disassembler::SubstituteConditionField(Instruction* instr, 1554 const char* format) { 1555 DCHECK(format[0] == 'C'); 1556 const char* condition_code[] = { "eq", "ne", "hs", "lo", 1557 "mi", "pl", "vs", "vc", 1558 "hi", "ls", "ge", "lt", 1559 "gt", "le", "al", "nv" }; 1560 int cond; 1561 switch (format[1]) { 1562 case 'B': cond = instr->ConditionBranch(); break; 1563 case 'I': { 1564 cond = NegateCondition(static_cast<Condition>(instr->Condition())); 1565 break; 1566 } 1567 default: cond = instr->Condition(); 1568 } 1569 AppendToOutput("%s", condition_code[cond]); 1570 return 4; 1571 } 1572 1573 1574 int Disassembler::SubstitutePCRelAddressField(Instruction* instr, 1575 const char* format) { 1576 USE(format); 1577 DCHECK(strncmp(format, "AddrPCRel", 9) == 0); 1578 1579 int offset = instr->ImmPCRel(); 1580 1581 // Only ADR (AddrPCRelByte) is supported. 1582 DCHECK(strcmp(format, "AddrPCRelByte") == 0); 1583 1584 char sign = '+'; 1585 if (offset < 0) { 1586 offset = -offset; 1587 sign = '-'; 1588 } 1589 AppendToOutput("#%c0x%x (addr %p)", sign, offset, 1590 instr->InstructionAtOffset(offset, Instruction::NO_CHECK)); 1591 return 13; 1592 } 1593 1594 1595 int Disassembler::SubstituteBranchTargetField(Instruction* instr, 1596 const char* format) { 1597 DCHECK(strncmp(format, "BImm", 4) == 0); 1598 1599 int64_t offset = 0; 1600 switch (format[5]) { 1601 // BImmUncn - unconditional branch immediate. 1602 case 'n': offset = instr->ImmUncondBranch(); break; 1603 // BImmCond - conditional branch immediate. 1604 case 'o': offset = instr->ImmCondBranch(); break; 1605 // BImmCmpa - compare and branch immediate. 1606 case 'm': offset = instr->ImmCmpBranch(); break; 1607 // BImmTest - test and branch immediate. 1608 case 'e': offset = instr->ImmTestBranch(); break; 1609 default: UNREACHABLE(); 1610 } 1611 offset <<= kInstructionSizeLog2; 1612 char sign = '+'; 1613 if (offset < 0) { 1614 sign = '-'; 1615 } 1616 AppendToOutput("#%c0x%" PRIx64 " (addr %p)", sign, Abs(offset), 1617 instr->InstructionAtOffset(offset), Instruction::NO_CHECK); 1618 return 8; 1619 } 1620 1621 1622 int Disassembler::SubstituteExtendField(Instruction* instr, 1623 const char* format) { 1624 DCHECK(strncmp(format, "Ext", 3) == 0); 1625 DCHECK(instr->ExtendMode() <= 7); 1626 USE(format); 1627 1628 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx", 1629 "sxtb", "sxth", "sxtw", "sxtx" }; 1630 1631 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit 1632 // registers becomes lsl. 1633 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) && 1634 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) || 1635 (instr->ExtendMode() == UXTX))) { 1636 if (instr->ImmExtendShift() > 0) { 1637 AppendToOutput(", lsl #%d", instr->ImmExtendShift()); 1638 } 1639 } else { 1640 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]); 1641 if (instr->ImmExtendShift() > 0) { 1642 AppendToOutput(" #%d", instr->ImmExtendShift()); 1643 } 1644 } 1645 return 3; 1646 } 1647 1648 1649 int Disassembler::SubstituteLSRegOffsetField(Instruction* instr, 1650 const char* format) { 1651 DCHECK(strncmp(format, "Offsetreg", 9) == 0); 1652 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl", 1653 "undefined", "undefined", "sxtw", "sxtx" }; 1654 USE(format); 1655 1656 unsigned shift = instr->ImmShiftLS(); 1657 Extend ext = static_cast<Extend>(instr->ExtendMode()); 1658 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x'; 1659 1660 unsigned rm = instr->Rm(); 1661 if (rm == kZeroRegCode) { 1662 AppendToOutput("%czr", reg_type); 1663 } else { 1664 AppendToOutput("%c%d", reg_type, rm); 1665 } 1666 1667 // Extend mode UXTX is an alias for shift mode LSL here. 1668 if (!((ext == UXTX) && (shift == 0))) { 1669 AppendToOutput(", %s", extend_mode[ext]); 1670 if (shift != 0) { 1671 AppendToOutput(" #%d", instr->SizeLS()); 1672 } 1673 } 1674 return 9; 1675 } 1676 1677 1678 int Disassembler::SubstitutePrefetchField(Instruction* instr, 1679 const char* format) { 1680 DCHECK(format[0] == 'P'); 1681 USE(format); 1682 1683 int prefetch_mode = instr->PrefetchMode(); 1684 1685 const char* ls = (prefetch_mode & 0x10) ? "st" : "ld"; 1686 int level = (prefetch_mode >> 1) + 1; 1687 const char* ks = (prefetch_mode & 1) ? "strm" : "keep"; 1688 1689 AppendToOutput("p%sl%d%s", ls, level, ks); 1690 return 6; 1691 } 1692 1693 int Disassembler::SubstituteBarrierField(Instruction* instr, 1694 const char* format) { 1695 DCHECK(format[0] == 'M'); 1696 USE(format); 1697 1698 static const char* options[4][4] = { 1699 { "sy (0b0000)", "oshld", "oshst", "osh" }, 1700 { "sy (0b0100)", "nshld", "nshst", "nsh" }, 1701 { "sy (0b1000)", "ishld", "ishst", "ish" }, 1702 { "sy (0b1100)", "ld", "st", "sy" } 1703 }; 1704 int domain = instr->ImmBarrierDomain(); 1705 int type = instr->ImmBarrierType(); 1706 1707 AppendToOutput("%s", options[domain][type]); 1708 return 1; 1709 } 1710 1711 1712 void Disassembler::ResetOutput() { 1713 buffer_pos_ = 0; 1714 buffer_[buffer_pos_] = 0; 1715 } 1716 1717 1718 void Disassembler::AppendToOutput(const char* format, ...) { 1719 va_list args; 1720 va_start(args, format); 1721 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args); 1722 va_end(args); 1723 } 1724 1725 1726 void PrintDisassembler::ProcessOutput(Instruction* instr) { 1727 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n", 1728 reinterpret_cast<uint64_t>(instr), instr->InstructionBits(), 1729 GetOutput()); 1730 } 1731 1732 } } // namespace v8::internal 1733 1734 1735 namespace disasm { 1736 1737 1738 const char* NameConverter::NameOfAddress(byte* addr) const { 1739 v8::internal::SNPrintF(tmp_buffer_, "%p", addr); 1740 return tmp_buffer_.start(); 1741 } 1742 1743 1744 const char* NameConverter::NameOfConstant(byte* addr) const { 1745 return NameOfAddress(addr); 1746 } 1747 1748 1749 const char* NameConverter::NameOfCPURegister(int reg) const { 1750 unsigned ureg = reg; // Avoid warnings about signed/unsigned comparisons. 1751 if (ureg >= v8::internal::kNumberOfRegisters) { 1752 return "noreg"; 1753 } 1754 if (ureg == v8::internal::kZeroRegCode) { 1755 return "xzr"; 1756 } 1757 v8::internal::SNPrintF(tmp_buffer_, "x%u", ureg); 1758 return tmp_buffer_.start(); 1759 } 1760 1761 1762 const char* NameConverter::NameOfByteCPURegister(int reg) const { 1763 UNREACHABLE(); // ARM64 does not have the concept of a byte register 1764 return "nobytereg"; 1765 } 1766 1767 1768 const char* NameConverter::NameOfXMMRegister(int reg) const { 1769 UNREACHABLE(); // ARM64 does not have any XMM registers 1770 return "noxmmreg"; 1771 } 1772 1773 1774 const char* NameConverter::NameInCode(byte* addr) const { 1775 // The default name converter is called for unknown code, so we will not try 1776 // to access any memory. 1777 return ""; 1778 } 1779 1780 1781 //------------------------------------------------------------------------------ 1782 1783 class BufferDisassembler : public v8::internal::Disassembler { 1784 public: 1785 explicit BufferDisassembler(v8::internal::Vector<char> out_buffer) 1786 : out_buffer_(out_buffer) { } 1787 1788 ~BufferDisassembler() { } 1789 1790 virtual void ProcessOutput(v8::internal::Instruction* instr) { 1791 v8::internal::SNPrintF(out_buffer_, "%s", GetOutput()); 1792 } 1793 1794 private: 1795 v8::internal::Vector<char> out_buffer_; 1796 }; 1797 1798 Disassembler::Disassembler(const NameConverter& converter) 1799 : converter_(converter) {} 1800 1801 1802 Disassembler::~Disassembler() { USE(converter_); } 1803 1804 1805 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 1806 byte* instr) { 1807 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder; 1808 BufferDisassembler disasm(buffer); 1809 decoder.AppendVisitor(&disasm); 1810 1811 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(instr)); 1812 return v8::internal::kInstructionSize; 1813 } 1814 1815 1816 int Disassembler::ConstantPoolSizeAt(byte* instr) { 1817 return v8::internal::Assembler::ConstantPoolSizeAt( 1818 reinterpret_cast<v8::internal::Instruction*>(instr)); 1819 } 1820 1821 1822 void Disassembler::Disassemble(FILE* file, byte* start, byte* end) { 1823 v8::internal::Decoder<v8::internal::DispatchingDecoderVisitor> decoder; 1824 v8::internal::PrintDisassembler disasm(file); 1825 decoder.AppendVisitor(&disasm); 1826 1827 for (byte* pc = start; pc < end; pc += v8::internal::kInstructionSize) { 1828 decoder.Decode(reinterpret_cast<v8::internal::Instruction*>(pc)); 1829 } 1830 } 1831 1832 } // namespace disasm 1833 1834 #endif // V8_TARGET_ARCH_ARM64 1835