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
, rd_hi
, rd_low
, s
;
1288 rs
= (opcode
& 0xf00) >> 8;
1289 rd_hi
= (opcode
& 0xf000) >> 12;
1290 rd_low
= (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 rd_low
, rd_hi
, rm
, rs
;
1598 instruction
->type
= ARM_SMLAXY
;
1599 rd_hi
= (opcode
& 0xf0000) >> 16;
1600 rd_low
= (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 */