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(),