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 */
Linking to existing account procedure
If you already have an account and want to add another login method
you
MUST first sign in with your existing account and
then change URL to read
https://review.openocd.org/login/?link
to get to this page again but this time it'll work for linking. Thank you.
SSH host keys fingerprints
1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=.. |
|+o.. . |
|*.o . . |
|+B . . . |
|Bo. = o S |
|Oo.+ + = |
|oB=.* = . o |
| =+=.+ + E |
|. .=o . o |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)