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