1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 ***************************************************************************/
26 #include "arm_disassembler.h"
27 #include <helper/log.h>
30 #include <capstone/capstone.h>
34 * This disassembler supports two main functions for OpenOCD:
36 * - Various "disassemble" commands. OpenOCD can serve as a
37 * machine-language debugger, without help from GDB.
39 * - Single stepping. Not all ARM cores support hardware single
40 * stepping. To work without that support, the debugger must
41 * be able to decode instructions to find out where to put a
42 * "next instruction" breakpoint.
44 * In addition, interpretation of ETM trace data needs some of the
45 * decoding mechanisms.
47 * At this writing (September 2009) neither function is complete.
50 * * Old-style syntax (not UAL) is generally used
51 * * VFP instructions are not understood (ARMv5 and later)
52 * except as coprocessor 10/11 operations
53 * * Most ARM instructions through ARMv6 are decoded, but some
54 * of the post-ARMv4 opcodes may not be handled yet
55 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
56 * * NEON instructions are not understood (ARMv7-A)
58 * - Thumb/Thumb2 decoding
59 * * UAL syntax should be consistently used
60 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
61 * be handled properly. Accordingly, so should the subset
62 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
64 * * Conditional effects of Thumb2 "IT" (if-then) instructions
65 * are not handled: the affected instructions are not shown
66 * with their now-conditional suffixes.
67 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
68 * handled (minimally for coprocessor access).
69 * * SIMD instructions, and some other Thumb2 instructions
70 * from ARMv7-A, are not understood.
73 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
74 * * Opcodes changed by ThumbEE mode are not handled; these
75 * instructions wrongly decode as LDM and STM.
77 * - Jazelle decoding ... no support whatsoever for Jazelle mode
78 * or decoding. ARM encourages use of the more generic ThumbEE
79 * mode, instead of Jazelle mode, in current chips.
81 * - Single-step/emulation ... spotty support, which is only weakly
82 * tested. Thumb2 is not supported. (Arguably a full simulator
83 * is not needed to support just single stepping. Recognizing
84 * branch vs non-branch instructions suffices, except when the
85 * instruction faults and triggers a synchronous exception which
86 * can be intercepted using other means.)
88 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
89 * ARM v7-R edition" gives the most complete coverage of the various
90 * generations of ARM instructions. At this writing it is publicly
91 * accessible to anyone willing to create an account at the ARM
92 * web site; see http://www.arm.com/documentation/ for information.
94 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
95 * more details relevant to the Thumb2-only processors (such as
96 * the Cortex-M implementations).
99 /* textual representation of the condition field
100 * ALways (default) is omitted (empty string) */
101 static const char *arm_condition_strings[] = {
102 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
105 /* make up for C's missing ROR */
106 static uint32_t ror(uint32_t value, int places)
108 return (value >> places) | (value << (32 - places));
111 static int evaluate_unknown(uint32_t opcode,
112 uint32_t address, struct arm_instruction *instruction)
114 instruction->type = ARM_UNDEFINED_INSTRUCTION;
115 snprintf(instruction->text, 128,
116 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32
117 "\tUNDEFINED INSTRUCTION", address, opcode);
121 static int evaluate_pld(uint32_t opcode,
122 uint32_t address, struct arm_instruction *instruction)
125 if ((opcode & 0x0d30f000) == 0x0510f000) {
130 instruction->type = ARM_PLD;
131 Rn = (opcode & 0xf0000) >> 16;
132 U = (opcode & 0x00800000) >> 23;
135 offset = opcode & 0x0fff;
136 snprintf(instruction->text, 128,
137 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD %s%d",
138 address, opcode, U ? "" : "-", offset);
142 I = (opcode & 0x02000000) >> 25;
143 R = (opcode & 0x00400000) >> 22;
146 /* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */
147 offset = (opcode & 0x0F80) >> 7;
153 snprintf(instruction->text, 128,
154 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d]",
155 address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm);
159 shift = (opcode & 0x60) >> 5;
163 snprintf(instruction->text, 128,
164 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSL #0x%x)",
165 address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
166 } else if (shift == 0x1) {
168 snprintf(instruction->text, 128,
169 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, LSR #0x%x)",
170 address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
171 } else if (shift == 0x2) {
173 snprintf(instruction->text, 128,
174 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ASR #0x%x)",
175 address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
176 } else if (shift == 0x3) {
178 snprintf(instruction->text, 128,
179 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, %sr%d, ROR #0x%x)",
180 address, opcode, R ? "" : "W", Rn, U ? "" : "-", Rm, offset);
184 /* immediate PLD{W} [<Rn>, #+/-<imm12>] */
185 offset = opcode & 0x0fff;
187 snprintf(instruction->text, 128,
188 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d]",
189 address, opcode, R ? "" : "W", Rn);
191 snprintf(instruction->text, 128,
192 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tPLD%s [r%d, #%s%d]",
193 address, opcode, R ? "" : "W", Rn, U ? "" : "-", offset);
200 if ((opcode & 0x07f000f0) == 0x05700040) {
201 instruction->type = ARM_DSB;
204 switch (opcode & 0x0000000f) {
233 snprintf(instruction->text,
235 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tDSB %s",
236 address, opcode, opt);
241 if ((opcode & 0x07f000f0) == 0x05700060) {
242 instruction->type = ARM_ISB;
244 snprintf(instruction->text,
246 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tISB %s",
248 ((opcode & 0x0000000f) == 0xf) ? "SY" : "UNK");
252 return evaluate_unknown(opcode, address, instruction);
255 static int evaluate_srs(uint32_t opcode,
256 uint32_t address, struct arm_instruction *instruction)
258 const char *wback = (opcode & (1 << 21)) ? "!" : "";
259 const char *mode = "";
261 switch ((opcode >> 23) & 0x3) {
266 /* "IA" is default */
276 switch (opcode & 0x0e500000) {
278 snprintf(instruction->text, 128, "0x%8.8" PRIx32
280 "\tSRS%s\tSP%s, #%d",
283 (unsigned)(opcode & 0x1f));
286 snprintf(instruction->text, 128, "0x%8.8" PRIx32
291 (unsigned)((opcode >> 16) & 0xf), wback);
294 return evaluate_unknown(opcode, address, instruction);
299 static int evaluate_swi(uint32_t opcode,
300 uint32_t address, struct arm_instruction *instruction)
302 instruction->type = ARM_SWI;
304 snprintf(instruction->text, 128,
305 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSVC %#6.6" PRIx32,
306 address, opcode, (opcode & 0xffffff));
311 static int evaluate_blx_imm(uint32_t opcode,
312 uint32_t address, struct arm_instruction *instruction)
316 uint32_t target_address;
318 instruction->type = ARM_BLX;
319 immediate = opcode & 0x00ffffff;
321 /* sign extend 24-bit immediate */
322 if (immediate & 0x00800000)
323 offset = 0xff000000 | immediate;
327 /* shift two bits left */
330 /* odd/event halfword */
331 if (opcode & 0x01000000)
334 target_address = address + 8 + offset;
336 snprintf(instruction->text,
338 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX 0x%8.8" PRIx32 "",
343 instruction->info.b_bl_bx_blx.reg_operand = -1;
344 instruction->info.b_bl_bx_blx.target_address = target_address;
349 static int evaluate_b_bl(uint32_t opcode,
350 uint32_t address, struct arm_instruction *instruction)
355 uint32_t target_address;
357 immediate = opcode & 0x00ffffff;
358 L = (opcode & 0x01000000) >> 24;
360 /* sign extend 24-bit immediate */
361 if (immediate & 0x00800000)
362 offset = 0xff000000 | immediate;
366 /* shift two bits left */
369 target_address = address + 8 + offset;
372 instruction->type = ARM_BL;
374 instruction->type = ARM_B;
376 snprintf(instruction->text,
378 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tB%s%s 0x%8.8" PRIx32,
385 instruction->info.b_bl_bx_blx.reg_operand = -1;
386 instruction->info.b_bl_bx_blx.target_address = target_address;
391 /* Coprocessor load/store and double register transfers
392 * both normal and extended instruction space (condition field b1111) */
393 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode,
394 uint32_t address, struct arm_instruction *instruction)
396 uint8_t cp_num = (opcode & 0xf00) >> 8;
399 if (((opcode & 0x0ff00000) == 0x0c400000) || ((opcode & 0x0ff00000) == 0x0c500000)) {
400 uint8_t cp_opcode, Rd, Rn, CRm;
403 cp_opcode = (opcode & 0xf0) >> 4;
404 Rd = (opcode & 0xf000) >> 12;
405 Rn = (opcode & 0xf0000) >> 16;
406 CRm = (opcode & 0xf);
409 if ((opcode & 0x0ff00000) == 0x0c400000) {
410 instruction->type = ARM_MCRR;
412 } else if ((opcode & 0x0ff00000) == 0x0c500000) {
414 instruction->type = ARM_MRRC;
417 LOG_ERROR("Unknown instruction");
421 snprintf(instruction->text, 128,
422 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32
423 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
424 address, opcode, mnemonic,
425 ((opcode & 0xf0000000) == 0xf0000000)
426 ? "2" : COND(opcode),
427 COND(opcode), cp_num, cp_opcode, Rd, Rn, CRm);
428 } else {/* LDC or STC */
429 uint8_t CRd, Rn, offset;
432 char addressing_mode[32];
434 CRd = (opcode & 0xf000) >> 12;
435 Rn = (opcode & 0xf0000) >> 16;
436 offset = (opcode & 0xff) << 2;
439 if (opcode & 0x00100000) {
440 instruction->type = ARM_LDC;
443 instruction->type = ARM_STC;
447 U = (opcode & 0x00800000) >> 23;
449 /* addressing modes */
450 if ((opcode & 0x01200000) == 0x01000000)/* offset */
451 snprintf(addressing_mode, 32, "[r%i, #%s%d]",
452 Rn, U ? "" : "-", offset);
453 else if ((opcode & 0x01200000) == 0x01200000) /* pre-indexed */
454 snprintf(addressing_mode, 32, "[r%i, #%s%d]!",
455 Rn, U ? "" : "-", offset);
456 else if ((opcode & 0x01200000) == 0x00200000) /* post-indexed */
457 snprintf(addressing_mode, 32, "[r%i], #%s%d",
458 Rn, U ? "" : "-", offset);
459 else if ((opcode & 0x01200000) == 0x00000000) /* unindexed */
460 snprintf(addressing_mode, 32, "[r%i], {%d}",
463 snprintf(instruction->text, 128, "0x%8.8" PRIx32
465 "\t%s%s%s p%i, c%i, %s",
466 address, opcode, mnemonic,
467 ((opcode & 0xf0000000) == 0xf0000000)
468 ? "2" : COND(opcode),
469 (opcode & (1 << 22)) ? "L" : "",
470 cp_num, CRd, addressing_mode);
476 /* Coprocessor data processing instructions
477 * Coprocessor register transfer instructions
478 * both normal and extended instruction space (condition field b1111) */
479 static int evaluate_cdp_mcr_mrc(uint32_t opcode,
480 uint32_t address, struct arm_instruction *instruction)
484 uint8_t cp_num, opcode_1, CRd_Rd, CRn, CRm, opcode_2;
486 cond = ((opcode & 0xf0000000) == 0xf0000000) ? "2" : COND(opcode);
487 cp_num = (opcode & 0xf00) >> 8;
488 CRd_Rd = (opcode & 0xf000) >> 12;
489 CRn = (opcode & 0xf0000) >> 16;
490 CRm = (opcode & 0xf);
491 opcode_2 = (opcode & 0xe0) >> 5;
494 if (opcode & 0x00000010) { /* bit 4 set -> MRC/MCR */
495 if (opcode & 0x00100000) { /* bit 20 set -> MRC */
496 instruction->type = ARM_MRC;
498 } else {/* bit 20 not set -> MCR */
499 instruction->type = ARM_MCR;
503 opcode_1 = (opcode & 0x00e00000) >> 21;
505 snprintf(instruction->text,
507 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
518 } else {/* bit 4 not set -> CDP */
519 instruction->type = ARM_CDP;
522 opcode_1 = (opcode & 0x00f00000) >> 20;
524 snprintf(instruction->text,
526 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
542 /* Load/store instructions */
543 static int evaluate_load_store(uint32_t opcode,
544 uint32_t address, struct arm_instruction *instruction)
546 uint8_t I, P, U, B, W, L;
548 char *operation;/* "LDR" or "STR" */
549 char *suffix; /* "", "B", "T", "BT" */
553 I = (opcode & 0x02000000) >> 25;
554 P = (opcode & 0x01000000) >> 24;
555 U = (opcode & 0x00800000) >> 23;
556 B = (opcode & 0x00400000) >> 22;
557 W = (opcode & 0x00200000) >> 21;
558 L = (opcode & 0x00100000) >> 20;
560 /* target register */
561 Rd = (opcode & 0xf000) >> 12;
564 Rn = (opcode & 0xf0000) >> 16;
566 instruction->info.load_store.Rd = Rd;
567 instruction->info.load_store.Rn = Rn;
568 instruction->info.load_store.U = U;
570 /* determine operation */
576 /* determine instruction type and suffix */
578 if ((P == 0) && (W == 1)) {
580 instruction->type = ARM_LDRBT;
582 instruction->type = ARM_STRBT;
586 instruction->type = ARM_LDRB;
588 instruction->type = ARM_STRB;
592 if ((P == 0) && (W == 1)) {
594 instruction->type = ARM_LDRT;
596 instruction->type = ARM_STRT;
600 instruction->type = ARM_LDR;
602 instruction->type = ARM_STR;
607 if (!I) { /* #+-<offset_12> */
608 uint32_t offset_12 = (opcode & 0xfff);
610 snprintf(offset, 32, ", #%s0x%" PRIx32 "", (U) ? "" : "-", offset_12);
612 snprintf(offset, 32, "%s", "");
614 instruction->info.load_store.offset_mode = 0;
615 instruction->info.load_store.offset.offset = offset_12;
616 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
617 uint8_t shift_imm, shift;
620 shift_imm = (opcode & 0xf80) >> 7;
621 shift = (opcode & 0x60) >> 5;
624 /* LSR encodes a shift by 32 bit as 0x0 */
625 if ((shift == 0x1) && (shift_imm == 0x0))
628 /* ASR encodes a shift by 32 bit as 0x0 */
629 if ((shift == 0x2) && (shift_imm == 0x0))
632 /* ROR by 32 bit is actually a RRX */
633 if ((shift == 0x3) && (shift_imm == 0x0))
636 instruction->info.load_store.offset_mode = 1;
637 instruction->info.load_store.offset.reg.Rm = Rm;
638 instruction->info.load_store.offset.reg.shift = shift;
639 instruction->info.load_store.offset.reg.shift_imm = shift_imm;
641 if ((shift_imm == 0x0) && (shift == 0x0)) /* +-<Rm> */
642 snprintf(offset, 32, ", %sr%i", (U) ? "" : "-", Rm);
643 else { /* +-<Rm>, <Shift>, #<shift_imm> */
646 snprintf(offset, 32, ", %sr%i, LSL #0x%x", (U) ? "" : "-", Rm, shift_imm);
649 snprintf(offset, 32, ", %sr%i, LSR #0x%x", (U) ? "" : "-", Rm, shift_imm);
652 snprintf(offset, 32, ", %sr%i, ASR #0x%x", (U) ? "" : "-", Rm, shift_imm);
655 snprintf(offset, 32, ", %sr%i, ROR #0x%x", (U) ? "" : "-", Rm, shift_imm);
658 snprintf(offset, 32, ", %sr%i, RRX", (U) ? "" : "-", Rm);
665 if (W == 0) { /* offset */
666 snprintf(instruction->text,
668 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]",
678 instruction->info.load_store.index_mode = 0;
679 } else {/* pre-indexed */
680 snprintf(instruction->text,
682 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i%s]!",
692 instruction->info.load_store.index_mode = 1;
694 } else {/* post-indexed */
695 snprintf(instruction->text,
697 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i]%s",
707 instruction->info.load_store.index_mode = 2;
713 static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp)
715 unsigned rm = (opcode >> 0) & 0xf;
716 unsigned rd = (opcode >> 12) & 0xf;
717 unsigned rn = (opcode >> 16) & 0xf;
720 switch ((opcode >> 24) & 0x3) {
725 sprintf(cp, "UNDEFINED");
726 return ARM_UNDEFINED_INSTRUCTION;
735 switch ((opcode >> 10) & 0x3) {
751 sprintf(cp, "%cXT%s%s\tr%d, r%d%s",
752 (opcode & (1 << 22)) ? 'U' : 'S',
757 sprintf(cp, "%cXTA%s%s\tr%d, r%d, r%d%s",
758 (opcode & (1 << 22)) ? 'U' : 'S',
765 static int evaluate_p_add_sub(uint32_t opcode, uint32_t address, char *cp)
771 switch ((opcode >> 20) & 0x7) {
794 switch ((opcode >> 5) & 0x7) {
823 sprintf(cp, "%s%s%s\tr%d, r%d, r%d", prefix, op, COND(opcode),
824 (int) (opcode >> 12) & 0xf,
825 (int) (opcode >> 16) & 0xf,
826 (int) (opcode >> 0) & 0xf);
830 /* these opcodes might be used someday */
831 sprintf(cp, "UNDEFINED");
832 return ARM_UNDEFINED_INSTRUCTION;
835 /* ARMv6 and later support "media" instructions (includes SIMD) */
836 static int evaluate_media(uint32_t opcode, uint32_t address,
837 struct arm_instruction *instruction)
839 char *cp = instruction->text;
840 char *mnemonic = NULL;
843 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t",
847 /* parallel add/subtract */
848 if ((opcode & 0x01800000) == 0x00000000) {
849 instruction->type = evaluate_p_add_sub(opcode, address, cp);
854 if ((opcode & 0x01f00020) == 0x00800000) {
856 unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
858 if (opcode & (1 << 6)) {
867 sprintf(cp, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
869 (int) (opcode >> 12) & 0xf,
870 (int) (opcode >> 16) & 0xf,
871 (int) (opcode >> 0) & 0xf,
877 if ((opcode & 0x01a00020) == 0x00a00000) {
879 unsigned imm = (unsigned) (opcode >> 7) & 0x1f;
881 if (opcode & (1 << 6)) {
888 sprintf(cp, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
889 (opcode & (1 << 22)) ? 'U' : 'S',
891 (int) (opcode >> 12) & 0xf,
892 (int) (opcode >> 16) & 0x1f,
893 (int) (opcode >> 0) & 0xf,
899 if ((opcode & 0x018000f0) == 0x00800070) {
900 instruction->type = evaluate_extend(opcode, address, cp);
905 if ((opcode & 0x01f00080) == 0x01000000) {
906 unsigned rn = (opcode >> 12) & 0xf;
909 sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
910 (opcode & (1 << 6)) ? 'S' : 'A',
911 (opcode & (1 << 5)) ? "X" : "",
913 (int) (opcode >> 16) & 0xf,
914 (int) (opcode >> 0) & 0xf,
915 (int) (opcode >> 8) & 0xf,
918 sprintf(cp, "SMU%cD%s%s\tr%d, r%d, r%d",
919 (opcode & (1 << 6)) ? 'S' : 'A',
920 (opcode & (1 << 5)) ? "X" : "",
922 (int) (opcode >> 16) & 0xf,
923 (int) (opcode >> 0) & 0xf,
924 (int) (opcode >> 8) & 0xf);
927 if ((opcode & 0x01f00000) == 0x01400000) {
928 sprintf(cp, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
929 (opcode & (1 << 6)) ? 'S' : 'A',
930 (opcode & (1 << 5)) ? "X" : "",
932 (int) (opcode >> 12) & 0xf,
933 (int) (opcode >> 16) & 0xf,
934 (int) (opcode >> 0) & 0xf,
935 (int) (opcode >> 8) & 0xf);
938 if ((opcode & 0x01f00000) == 0x01500000) {
939 unsigned rn = (opcode >> 12) & 0xf;
941 switch (opcode & 0xc0) {
953 sprintf(cp, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
954 (opcode & (1 << 6)) ? 'S' : 'A',
955 (opcode & (1 << 5)) ? "R" : "",
957 (int) (opcode >> 16) & 0xf,
958 (int) (opcode >> 0) & 0xf,
959 (int) (opcode >> 8) & 0xf,
962 sprintf(cp, "SMMUL%s%s\tr%d, r%d, r%d",
963 (opcode & (1 << 5)) ? "R" : "",
965 (int) (opcode >> 16) & 0xf,
966 (int) (opcode >> 0) & 0xf,
967 (int) (opcode >> 8) & 0xf);
971 /* simple matches against the remaining decode bits */
972 switch (opcode & 0x01f000f0) {
975 /* parallel halfword saturate */
976 sprintf(cp, "%cSAT16%s\tr%d, #%d, r%d",
977 (opcode & (1 << 22)) ? 'U' : 'S',
979 (int) (opcode >> 12) & 0xf,
980 (int) (opcode >> 16) & 0xf,
981 (int) (opcode >> 0) & 0xf);
994 sprintf(cp, "SEL%s\tr%d, r%d, r%d", COND(opcode),
995 (int) (opcode >> 12) & 0xf,
996 (int) (opcode >> 16) & 0xf,
997 (int) (opcode >> 0) & 0xf);
1000 /* unsigned sum of absolute differences */
1001 if (((opcode >> 12) & 0xf) == 0xf)
1002 sprintf(cp, "USAD8%s\tr%d, r%d, r%d", COND(opcode),
1003 (int) (opcode >> 16) & 0xf,
1004 (int) (opcode >> 0) & 0xf,
1005 (int) (opcode >> 8) & 0xf);
1007 sprintf(cp, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode),
1008 (int) (opcode >> 16) & 0xf,
1009 (int) (opcode >> 0) & 0xf,
1010 (int) (opcode >> 8) & 0xf,
1011 (int) (opcode >> 12) & 0xf);
1015 unsigned rm = (opcode >> 0) & 0xf;
1016 unsigned rd = (opcode >> 12) & 0xf;
1018 sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd);
1023 /* these opcodes might be used someday */
1024 sprintf(cp, "UNDEFINED");
1028 /* Miscellaneous load/store instructions */
1029 static int evaluate_misc_load_store(uint32_t opcode,
1030 uint32_t address, struct arm_instruction *instruction)
1032 uint8_t P, U, I, W, L, S, H;
1034 char *operation;/* "LDR" or "STR" */
1035 char *suffix; /* "H", "SB", "SH", "D" */
1039 P = (opcode & 0x01000000) >> 24;
1040 U = (opcode & 0x00800000) >> 23;
1041 I = (opcode & 0x00400000) >> 22;
1042 W = (opcode & 0x00200000) >> 21;
1043 L = (opcode & 0x00100000) >> 20;
1044 S = (opcode & 0x00000040) >> 6;
1045 H = (opcode & 0x00000020) >> 5;
1047 /* target register */
1048 Rd = (opcode & 0xf000) >> 12;
1051 Rn = (opcode & 0xf0000) >> 16;
1053 instruction->info.load_store.Rd = Rd;
1054 instruction->info.load_store.Rn = Rn;
1055 instruction->info.load_store.U = U;
1057 /* determine instruction type and suffix */
1058 if (S) {/* signed */
1062 instruction->type = ARM_LDRSH;
1066 instruction->type = ARM_LDRSB;
1069 } else {/* there are no signed stores, so this is used to encode double-register
1074 instruction->type = ARM_STRD;
1077 instruction->type = ARM_LDRD;
1080 } else {/* unsigned */
1084 instruction->type = ARM_LDRH;
1087 instruction->type = ARM_STRH;
1091 if (I) {/* Immediate offset/index (#+-<offset_8>)*/
1092 uint32_t offset_8 = ((opcode & 0xf00) >> 4) | (opcode & 0xf);
1093 snprintf(offset, 32, "#%s0x%" PRIx32 "", (U) ? "" : "-", offset_8);
1095 instruction->info.load_store.offset_mode = 0;
1096 instruction->info.load_store.offset.offset = offset_8;
1097 } else {/* Register offset/index (+-<Rm>) */
1099 Rm = (opcode & 0xf);
1100 snprintf(offset, 32, "%sr%i", (U) ? "" : "-", Rm);
1102 instruction->info.load_store.offset_mode = 1;
1103 instruction->info.load_store.offset.reg.Rm = Rm;
1104 instruction->info.load_store.offset.reg.shift = 0x0;
1105 instruction->info.load_store.offset.reg.shift_imm = 0x0;
1109 if (W == 0) { /* offset */
1110 snprintf(instruction->text,
1112 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]",
1122 instruction->info.load_store.index_mode = 0;
1123 } else {/* pre-indexed */
1124 snprintf(instruction->text,
1126 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i, %s]!",
1136 instruction->info.load_store.index_mode = 1;
1138 } else {/* post-indexed */
1139 snprintf(instruction->text,
1141 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, [r%i], %s",
1151 instruction->info.load_store.index_mode = 2;
1157 /* Load/store multiples instructions */
1158 static int evaluate_ldm_stm(uint32_t opcode,
1159 uint32_t address, struct arm_instruction *instruction)
1161 uint8_t P, U, S, W, L, Rn;
1162 uint32_t register_list;
1163 char *addressing_mode;
1170 P = (opcode & 0x01000000) >> 24;
1171 U = (opcode & 0x00800000) >> 23;
1172 S = (opcode & 0x00400000) >> 22;
1173 W = (opcode & 0x00200000) >> 21;
1174 L = (opcode & 0x00100000) >> 20;
1175 register_list = (opcode & 0xffff);
1176 Rn = (opcode & 0xf0000) >> 16;
1178 instruction->info.load_store_multiple.Rn = Rn;
1179 instruction->info.load_store_multiple.register_list = register_list;
1180 instruction->info.load_store_multiple.S = S;
1181 instruction->info.load_store_multiple.W = W;
1184 instruction->type = ARM_LDM;
1187 instruction->type = ARM_STM;
1193 instruction->info.load_store_multiple.addressing_mode = 1;
1194 addressing_mode = "IB";
1196 instruction->info.load_store_multiple.addressing_mode = 3;
1197 addressing_mode = "DB";
1201 instruction->info.load_store_multiple.addressing_mode = 0;
1202 /* "IA" is the default in UAL syntax */
1203 addressing_mode = "";
1205 instruction->info.load_store_multiple.addressing_mode = 2;
1206 addressing_mode = "DA";
1210 reg_list_p = reg_list;
1211 for (i = 0; i <= 15; i++) {
1212 if ((register_list >> i) & 1) {
1215 reg_list_p += snprintf(reg_list_p,
1216 (reg_list + 69 - reg_list_p),
1220 reg_list_p += snprintf(reg_list_p,
1221 (reg_list + 69 - reg_list_p),
1227 snprintf(instruction->text, 128,
1228 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32
1229 "\t%s%s%s r%i%s, {%s}%s",
1231 mnemonic, addressing_mode, COND(opcode),
1232 Rn, (W) ? "!" : "", reg_list, (S) ? "^" : "");
1237 /* Multiplies, extra load/stores */
1238 static int evaluate_mul_and_extra_ld_st(uint32_t opcode,
1239 uint32_t address, struct arm_instruction *instruction)
1241 /* Multiply (accumulate) (long) and Swap/swap byte */
1242 if ((opcode & 0x000000f0) == 0x00000090) {
1243 /* Multiply (accumulate) */
1244 if ((opcode & 0x0f800000) == 0x00000000) {
1245 uint8_t Rm, Rs, Rn, Rd, S;
1247 Rs = (opcode & 0xf00) >> 8;
1248 Rn = (opcode & 0xf000) >> 12;
1249 Rd = (opcode & 0xf0000) >> 16;
1250 S = (opcode & 0x00100000) >> 20;
1252 /* examine A bit (accumulate) */
1253 if (opcode & 0x00200000) {
1254 instruction->type = ARM_MLA;
1255 snprintf(instruction->text,
1257 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMLA%s%s r%i, r%i, r%i, r%i",
1267 instruction->type = ARM_MUL;
1268 snprintf(instruction->text,
1270 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMUL%s%s r%i, r%i, r%i",
1283 /* Multiply (accumulate) long */
1284 if ((opcode & 0x0f800000) == 0x00800000) {
1285 char *mnemonic = NULL;
1286 uint8_t Rm, Rs, RdHi, RdLow, S;
1288 Rs = (opcode & 0xf00) >> 8;
1289 RdHi = (opcode & 0xf000) >> 12;
1290 RdLow = (opcode & 0xf0000) >> 16;
1291 S = (opcode & 0x00100000) >> 20;
1293 switch ((opcode & 0x00600000) >> 21) {
1295 instruction->type = ARM_UMULL;
1299 instruction->type = ARM_UMLAL;
1303 instruction->type = ARM_SMULL;
1307 instruction->type = ARM_SMLAL;
1312 snprintf(instruction->text,
1314 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, r%i, r%i",
1328 /* Swap/swap byte */
1329 if ((opcode & 0x0f800000) == 0x01000000) {
1332 Rd = (opcode & 0xf000) >> 12;
1333 Rn = (opcode & 0xf0000) >> 16;
1335 /* examine B flag */
1336 instruction->type = (opcode & 0x00400000) ? ARM_SWPB : ARM_SWP;
1338 snprintf(instruction->text,
1340 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, [r%i]",
1343 (opcode & 0x00400000) ? "SWPB" : "SWP",
1353 return evaluate_misc_load_store(opcode, address, instruction);
1356 static int evaluate_mrs_msr(uint32_t opcode,
1357 uint32_t address, struct arm_instruction *instruction)
1359 int R = (opcode & 0x00400000) >> 22;
1360 char *PSR = (R) ? "SPSR" : "CPSR";
1362 /* Move register to status register (MSR) */
1363 if (opcode & 0x00200000) {
1364 instruction->type = ARM_MSR;
1366 /* immediate variant */
1367 if (opcode & 0x02000000) {
1368 uint8_t immediate = (opcode & 0xff);
1369 uint8_t rotate = (opcode & 0xf00);
1371 snprintf(instruction->text,
1373 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32,
1378 (opcode & 0x10000) ? "c" : "",
1379 (opcode & 0x20000) ? "x" : "",
1380 (opcode & 0x40000) ? "s" : "",
1381 (opcode & 0x80000) ? "f" : "",
1382 ror(immediate, (rotate * 2))
1384 } else {/* register variant */
1385 uint8_t Rm = opcode & 0xf;
1386 snprintf(instruction->text,
1388 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMSR%s %s_%s%s%s%s, r%i",
1393 (opcode & 0x10000) ? "c" : "",
1394 (opcode & 0x20000) ? "x" : "",
1395 (opcode & 0x40000) ? "s" : "",
1396 (opcode & 0x80000) ? "f" : "",
1401 } else {/* Move status register to register (MRS) */
1404 instruction->type = ARM_MRS;
1405 Rd = (opcode & 0x0000f000) >> 12;
1407 snprintf(instruction->text,
1409 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMRS%s r%i, %s",
1420 /* Miscellaneous instructions */
1421 static int evaluate_misc_instr(uint32_t opcode,
1422 uint32_t address, struct arm_instruction *instruction)
1425 if ((opcode & 0x000000f0) == 0x00000000)
1426 evaluate_mrs_msr(opcode, address, instruction);
1429 if ((opcode & 0x006000f0) == 0x00200010) {
1431 instruction->type = ARM_BX;
1434 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBX%s r%i",
1435 address, opcode, COND(opcode), Rm);
1437 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1438 instruction->info.b_bl_bx_blx.target_address = -1;
1441 /* BXJ - "Jazelle" support (ARMv5-J) */
1442 if ((opcode & 0x006000f0) == 0x00200020) {
1444 instruction->type = ARM_BX;
1447 snprintf(instruction->text, 128,
1448 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBXJ%s r%i",
1449 address, opcode, COND(opcode), Rm);
1451 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1452 instruction->info.b_bl_bx_blx.target_address = -1;
1456 if ((opcode & 0x006000f0) == 0x00600010) {
1458 instruction->type = ARM_CLZ;
1460 Rd = (opcode & 0xf000) >> 12;
1462 snprintf(instruction->text,
1464 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tCLZ%s r%i, r%i",
1473 if ((opcode & 0x006000f0) == 0x00200030) {
1475 instruction->type = ARM_BLX;
1478 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tBLX%s r%i",
1479 address, opcode, COND(opcode), Rm);
1481 instruction->info.b_bl_bx_blx.reg_operand = Rm;
1482 instruction->info.b_bl_bx_blx.target_address = -1;
1485 /* Enhanced DSP add/subtracts */
1486 if ((opcode & 0x0000000f0) == 0x00000050) {
1488 char *mnemonic = NULL;
1490 Rd = (opcode & 0xf000) >> 12;
1491 Rn = (opcode & 0xf0000) >> 16;
1493 switch ((opcode & 0x00600000) >> 21) {
1495 instruction->type = ARM_QADD;
1499 instruction->type = ARM_QSUB;
1503 instruction->type = ARM_QDADD;
1507 instruction->type = ARM_QDSUB;
1512 snprintf(instruction->text,
1514 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, r%i, r%i",
1524 /* exception return */
1525 if ((opcode & 0x0000000f0) == 0x00000060) {
1526 if (((opcode & 0x600000) >> 21) == 3)
1527 instruction->type = ARM_ERET;
1528 snprintf(instruction->text,
1530 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tERET",
1535 /* exception generate instructions */
1536 if ((opcode & 0x0000000f0) == 0x00000070) {
1537 uint32_t immediate = 0;
1538 char *mnemonic = NULL;
1540 switch ((opcode & 0x600000) >> 21) {
1542 instruction->type = ARM_BKPT;
1544 immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
1547 instruction->type = ARM_HVC;
1549 immediate = ((opcode & 0x000fff00) >> 4) | (opcode & 0xf);
1552 instruction->type = ARM_SMC;
1554 immediate = (opcode & 0xf);
1558 snprintf(instruction->text,
1560 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s 0x%4.4" PRIx32 "",
1567 /* Enhanced DSP multiplies */
1568 if ((opcode & 0x000000090) == 0x00000080) {
1569 int x = (opcode & 0x20) >> 5;
1570 int y = (opcode & 0x40) >> 6;
1573 if ((opcode & 0x00600000) == 0x00000000) {
1574 uint8_t Rd, Rm, Rs, Rn;
1575 instruction->type = ARM_SMLAxy;
1576 Rd = (opcode & 0xf0000) >> 16;
1577 Rm = (opcode & 0xf);
1578 Rs = (opcode & 0xf00) >> 8;
1579 Rn = (opcode & 0xf000) >> 12;
1581 snprintf(instruction->text,
1583 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1596 if ((opcode & 0x00600000) == 0x00400000) {
1597 uint8_t RdLow, RdHi, Rm, Rs;
1598 instruction->type = ARM_SMLAxy;
1599 RdHi = (opcode & 0xf0000) >> 16;
1600 RdLow = (opcode & 0xf000) >> 12;
1601 Rm = (opcode & 0xf);
1602 Rs = (opcode & 0xf00) >> 8;
1604 snprintf(instruction->text,
1606 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1619 if (((opcode & 0x00600000) == 0x00200000) && (x == 0)) {
1620 uint8_t Rd, Rm, Rs, Rn;
1621 instruction->type = ARM_SMLAWy;
1622 Rd = (opcode & 0xf0000) >> 16;
1623 Rm = (opcode & 0xf);
1624 Rs = (opcode & 0xf00) >> 8;
1625 Rn = (opcode & 0xf000) >> 12;
1627 snprintf(instruction->text,
1629 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMLAW%s%s r%i, r%i, r%i, r%i",
1641 if ((opcode & 0x00600000) == 0x00600000) {
1643 instruction->type = ARM_SMULxy;
1644 Rd = (opcode & 0xf0000) >> 16;
1645 Rm = (opcode & 0xf);
1646 Rs = (opcode & 0xf00) >> 8;
1648 snprintf(instruction->text,
1650 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s%s r%i, r%i, r%i",
1662 if (((opcode & 0x00600000) == 0x00200000) && (x == 1)) {
1664 instruction->type = ARM_SMULWy;
1665 Rd = (opcode & 0xf0000) >> 16;
1666 Rm = (opcode & 0xf);
1667 Rs = (opcode & 0xf00) >> 8;
1669 snprintf(instruction->text,
1671 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tSMULW%s%s r%i, r%i, r%i",
1685 static int evaluate_mov_imm(uint32_t opcode,
1686 uint32_t address, struct arm_instruction *instruction)
1692 Rd = (opcode & 0xf000) >> 12;
1693 T = opcode & 0x00400000;
1694 immediate = (opcode & 0xf0000) >> 4 | (opcode & 0xfff);
1696 instruction->type = ARM_MOV;
1697 instruction->info.data_proc.Rd = Rd;
1699 snprintf(instruction->text,
1701 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tMOV%s%s r%i, #0x%" PRIx16,
1712 static int evaluate_data_proc(uint32_t opcode,
1713 uint32_t address, struct arm_instruction *instruction)
1715 uint8_t I, op, S, Rn, Rd;
1716 char *mnemonic = NULL;
1717 char shifter_operand[32];
1719 I = (opcode & 0x02000000) >> 25;
1720 op = (opcode & 0x01e00000) >> 21;
1721 S = (opcode & 0x00100000) >> 20;
1723 Rd = (opcode & 0xf000) >> 12;
1724 Rn = (opcode & 0xf0000) >> 16;
1726 instruction->info.data_proc.Rd = Rd;
1727 instruction->info.data_proc.Rn = Rn;
1728 instruction->info.data_proc.S = S;
1732 instruction->type = ARM_AND;
1736 instruction->type = ARM_EOR;
1740 instruction->type = ARM_SUB;
1744 instruction->type = ARM_RSB;
1748 instruction->type = ARM_ADD;
1752 instruction->type = ARM_ADC;
1756 instruction->type = ARM_SBC;
1760 instruction->type = ARM_RSC;
1764 instruction->type = ARM_TST;
1768 instruction->type = ARM_TEQ;
1772 instruction->type = ARM_CMP;
1776 instruction->type = ARM_CMN;
1780 instruction->type = ARM_ORR;
1784 instruction->type = ARM_MOV;
1788 instruction->type = ARM_BIC;
1792 instruction->type = ARM_MVN;
1797 if (I) {/* immediate shifter operand (#<immediate>)*/
1798 uint8_t immed_8 = opcode & 0xff;
1799 uint8_t rotate_imm = (opcode & 0xf00) >> 8;
1802 immediate = ror(immed_8, rotate_imm * 2);
1804 snprintf(shifter_operand, 32, "#0x%" PRIx32 "", immediate);
1806 instruction->info.data_proc.variant = 0;
1807 instruction->info.data_proc.shifter_operand.immediate.immediate = immediate;
1808 } else {/* register-based shifter operand */
1810 shift = (opcode & 0x60) >> 5;
1811 Rm = (opcode & 0xf);
1813 if ((opcode & 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1814 *#<shift_immediate>") */
1816 shift_imm = (opcode & 0xf80) >> 7;
1818 instruction->info.data_proc.variant = 1;
1819 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
1820 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm =
1822 instruction->info.data_proc.shifter_operand.immediate_shift.shift = shift;
1824 /* LSR encodes a shift by 32 bit as 0x0 */
1825 if ((shift == 0x1) && (shift_imm == 0x0))
1828 /* ASR encodes a shift by 32 bit as 0x0 */
1829 if ((shift == 0x2) && (shift_imm == 0x0))
1832 /* ROR by 32 bit is actually a RRX */
1833 if ((shift == 0x3) && (shift_imm == 0x0))
1836 if ((shift_imm == 0x0) && (shift == 0x0))
1837 snprintf(shifter_operand, 32, "r%i", Rm);
1839 if (shift == 0x0) /* LSL */
1840 snprintf(shifter_operand,
1845 else if (shift == 0x1) /* LSR */
1846 snprintf(shifter_operand,
1851 else if (shift == 0x2) /* ASR */
1852 snprintf(shifter_operand,
1857 else if (shift == 0x3) /* ROR */
1858 snprintf(shifter_operand,
1863 else if (shift == 0x4) /* RRX */
1864 snprintf(shifter_operand, 32, "r%i, RRX", Rm);
1866 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1867 uint8_t Rs = (opcode & 0xf00) >> 8;
1869 instruction->info.data_proc.variant = 2;
1870 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rm;
1871 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rs;
1872 instruction->info.data_proc.shifter_operand.register_shift.shift = shift;
1874 if (shift == 0x0) /* LSL */
1875 snprintf(shifter_operand, 32, "r%i, LSL r%i", Rm, Rs);
1876 else if (shift == 0x1) /* LSR */
1877 snprintf(shifter_operand, 32, "r%i, LSR r%i", Rm, Rs);
1878 else if (shift == 0x2) /* ASR */
1879 snprintf(shifter_operand, 32, "r%i, ASR r%i", Rm, Rs);
1880 else if (shift == 0x3) /* ROR */
1881 snprintf(shifter_operand, 32, "r%i, ROR r%i", Rm, Rs);
1885 if ((op < 0x8) || (op == 0xc) || (op == 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1886 *<shifter_operand> */
1887 snprintf(instruction->text,
1889 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, r%i, %s",
1898 } else if ((op == 0xd) || (op == 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1899 *<shifter_operand> */
1900 if (opcode == 0xe1a00000) /* print MOV r0,r0 as NOP */
1901 snprintf(instruction->text,
1903 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tNOP",
1907 snprintf(instruction->text,
1909 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s%s r%i, %s",
1917 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1918 snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\t%s%s r%i, %s",
1919 address, opcode, mnemonic, COND(opcode),
1920 Rn, shifter_operand);
1926 int arm_evaluate_opcode(uint32_t opcode, uint32_t address,
1927 struct arm_instruction *instruction)
1929 /* clear fields, to avoid confusion */
1930 memset(instruction, 0, sizeof(struct arm_instruction));
1931 instruction->opcode = opcode;
1932 instruction->instruction_size = 4;
1934 /* catch opcodes with condition field [31:28] = b1111 */
1935 if ((opcode & 0xf0000000) == 0xf0000000) {
1936 /* Undefined instruction (or ARMv5E cache preload PLD) */
1937 if ((opcode & 0x08000000) == 0x00000000)
1938 return evaluate_pld(opcode, address, instruction);
1940 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1941 if ((opcode & 0x0e000000) == 0x08000000)
1942 return evaluate_srs(opcode, address, instruction);
1944 /* Branch and branch with link and change to Thumb */
1945 if ((opcode & 0x0e000000) == 0x0a000000)
1946 return evaluate_blx_imm(opcode, address, instruction);
1948 /* Extended coprocessor opcode space (ARMv5 and higher)
1949 * Coprocessor load/store and double register transfers */
1950 if ((opcode & 0x0e000000) == 0x0c000000)
1951 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
1953 /* Coprocessor data processing */
1954 if ((opcode & 0x0f000100) == 0x0c000000)
1955 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1957 /* Coprocessor register transfers */
1958 if ((opcode & 0x0f000010) == 0x0c000010)
1959 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
1961 /* Undefined instruction */
1962 if ((opcode & 0x0f000000) == 0x0f000000) {
1963 instruction->type = ARM_UNDEFINED_INSTRUCTION;
1964 snprintf(instruction->text,
1966 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEFINED INSTRUCTION",
1973 /* catch opcodes with [27:25] = b000 */
1974 if ((opcode & 0x0e000000) == 0x00000000) {
1975 /* Multiplies, extra load/stores */
1976 if ((opcode & 0x00000090) == 0x00000090)
1977 return evaluate_mul_and_extra_ld_st(opcode, address, instruction);
1979 /* Miscellaneous instructions */
1980 if ((opcode & 0x0f900000) == 0x01000000)
1981 return evaluate_misc_instr(opcode, address, instruction);
1983 return evaluate_data_proc(opcode, address, instruction);
1986 /* catch opcodes with [27:25] = b001 */
1987 if ((opcode & 0x0e000000) == 0x02000000) {
1988 /* 16-bit immediate load */
1989 if ((opcode & 0x0fb00000) == 0x03000000)
1990 return evaluate_mov_imm(opcode, address, instruction);
1992 /* Move immediate to status register */
1993 if ((opcode & 0x0fb00000) == 0x03200000)
1994 return evaluate_mrs_msr(opcode, address, instruction);
1996 return evaluate_data_proc(opcode, address, instruction);
2000 /* catch opcodes with [27:25] = b010 */
2001 if ((opcode & 0x0e000000) == 0x04000000) {
2002 /* Load/store immediate offset */
2003 return evaluate_load_store(opcode, address, instruction);
2006 /* catch opcodes with [27:25] = b011 */
2007 if ((opcode & 0x0e000000) == 0x06000000) {
2008 /* Load/store register offset */
2009 if ((opcode & 0x00000010) == 0x00000000)
2010 return evaluate_load_store(opcode, address, instruction);
2012 /* Architecturally Undefined instruction
2013 * ... don't expect these to ever be used
2015 if ((opcode & 0x07f000f0) == 0x07f000f0) {
2016 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2017 snprintf(instruction->text, 128,
2018 "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 "\tUNDEF",
2023 /* "media" instructions */
2024 return evaluate_media(opcode, address, instruction);
2027 /* catch opcodes with [27:25] = b100 */
2028 if ((opcode & 0x0e000000) == 0x08000000) {
2029 /* Load/store multiple */
2030 return evaluate_ldm_stm(opcode, address, instruction);
2033 /* catch opcodes with [27:25] = b101 */
2034 if ((opcode & 0x0e000000) == 0x0a000000) {
2035 /* Branch and branch with link */
2036 return evaluate_b_bl(opcode, address, instruction);
2039 /* catch opcodes with [27:25] = b110 */
2040 if ((opcode & 0x0e000000) == 0x0c000000) {
2041 /* Coprocessor load/store and double register transfers */
2042 return evaluate_ldc_stc_mcrr_mrrc(opcode, address, instruction);
2045 /* catch opcodes with [27:25] = b111 */
2046 if ((opcode & 0x0e000000) == 0x0e000000) {
2047 /* Software interrupt */
2048 if ((opcode & 0x0f000000) == 0x0f000000)
2049 return evaluate_swi(opcode, address, instruction);
2051 /* Coprocessor data processing */
2052 if ((opcode & 0x0f000010) == 0x0e000000)
2053 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
2055 /* Coprocessor register transfers */
2056 if ((opcode & 0x0f000010) == 0x0e000010)
2057 return evaluate_cdp_mcr_mrc(opcode, address, instruction);
2060 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
2065 static int evaluate_b_bl_blx_thumb(uint16_t opcode,
2066 uint32_t address, struct arm_instruction *instruction)
2068 uint32_t offset = opcode & 0x7ff;
2069 uint32_t opc = (opcode >> 11) & 0x3;
2070 uint32_t target_address;
2071 char *mnemonic = NULL;
2073 /* sign extend 11-bit offset */
2074 if (((opc == 0) || (opc == 2)) && (offset & 0x00000400))
2075 offset = 0xfffff800 | offset;
2077 target_address = address + 4 + (offset << 1);
2080 /* unconditional branch */
2082 instruction->type = ARM_B;
2087 instruction->type = ARM_BLX;
2089 target_address &= 0xfffffffc;
2093 instruction->type = ARM_UNKNOWN_INSTRUCTION;
2094 mnemonic = "prefix";
2095 target_address = offset << 12;
2099 instruction->type = ARM_BL;
2104 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
2105 * these are effectively 32-bit instructions even in Thumb1. For
2106 * disassembly, it's simplest to always use the Thumb2 decoder.
2108 * But some cores will evidently handle them as two instructions,
2109 * where exceptions may occur between the two. The ETMv3.2+ ID
2110 * register has a bit which exposes this behavior.
2113 snprintf(instruction->text, 128,
2114 "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%#8.8" PRIx32,
2115 address, opcode, mnemonic, target_address);
2117 instruction->info.b_bl_bx_blx.reg_operand = -1;
2118 instruction->info.b_bl_bx_blx.target_address = target_address;
2123 static int evaluate_add_sub_thumb(uint16_t opcode,
2124 uint32_t address, struct arm_instruction *instruction)
2126 uint8_t Rd = (opcode >> 0) & 0x7;
2127 uint8_t Rn = (opcode >> 3) & 0x7;
2128 uint8_t Rm_imm = (opcode >> 6) & 0x7;
2129 uint32_t opc = opcode & (1 << 9);
2130 uint32_t reg_imm = opcode & (1 << 10);
2134 instruction->type = ARM_SUB;
2137 /* REVISIT: if reg_imm == 0, display as "MOVS" */
2138 instruction->type = ARM_ADD;
2142 instruction->info.data_proc.Rd = Rd;
2143 instruction->info.data_proc.Rn = Rn;
2144 instruction->info.data_proc.S = 1;
2147 instruction->info.data_proc.variant = 0;/*immediate*/
2148 instruction->info.data_proc.shifter_operand.immediate.immediate = Rm_imm;
2149 snprintf(instruction->text, 128,
2150 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%d",
2151 address, opcode, mnemonic, Rd, Rn, Rm_imm);
2153 instruction->info.data_proc.variant = 1;/*immediate shift*/
2154 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm_imm;
2155 snprintf(instruction->text, 128,
2156 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, r%i",
2157 address, opcode, mnemonic, Rd, Rn, Rm_imm);
2163 static int evaluate_shift_imm_thumb(uint16_t opcode,
2164 uint32_t address, struct arm_instruction *instruction)
2166 uint8_t Rd = (opcode >> 0) & 0x7;
2167 uint8_t Rm = (opcode >> 3) & 0x7;
2168 uint8_t imm = (opcode >> 6) & 0x1f;
2169 uint8_t opc = (opcode >> 11) & 0x3;
2170 char *mnemonic = NULL;
2174 instruction->type = ARM_MOV;
2176 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 0;
2179 instruction->type = ARM_MOV;
2181 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 1;
2184 instruction->type = ARM_MOV;
2186 instruction->info.data_proc.shifter_operand.immediate_shift.shift = 2;
2190 if ((imm == 0) && (opc != 0))
2193 instruction->info.data_proc.Rd = Rd;
2194 instruction->info.data_proc.Rn = -1;
2195 instruction->info.data_proc.S = 1;
2197 instruction->info.data_proc.variant = 1;/*immediate_shift*/
2198 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
2199 instruction->info.data_proc.shifter_operand.immediate_shift.shift_imm = imm;
2201 snprintf(instruction->text, 128,
2202 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2203 address, opcode, mnemonic, Rd, Rm, imm);
2208 static int evaluate_data_proc_imm_thumb(uint16_t opcode,
2209 uint32_t address, struct arm_instruction *instruction)
2211 uint8_t imm = opcode & 0xff;
2212 uint8_t Rd = (opcode >> 8) & 0x7;
2213 uint32_t opc = (opcode >> 11) & 0x3;
2214 char *mnemonic = NULL;
2216 instruction->info.data_proc.Rd = Rd;
2217 instruction->info.data_proc.Rn = Rd;
2218 instruction->info.data_proc.S = 1;
2219 instruction->info.data_proc.variant = 0;/*immediate*/
2220 instruction->info.data_proc.shifter_operand.immediate.immediate = imm;
2224 instruction->type = ARM_MOV;
2226 instruction->info.data_proc.Rn = -1;
2229 instruction->type = ARM_CMP;
2231 instruction->info.data_proc.Rd = -1;
2234 instruction->type = ARM_ADD;
2238 instruction->type = ARM_SUB;
2243 snprintf(instruction->text, 128,
2244 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, #%#2.2x",
2245 address, opcode, mnemonic, Rd, imm);
2250 static int evaluate_data_proc_thumb(uint16_t opcode,
2251 uint32_t address, struct arm_instruction *instruction)
2253 uint8_t high_reg, op, Rm, Rd, H1, H2;
2254 char *mnemonic = NULL;
2257 high_reg = (opcode & 0x0400) >> 10;
2258 op = (opcode & 0x03C0) >> 6;
2260 Rd = (opcode & 0x0007);
2261 Rm = (opcode & 0x0038) >> 3;
2262 H1 = (opcode & 0x0080) >> 7;
2263 H2 = (opcode & 0x0040) >> 6;
2265 instruction->info.data_proc.Rd = Rd;
2266 instruction->info.data_proc.Rn = Rd;
2267 instruction->info.data_proc.S = (!high_reg || (instruction->type == ARM_CMP));
2268 instruction->info.data_proc.variant = 1 /*immediate shift*/;
2269 instruction->info.data_proc.shifter_operand.immediate_shift.Rm = Rm;
2278 instruction->type = ARM_ADD;
2282 instruction->type = ARM_CMP;
2286 instruction->type = ARM_MOV;
2292 if ((opcode & 0x7) == 0x0) {
2293 instruction->info.b_bl_bx_blx.reg_operand = Rm;
2295 instruction->type = ARM_BLX;
2296 snprintf(instruction->text, 128,
2298 " 0x%4.4x \tBLX\tr%i",
2299 address, opcode, Rm);
2301 instruction->type = ARM_BX;
2302 snprintf(instruction->text, 128,
2304 " 0x%4.4x \tBX\tr%i",
2305 address, opcode, Rm);
2308 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2309 snprintf(instruction->text, 128,
2312 "UNDEFINED INSTRUCTION",
2320 instruction->type = ARM_AND;
2324 instruction->type = ARM_EOR;
2328 instruction->type = ARM_MOV;
2330 instruction->info.data_proc.variant = 2 /*register shift*/;
2331 instruction->info.data_proc.shifter_operand.register_shift.shift = 0;
2332 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
2333 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
2336 instruction->type = ARM_MOV;
2338 instruction->info.data_proc.variant = 2 /*register shift*/;
2339 instruction->info.data_proc.shifter_operand.register_shift.shift = 1;
2340 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
2341 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
2344 instruction->type = ARM_MOV;
2346 instruction->info.data_proc.variant = 2 /*register shift*/;
2347 instruction->info.data_proc.shifter_operand.register_shift.shift = 2;
2348 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
2349 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
2352 instruction->type = ARM_ADC;
2356 instruction->type = ARM_SBC;
2360 instruction->type = ARM_MOV;
2362 instruction->info.data_proc.variant = 2 /*register shift*/;
2363 instruction->info.data_proc.shifter_operand.register_shift.shift = 3;
2364 instruction->info.data_proc.shifter_operand.register_shift.Rm = Rd;
2365 instruction->info.data_proc.shifter_operand.register_shift.Rs = Rm;
2368 instruction->type = ARM_TST;
2372 instruction->type = ARM_RSB;
2374 instruction->info.data_proc.variant = 0 /*immediate*/;
2375 instruction->info.data_proc.shifter_operand.immediate.immediate = 0;
2376 instruction->info.data_proc.Rn = Rm;
2379 instruction->type = ARM_CMP;
2383 instruction->type = ARM_CMN;
2387 instruction->type = ARM_ORR;
2391 instruction->type = ARM_MUL;
2395 instruction->type = ARM_BIC;
2399 instruction->type = ARM_MVN;
2406 snprintf(instruction->text, 128,
2407 "0x%8.8" PRIx32 " 0x%4.4x \tNOP\t\t\t"
2409 address, opcode, mnemonic, Rd, Rm);
2411 snprintf(instruction->text, 128,
2412 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, r%i",
2413 address, opcode, mnemonic, Rd, Rm);
2418 /* PC-relative data addressing is word-aligned even with Thumb */
2419 static inline uint32_t thumb_alignpc4(uint32_t addr)
2421 return (addr + 4) & ~3;
2424 static int evaluate_load_literal_thumb(uint16_t opcode,
2425 uint32_t address, struct arm_instruction *instruction)
2428 uint8_t Rd = (opcode >> 8) & 0x7;
2430 instruction->type = ARM_LDR;
2431 immediate = opcode & 0x000000ff;
2434 instruction->info.load_store.Rd = Rd;
2435 instruction->info.load_store.Rn = 15 /*PC*/;
2436 instruction->info.load_store.index_mode = 0; /*offset*/
2437 instruction->info.load_store.offset_mode = 0; /*immediate*/
2438 instruction->info.load_store.offset.offset = immediate;
2440 snprintf(instruction->text, 128,
2441 "0x%8.8" PRIx32 " 0x%4.4x \t"
2442 "LDR\tr%i, [pc, #%#" PRIx32 "]\t; %#8.8" PRIx32,
2443 address, opcode, Rd, immediate,
2444 thumb_alignpc4(address) + immediate);
2449 static int evaluate_load_store_reg_thumb(uint16_t opcode,
2450 uint32_t address, struct arm_instruction *instruction)
2452 uint8_t Rd = (opcode >> 0) & 0x7;
2453 uint8_t Rn = (opcode >> 3) & 0x7;
2454 uint8_t Rm = (opcode >> 6) & 0x7;
2455 uint8_t opc = (opcode >> 9) & 0x7;
2456 char *mnemonic = NULL;
2460 instruction->type = ARM_STR;
2464 instruction->type = ARM_STRH;
2468 instruction->type = ARM_STRB;
2472 instruction->type = ARM_LDRSB;
2476 instruction->type = ARM_LDR;
2480 instruction->type = ARM_LDRH;
2484 instruction->type = ARM_LDRB;
2488 instruction->type = ARM_LDRSH;
2493 snprintf(instruction->text, 128,
2494 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2495 address, opcode, mnemonic, Rd, Rn, Rm);
2497 instruction->info.load_store.Rd = Rd;
2498 instruction->info.load_store.Rn = Rn;
2499 instruction->info.load_store.index_mode = 0; /*offset*/
2500 instruction->info.load_store.offset_mode = 1; /*register*/
2501 instruction->info.load_store.offset.reg.Rm = Rm;
2506 static int evaluate_load_store_imm_thumb(uint16_t opcode,
2507 uint32_t address, struct arm_instruction *instruction)
2509 uint32_t offset = (opcode >> 6) & 0x1f;
2510 uint8_t Rd = (opcode >> 0) & 0x7;
2511 uint8_t Rn = (opcode >> 3) & 0x7;
2512 uint32_t L = opcode & (1 << 11);
2513 uint32_t B = opcode & (1 << 12);
2519 instruction->type = ARM_LDR;
2522 instruction->type = ARM_STR;
2526 if ((opcode&0xF000) == 0x8000) {
2534 snprintf(instruction->text, 128,
2535 "0x%8.8" PRIx32 " 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32 "]",
2536 address, opcode, mnemonic, suffix, Rd, Rn, offset << shift);
2538 instruction->info.load_store.Rd = Rd;
2539 instruction->info.load_store.Rn = Rn;
2540 instruction->info.load_store.index_mode = 0; /*offset*/
2541 instruction->info.load_store.offset_mode = 0; /*immediate*/
2542 instruction->info.load_store.offset.offset = offset << shift;
2547 static int evaluate_load_store_stack_thumb(uint16_t opcode,
2548 uint32_t address, struct arm_instruction *instruction)
2550 uint32_t offset = opcode & 0xff;
2551 uint8_t Rd = (opcode >> 8) & 0x7;
2552 uint32_t L = opcode & (1 << 11);
2556 instruction->type = ARM_LDR;
2559 instruction->type = ARM_STR;
2563 snprintf(instruction->text, 128,
2564 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32 "]",
2565 address, opcode, mnemonic, Rd, offset*4);
2567 instruction->info.load_store.Rd = Rd;
2568 instruction->info.load_store.Rn = 13 /*SP*/;
2569 instruction->info.load_store.index_mode = 0; /*offset*/
2570 instruction->info.load_store.offset_mode = 0; /*immediate*/
2571 instruction->info.load_store.offset.offset = offset*4;
2576 static int evaluate_add_sp_pc_thumb(uint16_t opcode,
2577 uint32_t address, struct arm_instruction *instruction)
2579 uint32_t imm = opcode & 0xff;
2580 uint8_t Rd = (opcode >> 8) & 0x7;
2582 uint32_t SP = opcode & (1 << 11);
2583 const char *reg_name;
2585 instruction->type = ARM_ADD;
2595 snprintf(instruction->text, 128,
2596 "0x%8.8" PRIx32 " 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32,
2597 address, opcode, Rd, reg_name, imm * 4);
2599 instruction->info.data_proc.variant = 0 /* immediate */;
2600 instruction->info.data_proc.Rd = Rd;
2601 instruction->info.data_proc.Rn = Rn;
2602 instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
2607 static int evaluate_adjust_stack_thumb(uint16_t opcode,
2608 uint32_t address, struct arm_instruction *instruction)
2610 uint32_t imm = opcode & 0x7f;
2611 uint8_t opc = opcode & (1 << 7);
2616 instruction->type = ARM_SUB;
2619 instruction->type = ARM_ADD;
2623 snprintf(instruction->text, 128,
2624 "0x%8.8" PRIx32 " 0x%4.4x \t%s\tSP, #%#" PRIx32,
2625 address, opcode, mnemonic, imm*4);
2627 instruction->info.data_proc.variant = 0 /* immediate */;
2628 instruction->info.data_proc.Rd = 13 /*SP*/;
2629 instruction->info.data_proc.Rn = 13 /*SP*/;
2630 instruction->info.data_proc.shifter_operand.immediate.immediate = imm*4;
2635 static int evaluate_breakpoint_thumb(uint16_t opcode,
2636 uint32_t address, struct arm_instruction *instruction)
2638 uint32_t imm = opcode & 0xff;
2640 instruction->type = ARM_BKPT;
2642 snprintf(instruction->text, 128,
2643 "0x%8.8" PRIx32 " 0x%4.4x \tBKPT\t%#2.2" PRIx32 "",
2644 address, opcode, imm);
2649 static int evaluate_load_store_multiple_thumb(uint16_t opcode,
2650 uint32_t address, struct arm_instruction *instruction)
2652 uint32_t reg_list = opcode & 0xff;
2653 uint32_t L = opcode & (1 << 11);
2654 uint32_t R = opcode & (1 << 8);
2655 uint8_t Rn = (opcode >> 8) & 7;
2656 uint8_t addr_mode = 0 /* IA */;
2660 char ptr_name[7] = "";
2663 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2664 * The STMIA and LDMIA opcodes are used for other instructions.
2667 if ((opcode & 0xf000) == 0xc000) { /* generic load/store multiple */
2671 instruction->type = ARM_LDM;
2673 if (opcode & (1 << Rn))
2676 instruction->type = ARM_STM;
2679 snprintf(ptr_name, sizeof(ptr_name), "r%i%s, ", Rn, wback);
2680 } else {/* push/pop */
2683 instruction->type = ARM_LDM;
2686 reg_list |= (1 << 15) /*PC*/;
2688 instruction->type = ARM_STM;
2690 addr_mode = 3; /*DB*/
2692 reg_list |= (1 << 14) /*LR*/;
2696 reg_names_p = reg_names;
2697 for (i = 0; i <= 15; i++) {
2698 if (reg_list & (1 << i))
2699 reg_names_p += snprintf(reg_names_p,
2700 (reg_names + 40 - reg_names_p),
2704 if (reg_names_p > reg_names)
2705 reg_names_p[-2] = '\0';
2706 else /* invalid op : no registers */
2707 reg_names[0] = '\0';
2709 snprintf(instruction->text, 128,
2710 "0x%8.8" PRIx32 " 0x%4.4x \t%s\t%s{%s}",
2711 address, opcode, mnemonic, ptr_name, reg_names);
2713 instruction->info.load_store_multiple.register_list = reg_list;
2714 instruction->info.load_store_multiple.Rn = Rn;
2715 instruction->info.load_store_multiple.addressing_mode = addr_mode;
2720 static int evaluate_cond_branch_thumb(uint16_t opcode,
2721 uint32_t address, struct arm_instruction *instruction)
2723 uint32_t offset = opcode & 0xff;
2724 uint8_t cond = (opcode >> 8) & 0xf;
2725 uint32_t target_address;
2728 instruction->type = ARM_SWI;
2729 snprintf(instruction->text, 128,
2730 "0x%8.8" PRIx32 " 0x%4.4x \tSVC\t%#2.2" PRIx32,
2731 address, opcode, offset);
2733 } else if (cond == 0xe) {
2734 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2735 snprintf(instruction->text, 128,
2736 "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION",
2741 /* sign extend 8-bit offset */
2742 if (offset & 0x00000080)
2743 offset = 0xffffff00 | offset;
2745 target_address = address + 4 + (offset << 1);
2747 snprintf(instruction->text, 128,
2748 "0x%8.8" PRIx32 " 0x%4.4x \tB%s\t%#8.8" PRIx32,
2750 arm_condition_strings[cond], target_address);
2752 instruction->type = ARM_B;
2753 instruction->info.b_bl_bx_blx.reg_operand = -1;
2754 instruction->info.b_bl_bx_blx.target_address = target_address;
2759 static int evaluate_cb_thumb(uint16_t opcode, uint32_t address,
2760 struct arm_instruction *instruction)
2764 /* added in Thumb2 */
2765 offset = (opcode >> 3) & 0x1f;
2766 offset |= (opcode & 0x0200) >> 4;
2768 snprintf(instruction->text, 128,
2769 "0x%8.8" PRIx32 " 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32,
2771 (opcode & 0x0800) ? "N" : "",
2772 opcode & 0x7, address + 4 + (offset << 1));
2777 static int evaluate_extend_thumb(uint16_t opcode, uint32_t address,
2778 struct arm_instruction *instruction)
2780 /* added in ARMv6 */
2781 snprintf(instruction->text, 128,
2782 "0x%8.8" PRIx32 " 0x%4.4x \t%cXT%c\tr%d, r%d",
2784 (opcode & 0x0080) ? 'U' : 'S',
2785 (opcode & 0x0040) ? 'B' : 'H',
2786 opcode & 0x7, (opcode >> 3) & 0x7);
2791 static int evaluate_cps_thumb(uint16_t opcode, uint32_t address,
2792 struct arm_instruction *instruction)
2794 /* added in ARMv6 */
2795 if ((opcode & 0x0ff0) == 0x0650)
2796 snprintf(instruction->text, 128,
2797 "0x%8.8" PRIx32 " 0x%4.4x \tSETEND %s",
2799 (opcode & 0x80) ? "BE" : "LE");
2800 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2801 snprintf(instruction->text, 128,
2802 "0x%8.8" PRIx32 " 0x%4.4x \tCPSI%c\t%s%s%s",
2804 (opcode & 0x0010) ? 'D' : 'E',
2805 (opcode & 0x0004) ? "A" : "",
2806 (opcode & 0x0002) ? "I" : "",
2807 (opcode & 0x0001) ? "F" : "");
2812 static int evaluate_byterev_thumb(uint16_t opcode, uint32_t address,
2813 struct arm_instruction *instruction)
2817 /* added in ARMv6 */
2818 switch ((opcode >> 6) & 3) {
2829 snprintf(instruction->text, 128,
2830 "0x%8.8" PRIx32 " 0x%4.4x \tREV%s\tr%d, r%d",
2831 address, opcode, suffix,
2832 opcode & 0x7, (opcode >> 3) & 0x7);
2837 static int evaluate_hint_thumb(uint16_t opcode, uint32_t address,
2838 struct arm_instruction *instruction)
2842 switch ((opcode >> 4) & 0x0f) {
2859 hint = "HINT (UNRECOGNIZED)";
2863 snprintf(instruction->text, 128,
2864 "0x%8.8" PRIx32 " 0x%4.4x \t%s",
2865 address, opcode, hint);
2870 static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address,
2871 struct arm_instruction *instruction)
2873 unsigned cond = (opcode >> 4) & 0x0f;
2874 char *x = "", *y = "", *z = "";
2877 z = (opcode & 0x02) ? "T" : "E";
2879 y = (opcode & 0x04) ? "T" : "E";
2881 x = (opcode & 0x08) ? "T" : "E";
2883 snprintf(instruction->text, 128,
2884 "0x%8.8" PRIx32 " 0x%4.4x \tIT%s%s%s\t%s",
2886 x, y, z, arm_condition_strings[cond]);
2888 /* NOTE: strictly speaking, the next 1-4 instructions should
2889 * now be displayed with the relevant conditional suffix...
2895 int thumb_evaluate_opcode(uint16_t opcode, uint32_t address, struct arm_instruction *instruction)
2897 /* clear fields, to avoid confusion */
2898 memset(instruction, 0, sizeof(struct arm_instruction));
2899 instruction->opcode = opcode;
2900 instruction->instruction_size = 2;
2902 if ((opcode & 0xe000) == 0x0000) {
2903 /* add/subtract register or immediate */
2904 if ((opcode & 0x1800) == 0x1800)
2905 return evaluate_add_sub_thumb(opcode, address, instruction);
2906 /* shift by immediate */
2908 return evaluate_shift_imm_thumb(opcode, address, instruction);
2911 /* Add/subtract/compare/move immediate */
2912 if ((opcode & 0xe000) == 0x2000)
2913 return evaluate_data_proc_imm_thumb(opcode, address, instruction);
2915 /* Data processing instructions */
2916 if ((opcode & 0xf800) == 0x4000)
2917 return evaluate_data_proc_thumb(opcode, address, instruction);
2919 /* Load from literal pool */
2920 if ((opcode & 0xf800) == 0x4800)
2921 return evaluate_load_literal_thumb(opcode, address, instruction);
2923 /* Load/Store register offset */
2924 if ((opcode & 0xf000) == 0x5000)
2925 return evaluate_load_store_reg_thumb(opcode, address, instruction);
2927 /* Load/Store immediate offset */
2928 if (((opcode & 0xe000) == 0x6000)
2929 || ((opcode & 0xf000) == 0x8000))
2930 return evaluate_load_store_imm_thumb(opcode, address, instruction);
2932 /* Load/Store from/to stack */
2933 if ((opcode & 0xf000) == 0x9000)
2934 return evaluate_load_store_stack_thumb(opcode, address, instruction);
2937 if ((opcode & 0xf000) == 0xa000)
2938 return evaluate_add_sp_pc_thumb(opcode, address, instruction);
2941 if ((opcode & 0xf000) == 0xb000) {
2942 switch ((opcode >> 8) & 0x0f) {
2944 return evaluate_adjust_stack_thumb(opcode, address, instruction);
2949 return evaluate_cb_thumb(opcode, address, instruction);
2951 return evaluate_extend_thumb(opcode, address, instruction);
2956 return evaluate_load_store_multiple_thumb(opcode, address,
2959 return evaluate_cps_thumb(opcode, address, instruction);
2961 if ((opcode & 0x00c0) == 0x0080)
2963 return evaluate_byterev_thumb(opcode, address, instruction);
2965 return evaluate_breakpoint_thumb(opcode, address, instruction);
2967 if (opcode & 0x000f)
2968 return evaluate_ifthen_thumb(opcode, address,
2971 return evaluate_hint_thumb(opcode, address,
2975 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2976 snprintf(instruction->text, 128,
2977 "0x%8.8" PRIx32 " 0x%4.4x \tUNDEFINED INSTRUCTION",
2982 /* Load/Store multiple */
2983 if ((opcode & 0xf000) == 0xc000)
2984 return evaluate_load_store_multiple_thumb(opcode, address, instruction);
2986 /* Conditional branch + SWI */
2987 if ((opcode & 0xf000) == 0xd000)
2988 return evaluate_cond_branch_thumb(opcode, address, instruction);
2990 if ((opcode & 0xe000) == 0xe000) {
2991 /* Undefined instructions */
2992 if ((opcode & 0xf801) == 0xe801) {
2993 instruction->type = ARM_UNDEFINED_INSTRUCTION;
2994 snprintf(instruction->text, 128,
2995 "0x%8.8" PRIx32 " 0x%8.8x\t"
2996 "UNDEFINED INSTRUCTION",
2999 } else /* Branch to offset */
3000 return evaluate_b_bl_blx_thumb(opcode, address, instruction);
3003 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode);
3007 int arm_access_size(struct arm_instruction *instruction)
3009 if ((instruction->type == ARM_LDRB)
3010 || (instruction->type == ARM_LDRBT)
3011 || (instruction->type == ARM_LDRSB)
3012 || (instruction->type == ARM_STRB)
3013 || (instruction->type == ARM_STRBT))
3015 else if ((instruction->type == ARM_LDRH)
3016 || (instruction->type == ARM_LDRSH)
3017 || (instruction->type == ARM_STRH))
3019 else if ((instruction->type == ARM_LDR)
3020 || (instruction->type == ARM_LDRT)
3021 || (instruction->type == ARM_STR)
3022 || (instruction->type == ARM_STRT))
3024 else if ((instruction->type == ARM_LDRD)
3025 || (instruction->type == ARM_STRD))
3028 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction",
3035 static void print_opcode(struct command_invocation *cmd, const cs_insn *insn)
3037 uint32_t opcode = 0;
3039 memcpy(&opcode, insn->bytes, insn->size);
3041 if (insn->size == 4) {
3042 uint16_t opcode_high = opcode >> 16;
3043 opcode = opcode & 0xffff;
3045 command_print(cmd, "0x%08" PRIx64" %04x %04x\t%s%s%s",
3046 insn->address, opcode, opcode_high, insn->mnemonic,
3047 insn->op_str[0] ? "\t" : "", insn->op_str);
3049 command_print(cmd, "0x%08" PRIx64" %04x\t%s%s%s",
3050 insn->address, opcode, insn->mnemonic,
3051 insn->op_str[0] ? "\t" : "", insn->op_str);
3055 int arm_disassemble(struct command_invocation *cmd, struct target *target,
3056 target_addr_t address, size_t count, bool thumb_mode)
3063 if (!cs_support(CS_ARCH_ARM)) {
3064 LOG_ERROR("ARM architecture not supported by capstone");
3068 mode = CS_MODE_LITTLE_ENDIAN;
3071 mode |= CS_MODE_THUMB;
3073 ret = cs_open(CS_ARCH_ARM, mode, &handle);
3075 if (ret != CS_ERR_OK) {
3076 LOG_ERROR("cs_open() failed: %s", cs_strerror(ret));
3080 ret = cs_option(handle, CS_OPT_SKIPDATA, CS_OPT_ON);
3082 if (ret != CS_ERR_OK) {
3083 LOG_ERROR("cs_option() failed: %s", cs_strerror(ret));
3088 insn = cs_malloc(handle);
3091 LOG_ERROR("cs_malloc() failed\n");
3099 ret = target_read_buffer(target, address, sizeof(buffer), buffer);
3101 if (ret != ERROR_OK) {
3107 size_t size = sizeof(buffer);
3108 const uint8_t *tmp = buffer;
3110 ret = cs_disasm_iter(handle, &tmp, &size, &address, insn);
3113 LOG_ERROR("cs_disasm_iter() failed: %s",
3114 cs_strerror(cs_errno(handle)));
3120 print_opcode(cmd, insn);
3129 #endif /* HAVE_CAPSTONE */