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