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