1 // SPDX-License-Identifier: GPL-2.0-or-later
3 /***************************************************************************
4 * Copyright (C) 2006 by Dominic Rath *
5 * Dominic.Rath@gmx.de *
7 * Copyright (C) 2009 by David Brownell *
8 ***************************************************************************/
15 #include "arm_disassembler.h"
16 #include <helper/log.h>
23 * This disassembler supports two main functions for OpenOCD:
25 * - Various "disassemble" commands. OpenOCD can serve as a
26 * machine-language debugger, without help from GDB.
28 * - Single stepping. Not all ARM cores support hardware single
29 * stepping. To work without that support, the debugger must
30 * be able to decode instructions to find out where to put a
31 * "next instruction" breakpoint.
33 * In addition, interpretation of ETM trace data needs some of the
34 * decoding mechanisms.
36 * At this writing (September 2009) neither function is complete.
39 * * Old-style syntax (not UAL) is generally used
40 * * VFP instructions are not understood (ARMv5 and later)
41 * except as coprocessor 10/11 operations
42 * * Most ARM instructions through ARMv6 are decoded, but some
43 * of the post-ARMv4 opcodes may not be handled yet
44 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
45 * * NEON instructions are not understood (ARMv7-A)
47 * - Thumb/Thumb2 decoding
48 * * UAL syntax should be consistently used
49 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
50 * be handled properly. Accordingly, so should the subset
51 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
53 * * Conditional effects of Thumb2 "IT" (if-then) instructions
54 * are not handled: the affected instructions are not shown
55 * with their now-conditional suffixes.
56 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
57 * handled (minimally for coprocessor access).
58 * * SIMD instructions, and some other Thumb2 instructions
59 * from ARMv7-A, are not understood.
62 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
63 * * Opcodes changed by ThumbEE mode are not handled; these
64 * instructions wrongly decode as LDM and STM.
66 * - Jazelle decoding ... no support whatsoever for Jazelle mode
67 * or decoding. ARM encourages use of the more generic ThumbEE
68 * mode, instead of Jazelle mode, in current chips.
70 * - Single-step/emulation ... spotty support, which is only weakly
71 * tested. Thumb2 is not supported. (Arguably a full simulator
72 * is not needed to support just single stepping. Recognizing
73 * branch vs non-branch instructions suffices, except when the
74 * instruction faults and triggers a synchronous exception which
75 * can be intercepted using other means.)
77 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
78 * ARM v7-R edition" gives the most complete coverage of the various
79 * generations of ARM instructions. At this writing it is publicly
80 * accessible to anyone willing to create an account at the ARM
81 * web site; see http://www.arm.com/documentation/ for information.
83 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
84 * more details relevant to the Thumb2-only processors (such as
85 * the Cortex-M implementations).
88 /* textual representation of the condition field
89 * ALways (default) is omitted (empty string) */
90 static const char *arm_condition_strings
[] = {
91 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
94 /* make up for C's missing ROR */
95 static uint32_t ror(uint32_t value
, int places
)
97 return (value
>> places
) | (value
<< (32 - places
));
100 static int evaluate_unknown(uint32_t opcode
,
101 uint32_t address
, struct arm_instruction
*instruction
)
103 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
104 snprintf(instruction
->text
, 128,
105 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
106 "\tUNDEFINED INSTRUCTION", address
, opcode
);
110 static int evaluate_pld(uint32_t opcode
,
111 uint32_t address
, struct arm_instruction
*instruction
)
114 if ((opcode
& 0x0d30f000) == 0x0510f000) {
119 instruction
->type
= ARM_PLD
;
120 rn
= (opcode
& 0xf0000) >> 16;
121 u
= (opcode
& 0x00800000) >> 23;
124 offset
= opcode
& 0x0fff;
125 snprintf(instruction
->text
, 128,
126 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD %s%d",
127 address
, opcode
, u
? "" : "-", offset
);
131 i
= (opcode
& 0x02000000) >> 25;
132 r
= (opcode
& 0x00400000) >> 22;
135 /* register PLD{W} [<Rn>,+/-<Rm>{, <shift>}] */
136 offset
= (opcode
& 0x0F80) >> 7;
142 snprintf(instruction
->text
, 128,
143 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d, %sr%d]",
144 address
, opcode
, r
? "" : "W", rn
, u
? "" : "-", rm
);
148 shift
= (opcode
& 0x60) >> 5;
152 snprintf(instruction
->text
, 128,
153 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d, %sr%d, LSL #0x%x)",
154 address
, opcode
, r
? "" : "W", rn
, u
? "" : "-", rm
, offset
);
155 } else if (shift
== 0x1) {
157 snprintf(instruction
->text
, 128,
158 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d, %sr%d, LSR #0x%x)",
159 address
, opcode
, r
? "" : "W", rn
, u
? "" : "-", rm
, offset
);
160 } else if (shift
== 0x2) {
162 snprintf(instruction
->text
, 128,
163 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d, %sr%d, ASR #0x%x)",
164 address
, opcode
, r
? "" : "W", rn
, u
? "" : "-", rm
, offset
);
165 } else if (shift
== 0x3) {
167 snprintf(instruction
->text
, 128,
168 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d, %sr%d, ROR #0x%x)",
169 address
, opcode
, r
? "" : "W", rn
, u
? "" : "-", rm
, offset
);
173 /* immediate PLD{W} [<Rn>, #+/-<imm12>] */
174 offset
= opcode
& 0x0fff;
176 snprintf(instruction
->text
, 128,
177 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d]",
178 address
, opcode
, r
? "" : "W", rn
);
180 snprintf(instruction
->text
, 128,
181 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD%s [r%d, #%s%d]",
182 address
, opcode
, r
? "" : "W", rn
, u
? "" : "-", offset
);
189 if ((opcode
& 0x07f000f0) == 0x05700040) {
190 instruction
->type
= ARM_DSB
;
193 switch (opcode
& 0x0000000f) {
222 snprintf(instruction
->text
,
224 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tDSB %s",
225 address
, opcode
, opt
);
230 if ((opcode
& 0x07f000f0) == 0x05700060) {
231 instruction
->type
= ARM_ISB
;
233 snprintf(instruction
->text
,
235 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tISB %s",
237 ((opcode
& 0x0000000f) == 0xf) ? "SY" : "UNK");
241 return evaluate_unknown(opcode
, address
, instruction
);
244 static int evaluate_srs(uint32_t opcode
,
245 uint32_t address
, struct arm_instruction
*instruction
)
247 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
248 const char *mode
= "";
250 switch ((opcode
>> 23) & 0x3) {
255 /* "IA" is default */
265 switch (opcode
& 0x0e500000) {
267 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
269 "\tSRS%s\tSP%s, #%d",
272 (unsigned)(opcode
& 0x1f));
275 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
280 (unsigned)((opcode
>> 16) & 0xf), wback
);
283 return evaluate_unknown(opcode
, address
, instruction
);
288 static int evaluate_swi(uint32_t opcode
,
289 uint32_t address
, struct arm_instruction
*instruction
)
291 instruction
->type
= ARM_SWI
;
293 snprintf(instruction
->text
, 128,
294 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
295 address
, opcode
, (opcode
& 0xffffff));
300 static int evaluate_blx_imm(uint32_t opcode
,
301 uint32_t address
, struct arm_instruction
*instruction
)
305 uint32_t target_address
;
307 instruction
->type
= ARM_BLX
;
308 immediate
= opcode
& 0x00ffffff;
310 /* sign extend 24-bit immediate */
311 if (immediate
& 0x00800000)
312 offset
= 0xff000000 | immediate
;
316 /* shift two bits left */
319 /* odd/event halfword */
320 if (opcode
& 0x01000000)
323 target_address
= address
+ 8 + offset
;
325 snprintf(instruction
->text
,
327 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
332 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
333 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
338 static int evaluate_b_bl(uint32_t opcode
,
339 uint32_t address
, struct arm_instruction
*instruction
)
344 uint32_t target_address
;
346 immediate
= opcode
& 0x00ffffff;
347 l
= (opcode
& 0x01000000) >> 24;
349 /* sign extend 24-bit immediate */
350 if (immediate
& 0x00800000)
351 offset
= 0xff000000 | immediate
;
355 /* shift two bits left */
358 target_address
= address
+ 8 + offset
;
361 instruction
->type
= ARM_BL
;
363 instruction
->type
= ARM_B
;
365 snprintf(instruction
->text
,
367 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
374 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
375 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
380 /* Coprocessor load/store and double register transfers
381 * both normal and extended instruction space (condition field b1111) */
382 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
383 uint32_t address
, struct arm_instruction
*instruction
)
385 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
388 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c500000)) {
389 uint8_t cp_opcode
, rd
, rn
, crm
;
392 cp_opcode
= (opcode
& 0xf0) >> 4;
393 rd
= (opcode
& 0xf000) >> 12;
394 rn
= (opcode
& 0xf0000) >> 16;
395 crm
= (opcode
& 0xf);
398 if ((opcode
& 0x0ff00000) == 0x0c400000) {
399 instruction
->type
= ARM_MCRR
;
401 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
403 instruction
->type
= ARM_MRRC
;
406 LOG_ERROR("Unknown instruction");
410 snprintf(instruction
->text
, 128,
411 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
412 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
413 address
, opcode
, mnemonic
,
414 ((opcode
& 0xf0000000) == 0xf0000000)
415 ? "2" : COND(opcode
),
416 COND(opcode
), cp_num
, cp_opcode
, rd
, rn
, crm
);
417 } else {/* LDC or STC */
418 uint8_t crd
, rn
, offset
;
421 char addressing_mode
[32];
423 crd
= (opcode
& 0xf000) >> 12;
424 rn
= (opcode
& 0xf0000) >> 16;
425 offset
= (opcode
& 0xff) << 2;
428 if (opcode
& 0x00100000) {
429 instruction
->type
= ARM_LDC
;
432 instruction
->type
= ARM_STC
;
436 u
= (opcode
& 0x00800000) >> 23;
438 /* addressing modes */
439 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
440 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
441 rn
, u
? "" : "-", offset
);
442 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
443 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
444 rn
, u
? "" : "-", offset
);
445 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
446 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
447 rn
, u
? "" : "-", offset
);
448 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
449 snprintf(addressing_mode
, 32, "[r%i], {%d}",
452 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
454 "\t%s%s%s p%i, c%i, %s",
455 address
, opcode
, mnemonic
,
456 ((opcode
& 0xf0000000) == 0xf0000000)
457 ? "2" : COND(opcode
),
458 (opcode
& (1 << 22)) ? "L" : "",
459 cp_num
, crd
, addressing_mode
);
465 /* Coprocessor data processing instructions
466 * Coprocessor register transfer instructions
467 * both normal and extended instruction space (condition field b1111) */
468 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
469 uint32_t address
, struct arm_instruction
*instruction
)
473 uint8_t cp_num
, opcode_1
, crd_rd
, crn
, crm
, opcode_2
;
475 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
476 cp_num
= (opcode
& 0xf00) >> 8;
477 crd_rd
= (opcode
& 0xf000) >> 12;
478 crn
= (opcode
& 0xf0000) >> 16;
479 crm
= (opcode
& 0xf);
480 opcode_2
= (opcode
& 0xe0) >> 5;
483 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
484 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
485 instruction
->type
= ARM_MRC
;
487 } else {/* bit 20 not set -> MCR */
488 instruction
->type
= ARM_MCR
;
492 opcode_1
= (opcode
& 0x00e00000) >> 21;
494 snprintf(instruction
->text
,
496 "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",
507 } else {/* bit 4 not set -> CDP */
508 instruction
->type
= ARM_CDP
;
511 opcode_1
= (opcode
& 0x00f00000) >> 20;
513 snprintf(instruction
->text
,
515 "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",
531 /* Load/store instructions */
532 static int evaluate_load_store(uint32_t opcode
,
533 uint32_t address
, struct arm_instruction
*instruction
)
535 uint8_t i
, p
, u
, b
, w
, l
;
537 char *operation
;/* "LDR" or "STR" */
538 char *suffix
; /* "", "B", "T", "BT" */
542 i
= (opcode
& 0x02000000) >> 25;
543 p
= (opcode
& 0x01000000) >> 24;
544 u
= (opcode
& 0x00800000) >> 23;
545 b
= (opcode
& 0x00400000) >> 22;
546 w
= (opcode
& 0x00200000) >> 21;
547 l
= (opcode
& 0x00100000) >> 20;
549 /* target register */
550 rd
= (opcode
& 0xf000) >> 12;
553 rn
= (opcode
& 0xf0000) >> 16;
555 instruction
->info
.load_store
.rd
= rd
;
556 instruction
->info
.load_store
.rn
= rn
;
557 instruction
->info
.load_store
.u
= u
;
559 /* determine operation */
565 /* determine instruction type and suffix */
567 if ((p
== 0) && (w
== 1)) {
569 instruction
->type
= ARM_LDRBT
;
571 instruction
->type
= ARM_STRBT
;
575 instruction
->type
= ARM_LDRB
;
577 instruction
->type
= ARM_STRB
;
581 if ((p
== 0) && (w
== 1)) {
583 instruction
->type
= ARM_LDRT
;
585 instruction
->type
= ARM_STRT
;
589 instruction
->type
= ARM_LDR
;
591 instruction
->type
= ARM_STR
;
596 if (!i
) { /* #+-<offset_12> */
597 uint32_t offset_12
= (opcode
& 0xfff);
599 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (u
) ? "" : "-", offset_12
);
601 snprintf(offset
, 32, "%s", "");
603 instruction
->info
.load_store
.offset_mode
= 0;
604 instruction
->info
.load_store
.offset
.offset
= offset_12
;
605 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
606 uint8_t shift_imm
, shift
;
609 shift_imm
= (opcode
& 0xf80) >> 7;
610 shift
= (opcode
& 0x60) >> 5;
613 /* LSR encodes a shift by 32 bit as 0x0 */
614 if ((shift
== 0x1) && (shift_imm
== 0x0))
617 /* ASR encodes a shift by 32 bit as 0x0 */
618 if ((shift
== 0x2) && (shift_imm
== 0x0))
621 /* ROR by 32 bit is actually a RRX */
622 if ((shift
== 0x3) && (shift_imm
== 0x0))
625 instruction
->info
.load_store
.offset_mode
= 1;
626 instruction
->info
.load_store
.offset
.reg
.rm
= rm
;
627 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
628 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
630 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
631 snprintf(offset
, 32, ", %sr%i", (u
) ? "" : "-", rm
);
632 else { /* +-<Rm>, <Shift>, #<shift_imm> */
635 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (u
) ? "" : "-", rm
, shift_imm
);
638 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (u
) ? "" : "-", rm
, shift_imm
);
641 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (u
) ? "" : "-", rm
, shift_imm
);
644 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (u
) ? "" : "-", rm
, shift_imm
);
647 snprintf(offset
, 32, ", %sr%i, RRX", (u
) ? "" : "-", rm
);
654 if (w
== 0) { /* offset */
655 snprintf(instruction
->text
,
657 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
667 instruction
->info
.load_store
.index_mode
= 0;
668 } else {/* pre-indexed */
669 snprintf(instruction
->text
,
671 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
681 instruction
->info
.load_store
.index_mode
= 1;
683 } else {/* post-indexed */
684 snprintf(instruction
->text
,
686 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
696 instruction
->info
.load_store
.index_mode
= 2;
702 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
704 unsigned rm
= (opcode
>> 0) & 0xf;
705 unsigned rd
= (opcode
>> 12) & 0xf;
706 unsigned rn
= (opcode
>> 16) & 0xf;
709 switch ((opcode
>> 24) & 0x3) {
714 sprintf(cp
, "UNDEFINED");
715 return ARM_UNDEFINED_INSTRUCTION
;
724 switch ((opcode
>> 10) & 0x3) {
740 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
741 (opcode
& (1 << 22)) ? 'U' : 'S',
746 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
747 (opcode
& (1 << 22)) ? 'U' : 'S',
754 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
760 switch ((opcode
>> 20) & 0x7) {
783 switch ((opcode
>> 5) & 0x7) {
812 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
813 (int) (opcode
>> 12) & 0xf,
814 (int) (opcode
>> 16) & 0xf,
815 (int) (opcode
>> 0) & 0xf);
819 /* these opcodes might be used someday */
820 sprintf(cp
, "UNDEFINED");
821 return ARM_UNDEFINED_INSTRUCTION
;
824 /* ARMv6 and later support "media" instructions (includes SIMD) */
825 static int evaluate_media(uint32_t opcode
, uint32_t address
,
826 struct arm_instruction
*instruction
)
828 char *cp
= instruction
->text
;
829 char *mnemonic
= NULL
;
832 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
836 /* parallel add/subtract */
837 if ((opcode
& 0x01800000) == 0x00000000) {
838 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
843 if ((opcode
& 0x01f00020) == 0x00800000) {
845 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
847 if (opcode
& (1 << 6)) {
856 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
858 (int) (opcode
>> 12) & 0xf,
859 (int) (opcode
>> 16) & 0xf,
860 (int) (opcode
>> 0) & 0xf,
866 if ((opcode
& 0x01a00020) == 0x00a00000) {
868 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
870 if (opcode
& (1 << 6)) {
877 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
878 (opcode
& (1 << 22)) ? 'U' : 'S',
880 (int) (opcode
>> 12) & 0xf,
881 (int) (opcode
>> 16) & 0x1f,
882 (int) (opcode
>> 0) & 0xf,
888 if ((opcode
& 0x018000f0) == 0x00800070) {
889 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
894 if ((opcode
& 0x01f00080) == 0x01000000) {
895 unsigned rn
= (opcode
>> 12) & 0xf;
898 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
899 (opcode
& (1 << 6)) ? 'S' : 'A',
900 (opcode
& (1 << 5)) ? "X" : "",
902 (int) (opcode
>> 16) & 0xf,
903 (int) (opcode
>> 0) & 0xf,
904 (int) (opcode
>> 8) & 0xf,
907 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
908 (opcode
& (1 << 6)) ? 'S' : 'A',
909 (opcode
& (1 << 5)) ? "X" : "",
911 (int) (opcode
>> 16) & 0xf,
912 (int) (opcode
>> 0) & 0xf,
913 (int) (opcode
>> 8) & 0xf);
916 if ((opcode
& 0x01f00000) == 0x01400000) {
917 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
918 (opcode
& (1 << 6)) ? 'S' : 'A',
919 (opcode
& (1 << 5)) ? "X" : "",
921 (int) (opcode
>> 12) & 0xf,
922 (int) (opcode
>> 16) & 0xf,
923 (int) (opcode
>> 0) & 0xf,
924 (int) (opcode
>> 8) & 0xf);
927 if ((opcode
& 0x01f00000) == 0x01500000) {
928 unsigned rn
= (opcode
>> 12) & 0xf;
930 switch (opcode
& 0xc0) {
942 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
943 (opcode
& (1 << 6)) ? 'S' : 'A',
944 (opcode
& (1 << 5)) ? "R" : "",
946 (int) (opcode
>> 16) & 0xf,
947 (int) (opcode
>> 0) & 0xf,
948 (int) (opcode
>> 8) & 0xf,
951 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
952 (opcode
& (1 << 5)) ? "R" : "",
954 (int) (opcode
>> 16) & 0xf,
955 (int) (opcode
>> 0) & 0xf,
956 (int) (opcode
>> 8) & 0xf);
960 /* simple matches against the remaining decode bits */
961 switch (opcode
& 0x01f000f0) {
964 /* parallel halfword saturate */
965 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
966 (opcode
& (1 << 22)) ? 'U' : 'S',
968 (int) (opcode
>> 12) & 0xf,
969 (int) (opcode
>> 16) & 0xf,
970 (int) (opcode
>> 0) & 0xf);
983 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
984 (int) (opcode
>> 12) & 0xf,
985 (int) (opcode
>> 16) & 0xf,
986 (int) (opcode
>> 0) & 0xf);
989 /* unsigned sum of absolute differences */
990 if (((opcode
>> 12) & 0xf) == 0xf)
991 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
992 (int) (opcode
>> 16) & 0xf,
993 (int) (opcode
>> 0) & 0xf,
994 (int) (opcode
>> 8) & 0xf);
996 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
997 (int) (opcode
>> 16) & 0xf,
998 (int) (opcode
>> 0) & 0xf,
999 (int) (opcode
>> 8) & 0xf,
1000 (int) (opcode
>> 12) & 0xf);
1004 unsigned rm
= (opcode
>> 0) & 0xf;
1005 unsigned rd
= (opcode
>> 12) & 0xf;
1007 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
1012 /* these opcodes might be used someday */
1013 sprintf(cp
, "UNDEFINED");
1017 /* Miscellaneous load/store instructions */
1018 static int evaluate_misc_load_store(uint32_t opcode
,
1019 uint32_t address
, struct arm_instruction
*instruction
)
1021 uint8_t p
, u
, i
, w
, l
, s
, h
;
1023 char *operation
;/* "LDR" or "STR" */
1024 char *suffix
; /* "H", "SB", "SH", "D" */
1028 p
= (opcode
& 0x01000000) >> 24;
1029 u
= (opcode
& 0x00800000) >> 23;
1030 i
= (opcode
& 0x00400000) >> 22;
1031 w
= (opcode
& 0x00200000) >> 21;
1032 l
= (opcode
& 0x00100000) >> 20;
1033 s
= (opcode
& 0x00000040) >> 6;
1034 h
= (opcode
& 0x00000020) >> 5;
1036 /* target register */
1037 rd
= (opcode
& 0xf000) >> 12;
1040 rn
= (opcode
& 0xf0000) >> 16;
1042 instruction
->info
.load_store
.rd
= rd
;
1043 instruction
->info
.load_store
.rn
= rn
;
1044 instruction
->info
.load_store
.u
= u
;
1046 /* determine instruction type and suffix */
1047 if (s
) {/* signed */
1051 instruction
->type
= ARM_LDRSH
;
1055 instruction
->type
= ARM_LDRSB
;
1058 } else {/* there are no signed stores, so this is used to encode double-register
1063 instruction
->type
= ARM_STRD
;
1066 instruction
->type
= ARM_LDRD
;
1069 } else {/* unsigned */
1073 instruction
->type
= ARM_LDRH
;
1076 instruction
->type
= ARM_STRH
;
1080 if (i
) {/* Immediate offset/index (#+-<offset_8>)*/
1081 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
1082 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (u
) ? "" : "-", offset_8
);
1084 instruction
->info
.load_store
.offset_mode
= 0;
1085 instruction
->info
.load_store
.offset
.offset
= offset_8
;
1086 } else {/* Register offset/index (+-<Rm>) */
1088 rm
= (opcode
& 0xf);
1089 snprintf(offset
, 32, "%sr%i", (u
) ? "" : "-", rm
);
1091 instruction
->info
.load_store
.offset_mode
= 1;
1092 instruction
->info
.load_store
.offset
.reg
.rm
= rm
;
1093 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
1094 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
1098 if (w
== 0) { /* offset */
1099 snprintf(instruction
->text
,
1101 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1111 instruction
->info
.load_store
.index_mode
= 0;
1112 } else {/* pre-indexed */
1113 snprintf(instruction
->text
,
1115 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1125 instruction
->info
.load_store
.index_mode
= 1;
1127 } else {/* post-indexed */
1128 snprintf(instruction
->text
,
1130 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1140 instruction
->info
.load_store
.index_mode
= 2;
1146 /* Load/store multiples instructions */
1147 static int evaluate_ldm_stm(uint32_t opcode
,
1148 uint32_t address
, struct arm_instruction
*instruction
)
1150 uint8_t p
, u
, s
, w
, l
, rn
;
1151 uint32_t register_list
;
1152 char *addressing_mode
;
1159 p
= (opcode
& 0x01000000) >> 24;
1160 u
= (opcode
& 0x00800000) >> 23;
1161 s
= (opcode
& 0x00400000) >> 22;
1162 w
= (opcode
& 0x00200000) >> 21;
1163 l
= (opcode
& 0x00100000) >> 20;
1164 register_list
= (opcode
& 0xffff);
1165 rn
= (opcode
& 0xf0000) >> 16;
1167 instruction
->info
.load_store_multiple
.rn
= rn
;
1168 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1169 instruction
->info
.load_store_multiple
.s
= s
;
1170 instruction
->info
.load_store_multiple
.w
= w
;
1173 instruction
->type
= ARM_LDM
;
1176 instruction
->type
= ARM_STM
;
1182 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1183 addressing_mode
= "IB";
1185 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1186 addressing_mode
= "DB";
1190 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1191 /* "IA" is the default in UAL syntax */
1192 addressing_mode
= "";
1194 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1195 addressing_mode
= "DA";
1199 reg_list_p
= reg_list
;
1200 for (i
= 0; i
<= 15; i
++) {
1201 if ((register_list
>> i
) & 1) {
1204 reg_list_p
+= snprintf(reg_list_p
,
1205 (reg_list
+ 69 - reg_list_p
),
1209 reg_list_p
+= snprintf(reg_list_p
,
1210 (reg_list
+ 69 - reg_list_p
),
1216 snprintf(instruction
->text
, 128,
1217 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1218 "\t%s%s%s r%i%s, {%s}%s",
1220 mnemonic
, addressing_mode
, COND(opcode
),
1221 rn
, (w
) ? "!" : "", reg_list
, (s
) ? "^" : "");
1226 /* Multiplies, extra load/stores */
1227 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1228 uint32_t address
, struct arm_instruction
*instruction
)
1230 /* Multiply (accumulate) (long) and Swap/swap byte */
1231 if ((opcode
& 0x000000f0) == 0x00000090) {
1232 /* Multiply (accumulate) */
1233 if ((opcode
& 0x0f800000) == 0x00000000) {
1234 uint8_t rm
, rs
, rn
, rd
, s
;
1236 rs
= (opcode
& 0xf00) >> 8;
1237 rn
= (opcode
& 0xf000) >> 12;
1238 rd
= (opcode
& 0xf0000) >> 16;
1239 s
= (opcode
& 0x00100000) >> 20;
1241 /* examine A bit (accumulate) */
1242 if (opcode
& 0x00200000) {
1243 instruction
->type
= ARM_MLA
;
1244 snprintf(instruction
->text
,
1246 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1256 instruction
->type
= ARM_MUL
;
1257 snprintf(instruction
->text
,
1259 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1272 /* Multiply (accumulate) long */
1273 if ((opcode
& 0x0f800000) == 0x00800000) {
1274 char *mnemonic
= NULL
;
1275 uint8_t rm
, rs
, rd_hi
, rd_low
, s
;
1277 rs
= (opcode
& 0xf00) >> 8;
1278 rd_hi
= (opcode
& 0xf000) >> 12;
1279 rd_low
= (opcode
& 0xf0000) >> 16;
1280 s
= (opcode
& 0x00100000) >> 20;
1282 switch ((opcode
& 0x00600000) >> 21) {
1284 instruction
->type
= ARM_UMULL
;
1288 instruction
->type
= ARM_UMLAL
;
1292 instruction
->type
= ARM_SMULL
;
1296 instruction
->type
= ARM_SMLAL
;
1301 snprintf(instruction
->text
,
1303 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1317 /* Swap/swap byte */
1318 if ((opcode
& 0x0f800000) == 0x01000000) {
1321 rd
= (opcode
& 0xf000) >> 12;
1322 rn
= (opcode
& 0xf0000) >> 16;
1324 /* examine B flag */
1325 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1327 snprintf(instruction
->text
,
1329 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1332 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1342 return evaluate_misc_load_store(opcode
, address
, instruction
);
1345 static int evaluate_mrs_msr(uint32_t opcode
,
1346 uint32_t address
, struct arm_instruction
*instruction
)
1348 int r
= (opcode
& 0x00400000) >> 22;
1349 char *PSR
= (r
) ? "SPSR" : "CPSR";
1351 /* Move register to status register (MSR) */
1352 if (opcode
& 0x00200000) {
1353 instruction
->type
= ARM_MSR
;
1355 /* immediate variant */
1356 if (opcode
& 0x02000000) {
1357 uint8_t immediate
= (opcode
& 0xff);
1358 uint8_t rotate
= (opcode
& 0xf00);
1360 snprintf(instruction
->text
,
1362 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1367 (opcode
& 0x10000) ? "c" : "",
1368 (opcode
& 0x20000) ? "x" : "",
1369 (opcode
& 0x40000) ? "s" : "",
1370 (opcode
& 0x80000) ? "f" : "",
1371 ror(immediate
, (rotate
* 2))
1373 } else {/* register variant */
1374 uint8_t rm
= opcode
& 0xf;
1375 snprintf(instruction
->text
,
1377 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1382 (opcode
& 0x10000) ? "c" : "",
1383 (opcode
& 0x20000) ? "x" : "",
1384 (opcode
& 0x40000) ? "s" : "",
1385 (opcode
& 0x80000) ? "f" : "",
1390 } else {/* Move status register to register (MRS) */
1393 instruction
->type
= ARM_MRS
;
1394 rd
= (opcode
& 0x0000f000) >> 12;
1396 snprintf(instruction
->text
,
1398 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1409 /* Miscellaneous instructions */
1410 static int evaluate_misc_instr(uint32_t opcode
,
1411 uint32_t address
, struct arm_instruction
*instruction
)
1414 if ((opcode
& 0x000000f0) == 0x00000000)
1415 evaluate_mrs_msr(opcode
, address
, instruction
);
1418 if ((opcode
& 0x006000f0) == 0x00200010) {
1420 instruction
->type
= ARM_BX
;
1423 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1424 address
, opcode
, COND(opcode
), rm
);
1426 instruction
->info
.b_bl_bx_blx
.reg_operand
= rm
;
1427 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1430 /* BXJ - "Jazelle" support (ARMv5-J) */
1431 if ((opcode
& 0x006000f0) == 0x00200020) {
1433 instruction
->type
= ARM_BX
;
1436 snprintf(instruction
->text
, 128,
1437 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1438 address
, opcode
, COND(opcode
), rm
);
1440 instruction
->info
.b_bl_bx_blx
.reg_operand
= rm
;
1441 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1445 if ((opcode
& 0x006000f0) == 0x00600010) {
1447 instruction
->type
= ARM_CLZ
;
1449 rd
= (opcode
& 0xf000) >> 12;
1451 snprintf(instruction
->text
,
1453 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1462 if ((opcode
& 0x006000f0) == 0x00200030) {
1464 instruction
->type
= ARM_BLX
;
1467 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1468 address
, opcode
, COND(opcode
), rm
);
1470 instruction
->info
.b_bl_bx_blx
.reg_operand
= rm
;
1471 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1474 /* Enhanced DSP add/subtracts */
1475 if ((opcode
& 0x0000000f0) == 0x00000050) {
1477 char *mnemonic
= NULL
;
1479 rd
= (opcode
& 0xf000) >> 12;
1480 rn
= (opcode
& 0xf0000) >> 16;
1482 switch ((opcode
& 0x00600000) >> 21) {
1484 instruction
->type
= ARM_QADD
;
1488 instruction
->type
= ARM_QSUB
;
1492 instruction
->type
= ARM_QDADD
;
1496 instruction
->type
= ARM_QDSUB
;
1501 snprintf(instruction
->text
,
1503 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1513 /* exception return */
1514 if ((opcode
& 0x0000000f0) == 0x00000060) {
1515 if (((opcode
& 0x600000) >> 21) == 3)
1516 instruction
->type
= ARM_ERET
;
1517 snprintf(instruction
->text
,
1519 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tERET",
1524 /* exception generate instructions */
1525 if ((opcode
& 0x0000000f0) == 0x00000070) {
1526 uint32_t immediate
= 0;
1527 char *mnemonic
= NULL
;
1529 switch ((opcode
& 0x600000) >> 21) {
1531 instruction
->type
= ARM_BKPT
;
1533 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1536 instruction
->type
= ARM_HVC
;
1538 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1541 instruction
->type
= ARM_SMC
;
1543 immediate
= (opcode
& 0xf);
1547 snprintf(instruction
->text
,
1549 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s 0x%4.4" PRIx32
"",
1556 /* Enhanced DSP multiplies */
1557 if ((opcode
& 0x000000090) == 0x00000080) {
1558 int x
= (opcode
& 0x20) >> 5;
1559 int y
= (opcode
& 0x40) >> 6;
1562 if ((opcode
& 0x00600000) == 0x00000000) {
1563 uint8_t rd
, rm
, rs
, rn
;
1564 instruction
->type
= ARM_SMLAXY
;
1565 rd
= (opcode
& 0xf0000) >> 16;
1566 rm
= (opcode
& 0xf);
1567 rs
= (opcode
& 0xf00) >> 8;
1568 rn
= (opcode
& 0xf000) >> 12;
1570 snprintf(instruction
->text
,
1572 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1585 if ((opcode
& 0x00600000) == 0x00400000) {
1586 uint8_t rd_low
, rd_hi
, rm
, rs
;
1587 instruction
->type
= ARM_SMLAXY
;
1588 rd_hi
= (opcode
& 0xf0000) >> 16;
1589 rd_low
= (opcode
& 0xf000) >> 12;
1590 rm
= (opcode
& 0xf);
1591 rs
= (opcode
& 0xf00) >> 8;
1593 snprintf(instruction
->text
,
1595 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1608 if (((opcode
& 0x00600000) == 0x00200000) && (x
== 0)) {
1609 uint8_t rd
, rm
, rs
, rn
;
1610 instruction
->type
= ARM_SMLAWY
;
1611 rd
= (opcode
& 0xf0000) >> 16;
1612 rm
= (opcode
& 0xf);
1613 rs
= (opcode
& 0xf00) >> 8;
1614 rn
= (opcode
& 0xf000) >> 12;
1616 snprintf(instruction
->text
,
1618 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1630 if ((opcode
& 0x00600000) == 0x00600000) {
1632 instruction
->type
= ARM_SMULXY
;
1633 rd
= (opcode
& 0xf0000) >> 16;
1634 rm
= (opcode
& 0xf);
1635 rs
= (opcode
& 0xf00) >> 8;
1637 snprintf(instruction
->text
,
1639 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1651 if (((opcode
& 0x00600000) == 0x00200000) && (x
== 1)) {
1653 instruction
->type
= ARM_SMULWY
;
1654 rd
= (opcode
& 0xf0000) >> 16;
1655 rm
= (opcode
& 0xf);
1656 rs
= (opcode
& 0xf00) >> 8;
1658 snprintf(instruction
->text
,
1660 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1674 static int evaluate_mov_imm(uint32_t opcode
,
1675 uint32_t address
, struct arm_instruction
*instruction
)
1681 rd
= (opcode
& 0xf000) >> 12;
1682 t
= opcode
& 0x00400000;
1683 immediate
= (opcode
& 0xf0000) >> 4 | (opcode
& 0xfff);
1685 instruction
->type
= ARM_MOV
;
1686 instruction
->info
.data_proc
.rd
= rd
;
1688 snprintf(instruction
->text
,
1690 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMOV%s%s r%i, #0x%" PRIx16
,
1701 static int evaluate_data_proc(uint32_t opcode
,
1702 uint32_t address
, struct arm_instruction
*instruction
)
1704 uint8_t i
, op
, s
, rn
, rd
;
1705 char *mnemonic
= NULL
;
1706 char shifter_operand
[32];
1708 i
= (opcode
& 0x02000000) >> 25;
1709 op
= (opcode
& 0x01e00000) >> 21;
1710 s
= (opcode
& 0x00100000) >> 20;
1712 rd
= (opcode
& 0xf000) >> 12;
1713 rn
= (opcode
& 0xf0000) >> 16;
1715 instruction
->info
.data_proc
.rd
= rd
;
1716 instruction
->info
.data_proc
.rn
= rn
;
1717 instruction
->info
.data_proc
.s
= s
;
1721 instruction
->type
= ARM_AND
;
1725 instruction
->type
= ARM_EOR
;
1729 instruction
->type
= ARM_SUB
;
1733 instruction
->type
= ARM_RSB
;
1737 instruction
->type
= ARM_ADD
;
1741 instruction
->type
= ARM_ADC
;
1745 instruction
->type
= ARM_SBC
;
1749 instruction
->type
= ARM_RSC
;
1753 instruction
->type
= ARM_TST
;
1757 instruction
->type
= ARM_TEQ
;
1761 instruction
->type
= ARM_CMP
;
1765 instruction
->type
= ARM_CMN
;
1769 instruction
->type
= ARM_ORR
;
1773 instruction
->type
= ARM_MOV
;
1777 instruction
->type
= ARM_BIC
;
1781 instruction
->type
= ARM_MVN
;
1786 if (i
) {/* immediate shifter operand (#<immediate>)*/
1787 uint8_t immed_8
= opcode
& 0xff;
1788 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1791 immediate
= ror(immed_8
, rotate_imm
* 2);
1793 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1795 instruction
->info
.data_proc
.variant
= 0;
1796 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1797 } else {/* register-based shifter operand */
1799 shift
= (opcode
& 0x60) >> 5;
1800 rm
= (opcode
& 0xf);
1802 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1803 *#<shift_immediate>") */
1805 shift_imm
= (opcode
& 0xf80) >> 7;
1807 instruction
->info
.data_proc
.variant
= 1;
1808 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.rm
= rm
;
1809 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1811 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1813 /* LSR encodes a shift by 32 bit as 0x0 */
1814 if ((shift
== 0x1) && (shift_imm
== 0x0))
1817 /* ASR encodes a shift by 32 bit as 0x0 */
1818 if ((shift
== 0x2) && (shift_imm
== 0x0))
1821 /* ROR by 32 bit is actually a RRX */
1822 if ((shift
== 0x3) && (shift_imm
== 0x0))
1825 if ((shift_imm
== 0x0) && (shift
== 0x0))
1826 snprintf(shifter_operand
, 32, "r%i", rm
);
1828 if (shift
== 0x0) /* LSL */
1829 snprintf(shifter_operand
,
1834 else if (shift
== 0x1) /* LSR */
1835 snprintf(shifter_operand
,
1840 else if (shift
== 0x2) /* ASR */
1841 snprintf(shifter_operand
,
1846 else if (shift
== 0x3) /* ROR */
1847 snprintf(shifter_operand
,
1852 else if (shift
== 0x4) /* RRX */
1853 snprintf(shifter_operand
, 32, "r%i, RRX", rm
);
1855 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1856 uint8_t rs
= (opcode
& 0xf00) >> 8;
1858 instruction
->info
.data_proc
.variant
= 2;
1859 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rm
= rm
;
1860 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rs
= rs
;
1861 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1863 if (shift
== 0x0) /* LSL */
1864 snprintf(shifter_operand
, 32, "r%i, LSL r%i", rm
, rs
);
1865 else if (shift
== 0x1) /* LSR */
1866 snprintf(shifter_operand
, 32, "r%i, LSR r%i", rm
, rs
);
1867 else if (shift
== 0x2) /* ASR */
1868 snprintf(shifter_operand
, 32, "r%i, ASR r%i", rm
, rs
);
1869 else if (shift
== 0x3) /* ROR */
1870 snprintf(shifter_operand
, 32, "r%i, ROR r%i", rm
, rs
);
1874 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1875 *<shifter_operand> */
1876 snprintf(instruction
->text
,
1878 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1887 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1888 *<shifter_operand> */
1889 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1890 snprintf(instruction
->text
,
1892 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1896 snprintf(instruction
->text
,
1898 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1906 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1907 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1908 address
, opcode
, mnemonic
, COND(opcode
),
1909 rn
, shifter_operand
);
1915 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1916 struct arm_instruction
*instruction
)
1918 /* clear fields, to avoid confusion */
1919 memset(instruction
, 0, sizeof(struct arm_instruction
));
1920 instruction
->opcode
= opcode
;
1921 instruction
->instruction_size
= 4;
1923 /* catch opcodes with condition field [31:28] = b1111 */
1924 if ((opcode
& 0xf0000000) == 0xf0000000) {
1925 /* Undefined instruction (or ARMv5E cache preload PLD) */
1926 if ((opcode
& 0x08000000) == 0x00000000)
1927 return evaluate_pld(opcode
, address
, instruction
);
1929 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1930 if ((opcode
& 0x0e000000) == 0x08000000)
1931 return evaluate_srs(opcode
, address
, instruction
);
1933 /* Branch and branch with link and change to Thumb */
1934 if ((opcode
& 0x0e000000) == 0x0a000000)
1935 return evaluate_blx_imm(opcode
, address
, instruction
);
1937 /* Extended coprocessor opcode space (ARMv5 and higher)
1938 * Coprocessor load/store and double register transfers */
1939 if ((opcode
& 0x0e000000) == 0x0c000000)
1940 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1942 /* Coprocessor data processing */
1943 if ((opcode
& 0x0f000100) == 0x0c000000)
1944 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1946 /* Coprocessor register transfers */
1947 if ((opcode
& 0x0f000010) == 0x0c000010)
1948 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1950 /* Undefined instruction */
1951 if ((opcode
& 0x0f000000) == 0x0f000000) {
1952 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1953 snprintf(instruction
->text
,
1955 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1962 /* catch opcodes with [27:25] = b000 */
1963 if ((opcode
& 0x0e000000) == 0x00000000) {
1964 /* Multiplies, extra load/stores */
1965 if ((opcode
& 0x00000090) == 0x00000090)
1966 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1968 /* Miscellaneous instructions */
1969 if ((opcode
& 0x0f900000) == 0x01000000)
1970 return evaluate_misc_instr(opcode
, address
, instruction
);
1972 return evaluate_data_proc(opcode
, address
, instruction
);
1975 /* catch opcodes with [27:25] = b001 */
1976 if ((opcode
& 0x0e000000) == 0x02000000) {
1977 /* 16-bit immediate load */
1978 if ((opcode
& 0x0fb00000) == 0x03000000)
1979 return evaluate_mov_imm(opcode
, address
, instruction
);
1981 /* Move immediate to status register */
1982 if ((opcode
& 0x0fb00000) == 0x03200000)
1983 return evaluate_mrs_msr(opcode
, address
, instruction
);
1985 return evaluate_data_proc(opcode
, address
, instruction
);
1989 /* catch opcodes with [27:25] = b010 */
1990 if ((opcode
& 0x0e000000) == 0x04000000) {
1991 /* Load/store immediate offset */
1992 return evaluate_load_store(opcode
, address
, instruction
);
1995 /* catch opcodes with [27:25] = b011 */
1996 if ((opcode
& 0x0e000000) == 0x06000000) {
1997 /* Load/store register offset */
1998 if ((opcode
& 0x00000010) == 0x00000000)
1999 return evaluate_load_store(opcode
, address
, instruction
);
2001 /* Architecturally Undefined instruction
2002 * ... don't expect these to ever be used
2004 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
2005 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2006 snprintf(instruction
->text
, 128,
2007 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
2012 /* "media" instructions */
2013 return evaluate_media(opcode
, address
, instruction
);
2016 /* catch opcodes with [27:25] = b100 */
2017 if ((opcode
& 0x0e000000) == 0x08000000) {
2018 /* Load/store multiple */
2019 return evaluate_ldm_stm(opcode
, address
, instruction
);
2022 /* catch opcodes with [27:25] = b101 */
2023 if ((opcode
& 0x0e000000) == 0x0a000000) {
2024 /* Branch and branch with link */
2025 return evaluate_b_bl(opcode
, address
, instruction
);
2028 /* catch opcodes with [27:25] = b110 */
2029 if ((opcode
& 0x0e000000) == 0x0c000000) {
2030 /* Coprocessor load/store and double register transfers */
2031 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
2034 /* catch opcodes with [27:25] = b111 */
2035 if ((opcode
& 0x0e000000) == 0x0e000000) {
2036 /* Software interrupt */
2037 if ((opcode
& 0x0f000000) == 0x0f000000)
2038 return evaluate_swi(opcode
, address
, instruction
);
2040 /* Coprocessor data processing */
2041 if ((opcode
& 0x0f000010) == 0x0e000000)
2042 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
2044 /* Coprocessor register transfers */
2045 if ((opcode
& 0x0f000010) == 0x0e000010)
2046 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
2049 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
2054 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
2055 uint32_t address
, struct arm_instruction
*instruction
)
2057 uint32_t offset
= opcode
& 0x7ff;
2058 uint32_t opc
= (opcode
>> 11) & 0x3;
2059 uint32_t target_address
;
2060 char *mnemonic
= NULL
;
2062 /* sign extend 11-bit offset */
2063 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
2064 offset
= 0xfffff800 | offset
;
2066 target_address
= address
+ 4 + (offset
<< 1);
2069 /* unconditional branch */
2071 instruction
->type
= ARM_B
;
2076 instruction
->type
= ARM_BLX
;
2078 target_address
&= 0xfffffffc;
2082 instruction
->type
= ARM_UNKNOWN_INSTRUCTION
;
2083 mnemonic
= "prefix";
2084 target_address
= offset
<< 12;
2088 instruction
->type
= ARM_BL
;
2093 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
2094 * these are effectively 32-bit instructions even in Thumb1. For
2095 * disassembly, it's simplest to always use the Thumb2 decoder.
2097 * But some cores will evidently handle them as two instructions,
2098 * where exceptions may occur between the two. The ETMv3.2+ ID
2099 * register has a bit which exposes this behavior.
2102 snprintf(instruction
->text
, 128,
2103 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
2104 address
, opcode
, mnemonic
, target_address
);
2106 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2107 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2112 static int evaluate_add_sub_thumb(uint16_t opcode
,
2113 uint32_t address
, struct arm_instruction
*instruction
)
2115 uint8_t rd
= (opcode
>> 0) & 0x7;
2116 uint8_t rn
= (opcode
>> 3) & 0x7;
2117 uint8_t rm_imm
= (opcode
>> 6) & 0x7;
2118 uint32_t opc
= opcode
& (1 << 9);
2119 uint32_t reg_imm
= opcode
& (1 << 10);
2123 instruction
->type
= ARM_SUB
;
2126 /* REVISIT: if reg_imm == 0, display as "MOVS" */
2127 instruction
->type
= ARM_ADD
;
2131 instruction
->info
.data_proc
.rd
= rd
;
2132 instruction
->info
.data_proc
.rn
= rn
;
2133 instruction
->info
.data_proc
.s
= 1;
2136 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2137 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= rm_imm
;
2138 snprintf(instruction
->text
, 128,
2139 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
2140 address
, opcode
, mnemonic
, rd
, rn
, rm_imm
);
2142 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
2143 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.rm
= rm_imm
;
2144 snprintf(instruction
->text
, 128,
2145 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
2146 address
, opcode
, mnemonic
, rd
, rn
, rm_imm
);
2152 static int evaluate_shift_imm_thumb(uint16_t opcode
,
2153 uint32_t address
, struct arm_instruction
*instruction
)
2155 uint8_t rd
= (opcode
>> 0) & 0x7;
2156 uint8_t rm
= (opcode
>> 3) & 0x7;
2157 uint8_t imm
= (opcode
>> 6) & 0x1f;
2158 uint8_t opc
= (opcode
>> 11) & 0x3;
2159 char *mnemonic
= NULL
;
2163 instruction
->type
= ARM_MOV
;
2165 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2168 instruction
->type
= ARM_MOV
;
2170 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2173 instruction
->type
= ARM_MOV
;
2175 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2179 if ((imm
== 0) && (opc
!= 0))
2182 instruction
->info
.data_proc
.rd
= rd
;
2183 instruction
->info
.data_proc
.rn
= -1;
2184 instruction
->info
.data_proc
.s
= 1;
2186 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2187 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.rm
= rm
;
2188 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2190 snprintf(instruction
->text
, 128,
2191 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2192 address
, opcode
, mnemonic
, rd
, rm
, imm
);
2197 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2198 uint32_t address
, struct arm_instruction
*instruction
)
2200 uint8_t imm
= opcode
& 0xff;
2201 uint8_t rd
= (opcode
>> 8) & 0x7;
2202 uint32_t opc
= (opcode
>> 11) & 0x3;
2203 char *mnemonic
= NULL
;
2205 instruction
->info
.data_proc
.rd
= rd
;
2206 instruction
->info
.data_proc
.rn
= rd
;
2207 instruction
->info
.data_proc
.s
= 1;
2208 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2209 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2213 instruction
->type
= ARM_MOV
;
2215 instruction
->info
.data_proc
.rn
= -1;
2218 instruction
->type
= ARM_CMP
;
2220 instruction
->info
.data_proc
.rd
= -1;
2223 instruction
->type
= ARM_ADD
;
2227 instruction
->type
= ARM_SUB
;
2232 snprintf(instruction
->text
, 128,
2233 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2234 address
, opcode
, mnemonic
, rd
, imm
);
2239 static int evaluate_data_proc_thumb(uint16_t opcode
,
2240 uint32_t address
, struct arm_instruction
*instruction
)
2242 uint8_t high_reg
, op
, rm
, rd
, h1
, h2
;
2243 char *mnemonic
= NULL
;
2246 high_reg
= (opcode
& 0x0400) >> 10;
2247 op
= (opcode
& 0x03C0) >> 6;
2249 rd
= (opcode
& 0x0007);
2250 rm
= (opcode
& 0x0038) >> 3;
2251 h1
= (opcode
& 0x0080) >> 7;
2252 h2
= (opcode
& 0x0040) >> 6;
2254 instruction
->info
.data_proc
.rd
= rd
;
2255 instruction
->info
.data_proc
.rn
= rd
;
2256 instruction
->info
.data_proc
.s
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2257 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2258 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.rm
= rm
;
2267 instruction
->type
= ARM_ADD
;
2271 instruction
->type
= ARM_CMP
;
2275 instruction
->type
= ARM_MOV
;
2281 if ((opcode
& 0x7) == 0x0) {
2282 instruction
->info
.b_bl_bx_blx
.reg_operand
= rm
;
2284 instruction
->type
= ARM_BLX
;
2285 snprintf(instruction
->text
, 128,
2287 " 0x%4.4x \tBLX\tr%i",
2288 address
, opcode
, rm
);
2290 instruction
->type
= ARM_BX
;
2291 snprintf(instruction
->text
, 128,
2293 " 0x%4.4x \tBX\tr%i",
2294 address
, opcode
, rm
);
2297 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2298 snprintf(instruction
->text
, 128,
2301 "UNDEFINED INSTRUCTION",
2309 instruction
->type
= ARM_AND
;
2313 instruction
->type
= ARM_EOR
;
2317 instruction
->type
= ARM_MOV
;
2319 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2320 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2321 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rm
= rd
;
2322 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rs
= rm
;
2325 instruction
->type
= ARM_MOV
;
2327 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2328 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2329 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rm
= rd
;
2330 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rs
= rm
;
2333 instruction
->type
= ARM_MOV
;
2335 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2336 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2337 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rm
= rd
;
2338 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rs
= rm
;
2341 instruction
->type
= ARM_ADC
;
2345 instruction
->type
= ARM_SBC
;
2349 instruction
->type
= ARM_MOV
;
2351 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2352 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2353 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rm
= rd
;
2354 instruction
->info
.data_proc
.shifter_operand
.register_shift
.rs
= rm
;
2357 instruction
->type
= ARM_TST
;
2361 instruction
->type
= ARM_RSB
;
2363 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2364 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2365 instruction
->info
.data_proc
.rn
= rm
;
2368 instruction
->type
= ARM_CMP
;
2372 instruction
->type
= ARM_CMN
;
2376 instruction
->type
= ARM_ORR
;
2380 instruction
->type
= ARM_MUL
;
2384 instruction
->type
= ARM_BIC
;
2388 instruction
->type
= ARM_MVN
;
2395 snprintf(instruction
->text
, 128,
2396 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2398 address
, opcode
, mnemonic
, rd
, rm
);
2400 snprintf(instruction
->text
, 128,
2401 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2402 address
, opcode
, mnemonic
, rd
, rm
);
2407 /* PC-relative data addressing is word-aligned even with Thumb */
2408 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2410 return (addr
+ 4) & ~3;
2413 static int evaluate_load_literal_thumb(uint16_t opcode
,
2414 uint32_t address
, struct arm_instruction
*instruction
)
2417 uint8_t rd
= (opcode
>> 8) & 0x7;
2419 instruction
->type
= ARM_LDR
;
2420 immediate
= opcode
& 0x000000ff;
2423 instruction
->info
.load_store
.rd
= rd
;
2424 instruction
->info
.load_store
.rn
= 15 /*PC*/;
2425 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2426 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2427 instruction
->info
.load_store
.offset
.offset
= immediate
;
2429 snprintf(instruction
->text
, 128,
2430 "0x%8.8" PRIx32
" 0x%4.4x \t"
2431 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2432 address
, opcode
, rd
, immediate
,
2433 thumb_alignpc4(address
) + immediate
);
2438 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2439 uint32_t address
, struct arm_instruction
*instruction
)
2441 uint8_t rd
= (opcode
>> 0) & 0x7;
2442 uint8_t rn
= (opcode
>> 3) & 0x7;
2443 uint8_t rm
= (opcode
>> 6) & 0x7;
2444 uint8_t opc
= (opcode
>> 9) & 0x7;
2445 char *mnemonic
= NULL
;
2449 instruction
->type
= ARM_STR
;
2453 instruction
->type
= ARM_STRH
;
2457 instruction
->type
= ARM_STRB
;
2461 instruction
->type
= ARM_LDRSB
;
2465 instruction
->type
= ARM_LDR
;
2469 instruction
->type
= ARM_LDRH
;
2473 instruction
->type
= ARM_LDRB
;
2477 instruction
->type
= ARM_LDRSH
;
2482 snprintf(instruction
->text
, 128,
2483 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2484 address
, opcode
, mnemonic
, rd
, rn
, rm
);
2486 instruction
->info
.load_store
.rd
= rd
;
2487 instruction
->info
.load_store
.rn
= rn
;
2488 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2489 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2490 instruction
->info
.load_store
.offset
.reg
.rm
= rm
;
2495 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2496 uint32_t address
, struct arm_instruction
*instruction
)
2498 uint32_t offset
= (opcode
>> 6) & 0x1f;
2499 uint8_t rd
= (opcode
>> 0) & 0x7;
2500 uint8_t rn
= (opcode
>> 3) & 0x7;
2501 uint32_t l
= opcode
& (1 << 11);
2502 uint32_t b
= opcode
& (1 << 12);
2508 instruction
->type
= ARM_LDR
;
2511 instruction
->type
= ARM_STR
;
2515 if ((opcode
&0xF000) == 0x8000) {
2523 snprintf(instruction
->text
, 128,
2524 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2525 address
, opcode
, mnemonic
, suffix
, rd
, rn
, offset
<< shift
);
2527 instruction
->info
.load_store
.rd
= rd
;
2528 instruction
->info
.load_store
.rn
= rn
;
2529 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2530 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2531 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2536 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2537 uint32_t address
, struct arm_instruction
*instruction
)
2539 uint32_t offset
= opcode
& 0xff;
2540 uint8_t rd
= (opcode
>> 8) & 0x7;
2541 uint32_t l
= opcode
& (1 << 11);
2545 instruction
->type
= ARM_LDR
;
2548 instruction
->type
= ARM_STR
;
2552 snprintf(instruction
->text
, 128,
2553 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2554 address
, opcode
, mnemonic
, rd
, offset
*4);
2556 instruction
->info
.load_store
.rd
= rd
;
2557 instruction
->info
.load_store
.rn
= 13 /*SP*/;
2558 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2559 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2560 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2565 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2566 uint32_t address
, struct arm_instruction
*instruction
)
2568 uint32_t imm
= opcode
& 0xff;
2569 uint8_t rd
= (opcode
>> 8) & 0x7;
2571 uint32_t sp
= opcode
& (1 << 11);
2572 const char *reg_name
;
2574 instruction
->type
= ARM_ADD
;
2584 snprintf(instruction
->text
, 128,
2585 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2586 address
, opcode
, rd
, reg_name
, imm
* 4);
2588 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2589 instruction
->info
.data_proc
.rd
= rd
;
2590 instruction
->info
.data_proc
.rn
= rn
;
2591 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2596 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2597 uint32_t address
, struct arm_instruction
*instruction
)
2599 uint32_t imm
= opcode
& 0x7f;
2600 uint8_t opc
= opcode
& (1 << 7);
2605 instruction
->type
= ARM_SUB
;
2608 instruction
->type
= ARM_ADD
;
2612 snprintf(instruction
->text
, 128,
2613 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2614 address
, opcode
, mnemonic
, imm
*4);
2616 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2617 instruction
->info
.data_proc
.rd
= 13 /*SP*/;
2618 instruction
->info
.data_proc
.rn
= 13 /*SP*/;
2619 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2624 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2625 uint32_t address
, struct arm_instruction
*instruction
)
2627 uint32_t imm
= opcode
& 0xff;
2629 instruction
->type
= ARM_BKPT
;
2631 snprintf(instruction
->text
, 128,
2632 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2633 address
, opcode
, imm
);
2638 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2639 uint32_t address
, struct arm_instruction
*instruction
)
2641 uint32_t reg_list
= opcode
& 0xff;
2642 uint32_t l
= opcode
& (1 << 11);
2643 uint32_t r
= opcode
& (1 << 8);
2644 uint8_t rn
= (opcode
>> 8) & 7;
2645 uint8_t addr_mode
= 0 /* IA */;
2649 char ptr_name
[7] = "";
2652 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2653 * The STMIA and LDMIA opcodes are used for other instructions.
2656 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2660 instruction
->type
= ARM_LDM
;
2662 if (opcode
& (1 << rn
))
2665 instruction
->type
= ARM_STM
;
2668 snprintf(ptr_name
, sizeof(ptr_name
), "r%i%s, ", rn
, wback
);
2669 } else {/* push/pop */
2672 instruction
->type
= ARM_LDM
;
2675 reg_list
|= (1 << 15) /*PC*/;
2677 instruction
->type
= ARM_STM
;
2679 addr_mode
= 3; /*DB*/
2681 reg_list
|= (1 << 14) /*LR*/;
2685 reg_names_p
= reg_names
;
2686 for (i
= 0; i
<= 15; i
++) {
2687 if (reg_list
& (1 << i
))
2688 reg_names_p
+= snprintf(reg_names_p
,
2689 (reg_names
+ 40 - reg_names_p
),
2693 if (reg_names_p
> reg_names
)
2694 reg_names_p
[-2] = '\0';
2695 else /* invalid op : no registers */
2696 reg_names
[0] = '\0';
2698 snprintf(instruction
->text
, 128,
2699 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2700 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2702 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2703 instruction
->info
.load_store_multiple
.rn
= rn
;
2704 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2709 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2710 uint32_t address
, struct arm_instruction
*instruction
)
2712 uint32_t offset
= opcode
& 0xff;
2713 uint8_t cond
= (opcode
>> 8) & 0xf;
2714 uint32_t target_address
;
2717 instruction
->type
= ARM_SWI
;
2718 snprintf(instruction
->text
, 128,
2719 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2720 address
, opcode
, offset
);
2722 } else if (cond
== 0xe) {
2723 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2724 snprintf(instruction
->text
, 128,
2725 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2730 /* sign extend 8-bit offset */
2731 if (offset
& 0x00000080)
2732 offset
= 0xffffff00 | offset
;
2734 target_address
= address
+ 4 + (offset
<< 1);
2736 snprintf(instruction
->text
, 128,
2737 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2739 arm_condition_strings
[cond
], target_address
);
2741 instruction
->type
= ARM_B
;
2742 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2743 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2748 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2749 struct arm_instruction
*instruction
)
2753 /* added in Thumb2 */
2754 offset
= (opcode
>> 3) & 0x1f;
2755 offset
|= (opcode
& 0x0200) >> 4;
2757 snprintf(instruction
->text
, 128,
2758 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2760 (opcode
& 0x0800) ? "N" : "",
2761 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2766 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2767 struct arm_instruction
*instruction
)
2769 /* added in ARMv6 */
2770 snprintf(instruction
->text
, 128,
2771 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2773 (opcode
& 0x0080) ? 'U' : 'S',
2774 (opcode
& 0x0040) ? 'B' : 'H',
2775 opcode
& 0x7, (opcode
>> 3) & 0x7);
2780 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2781 struct arm_instruction
*instruction
)
2783 /* added in ARMv6 */
2784 if ((opcode
& 0x0ff0) == 0x0650)
2785 snprintf(instruction
->text
, 128,
2786 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2788 (opcode
& 0x80) ? "BE" : "LE");
2789 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2790 snprintf(instruction
->text
, 128,
2791 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2793 (opcode
& 0x0010) ? 'D' : 'E',
2794 (opcode
& 0x0004) ? "A" : "",
2795 (opcode
& 0x0002) ? "I" : "",
2796 (opcode
& 0x0001) ? "F" : "");
2801 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2802 struct arm_instruction
*instruction
)
2806 /* added in ARMv6 */
2807 switch ((opcode
>> 6) & 3) {
2818 snprintf(instruction
->text
, 128,
2819 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2820 address
, opcode
, suffix
,
2821 opcode
& 0x7, (opcode
>> 3) & 0x7);
2826 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2827 struct arm_instruction
*instruction
)
2831 switch ((opcode
>> 4) & 0x0f) {
2848 hint
= "HINT (UNRECOGNIZED)";
2852 snprintf(instruction
->text
, 128,
2853 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2854 address
, opcode
, hint
);
2859 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2860 struct arm_instruction
*instruction
)
2862 unsigned cond
= (opcode
>> 4) & 0x0f;
2863 char *x
= "", *y
= "", *z
= "";
2866 z
= (opcode
& 0x02) ? "T" : "E";
2868 y
= (opcode
& 0x04) ? "T" : "E";
2870 x
= (opcode
& 0x08) ? "T" : "E";
2872 snprintf(instruction
->text
, 128,
2873 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2875 x
, y
, z
, arm_condition_strings
[cond
]);
2877 /* NOTE: strictly speaking, the next 1-4 instructions should
2878 * now be displayed with the relevant conditional suffix...
2884 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2886 /* clear fields, to avoid confusion */
2887 memset(instruction
, 0, sizeof(struct arm_instruction
));
2888 instruction
->opcode
= opcode
;
2889 instruction
->instruction_size
= 2;
2891 if ((opcode
& 0xe000) == 0x0000) {
2892 /* add/subtract register or immediate */
2893 if ((opcode
& 0x1800) == 0x1800)
2894 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2895 /* shift by immediate */
2897 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2900 /* Add/subtract/compare/move immediate */
2901 if ((opcode
& 0xe000) == 0x2000)
2902 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2904 /* Data processing instructions */
2905 if ((opcode
& 0xf800) == 0x4000)
2906 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2908 /* Load from literal pool */
2909 if ((opcode
& 0xf800) == 0x4800)
2910 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2912 /* Load/Store register offset */
2913 if ((opcode
& 0xf000) == 0x5000)
2914 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2916 /* Load/Store immediate offset */
2917 if (((opcode
& 0xe000) == 0x6000)
2918 || ((opcode
& 0xf000) == 0x8000))
2919 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2921 /* Load/Store from/to stack */
2922 if ((opcode
& 0xf000) == 0x9000)
2923 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2926 if ((opcode
& 0xf000) == 0xa000)
2927 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2930 if ((opcode
& 0xf000) == 0xb000) {
2931 switch ((opcode
>> 8) & 0x0f) {
2933 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2938 return evaluate_cb_thumb(opcode
, address
, instruction
);
2940 return evaluate_extend_thumb(opcode
, address
, instruction
);
2945 return evaluate_load_store_multiple_thumb(opcode
, address
,
2948 return evaluate_cps_thumb(opcode
, address
, instruction
);
2950 if ((opcode
& 0x00c0) == 0x0080)
2952 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2954 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2956 if (opcode
& 0x000f)
2957 return evaluate_ifthen_thumb(opcode
, address
,
2960 return evaluate_hint_thumb(opcode
, address
,
2964 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2965 snprintf(instruction
->text
, 128,
2966 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2971 /* Load/Store multiple */
2972 if ((opcode
& 0xf000) == 0xc000)
2973 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2975 /* Conditional branch + SWI */
2976 if ((opcode
& 0xf000) == 0xd000)
2977 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2979 if ((opcode
& 0xe000) == 0xe000) {
2980 /* Undefined instructions */
2981 if ((opcode
& 0xf801) == 0xe801) {
2982 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2983 snprintf(instruction
->text
, 128,
2984 "0x%8.8" PRIx32
" 0x%8.8x\t"
2985 "UNDEFINED INSTRUCTION",
2988 } else /* Branch to offset */
2989 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2992 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2996 int arm_access_size(struct arm_instruction
*instruction
)
2998 if ((instruction
->type
== ARM_LDRB
)
2999 || (instruction
->type
== ARM_LDRBT
)
3000 || (instruction
->type
== ARM_LDRSB
)
3001 || (instruction
->type
== ARM_STRB
)
3002 || (instruction
->type
== ARM_STRBT
))
3004 else if ((instruction
->type
== ARM_LDRH
)
3005 || (instruction
->type
== ARM_LDRSH
)
3006 || (instruction
->type
== ARM_STRH
))
3008 else if ((instruction
->type
== ARM_LDR
)
3009 || (instruction
->type
== ARM_LDRT
)
3010 || (instruction
->type
== ARM_STR
)
3011 || (instruction
->type
== ARM_STRT
))
3013 else if ((instruction
->type
== ARM_LDRD
)
3014 || (instruction
->type
== ARM_STRD
))
3017 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction",
3024 static void print_opcode(struct command_invocation
*cmd
, const cs_insn
*insn
)
3026 uint32_t opcode
= 0;
3028 memcpy(&opcode
, insn
->bytes
, insn
->size
);
3030 if (insn
->size
== 4) {
3031 uint16_t opcode_high
= opcode
>> 16;
3032 opcode
= opcode
& 0xffff;
3034 command_print(cmd
, "0x%08" PRIx64
" %04x %04x\t%s%s%s",
3035 insn
->address
, opcode
, opcode_high
, insn
->mnemonic
,
3036 insn
->op_str
[0] ? "\t" : "", insn
->op_str
);
3038 command_print(cmd
, "0x%08" PRIx64
" %04x\t%s%s%s",
3039 insn
->address
, opcode
, insn
->mnemonic
,
3040 insn
->op_str
[0] ? "\t" : "", insn
->op_str
);
3044 int arm_disassemble(struct command_invocation
*cmd
, struct target
*target
,
3045 target_addr_t address
, size_t count
, bool thumb_mode
)
3052 if (!cs_support(CS_ARCH_ARM
)) {
3053 LOG_ERROR("ARM architecture not supported by capstone");
3057 mode
= CS_MODE_LITTLE_ENDIAN
;
3060 mode
|= CS_MODE_THUMB
;
3062 ret
= cs_open(CS_ARCH_ARM
, mode
, &handle
);
3064 if (ret
!= CS_ERR_OK
) {
3065 LOG_ERROR("cs_open() failed: %s", cs_strerror(ret
));
3069 ret
= cs_option(handle
, CS_OPT_SKIPDATA
, CS_OPT_ON
);
3071 if (ret
!= CS_ERR_OK
) {
3072 LOG_ERROR("cs_option() failed: %s", cs_strerror(ret
));
3077 insn
= cs_malloc(handle
);
3080 LOG_ERROR("cs_malloc() failed\n");
3088 ret
= target_read_buffer(target
, address
, sizeof(buffer
), buffer
);
3090 if (ret
!= ERROR_OK
) {
3096 size_t size
= sizeof(buffer
);
3097 const uint8_t *tmp
= buffer
;
3099 ret
= cs_disasm_iter(handle
, &tmp
, &size
, &address
, insn
);
3102 LOG_ERROR("cs_disasm_iter() failed: %s",
3103 cs_strerror(cs_errno(handle
)));
3109 print_opcode(cmd
, insn
);
3118 #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)