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