blob: 36bad37705f7e3e08db467d3cf8b7977da9b37f9 [file] [log] [blame]
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001// 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
Emily Bernierd0a1eb72015-03-24 16:35:39 -04001698 static const char* const options[4][4] = {
Ben Murdochb8a8cc12014-11-26 15:28:44 +00001699 { "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