• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
20 namespace v8 {
21 namespace internal {
22 
23 
Disassembler()24 Disassembler::Disassembler() {
25   buffer_size_ = 256;
26   buffer_ = reinterpret_cast<char*>(malloc(buffer_size_));
27   buffer_pos_ = 0;
28   own_buffer_ = true;
29 }
30 
31 
Disassembler(char * text_buffer,int buffer_size)32 Disassembler::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 
~Disassembler()40 Disassembler::~Disassembler() {
41   if (own_buffer_) {
42     free(buffer_);
43   }
44 }
45 
46 
GetOutput()47 char* Disassembler::GetOutput() {
48   return buffer_;
49 }
50 
51 
VisitAddSubImmediate(Instruction * instr)52 void 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 
VisitAddSubShifted(Instruction * instr)97 void 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 
VisitAddSubExtended(Instruction * instr)144 void 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 
VisitAddSubWithCarry(Instruction * instr)182 void 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 
VisitLogicalImmediate(Instruction * instr)217 void 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 
IsMovzMovnImm(unsigned reg_size,uint64_t value)260 bool 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 
VisitLogicalShifted(Instruction * instr)289 void 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 
VisitConditionalCompareRegister(Instruction * instr)340 void 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 
VisitConditionalCompareImmediate(Instruction * instr)355 void 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 
VisitConditionalSelect(Instruction * instr)370 void 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 
VisitBitfield(Instruction * instr)423 void 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 
VisitExtract(Instruction * instr)501 void 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 
VisitPCRelAddressing(Instruction * instr)522 void 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 
VisitConditionalBranch(Instruction * instr)531 void 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 
VisitUnconditionalBranchToRegister(Instruction * instr)539 void 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 
VisitUnconditionalBranch(Instruction * instr)559 void 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 
VisitDataProcessing1Source(Instruction * instr)572 void 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 
VisitDataProcessing2Source(Instruction * instr)593 void 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 
VisitDataProcessing3Source(Instruction * instr)614 void 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 
VisitCompareBranch(Instruction * instr)692 void 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 
VisitTestBranch(Instruction * instr)707 void 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 
VisitMoveWideImmediate(Instruction * instr)724 void 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 
VisitLoadStorePreIndex(Instruction * instr)763 void 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 
VisitLoadStorePostIndex(Instruction * instr)777 void 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 
VisitLoadStoreUnsignedOffset(Instruction * instr)791 void 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 
VisitLoadStoreRegisterOffset(Instruction * instr)806 void 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 
VisitLoadStoreUnscaledOffset(Instruction * instr)821 void 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 
VisitLoadLiteral(Instruction * instr)852 void 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 
VisitLoadStorePairPostIndex(Instruction * instr)878 void 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 
VisitLoadStorePairPreIndex(Instruction * instr)892 void 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 
VisitLoadStorePairOffset(Instruction * instr)906 void 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 
VisitLoadStorePairNonTemporal(Instruction * instr)920 void 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 
VisitFPCompare(Instruction * instr)939 void 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 
VisitFPConditionalCompare(Instruction * instr)955 void 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 
VisitFPConditionalSelect(Instruction * instr)970 void 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 
VisitFPDataProcessing1Source(Instruction * instr)983 void 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 
VisitFPDataProcessing2Source(Instruction * instr)1011 void 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 
VisitFPDataProcessing3Source(Instruction * instr)1035 void 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 
VisitFPImmediate(Instruction * instr)1054 void 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 
VisitFPIntegerConvert(Instruction * instr)1067 void 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 
VisitFPFixedPointConvert(Instruction * instr)1123 void 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 
VisitSystem(Instruction * instr)1150 void Disassembler::VisitSystem(Instruction* instr) {
1151   // Some system instructions hijack their Op and Cp fields to represent a
1152   // range of immediates instead of indicating a different instruction. This
1153   // makes the decoding tricky.
1154   const char *mnemonic = "unimplemented";
1155   const char *form = "(System)";
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 
VisitException(Instruction * instr)1211 void 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 
VisitUnimplemented(Instruction * instr)1230 void Disassembler::VisitUnimplemented(Instruction* instr) {
1231   Format(instr, "unimplemented", "(Unimplemented)");
1232 }
1233 
1234 
VisitUnallocated(Instruction * instr)1235 void Disassembler::VisitUnallocated(Instruction* instr) {
1236   Format(instr, "unallocated", "(Unallocated)");
1237 }
1238 
1239 
ProcessOutput(Instruction *)1240 void Disassembler::ProcessOutput(Instruction* /*instr*/) {
1241   // The base disasm does nothing more than disassembling into a buffer.
1242 }
1243 
1244 
Format(Instruction * instr,const char * mnemonic,const char * format)1245 void 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 
Substitute(Instruction * instr,const char * string)1261 void 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 
SubstituteField(Instruction * instr,const char * format)1274 int 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 
SubstituteRegisterField(Instruction * instr,const char * format)1300 int 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 
SubstituteImmediateField(Instruction * instr,const char * format)1365 int 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 
SubstituteBitfieldImmediateField(Instruction * instr,const char * format)1475 int 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 
SubstituteLiteralField(Instruction * instr,const char * format)1511 int 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 
SubstituteShiftField(Instruction * instr,const char * format)1530 int 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 
SubstituteConditionField(Instruction * instr,const char * format)1553 int 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 
SubstitutePCRelAddressField(Instruction * instr,const char * format)1574 int 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 
SubstituteBranchTargetField(Instruction * instr,const char * format)1595 int 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 
SubstituteExtendField(Instruction * instr,const char * format)1622 int 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 
SubstituteLSRegOffsetField(Instruction * instr,const char * format)1649 int 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 
SubstitutePrefetchField(Instruction * instr,const char * format)1678 int 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 
SubstituteBarrierField(Instruction * instr,const char * format)1693 int 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 
ResetOutput()1712 void Disassembler::ResetOutput() {
1713   buffer_pos_ = 0;
1714   buffer_[buffer_pos_] = 0;
1715 }
1716 
1717 
AppendToOutput(const char * format,...)1718 void 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 
ProcessOutput(Instruction * instr)1726 void 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 
1735 namespace disasm {
1736 
1737 
NameOfAddress(byte * addr) const1738 const char* NameConverter::NameOfAddress(byte* addr) const {
1739   v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1740   return tmp_buffer_.start();
1741 }
1742 
1743 
NameOfConstant(byte * addr) const1744 const char* NameConverter::NameOfConstant(byte* addr) const {
1745   return NameOfAddress(addr);
1746 }
1747 
1748 
NameOfCPURegister(int reg) const1749 const 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 
NameOfByteCPURegister(int reg) const1762 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1763   UNREACHABLE();  // ARM64 does not have the concept of a byte register
1764   return "nobytereg";
1765 }
1766 
1767 
NameOfXMMRegister(int reg) const1768 const char* NameConverter::NameOfXMMRegister(int reg) const {
1769   UNREACHABLE();  // ARM64 does not have any XMM registers
1770   return "noxmmreg";
1771 }
1772 
1773 
NameInCode(byte * addr) const1774 const 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 
1783 class BufferDisassembler : public v8::internal::Disassembler {
1784  public:
BufferDisassembler(v8::internal::Vector<char> out_buffer)1785   explicit BufferDisassembler(v8::internal::Vector<char> out_buffer)
1786       : out_buffer_(out_buffer) { }
1787 
~BufferDisassembler()1788   ~BufferDisassembler() { }
1789 
ProcessOutput(v8::internal::Instruction * instr)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 
Disassembler(const NameConverter & converter)1798 Disassembler::Disassembler(const NameConverter& converter)
1799     : converter_(converter) {}
1800 
1801 
~Disassembler()1802 Disassembler::~Disassembler() { USE(converter_); }
1803 
1804 
InstructionDecode(v8::internal::Vector<char> buffer,byte * instr)1805 int 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 
ConstantPoolSizeAt(byte * instr)1816 int Disassembler::ConstantPoolSizeAt(byte* instr) {
1817   return v8::internal::Assembler::ConstantPoolSizeAt(
1818       reinterpret_cast<v8::internal::Instruction*>(instr));
1819 }
1820 
1821 
Disassemble(FILE * file,byte * start,byte * end)1822 void 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