1 // Copyright 2013, ARM Limited
2 // All rights reserved.
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
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.
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.
28 #include "a64/disasm-a64.h"
32 Disassembler::Disassembler() {
34 buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
37 code_address_offset_ = 0;
41 Disassembler::Disassembler(char* text_buffer, int buffer_size) {
42 buffer_size_ = buffer_size;
43 buffer_ = text_buffer;
46 code_address_offset_ = 0;
50 Disassembler::~Disassembler() {
57 char* Disassembler::GetOutput() {
62 void Disassembler::VisitAddSubImmediate(const Instruction* instr) {
63 bool rd_is_zr = RdIsZROrSP(instr);
64 bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
65 (instr->ImmAddSub() == 0) ? true : false;
66 const char *mnemonic = "";
67 const char *form = "'Rds, 'Rns, 'IAddSub";
68 const char *form_cmp = "'Rns, 'IAddSub";
69 const char *form_mov = "'Rds, 'Rns";
71 switch (instr->Mask(AddSubImmediateMask)) {
91 case SUB_x_imm: mnemonic = "sub"; break;
101 default: VIXL_UNREACHABLE();
103 Format(instr, mnemonic, form);
107 void Disassembler::VisitAddSubShifted(const Instruction* instr) {
108 bool rd_is_zr = RdIsZROrSP(instr);
109 bool rn_is_zr = RnIsZROrSP(instr);
110 const char *mnemonic = "";
111 const char *form = "'Rd, 'Rn, 'Rm'HDP";
112 const char *form_cmp = "'Rn, 'Rm'HDP";
113 const char *form_neg = "'Rd, 'Rm'HDP";
115 switch (instr->Mask(AddSubShiftedMask)) {
117 case ADD_x_shift: mnemonic = "add"; break;
142 } else if (rn_is_zr) {
148 default: VIXL_UNREACHABLE();
150 Format(instr, mnemonic, form);
154 void Disassembler::VisitAddSubExtended(const Instruction* instr) {
155 bool rd_is_zr = RdIsZROrSP(instr);
156 const char *mnemonic = "";
157 Extend mode = static_cast<Extend>(instr->ExtendMode());
158 const char *form = ((mode == UXTX) || (mode == SXTX)) ?
159 "'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
160 const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
161 "'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
163 switch (instr->Mask(AddSubExtendedMask)) {
165 case ADD_x_ext: mnemonic = "add"; break;
176 case SUB_x_ext: mnemonic = "sub"; break;
186 default: VIXL_UNREACHABLE();
188 Format(instr, mnemonic, form);
192 void Disassembler::VisitAddSubWithCarry(const Instruction* instr) {
193 bool rn_is_zr = RnIsZROrSP(instr);
194 const char *mnemonic = "";
195 const char *form = "'Rd, 'Rn, 'Rm";
196 const char *form_neg = "'Rd, 'Rm";
198 switch (instr->Mask(AddSubWithCarryMask)) {
200 case ADC_x: mnemonic = "adc"; break;
202 case ADCS_x: mnemonic = "adcs"; break;
221 default: VIXL_UNREACHABLE();
223 Format(instr, mnemonic, form);
227 void Disassembler::VisitLogicalImmediate(const Instruction* instr) {
228 bool rd_is_zr = RdIsZROrSP(instr);
229 bool rn_is_zr = RnIsZROrSP(instr);
230 const char *mnemonic = "";
231 const char *form = "'Rds, 'Rn, 'ITri";
233 if (instr->ImmLogical() == 0) {
234 // The immediate encoded in the instruction is not in the expected format.
235 Format(instr, "unallocated", "(LogicalImmediate)");
239 switch (instr->Mask(LogicalImmediateMask)) {
241 case AND_x_imm: mnemonic = "and"; break;
245 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
247 if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
249 form = "'Rds, 'ITri";
254 case EOR_x_imm: mnemonic = "eor"; break;
264 default: VIXL_UNREACHABLE();
266 Format(instr, mnemonic, form);
270 bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
271 VIXL_ASSERT((reg_size == kXRegSize) ||
272 ((reg_size == kWRegSize) && (value <= 0xffffffff)));
274 // Test for movz: 16 bits set at positions 0, 16, 32 or 48.
275 if (((value & UINT64_C(0xffffffffffff0000)) == 0) ||
276 ((value & UINT64_C(0xffffffff0000ffff)) == 0) ||
277 ((value & UINT64_C(0xffff0000ffffffff)) == 0) ||
278 ((value & UINT64_C(0x0000ffffffffffff)) == 0)) {
282 // Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
283 if ((reg_size == kXRegSize) &&
284 (((~value & UINT64_C(0xffffffffffff0000)) == 0) ||
285 ((~value & UINT64_C(0xffffffff0000ffff)) == 0) ||
286 ((~value & UINT64_C(0xffff0000ffffffff)) == 0) ||
287 ((~value & UINT64_C(0x0000ffffffffffff)) == 0))) {
290 if ((reg_size == kWRegSize) &&
291 (((value & 0xffff0000) == 0xffff0000) ||
292 ((value & 0x0000ffff) == 0x0000ffff))) {
299 void Disassembler::VisitLogicalShifted(const Instruction* instr) {
300 bool rd_is_zr = RdIsZROrSP(instr);
301 bool rn_is_zr = RnIsZROrSP(instr);
302 const char *mnemonic = "";
303 const char *form = "'Rd, 'Rn, 'Rm'HLo";
305 switch (instr->Mask(LogicalShiftedMask)) {
307 case AND_x: mnemonic = "and"; break;
309 case BIC_x: mnemonic = "bic"; break;
311 case EOR_x: mnemonic = "eor"; break;
313 case EON_x: mnemonic = "eon"; break;
315 case BICS_x: mnemonic = "bics"; break;
321 form = "'Rn, 'Rm'HLo";
328 if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
339 form = "'Rd, 'Rm'HLo";
343 default: VIXL_UNREACHABLE();
346 Format(instr, mnemonic, form);
350 void Disassembler::VisitConditionalCompareRegister(const Instruction* instr) {
351 const char *mnemonic = "";
352 const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
354 switch (instr->Mask(ConditionalCompareRegisterMask)) {
356 case CCMN_x: mnemonic = "ccmn"; break;
358 case CCMP_x: mnemonic = "ccmp"; break;
359 default: VIXL_UNREACHABLE();
361 Format(instr, mnemonic, form);
365 void Disassembler::VisitConditionalCompareImmediate(const Instruction* instr) {
366 const char *mnemonic = "";
367 const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
369 switch (instr->Mask(ConditionalCompareImmediateMask)) {
371 case CCMN_x_imm: mnemonic = "ccmn"; break;
373 case CCMP_x_imm: mnemonic = "ccmp"; break;
374 default: VIXL_UNREACHABLE();
376 Format(instr, mnemonic, form);
380 void Disassembler::VisitConditionalSelect(const Instruction* instr) {
381 bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
382 bool rn_is_rm = (instr->Rn() == instr->Rm());
383 const char *mnemonic = "";
384 const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
385 const char *form_test = "'Rd, 'CInv";
386 const char *form_update = "'Rd, 'Rn, 'CInv";
388 Condition cond = static_cast<Condition>(instr->Condition());
389 bool invertible_cond = (cond != al) && (cond != nv);
391 switch (instr->Mask(ConditionalSelectMask)) {
393 case CSEL_x: mnemonic = "csel"; break;
397 if (rnm_is_zr && invertible_cond) {
400 } else if (rn_is_rm && invertible_cond) {
409 if (rnm_is_zr && invertible_cond) {
412 } else if (rn_is_rm && invertible_cond) {
421 if (rn_is_rm && invertible_cond) {
427 default: VIXL_UNREACHABLE();
429 Format(instr, mnemonic, form);
433 void Disassembler::VisitBitfield(const Instruction* instr) {
434 unsigned s = instr->ImmS();
435 unsigned r = instr->ImmR();
436 unsigned rd_size_minus_1 =
437 ((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;
438 const char *mnemonic = "";
439 const char *form = "";
440 const char *form_shift_right = "'Rd, 'Rn, 'IBr";
441 const char *form_extend = "'Rd, 'Wn";
442 const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
443 const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
444 const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
446 switch (instr->Mask(BitfieldMask)) {
455 } else if (s == 15) {
457 } else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
462 } else if (s == rd_size_minus_1) {
464 form = form_shift_right;
479 } else if (s == 15) {
485 if (s == rd_size_minus_1) {
487 form = form_shift_right;
488 } else if (r == s + 1) {
507 Format(instr, mnemonic, form);
511 void Disassembler::VisitExtract(const Instruction* instr) {
512 const char *mnemonic = "";
513 const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
515 switch (instr->Mask(ExtractMask)) {
518 if (instr->Rn() == instr->Rm()) {
520 form = "'Rd, 'Rn, 'IExtract";
526 default: VIXL_UNREACHABLE();
528 Format(instr, mnemonic, form);
532 void Disassembler::VisitPCRelAddressing(const Instruction* instr) {
533 switch (instr->Mask(PCRelAddressingMask)) {
534 case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
535 case ADRP: Format(instr, "adrp", "'Xd, 'AddrPCRelPage"); break;
536 default: Format(instr, "unimplemented", "(PCRelAddressing)");
541 void Disassembler::VisitConditionalBranch(const Instruction* instr) {
542 switch (instr->Mask(ConditionalBranchMask)) {
543 case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
544 default: VIXL_UNREACHABLE();
549 void Disassembler::VisitUnconditionalBranchToRegister(
550 const Instruction* instr) {
551 const char *mnemonic = "unimplemented";
552 const char *form = "'Xn";
554 switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
555 case BR: mnemonic = "br"; break;
556 case BLR: mnemonic = "blr"; break;
559 if (instr->Rn() == kLinkRegCode) {
564 default: form = "(UnconditionalBranchToRegister)";
566 Format(instr, mnemonic, form);
570 void Disassembler::VisitUnconditionalBranch(const Instruction* instr) {
571 const char *mnemonic = "";
572 const char *form = "'BImmUncn";
574 switch (instr->Mask(UnconditionalBranchMask)) {
575 case B: mnemonic = "b"; break;
576 case BL: mnemonic = "bl"; break;
577 default: VIXL_UNREACHABLE();
579 Format(instr, mnemonic, form);
583 void Disassembler::VisitDataProcessing1Source(const Instruction* instr) {
584 const char *mnemonic = "";
585 const char *form = "'Rd, 'Rn";
587 switch (instr->Mask(DataProcessing1SourceMask)) {
588 #define FORMAT(A, B) \
590 case A##_x: mnemonic = B; break;
591 FORMAT(RBIT, "rbit");
592 FORMAT(REV16, "rev16");
597 case REV32_x: mnemonic = "rev32"; break;
598 default: VIXL_UNREACHABLE();
600 Format(instr, mnemonic, form);
604 void Disassembler::VisitDataProcessing2Source(const Instruction* instr) {
605 const char *mnemonic = "unimplemented";
606 const char *form = "'Rd, 'Rn, 'Rm";
608 switch (instr->Mask(DataProcessing2SourceMask)) {
609 #define FORMAT(A, B) \
611 case A##_x: mnemonic = B; break;
612 FORMAT(UDIV, "udiv");
613 FORMAT(SDIV, "sdiv");
619 default: form = "(DataProcessing2Source)";
621 Format(instr, mnemonic, form);
625 void Disassembler::VisitDataProcessing3Source(const Instruction* instr) {
626 bool ra_is_zr = RaIsZROrSP(instr);
627 const char *mnemonic = "";
628 const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
629 const char *form_rrr = "'Rd, 'Rn, 'Rm";
630 const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
631 const char *form_xww = "'Xd, 'Wn, 'Wm";
632 const char *form_xxx = "'Xd, 'Xn, 'Xm";
634 switch (instr->Mask(DataProcessing3SourceMask)) {
697 default: VIXL_UNREACHABLE();
699 Format(instr, mnemonic, form);
703 void Disassembler::VisitCompareBranch(const Instruction* instr) {
704 const char *mnemonic = "";
705 const char *form = "'Rt, 'BImmCmpa";
707 switch (instr->Mask(CompareBranchMask)) {
709 case CBZ_x: mnemonic = "cbz"; break;
711 case CBNZ_x: mnemonic = "cbnz"; break;
712 default: VIXL_UNREACHABLE();
714 Format(instr, mnemonic, form);
718 void Disassembler::VisitTestBranch(const Instruction* instr) {
719 const char *mnemonic = "";
720 // If the top bit of the immediate is clear, the tested register is
721 // disassembled as Wt, otherwise Xt. As the top bit of the immediate is
722 // encoded in bit 31 of the instruction, we can reuse the Rt form, which
723 // uses bit 31 (normally "sf") to choose the register size.
724 const char *form = "'Rt, 'IS, 'BImmTest";
726 switch (instr->Mask(TestBranchMask)) {
727 case TBZ: mnemonic = "tbz"; break;
728 case TBNZ: mnemonic = "tbnz"; break;
729 default: VIXL_UNREACHABLE();
731 Format(instr, mnemonic, form);
735 void Disassembler::VisitMoveWideImmediate(const Instruction* instr) {
736 const char *mnemonic = "";
737 const char *form = "'Rd, 'IMoveImm";
739 // Print the shift separately for movk, to make it clear which half word will
740 // be overwritten. Movn and movz print the computed immediate, which includes
741 // shift calculation.
742 switch (instr->Mask(MoveWideImmediateMask)) {
745 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0)) {
746 if ((instr->SixtyFourBits() == 0) && (instr->ImmMoveWide() == 0xffff)) {
750 form = "'Rd, 'IMoveNeg";
758 if ((instr->ImmMoveWide()) || (instr->ShiftMoveWide() == 0))
764 case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
765 default: VIXL_UNREACHABLE();
767 Format(instr, mnemonic, form);
771 #define LOAD_STORE_LIST(V) \
772 V(STRB_w, "strb", "'Wt") \
773 V(STRH_w, "strh", "'Wt") \
774 V(STR_w, "str", "'Wt") \
775 V(STR_x, "str", "'Xt") \
776 V(LDRB_w, "ldrb", "'Wt") \
777 V(LDRH_w, "ldrh", "'Wt") \
778 V(LDR_w, "ldr", "'Wt") \
779 V(LDR_x, "ldr", "'Xt") \
780 V(LDRSB_x, "ldrsb", "'Xt") \
781 V(LDRSH_x, "ldrsh", "'Xt") \
782 V(LDRSW_x, "ldrsw", "'Xt") \
783 V(LDRSB_w, "ldrsb", "'Wt") \
784 V(LDRSH_w, "ldrsh", "'Wt") \
785 V(STR_s, "str", "'St") \
786 V(STR_d, "str", "'Dt") \
787 V(LDR_s, "ldr", "'St") \
788 V(LDR_d, "ldr", "'Dt")
790 void Disassembler::VisitLoadStorePreIndex(const Instruction* instr) {
791 const char *mnemonic = "unimplemented";
792 const char *form = "(LoadStorePreIndex)";
794 switch (instr->Mask(LoadStorePreIndexMask)) {
795 #define LS_PREINDEX(A, B, C) \
796 case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
797 LOAD_STORE_LIST(LS_PREINDEX)
800 Format(instr, mnemonic, form);
804 void Disassembler::VisitLoadStorePostIndex(const Instruction* instr) {
805 const char *mnemonic = "unimplemented";
806 const char *form = "(LoadStorePostIndex)";
808 switch (instr->Mask(LoadStorePostIndexMask)) {
809 #define LS_POSTINDEX(A, B, C) \
810 case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
811 LOAD_STORE_LIST(LS_POSTINDEX)
814 Format(instr, mnemonic, form);
818 void Disassembler::VisitLoadStoreUnsignedOffset(const Instruction* instr) {
819 const char *mnemonic = "unimplemented";
820 const char *form = "(LoadStoreUnsignedOffset)";
822 switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
823 #define LS_UNSIGNEDOFFSET(A, B, C) \
824 case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
825 LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
826 #undef LS_UNSIGNEDOFFSET
827 case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xns'ILU]";
829 Format(instr, mnemonic, form);
833 void Disassembler::VisitLoadStoreRegisterOffset(const Instruction* instr) {
834 const char *mnemonic = "unimplemented";
835 const char *form = "(LoadStoreRegisterOffset)";
837 switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
838 #define LS_REGISTEROFFSET(A, B, C) \
839 case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
840 LOAD_STORE_LIST(LS_REGISTEROFFSET)
841 #undef LS_REGISTEROFFSET
842 case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
844 Format(instr, mnemonic, form);
848 void Disassembler::VisitLoadStoreUnscaledOffset(const Instruction* instr) {
849 const char *mnemonic = "unimplemented";
850 const char *form = "'Wt, ['Xns'ILS]";
851 const char *form_x = "'Xt, ['Xns'ILS]";
852 const char *form_s = "'St, ['Xns'ILS]";
853 const char *form_d = "'Dt, ['Xns'ILS]";
854 const char *form_prefetch = "'PrefOp, ['Xns'ILS]";
856 switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
857 case STURB_w: mnemonic = "sturb"; break;
858 case STURH_w: mnemonic = "sturh"; break;
859 case STUR_w: mnemonic = "stur"; break;
860 case STUR_x: mnemonic = "stur"; form = form_x; break;
861 case STUR_s: mnemonic = "stur"; form = form_s; break;
862 case STUR_d: mnemonic = "stur"; form = form_d; break;
863 case LDURB_w: mnemonic = "ldurb"; break;
864 case LDURH_w: mnemonic = "ldurh"; break;
865 case LDUR_w: mnemonic = "ldur"; break;
866 case LDUR_x: mnemonic = "ldur"; form = form_x; break;
867 case LDUR_s: mnemonic = "ldur"; form = form_s; break;
868 case LDUR_d: mnemonic = "ldur"; form = form_d; break;
869 case LDURSB_x: form = form_x; // Fall through.
870 case LDURSB_w: mnemonic = "ldursb"; break;
871 case LDURSH_x: form = form_x; // Fall through.
872 case LDURSH_w: mnemonic = "ldursh"; break;
873 case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
874 case PRFUM: mnemonic = "prfum"; form = form_prefetch; break;
875 default: form = "(LoadStoreUnscaledOffset)";
877 Format(instr, mnemonic, form);
881 void Disassembler::VisitLoadLiteral(const Instruction* instr) {
882 const char *mnemonic = "ldr";
883 const char *form = "(LoadLiteral)";
885 switch (instr->Mask(LoadLiteralMask)) {
886 case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
887 case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
888 case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
889 case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
892 form = "'Xt, 'ILLiteral 'LValue";
897 form = "'PrefOp, 'ILLiteral 'LValue";
900 default: mnemonic = "unimplemented";
902 Format(instr, mnemonic, form);
906 #define LOAD_STORE_PAIR_LIST(V) \
907 V(STP_w, "stp", "'Wt, 'Wt2", "4") \
908 V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
909 V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
910 V(STP_x, "stp", "'Xt, 'Xt2", "8") \
911 V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
912 V(STP_s, "stp", "'St, 'St2", "4") \
913 V(LDP_s, "ldp", "'St, 'St2", "4") \
914 V(STP_d, "stp", "'Dt, 'Dt2", "8") \
915 V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
917 void Disassembler::VisitLoadStorePairPostIndex(const Instruction* instr) {
918 const char *mnemonic = "unimplemented";
919 const char *form = "(LoadStorePairPostIndex)";
921 switch (instr->Mask(LoadStorePairPostIndexMask)) {
922 #define LSP_POSTINDEX(A, B, C, D) \
923 case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
924 LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
927 Format(instr, mnemonic, form);
931 void Disassembler::VisitLoadStorePairPreIndex(const Instruction* instr) {
932 const char *mnemonic = "unimplemented";
933 const char *form = "(LoadStorePairPreIndex)";
935 switch (instr->Mask(LoadStorePairPreIndexMask)) {
936 #define LSP_PREINDEX(A, B, C, D) \
937 case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
938 LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
941 Format(instr, mnemonic, form);
945 void Disassembler::VisitLoadStorePairOffset(const Instruction* instr) {
946 const char *mnemonic = "unimplemented";
947 const char *form = "(LoadStorePairOffset)";
949 switch (instr->Mask(LoadStorePairOffsetMask)) {
950 #define LSP_OFFSET(A, B, C, D) \
951 case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
952 LOAD_STORE_PAIR_LIST(LSP_OFFSET)
955 Format(instr, mnemonic, form);
959 void Disassembler::VisitLoadStorePairNonTemporal(const Instruction* instr) {
960 const char *mnemonic = "unimplemented";
963 switch (instr->Mask(LoadStorePairNonTemporalMask)) {
964 case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
965 case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
966 case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
967 case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
968 case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
969 case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
970 case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
971 case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
972 default: form = "(LoadStorePairNonTemporal)";
974 Format(instr, mnemonic, form);
978 void Disassembler::VisitLoadStoreExclusive(const Instruction* instr) {
979 const char *mnemonic = "unimplemented";
982 switch (instr->Mask(LoadStoreExclusiveMask)) {
983 case STXRB_w: mnemonic = "stxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
984 case STXRH_w: mnemonic = "stxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
985 case STXR_w: mnemonic = "stxr"; form = "'Ws, 'Wt, ['Xns]"; break;
986 case STXR_x: mnemonic = "stxr"; form = "'Ws, 'Xt, ['Xns]"; break;
987 case LDXRB_w: mnemonic = "ldxrb"; form = "'Wt, ['Xns]"; break;
988 case LDXRH_w: mnemonic = "ldxrh"; form = "'Wt, ['Xns]"; break;
989 case LDXR_w: mnemonic = "ldxr"; form = "'Wt, ['Xns]"; break;
990 case LDXR_x: mnemonic = "ldxr"; form = "'Xt, ['Xns]"; break;
991 case STXP_w: mnemonic = "stxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
992 case STXP_x: mnemonic = "stxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
993 case LDXP_w: mnemonic = "ldxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
994 case LDXP_x: mnemonic = "ldxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
995 case STLXRB_w: mnemonic = "stlxrb"; form = "'Ws, 'Wt, ['Xns]"; break;
996 case STLXRH_w: mnemonic = "stlxrh"; form = "'Ws, 'Wt, ['Xns]"; break;
997 case STLXR_w: mnemonic = "stlxr"; form = "'Ws, 'Wt, ['Xns]"; break;
998 case STLXR_x: mnemonic = "stlxr"; form = "'Ws, 'Xt, ['Xns]"; break;
999 case LDAXRB_w: mnemonic = "ldaxrb"; form = "'Wt, ['Xns]"; break;
1000 case LDAXRH_w: mnemonic = "ldaxrh"; form = "'Wt, ['Xns]"; break;
1001 case LDAXR_w: mnemonic = "ldaxr"; form = "'Wt, ['Xns]"; break;
1002 case LDAXR_x: mnemonic = "ldaxr"; form = "'Xt, ['Xns]"; break;
1003 case STLXP_w: mnemonic = "stlxp"; form = "'Ws, 'Wt, 'Wt2, ['Xns]"; break;
1004 case STLXP_x: mnemonic = "stlxp"; form = "'Ws, 'Xt, 'Xt2, ['Xns]"; break;
1005 case LDAXP_w: mnemonic = "ldaxp"; form = "'Wt, 'Wt2, ['Xns]"; break;
1006 case LDAXP_x: mnemonic = "ldaxp"; form = "'Xt, 'Xt2, ['Xns]"; break;
1007 case STLRB_w: mnemonic = "stlrb"; form = "'Wt, ['Xns]"; break;
1008 case STLRH_w: mnemonic = "stlrh"; form = "'Wt, ['Xns]"; break;
1009 case STLR_w: mnemonic = "stlr"; form = "'Wt, ['Xns]"; break;
1010 case STLR_x: mnemonic = "stlr"; form = "'Xt, ['Xns]"; break;
1011 case LDARB_w: mnemonic = "ldarb"; form = "'Wt, ['Xns]"; break;
1012 case LDARH_w: mnemonic = "ldarh"; form = "'Wt, ['Xns]"; break;
1013 case LDAR_w: mnemonic = "ldar"; form = "'Wt, ['Xns]"; break;
1014 case LDAR_x: mnemonic = "ldar"; form = "'Xt, ['Xns]"; break;
1015 default: form = "(LoadStoreExclusive)";
1017 Format(instr, mnemonic, form);
1021 void Disassembler::VisitFPCompare(const Instruction* instr) {
1022 const char *mnemonic = "unimplemented";
1023 const char *form = "'Fn, 'Fm";
1024 const char *form_zero = "'Fn, #0.0";
1026 switch (instr->Mask(FPCompareMask)) {
1028 case FCMP_d_zero: form = form_zero; // Fall through.
1030 case FCMP_d: mnemonic = "fcmp"; break;
1031 default: form = "(FPCompare)";
1033 Format(instr, mnemonic, form);
1037 void Disassembler::VisitFPConditionalCompare(const Instruction* instr) {
1038 const char *mnemonic = "unmplemented";
1039 const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
1041 switch (instr->Mask(FPConditionalCompareMask)) {
1043 case FCCMP_d: mnemonic = "fccmp"; break;
1045 case FCCMPE_d: mnemonic = "fccmpe"; break;
1046 default: form = "(FPConditionalCompare)";
1048 Format(instr, mnemonic, form);
1052 void Disassembler::VisitFPConditionalSelect(const Instruction* instr) {
1053 const char *mnemonic = "";
1054 const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
1056 switch (instr->Mask(FPConditionalSelectMask)) {
1058 case FCSEL_d: mnemonic = "fcsel"; break;
1059 default: VIXL_UNREACHABLE();
1061 Format(instr, mnemonic, form);
1065 void Disassembler::VisitFPDataProcessing1Source(const Instruction* instr) {
1066 const char *mnemonic = "unimplemented";
1067 const char *form = "'Fd, 'Fn";
1069 switch (instr->Mask(FPDataProcessing1SourceMask)) {
1070 #define FORMAT(A, B) \
1072 case A##_d: mnemonic = B; break;
1073 FORMAT(FMOV, "fmov");
1074 FORMAT(FABS, "fabs");
1075 FORMAT(FNEG, "fneg");
1076 FORMAT(FSQRT, "fsqrt");
1077 FORMAT(FRINTN, "frintn");
1078 FORMAT(FRINTP, "frintp");
1079 FORMAT(FRINTM, "frintm");
1080 FORMAT(FRINTZ, "frintz");
1081 FORMAT(FRINTA, "frinta");
1082 FORMAT(FRINTX, "frintx");
1083 FORMAT(FRINTI, "frinti");
1085 case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1086 case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1087 default: form = "(FPDataProcessing1Source)";
1089 Format(instr, mnemonic, form);
1093 void Disassembler::VisitFPDataProcessing2Source(const Instruction* instr) {
1094 const char *mnemonic = "";
1095 const char *form = "'Fd, 'Fn, 'Fm";
1097 switch (instr->Mask(FPDataProcessing2SourceMask)) {
1098 #define FORMAT(A, B) \
1100 case A##_d: mnemonic = B; break;
1101 FORMAT(FMUL, "fmul");
1102 FORMAT(FDIV, "fdiv");
1103 FORMAT(FADD, "fadd");
1104 FORMAT(FSUB, "fsub");
1105 FORMAT(FMAX, "fmax");
1106 FORMAT(FMIN, "fmin");
1107 FORMAT(FMAXNM, "fmaxnm");
1108 FORMAT(FMINNM, "fminnm");
1109 FORMAT(FNMUL, "fnmul");
1111 default: VIXL_UNREACHABLE();
1113 Format(instr, mnemonic, form);
1117 void Disassembler::VisitFPDataProcessing3Source(const Instruction* instr) {
1118 const char *mnemonic = "";
1119 const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1121 switch (instr->Mask(FPDataProcessing3SourceMask)) {
1122 #define FORMAT(A, B) \
1124 case A##_d: mnemonic = B; break;
1125 FORMAT(FMADD, "fmadd");
1126 FORMAT(FMSUB, "fmsub");
1127 FORMAT(FNMADD, "fnmadd");
1128 FORMAT(FNMSUB, "fnmsub");
1130 default: VIXL_UNREACHABLE();
1132 Format(instr, mnemonic, form);
1136 void Disassembler::VisitFPImmediate(const Instruction* instr) {
1137 const char *mnemonic = "";
1138 const char *form = "(FPImmediate)";
1140 switch (instr->Mask(FPImmediateMask)) {
1141 case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1142 case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1143 default: VIXL_UNREACHABLE();
1145 Format(instr, mnemonic, form);
1149 void Disassembler::VisitFPIntegerConvert(const Instruction* instr) {
1150 const char *mnemonic = "unimplemented";
1151 const char *form = "(FPIntegerConvert)";
1152 const char *form_rf = "'Rd, 'Fn";
1153 const char *form_fr = "'Fd, 'Rn";
1155 switch (instr->Mask(FPIntegerConvertMask)) {
1157 case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1159 case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1163 case FCVTAS_xd: mnemonic = "fcvtas"; form = form_rf; break;
1167 case FCVTAU_xd: mnemonic = "fcvtau"; form = form_rf; break;
1171 case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1175 case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1179 case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1183 case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1187 case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1191 case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1195 case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1199 case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1201 Format(instr, mnemonic, form);
1205 void Disassembler::VisitFPFixedPointConvert(const Instruction* instr) {
1206 const char *mnemonic = "";
1207 const char *form = "'Rd, 'Fn, 'IFPFBits";
1208 const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1210 switch (instr->Mask(FPFixedPointConvertMask)) {
1211 case FCVTZS_ws_fixed:
1212 case FCVTZS_xs_fixed:
1213 case FCVTZS_wd_fixed:
1214 case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1215 case FCVTZU_ws_fixed:
1216 case FCVTZU_xs_fixed:
1217 case FCVTZU_wd_fixed:
1218 case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1219 case SCVTF_sw_fixed:
1220 case SCVTF_sx_fixed:
1221 case SCVTF_dw_fixed:
1222 case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1223 case UCVTF_sw_fixed:
1224 case UCVTF_sx_fixed:
1225 case UCVTF_dw_fixed:
1226 case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1227 default: VIXL_UNREACHABLE();
1229 Format(instr, mnemonic, form);
1233 void Disassembler::VisitSystem(const Instruction* instr) {
1234 // Some system instructions hijack their Op and Cp fields to represent a
1235 // range of immediates instead of indicating a different instruction. This
1236 // makes the decoding tricky.
1237 const char *mnemonic = "unimplemented";
1238 const char *form = "(System)";
1240 if (instr->Mask(SystemExclusiveMonitorFMask) == SystemExclusiveMonitorFixed) {
1241 switch (instr->Mask(SystemExclusiveMonitorMask)) {
1244 form = (instr->CRm() == 0xf) ? NULL : "'IX";
1248 } else if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1249 switch (instr->Mask(SystemSysRegMask)) {
1252 switch (instr->ImmSystemRegister()) {
1253 case NZCV: form = "'Xt, nzcv"; break;
1254 case FPCR: form = "'Xt, fpcr"; break;
1255 default: form = "'Xt, (unknown)"; break;
1261 switch (instr->ImmSystemRegister()) {
1262 case NZCV: form = "nzcv, 'Xt"; break;
1263 case FPCR: form = "fpcr, 'Xt"; break;
1264 default: form = "(unknown), 'Xt"; break;
1269 } else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1270 switch (instr->ImmHint()) {
1277 } else if (instr->Mask(MemBarrierFMask) == MemBarrierFixed) {
1278 switch (instr->Mask(MemBarrierMask)) {
1297 Format(instr, mnemonic, form);
1301 void Disassembler::VisitException(const Instruction* instr) {
1302 const char *mnemonic = "unimplemented";
1303 const char *form = "'IDebug";
1305 switch (instr->Mask(ExceptionMask)) {
1306 case HLT: mnemonic = "hlt"; break;
1307 case BRK: mnemonic = "brk"; break;
1308 case SVC: mnemonic = "svc"; break;
1309 case HVC: mnemonic = "hvc"; break;
1310 case SMC: mnemonic = "smc"; break;
1311 case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1312 case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1313 case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1314 default: form = "(Exception)";
1316 Format(instr, mnemonic, form);
1320 void Disassembler::VisitUnimplemented(const Instruction* instr) {
1321 Format(instr, "unimplemented", "(Unimplemented)");
1325 void Disassembler::VisitUnallocated(const Instruction* instr) {
1326 Format(instr, "unallocated", "(Unallocated)");
1330 void Disassembler::ProcessOutput(const Instruction* /*instr*/) {
1331 // The base disasm does nothing more than disassembling into a buffer.
1335 void Disassembler::AppendRegisterNameToOutput(const Instruction* instr,
1336 const CPURegister& reg) {
1338 VIXL_ASSERT(reg.IsValid());
1341 if (reg.IsRegister()) {
1342 reg_char = reg.Is64Bits() ? 'x' : 'w';
1344 VIXL_ASSERT(reg.IsFPRegister());
1345 reg_char = reg.Is64Bits() ? 'd' : 's';
1348 if (reg.IsFPRegister() || !(reg.Aliases(sp) || reg.Aliases(xzr))) {
1349 // A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1350 AppendToOutput("%c%d", reg_char, reg.code());
1351 } else if (reg.Aliases(sp)) {
1352 // Disassemble w31/x31 as stack pointer wsp/sp.
1353 AppendToOutput("%s", reg.Is64Bits() ? "sp" : "wsp");
1355 // Disassemble w31/x31 as zero register wzr/xzr.
1356 AppendToOutput("%czr", reg_char);
1361 void Disassembler::AppendPCRelativeOffsetToOutput(const Instruction* instr,
1364 char sign = (offset < 0) ? '-' : '+';
1365 AppendToOutput("#%c0x%" PRIx64, sign, std::abs(offset));
1369 void Disassembler::AppendAddressToOutput(const Instruction* instr,
1372 AppendToOutput("(addr 0x%" PRIxPTR ")", reinterpret_cast<uintptr_t>(addr));
1376 void Disassembler::AppendCodeAddressToOutput(const Instruction* instr,
1378 AppendAddressToOutput(instr, addr);
1382 void Disassembler::AppendDataAddressToOutput(const Instruction* instr,
1384 AppendAddressToOutput(instr, addr);
1388 void Disassembler::AppendCodeRelativeAddressToOutput(const Instruction* instr,
1391 int64_t rel_addr = CodeRelativeAddress(addr);
1392 if (rel_addr >= 0) {
1393 AppendToOutput("(addr 0x%" PRIx64 ")", rel_addr);
1395 AppendToOutput("(addr -0x%" PRIx64 ")", -rel_addr);
1400 void Disassembler::AppendCodeRelativeCodeAddressToOutput(
1401 const Instruction* instr, const void* addr) {
1402 AppendCodeRelativeAddressToOutput(instr, addr);
1406 void Disassembler::AppendCodeRelativeDataAddressToOutput(
1407 const Instruction* instr, const void* addr) {
1408 AppendCodeRelativeAddressToOutput(instr, addr);
1412 void Disassembler::MapCodeAddress(int64_t base_address,
1413 const Instruction* instr_address) {
1414 set_code_address_offset(
1415 base_address - reinterpret_cast<intptr_t>(instr_address));
1417 int64_t Disassembler::CodeRelativeAddress(const void* addr) {
1418 return reinterpret_cast<intptr_t>(addr) + code_address_offset();
1422 void Disassembler::Format(const Instruction* instr, const char* mnemonic,
1423 const char* format) {
1424 VIXL_ASSERT(mnemonic != NULL);
1426 Substitute(instr, mnemonic);
1427 if (format != NULL) {
1428 buffer_[buffer_pos_++] = ' ';
1429 Substitute(instr, format);
1431 buffer_[buffer_pos_] = 0;
1432 ProcessOutput(instr);
1436 void Disassembler::Substitute(const Instruction* instr, const char* string) {
1437 char chr = *string++;
1438 while (chr != '\0') {
1440 string += SubstituteField(instr, string);
1442 buffer_[buffer_pos_++] = chr;
1449 int Disassembler::SubstituteField(const Instruction* instr,
1450 const char* format) {
1451 switch (format[0]) {
1452 case 'R': // Register. X or W, selected by sf bit.
1453 case 'F': // FP Register. S or D, selected by type field.
1457 case 'D': return SubstituteRegisterField(instr, format);
1458 case 'I': return SubstituteImmediateField(instr, format);
1459 case 'L': return SubstituteLiteralField(instr, format);
1460 case 'H': return SubstituteShiftField(instr, format);
1461 case 'P': return SubstitutePrefetchField(instr, format);
1462 case 'C': return SubstituteConditionField(instr, format);
1463 case 'E': return SubstituteExtendField(instr, format);
1464 case 'A': return SubstitutePCRelAddressField(instr, format);
1465 case 'B': return SubstituteBranchTargetField(instr, format);
1466 case 'O': return SubstituteLSRegOffsetField(instr, format);
1467 case 'M': return SubstituteBarrierField(instr, format);
1476 int Disassembler::SubstituteRegisterField(const Instruction* instr,
1477 const char* format) {
1478 unsigned reg_num = 0;
1479 unsigned field_len = 2;
1480 switch (format[1]) {
1481 case 'd': reg_num = instr->Rd(); break;
1482 case 'n': reg_num = instr->Rn(); break;
1483 case 'm': reg_num = instr->Rm(); break;
1484 case 'a': reg_num = instr->Ra(); break;
1485 case 's': reg_num = instr->Rs(); break;
1487 if (format[2] == '2') {
1488 reg_num = instr->Rt2();
1491 reg_num = instr->Rt();
1495 default: VIXL_UNREACHABLE();
1498 // Increase field length for registers tagged as stack.
1499 if (format[2] == 's') {
1503 CPURegister::RegisterType reg_type;
1506 if (format[0] == 'R') {
1507 // Register type is R: use sf bit to choose X and W.
1508 reg_type = CPURegister::kRegister;
1509 reg_size = instr->SixtyFourBits() ? kXRegSize : kWRegSize;
1510 } else if (format[0] == 'F') {
1511 // Floating-point register: use type field to choose S or D.
1512 reg_type = CPURegister::kFPRegister;
1513 reg_size = ((instr->FPType() & 1) == 0) ? kSRegSize : kDRegSize;
1515 // The register type is specified.
1516 switch (format[0]) {
1518 reg_type = CPURegister::kRegister; reg_size = kWRegSize; break;
1520 reg_type = CPURegister::kRegister; reg_size = kXRegSize; break;
1522 reg_type = CPURegister::kFPRegister; reg_size = kSRegSize; break;
1524 reg_type = CPURegister::kFPRegister; reg_size = kDRegSize; break;
1527 reg_type = CPURegister::kRegister;
1528 reg_size = kXRegSize;
1532 if ((reg_type == CPURegister::kRegister) &&
1533 (reg_num == kZeroRegCode) && (format[2] == 's')) {
1534 reg_num = kSPRegInternalCode;
1537 AppendRegisterNameToOutput(instr, CPURegister(reg_num, reg_size, reg_type));
1543 int Disassembler::SubstituteImmediateField(const Instruction* instr,
1544 const char* format) {
1545 VIXL_ASSERT(format[0] == 'I');
1547 switch (format[1]) {
1548 case 'M': { // IMoveImm, IMoveNeg or IMoveLSL.
1549 if (format[5] == 'L') {
1550 AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1551 if (instr->ShiftMoveWide() > 0) {
1552 AppendToOutput(", lsl #%" PRId64, 16 * instr->ShiftMoveWide());
1555 VIXL_ASSERT((format[5] == 'I') || (format[5] == 'N'));
1556 uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1557 if (format[5] == 'N')
1559 if (!instr->SixtyFourBits())
1560 imm &= UINT64_C(0xffffffff);
1561 AppendToOutput("#0x%" PRIx64, imm);
1566 switch (format[2]) {
1567 case 'L': { // ILLiteral - Immediate Load Literal.
1568 AppendToOutput("pc%+" PRId64,
1569 instr->ImmLLiteral() << kLiteralEntrySizeLog2);
1572 case 'S': { // ILS - Immediate Load/Store.
1573 if (instr->ImmLS() != 0) {
1574 AppendToOutput(", #%" PRId64, instr->ImmLS());
1578 case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1579 if (instr->ImmLSPair() != 0) {
1580 // format[3] is the scale value. Convert to a number.
1581 int scale = format[3] - 0x30;
1582 AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1586 case 'U': { // ILU - Immediate Load/Store Unsigned.
1587 if (instr->ImmLSUnsigned() != 0) {
1588 AppendToOutput(", #%" PRIu64,
1589 instr->ImmLSUnsigned() << instr->SizeLS());
1595 case 'C': { // ICondB - Immediate Conditional Branch.
1596 int64_t offset = instr->ImmCondBranch() << 2;
1597 AppendPCRelativeOffsetToOutput(instr, offset);
1600 case 'A': { // IAddSub.
1601 VIXL_ASSERT(instr->ShiftAddSub() <= 1);
1602 int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1603 AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1606 case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1607 if (format[3] == 'F') { // IFPFbits.
1608 AppendToOutput("#%" PRId64, 64 - instr->FPScale());
1611 AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1612 format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1616 case 'T': { // ITri - Immediate Triangular Encoded.
1617 AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1620 case 'N': { // INzcv.
1621 int nzcv = (instr->Nzcv() << Flags_offset);
1622 AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1623 ((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1624 ((nzcv & CFlag) == 0) ? 'c' : 'C',
1625 ((nzcv & VFlag) == 0) ? 'v' : 'V');
1628 case 'P': { // IP - Conditional compare.
1629 AppendToOutput("#%" PRId64, instr->ImmCondCmp());
1632 case 'B': { // Bitfields.
1633 return SubstituteBitfieldImmediateField(instr, format);
1635 case 'E': { // IExtract.
1636 AppendToOutput("#%" PRId64, instr->ImmS());
1639 case 'S': { // IS - Test and branch bit.
1640 AppendToOutput("#%" PRId64, (instr->ImmTestBranchBit5() << 5) |
1641 instr->ImmTestBranchBit40());
1644 case 'D': { // IDebug - HLT and BRK instructions.
1645 AppendToOutput("#0x%" PRIx64, instr->ImmException());
1648 case 'X': { // IX - CLREX instruction.
1649 AppendToOutput("#0x%" PRIx64, instr->CRm());
1653 VIXL_UNIMPLEMENTED();
1660 int Disassembler::SubstituteBitfieldImmediateField(const Instruction* instr,
1661 const char* format) {
1662 VIXL_ASSERT((format[0] == 'I') && (format[1] == 'B'));
1663 unsigned r = instr->ImmR();
1664 unsigned s = instr->ImmS();
1666 switch (format[2]) {
1668 AppendToOutput("#%d", r);
1671 case 's': { // IBs+1 or IBs-r+1.
1672 if (format[3] == '+') {
1673 AppendToOutput("#%d", s + 1);
1676 VIXL_ASSERT(format[3] == '-');
1677 AppendToOutput("#%d", s - r + 1);
1681 case 'Z': { // IBZ-r.
1682 VIXL_ASSERT((format[3] == '-') && (format[4] == 'r'));
1683 unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
1684 AppendToOutput("#%d", reg_size - r);
1695 int Disassembler::SubstituteLiteralField(const Instruction* instr,
1696 const char* format) {
1697 VIXL_ASSERT(strncmp(format, "LValue", 6) == 0);
1700 const void * address = instr->LiteralAddress<const void *>();
1701 switch (instr->Mask(LoadLiteralMask)) {
1707 AppendCodeRelativeDataAddressToOutput(instr, address);
1710 // Use the prefetch hint to decide how to print the address.
1711 switch (instr->PrefetchHint()) {
1712 case 0x0: // PLD: prefetch for load.
1713 case 0x2: // PST: prepare for store.
1714 AppendCodeRelativeDataAddressToOutput(instr, address);
1716 case 0x1: // PLI: preload instructions.
1717 AppendCodeRelativeCodeAddressToOutput(instr, address);
1719 case 0x3: // Unallocated hint.
1720 AppendCodeRelativeAddressToOutput(instr, address);
1733 int Disassembler::SubstituteShiftField(const Instruction* instr,
1734 const char* format) {
1735 VIXL_ASSERT(format[0] == 'H');
1736 VIXL_ASSERT(instr->ShiftDP() <= 0x3);
1738 switch (format[1]) {
1740 VIXL_ASSERT(instr->ShiftDP() != ROR);
1743 if (instr->ImmDPShift() != 0) {
1744 const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1745 AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1746 instr->ImmDPShift());
1751 VIXL_UNIMPLEMENTED();
1757 int Disassembler::SubstituteConditionField(const Instruction* instr,
1758 const char* format) {
1759 VIXL_ASSERT(format[0] == 'C');
1760 const char* condition_code[] = { "eq", "ne", "hs", "lo",
1761 "mi", "pl", "vs", "vc",
1762 "hi", "ls", "ge", "lt",
1763 "gt", "le", "al", "nv" };
1765 switch (format[1]) {
1766 case 'B': cond = instr->ConditionBranch(); break;
1768 cond = InvertCondition(static_cast<Condition>(instr->Condition()));
1771 default: cond = instr->Condition();
1773 AppendToOutput("%s", condition_code[cond]);
1778 int Disassembler::SubstitutePCRelAddressField(const Instruction* instr,
1779 const char* format) {
1780 VIXL_ASSERT((strcmp(format, "AddrPCRelByte") == 0) || // Used by `adr`.
1781 (strcmp(format, "AddrPCRelPage") == 0)); // Used by `adrp`.
1783 int64_t offset = instr->ImmPCRel();
1785 // Compute the target address based on the effective address (after applying
1786 // code_address_offset). This is required for correct behaviour of adrp.
1787 const Instruction* base = instr + code_address_offset();
1788 if (format[9] == 'P') {
1789 offset *= kPageSize;
1790 base = AlignDown(base, kPageSize);
1792 // Strip code_address_offset before printing, so we can use the
1793 // semantically-correct AppendCodeRelativeAddressToOutput.
1794 const void* target =
1795 reinterpret_cast<const void*>(base + offset - code_address_offset());
1797 AppendPCRelativeOffsetToOutput(instr, offset);
1798 AppendToOutput(" ");
1799 AppendCodeRelativeAddressToOutput(instr, target);
1804 int Disassembler::SubstituteBranchTargetField(const Instruction* instr,
1805 const char* format) {
1806 VIXL_ASSERT(strncmp(format, "BImm", 4) == 0);
1809 switch (format[5]) {
1810 // BImmUncn - unconditional branch immediate.
1811 case 'n': offset = instr->ImmUncondBranch(); break;
1812 // BImmCond - conditional branch immediate.
1813 case 'o': offset = instr->ImmCondBranch(); break;
1814 // BImmCmpa - compare and branch immediate.
1815 case 'm': offset = instr->ImmCmpBranch(); break;
1816 // BImmTest - test and branch immediate.
1817 case 'e': offset = instr->ImmTestBranch(); break;
1818 default: VIXL_UNIMPLEMENTED();
1820 offset <<= kInstructionSizeLog2;
1821 const void* target_address = reinterpret_cast<const void*>(instr + offset);
1822 VIXL_STATIC_ASSERT(sizeof(*instr) == 1);
1824 AppendPCRelativeOffsetToOutput(instr, offset);
1825 AppendToOutput(" ");
1826 AppendCodeRelativeCodeAddressToOutput(instr, target_address);
1832 int Disassembler::SubstituteExtendField(const Instruction* instr,
1833 const char* format) {
1834 VIXL_ASSERT(strncmp(format, "Ext", 3) == 0);
1835 VIXL_ASSERT(instr->ExtendMode() <= 7);
1838 const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1839 "sxtb", "sxth", "sxtw", "sxtx" };
1841 // If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1842 // registers becomes lsl.
1843 if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1844 (((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1845 (instr->ExtendMode() == UXTX))) {
1846 if (instr->ImmExtendShift() > 0) {
1847 AppendToOutput(", lsl #%" PRId64, instr->ImmExtendShift());
1850 AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1851 if (instr->ImmExtendShift() > 0) {
1852 AppendToOutput(" #%" PRId64, instr->ImmExtendShift());
1859 int Disassembler::SubstituteLSRegOffsetField(const Instruction* instr,
1860 const char* format) {
1861 VIXL_ASSERT(strncmp(format, "Offsetreg", 9) == 0);
1862 const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1863 "undefined", "undefined", "sxtw", "sxtx" };
1866 unsigned shift = instr->ImmShiftLS();
1867 Extend ext = static_cast<Extend>(instr->ExtendMode());
1868 char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1870 unsigned rm = instr->Rm();
1871 if (rm == kZeroRegCode) {
1872 AppendToOutput("%czr", reg_type);
1874 AppendToOutput("%c%d", reg_type, rm);
1877 // Extend mode UXTX is an alias for shift mode LSL here.
1878 if (!((ext == UXTX) && (shift == 0))) {
1879 AppendToOutput(", %s", extend_mode[ext]);
1881 AppendToOutput(" #%" PRId64, instr->SizeLS());
1888 int Disassembler::SubstitutePrefetchField(const Instruction* instr,
1889 const char* format) {
1890 VIXL_ASSERT(format[0] == 'P');
1893 static const char* hints[] = {"ld", "li", "st"};
1894 static const char* stream_options[] = {"keep", "strm"};
1896 unsigned hint = instr->PrefetchHint();
1897 unsigned target = instr->PrefetchTarget() + 1;
1898 unsigned stream = instr->PrefetchStream();
1900 if ((hint >= (sizeof(hints) / sizeof(hints[0]))) || (target > 3)) {
1901 // Unallocated prefetch operations.
1902 int prefetch_mode = instr->ImmPrefetchOperation();
1903 AppendToOutput("#0b%c%c%c%c%c",
1904 (prefetch_mode & (1 << 4)) ? '1' : '0',
1905 (prefetch_mode & (1 << 3)) ? '1' : '0',
1906 (prefetch_mode & (1 << 2)) ? '1' : '0',
1907 (prefetch_mode & (1 << 1)) ? '1' : '0',
1908 (prefetch_mode & (1 << 0)) ? '1' : '0');
1910 VIXL_ASSERT(stream < (sizeof(stream_options) / sizeof(stream_options[0])));
1911 AppendToOutput("p%sl%d%s", hints[hint], target, stream_options[stream]);
1916 int Disassembler::SubstituteBarrierField(const Instruction* instr,
1917 const char* format) {
1918 VIXL_ASSERT(format[0] == 'M');
1921 static const char* options[4][4] = {
1922 { "sy (0b0000)", "oshld", "oshst", "osh" },
1923 { "sy (0b0100)", "nshld", "nshst", "nsh" },
1924 { "sy (0b1000)", "ishld", "ishst", "ish" },
1925 { "sy (0b1100)", "ld", "st", "sy" }
1927 int domain = instr->ImmBarrierDomain();
1928 int type = instr->ImmBarrierType();
1930 AppendToOutput("%s", options[domain][type]);
1934 void Disassembler::ResetOutput() {
1936 buffer_[buffer_pos_] = 0;
1940 void Disassembler::AppendToOutput(const char* format, ...) {
1942 va_start(args, format);
1943 buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1948 void PrintDisassembler::ProcessOutput(const Instruction* instr) {
1949 fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1950 reinterpret_cast<uint64_t>(instr),
1951 instr->InstructionBits(),