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, write to the *
19 * Free Software Foundation, Inc., *
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
21 ***************************************************************************/
27 #include "arm_disassembler.h"
28 #include <helper/log.h>
32 * This disassembler supports two main functions for OpenOCD:
34 * - Various "disassemble" commands. OpenOCD can serve as a
35 * machine-language debugger, without help from GDB.
37 * - Single stepping. Not all ARM cores support hardware single
38 * stepping. To work without that support, the debugger must
39 * be able to decode instructions to find out where to put a
40 * "next instruction" breakpoint.
42 * In addition, interpretation of ETM trace data needs some of the
43 * decoding mechanisms.
45 * At this writing (September 2009) neither function is complete.
48 * * Old-style syntax (not UAL) is generally used
49 * * VFP instructions are not understood (ARMv5 and later)
50 * except as coprocessor 10/11 operations
51 * * Most ARM instructions through ARMv6 are decoded, but some
52 * of the post-ARMv4 opcodes may not be handled yet
53 * * NEON instructions are not understood (ARMv7-A)
55 * - Thumb/Thumb2 decoding
56 * * UAL syntax should be consistently used
57 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
58 * be handled properly. Accordingly, so should the subset
59 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
61 * * Conditional effects of Thumb2 "IT" (if-then) instructions
62 * are not handled: the affected instructions are not shown
63 * with their now-conditional suffixes.
64 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
65 * handled (minimally for coprocessor access).
66 * * SIMD instructions, and some other Thumb2 instructions
67 * from ARMv7-A, are not understood.
70 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
71 * * Opcodes changed by ThumbEE mode are not handled; these
72 * instructions wrongly decode as LDM and STM.
74 * - Jazelle decoding ... no support whatsoever for Jazelle mode
75 * or decoding. ARM encourages use of the more generic ThumbEE
76 * mode, instead of Jazelle mode, in current chips.
78 * - Single-step/emulation ... spotty support, which is only weakly
79 * tested. Thumb2 is not supported. (Arguably a full simulator
80 * is not needed to support just single stepping. Recognizing
81 * branch vs non-branch instructions suffices, except when the
82 * instruction faults and triggers a synchronous exception which
83 * can be intercepted using other means.)
85 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
86 * ARM v7-R edition" gives the most complete coverage of the various
87 * generations of ARM instructions. At this writing it is publicly
88 * accessible to anyone willing to create an account at the ARM
89 * web site; see http://www.arm.com/documentation/ for information.
91 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
92 * more details relevant to the Thumb2-only processors (such as
93 * the Cortex-M implementations).
96 /* textual represenation of the condition field */
97 /* ALways (default) is ommitted (empty string) */
98 static const char *arm_condition_strings
[] =
100 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
103 /* make up for C's missing ROR */
104 static uint32_t ror(uint32_t value
, int places
)
106 return (value
>> places
) | (value
<< (32 - places
));
109 static int evaluate_unknown(uint32_t opcode
,
110 uint32_t address
, struct arm_instruction
*instruction
)
112 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
113 snprintf(instruction
->text
, 128,
114 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
115 "\tUNDEFINED INSTRUCTION", address
, opcode
);
119 static int evaluate_pld(uint32_t opcode
,
120 uint32_t address
, struct arm_instruction
*instruction
)
123 if ((opcode
& 0x0d70f000) == 0x0550f000)
125 instruction
->type
= ARM_PLD
;
127 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...", address
, opcode
);
131 return evaluate_unknown(opcode
, address
, instruction
);
134 static int evaluate_srs(uint32_t opcode
,
135 uint32_t address
, struct arm_instruction
*instruction
)
137 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
138 const char *mode
= "";
140 switch ((opcode
>> 23) & 0x3) {
145 /* "IA" is default */
155 switch (opcode
& 0x0e500000) {
157 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
159 "\tSRS%s\tSP%s, #%d",
162 (unsigned)(opcode
& 0x1f));
165 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
170 (unsigned)((opcode
>> 16) & 0xf), wback
);
173 return evaluate_unknown(opcode
, address
, instruction
);
178 static int evaluate_swi(uint32_t opcode
,
179 uint32_t address
, struct arm_instruction
*instruction
)
181 instruction
->type
= ARM_SWI
;
183 snprintf(instruction
->text
, 128,
184 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
185 address
, opcode
, (opcode
& 0xffffff));
190 static int evaluate_blx_imm(uint32_t opcode
,
191 uint32_t address
, struct arm_instruction
*instruction
)
195 uint32_t target_address
;
197 instruction
->type
= ARM_BLX
;
198 immediate
= opcode
& 0x00ffffff;
200 /* sign extend 24-bit immediate */
201 if (immediate
& 0x00800000)
202 offset
= 0xff000000 | immediate
;
206 /* shift two bits left */
209 /* odd/event halfword */
210 if (opcode
& 0x01000000)
213 target_address
= address
+ 8 + offset
;
215 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
217 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
218 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
223 static int evaluate_b_bl(uint32_t opcode
,
224 uint32_t address
, struct arm_instruction
*instruction
)
229 uint32_t target_address
;
231 immediate
= opcode
& 0x00ffffff;
232 L
= (opcode
& 0x01000000) >> 24;
234 /* sign extend 24-bit immediate */
235 if (immediate
& 0x00800000)
236 offset
= 0xff000000 | immediate
;
240 /* shift two bits left */
243 target_address
= address
+ 8 + offset
;
246 instruction
->type
= ARM_BL
;
248 instruction
->type
= ARM_B
;
250 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
251 (L
) ? "L" : "", COND(opcode
), target_address
);
253 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
254 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
259 /* Coprocessor load/store and double register transfers */
260 /* both normal and extended instruction space (condition field b1111) */
261 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
262 uint32_t address
, struct arm_instruction
*instruction
)
264 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
267 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
269 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
272 cp_opcode
= (opcode
& 0xf0) >> 4;
273 Rd
= (opcode
& 0xf000) >> 12;
274 Rn
= (opcode
& 0xf0000) >> 16;
275 CRm
= (opcode
& 0xf);
278 if ((opcode
& 0x0ff00000) == 0x0c400000)
280 instruction
->type
= ARM_MCRR
;
285 if ((opcode
& 0x0ff00000) == 0x0c500000)
287 instruction
->type
= ARM_MRRC
;
291 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
292 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
294 else /* LDC or STC */
296 uint8_t CRd
, Rn
, offset
;
299 char addressing_mode
[32];
301 CRd
= (opcode
& 0xf000) >> 12;
302 Rn
= (opcode
& 0xf0000) >> 16;
303 offset
= (opcode
& 0xff);
306 if (opcode
& 0x00100000)
308 instruction
->type
= ARM_LDC
;
313 instruction
->type
= ARM_STC
;
317 U
= (opcode
& 0x00800000) >> 23;
318 N
= (opcode
& 0x00400000) >> 22;
320 /* addressing modes */
321 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
322 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
323 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
324 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
325 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
326 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
327 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
328 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
330 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
331 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
333 cp_num
, CRd
, addressing_mode
);
339 /* Coprocessor data processing instructions */
340 /* Coprocessor register transfer instructions */
341 /* both normal and extended instruction space (condition field b1111) */
342 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
343 uint32_t address
, struct arm_instruction
*instruction
)
347 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
349 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
350 cp_num
= (opcode
& 0xf00) >> 8;
351 CRd_Rd
= (opcode
& 0xf000) >> 12;
352 CRn
= (opcode
& 0xf0000) >> 16;
353 CRm
= (opcode
& 0xf);
354 opcode_2
= (opcode
& 0xe0) >> 5;
357 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
359 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
361 instruction
->type
= ARM_MRC
;
364 else /* bit 20 not set -> MCR */
366 instruction
->type
= ARM_MCR
;
370 opcode_1
= (opcode
& 0x00e00000) >> 21;
372 snprintf(instruction
->text
, 128, "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",
373 address
, opcode
, mnemonic
, cond
,
374 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
376 else /* bit 4 not set -> CDP */
378 instruction
->type
= ARM_CDP
;
381 opcode_1
= (opcode
& 0x00f00000) >> 20;
383 snprintf(instruction
->text
, 128, "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",
384 address
, opcode
, mnemonic
, cond
,
385 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
391 /* Load/store instructions */
392 static int evaluate_load_store(uint32_t opcode
,
393 uint32_t address
, struct arm_instruction
*instruction
)
395 uint8_t I
, P
, U
, B
, W
, L
;
397 char *operation
; /* "LDR" or "STR" */
398 char *suffix
; /* "", "B", "T", "BT" */
402 I
= (opcode
& 0x02000000) >> 25;
403 P
= (opcode
& 0x01000000) >> 24;
404 U
= (opcode
& 0x00800000) >> 23;
405 B
= (opcode
& 0x00400000) >> 22;
406 W
= (opcode
& 0x00200000) >> 21;
407 L
= (opcode
& 0x00100000) >> 20;
409 /* target register */
410 Rd
= (opcode
& 0xf000) >> 12;
413 Rn
= (opcode
& 0xf0000) >> 16;
415 instruction
->info
.load_store
.Rd
= Rd
;
416 instruction
->info
.load_store
.Rn
= Rn
;
417 instruction
->info
.load_store
.U
= U
;
419 /* determine operation */
425 /* determine instruction type and suffix */
428 if ((P
== 0) && (W
== 1))
431 instruction
->type
= ARM_LDRBT
;
433 instruction
->type
= ARM_STRBT
;
439 instruction
->type
= ARM_LDRB
;
441 instruction
->type
= ARM_STRB
;
447 if ((P
== 0) && (W
== 1))
450 instruction
->type
= ARM_LDRT
;
452 instruction
->type
= ARM_STRT
;
458 instruction
->type
= ARM_LDR
;
460 instruction
->type
= ARM_STR
;
465 if (!I
) /* #+-<offset_12> */
467 uint32_t offset_12
= (opcode
& 0xfff);
469 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
471 snprintf(offset
, 32, "%s", "");
473 instruction
->info
.load_store
.offset_mode
= 0;
474 instruction
->info
.load_store
.offset
.offset
= offset_12
;
476 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
478 uint8_t shift_imm
, shift
;
481 shift_imm
= (opcode
& 0xf80) >> 7;
482 shift
= (opcode
& 0x60) >> 5;
485 /* LSR encodes a shift by 32 bit as 0x0 */
486 if ((shift
== 0x1) && (shift_imm
== 0x0))
489 /* ASR encodes a shift by 32 bit as 0x0 */
490 if ((shift
== 0x2) && (shift_imm
== 0x0))
493 /* ROR by 32 bit is actually a RRX */
494 if ((shift
== 0x3) && (shift_imm
== 0x0))
497 instruction
->info
.load_store
.offset_mode
= 1;
498 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
499 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
500 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
502 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
504 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
506 else /* +-<Rm>, <Shift>, #<shift_imm> */
511 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
514 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
517 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
520 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
523 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
531 if (W
== 0) /* offset */
533 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
534 address
, opcode
, operation
, COND(opcode
), suffix
,
537 instruction
->info
.load_store
.index_mode
= 0;
539 else /* pre-indexed */
541 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
542 address
, opcode
, operation
, COND(opcode
), suffix
,
545 instruction
->info
.load_store
.index_mode
= 1;
548 else /* post-indexed */
550 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
551 address
, opcode
, operation
, COND(opcode
), suffix
,
554 instruction
->info
.load_store
.index_mode
= 2;
560 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
562 unsigned rm
= (opcode
>> 0) & 0xf;
563 unsigned rd
= (opcode
>> 12) & 0xf;
564 unsigned rn
= (opcode
>> 16) & 0xf;
567 switch ((opcode
>> 24) & 0x3) {
572 sprintf(cp
, "UNDEFINED");
573 return ARM_UNDEFINED_INSTRUCTION
;
582 switch ((opcode
>> 10) & 0x3) {
598 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
599 (opcode
& (1 << 22)) ? 'U' : 'S',
604 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
605 (opcode
& (1 << 22)) ? 'U' : 'S',
612 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
618 switch ((opcode
>> 20) & 0x7) {
641 switch ((opcode
>> 5) & 0x7) {
670 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
671 (int) (opcode
>> 12) & 0xf,
672 (int) (opcode
>> 16) & 0xf,
673 (int) (opcode
>> 0) & 0xf);
677 /* these opcodes might be used someday */
678 sprintf(cp
, "UNDEFINED");
679 return ARM_UNDEFINED_INSTRUCTION
;
682 /* ARMv6 and later support "media" instructions (includes SIMD) */
683 static int evaluate_media(uint32_t opcode
, uint32_t address
,
684 struct arm_instruction
*instruction
)
686 char *cp
= instruction
->text
;
687 char *mnemonic
= NULL
;
690 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
694 /* parallel add/subtract */
695 if ((opcode
& 0x01800000) == 0x00000000) {
696 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
701 if ((opcode
& 0x01f00020) == 0x00800000) {
703 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
705 if (opcode
& (1 << 6)) {
714 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
716 (int) (opcode
>> 12) & 0xf,
717 (int) (opcode
>> 16) & 0xf,
718 (int) (opcode
>> 0) & 0xf,
724 if ((opcode
& 0x01a00020) == 0x00a00000) {
726 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
728 if (opcode
& (1 << 6)) {
736 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
737 (opcode
& (1 << 22)) ? 'U' : 'S',
739 (int) (opcode
>> 12) & 0xf,
740 (int) (opcode
>> 16) & 0x1f,
741 (int) (opcode
>> 0) & 0xf,
747 if ((opcode
& 0x018000f0) == 0x00800070) {
748 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
753 if ((opcode
& 0x01f00080) == 0x01000000) {
754 unsigned rn
= (opcode
>> 12) & 0xf;
757 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
758 (opcode
& (1 << 6)) ? 'S' : 'A',
759 (opcode
& (1 << 5)) ? "X" : "",
761 (int) (opcode
>> 16) & 0xf,
762 (int) (opcode
>> 0) & 0xf,
763 (int) (opcode
>> 8) & 0xf,
766 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
767 (opcode
& (1 << 6)) ? 'S' : 'A',
768 (opcode
& (1 << 5)) ? "X" : "",
770 (int) (opcode
>> 16) & 0xf,
771 (int) (opcode
>> 0) & 0xf,
772 (int) (opcode
>> 8) & 0xf);
775 if ((opcode
& 0x01f00000) == 0x01400000) {
776 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
777 (opcode
& (1 << 6)) ? 'S' : 'A',
778 (opcode
& (1 << 5)) ? "X" : "",
780 (int) (opcode
>> 12) & 0xf,
781 (int) (opcode
>> 16) & 0xf,
782 (int) (opcode
>> 0) & 0xf,
783 (int) (opcode
>> 8) & 0xf);
786 if ((opcode
& 0x01f00000) == 0x01500000) {
787 unsigned rn
= (opcode
>> 12) & 0xf;
789 switch (opcode
& 0xc0) {
801 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
802 (opcode
& (1 << 6)) ? 'S' : 'A',
803 (opcode
& (1 << 5)) ? "R" : "",
805 (int) (opcode
>> 16) & 0xf,
806 (int) (opcode
>> 0) & 0xf,
807 (int) (opcode
>> 8) & 0xf,
810 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
811 (opcode
& (1 << 5)) ? "R" : "",
813 (int) (opcode
>> 16) & 0xf,
814 (int) (opcode
>> 0) & 0xf,
815 (int) (opcode
>> 8) & 0xf);
820 /* simple matches against the remaining decode bits */
821 switch (opcode
& 0x01f000f0) {
824 /* parallel halfword saturate */
825 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
826 (opcode
& (1 << 22)) ? 'U' : 'S',
828 (int) (opcode
>> 12) & 0xf,
829 (int) (opcode
>> 16) & 0xf,
830 (int) (opcode
>> 0) & 0xf);
843 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
844 (int) (opcode
>> 12) & 0xf,
845 (int) (opcode
>> 16) & 0xf,
846 (int) (opcode
>> 0) & 0xf);
849 /* unsigned sum of absolute differences */
850 if (((opcode
>> 12) & 0xf) == 0xf)
851 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
852 (int) (opcode
>> 16) & 0xf,
853 (int) (opcode
>> 0) & 0xf,
854 (int) (opcode
>> 8) & 0xf);
856 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
857 (int) (opcode
>> 16) & 0xf,
858 (int) (opcode
>> 0) & 0xf,
859 (int) (opcode
>> 8) & 0xf,
860 (int) (opcode
>> 12) & 0xf);
864 unsigned rm
= (opcode
>> 0) & 0xf;
865 unsigned rd
= (opcode
>> 12) & 0xf;
867 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
872 /* these opcodes might be used someday */
873 sprintf(cp
, "UNDEFINED");
877 /* Miscellaneous load/store instructions */
878 static int evaluate_misc_load_store(uint32_t opcode
,
879 uint32_t address
, struct arm_instruction
*instruction
)
881 uint8_t P
, U
, I
, W
, L
, S
, H
;
883 char *operation
; /* "LDR" or "STR" */
884 char *suffix
; /* "H", "SB", "SH", "D" */
888 P
= (opcode
& 0x01000000) >> 24;
889 U
= (opcode
& 0x00800000) >> 23;
890 I
= (opcode
& 0x00400000) >> 22;
891 W
= (opcode
& 0x00200000) >> 21;
892 L
= (opcode
& 0x00100000) >> 20;
893 S
= (opcode
& 0x00000040) >> 6;
894 H
= (opcode
& 0x00000020) >> 5;
896 /* target register */
897 Rd
= (opcode
& 0xf000) >> 12;
900 Rn
= (opcode
& 0xf0000) >> 16;
902 instruction
->info
.load_store
.Rd
= Rd
;
903 instruction
->info
.load_store
.Rn
= Rn
;
904 instruction
->info
.load_store
.U
= U
;
906 /* determine instruction type and suffix */
914 instruction
->type
= ARM_LDRSH
;
920 instruction
->type
= ARM_LDRSB
;
924 else /* there are no signed stores, so this is used to encode double-register load/stores */
930 instruction
->type
= ARM_STRD
;
935 instruction
->type
= ARM_LDRD
;
945 instruction
->type
= ARM_LDRH
;
950 instruction
->type
= ARM_STRH
;
954 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
956 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
957 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
959 instruction
->info
.load_store
.offset_mode
= 0;
960 instruction
->info
.load_store
.offset
.offset
= offset_8
;
962 else /* Register offset/index (+-<Rm>) */
966 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
968 instruction
->info
.load_store
.offset_mode
= 1;
969 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
970 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
971 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
976 if (W
== 0) /* offset */
978 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
979 address
, opcode
, operation
, COND(opcode
), suffix
,
982 instruction
->info
.load_store
.index_mode
= 0;
984 else /* pre-indexed */
986 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
987 address
, opcode
, operation
, COND(opcode
), suffix
,
990 instruction
->info
.load_store
.index_mode
= 1;
993 else /* post-indexed */
995 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
996 address
, opcode
, operation
, COND(opcode
), suffix
,
999 instruction
->info
.load_store
.index_mode
= 2;
1005 /* Load/store multiples instructions */
1006 static int evaluate_ldm_stm(uint32_t opcode
,
1007 uint32_t address
, struct arm_instruction
*instruction
)
1009 uint8_t P
, U
, S
, W
, L
, Rn
;
1010 uint32_t register_list
;
1011 char *addressing_mode
;
1018 P
= (opcode
& 0x01000000) >> 24;
1019 U
= (opcode
& 0x00800000) >> 23;
1020 S
= (opcode
& 0x00400000) >> 22;
1021 W
= (opcode
& 0x00200000) >> 21;
1022 L
= (opcode
& 0x00100000) >> 20;
1023 register_list
= (opcode
& 0xffff);
1024 Rn
= (opcode
& 0xf0000) >> 16;
1026 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1027 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1028 instruction
->info
.load_store_multiple
.S
= S
;
1029 instruction
->info
.load_store_multiple
.W
= W
;
1033 instruction
->type
= ARM_LDM
;
1038 instruction
->type
= ARM_STM
;
1046 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1047 addressing_mode
= "IB";
1051 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1052 addressing_mode
= "DB";
1059 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1060 /* "IA" is the default in UAL syntax */
1061 addressing_mode
= "";
1065 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1066 addressing_mode
= "DA";
1070 reg_list_p
= reg_list
;
1071 for (i
= 0; i
<= 15; i
++)
1073 if ((register_list
>> i
) & 1)
1078 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1082 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1087 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1088 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1089 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1094 /* Multiplies, extra load/stores */
1095 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1096 uint32_t address
, struct arm_instruction
*instruction
)
1098 /* Multiply (accumulate) (long) and Swap/swap byte */
1099 if ((opcode
& 0x000000f0) == 0x00000090)
1101 /* Multiply (accumulate) */
1102 if ((opcode
& 0x0f800000) == 0x00000000)
1104 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1106 Rs
= (opcode
& 0xf00) >> 8;
1107 Rn
= (opcode
& 0xf000) >> 12;
1108 Rd
= (opcode
& 0xf0000) >> 16;
1109 S
= (opcode
& 0x00100000) >> 20;
1111 /* examine A bit (accumulate) */
1112 if (opcode
& 0x00200000)
1114 instruction
->type
= ARM_MLA
;
1115 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1116 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1120 instruction
->type
= ARM_MUL
;
1121 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1122 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1128 /* Multiply (accumulate) long */
1129 if ((opcode
& 0x0f800000) == 0x00800000)
1131 char* mnemonic
= NULL
;
1132 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1134 Rs
= (opcode
& 0xf00) >> 8;
1135 RdHi
= (opcode
& 0xf000) >> 12;
1136 RdLow
= (opcode
& 0xf0000) >> 16;
1137 S
= (opcode
& 0x00100000) >> 20;
1139 switch ((opcode
& 0x00600000) >> 21)
1142 instruction
->type
= ARM_UMULL
;
1146 instruction
->type
= ARM_UMLAL
;
1150 instruction
->type
= ARM_SMULL
;
1154 instruction
->type
= ARM_SMLAL
;
1159 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1160 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1161 RdLow
, RdHi
, Rm
, Rs
);
1166 /* Swap/swap byte */
1167 if ((opcode
& 0x0f800000) == 0x01000000)
1171 Rd
= (opcode
& 0xf000) >> 12;
1172 Rn
= (opcode
& 0xf0000) >> 16;
1174 /* examine B flag */
1175 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1177 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1178 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1184 return evaluate_misc_load_store(opcode
, address
, instruction
);
1187 static int evaluate_mrs_msr(uint32_t opcode
,
1188 uint32_t address
, struct arm_instruction
*instruction
)
1190 int R
= (opcode
& 0x00400000) >> 22;
1191 char *PSR
= (R
) ? "SPSR" : "CPSR";
1193 /* Move register to status register (MSR) */
1194 if (opcode
& 0x00200000)
1196 instruction
->type
= ARM_MSR
;
1198 /* immediate variant */
1199 if (opcode
& 0x02000000)
1201 uint8_t immediate
= (opcode
& 0xff);
1202 uint8_t rotate
= (opcode
& 0xf00);
1204 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1205 address
, opcode
, COND(opcode
), PSR
,
1206 (opcode
& 0x10000) ? "c" : "",
1207 (opcode
& 0x20000) ? "x" : "",
1208 (opcode
& 0x40000) ? "s" : "",
1209 (opcode
& 0x80000) ? "f" : "",
1210 ror(immediate
, (rotate
* 2))
1213 else /* register variant */
1215 uint8_t Rm
= opcode
& 0xf;
1216 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1217 address
, opcode
, COND(opcode
), PSR
,
1218 (opcode
& 0x10000) ? "c" : "",
1219 (opcode
& 0x20000) ? "x" : "",
1220 (opcode
& 0x40000) ? "s" : "",
1221 (opcode
& 0x80000) ? "f" : "",
1227 else /* Move status register to register (MRS) */
1231 instruction
->type
= ARM_MRS
;
1232 Rd
= (opcode
& 0x0000f000) >> 12;
1234 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1235 address
, opcode
, COND(opcode
), Rd
, PSR
);
1241 /* Miscellaneous instructions */
1242 static int evaluate_misc_instr(uint32_t opcode
,
1243 uint32_t address
, struct arm_instruction
*instruction
)
1246 if ((opcode
& 0x000000f0) == 0x00000000)
1248 evaluate_mrs_msr(opcode
, address
, instruction
);
1252 if ((opcode
& 0x006000f0) == 0x00200010)
1255 instruction
->type
= ARM_BX
;
1258 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1259 address
, opcode
, COND(opcode
), Rm
);
1261 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1262 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1265 /* BXJ - "Jazelle" support (ARMv5-J) */
1266 if ((opcode
& 0x006000f0) == 0x00200020)
1269 instruction
->type
= ARM_BX
;
1272 snprintf(instruction
->text
, 128,
1273 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1274 address
, opcode
, COND(opcode
), Rm
);
1276 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1277 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1281 if ((opcode
& 0x006000f0) == 0x00600010)
1284 instruction
->type
= ARM_CLZ
;
1286 Rd
= (opcode
& 0xf000) >> 12;
1288 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1289 address
, opcode
, COND(opcode
), Rd
, Rm
);
1293 if ((opcode
& 0x006000f0) == 0x00200030)
1296 instruction
->type
= ARM_BLX
;
1299 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1300 address
, opcode
, COND(opcode
), Rm
);
1302 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1303 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1306 /* Enhanced DSP add/subtracts */
1307 if ((opcode
& 0x0000000f0) == 0x00000050)
1310 char *mnemonic
= NULL
;
1312 Rd
= (opcode
& 0xf000) >> 12;
1313 Rn
= (opcode
& 0xf0000) >> 16;
1315 switch ((opcode
& 0x00600000) >> 21)
1318 instruction
->type
= ARM_QADD
;
1322 instruction
->type
= ARM_QSUB
;
1326 instruction
->type
= ARM_QDADD
;
1330 instruction
->type
= ARM_QDSUB
;
1335 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1336 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1339 /* Software breakpoints */
1340 if ((opcode
& 0x0000000f0) == 0x00000070)
1343 instruction
->type
= ARM_BKPT
;
1344 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1346 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1347 address
, opcode
, immediate
);
1350 /* Enhanced DSP multiplies */
1351 if ((opcode
& 0x000000090) == 0x00000080)
1353 int x
= (opcode
& 0x20) >> 5;
1354 int y
= (opcode
& 0x40) >> 6;
1357 if ((opcode
& 0x00600000) == 0x00000000)
1359 uint8_t Rd
, Rm
, Rs
, Rn
;
1360 instruction
->type
= ARM_SMLAxy
;
1361 Rd
= (opcode
& 0xf0000) >> 16;
1362 Rm
= (opcode
& 0xf);
1363 Rs
= (opcode
& 0xf00) >> 8;
1364 Rn
= (opcode
& 0xf000) >> 12;
1366 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1367 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1372 if ((opcode
& 0x00600000) == 0x00400000)
1374 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1375 instruction
->type
= ARM_SMLAxy
;
1376 RdHi
= (opcode
& 0xf0000) >> 16;
1377 RdLow
= (opcode
& 0xf000) >> 12;
1378 Rm
= (opcode
& 0xf);
1379 Rs
= (opcode
& 0xf00) >> 8;
1381 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1382 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1383 RdLow
, RdHi
, Rm
, Rs
);
1387 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1389 uint8_t Rd
, Rm
, Rs
, Rn
;
1390 instruction
->type
= ARM_SMLAWy
;
1391 Rd
= (opcode
& 0xf0000) >> 16;
1392 Rm
= (opcode
& 0xf);
1393 Rs
= (opcode
& 0xf00) >> 8;
1394 Rn
= (opcode
& 0xf000) >> 12;
1396 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1397 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1402 if ((opcode
& 0x00600000) == 0x00300000)
1405 instruction
->type
= ARM_SMULxy
;
1406 Rd
= (opcode
& 0xf0000) >> 16;
1407 Rm
= (opcode
& 0xf);
1408 Rs
= (opcode
& 0xf00) >> 8;
1410 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1411 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1416 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1419 instruction
->type
= ARM_SMULWy
;
1420 Rd
= (opcode
& 0xf0000) >> 16;
1421 Rm
= (opcode
& 0xf);
1422 Rs
= (opcode
& 0xf00) >> 8;
1424 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1425 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1433 static int evaluate_data_proc(uint32_t opcode
,
1434 uint32_t address
, struct arm_instruction
*instruction
)
1436 uint8_t I
, op
, S
, Rn
, Rd
;
1437 char *mnemonic
= NULL
;
1438 char shifter_operand
[32];
1440 I
= (opcode
& 0x02000000) >> 25;
1441 op
= (opcode
& 0x01e00000) >> 21;
1442 S
= (opcode
& 0x00100000) >> 20;
1444 Rd
= (opcode
& 0xf000) >> 12;
1445 Rn
= (opcode
& 0xf0000) >> 16;
1447 instruction
->info
.data_proc
.Rd
= Rd
;
1448 instruction
->info
.data_proc
.Rn
= Rn
;
1449 instruction
->info
.data_proc
.S
= S
;
1454 instruction
->type
= ARM_AND
;
1458 instruction
->type
= ARM_EOR
;
1462 instruction
->type
= ARM_SUB
;
1466 instruction
->type
= ARM_RSB
;
1470 instruction
->type
= ARM_ADD
;
1474 instruction
->type
= ARM_ADC
;
1478 instruction
->type
= ARM_SBC
;
1482 instruction
->type
= ARM_RSC
;
1486 instruction
->type
= ARM_TST
;
1490 instruction
->type
= ARM_TEQ
;
1494 instruction
->type
= ARM_CMP
;
1498 instruction
->type
= ARM_CMN
;
1502 instruction
->type
= ARM_ORR
;
1506 instruction
->type
= ARM_MOV
;
1510 instruction
->type
= ARM_BIC
;
1514 instruction
->type
= ARM_MVN
;
1519 if (I
) /* immediate shifter operand (#<immediate>)*/
1521 uint8_t immed_8
= opcode
& 0xff;
1522 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1525 immediate
= ror(immed_8
, rotate_imm
* 2);
1527 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1529 instruction
->info
.data_proc
.variant
= 0;
1530 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1532 else /* register-based shifter operand */
1535 shift
= (opcode
& 0x60) >> 5;
1536 Rm
= (opcode
& 0xf);
1538 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1541 shift_imm
= (opcode
& 0xf80) >> 7;
1543 instruction
->info
.data_proc
.variant
= 1;
1544 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1545 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1546 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1548 /* LSR encodes a shift by 32 bit as 0x0 */
1549 if ((shift
== 0x1) && (shift_imm
== 0x0))
1552 /* ASR encodes a shift by 32 bit as 0x0 */
1553 if ((shift
== 0x2) && (shift_imm
== 0x0))
1556 /* ROR by 32 bit is actually a RRX */
1557 if ((shift
== 0x3) && (shift_imm
== 0x0))
1560 if ((shift_imm
== 0x0) && (shift
== 0x0))
1562 snprintf(shifter_operand
, 32, "r%i", Rm
);
1566 if (shift
== 0x0) /* LSL */
1568 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1570 else if (shift
== 0x1) /* LSR */
1572 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1574 else if (shift
== 0x2) /* ASR */
1576 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1578 else if (shift
== 0x3) /* ROR */
1580 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1582 else if (shift
== 0x4) /* RRX */
1584 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1588 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1590 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1592 instruction
->info
.data_proc
.variant
= 2;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1594 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1595 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1597 if (shift
== 0x0) /* LSL */
1599 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1601 else if (shift
== 0x1) /* LSR */
1603 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1605 else if (shift
== 0x2) /* ASR */
1607 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1609 else if (shift
== 0x3) /* ROR */
1611 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1616 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1618 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1619 address
, opcode
, mnemonic
, COND(opcode
),
1620 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1622 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1624 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1625 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1627 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1628 address
, opcode
, mnemonic
, COND(opcode
),
1629 (S
) ? "S" : "", Rd
, shifter_operand
);
1631 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1633 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1634 address
, opcode
, mnemonic
, COND(opcode
),
1635 Rn
, shifter_operand
);
1641 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
1643 /* clear fields, to avoid confusion */
1644 memset(instruction
, 0, sizeof(struct arm_instruction
));
1645 instruction
->opcode
= opcode
;
1646 instruction
->instruction_size
= 4;
1648 /* catch opcodes with condition field [31:28] = b1111 */
1649 if ((opcode
& 0xf0000000) == 0xf0000000)
1651 /* Undefined instruction (or ARMv5E cache preload PLD) */
1652 if ((opcode
& 0x08000000) == 0x00000000)
1653 return evaluate_pld(opcode
, address
, instruction
);
1655 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1656 if ((opcode
& 0x0e000000) == 0x08000000)
1657 return evaluate_srs(opcode
, address
, instruction
);
1659 /* Branch and branch with link and change to Thumb */
1660 if ((opcode
& 0x0e000000) == 0x0a000000)
1661 return evaluate_blx_imm(opcode
, address
, instruction
);
1663 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1664 /* Coprocessor load/store and double register transfers */
1665 if ((opcode
& 0x0e000000) == 0x0c000000)
1666 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1668 /* Coprocessor data processing */
1669 if ((opcode
& 0x0f000100) == 0x0c000000)
1670 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1672 /* Coprocessor register transfers */
1673 if ((opcode
& 0x0f000010) == 0x0c000010)
1674 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1676 /* Undefined instruction */
1677 if ((opcode
& 0x0f000000) == 0x0f000000)
1679 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1680 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1685 /* catch opcodes with [27:25] = b000 */
1686 if ((opcode
& 0x0e000000) == 0x00000000)
1688 /* Multiplies, extra load/stores */
1689 if ((opcode
& 0x00000090) == 0x00000090)
1690 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1692 /* Miscellaneous instructions */
1693 if ((opcode
& 0x0f900000) == 0x01000000)
1694 return evaluate_misc_instr(opcode
, address
, instruction
);
1696 return evaluate_data_proc(opcode
, address
, instruction
);
1699 /* catch opcodes with [27:25] = b001 */
1700 if ((opcode
& 0x0e000000) == 0x02000000)
1702 /* Undefined instruction */
1703 if ((opcode
& 0x0fb00000) == 0x03000000)
1705 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1706 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1710 /* Move immediate to status register */
1711 if ((opcode
& 0x0fb00000) == 0x03200000)
1712 return evaluate_mrs_msr(opcode
, address
, instruction
);
1714 return evaluate_data_proc(opcode
, address
, instruction
);
1718 /* catch opcodes with [27:25] = b010 */
1719 if ((opcode
& 0x0e000000) == 0x04000000)
1721 /* Load/store immediate offset */
1722 return evaluate_load_store(opcode
, address
, instruction
);
1725 /* catch opcodes with [27:25] = b011 */
1726 if ((opcode
& 0x0e000000) == 0x06000000)
1728 /* Load/store register offset */
1729 if ((opcode
& 0x00000010) == 0x00000000)
1730 return evaluate_load_store(opcode
, address
, instruction
);
1732 /* Architecturally Undefined instruction
1733 * ... don't expect these to ever be used
1735 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1737 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1738 snprintf(instruction
->text
, 128,
1739 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1744 /* "media" instructions */
1745 return evaluate_media(opcode
, address
, instruction
);
1748 /* catch opcodes with [27:25] = b100 */
1749 if ((opcode
& 0x0e000000) == 0x08000000)
1751 /* Load/store multiple */
1752 return evaluate_ldm_stm(opcode
, address
, instruction
);
1755 /* catch opcodes with [27:25] = b101 */
1756 if ((opcode
& 0x0e000000) == 0x0a000000)
1758 /* Branch and branch with link */
1759 return evaluate_b_bl(opcode
, address
, instruction
);
1762 /* catch opcodes with [27:25] = b110 */
1763 if ((opcode
& 0x0e000000) == 0x0a000000)
1765 /* Coprocessor load/store and double register transfers */
1766 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1769 /* catch opcodes with [27:25] = b111 */
1770 if ((opcode
& 0x0e000000) == 0x0e000000)
1772 /* Software interrupt */
1773 if ((opcode
& 0x0f000000) == 0x0f000000)
1774 return evaluate_swi(opcode
, address
, instruction
);
1776 /* Coprocessor data processing */
1777 if ((opcode
& 0x0f000010) == 0x0e000000)
1778 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1780 /* Coprocessor register transfers */
1781 if ((opcode
& 0x0f000010) == 0x0e000010)
1782 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1785 LOG_ERROR("should never reach this point");
1789 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1790 uint32_t address
, struct arm_instruction
*instruction
)
1792 uint32_t offset
= opcode
& 0x7ff;
1793 uint32_t opc
= (opcode
>> 11) & 0x3;
1794 uint32_t target_address
;
1795 char *mnemonic
= NULL
;
1797 /* sign extend 11-bit offset */
1798 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1799 offset
= 0xfffff800 | offset
;
1801 target_address
= address
+ 4 + (offset
<< 1);
1805 /* unconditional branch */
1807 instruction
->type
= ARM_B
;
1812 instruction
->type
= ARM_BLX
;
1814 target_address
&= 0xfffffffc;
1818 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1819 mnemonic
= "prefix";
1820 target_address
= offset
<< 12;
1824 instruction
->type
= ARM_BL
;
1829 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1830 * these are effectively 32-bit instructions even in Thumb1. For
1831 * disassembly, it's simplest to always use the Thumb2 decoder.
1833 * But some cores will evidently handle them as two instructions,
1834 * where exceptions may occur between the two. The ETMv3.2+ ID
1835 * register has a bit which exposes this behavior.
1838 snprintf(instruction
->text
, 128,
1839 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1840 address
, opcode
, mnemonic
, target_address
);
1842 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1843 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1848 static int evaluate_add_sub_thumb(uint16_t opcode
,
1849 uint32_t address
, struct arm_instruction
*instruction
)
1851 uint8_t Rd
= (opcode
>> 0) & 0x7;
1852 uint8_t Rn
= (opcode
>> 3) & 0x7;
1853 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1854 uint32_t opc
= opcode
& (1 << 9);
1855 uint32_t reg_imm
= opcode
& (1 << 10);
1860 instruction
->type
= ARM_SUB
;
1865 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1866 instruction
->type
= ARM_ADD
;
1870 instruction
->info
.data_proc
.Rd
= Rd
;
1871 instruction
->info
.data_proc
.Rn
= Rn
;
1872 instruction
->info
.data_proc
.S
= 1;
1876 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1877 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1878 snprintf(instruction
->text
, 128,
1879 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1880 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1884 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1885 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1886 snprintf(instruction
->text
, 128,
1887 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1888 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1894 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1895 uint32_t address
, struct arm_instruction
*instruction
)
1897 uint8_t Rd
= (opcode
>> 0) & 0x7;
1898 uint8_t Rm
= (opcode
>> 3) & 0x7;
1899 uint8_t imm
= (opcode
>> 6) & 0x1f;
1900 uint8_t opc
= (opcode
>> 11) & 0x3;
1901 char *mnemonic
= NULL
;
1906 instruction
->type
= ARM_MOV
;
1908 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1911 instruction
->type
= ARM_MOV
;
1913 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1916 instruction
->type
= ARM_MOV
;
1918 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1922 if ((imm
== 0) && (opc
!= 0))
1925 instruction
->info
.data_proc
.Rd
= Rd
;
1926 instruction
->info
.data_proc
.Rn
= -1;
1927 instruction
->info
.data_proc
.S
= 1;
1929 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1930 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1931 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1933 snprintf(instruction
->text
, 128,
1934 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1935 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1940 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1941 uint32_t address
, struct arm_instruction
*instruction
)
1943 uint8_t imm
= opcode
& 0xff;
1944 uint8_t Rd
= (opcode
>> 8) & 0x7;
1945 uint32_t opc
= (opcode
>> 11) & 0x3;
1946 char *mnemonic
= NULL
;
1948 instruction
->info
.data_proc
.Rd
= Rd
;
1949 instruction
->info
.data_proc
.Rn
= Rd
;
1950 instruction
->info
.data_proc
.S
= 1;
1951 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1952 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1957 instruction
->type
= ARM_MOV
;
1959 instruction
->info
.data_proc
.Rn
= -1;
1962 instruction
->type
= ARM_CMP
;
1964 instruction
->info
.data_proc
.Rd
= -1;
1967 instruction
->type
= ARM_ADD
;
1971 instruction
->type
= ARM_SUB
;
1976 snprintf(instruction
->text
, 128,
1977 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1978 address
, opcode
, mnemonic
, Rd
, imm
);
1983 static int evaluate_data_proc_thumb(uint16_t opcode
,
1984 uint32_t address
, struct arm_instruction
*instruction
)
1986 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1987 char *mnemonic
= NULL
;
1990 high_reg
= (opcode
& 0x0400) >> 10;
1991 op
= (opcode
& 0x03C0) >> 6;
1993 Rd
= (opcode
& 0x0007);
1994 Rm
= (opcode
& 0x0038) >> 3;
1995 H1
= (opcode
& 0x0080) >> 7;
1996 H2
= (opcode
& 0x0040) >> 6;
1998 instruction
->info
.data_proc
.Rd
= Rd
;
1999 instruction
->info
.data_proc
.Rn
= Rd
;
2000 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2001 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2002 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2013 instruction
->type
= ARM_ADD
;
2017 instruction
->type
= ARM_CMP
;
2021 instruction
->type
= ARM_MOV
;
2027 if ((opcode
& 0x7) == 0x0)
2029 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2032 instruction
->type
= ARM_BLX
;
2033 snprintf(instruction
->text
, 128,
2035 " 0x%4.4x \tBLX\tr%i",
2036 address
, opcode
, Rm
);
2040 instruction
->type
= ARM_BX
;
2041 snprintf(instruction
->text
, 128,
2043 " 0x%4.4x \tBX\tr%i",
2044 address
, opcode
, Rm
);
2049 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2050 snprintf(instruction
->text
, 128,
2053 "UNDEFINED INSTRUCTION",
2065 instruction
->type
= ARM_AND
;
2069 instruction
->type
= ARM_EOR
;
2073 instruction
->type
= ARM_MOV
;
2075 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2076 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2077 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2078 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2081 instruction
->type
= ARM_MOV
;
2083 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2084 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2085 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2086 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2089 instruction
->type
= ARM_MOV
;
2091 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2092 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2093 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2094 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2097 instruction
->type
= ARM_ADC
;
2101 instruction
->type
= ARM_SBC
;
2105 instruction
->type
= ARM_MOV
;
2107 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2108 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2109 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2110 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2113 instruction
->type
= ARM_TST
;
2117 instruction
->type
= ARM_RSB
;
2119 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2120 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2121 instruction
->info
.data_proc
.Rn
= Rm
;
2124 instruction
->type
= ARM_CMP
;
2128 instruction
->type
= ARM_CMN
;
2132 instruction
->type
= ARM_ORR
;
2136 instruction
->type
= ARM_MUL
;
2140 instruction
->type
= ARM_BIC
;
2144 instruction
->type
= ARM_MVN
;
2151 snprintf(instruction
->text
, 128,
2152 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2154 address
, opcode
, mnemonic
, Rd
, Rm
);
2156 snprintf(instruction
->text
, 128,
2157 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2158 address
, opcode
, mnemonic
, Rd
, Rm
);
2163 /* PC-relative data addressing is word-aligned even with Thumb */
2164 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2166 return (addr
+ 4) & ~3;
2169 static int evaluate_load_literal_thumb(uint16_t opcode
,
2170 uint32_t address
, struct arm_instruction
*instruction
)
2173 uint8_t Rd
= (opcode
>> 8) & 0x7;
2175 instruction
->type
= ARM_LDR
;
2176 immediate
= opcode
& 0x000000ff;
2179 instruction
->info
.load_store
.Rd
= Rd
;
2180 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2181 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2182 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2183 instruction
->info
.load_store
.offset
.offset
= immediate
;
2185 snprintf(instruction
->text
, 128,
2186 "0x%8.8" PRIx32
" 0x%4.4x \t"
2187 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2188 address
, opcode
, Rd
, immediate
,
2189 thumb_alignpc4(address
) + immediate
);
2194 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2195 uint32_t address
, struct arm_instruction
*instruction
)
2197 uint8_t Rd
= (opcode
>> 0) & 0x7;
2198 uint8_t Rn
= (opcode
>> 3) & 0x7;
2199 uint8_t Rm
= (opcode
>> 6) & 0x7;
2200 uint8_t opc
= (opcode
>> 9) & 0x7;
2201 char *mnemonic
= NULL
;
2206 instruction
->type
= ARM_STR
;
2210 instruction
->type
= ARM_STRH
;
2214 instruction
->type
= ARM_STRB
;
2218 instruction
->type
= ARM_LDRSB
;
2222 instruction
->type
= ARM_LDR
;
2226 instruction
->type
= ARM_LDRH
;
2230 instruction
->type
= ARM_LDRB
;
2234 instruction
->type
= ARM_LDRSH
;
2239 snprintf(instruction
->text
, 128,
2240 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2241 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2243 instruction
->info
.load_store
.Rd
= Rd
;
2244 instruction
->info
.load_store
.Rn
= Rn
;
2245 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2246 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2247 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2252 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2253 uint32_t address
, struct arm_instruction
*instruction
)
2255 uint32_t offset
= (opcode
>> 6) & 0x1f;
2256 uint8_t Rd
= (opcode
>> 0) & 0x7;
2257 uint8_t Rn
= (opcode
>> 3) & 0x7;
2258 uint32_t L
= opcode
& (1 << 11);
2259 uint32_t B
= opcode
& (1 << 12);
2266 instruction
->type
= ARM_LDR
;
2271 instruction
->type
= ARM_STR
;
2275 if ((opcode
&0xF000) == 0x8000)
2286 snprintf(instruction
->text
, 128,
2287 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2288 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2290 instruction
->info
.load_store
.Rd
= Rd
;
2291 instruction
->info
.load_store
.Rn
= Rn
;
2292 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2293 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2294 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2299 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2300 uint32_t address
, struct arm_instruction
*instruction
)
2302 uint32_t offset
= opcode
& 0xff;
2303 uint8_t Rd
= (opcode
>> 8) & 0x7;
2304 uint32_t L
= opcode
& (1 << 11);
2309 instruction
->type
= ARM_LDR
;
2314 instruction
->type
= ARM_STR
;
2318 snprintf(instruction
->text
, 128,
2319 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2320 address
, opcode
, mnemonic
, Rd
, offset
*4);
2322 instruction
->info
.load_store
.Rd
= Rd
;
2323 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2324 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2325 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2326 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2331 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2332 uint32_t address
, struct arm_instruction
*instruction
)
2334 uint32_t imm
= opcode
& 0xff;
2335 uint8_t Rd
= (opcode
>> 8) & 0x7;
2337 uint32_t SP
= opcode
& (1 << 11);
2340 instruction
->type
= ARM_ADD
;
2353 snprintf(instruction
->text
, 128,
2354 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2355 address
, opcode
, Rd
, reg_name
, imm
* 4);
2357 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2358 instruction
->info
.data_proc
.Rd
= Rd
;
2359 instruction
->info
.data_proc
.Rn
= Rn
;
2360 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2365 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2366 uint32_t address
, struct arm_instruction
*instruction
)
2368 uint32_t imm
= opcode
& 0x7f;
2369 uint8_t opc
= opcode
& (1 << 7);
2375 instruction
->type
= ARM_SUB
;
2380 instruction
->type
= ARM_ADD
;
2384 snprintf(instruction
->text
, 128,
2385 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2386 address
, opcode
, mnemonic
, imm
*4);
2388 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2389 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2390 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2391 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2396 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2397 uint32_t address
, struct arm_instruction
*instruction
)
2399 uint32_t imm
= opcode
& 0xff;
2401 instruction
->type
= ARM_BKPT
;
2403 snprintf(instruction
->text
, 128,
2404 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2405 address
, opcode
, imm
);
2410 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2411 uint32_t address
, struct arm_instruction
*instruction
)
2413 uint32_t reg_list
= opcode
& 0xff;
2414 uint32_t L
= opcode
& (1 << 11);
2415 uint32_t R
= opcode
& (1 << 8);
2416 uint8_t Rn
= (opcode
>> 8) & 7;
2417 uint8_t addr_mode
= 0 /* IA */;
2421 char ptr_name
[7] = "";
2424 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2425 * The STMIA and LDMIA opcodes are used for other instructions.
2428 if ((opcode
& 0xf000) == 0xc000)
2429 { /* generic load/store multiple */
2434 instruction
->type
= ARM_LDM
;
2436 if (opcode
& (1 << Rn
))
2441 instruction
->type
= ARM_STM
;
2444 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2451 instruction
->type
= ARM_LDM
;
2454 reg_list
|= (1 << 15) /*PC*/;
2458 instruction
->type
= ARM_STM
;
2460 addr_mode
= 3; /*DB*/
2462 reg_list
|= (1 << 14) /*LR*/;
2466 reg_names_p
= reg_names
;
2467 for (i
= 0; i
<= 15; i
++)
2469 if (reg_list
& (1 << i
))
2470 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2472 if (reg_names_p
> reg_names
)
2473 reg_names_p
[-2] = '\0';
2474 else /* invalid op : no registers */
2475 reg_names
[0] = '\0';
2477 snprintf(instruction
->text
, 128,
2478 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2479 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2481 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2482 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2483 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2488 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2489 uint32_t address
, struct arm_instruction
*instruction
)
2491 uint32_t offset
= opcode
& 0xff;
2492 uint8_t cond
= (opcode
>> 8) & 0xf;
2493 uint32_t target_address
;
2497 instruction
->type
= ARM_SWI
;
2498 snprintf(instruction
->text
, 128,
2499 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2500 address
, opcode
, offset
);
2503 else if (cond
== 0xe)
2505 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2506 snprintf(instruction
->text
, 128,
2507 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2512 /* sign extend 8-bit offset */
2513 if (offset
& 0x00000080)
2514 offset
= 0xffffff00 | offset
;
2516 target_address
= address
+ 4 + (offset
<< 1);
2518 snprintf(instruction
->text
, 128,
2519 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2521 arm_condition_strings
[cond
], target_address
);
2523 instruction
->type
= ARM_B
;
2524 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2525 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2530 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2531 struct arm_instruction
*instruction
)
2535 /* added in Thumb2 */
2536 offset
= (opcode
>> 3) & 0x1f;
2537 offset
|= (opcode
& 0x0200) >> 4;
2539 snprintf(instruction
->text
, 128,
2540 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2542 (opcode
& 0x0800) ? "N" : "",
2543 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2548 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2549 struct arm_instruction
*instruction
)
2551 /* added in ARMv6 */
2552 snprintf(instruction
->text
, 128,
2553 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2555 (opcode
& 0x0080) ? 'U' : 'S',
2556 (opcode
& 0x0040) ? 'B' : 'H',
2557 opcode
& 0x7, (opcode
>> 3) & 0x7);
2562 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2563 struct arm_instruction
*instruction
)
2565 /* added in ARMv6 */
2566 if ((opcode
& 0x0ff0) == 0x0650)
2567 snprintf(instruction
->text
, 128,
2568 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2570 (opcode
& 0x80) ? "BE" : "LE");
2571 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2572 snprintf(instruction
->text
, 128,
2573 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2575 (opcode
& 0x0010) ? 'D' : 'E',
2576 (opcode
& 0x0004) ? "A" : "",
2577 (opcode
& 0x0002) ? "I" : "",
2578 (opcode
& 0x0001) ? "F" : "");
2583 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2584 struct arm_instruction
*instruction
)
2588 /* added in ARMv6 */
2589 switch ((opcode
>> 6) & 3) {
2600 snprintf(instruction
->text
, 128,
2601 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2602 address
, opcode
, suffix
,
2603 opcode
& 0x7, (opcode
>> 3) & 0x7);
2608 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2609 struct arm_instruction
*instruction
)
2613 switch ((opcode
>> 4) & 0x0f) {
2630 hint
= "HINT (UNRECOGNIZED)";
2634 snprintf(instruction
->text
, 128,
2635 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2636 address
, opcode
, hint
);
2641 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2642 struct arm_instruction
*instruction
)
2644 unsigned cond
= (opcode
>> 4) & 0x0f;
2645 char *x
= "", *y
= "", *z
= "";
2648 z
= (opcode
& 0x02) ? "T" : "E";
2650 y
= (opcode
& 0x04) ? "T" : "E";
2652 x
= (opcode
& 0x08) ? "T" : "E";
2654 snprintf(instruction
->text
, 128,
2655 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2657 x
, y
, z
, arm_condition_strings
[cond
]);
2659 /* NOTE: strictly speaking, the next 1-4 instructions should
2660 * now be displayed with the relevant conditional suffix...
2666 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2668 /* clear fields, to avoid confusion */
2669 memset(instruction
, 0, sizeof(struct arm_instruction
));
2670 instruction
->opcode
= opcode
;
2671 instruction
->instruction_size
= 2;
2673 if ((opcode
& 0xe000) == 0x0000)
2675 /* add/substract register or immediate */
2676 if ((opcode
& 0x1800) == 0x1800)
2677 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2678 /* shift by immediate */
2680 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2683 /* Add/substract/compare/move immediate */
2684 if ((opcode
& 0xe000) == 0x2000)
2686 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2689 /* Data processing instructions */
2690 if ((opcode
& 0xf800) == 0x4000)
2692 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2695 /* Load from literal pool */
2696 if ((opcode
& 0xf800) == 0x4800)
2698 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2701 /* Load/Store register offset */
2702 if ((opcode
& 0xf000) == 0x5000)
2704 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2707 /* Load/Store immediate offset */
2708 if (((opcode
& 0xe000) == 0x6000)
2709 ||((opcode
& 0xf000) == 0x8000))
2711 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2714 /* Load/Store from/to stack */
2715 if ((opcode
& 0xf000) == 0x9000)
2717 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2721 if ((opcode
& 0xf000) == 0xa000)
2723 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2727 if ((opcode
& 0xf000) == 0xb000)
2729 switch ((opcode
>> 8) & 0x0f) {
2731 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2736 return evaluate_cb_thumb(opcode
, address
, instruction
);
2738 return evaluate_extend_thumb(opcode
, address
, instruction
);
2743 return evaluate_load_store_multiple_thumb(opcode
, address
,
2746 return evaluate_cps_thumb(opcode
, address
, instruction
);
2748 if ((opcode
& 0x00c0) == 0x0080)
2750 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2752 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2754 if (opcode
& 0x000f)
2755 return evaluate_ifthen_thumb(opcode
, address
,
2758 return evaluate_hint_thumb(opcode
, address
,
2762 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2763 snprintf(instruction
->text
, 128,
2764 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2769 /* Load/Store multiple */
2770 if ((opcode
& 0xf000) == 0xc000)
2772 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2775 /* Conditional branch + SWI */
2776 if ((opcode
& 0xf000) == 0xd000)
2778 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2781 if ((opcode
& 0xe000) == 0xe000)
2783 /* Undefined instructions */
2784 if ((opcode
& 0xf801) == 0xe801)
2786 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2787 snprintf(instruction
->text
, 128,
2788 "0x%8.8" PRIx32
" 0x%8.8x\t"
2789 "UNDEFINED INSTRUCTION",
2794 { /* Branch to offset */
2795 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2799 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2803 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2804 struct arm_instruction
*instruction
, char *cp
)
2807 unsigned b21
= 1 << 21;
2808 unsigned b22
= 1 << 22;
2810 /* instead of combining two smaller 16-bit branch instructions,
2811 * Thumb2 uses only one larger 32-bit instruction.
2813 offset
= opcode
& 0x7ff;
2814 offset
|= (opcode
& 0x03ff0000) >> 5;
2815 if (opcode
& (1 << 26)) {
2816 offset
|= 0xff << 23;
2817 if ((opcode
& (1 << 11)) == 0)
2819 if ((opcode
& (1 << 13)) == 0)
2822 if (opcode
& (1 << 11))
2824 if (opcode
& (1 << 13))
2832 address
+= offset
<< 1;
2834 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2835 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2836 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2837 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2838 (opcode
& (1 << 14)) ? "BL" : "B.W",
2844 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2845 struct arm_instruction
*instruction
, char *cp
)
2848 unsigned b17
= 1 << 17;
2849 unsigned b18
= 1 << 18;
2850 unsigned cond
= (opcode
>> 22) & 0x0f;
2852 offset
= opcode
& 0x7ff;
2853 offset
|= (opcode
& 0x003f0000) >> 5;
2854 if (opcode
& (1 << 26)) {
2855 offset
|= 0xffff << 19;
2856 if ((opcode
& (1 << 11)) == 0)
2858 if ((opcode
& (1 << 13)) == 0)
2861 if (opcode
& (1 << 11))
2863 if (opcode
& (1 << 13))
2870 address
+= offset
<< 1;
2872 instruction
->type
= ARM_B
;
2873 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2874 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2875 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2876 arm_condition_strings
[cond
],
2882 static const char *special_name(int number
)
2884 char *special
= "(RESERVED)";
2915 special
= "primask";
2918 special
= "basepri";
2921 special
= "basepri_max";
2924 special
= "faultmask";
2927 special
= "control";
2933 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2934 struct arm_instruction
*instruction
, char *cp
)
2936 const char *mnemonic
;
2938 if (opcode
& 0x0700) {
2939 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2940 strcpy(cp
, "UNDEFINED");
2944 if (opcode
& 0x00f0) {
2945 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2949 switch (opcode
& 0x0f) {
2954 mnemonic
= "YIELD.W";
2966 mnemonic
= "HINT.W (UNRECOGNIZED)";
2969 strcpy(cp
, mnemonic
);
2973 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2974 struct arm_instruction
*instruction
, char *cp
)
2976 const char *mnemonic
;
2978 switch ((opcode
>> 4) & 0x0f) {
2980 mnemonic
= "LEAVEX";
2983 mnemonic
= "ENTERX";
2998 return ERROR_INVALID_ARGUMENTS
;
3000 strcpy(cp
, mnemonic
);
3004 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3005 struct arm_instruction
*instruction
, char *cp
)
3007 /* permanently undefined */
3008 if ((opcode
& 0x07f07000) == 0x07f02000) {
3009 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3010 strcpy(cp
, "UNDEFINED");
3014 switch ((opcode
>> 12) & 0x5) {
3017 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3021 if (((opcode
>> 23) & 0x07) != 0x07)
3022 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3023 if (opcode
& (1 << 26))
3028 switch ((opcode
>> 20) & 0x7f) {
3031 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3032 (int) (opcode
>> 16) & 0x0f);
3035 return t2ev_hint(opcode
, address
, instruction
, cp
);
3037 return t2ev_misc(opcode
, address
, instruction
, cp
);
3039 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3043 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3044 special_name(opcode
& 0xff));
3049 return ERROR_INVALID_ARGUMENTS
;
3052 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3053 struct arm_instruction
*instruction
, char *cp
)
3055 char *mnemonic
= NULL
;
3056 int rn
= (opcode
>> 16) & 0xf;
3057 int rd
= (opcode
>> 8) & 0xf;
3058 unsigned immed
= opcode
& 0xff;
3064 /* ARMv7-M: A5.3.2 Modified immediate constants */
3065 func
= (opcode
>> 11) & 0x0e;
3068 if (opcode
& (1 << 26))
3071 /* "Modified" immediates */
3072 switch (func
>> 1) {
3079 immed
+= immed
<< 16;
3082 immed
+= immed
<< 8;
3083 immed
+= immed
<< 16;
3087 immed
= ror(immed
, func
);
3090 if (opcode
& (1 << 20))
3093 switch ((opcode
>> 21) & 0xf) {
3096 instruction
->type
= ARM_TST
;
3102 instruction
->type
= ARM_AND
;
3107 instruction
->type
= ARM_BIC
;
3112 instruction
->type
= ARM_MOV
;
3117 instruction
->type
= ARM_ORR
;
3123 instruction
->type
= ARM_MVN
;
3127 // instruction->type = ARM_ORN;
3133 instruction
->type
= ARM_TEQ
;
3139 instruction
->type
= ARM_EOR
;
3145 instruction
->type
= ARM_CMN
;
3151 instruction
->type
= ARM_ADD
;
3157 instruction
->type
= ARM_ADC
;
3162 instruction
->type
= ARM_SBC
;
3167 instruction
->type
= ARM_CMP
;
3173 instruction
->type
= ARM_SUB
;
3179 instruction
->type
= ARM_RSB
;
3184 return ERROR_INVALID_ARGUMENTS
;
3188 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3189 mnemonic
, suffix2
,rd
, immed
, immed
);
3191 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3192 mnemonic
, suffix
, suffix2
,
3193 rd
, rn
, immed
, immed
);
3198 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3199 struct arm_instruction
*instruction
, char *cp
)
3201 char *mnemonic
= NULL
;
3202 int rn
= (opcode
>> 16) & 0xf;
3203 int rd
= (opcode
>> 8) & 0xf;
3206 bool is_signed
= false;
3208 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3209 if (opcode
& (1 << 26))
3212 switch ((opcode
>> 20) & 0x1f) {
3221 immed
|= (opcode
>> 4) & 0xf000;
3222 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3230 /* move constant to top 16 bits of register */
3231 immed
|= (opcode
>> 4) & 0xf000;
3232 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3239 /* signed/unsigned saturated add */
3240 immed
= (opcode
>> 6) & 0x03;
3241 immed
|= (opcode
>> 10) & 0x1c;
3242 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3243 is_signed
? "S" : "U",
3244 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3245 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3246 immed
? immed
: 32);
3252 /* signed/unsigned bitfield extract */
3253 immed
= (opcode
>> 6) & 0x03;
3254 immed
|= (opcode
>> 10) & 0x1c;
3255 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3256 is_signed
? "S" : "U",
3258 (int) (opcode
& 0x1f) + 1);
3261 immed
= (opcode
>> 6) & 0x03;
3262 immed
|= (opcode
>> 10) & 0x1c;
3263 if (rn
== 0xf) /* bitfield clear */
3264 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3266 (int) (opcode
& 0x1f) + 1 - immed
);
3267 else /* bitfield insert */
3268 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3270 (int) (opcode
& 0x1f) + 1 - immed
);
3273 return ERROR_INVALID_ARGUMENTS
;
3276 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3277 rd
, rn
, immed
, immed
);
3281 address
= thumb_alignpc4(address
);
3286 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3287 * not hiding the pc-relative stuff will sometimes be useful.
3289 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3293 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3294 struct arm_instruction
*instruction
, char *cp
)
3296 unsigned op
= (opcode
>> 20) & 0xf;
3302 unsigned rn
= (opcode
>> 16) & 0x0f;
3303 unsigned rt
= (opcode
>> 12) & 0x0f;
3306 return ERROR_INVALID_ARGUMENTS
;
3308 if (opcode
& 0x0800)
3343 return ERROR_INVALID_ARGUMENTS
;
3346 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3347 size
, rt
, rn
, (int) opcode
& 0x0f,
3348 (int) (opcode
>> 4) & 0x03);
3352 immed
= opcode
& 0x0fff;
3353 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3354 size
, rt
, rn
, immed
, immed
);
3358 immed
= opcode
& 0x00ff;
3360 switch (opcode
& 0x700) {
3366 return ERROR_INVALID_ARGUMENTS
;
3369 /* two indexed modes will write back rn */
3370 if (opcode
& 0x100) {
3371 if (opcode
& 0x400) /* pre-indexed */
3373 else { /* post-indexed */
3379 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3380 size
, suffix
, rt
, rn
, p1
,
3381 (opcode
& 0x200) ? "" : "-",
3386 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3387 struct arm_instruction
*instruction
, char *cp
)
3389 int ra
= (opcode
>> 12) & 0xf;
3391 switch (opcode
& 0x007000f0) {
3394 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3395 (int) (opcode
>> 8) & 0xf,
3396 (int) (opcode
>> 16) & 0xf,
3397 (int) (opcode
>> 0) & 0xf);
3399 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3400 (int) (opcode
>> 8) & 0xf,
3401 (int) (opcode
>> 16) & 0xf,
3402 (int) (opcode
>> 0) & 0xf, ra
);
3405 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3406 (int) (opcode
>> 8) & 0xf,
3407 (int) (opcode
>> 16) & 0xf,
3408 (int) (opcode
>> 0) & 0xf, ra
);
3411 return ERROR_INVALID_ARGUMENTS
;
3416 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3417 struct arm_instruction
*instruction
, char *cp
)
3419 int op
= (opcode
>> 4) & 0xf;
3420 char *infix
= "MUL";
3422 op
+= (opcode
>> 16) & 0x70;
3430 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3431 (op
& 0x20) ? 'U' : 'S',
3433 (int) (opcode
>> 12) & 0xf,
3434 (int) (opcode
>> 8) & 0xf,
3435 (int) (opcode
>> 16) & 0xf,
3436 (int) (opcode
>> 0) & 0xf);
3440 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3441 (op
& 0x20) ? 'U' : 'S',
3442 (int) (opcode
>> 8) & 0xf,
3443 (int) (opcode
>> 16) & 0xf,
3444 (int) (opcode
>> 0) & 0xf);
3447 return ERROR_INVALID_ARGUMENTS
;
3453 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3454 struct arm_instruction
*instruction
, char *cp
)
3456 int rn
= (opcode
>> 16) & 0xf;
3457 int op
= (opcode
>> 22) & 0x6;
3458 int t
= (opcode
>> 21) & 1;
3459 unsigned registers
= opcode
& 0xffff;
3462 if (opcode
& (1 << 20))
3470 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3472 (unsigned) (opcode
& 0x1f));
3478 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3479 (unsigned) ((opcode
>> 16) & 0xf),
3483 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3487 sprintf(cp
, "POP.W\t");
3489 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3493 sprintf(cp
, "PUSH.W\t");
3495 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3498 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3501 return ERROR_INVALID_ARGUMENTS
;
3506 for (t
= 0; registers
; t
++, registers
>>= 1) {
3507 if ((registers
& 1) == 0)
3510 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3519 /* load/store dual or exclusive, table branch */
3520 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3521 struct arm_instruction
*instruction
, char *cp
)
3523 unsigned op1op2
= (opcode
>> 20) & 0x3;
3524 unsigned op3
= (opcode
>> 4) & 0xf;
3526 unsigned rn
= (opcode
>> 16) & 0xf;
3527 unsigned rt
= (opcode
>> 12) & 0xf;
3528 unsigned rd
= (opcode
>> 8) & 0xf;
3529 unsigned imm
= opcode
& 0xff;
3533 op1op2
|= (opcode
>> 21) & 0xc;
3563 mnemonic
= "STREXB";
3566 mnemonic
= "STREXH";
3569 return ERROR_INVALID_ARGUMENTS
;
3577 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3580 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3583 mnemonic
= "LDREXB";
3586 mnemonic
= "LDREXH";
3589 return ERROR_INVALID_ARGUMENTS
;
3594 return ERROR_INVALID_ARGUMENTS
;
3599 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3600 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3602 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3603 mnemonic
, rd
, rt
, rn
);
3609 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3610 mnemonic
, rt
, rn
, imm
, imm
);
3612 sprintf(cp
, "%s\tr%u, [r%u]",
3617 /* two indexed modes will write back rn */
3618 if (opcode
& (1 << 21)) {
3619 if (opcode
& (1 << 24)) /* pre-indexed */
3621 else { /* post-indexed */
3628 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3629 mnemonic
, rt
, rd
, rn
, p1
,
3630 (opcode
& (1 << 23)) ? "" : "-",
3635 address
= thumb_alignpc4(address
);
3637 if (opcode
& (1 << 23))
3641 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3642 mnemonic
, rt
, rd
, address
);
3646 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3647 struct arm_instruction
*instruction
, char *cp
)
3649 int op
= (opcode
>> 21) & 0xf;
3650 int rd
= (opcode
>> 8) & 0xf;
3651 int rn
= (opcode
>> 16) & 0xf;
3652 int type
= (opcode
>> 4) & 0x3;
3653 int immed
= (opcode
>> 6) & 0x3;
3657 immed
|= (opcode
>> 10) & 0x1c;
3658 if (opcode
& (1 << 20))
3664 if (!(opcode
& (1 << 20)))
3665 return ERROR_INVALID_ARGUMENTS
;
3666 instruction
->type
= ARM_TST
;
3671 instruction
->type
= ARM_AND
;
3675 instruction
->type
= ARM_BIC
;
3680 instruction
->type
= ARM_MOV
;
3684 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3686 (int) (opcode
& 0xf));
3699 sprintf(cp
, "RRX%s\tr%d, r%d",
3701 (int) (opcode
& 0xf));
3709 instruction
->type
= ARM_ORR
;
3715 instruction
->type
= ARM_MVN
;
3720 // instruction->type = ARM_ORN;
3726 if (!(opcode
& (1 << 20)))
3727 return ERROR_INVALID_ARGUMENTS
;
3728 instruction
->type
= ARM_TEQ
;
3733 instruction
->type
= ARM_EOR
;
3738 if (!(opcode
& (1 << 20)))
3739 return ERROR_INVALID_ARGUMENTS
;
3740 instruction
->type
= ARM_CMN
;
3745 instruction
->type
= ARM_ADD
;
3749 instruction
->type
= ARM_ADC
;
3753 instruction
->type
= ARM_SBC
;
3758 if (!(opcode
& (1 << 21)))
3759 return ERROR_INVALID_ARGUMENTS
;
3760 instruction
->type
= ARM_CMP
;
3765 instruction
->type
= ARM_SUB
;
3769 instruction
->type
= ARM_RSB
;
3773 return ERROR_INVALID_ARGUMENTS
;
3776 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3777 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3800 strcpy(cp
, ", RRX");
3806 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3810 sprintf(cp
, "%s%s.W\tr%d, r%d",
3811 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3815 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3816 mnemonic
, suffix
, rd
,
3817 (int) (opcode
& 0xf), immed
? immed
: 32);
3821 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3822 struct arm_instruction
*instruction
, char *cp
)
3827 if (((opcode
>> 4) & 0xf) == 0) {
3828 switch ((opcode
>> 21) & 0x7) {
3842 return ERROR_INVALID_ARGUMENTS
;
3845 instruction
->type
= ARM_MOV
;
3846 if (opcode
& (1 << 20))
3848 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3850 (int) (opcode
>> 8) & 0xf,
3851 (int) (opcode
>> 16) & 0xf,
3852 (int) (opcode
>> 0) & 0xf);
3854 } else if (opcode
& (1 << 7)) {
3855 switch ((opcode
>> 20) & 0xf) {
3860 switch ((opcode
>> 4) & 0x3) {
3862 suffix
= ", ROR #8";
3865 suffix
= ", ROR #16";
3868 suffix
= ", ROR #24";
3871 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3872 (opcode
& (1 << 24)) ? 'U' : 'S',
3873 (opcode
& (1 << 26)) ? 'B' : 'H',
3874 (int) (opcode
>> 8) & 0xf,
3875 (int) (opcode
>> 0) & 0xf,
3882 if (opcode
& (1 << 6))
3883 return ERROR_INVALID_ARGUMENTS
;
3884 if (((opcode
>> 12) & 0xf) != 0xf)
3885 return ERROR_INVALID_ARGUMENTS
;
3886 if (!(opcode
& (1 << 20)))
3887 return ERROR_INVALID_ARGUMENTS
;
3889 switch (((opcode
>> 19) & 0x04)
3890 | ((opcode
>> 4) & 0x3)) {
3895 mnemonic
= "REV16.W";
3901 mnemonic
= "REVSH.W";
3907 return ERROR_INVALID_ARGUMENTS
;
3909 sprintf(cp
, "%s\tr%d, r%d",
3911 (int) (opcode
>> 8) & 0xf,
3912 (int) (opcode
>> 0) & 0xf);
3915 return ERROR_INVALID_ARGUMENTS
;
3922 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3923 struct arm_instruction
*instruction
, char *cp
)
3925 int rn
= (opcode
>> 16) & 0xf;
3928 instruction
->type
= ARM_LDR
;
3931 immed
= opcode
& 0x0fff;
3932 if ((opcode
& (1 << 23)) == 0)
3934 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3935 (int) (opcode
>> 12) & 0xf,
3936 thumb_alignpc4(address
) + immed
);
3940 if (opcode
& (1 << 23)) {
3941 immed
= opcode
& 0x0fff;
3942 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3943 (int) (opcode
>> 12) & 0xf,
3948 if (!(opcode
& (0x3f << 6))) {
3949 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3950 (int) (opcode
>> 12) & 0xf,
3952 (int) (opcode
>> 0) & 0xf,
3953 (int) (opcode
>> 4) & 0x3);
3958 if (((opcode
>> 8) & 0xf) == 0xe) {
3959 immed
= opcode
& 0x00ff;
3961 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3962 (int) (opcode
>> 12) & 0xf,
3967 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3968 char *p1
= "]", *p2
= "";
3970 if (!(opcode
& 0x0500))
3971 return ERROR_INVALID_ARGUMENTS
;
3973 immed
= opcode
& 0x00ff;
3975 /* two indexed modes will write back rn */
3976 if (opcode
& 0x100) {
3977 if (opcode
& 0x400) /* pre-indexed */
3979 else { /* post-indexed */
3985 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3986 (int) (opcode
>> 12) & 0xf,
3988 (opcode
& 0x200) ? "" : "-",
3993 return ERROR_INVALID_ARGUMENTS
;
3996 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3997 struct arm_instruction
*instruction
, char *cp
)
3999 int rn
= (opcode
>> 16) & 0xf;
4000 int rt
= (opcode
>> 12) & 0xf;
4001 int op2
= (opcode
>> 6) & 0x3f;
4003 char *p1
= "", *p2
= "]";
4006 switch ((opcode
>> 23) & 0x3) {
4008 if ((rn
& rt
) == 0xf) {
4010 immed
= opcode
& 0xfff;
4011 address
= thumb_alignpc4(address
);
4012 if (opcode
& (1 << 23))
4016 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4020 if (rn
== 0x0f && rt
!= 0x0f) {
4022 immed
= opcode
& 0xfff;
4023 address
= thumb_alignpc4(address
);
4024 if (opcode
& (1 << 23))
4028 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4034 if ((op2
& 0x3c) == 0x38) {
4035 immed
= opcode
& 0xff;
4036 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4037 rt
, rn
, immed
, immed
);
4040 if ((op2
& 0x3c) == 0x30) {
4042 immed
= opcode
& 0xff;
4045 p1
= (opcode
& (1 << 21)) ? "W" : "";
4046 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4047 p1
, rn
, immed
, immed
);
4052 immed
= opcode
& 0xff;
4053 if (!(opcode
& 0x200))
4056 /* two indexed modes will write back rn */
4057 if (opcode
& 0x100) {
4058 if (opcode
& 0x400) /* pre-indexed */
4060 else { /* post-indexed */
4066 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4067 mnemonic
, rt
, rn
, p1
,
4071 if ((op2
& 0x24) == 0x24) {
4073 goto ldrxb_immediate_t3
;
4076 int rm
= opcode
& 0xf;
4079 sprintf(cp
, "PLD\t");
4081 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4082 immed
= (opcode
>> 4) & 0x3;
4084 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4089 if ((rn
& rt
) == 0xf)
4092 immed
= opcode
& 0xfff;
4093 goto preload_immediate
;
4097 mnemonic
= "LDRB.W";
4098 immed
= opcode
& 0xfff;
4099 goto ldrxb_immediate_t2
;
4101 if ((rn
& rt
) == 0xf) {
4102 immed
= opcode
& 0xfff;
4103 address
= thumb_alignpc4(address
);
4104 if (opcode
& (1 << 23))
4108 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4111 if (rn
== 0xf && rt
!= 0xf) {
4113 immed
= opcode
& 0xfff;
4114 address
= thumb_alignpc4(address
);
4115 if (opcode
& (1 << 23))
4119 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4124 if ((op2
& 0x3c) == 0x38) {
4125 immed
= opcode
& 0xff;
4126 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4127 rt
, rn
, immed
, immed
);
4130 if ((op2
& 0x3c) == 0x30) {
4132 immed
= opcode
& 0xff;
4133 immed
= -immed
; // pli
4134 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4139 goto ldrxb_immediate_t3
;
4141 if ((op2
& 0x24) == 0x24) {
4143 goto ldrxb_immediate_t3
;
4146 int rm
= opcode
& 0xf;
4149 sprintf(cp
, "PLI\t");
4151 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4152 immed
= (opcode
>> 4) & 0x3;
4154 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4160 immed
= opcode
& 0xfff;
4161 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4167 immed
= opcode
& 0xfff;
4169 goto ldrxb_immediate_t2
;
4172 return ERROR_INVALID_ARGUMENTS
;
4175 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4176 struct arm_instruction
*instruction
, char *cp
)
4178 int rn
= (opcode
>> 16) & 0xf;
4179 int rt
= (opcode
>> 12) & 0xf;
4180 int op2
= (opcode
>> 6) & 0x3f;
4185 sprintf(cp
, "HINT (UNALLOCATED)");
4189 if (opcode
& (1 << 24))
4192 if ((opcode
& (1 << 23)) == 0) {
4195 immed
= opcode
& 0xfff;
4196 address
= thumb_alignpc4(address
);
4197 if (opcode
& (1 << 23))
4201 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4206 int rm
= opcode
& 0xf;
4208 immed
= (opcode
>> 4) & 0x3;
4209 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4210 sign
, rt
, rn
, rm
, immed
);
4213 if ((op2
& 0x3c) == 0x38) {
4214 immed
= opcode
& 0xff;
4215 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4216 sign
, rt
, rn
, immed
, immed
);
4219 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4220 char *p1
= "", *p2
= "]";
4222 immed
= opcode
& 0xff;
4223 if (!(opcode
& 0x200))
4226 /* two indexed modes will write back rn */
4227 if (opcode
& 0x100) {
4228 if (opcode
& 0x400) /* pre-indexed */
4230 else { /* post-indexed */
4235 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4236 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4243 immed
= opcode
& 0xfff;
4244 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4245 sign
, *sign
? "" : ".W",
4246 rt
, rn
, immed
, immed
);
4250 return ERROR_INVALID_ARGUMENTS
;
4254 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4255 * always set. That means eventual arm_simulate_step() support for Thumb2
4256 * will need work in this area.
4258 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4265 /* clear low bit ... it's set on function pointers */
4268 /* clear fields, to avoid confusion */
4269 memset(instruction
, 0, sizeof(struct arm_instruction
));
4271 /* read first halfword, see if this is the only one */
4272 retval
= target_read_u16(target
, address
, &op
);
4273 if (retval
!= ERROR_OK
)
4276 switch (op
& 0xf800) {
4280 /* 32-bit instructions */
4281 instruction
->instruction_size
= 4;
4283 retval
= target_read_u16(target
, address
+ 2, &op
);
4284 if (retval
!= ERROR_OK
)
4287 instruction
->opcode
= opcode
;
4290 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4291 return thumb_evaluate_opcode(op
, address
, instruction
);
4294 snprintf(instruction
->text
, 128,
4295 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4297 cp
= strchr(instruction
->text
, 0);
4298 retval
= ERROR_FAIL
;
4300 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4301 if ((opcode
& 0x1a008000) == 0x10000000)
4302 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4304 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4305 else if ((opcode
& 0x1a008000) == 0x12000000)
4306 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4308 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4309 else if ((opcode
& 0x18008000) == 0x10008000)
4310 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4312 /* ARMv7-M: A5.3.5 Load/store multiple */
4313 else if ((opcode
& 0x1e400000) == 0x08000000)
4314 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4316 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4317 else if ((opcode
& 0x1e400000) == 0x08400000)
4318 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4320 /* ARMv7-M: A5.3.7 Load word */
4321 else if ((opcode
& 0x1f700000) == 0x18500000)
4322 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4324 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4325 else if ((opcode
& 0x1e700000) == 0x18300000)
4326 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4328 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4329 else if ((opcode
& 0x1e700000) == 0x18100000)
4330 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4332 /* ARMv7-M: A5.3.10 Store single data item */
4333 else if ((opcode
& 0x1f100000) == 0x18000000)
4334 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4336 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4337 else if ((opcode
& 0x1e000000) == 0x0a000000)
4338 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4340 /* ARMv7-M: A5.3.12 Data processing (register)
4341 * and A5.3.13 Miscellaneous operations
4343 else if ((opcode
& 0x1f000000) == 0x1a000000)
4344 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4346 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4347 else if ((opcode
& 0x1f800000) == 0x1b000000)
4348 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4350 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4351 else if ((opcode
& 0x1f800000) == 0x1b800000)
4352 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4354 if (retval
== ERROR_OK
)
4358 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4359 * instructions; not yet handled here.
4362 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4363 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4364 strcpy(cp
, "UNDEFINED OPCODE");
4368 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4371 strcpy(cp
, "(32-bit Thumb2 ...)");
4375 int arm_access_size(struct arm_instruction
*instruction
)
4377 if ((instruction
->type
== ARM_LDRB
)
4378 || (instruction
->type
== ARM_LDRBT
)
4379 || (instruction
->type
== ARM_LDRSB
)
4380 || (instruction
->type
== ARM_STRB
)
4381 || (instruction
->type
== ARM_STRBT
))
4385 else if ((instruction
->type
== ARM_LDRH
)
4386 || (instruction
->type
== ARM_LDRSH
)
4387 || (instruction
->type
== ARM_STRH
))
4391 else if ((instruction
->type
== ARM_LDR
)
4392 || (instruction
->type
== ARM_LDRT
)
4393 || (instruction
->type
== ARM_STR
)
4394 || (instruction
->type
== ARM_STRT
))
4398 else if ((instruction
->type
== ARM_LDRD
)
4399 || (instruction
->type
== ARM_STRD
))
4405 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction
->type
);