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.
27
#include "a64/disasm-a64.h"
31
Disassembler::Disassembler() {
33
buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
39
Disassembler::Disassembler(char* text_buffer, int buffer_size) {
40
buffer_size_ = buffer_size;
41
buffer_ = text_buffer;
47
Disassembler::~Disassembler() {
54
char* Disassembler::GetOutput() {
59
void Disassembler::VisitAddSubImmediate(Instruction* instr) {
60
bool rd_is_zr = RdIsZROrSP(instr);
61
bool stack_op = (rd_is_zr || RnIsZROrSP(instr)) &&
62
(instr->ImmAddSub() == 0) ? true : false;
63
const char *mnemonic = "";
64
const char *form = "'Rds, 'Rns, 'IAddSub";
65
const char *form_cmp = "'Rns, 'IAddSub";
66
const char *form_mov = "'Rds, 'Rns";
68
switch (instr->Mask(AddSubImmediateMask)) {
88
case SUB_x_imm: mnemonic = "sub"; break;
98
default: UNREACHABLE();
100
Format(instr, mnemonic, form);
104
void Disassembler::VisitAddSubShifted(Instruction* instr) {
105
bool rd_is_zr = RdIsZROrSP(instr);
106
bool rn_is_zr = RnIsZROrSP(instr);
107
const char *mnemonic = "";
108
const char *form = "'Rd, 'Rn, 'Rm'HDP";
109
const char *form_cmp = "'Rn, 'Rm'HDP";
110
const char *form_neg = "'Rd, 'Rm'HDP";
112
switch (instr->Mask(AddSubShiftedMask)) {
114
case ADD_x_shift: mnemonic = "add"; break;
139
} else if (rn_is_zr) {
145
default: UNREACHABLE();
147
Format(instr, mnemonic, form);
151
void Disassembler::VisitAddSubExtended(Instruction* instr) {
152
bool rd_is_zr = RdIsZROrSP(instr);
153
const char *mnemonic = "";
154
Extend mode = static_cast<Extend>(instr->ExtendMode());
155
const char *form = ((mode == UXTX) || (mode == SXTX)) ?
156
"'Rds, 'Rns, 'Xm'Ext" : "'Rds, 'Rns, 'Wm'Ext";
157
const char *form_cmp = ((mode == UXTX) || (mode == SXTX)) ?
158
"'Rns, 'Xm'Ext" : "'Rns, 'Wm'Ext";
160
switch (instr->Mask(AddSubExtendedMask)) {
162
case ADD_x_ext: mnemonic = "add"; break;
173
case SUB_x_ext: mnemonic = "sub"; break;
183
default: UNREACHABLE();
185
Format(instr, mnemonic, form);
189
void Disassembler::VisitAddSubWithCarry(Instruction* instr) {
190
bool rn_is_zr = RnIsZROrSP(instr);
191
const char *mnemonic = "";
192
const char *form = "'Rd, 'Rn, 'Rm";
193
const char *form_neg = "'Rd, 'Rm";
195
switch (instr->Mask(AddSubWithCarryMask)) {
197
case ADC_x: mnemonic = "adc"; break;
199
case ADCS_x: mnemonic = "adcs"; break;
218
default: UNREACHABLE();
220
Format(instr, mnemonic, form);
224
void Disassembler::VisitLogicalImmediate(Instruction* instr) {
225
bool rd_is_zr = RdIsZROrSP(instr);
226
bool rn_is_zr = RnIsZROrSP(instr);
227
const char *mnemonic = "";
228
const char *form = "'Rds, 'Rn, 'ITri";
230
if (instr->ImmLogical() == 0) {
231
// The immediate encoded in the instruction is not in the expected format.
232
Format(instr, "unallocated", "(LogicalImmediate)");
236
switch (instr->Mask(LogicalImmediateMask)) {
238
case AND_x_imm: mnemonic = "and"; break;
242
unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize
244
if (rn_is_zr && !IsMovzMovnImm(reg_size, instr->ImmLogical())) {
246
form = "'Rds, 'ITri";
251
case EOR_x_imm: mnemonic = "eor"; break;
261
default: UNREACHABLE();
263
Format(instr, mnemonic, form);
267
bool Disassembler::IsMovzMovnImm(unsigned reg_size, uint64_t value) {
268
ASSERT((reg_size == kXRegSize) ||
269
((reg_size == kWRegSize) && (value <= 0xffffffff)));
271
// Test for movz: 16 bits set at positions 0, 16, 32 or 48.
272
if (((value & 0xffffffffffff0000UL) == 0UL) ||
273
((value & 0xffffffff0000ffffUL) == 0UL) ||
274
((value & 0xffff0000ffffffffUL) == 0UL) ||
275
((value & 0x0000ffffffffffffUL) == 0UL)) {
279
// Test for movn: NOT(16 bits set at positions 0, 16, 32 or 48).
280
if ((reg_size == kXRegSize) &&
281
(((value & 0xffffffffffff0000UL) == 0xffffffffffff0000UL) ||
282
((value & 0xffffffff0000ffffUL) == 0xffffffff0000ffffUL) ||
283
((value & 0xffff0000ffffffffUL) == 0xffff0000ffffffffUL) ||
284
((value & 0x0000ffffffffffffUL) == 0x0000ffffffffffffUL))) {
287
if ((reg_size == kWRegSize) &&
288
(((value & 0xffff0000) == 0xffff0000) ||
289
((value & 0x0000ffff) == 0x0000ffff))) {
296
void Disassembler::VisitLogicalShifted(Instruction* instr) {
297
bool rd_is_zr = RdIsZROrSP(instr);
298
bool rn_is_zr = RnIsZROrSP(instr);
299
const char *mnemonic = "";
300
const char *form = "'Rd, 'Rn, 'Rm'HLo";
302
switch (instr->Mask(LogicalShiftedMask)) {
304
case AND_x: mnemonic = "and"; break;
306
case BIC_x: mnemonic = "bic"; break;
308
case EOR_x: mnemonic = "eor"; break;
310
case EON_x: mnemonic = "eon"; break;
312
case BICS_x: mnemonic = "bics"; break;
318
form = "'Rn, 'Rm'HLo";
325
if (rn_is_zr && (instr->ImmDPShift() == 0) && (instr->ShiftDP() == LSL)) {
336
form = "'Rd, 'Rm'HLo";
340
default: UNREACHABLE();
343
Format(instr, mnemonic, form);
347
void Disassembler::VisitConditionalCompareRegister(Instruction* instr) {
348
const char *mnemonic = "";
349
const char *form = "'Rn, 'Rm, 'INzcv, 'Cond";
351
switch (instr->Mask(ConditionalCompareRegisterMask)) {
353
case CCMN_x: mnemonic = "ccmn"; break;
355
case CCMP_x: mnemonic = "ccmp"; break;
356
default: UNREACHABLE();
358
Format(instr, mnemonic, form);
362
void Disassembler::VisitConditionalCompareImmediate(Instruction* instr) {
363
const char *mnemonic = "";
364
const char *form = "'Rn, 'IP, 'INzcv, 'Cond";
366
switch (instr->Mask(ConditionalCompareImmediateMask)) {
368
case CCMN_x_imm: mnemonic = "ccmn"; break;
370
case CCMP_x_imm: mnemonic = "ccmp"; break;
371
default: UNREACHABLE();
373
Format(instr, mnemonic, form);
377
void Disassembler::VisitConditionalSelect(Instruction* instr) {
378
bool rnm_is_zr = (RnIsZROrSP(instr) && RmIsZROrSP(instr));
379
bool rn_is_rm = (instr->Rn() == instr->Rm());
380
const char *mnemonic = "";
381
const char *form = "'Rd, 'Rn, 'Rm, 'Cond";
382
const char *form_test = "'Rd, 'CInv";
383
const char *form_update = "'Rd, 'Rn, 'CInv";
385
Condition cond = static_cast<Condition>(instr->Condition());
386
bool invertible_cond = (cond != al) && (cond != nv);
388
switch (instr->Mask(ConditionalSelectMask)) {
390
case CSEL_x: mnemonic = "csel"; break;
394
if (rnm_is_zr && invertible_cond) {
397
} else if (rn_is_rm && invertible_cond) {
406
if (rnm_is_zr && invertible_cond) {
409
} else if (rn_is_rm && invertible_cond) {
418
if (rn_is_rm && invertible_cond) {
424
default: UNREACHABLE();
426
Format(instr, mnemonic, form);
430
void Disassembler::VisitBitfield(Instruction* instr) {
431
unsigned s = instr->ImmS();
432
unsigned r = instr->ImmR();
433
unsigned rd_size_minus_1 =
434
((instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize) - 1;
435
const char *mnemonic = "";
436
const char *form = "";
437
const char *form_shift_right = "'Rd, 'Rn, 'IBr";
438
const char *form_extend = "'Rd, 'Wn";
439
const char *form_bfiz = "'Rd, 'Rn, 'IBZ-r, 'IBs+1";
440
const char *form_bfx = "'Rd, 'Rn, 'IBr, 'IBs-r+1";
441
const char *form_lsl = "'Rd, 'Rn, 'IBZ-r";
443
switch (instr->Mask(BitfieldMask)) {
452
} else if (s == 15) {
454
} else if ((s == 31) && (instr->SixtyFourBits() == 1)) {
459
} else if (s == rd_size_minus_1) {
461
form = form_shift_right;
476
} else if (s == 15) {
482
if (s == rd_size_minus_1) {
484
form = form_shift_right;
485
} else if (r == s + 1) {
504
Format(instr, mnemonic, form);
508
void Disassembler::VisitExtract(Instruction* instr) {
509
const char *mnemonic = "";
510
const char *form = "'Rd, 'Rn, 'Rm, 'IExtract";
512
switch (instr->Mask(ExtractMask)) {
515
if (instr->Rn() == instr->Rm()) {
517
form = "'Rd, 'Rn, 'IExtract";
523
default: UNREACHABLE();
525
Format(instr, mnemonic, form);
529
void Disassembler::VisitPCRelAddressing(Instruction* instr) {
530
switch (instr->Mask(PCRelAddressingMask)) {
531
case ADR: Format(instr, "adr", "'Xd, 'AddrPCRelByte"); break;
532
// ADRP is not implemented.
533
default: Format(instr, "unimplemented", "(PCRelAddressing)");
538
void Disassembler::VisitConditionalBranch(Instruction* instr) {
539
switch (instr->Mask(ConditionalBranchMask)) {
540
case B_cond: Format(instr, "b.'CBrn", "'BImmCond"); break;
541
default: UNREACHABLE();
546
void Disassembler::VisitUnconditionalBranchToRegister(Instruction* instr) {
547
const char *mnemonic = "unimplemented";
548
const char *form = "'Xn";
550
switch (instr->Mask(UnconditionalBranchToRegisterMask)) {
551
case BR: mnemonic = "br"; break;
552
case BLR: mnemonic = "blr"; break;
555
if (instr->Rn() == kLinkRegCode) {
560
default: form = "(UnconditionalBranchToRegister)";
562
Format(instr, mnemonic, form);
566
void Disassembler::VisitUnconditionalBranch(Instruction* instr) {
567
const char *mnemonic = "";
568
const char *form = "'BImmUncn";
570
switch (instr->Mask(UnconditionalBranchMask)) {
571
case B: mnemonic = "b"; break;
572
case BL: mnemonic = "bl"; break;
573
default: UNREACHABLE();
575
Format(instr, mnemonic, form);
579
void Disassembler::VisitDataProcessing1Source(Instruction* instr) {
580
const char *mnemonic = "";
581
const char *form = "'Rd, 'Rn";
583
switch (instr->Mask(DataProcessing1SourceMask)) {
584
#define FORMAT(A, B) \
586
case A##_x: mnemonic = B; break;
587
FORMAT(RBIT, "rbit");
588
FORMAT(REV16, "rev16");
593
case REV32_x: mnemonic = "rev32"; break;
594
default: UNREACHABLE();
596
Format(instr, mnemonic, form);
600
void Disassembler::VisitDataProcessing2Source(Instruction* instr) {
601
const char *mnemonic = "unimplemented";
602
const char *form = "'Rd, 'Rn, 'Rm";
604
switch (instr->Mask(DataProcessing2SourceMask)) {
605
#define FORMAT(A, B) \
607
case A##_x: mnemonic = B; break;
608
FORMAT(UDIV, "udiv");
609
FORMAT(SDIV, "sdiv");
615
default: form = "(DataProcessing2Source)";
617
Format(instr, mnemonic, form);
621
void Disassembler::VisitDataProcessing3Source(Instruction* instr) {
622
bool ra_is_zr = RaIsZROrSP(instr);
623
const char *mnemonic = "";
624
const char *form = "'Xd, 'Wn, 'Wm, 'Xa";
625
const char *form_rrr = "'Rd, 'Rn, 'Rm";
626
const char *form_rrrr = "'Rd, 'Rn, 'Rm, 'Ra";
627
const char *form_xww = "'Xd, 'Wn, 'Wm";
628
const char *form_xxx = "'Xd, 'Xn, 'Xm";
630
switch (instr->Mask(DataProcessing3SourceMask)) {
693
default: UNREACHABLE();
695
Format(instr, mnemonic, form);
699
void Disassembler::VisitCompareBranch(Instruction* instr) {
700
const char *mnemonic = "";
701
const char *form = "'Rt, 'BImmCmpa";
703
switch (instr->Mask(CompareBranchMask)) {
705
case CBZ_x: mnemonic = "cbz"; break;
707
case CBNZ_x: mnemonic = "cbnz"; break;
708
default: UNREACHABLE();
710
Format(instr, mnemonic, form);
714
void Disassembler::VisitTestBranch(Instruction* instr) {
715
const char *mnemonic = "";
716
// If the top bit of the immediate is clear, the tested register is
717
// disassembled as Wt, otherwise Xt. As the top bit of the immediate is
718
// encoded in bit 31 of the instruction, we can reuse the Rt form, which
719
// uses bit 31 (normally "sf") to choose the register size.
720
const char *form = "'Rt, 'IS, 'BImmTest";
722
switch (instr->Mask(TestBranchMask)) {
723
case TBZ: mnemonic = "tbz"; break;
724
case TBNZ: mnemonic = "tbnz"; break;
725
default: UNREACHABLE();
727
Format(instr, mnemonic, form);
731
void Disassembler::VisitMoveWideImmediate(Instruction* instr) {
732
const char *mnemonic = "";
733
const char *form = "'Rd, 'IMoveImm";
735
// Print the shift separately for movk, to make it clear which half word will
736
// be overwritten. Movn and movz print the computed immediate, which includes
737
// shift calculation.
738
switch (instr->Mask(MoveWideImmediateMask)) {
740
case MOVN_x: mnemonic = "movn"; break;
742
case MOVZ_x: mnemonic = "movz"; break;
744
case MOVK_x: mnemonic = "movk"; form = "'Rd, 'IMoveLSL"; break;
745
default: UNREACHABLE();
747
Format(instr, mnemonic, form);
751
#define LOAD_STORE_LIST(V) \
752
V(STRB_w, "strb", "'Wt") \
753
V(STRH_w, "strh", "'Wt") \
754
V(STR_w, "str", "'Wt") \
755
V(STR_x, "str", "'Xt") \
756
V(LDRB_w, "ldrb", "'Wt") \
757
V(LDRH_w, "ldrh", "'Wt") \
758
V(LDR_w, "ldr", "'Wt") \
759
V(LDR_x, "ldr", "'Xt") \
760
V(LDRSB_x, "ldrsb", "'Xt") \
761
V(LDRSH_x, "ldrsh", "'Xt") \
762
V(LDRSW_x, "ldrsw", "'Xt") \
763
V(LDRSB_w, "ldrsb", "'Wt") \
764
V(LDRSH_w, "ldrsh", "'Wt") \
765
V(STR_s, "str", "'St") \
766
V(STR_d, "str", "'Dt") \
767
V(LDR_s, "ldr", "'St") \
768
V(LDR_d, "ldr", "'Dt")
770
void Disassembler::VisitLoadStorePreIndex(Instruction* instr) {
771
const char *mnemonic = "unimplemented";
772
const char *form = "(LoadStorePreIndex)";
774
switch (instr->Mask(LoadStorePreIndexMask)) {
775
#define LS_PREINDEX(A, B, C) \
776
case A##_pre: mnemonic = B; form = C ", ['Xns'ILS]!"; break;
777
LOAD_STORE_LIST(LS_PREINDEX)
780
Format(instr, mnemonic, form);
784
void Disassembler::VisitLoadStorePostIndex(Instruction* instr) {
785
const char *mnemonic = "unimplemented";
786
const char *form = "(LoadStorePostIndex)";
788
switch (instr->Mask(LoadStorePostIndexMask)) {
789
#define LS_POSTINDEX(A, B, C) \
790
case A##_post: mnemonic = B; form = C ", ['Xns]'ILS"; break;
791
LOAD_STORE_LIST(LS_POSTINDEX)
794
Format(instr, mnemonic, form);
798
void Disassembler::VisitLoadStoreUnsignedOffset(Instruction* instr) {
799
const char *mnemonic = "unimplemented";
800
const char *form = "(LoadStoreUnsignedOffset)";
802
switch (instr->Mask(LoadStoreUnsignedOffsetMask)) {
803
#define LS_UNSIGNEDOFFSET(A, B, C) \
804
case A##_unsigned: mnemonic = B; form = C ", ['Xns'ILU]"; break;
805
LOAD_STORE_LIST(LS_UNSIGNEDOFFSET)
806
#undef LS_UNSIGNEDOFFSET
807
case PRFM_unsigned: mnemonic = "prfm"; form = "'PrefOp, ['Xn'ILU]";
809
Format(instr, mnemonic, form);
813
void Disassembler::VisitLoadStoreRegisterOffset(Instruction* instr) {
814
const char *mnemonic = "unimplemented";
815
const char *form = "(LoadStoreRegisterOffset)";
817
switch (instr->Mask(LoadStoreRegisterOffsetMask)) {
818
#define LS_REGISTEROFFSET(A, B, C) \
819
case A##_reg: mnemonic = B; form = C ", ['Xns, 'Offsetreg]"; break;
820
LOAD_STORE_LIST(LS_REGISTEROFFSET)
821
#undef LS_REGISTEROFFSET
822
case PRFM_reg: mnemonic = "prfm"; form = "'PrefOp, ['Xns, 'Offsetreg]";
824
Format(instr, mnemonic, form);
828
void Disassembler::VisitLoadStoreUnscaledOffset(Instruction* instr) {
829
const char *mnemonic = "unimplemented";
830
const char *form = "'Wt, ['Xns'ILS]";
831
const char *form_x = "'Xt, ['Xns'ILS]";
832
const char *form_s = "'St, ['Xns'ILS]";
833
const char *form_d = "'Dt, ['Xns'ILS]";
835
switch (instr->Mask(LoadStoreUnscaledOffsetMask)) {
836
case STURB_w: mnemonic = "sturb"; break;
837
case STURH_w: mnemonic = "sturh"; break;
838
case STUR_w: mnemonic = "stur"; break;
839
case STUR_x: mnemonic = "stur"; form = form_x; break;
840
case STUR_s: mnemonic = "stur"; form = form_s; break;
841
case STUR_d: mnemonic = "stur"; form = form_d; break;
842
case LDURB_w: mnemonic = "ldurb"; break;
843
case LDURH_w: mnemonic = "ldurh"; break;
844
case LDUR_w: mnemonic = "ldur"; break;
845
case LDUR_x: mnemonic = "ldur"; form = form_x; break;
846
case LDUR_s: mnemonic = "ldur"; form = form_s; break;
847
case LDUR_d: mnemonic = "ldur"; form = form_d; break;
848
case LDURSB_x: form = form_x; // Fall through.
849
case LDURSB_w: mnemonic = "ldursb"; break;
850
case LDURSH_x: form = form_x; // Fall through.
851
case LDURSH_w: mnemonic = "ldursh"; break;
852
case LDURSW_x: mnemonic = "ldursw"; form = form_x; break;
853
default: form = "(LoadStoreUnscaledOffset)";
855
Format(instr, mnemonic, form);
859
void Disassembler::VisitLoadLiteral(Instruction* instr) {
860
const char *mnemonic = "ldr";
861
const char *form = "(LoadLiteral)";
863
switch (instr->Mask(LoadLiteralMask)) {
864
case LDR_w_lit: form = "'Wt, 'ILLiteral 'LValue"; break;
865
case LDR_x_lit: form = "'Xt, 'ILLiteral 'LValue"; break;
866
case LDR_s_lit: form = "'St, 'ILLiteral 'LValue"; break;
867
case LDR_d_lit: form = "'Dt, 'ILLiteral 'LValue"; break;
868
default: mnemonic = "unimplemented";
870
Format(instr, mnemonic, form);
874
#define LOAD_STORE_PAIR_LIST(V) \
875
V(STP_w, "stp", "'Wt, 'Wt2", "4") \
876
V(LDP_w, "ldp", "'Wt, 'Wt2", "4") \
877
V(LDPSW_x, "ldpsw", "'Xt, 'Xt2", "4") \
878
V(STP_x, "stp", "'Xt, 'Xt2", "8") \
879
V(LDP_x, "ldp", "'Xt, 'Xt2", "8") \
880
V(STP_s, "stp", "'St, 'St2", "4") \
881
V(LDP_s, "ldp", "'St, 'St2", "4") \
882
V(STP_d, "stp", "'Dt, 'Dt2", "8") \
883
V(LDP_d, "ldp", "'Dt, 'Dt2", "8")
885
void Disassembler::VisitLoadStorePairPostIndex(Instruction* instr) {
886
const char *mnemonic = "unimplemented";
887
const char *form = "(LoadStorePairPostIndex)";
889
switch (instr->Mask(LoadStorePairPostIndexMask)) {
890
#define LSP_POSTINDEX(A, B, C, D) \
891
case A##_post: mnemonic = B; form = C ", ['Xns]'ILP" D; break;
892
LOAD_STORE_PAIR_LIST(LSP_POSTINDEX)
895
Format(instr, mnemonic, form);
899
void Disassembler::VisitLoadStorePairPreIndex(Instruction* instr) {
900
const char *mnemonic = "unimplemented";
901
const char *form = "(LoadStorePairPreIndex)";
903
switch (instr->Mask(LoadStorePairPreIndexMask)) {
904
#define LSP_PREINDEX(A, B, C, D) \
905
case A##_pre: mnemonic = B; form = C ", ['Xns'ILP" D "]!"; break;
906
LOAD_STORE_PAIR_LIST(LSP_PREINDEX)
909
Format(instr, mnemonic, form);
913
void Disassembler::VisitLoadStorePairOffset(Instruction* instr) {
914
const char *mnemonic = "unimplemented";
915
const char *form = "(LoadStorePairOffset)";
917
switch (instr->Mask(LoadStorePairOffsetMask)) {
918
#define LSP_OFFSET(A, B, C, D) \
919
case A##_off: mnemonic = B; form = C ", ['Xns'ILP" D "]"; break;
920
LOAD_STORE_PAIR_LIST(LSP_OFFSET)
923
Format(instr, mnemonic, form);
927
void Disassembler::VisitLoadStorePairNonTemporal(Instruction* instr) {
928
const char *mnemonic = "unimplemented";
931
switch (instr->Mask(LoadStorePairNonTemporalMask)) {
932
case STNP_w: mnemonic = "stnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
933
case LDNP_w: mnemonic = "ldnp"; form = "'Wt, 'Wt2, ['Xns'ILP4]"; break;
934
case STNP_x: mnemonic = "stnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
935
case LDNP_x: mnemonic = "ldnp"; form = "'Xt, 'Xt2, ['Xns'ILP8]"; break;
936
case STNP_s: mnemonic = "stnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
937
case LDNP_s: mnemonic = "ldnp"; form = "'St, 'St2, ['Xns'ILP4]"; break;
938
case STNP_d: mnemonic = "stnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
939
case LDNP_d: mnemonic = "ldnp"; form = "'Dt, 'Dt2, ['Xns'ILP8]"; break;
940
default: form = "(LoadStorePairNonTemporal)";
942
Format(instr, mnemonic, form);
946
void Disassembler::VisitFPCompare(Instruction* instr) {
947
const char *mnemonic = "unimplemented";
948
const char *form = "'Fn, 'Fm";
949
const char *form_zero = "'Fn, #0.0";
951
switch (instr->Mask(FPCompareMask)) {
953
case FCMP_d_zero: form = form_zero; // Fall through.
955
case FCMP_d: mnemonic = "fcmp"; break;
956
default: form = "(FPCompare)";
958
Format(instr, mnemonic, form);
962
void Disassembler::VisitFPConditionalCompare(Instruction* instr) {
963
const char *mnemonic = "unmplemented";
964
const char *form = "'Fn, 'Fm, 'INzcv, 'Cond";
966
switch (instr->Mask(FPConditionalCompareMask)) {
968
case FCCMP_d: mnemonic = "fccmp"; break;
970
case FCCMPE_d: mnemonic = "fccmpe"; break;
971
default: form = "(FPConditionalCompare)";
973
Format(instr, mnemonic, form);
977
void Disassembler::VisitFPConditionalSelect(Instruction* instr) {
978
const char *mnemonic = "";
979
const char *form = "'Fd, 'Fn, 'Fm, 'Cond";
981
switch (instr->Mask(FPConditionalSelectMask)) {
983
case FCSEL_d: mnemonic = "fcsel"; break;
984
default: UNREACHABLE();
986
Format(instr, mnemonic, form);
990
void Disassembler::VisitFPDataProcessing1Source(Instruction* instr) {
991
const char *mnemonic = "unimplemented";
992
const char *form = "'Fd, 'Fn";
994
switch (instr->Mask(FPDataProcessing1SourceMask)) {
995
#define FORMAT(A, B) \
997
case A##_d: mnemonic = B; break;
998
FORMAT(FMOV, "fmov");
999
FORMAT(FABS, "fabs");
1000
FORMAT(FNEG, "fneg");
1001
FORMAT(FSQRT, "fsqrt");
1002
FORMAT(FRINTN, "frintn");
1003
FORMAT(FRINTP, "frintp");
1004
FORMAT(FRINTM, "frintm");
1005
FORMAT(FRINTZ, "frintz");
1006
FORMAT(FRINTA, "frinta");
1007
FORMAT(FRINTX, "frintx");
1008
FORMAT(FRINTI, "frinti");
1010
case FCVT_ds: mnemonic = "fcvt"; form = "'Dd, 'Sn"; break;
1011
case FCVT_sd: mnemonic = "fcvt"; form = "'Sd, 'Dn"; break;
1012
default: form = "(FPDataProcessing1Source)";
1014
Format(instr, mnemonic, form);
1018
void Disassembler::VisitFPDataProcessing2Source(Instruction* instr) {
1019
const char *mnemonic = "";
1020
const char *form = "'Fd, 'Fn, 'Fm";
1022
switch (instr->Mask(FPDataProcessing2SourceMask)) {
1023
#define FORMAT(A, B) \
1025
case A##_d: mnemonic = B; break;
1026
FORMAT(FMUL, "fmul");
1027
FORMAT(FDIV, "fdiv");
1028
FORMAT(FADD, "fadd");
1029
FORMAT(FSUB, "fsub");
1030
FORMAT(FMAX, "fmax");
1031
FORMAT(FMIN, "fmin");
1032
FORMAT(FMAXNM, "fmaxnm");
1033
FORMAT(FMINNM, "fminnm");
1034
FORMAT(FNMUL, "fnmul");
1036
default: UNREACHABLE();
1038
Format(instr, mnemonic, form);
1042
void Disassembler::VisitFPDataProcessing3Source(Instruction* instr) {
1043
const char *mnemonic = "";
1044
const char *form = "'Fd, 'Fn, 'Fm, 'Fa";
1046
switch (instr->Mask(FPDataProcessing3SourceMask)) {
1047
#define FORMAT(A, B) \
1049
case A##_d: mnemonic = B; break;
1050
FORMAT(FMADD, "fmadd");
1051
FORMAT(FMSUB, "fmsub");
1052
FORMAT(FNMADD, "fnmadd");
1053
FORMAT(FNMSUB, "fnmsub");
1055
default: UNREACHABLE();
1057
Format(instr, mnemonic, form);
1061
void Disassembler::VisitFPImmediate(Instruction* instr) {
1062
const char *mnemonic = "";
1063
const char *form = "(FPImmediate)";
1065
switch (instr->Mask(FPImmediateMask)) {
1066
case FMOV_s_imm: mnemonic = "fmov"; form = "'Sd, 'IFPSingle"; break;
1067
case FMOV_d_imm: mnemonic = "fmov"; form = "'Dd, 'IFPDouble"; break;
1068
default: UNREACHABLE();
1070
Format(instr, mnemonic, form);
1074
void Disassembler::VisitFPIntegerConvert(Instruction* instr) {
1075
const char *mnemonic = "unimplemented";
1076
const char *form = "(FPIntegerConvert)";
1077
const char *form_rf = "'Rd, 'Fn";
1078
const char *form_fr = "'Fd, 'Rn";
1080
switch (instr->Mask(FPIntegerConvertMask)) {
1082
case FMOV_xd: mnemonic = "fmov"; form = form_rf; break;
1084
case FMOV_dx: mnemonic = "fmov"; form = form_fr; break;
1088
case FCVTMS_xd: mnemonic = "fcvtms"; form = form_rf; break;
1092
case FCVTMU_xd: mnemonic = "fcvtmu"; form = form_rf; break;
1096
case FCVTNS_xd: mnemonic = "fcvtns"; form = form_rf; break;
1100
case FCVTNU_xd: mnemonic = "fcvtnu"; form = form_rf; break;
1104
case FCVTZU_xs: mnemonic = "fcvtzu"; form = form_rf; break;
1108
case FCVTZS_ws: mnemonic = "fcvtzs"; form = form_rf; break;
1112
case SCVTF_dx: mnemonic = "scvtf"; form = form_fr; break;
1116
case UCVTF_dx: mnemonic = "ucvtf"; form = form_fr; break;
1118
Format(instr, mnemonic, form);
1122
void Disassembler::VisitFPFixedPointConvert(Instruction* instr) {
1123
const char *mnemonic = "";
1124
const char *form = "'Rd, 'Fn, 'IFPFBits";
1125
const char *form_fr = "'Fd, 'Rn, 'IFPFBits";
1127
switch (instr->Mask(FPFixedPointConvertMask)) {
1128
case FCVTZS_ws_fixed:
1129
case FCVTZS_xs_fixed:
1130
case FCVTZS_wd_fixed:
1131
case FCVTZS_xd_fixed: mnemonic = "fcvtzs"; break;
1132
case FCVTZU_ws_fixed:
1133
case FCVTZU_xs_fixed:
1134
case FCVTZU_wd_fixed:
1135
case FCVTZU_xd_fixed: mnemonic = "fcvtzu"; break;
1136
case SCVTF_sw_fixed:
1137
case SCVTF_sx_fixed:
1138
case SCVTF_dw_fixed:
1139
case SCVTF_dx_fixed: mnemonic = "scvtf"; form = form_fr; break;
1140
case UCVTF_sw_fixed:
1141
case UCVTF_sx_fixed:
1142
case UCVTF_dw_fixed:
1143
case UCVTF_dx_fixed: mnemonic = "ucvtf"; form = form_fr; break;
1144
default: UNREACHABLE();
1146
Format(instr, mnemonic, form);
1150
void Disassembler::VisitSystem(Instruction* instr) {
1151
// Some system instructions hijack their Op and Cp fields to represent a
1152
// range of immediates instead of indicating a different instruction. This
1153
// makes the decoding tricky.
1154
const char *mnemonic = "unimplemented";
1155
const char *form = "(System)";
1157
if (instr->Mask(SystemSysRegFMask) == SystemSysRegFixed) {
1158
switch (instr->Mask(SystemSysRegMask)) {
1161
switch (instr->ImmSystemRegister()) {
1162
case NZCV: form = "'Xt, nzcv"; break;
1163
case FPCR: form = "'Xt, fpcr"; break;
1164
default: form = "'Xt, (unknown)"; break;
1170
switch (instr->ImmSystemRegister()) {
1171
case NZCV: form = "nzcv, 'Xt"; break;
1172
case FPCR: form = "fpcr, 'Xt"; break;
1173
default: form = "(unknown), 'Xt"; break;
1178
} else if (instr->Mask(SystemHintFMask) == SystemHintFixed) {
1179
ASSERT(instr->Mask(SystemHintMask) == HINT);
1180
switch (instr->ImmHint()) {
1189
Format(instr, mnemonic, form);
1193
void Disassembler::VisitException(Instruction* instr) {
1194
const char *mnemonic = "unimplemented";
1195
const char *form = "'IDebug";
1197
switch (instr->Mask(ExceptionMask)) {
1198
case HLT: mnemonic = "hlt"; break;
1199
case BRK: mnemonic = "brk"; break;
1200
case SVC: mnemonic = "svc"; break;
1201
case HVC: mnemonic = "hvc"; break;
1202
case SMC: mnemonic = "smc"; break;
1203
case DCPS1: mnemonic = "dcps1"; form = "{'IDebug}"; break;
1204
case DCPS2: mnemonic = "dcps2"; form = "{'IDebug}"; break;
1205
case DCPS3: mnemonic = "dcps3"; form = "{'IDebug}"; break;
1206
default: form = "(Exception)";
1208
Format(instr, mnemonic, form);
1212
void Disassembler::VisitUnimplemented(Instruction* instr) {
1213
Format(instr, "unimplemented", "(Unimplemented)");
1217
void Disassembler::VisitUnallocated(Instruction* instr) {
1218
Format(instr, "unallocated", "(Unallocated)");
1222
void Disassembler::ProcessOutput(Instruction* /*instr*/) {
1223
// The base disasm does nothing more than disassembling into a buffer.
1227
void Disassembler::Format(Instruction* instr, const char* mnemonic,
1228
const char* format) {
1229
ASSERT(mnemonic != NULL);
1231
Substitute(instr, mnemonic);
1232
if (format != NULL) {
1233
buffer_[buffer_pos_++] = ' ';
1234
Substitute(instr, format);
1236
buffer_[buffer_pos_] = 0;
1237
ProcessOutput(instr);
1241
void Disassembler::Substitute(Instruction* instr, const char* string) {
1242
char chr = *string++;
1243
while (chr != '\0') {
1245
string += SubstituteField(instr, string);
1247
buffer_[buffer_pos_++] = chr;
1254
int Disassembler::SubstituteField(Instruction* instr, const char* format) {
1255
switch (format[0]) {
1256
case 'R': // Register. X or W, selected by sf bit.
1257
case 'F': // FP Register. S or D, selected by type field.
1261
case 'D': return SubstituteRegisterField(instr, format);
1262
case 'I': return SubstituteImmediateField(instr, format);
1263
case 'L': return SubstituteLiteralField(instr, format);
1264
case 'H': return SubstituteShiftField(instr, format);
1265
case 'P': return SubstitutePrefetchField(instr, format);
1266
case 'C': return SubstituteConditionField(instr, format);
1267
case 'E': return SubstituteExtendField(instr, format);
1268
case 'A': return SubstitutePCRelAddressField(instr, format);
1269
case 'B': return SubstituteBranchTargetField(instr, format);
1270
case 'O': return SubstituteLSRegOffsetField(instr, format);
1279
int Disassembler::SubstituteRegisterField(Instruction* instr,
1280
const char* format) {
1281
unsigned reg_num = 0;
1282
unsigned field_len = 2;
1283
switch (format[1]) {
1284
case 'd': reg_num = instr->Rd(); break;
1285
case 'n': reg_num = instr->Rn(); break;
1286
case 'm': reg_num = instr->Rm(); break;
1287
case 'a': reg_num = instr->Ra(); break;
1289
if (format[2] == '2') {
1290
reg_num = instr->Rt2();
1293
reg_num = instr->Rt();
1297
default: UNREACHABLE();
1300
// Increase field length for registers tagged as stack.
1301
if (format[2] == 's') {
1306
if (format[0] == 'R') {
1307
// Register type is R: use sf bit to choose X and W.
1308
reg_type = instr->SixtyFourBits() ? 'x' : 'w';
1309
} else if (format[0] == 'F') {
1310
// Floating-point register: use type field to choose S or D.
1311
reg_type = ((instr->FPType() & 1) == 0) ? 's' : 'd';
1313
// Register type is specified. Make it lower case.
1314
reg_type = format[0] + 0x20;
1317
if ((reg_num != kZeroRegCode) || (reg_type == 's') || (reg_type == 'd')) {
1318
// A normal register: w0 - w30, x0 - x30, s0 - s31, d0 - d31.
1319
AppendToOutput("%c%d", reg_type, reg_num);
1320
} else if (format[2] == 's') {
1321
// Disassemble w31/x31 as stack pointer wsp/sp.
1322
AppendToOutput("%s", (reg_type == 'w') ? "wsp" : "sp");
1324
// Disassemble w31/x31 as zero register wzr/xzr.
1325
AppendToOutput("%czr", reg_type);
1332
int Disassembler::SubstituteImmediateField(Instruction* instr,
1333
const char* format) {
1334
ASSERT(format[0] == 'I');
1336
switch (format[1]) {
1337
case 'M': { // IMoveImm or IMoveLSL.
1338
if (format[5] == 'I') {
1339
uint64_t imm = instr->ImmMoveWide() << (16 * instr->ShiftMoveWide());
1340
AppendToOutput("#0x%" PRIx64, imm);
1342
ASSERT(format[5] == 'L');
1343
AppendToOutput("#0x%" PRIx64, instr->ImmMoveWide());
1344
if (instr->ShiftMoveWide() > 0) {
1345
AppendToOutput(", lsl #%d", 16 * instr->ShiftMoveWide());
1351
switch (format[2]) {
1352
case 'L': { // ILLiteral - Immediate Load Literal.
1353
AppendToOutput("pc%+" PRId64,
1354
instr->ImmLLiteral() << kLiteralEntrySizeLog2);
1357
case 'S': { // ILS - Immediate Load/Store.
1358
if (instr->ImmLS() != 0) {
1359
AppendToOutput(", #%" PRId64, instr->ImmLS());
1363
case 'P': { // ILPx - Immediate Load/Store Pair, x = access size.
1364
if (instr->ImmLSPair() != 0) {
1365
// format[3] is the scale value. Convert to a number.
1366
int scale = format[3] - 0x30;
1367
AppendToOutput(", #%" PRId64, instr->ImmLSPair() * scale);
1371
case 'U': { // ILU - Immediate Load/Store Unsigned.
1372
if (instr->ImmLSUnsigned() != 0) {
1373
AppendToOutput(", #%" PRIu64,
1374
instr->ImmLSUnsigned() << instr->SizeLS());
1380
case 'C': { // ICondB - Immediate Conditional Branch.
1381
int64_t offset = instr->ImmCondBranch() << 2;
1382
char sign = (offset >= 0) ? '+' : '-';
1383
AppendToOutput("#%c0x%" PRIx64, sign, offset);
1386
case 'A': { // IAddSub.
1387
ASSERT(instr->ShiftAddSub() <= 1);
1388
int64_t imm = instr->ImmAddSub() << (12 * instr->ShiftAddSub());
1389
AppendToOutput("#0x%" PRIx64 " (%" PRId64 ")", imm, imm);
1392
case 'F': { // IFPSingle, IFPDouble or IFPFBits.
1393
if (format[3] == 'F') { // IFPFbits.
1394
AppendToOutput("#%d", 64 - instr->FPScale());
1397
AppendToOutput("#0x%" PRIx64 " (%.4f)", instr->ImmFP(),
1398
format[3] == 'S' ? instr->ImmFP32() : instr->ImmFP64());
1402
case 'T': { // ITri - Immediate Triangular Encoded.
1403
AppendToOutput("#0x%" PRIx64, instr->ImmLogical());
1406
case 'N': { // INzcv.
1407
int nzcv = (instr->Nzcv() << Flags_offset);
1408
AppendToOutput("#%c%c%c%c", ((nzcv & NFlag) == 0) ? 'n' : 'N',
1409
((nzcv & ZFlag) == 0) ? 'z' : 'Z',
1410
((nzcv & CFlag) == 0) ? 'c' : 'C',
1411
((nzcv & VFlag) == 0) ? 'v' : 'V');
1414
case 'P': { // IP - Conditional compare.
1415
AppendToOutput("#%d", instr->ImmCondCmp());
1418
case 'B': { // Bitfields.
1419
return SubstituteBitfieldImmediateField(instr, format);
1421
case 'E': { // IExtract.
1422
AppendToOutput("#%d", instr->ImmS());
1425
case 'S': { // IS - Test and branch bit.
1426
AppendToOutput("#%d", (instr->ImmTestBranchBit5() << 5) |
1427
instr->ImmTestBranchBit40());
1430
case 'D': { // IDebug - HLT and BRK instructions.
1431
AppendToOutput("#0x%x", instr->ImmException());
1442
int Disassembler::SubstituteBitfieldImmediateField(Instruction* instr,
1443
const char* format) {
1444
ASSERT((format[0] == 'I') && (format[1] == 'B'));
1445
unsigned r = instr->ImmR();
1446
unsigned s = instr->ImmS();
1448
switch (format[2]) {
1450
AppendToOutput("#%d", r);
1453
case 's': { // IBs+1 or IBs-r+1.
1454
if (format[3] == '+') {
1455
AppendToOutput("#%d", s + 1);
1458
ASSERT(format[3] == '-');
1459
AppendToOutput("#%d", s - r + 1);
1463
case 'Z': { // IBZ-r.
1464
ASSERT((format[3] == '-') && (format[4] == 'r'));
1465
unsigned reg_size = (instr->SixtyFourBits() == 1) ? kXRegSize : kWRegSize;
1466
AppendToOutput("#%d", reg_size - r);
1477
int Disassembler::SubstituteLiteralField(Instruction* instr,
1478
const char* format) {
1479
ASSERT(strncmp(format, "LValue", 6) == 0);
1482
switch (instr->Mask(LoadLiteralMask)) {
1486
case LDR_d_lit: AppendToOutput("(addr %p)", instr->LiteralAddress()); break;
1487
default: UNREACHABLE();
1494
int Disassembler::SubstituteShiftField(Instruction* instr, const char* format) {
1495
ASSERT(format[0] == 'H');
1496
ASSERT(instr->ShiftDP() <= 0x3);
1498
switch (format[1]) {
1500
ASSERT(instr->ShiftDP() != ROR);
1503
if (instr->ImmDPShift() != 0) {
1504
const char* shift_type[] = {"lsl", "lsr", "asr", "ror"};
1505
AppendToOutput(", %s #%" PRId64, shift_type[instr->ShiftDP()],
1506
instr->ImmDPShift());
1517
int Disassembler::SubstituteConditionField(Instruction* instr,
1518
const char* format) {
1519
ASSERT(format[0] == 'C');
1520
const char* condition_code[] = { "eq", "ne", "hs", "lo",
1521
"mi", "pl", "vs", "vc",
1522
"hi", "ls", "ge", "lt",
1523
"gt", "le", "al", "nv" };
1525
switch (format[1]) {
1526
case 'B': cond = instr->ConditionBranch(); break;
1528
cond = InvertCondition(static_cast<Condition>(instr->Condition()));
1531
default: cond = instr->Condition();
1533
AppendToOutput("%s", condition_code[cond]);
1538
int Disassembler::SubstitutePCRelAddressField(Instruction* instr,
1539
const char* format) {
1541
ASSERT(strncmp(format, "AddrPCRel", 9) == 0);
1543
int offset = instr->ImmPCRel();
1545
// Only ADR (AddrPCRelByte) is supported.
1546
ASSERT(strcmp(format, "AddrPCRelByte") == 0);
1553
// TODO: Extend this to support printing the target address.
1554
AppendToOutput("#%c0x%x", sign, offset);
1559
int Disassembler::SubstituteBranchTargetField(Instruction* instr,
1560
const char* format) {
1561
ASSERT(strncmp(format, "BImm", 4) == 0);
1564
switch (format[5]) {
1565
// BImmUncn - unconditional branch immediate.
1566
case 'n': offset = instr->ImmUncondBranch(); break;
1567
// BImmCond - conditional branch immediate.
1568
case 'o': offset = instr->ImmCondBranch(); break;
1569
// BImmCmpa - compare and branch immediate.
1570
case 'm': offset = instr->ImmCmpBranch(); break;
1571
// BImmTest - test and branch immediate.
1572
case 'e': offset = instr->ImmTestBranch(); break;
1573
default: UNIMPLEMENTED();
1575
offset <<= kInstructionSizeLog2;
1581
AppendToOutput("#%c0x%" PRIx64, sign, offset);
1586
int Disassembler::SubstituteExtendField(Instruction* instr,
1587
const char* format) {
1588
ASSERT(strncmp(format, "Ext", 3) == 0);
1589
ASSERT(instr->ExtendMode() <= 7);
1592
const char* extend_mode[] = { "uxtb", "uxth", "uxtw", "uxtx",
1593
"sxtb", "sxth", "sxtw", "sxtx" };
1595
// If rd or rn is SP, uxtw on 32-bit registers and uxtx on 64-bit
1596
// registers becomes lsl.
1597
if (((instr->Rd() == kZeroRegCode) || (instr->Rn() == kZeroRegCode)) &&
1598
(((instr->ExtendMode() == UXTW) && (instr->SixtyFourBits() == 0)) ||
1599
(instr->ExtendMode() == UXTX))) {
1600
if (instr->ImmExtendShift() > 0) {
1601
AppendToOutput(", lsl #%d", instr->ImmExtendShift());
1604
AppendToOutput(", %s", extend_mode[instr->ExtendMode()]);
1605
if (instr->ImmExtendShift() > 0) {
1606
AppendToOutput(" #%d", instr->ImmExtendShift());
1613
int Disassembler::SubstituteLSRegOffsetField(Instruction* instr,
1614
const char* format) {
1615
ASSERT(strncmp(format, "Offsetreg", 9) == 0);
1616
const char* extend_mode[] = { "undefined", "undefined", "uxtw", "lsl",
1617
"undefined", "undefined", "sxtw", "sxtx" };
1620
unsigned shift = instr->ImmShiftLS();
1621
Extend ext = static_cast<Extend>(instr->ExtendMode());
1622
char reg_type = ((ext == UXTW) || (ext == SXTW)) ? 'w' : 'x';
1624
unsigned rm = instr->Rm();
1625
if (rm == kZeroRegCode) {
1626
AppendToOutput("%czr", reg_type);
1628
AppendToOutput("%c%d", reg_type, rm);
1631
// Extend mode UXTX is an alias for shift mode LSL here.
1632
if (!((ext == UXTX) && (shift == 0))) {
1633
AppendToOutput(", %s", extend_mode[ext]);
1635
AppendToOutput(" #%d", instr->SizeLS());
1642
int Disassembler::SubstitutePrefetchField(Instruction* instr,
1643
const char* format) {
1644
ASSERT(format[0] == 'P');
1647
int prefetch_mode = instr->PrefetchMode();
1649
const char* ls = (prefetch_mode & 0x10) ? "st" : "ld";
1650
int level = (prefetch_mode >> 1) + 1;
1651
const char* ks = (prefetch_mode & 1) ? "strm" : "keep";
1653
AppendToOutput("p%sl%d%s", ls, level, ks);
1658
void Disassembler::ResetOutput() {
1660
buffer_[buffer_pos_] = 0;
1664
void Disassembler::AppendToOutput(const char* format, ...) {
1666
va_start(args, format);
1667
buffer_pos_ += vsnprintf(&buffer_[buffer_pos_], buffer_size_, format, args);
1672
void PrintDisassembler::ProcessOutput(Instruction* instr) {
1673
fprintf(stream_, "0x%016" PRIx64 " %08" PRIx32 "\t\t%s\n",
1674
reinterpret_cast<uint64_t>(instr),
1675
instr->InstructionBits(),