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)) ? "!" : "";
140 switch ((opcode
>> 23) & 0x3) {
145 /* "IA" is default */
156 switch (opcode
& 0x0e500000) {
158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
160 "\tSRS%s\tSP%s, #%d",
162 mode
, wback
, opcode
& 0x1f);
165 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
169 mode
, (opcode
>> 16) & 0xf, wback
);
172 return evaluate_unknown(opcode
, address
, instruction
);
177 static int evaluate_swi(uint32_t opcode
,
178 uint32_t address
, struct arm_instruction
*instruction
)
180 instruction
->type
= ARM_SWI
;
182 snprintf(instruction
->text
, 128,
183 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
184 address
, opcode
, (opcode
& 0xffffff));
189 static int evaluate_blx_imm(uint32_t opcode
,
190 uint32_t address
, struct arm_instruction
*instruction
)
194 uint32_t target_address
;
196 instruction
->type
= ARM_BLX
;
197 immediate
= opcode
& 0x00ffffff;
199 /* sign extend 24-bit immediate */
200 if (immediate
& 0x00800000)
201 offset
= 0xff000000 | immediate
;
205 /* shift two bits left */
208 /* odd/event halfword */
209 if (opcode
& 0x01000000)
212 target_address
= address
+ 8 + offset
;
214 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"", address
, opcode
, target_address
);
216 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
217 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
222 static int evaluate_b_bl(uint32_t opcode
,
223 uint32_t address
, struct arm_instruction
*instruction
)
228 uint32_t target_address
;
230 immediate
= opcode
& 0x00ffffff;
231 L
= (opcode
& 0x01000000) >> 24;
233 /* sign extend 24-bit immediate */
234 if (immediate
& 0x00800000)
235 offset
= 0xff000000 | immediate
;
239 /* shift two bits left */
242 target_address
= address
+ 8 + offset
;
245 instruction
->type
= ARM_BL
;
247 instruction
->type
= ARM_B
;
249 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
, address
, opcode
,
250 (L
) ? "L" : "", COND(opcode
), target_address
);
252 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
253 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
258 /* Coprocessor load/store and double register transfers */
259 /* both normal and extended instruction space (condition field b1111) */
260 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
261 uint32_t address
, struct arm_instruction
*instruction
)
263 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
266 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
268 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
271 cp_opcode
= (opcode
& 0xf0) >> 4;
272 Rd
= (opcode
& 0xf000) >> 12;
273 Rn
= (opcode
& 0xf0000) >> 16;
274 CRm
= (opcode
& 0xf);
277 if ((opcode
& 0x0ff00000) == 0x0c400000)
279 instruction
->type
= ARM_MCRR
;
284 if ((opcode
& 0x0ff00000) == 0x0c500000)
286 instruction
->type
= ARM_MRRC
;
290 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s p%i, %x, r%i, r%i, c%i",
291 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
293 else /* LDC or STC */
295 uint8_t CRd
, Rn
, offset
;
298 char addressing_mode
[32];
300 CRd
= (opcode
& 0xf000) >> 12;
301 Rn
= (opcode
& 0xf0000) >> 16;
302 offset
= (opcode
& 0xff);
305 if (opcode
& 0x00100000)
307 instruction
->type
= ARM_LDC
;
312 instruction
->type
= ARM_STC
;
316 U
= (opcode
& 0x00800000) >> 23;
317 N
= (opcode
& 0x00400000) >> 22;
319 /* addressing modes */
320 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
321 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
322 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
323 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
324 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
325 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
326 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
327 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
329 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s p%i, c%i, %s",
330 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
332 cp_num
, CRd
, addressing_mode
);
338 /* Coprocessor data processing instructions */
339 /* Coprocessor register transfer instructions */
340 /* both normal and extended instruction space (condition field b1111) */
341 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
342 uint32_t address
, struct arm_instruction
*instruction
)
346 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
348 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
349 cp_num
= (opcode
& 0xf00) >> 8;
350 CRd_Rd
= (opcode
& 0xf000) >> 12;
351 CRn
= (opcode
& 0xf0000) >> 16;
352 CRm
= (opcode
& 0xf);
353 opcode_2
= (opcode
& 0xe0) >> 5;
356 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
358 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
360 instruction
->type
= ARM_MRC
;
363 else /* bit 20 not set -> MCR */
365 instruction
->type
= ARM_MCR
;
369 opcode_1
= (opcode
& 0x00e00000) >> 21;
371 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",
372 address
, opcode
, mnemonic
, cond
,
373 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
375 else /* bit 4 not set -> CDP */
377 instruction
->type
= ARM_CDP
;
380 opcode_1
= (opcode
& 0x00f00000) >> 20;
382 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",
383 address
, opcode
, mnemonic
, cond
,
384 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
390 /* Load/store instructions */
391 static int evaluate_load_store(uint32_t opcode
,
392 uint32_t address
, struct arm_instruction
*instruction
)
394 uint8_t I
, P
, U
, B
, W
, L
;
396 char *operation
; /* "LDR" or "STR" */
397 char *suffix
; /* "", "B", "T", "BT" */
401 I
= (opcode
& 0x02000000) >> 25;
402 P
= (opcode
& 0x01000000) >> 24;
403 U
= (opcode
& 0x00800000) >> 23;
404 B
= (opcode
& 0x00400000) >> 22;
405 W
= (opcode
& 0x00200000) >> 21;
406 L
= (opcode
& 0x00100000) >> 20;
408 /* target register */
409 Rd
= (opcode
& 0xf000) >> 12;
412 Rn
= (opcode
& 0xf0000) >> 16;
414 instruction
->info
.load_store
.Rd
= Rd
;
415 instruction
->info
.load_store
.Rn
= Rn
;
416 instruction
->info
.load_store
.U
= U
;
418 /* determine operation */
424 /* determine instruction type and suffix */
427 if ((P
== 0) && (W
== 1))
430 instruction
->type
= ARM_LDRBT
;
432 instruction
->type
= ARM_STRBT
;
438 instruction
->type
= ARM_LDRB
;
440 instruction
->type
= ARM_STRB
;
446 if ((P
== 0) && (W
== 1))
449 instruction
->type
= ARM_LDRT
;
451 instruction
->type
= ARM_STRT
;
457 instruction
->type
= ARM_LDR
;
459 instruction
->type
= ARM_STR
;
464 if (!I
) /* #+-<offset_12> */
466 uint32_t offset_12
= (opcode
& 0xfff);
468 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
470 snprintf(offset
, 32, "%s", "");
472 instruction
->info
.load_store
.offset_mode
= 0;
473 instruction
->info
.load_store
.offset
.offset
= offset_12
;
475 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
477 uint8_t shift_imm
, shift
;
480 shift_imm
= (opcode
& 0xf80) >> 7;
481 shift
= (opcode
& 0x60) >> 5;
484 /* LSR encodes a shift by 32 bit as 0x0 */
485 if ((shift
== 0x1) && (shift_imm
== 0x0))
488 /* ASR encodes a shift by 32 bit as 0x0 */
489 if ((shift
== 0x2) && (shift_imm
== 0x0))
492 /* ROR by 32 bit is actually a RRX */
493 if ((shift
== 0x3) && (shift_imm
== 0x0))
496 instruction
->info
.load_store
.offset_mode
= 1;
497 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
498 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
499 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
501 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
503 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
505 else /* +-<Rm>, <Shift>, #<shift_imm> */
510 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
513 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
516 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
519 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
522 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
530 if (W
== 0) /* offset */
532 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
533 address
, opcode
, operation
, COND(opcode
), suffix
,
536 instruction
->info
.load_store
.index_mode
= 0;
538 else /* pre-indexed */
540 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
541 address
, opcode
, operation
, COND(opcode
), suffix
,
544 instruction
->info
.load_store
.index_mode
= 1;
547 else /* post-indexed */
549 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
550 address
, opcode
, operation
, COND(opcode
), suffix
,
553 instruction
->info
.load_store
.index_mode
= 2;
559 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
561 unsigned rm
= (opcode
>> 0) & 0xf;
562 unsigned rd
= (opcode
>> 12) & 0xf;
563 unsigned rn
= (opcode
>> 16) & 0xf;
566 switch ((opcode
>> 24) & 0x3) {
571 sprintf(cp
, "UNDEFINED");
572 return ARM_UNDEFINED_INSTRUCTION
;
581 switch ((opcode
>> 10) & 0x3) {
597 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
598 (opcode
& (1 << 22)) ? 'U' : 'S',
603 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
604 (opcode
& (1 << 22)) ? 'U' : 'S',
611 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
617 switch ((opcode
>> 20) & 0x7) {
640 switch ((opcode
>> 5) & 0x7) {
669 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
670 (int) (opcode
>> 12) & 0xf,
671 (int) (opcode
>> 16) & 0xf,
672 (int) (opcode
>> 0) & 0xf);
676 /* these opcodes might be used someday */
677 sprintf(cp
, "UNDEFINED");
678 return ARM_UNDEFINED_INSTRUCTION
;
681 /* ARMv6 and later support "media" instructions (includes SIMD) */
682 static int evaluate_media(uint32_t opcode
, uint32_t address
,
683 struct arm_instruction
*instruction
)
685 char *cp
= instruction
->text
;
686 char *mnemonic
= NULL
;
689 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
693 /* parallel add/subtract */
694 if ((opcode
& 0x01800000) == 0x00000000) {
695 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
700 if ((opcode
& 0x01f00020) == 0x00800000) {
702 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
704 if (opcode
& (1 << 6)) {
713 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
715 (int) (opcode
>> 12) & 0xf,
716 (int) (opcode
>> 16) & 0xf,
717 (int) (opcode
>> 0) & 0xf,
723 if ((opcode
& 0x01a00020) == 0x00a00000) {
725 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
727 if (opcode
& (1 << 6)) {
735 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
736 (opcode
& (1 << 22)) ? 'U' : 'S',
738 (int) (opcode
>> 12) & 0xf,
739 (int) (opcode
>> 16) & 0x1f,
740 (int) (opcode
>> 0) & 0xf,
746 if ((opcode
& 0x018000f0) == 0x00800070) {
747 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
752 if ((opcode
& 0x01f00080) == 0x01000000) {
753 unsigned rn
= (opcode
>> 12) & 0xf;
756 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
757 (opcode
& (1 << 6)) ? 'S' : 'A',
758 (opcode
& (1 << 5)) ? "X" : "",
760 (int) (opcode
>> 16) & 0xf,
761 (int) (opcode
>> 0) & 0xf,
762 (int) (opcode
>> 8) & 0xf,
765 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
766 (opcode
& (1 << 6)) ? 'S' : 'A',
767 (opcode
& (1 << 5)) ? "X" : "",
769 (int) (opcode
>> 16) & 0xf,
770 (int) (opcode
>> 0) & 0xf,
771 (int) (opcode
>> 8) & 0xf);
774 if ((opcode
& 0x01f00000) == 0x01400000) {
775 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
776 (opcode
& (1 << 6)) ? 'S' : 'A',
777 (opcode
& (1 << 5)) ? "X" : "",
779 (int) (opcode
>> 12) & 0xf,
780 (int) (opcode
>> 16) & 0xf,
781 (int) (opcode
>> 0) & 0xf,
782 (int) (opcode
>> 8) & 0xf);
785 if ((opcode
& 0x01f00000) == 0x01500000) {
786 unsigned rn
= (opcode
>> 12) & 0xf;
788 switch (opcode
& 0xc0) {
800 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
801 (opcode
& (1 << 6)) ? 'S' : 'A',
802 (opcode
& (1 << 5)) ? "R" : "",
804 (int) (opcode
>> 16) & 0xf,
805 (int) (opcode
>> 0) & 0xf,
806 (int) (opcode
>> 8) & 0xf,
809 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
810 (opcode
& (1 << 5)) ? "R" : "",
812 (int) (opcode
>> 16) & 0xf,
813 (int) (opcode
>> 0) & 0xf,
814 (int) (opcode
>> 8) & 0xf);
819 /* simple matches against the remaining decode bits */
820 switch (opcode
& 0x01f000f0) {
823 /* parallel halfword saturate */
824 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
825 (opcode
& (1 << 22)) ? 'U' : 'S',
827 (int) (opcode
>> 12) & 0xf,
828 (int) (opcode
>> 16) & 0xf,
829 (int) (opcode
>> 0) & 0xf);
842 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
843 (int) (opcode
>> 12) & 0xf,
844 (int) (opcode
>> 16) & 0xf,
845 (int) (opcode
>> 0) & 0xf);
848 /* unsigned sum of absolute differences */
849 if (((opcode
>> 12) & 0xf) == 0xf)
850 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
851 (int) (opcode
>> 16) & 0xf,
852 (int) (opcode
>> 0) & 0xf,
853 (int) (opcode
>> 8) & 0xf);
855 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
856 (int) (opcode
>> 16) & 0xf,
857 (int) (opcode
>> 0) & 0xf,
858 (int) (opcode
>> 8) & 0xf,
859 (int) (opcode
>> 12) & 0xf);
863 unsigned rm
= (opcode
>> 0) & 0xf;
864 unsigned rd
= (opcode
>> 12) & 0xf;
866 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
871 /* these opcodes might be used someday */
872 sprintf(cp
, "UNDEFINED");
876 /* Miscellaneous load/store instructions */
877 static int evaluate_misc_load_store(uint32_t opcode
,
878 uint32_t address
, struct arm_instruction
*instruction
)
880 uint8_t P
, U
, I
, W
, L
, S
, H
;
882 char *operation
; /* "LDR" or "STR" */
883 char *suffix
; /* "H", "SB", "SH", "D" */
887 P
= (opcode
& 0x01000000) >> 24;
888 U
= (opcode
& 0x00800000) >> 23;
889 I
= (opcode
& 0x00400000) >> 22;
890 W
= (opcode
& 0x00200000) >> 21;
891 L
= (opcode
& 0x00100000) >> 20;
892 S
= (opcode
& 0x00000040) >> 6;
893 H
= (opcode
& 0x00000020) >> 5;
895 /* target register */
896 Rd
= (opcode
& 0xf000) >> 12;
899 Rn
= (opcode
& 0xf0000) >> 16;
901 instruction
->info
.load_store
.Rd
= Rd
;
902 instruction
->info
.load_store
.Rn
= Rn
;
903 instruction
->info
.load_store
.U
= U
;
905 /* determine instruction type and suffix */
913 instruction
->type
= ARM_LDRSH
;
919 instruction
->type
= ARM_LDRSB
;
923 else /* there are no signed stores, so this is used to encode double-register load/stores */
929 instruction
->type
= ARM_STRD
;
934 instruction
->type
= ARM_LDRD
;
944 instruction
->type
= ARM_LDRH
;
949 instruction
->type
= ARM_STRH
;
953 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
955 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
956 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
958 instruction
->info
.load_store
.offset_mode
= 0;
959 instruction
->info
.load_store
.offset
.offset
= offset_8
;
961 else /* Register offset/index (+-<Rm>) */
965 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
967 instruction
->info
.load_store
.offset_mode
= 1;
968 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
969 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
970 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
975 if (W
== 0) /* offset */
977 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
978 address
, opcode
, operation
, COND(opcode
), suffix
,
981 instruction
->info
.load_store
.index_mode
= 0;
983 else /* pre-indexed */
985 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
986 address
, opcode
, operation
, COND(opcode
), suffix
,
989 instruction
->info
.load_store
.index_mode
= 1;
992 else /* post-indexed */
994 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
995 address
, opcode
, operation
, COND(opcode
), suffix
,
998 instruction
->info
.load_store
.index_mode
= 2;
1004 /* Load/store multiples instructions */
1005 static int evaluate_ldm_stm(uint32_t opcode
,
1006 uint32_t address
, struct arm_instruction
*instruction
)
1008 uint8_t P
, U
, S
, W
, L
, Rn
;
1009 uint32_t register_list
;
1010 char *addressing_mode
;
1017 P
= (opcode
& 0x01000000) >> 24;
1018 U
= (opcode
& 0x00800000) >> 23;
1019 S
= (opcode
& 0x00400000) >> 22;
1020 W
= (opcode
& 0x00200000) >> 21;
1021 L
= (opcode
& 0x00100000) >> 20;
1022 register_list
= (opcode
& 0xffff);
1023 Rn
= (opcode
& 0xf0000) >> 16;
1025 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1026 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1027 instruction
->info
.load_store_multiple
.S
= S
;
1028 instruction
->info
.load_store_multiple
.W
= W
;
1032 instruction
->type
= ARM_LDM
;
1037 instruction
->type
= ARM_STM
;
1045 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1046 addressing_mode
= "IB";
1050 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1051 addressing_mode
= "DB";
1058 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1059 /* "IA" is the default in UAL syntax */
1060 addressing_mode
= "";
1064 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1065 addressing_mode
= "DA";
1069 reg_list_p
= reg_list
;
1070 for (i
= 0; i
<= 15; i
++)
1072 if ((register_list
>> i
) & 1)
1077 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
1081 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
1086 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i%s, {%s}%s",
1087 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
1088 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1093 /* Multiplies, extra load/stores */
1094 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1095 uint32_t address
, struct arm_instruction
*instruction
)
1097 /* Multiply (accumulate) (long) and Swap/swap byte */
1098 if ((opcode
& 0x000000f0) == 0x00000090)
1100 /* Multiply (accumulate) */
1101 if ((opcode
& 0x0f800000) == 0x00000000)
1103 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1105 Rs
= (opcode
& 0xf00) >> 8;
1106 Rn
= (opcode
& 0xf000) >> 12;
1107 Rd
= (opcode
& 0xf0000) >> 16;
1108 S
= (opcode
& 0x00100000) >> 20;
1110 /* examine A bit (accumulate) */
1111 if (opcode
& 0x00200000)
1113 instruction
->type
= ARM_MLA
;
1114 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1115 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
1119 instruction
->type
= ARM_MUL
;
1120 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1121 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
1127 /* Multiply (accumulate) long */
1128 if ((opcode
& 0x0f800000) == 0x00800000)
1130 char* mnemonic
= NULL
;
1131 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1133 Rs
= (opcode
& 0xf00) >> 8;
1134 RdHi
= (opcode
& 0xf000) >> 12;
1135 RdLow
= (opcode
& 0xf0000) >> 16;
1136 S
= (opcode
& 0x00100000) >> 20;
1138 switch ((opcode
& 0x00600000) >> 21)
1141 instruction
->type
= ARM_UMULL
;
1145 instruction
->type
= ARM_UMLAL
;
1149 instruction
->type
= ARM_SMULL
;
1153 instruction
->type
= ARM_SMLAL
;
1158 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1159 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
1160 RdLow
, RdHi
, Rm
, Rs
);
1165 /* Swap/swap byte */
1166 if ((opcode
& 0x0f800000) == 0x01000000)
1170 Rd
= (opcode
& 0xf000) >> 12;
1171 Rn
= (opcode
& 0xf0000) >> 16;
1173 /* examine B flag */
1174 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1176 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1177 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
1183 return evaluate_misc_load_store(opcode
, address
, instruction
);
1186 static int evaluate_mrs_msr(uint32_t opcode
,
1187 uint32_t address
, struct arm_instruction
*instruction
)
1189 int R
= (opcode
& 0x00400000) >> 22;
1190 char *PSR
= (R
) ? "SPSR" : "CPSR";
1192 /* Move register to status register (MSR) */
1193 if (opcode
& 0x00200000)
1195 instruction
->type
= ARM_MSR
;
1197 /* immediate variant */
1198 if (opcode
& 0x02000000)
1200 uint8_t immediate
= (opcode
& 0xff);
1201 uint8_t rotate
= (opcode
& 0xf00);
1203 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1204 address
, opcode
, COND(opcode
), PSR
,
1205 (opcode
& 0x10000) ? "c" : "",
1206 (opcode
& 0x20000) ? "x" : "",
1207 (opcode
& 0x40000) ? "s" : "",
1208 (opcode
& 0x80000) ? "f" : "",
1209 ror(immediate
, (rotate
* 2))
1212 else /* register variant */
1214 uint8_t Rm
= opcode
& 0xf;
1215 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1216 address
, opcode
, COND(opcode
), PSR
,
1217 (opcode
& 0x10000) ? "c" : "",
1218 (opcode
& 0x20000) ? "x" : "",
1219 (opcode
& 0x40000) ? "s" : "",
1220 (opcode
& 0x80000) ? "f" : "",
1226 else /* Move status register to register (MRS) */
1230 instruction
->type
= ARM_MRS
;
1231 Rd
= (opcode
& 0x0000f000) >> 12;
1233 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1234 address
, opcode
, COND(opcode
), Rd
, PSR
);
1240 /* Miscellaneous instructions */
1241 static int evaluate_misc_instr(uint32_t opcode
,
1242 uint32_t address
, struct arm_instruction
*instruction
)
1245 if ((opcode
& 0x000000f0) == 0x00000000)
1247 evaluate_mrs_msr(opcode
, address
, instruction
);
1251 if ((opcode
& 0x006000f0) == 0x00200010)
1254 instruction
->type
= ARM_BX
;
1257 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1258 address
, opcode
, COND(opcode
), Rm
);
1260 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1261 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1264 /* BXJ - "Jazelle" support (ARMv5-J) */
1265 if ((opcode
& 0x006000f0) == 0x00200020)
1268 instruction
->type
= ARM_BX
;
1271 snprintf(instruction
->text
, 128,
1272 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1273 address
, opcode
, COND(opcode
), Rm
);
1275 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1276 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1280 if ((opcode
& 0x006000f0) == 0x00600010)
1283 instruction
->type
= ARM_CLZ
;
1285 Rd
= (opcode
& 0xf000) >> 12;
1287 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1288 address
, opcode
, COND(opcode
), Rd
, Rm
);
1292 if ((opcode
& 0x006000f0) == 0x00200030)
1295 instruction
->type
= ARM_BLX
;
1298 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1299 address
, opcode
, COND(opcode
), Rm
);
1301 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1302 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1305 /* Enhanced DSP add/subtracts */
1306 if ((opcode
& 0x0000000f0) == 0x00000050)
1309 char *mnemonic
= NULL
;
1311 Rd
= (opcode
& 0xf000) >> 12;
1312 Rn
= (opcode
& 0xf0000) >> 16;
1314 switch ((opcode
& 0x00600000) >> 21)
1317 instruction
->type
= ARM_QADD
;
1321 instruction
->type
= ARM_QSUB
;
1325 instruction
->type
= ARM_QDADD
;
1329 instruction
->type
= ARM_QDSUB
;
1334 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1335 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
1338 /* Software breakpoints */
1339 if ((opcode
& 0x0000000f0) == 0x00000070)
1342 instruction
->type
= ARM_BKPT
;
1343 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1345 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBKPT 0x%4.4" PRIx32
"",
1346 address
, opcode
, immediate
);
1349 /* Enhanced DSP multiplies */
1350 if ((opcode
& 0x000000090) == 0x00000080)
1352 int x
= (opcode
& 0x20) >> 5;
1353 int y
= (opcode
& 0x40) >> 6;
1356 if ((opcode
& 0x00600000) == 0x00000000)
1358 uint8_t Rd
, Rm
, Rs
, Rn
;
1359 instruction
->type
= ARM_SMLAxy
;
1360 Rd
= (opcode
& 0xf0000) >> 16;
1361 Rm
= (opcode
& 0xf);
1362 Rs
= (opcode
& 0xf00) >> 8;
1363 Rn
= (opcode
& 0xf000) >> 12;
1365 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1366 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1371 if ((opcode
& 0x00600000) == 0x00400000)
1373 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1374 instruction
->type
= ARM_SMLAxy
;
1375 RdHi
= (opcode
& 0xf0000) >> 16;
1376 RdLow
= (opcode
& 0xf000) >> 12;
1377 Rm
= (opcode
& 0xf);
1378 Rs
= (opcode
& 0xf00) >> 8;
1380 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1381 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1382 RdLow
, RdHi
, Rm
, Rs
);
1386 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
1388 uint8_t Rd
, Rm
, Rs
, Rn
;
1389 instruction
->type
= ARM_SMLAWy
;
1390 Rd
= (opcode
& 0xf0000) >> 16;
1391 Rm
= (opcode
& 0xf);
1392 Rs
= (opcode
& 0xf00) >> 8;
1393 Rn
= (opcode
& 0xf000) >> 12;
1395 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1396 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1401 if ((opcode
& 0x00600000) == 0x00300000)
1404 instruction
->type
= ARM_SMULxy
;
1405 Rd
= (opcode
& 0xf0000) >> 16;
1406 Rm
= (opcode
& 0xf);
1407 Rs
= (opcode
& 0xf00) >> 8;
1409 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1410 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
1415 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
1418 instruction
->type
= ARM_SMULWy
;
1419 Rd
= (opcode
& 0xf0000) >> 16;
1420 Rm
= (opcode
& 0xf);
1421 Rs
= (opcode
& 0xf00) >> 8;
1423 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1424 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
1432 static int evaluate_data_proc(uint32_t opcode
,
1433 uint32_t address
, struct arm_instruction
*instruction
)
1435 uint8_t I
, op
, S
, Rn
, Rd
;
1436 char *mnemonic
= NULL
;
1437 char shifter_operand
[32];
1439 I
= (opcode
& 0x02000000) >> 25;
1440 op
= (opcode
& 0x01e00000) >> 21;
1441 S
= (opcode
& 0x00100000) >> 20;
1443 Rd
= (opcode
& 0xf000) >> 12;
1444 Rn
= (opcode
& 0xf0000) >> 16;
1446 instruction
->info
.data_proc
.Rd
= Rd
;
1447 instruction
->info
.data_proc
.Rn
= Rn
;
1448 instruction
->info
.data_proc
.S
= S
;
1453 instruction
->type
= ARM_AND
;
1457 instruction
->type
= ARM_EOR
;
1461 instruction
->type
= ARM_SUB
;
1465 instruction
->type
= ARM_RSB
;
1469 instruction
->type
= ARM_ADD
;
1473 instruction
->type
= ARM_ADC
;
1477 instruction
->type
= ARM_SBC
;
1481 instruction
->type
= ARM_RSC
;
1485 instruction
->type
= ARM_TST
;
1489 instruction
->type
= ARM_TEQ
;
1493 instruction
->type
= ARM_CMP
;
1497 instruction
->type
= ARM_CMN
;
1501 instruction
->type
= ARM_ORR
;
1505 instruction
->type
= ARM_MOV
;
1509 instruction
->type
= ARM_BIC
;
1513 instruction
->type
= ARM_MVN
;
1518 if (I
) /* immediate shifter operand (#<immediate>)*/
1520 uint8_t immed_8
= opcode
& 0xff;
1521 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1524 immediate
= ror(immed_8
, rotate_imm
* 2);
1526 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1528 instruction
->info
.data_proc
.variant
= 0;
1529 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1531 else /* register-based shifter operand */
1534 shift
= (opcode
& 0x60) >> 5;
1535 Rm
= (opcode
& 0xf);
1537 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1540 shift_imm
= (opcode
& 0xf80) >> 7;
1542 instruction
->info
.data_proc
.variant
= 1;
1543 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1544 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1545 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1547 /* LSR encodes a shift by 32 bit as 0x0 */
1548 if ((shift
== 0x1) && (shift_imm
== 0x0))
1551 /* ASR encodes a shift by 32 bit as 0x0 */
1552 if ((shift
== 0x2) && (shift_imm
== 0x0))
1555 /* ROR by 32 bit is actually a RRX */
1556 if ((shift
== 0x3) && (shift_imm
== 0x0))
1559 if ((shift_imm
== 0x0) && (shift
== 0x0))
1561 snprintf(shifter_operand
, 32, "r%i", Rm
);
1565 if (shift
== 0x0) /* LSL */
1567 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1569 else if (shift
== 0x1) /* LSR */
1571 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1573 else if (shift
== 0x2) /* ASR */
1575 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1577 else if (shift
== 0x3) /* ROR */
1579 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1581 else if (shift
== 0x4) /* RRX */
1583 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1587 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1589 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1591 instruction
->info
.data_proc
.variant
= 2;
1592 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1594 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1596 if (shift
== 0x0) /* LSL */
1598 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1600 else if (shift
== 0x1) /* LSR */
1602 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1604 else if (shift
== 0x2) /* ASR */
1606 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1608 else if (shift
== 0x3) /* ROR */
1610 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1615 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1617 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1618 address
, opcode
, mnemonic
, COND(opcode
),
1619 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1621 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1623 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1624 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",address
, opcode
);
1626 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1627 address
, opcode
, mnemonic
, COND(opcode
),
1628 (S
) ? "S" : "", Rd
, shifter_operand
);
1630 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1632 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1633 address
, opcode
, mnemonic
, COND(opcode
),
1634 Rn
, shifter_operand
);
1640 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
1642 /* clear fields, to avoid confusion */
1643 memset(instruction
, 0, sizeof(struct arm_instruction
));
1644 instruction
->opcode
= opcode
;
1645 instruction
->instruction_size
= 4;
1647 /* catch opcodes with condition field [31:28] = b1111 */
1648 if ((opcode
& 0xf0000000) == 0xf0000000)
1650 /* Undefined instruction (or ARMv5E cache preload PLD) */
1651 if ((opcode
& 0x08000000) == 0x00000000)
1652 return evaluate_pld(opcode
, address
, instruction
);
1654 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1655 if ((opcode
& 0x0e000000) == 0x08000000)
1656 return evaluate_srs(opcode
, address
, instruction
);
1658 /* Branch and branch with link and change to Thumb */
1659 if ((opcode
& 0x0e000000) == 0x0a000000)
1660 return evaluate_blx_imm(opcode
, address
, instruction
);
1662 /* Extended coprocessor opcode space (ARMv5 and higher)*/
1663 /* Coprocessor load/store and double register transfers */
1664 if ((opcode
& 0x0e000000) == 0x0c000000)
1665 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1667 /* Coprocessor data processing */
1668 if ((opcode
& 0x0f000100) == 0x0c000000)
1669 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1671 /* Coprocessor register transfers */
1672 if ((opcode
& 0x0f000010) == 0x0c000010)
1673 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1675 /* Undefined instruction */
1676 if ((opcode
& 0x0f000000) == 0x0f000000)
1678 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1679 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1684 /* catch opcodes with [27:25] = b000 */
1685 if ((opcode
& 0x0e000000) == 0x00000000)
1687 /* Multiplies, extra load/stores */
1688 if ((opcode
& 0x00000090) == 0x00000090)
1689 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1691 /* Miscellaneous instructions */
1692 if ((opcode
& 0x0f900000) == 0x01000000)
1693 return evaluate_misc_instr(opcode
, address
, instruction
);
1695 return evaluate_data_proc(opcode
, address
, instruction
);
1698 /* catch opcodes with [27:25] = b001 */
1699 if ((opcode
& 0x0e000000) == 0x02000000)
1701 /* Undefined instruction */
1702 if ((opcode
& 0x0fb00000) == 0x03000000)
1704 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1705 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION", address
, opcode
);
1709 /* Move immediate to status register */
1710 if ((opcode
& 0x0fb00000) == 0x03200000)
1711 return evaluate_mrs_msr(opcode
, address
, instruction
);
1713 return evaluate_data_proc(opcode
, address
, instruction
);
1717 /* catch opcodes with [27:25] = b010 */
1718 if ((opcode
& 0x0e000000) == 0x04000000)
1720 /* Load/store immediate offset */
1721 return evaluate_load_store(opcode
, address
, instruction
);
1724 /* catch opcodes with [27:25] = b011 */
1725 if ((opcode
& 0x0e000000) == 0x06000000)
1727 /* Load/store register offset */
1728 if ((opcode
& 0x00000010) == 0x00000000)
1729 return evaluate_load_store(opcode
, address
, instruction
);
1731 /* Architecturally Undefined instruction
1732 * ... don't expect these to ever be used
1734 if ((opcode
& 0x07f000f0) == 0x07f000f0)
1736 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1737 snprintf(instruction
->text
, 128,
1738 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1743 /* "media" instructions */
1744 return evaluate_media(opcode
, address
, instruction
);
1747 /* catch opcodes with [27:25] = b100 */
1748 if ((opcode
& 0x0e000000) == 0x08000000)
1750 /* Load/store multiple */
1751 return evaluate_ldm_stm(opcode
, address
, instruction
);
1754 /* catch opcodes with [27:25] = b101 */
1755 if ((opcode
& 0x0e000000) == 0x0a000000)
1757 /* Branch and branch with link */
1758 return evaluate_b_bl(opcode
, address
, instruction
);
1761 /* catch opcodes with [27:25] = b110 */
1762 if ((opcode
& 0x0e000000) == 0x0a000000)
1764 /* Coprocessor load/store and double register transfers */
1765 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1768 /* catch opcodes with [27:25] = b111 */
1769 if ((opcode
& 0x0e000000) == 0x0e000000)
1771 /* Software interrupt */
1772 if ((opcode
& 0x0f000000) == 0x0f000000)
1773 return evaluate_swi(opcode
, address
, instruction
);
1775 /* Coprocessor data processing */
1776 if ((opcode
& 0x0f000010) == 0x0e000000)
1777 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1779 /* Coprocessor register transfers */
1780 if ((opcode
& 0x0f000010) == 0x0e000010)
1781 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1784 LOG_ERROR("should never reach this point");
1788 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1789 uint32_t address
, struct arm_instruction
*instruction
)
1791 uint32_t offset
= opcode
& 0x7ff;
1792 uint32_t opc
= (opcode
>> 11) & 0x3;
1793 uint32_t target_address
;
1794 char *mnemonic
= NULL
;
1796 /* sign extend 11-bit offset */
1797 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1798 offset
= 0xfffff800 | offset
;
1800 target_address
= address
+ 4 + (offset
<< 1);
1804 /* unconditional branch */
1806 instruction
->type
= ARM_B
;
1811 instruction
->type
= ARM_BLX
;
1813 target_address
&= 0xfffffffc;
1817 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1818 mnemonic
= "prefix";
1819 target_address
= offset
<< 12;
1823 instruction
->type
= ARM_BL
;
1828 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
1829 * these are effectively 32-bit instructions even in Thumb1. For
1830 * disassembly, it's simplest to always use the Thumb2 decoder.
1832 * But some cores will evidently handle them as two instructions,
1833 * where exceptions may occur between the two. The ETMv3.2+ ID
1834 * register has a bit which exposes this behavior.
1837 snprintf(instruction
->text
, 128,
1838 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
1839 address
, opcode
, mnemonic
, target_address
);
1841 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1842 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1847 static int evaluate_add_sub_thumb(uint16_t opcode
,
1848 uint32_t address
, struct arm_instruction
*instruction
)
1850 uint8_t Rd
= (opcode
>> 0) & 0x7;
1851 uint8_t Rn
= (opcode
>> 3) & 0x7;
1852 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1853 uint32_t opc
= opcode
& (1 << 9);
1854 uint32_t reg_imm
= opcode
& (1 << 10);
1859 instruction
->type
= ARM_SUB
;
1864 /* REVISIT: if reg_imm == 0, display as "MOVS" */
1865 instruction
->type
= ARM_ADD
;
1869 instruction
->info
.data_proc
.Rd
= Rd
;
1870 instruction
->info
.data_proc
.Rn
= Rn
;
1871 instruction
->info
.data_proc
.S
= 1;
1875 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1876 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1877 snprintf(instruction
->text
, 128,
1878 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
1879 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1883 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1884 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1885 snprintf(instruction
->text
, 128,
1886 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
1887 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1893 static int evaluate_shift_imm_thumb(uint16_t opcode
,
1894 uint32_t address
, struct arm_instruction
*instruction
)
1896 uint8_t Rd
= (opcode
>> 0) & 0x7;
1897 uint8_t Rm
= (opcode
>> 3) & 0x7;
1898 uint8_t imm
= (opcode
>> 6) & 0x1f;
1899 uint8_t opc
= (opcode
>> 11) & 0x3;
1900 char *mnemonic
= NULL
;
1905 instruction
->type
= ARM_MOV
;
1907 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1910 instruction
->type
= ARM_MOV
;
1912 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1915 instruction
->type
= ARM_MOV
;
1917 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1921 if ((imm
== 0) && (opc
!= 0))
1924 instruction
->info
.data_proc
.Rd
= Rd
;
1925 instruction
->info
.data_proc
.Rn
= -1;
1926 instruction
->info
.data_proc
.S
= 1;
1928 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1929 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1930 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1932 snprintf(instruction
->text
, 128,
1933 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x" ,
1934 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1939 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
1940 uint32_t address
, struct arm_instruction
*instruction
)
1942 uint8_t imm
= opcode
& 0xff;
1943 uint8_t Rd
= (opcode
>> 8) & 0x7;
1944 uint32_t opc
= (opcode
>> 11) & 0x3;
1945 char *mnemonic
= NULL
;
1947 instruction
->info
.data_proc
.Rd
= Rd
;
1948 instruction
->info
.data_proc
.Rn
= Rd
;
1949 instruction
->info
.data_proc
.S
= 1;
1950 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1951 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1956 instruction
->type
= ARM_MOV
;
1958 instruction
->info
.data_proc
.Rn
= -1;
1961 instruction
->type
= ARM_CMP
;
1963 instruction
->info
.data_proc
.Rd
= -1;
1966 instruction
->type
= ARM_ADD
;
1970 instruction
->type
= ARM_SUB
;
1975 snprintf(instruction
->text
, 128,
1976 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
1977 address
, opcode
, mnemonic
, Rd
, imm
);
1982 static int evaluate_data_proc_thumb(uint16_t opcode
,
1983 uint32_t address
, struct arm_instruction
*instruction
)
1985 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1986 char *mnemonic
= NULL
;
1989 high_reg
= (opcode
& 0x0400) >> 10;
1990 op
= (opcode
& 0x03C0) >> 6;
1992 Rd
= (opcode
& 0x0007);
1993 Rm
= (opcode
& 0x0038) >> 3;
1994 H1
= (opcode
& 0x0080) >> 7;
1995 H2
= (opcode
& 0x0040) >> 6;
1997 instruction
->info
.data_proc
.Rd
= Rd
;
1998 instruction
->info
.data_proc
.Rn
= Rd
;
1999 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2000 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2001 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2012 instruction
->type
= ARM_ADD
;
2016 instruction
->type
= ARM_CMP
;
2020 instruction
->type
= ARM_MOV
;
2026 if ((opcode
& 0x7) == 0x0)
2028 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2031 instruction
->type
= ARM_BLX
;
2032 snprintf(instruction
->text
, 128,
2034 " 0x%4.4x \tBLX\tr%i",
2035 address
, opcode
, Rm
);
2039 instruction
->type
= ARM_BX
;
2040 snprintf(instruction
->text
, 128,
2042 " 0x%4.4x \tBX\tr%i",
2043 address
, opcode
, Rm
);
2048 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2049 snprintf(instruction
->text
, 128,
2052 "UNDEFINED INSTRUCTION",
2064 instruction
->type
= ARM_AND
;
2068 instruction
->type
= ARM_EOR
;
2072 instruction
->type
= ARM_MOV
;
2074 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2075 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2076 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2077 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2080 instruction
->type
= ARM_MOV
;
2082 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2083 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2084 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2085 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2088 instruction
->type
= ARM_MOV
;
2090 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2091 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2092 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2093 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2096 instruction
->type
= ARM_ADC
;
2100 instruction
->type
= ARM_SBC
;
2104 instruction
->type
= ARM_MOV
;
2106 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2107 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2108 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2109 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2112 instruction
->type
= ARM_TST
;
2116 instruction
->type
= ARM_RSB
;
2118 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2119 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2120 instruction
->info
.data_proc
.Rn
= Rm
;
2123 instruction
->type
= ARM_CMP
;
2127 instruction
->type
= ARM_CMN
;
2131 instruction
->type
= ARM_ORR
;
2135 instruction
->type
= ARM_MUL
;
2139 instruction
->type
= ARM_BIC
;
2143 instruction
->type
= ARM_MVN
;
2150 snprintf(instruction
->text
, 128,
2151 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2153 address
, opcode
, mnemonic
, Rd
, Rm
);
2155 snprintf(instruction
->text
, 128,
2156 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2157 address
, opcode
, mnemonic
, Rd
, Rm
);
2162 /* PC-relative data addressing is word-aligned even with Thumb */
2163 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2165 return (addr
+ 4) & ~3;
2168 static int evaluate_load_literal_thumb(uint16_t opcode
,
2169 uint32_t address
, struct arm_instruction
*instruction
)
2172 uint8_t Rd
= (opcode
>> 8) & 0x7;
2174 instruction
->type
= ARM_LDR
;
2175 immediate
= opcode
& 0x000000ff;
2178 instruction
->info
.load_store
.Rd
= Rd
;
2179 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2180 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2181 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2182 instruction
->info
.load_store
.offset
.offset
= immediate
;
2184 snprintf(instruction
->text
, 128,
2185 "0x%8.8" PRIx32
" 0x%4.4x \t"
2186 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2187 address
, opcode
, Rd
, immediate
,
2188 thumb_alignpc4(address
) + immediate
);
2193 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2194 uint32_t address
, struct arm_instruction
*instruction
)
2196 uint8_t Rd
= (opcode
>> 0) & 0x7;
2197 uint8_t Rn
= (opcode
>> 3) & 0x7;
2198 uint8_t Rm
= (opcode
>> 6) & 0x7;
2199 uint8_t opc
= (opcode
>> 9) & 0x7;
2200 char *mnemonic
= NULL
;
2205 instruction
->type
= ARM_STR
;
2209 instruction
->type
= ARM_STRH
;
2213 instruction
->type
= ARM_STRB
;
2217 instruction
->type
= ARM_LDRSB
;
2221 instruction
->type
= ARM_LDR
;
2225 instruction
->type
= ARM_LDRH
;
2229 instruction
->type
= ARM_LDRB
;
2233 instruction
->type
= ARM_LDRSH
;
2238 snprintf(instruction
->text
, 128,
2239 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2240 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2242 instruction
->info
.load_store
.Rd
= Rd
;
2243 instruction
->info
.load_store
.Rn
= Rn
;
2244 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2245 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2246 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2251 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2252 uint32_t address
, struct arm_instruction
*instruction
)
2254 uint32_t offset
= (opcode
>> 6) & 0x1f;
2255 uint8_t Rd
= (opcode
>> 0) & 0x7;
2256 uint8_t Rn
= (opcode
>> 3) & 0x7;
2257 uint32_t L
= opcode
& (1 << 11);
2258 uint32_t B
= opcode
& (1 << 12);
2265 instruction
->type
= ARM_LDR
;
2270 instruction
->type
= ARM_STR
;
2274 if ((opcode
&0xF000) == 0x8000)
2285 snprintf(instruction
->text
, 128,
2286 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2287 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2289 instruction
->info
.load_store
.Rd
= Rd
;
2290 instruction
->info
.load_store
.Rn
= Rn
;
2291 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2292 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2293 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2298 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2299 uint32_t address
, struct arm_instruction
*instruction
)
2301 uint32_t offset
= opcode
& 0xff;
2302 uint8_t Rd
= (opcode
>> 8) & 0x7;
2303 uint32_t L
= opcode
& (1 << 11);
2308 instruction
->type
= ARM_LDR
;
2313 instruction
->type
= ARM_STR
;
2317 snprintf(instruction
->text
, 128,
2318 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2319 address
, opcode
, mnemonic
, Rd
, offset
*4);
2321 instruction
->info
.load_store
.Rd
= Rd
;
2322 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2323 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2324 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2325 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2330 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2331 uint32_t address
, struct arm_instruction
*instruction
)
2333 uint32_t imm
= opcode
& 0xff;
2334 uint8_t Rd
= (opcode
>> 8) & 0x7;
2336 uint32_t SP
= opcode
& (1 << 11);
2339 instruction
->type
= ARM_ADD
;
2352 snprintf(instruction
->text
, 128,
2353 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2354 address
, opcode
, Rd
, reg_name
, imm
* 4);
2356 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2357 instruction
->info
.data_proc
.Rd
= Rd
;
2358 instruction
->info
.data_proc
.Rn
= Rn
;
2359 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2364 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2365 uint32_t address
, struct arm_instruction
*instruction
)
2367 uint32_t imm
= opcode
& 0x7f;
2368 uint8_t opc
= opcode
& (1 << 7);
2374 instruction
->type
= ARM_SUB
;
2379 instruction
->type
= ARM_ADD
;
2383 snprintf(instruction
->text
, 128,
2384 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2385 address
, opcode
, mnemonic
, imm
*4);
2387 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2388 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2389 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2390 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2395 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2396 uint32_t address
, struct arm_instruction
*instruction
)
2398 uint32_t imm
= opcode
& 0xff;
2400 instruction
->type
= ARM_BKPT
;
2402 snprintf(instruction
->text
, 128,
2403 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2404 address
, opcode
, imm
);
2409 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2410 uint32_t address
, struct arm_instruction
*instruction
)
2412 uint32_t reg_list
= opcode
& 0xff;
2413 uint32_t L
= opcode
& (1 << 11);
2414 uint32_t R
= opcode
& (1 << 8);
2415 uint8_t Rn
= (opcode
>> 8) & 7;
2416 uint8_t addr_mode
= 0 /* IA */;
2420 char ptr_name
[7] = "";
2423 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2424 * The STMIA and LDMIA opcodes are used for other instructions.
2427 if ((opcode
& 0xf000) == 0xc000)
2428 { /* generic load/store multiple */
2433 instruction
->type
= ARM_LDM
;
2435 if (opcode
& (1 << Rn
))
2440 instruction
->type
= ARM_STM
;
2443 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2450 instruction
->type
= ARM_LDM
;
2453 reg_list
|= (1 << 15) /*PC*/;
2457 instruction
->type
= ARM_STM
;
2459 addr_mode
= 3; /*DB*/
2461 reg_list
|= (1 << 14) /*LR*/;
2465 reg_names_p
= reg_names
;
2466 for (i
= 0; i
<= 15; i
++)
2468 if (reg_list
& (1 << i
))
2469 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
2471 if (reg_names_p
> reg_names
)
2472 reg_names_p
[-2] = '\0';
2473 else /* invalid op : no registers */
2474 reg_names
[0] = '\0';
2476 snprintf(instruction
->text
, 128,
2477 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2478 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2480 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2481 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2482 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2487 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2488 uint32_t address
, struct arm_instruction
*instruction
)
2490 uint32_t offset
= opcode
& 0xff;
2491 uint8_t cond
= (opcode
>> 8) & 0xf;
2492 uint32_t target_address
;
2496 instruction
->type
= ARM_SWI
;
2497 snprintf(instruction
->text
, 128,
2498 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2499 address
, opcode
, offset
);
2502 else if (cond
== 0xe)
2504 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2505 snprintf(instruction
->text
, 128,
2506 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2511 /* sign extend 8-bit offset */
2512 if (offset
& 0x00000080)
2513 offset
= 0xffffff00 | offset
;
2515 target_address
= address
+ 4 + (offset
<< 1);
2517 snprintf(instruction
->text
, 128,
2518 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2520 arm_condition_strings
[cond
], target_address
);
2522 instruction
->type
= ARM_B
;
2523 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2524 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2529 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2530 struct arm_instruction
*instruction
)
2534 /* added in Thumb2 */
2535 offset
= (opcode
>> 3) & 0x1f;
2536 offset
|= (opcode
& 0x0200) >> 4;
2538 snprintf(instruction
->text
, 128,
2539 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2541 (opcode
& 0x0800) ? "N" : "",
2542 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2547 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2548 struct arm_instruction
*instruction
)
2550 /* added in ARMv6 */
2551 snprintf(instruction
->text
, 128,
2552 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2554 (opcode
& 0x0080) ? 'U' : 'S',
2555 (opcode
& 0x0040) ? 'B' : 'H',
2556 opcode
& 0x7, (opcode
>> 3) & 0x7);
2561 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2562 struct arm_instruction
*instruction
)
2564 /* added in ARMv6 */
2565 if ((opcode
& 0x0ff0) == 0x0650)
2566 snprintf(instruction
->text
, 128,
2567 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2569 (opcode
& 0x80) ? "BE" : "LE");
2570 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2571 snprintf(instruction
->text
, 128,
2572 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2574 (opcode
& 0x0010) ? 'D' : 'E',
2575 (opcode
& 0x0004) ? "A" : "",
2576 (opcode
& 0x0002) ? "I" : "",
2577 (opcode
& 0x0001) ? "F" : "");
2582 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2583 struct arm_instruction
*instruction
)
2587 /* added in ARMv6 */
2588 switch ((opcode
>> 6) & 3) {
2599 snprintf(instruction
->text
, 128,
2600 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2601 address
, opcode
, suffix
,
2602 opcode
& 0x7, (opcode
>> 3) & 0x7);
2607 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2608 struct arm_instruction
*instruction
)
2612 switch ((opcode
>> 4) & 0x0f) {
2629 hint
= "HINT (UNRECOGNIZED)";
2633 snprintf(instruction
->text
, 128,
2634 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2635 address
, opcode
, hint
);
2640 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2641 struct arm_instruction
*instruction
)
2643 unsigned cond
= (opcode
>> 4) & 0x0f;
2644 char *x
= "", *y
= "", *z
= "";
2647 z
= (opcode
& 0x02) ? "T" : "E";
2649 y
= (opcode
& 0x04) ? "T" : "E";
2651 x
= (opcode
& 0x08) ? "T" : "E";
2653 snprintf(instruction
->text
, 128,
2654 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2656 x
, y
, z
, arm_condition_strings
[cond
]);
2658 /* NOTE: strictly speaking, the next 1-4 instructions should
2659 * now be displayed with the relevant conditional suffix...
2665 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2667 /* clear fields, to avoid confusion */
2668 memset(instruction
, 0, sizeof(struct arm_instruction
));
2669 instruction
->opcode
= opcode
;
2670 instruction
->instruction_size
= 2;
2672 if ((opcode
& 0xe000) == 0x0000)
2674 /* add/substract register or immediate */
2675 if ((opcode
& 0x1800) == 0x1800)
2676 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2677 /* shift by immediate */
2679 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2682 /* Add/substract/compare/move immediate */
2683 if ((opcode
& 0xe000) == 0x2000)
2685 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2688 /* Data processing instructions */
2689 if ((opcode
& 0xf800) == 0x4000)
2691 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2694 /* Load from literal pool */
2695 if ((opcode
& 0xf800) == 0x4800)
2697 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2700 /* Load/Store register offset */
2701 if ((opcode
& 0xf000) == 0x5000)
2703 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2706 /* Load/Store immediate offset */
2707 if (((opcode
& 0xe000) == 0x6000)
2708 ||((opcode
& 0xf000) == 0x8000))
2710 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2713 /* Load/Store from/to stack */
2714 if ((opcode
& 0xf000) == 0x9000)
2716 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2720 if ((opcode
& 0xf000) == 0xa000)
2722 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2726 if ((opcode
& 0xf000) == 0xb000)
2728 switch ((opcode
>> 8) & 0x0f) {
2730 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2735 return evaluate_cb_thumb(opcode
, address
, instruction
);
2737 return evaluate_extend_thumb(opcode
, address
, instruction
);
2742 return evaluate_load_store_multiple_thumb(opcode
, address
,
2745 return evaluate_cps_thumb(opcode
, address
, instruction
);
2747 if ((opcode
& 0x00c0) == 0x0080)
2749 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2751 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2753 if (opcode
& 0x000f)
2754 return evaluate_ifthen_thumb(opcode
, address
,
2757 return evaluate_hint_thumb(opcode
, address
,
2761 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2762 snprintf(instruction
->text
, 128,
2763 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2768 /* Load/Store multiple */
2769 if ((opcode
& 0xf000) == 0xc000)
2771 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2774 /* Conditional branch + SWI */
2775 if ((opcode
& 0xf000) == 0xd000)
2777 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2780 if ((opcode
& 0xe000) == 0xe000)
2782 /* Undefined instructions */
2783 if ((opcode
& 0xf801) == 0xe801)
2785 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2786 snprintf(instruction
->text
, 128,
2787 "0x%8.8" PRIx32
" 0x%8.8x\t"
2788 "UNDEFINED INSTRUCTION",
2793 { /* Branch to offset */
2794 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2798 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2802 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2803 struct arm_instruction
*instruction
, char *cp
)
2806 unsigned b21
= 1 << 21;
2807 unsigned b22
= 1 << 22;
2809 /* instead of combining two smaller 16-bit branch instructions,
2810 * Thumb2 uses only one larger 32-bit instruction.
2812 offset
= opcode
& 0x7ff;
2813 offset
|= (opcode
& 0x03ff0000) >> 5;
2814 if (opcode
& (1 << 26)) {
2815 offset
|= 0xff << 23;
2816 if ((opcode
& (1 << 11)) == 0)
2818 if ((opcode
& (1 << 13)) == 0)
2821 if (opcode
& (1 << 11))
2823 if (opcode
& (1 << 13))
2831 address
+= offset
<< 1;
2833 instruction
->type
= (opcode
& (1 << 14)) ? ARM_BL
: ARM_B
;
2834 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2835 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2836 sprintf(cp
, "%s\t%#8.8" PRIx32
,
2837 (opcode
& (1 << 14)) ? "BL" : "B.W",
2843 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2844 struct arm_instruction
*instruction
, char *cp
)
2847 unsigned b17
= 1 << 17;
2848 unsigned b18
= 1 << 18;
2849 unsigned cond
= (opcode
>> 22) & 0x0f;
2851 offset
= opcode
& 0x7ff;
2852 offset
|= (opcode
& 0x003f0000) >> 5;
2853 if (opcode
& (1 << 26)) {
2854 offset
|= 0xffff << 19;
2855 if ((opcode
& (1 << 11)) == 0)
2857 if ((opcode
& (1 << 13)) == 0)
2860 if (opcode
& (1 << 11))
2862 if (opcode
& (1 << 13))
2869 address
+= offset
<< 1;
2871 instruction
->type
= ARM_B
;
2872 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2873 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2874 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
2875 arm_condition_strings
[cond
],
2881 static const char *special_name(int number
)
2883 char *special
= "(RESERVED)";
2914 special
= "primask";
2917 special
= "basepri";
2920 special
= "basepri_max";
2923 special
= "faultmask";
2926 special
= "control";
2932 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
2933 struct arm_instruction
*instruction
, char *cp
)
2935 const char *mnemonic
;
2937 if (opcode
& 0x0700) {
2938 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2939 strcpy(cp
, "UNDEFINED");
2943 if (opcode
& 0x00f0) {
2944 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
2948 switch (opcode
& 0x0f) {
2953 mnemonic
= "YIELD.W";
2965 mnemonic
= "HINT.W (UNRECOGNIZED)";
2968 strcpy(cp
, mnemonic
);
2972 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
2973 struct arm_instruction
*instruction
, char *cp
)
2975 const char *mnemonic
;
2977 switch ((opcode
>> 4) & 0x0f) {
2979 mnemonic
= "LEAVEX";
2982 mnemonic
= "ENTERX";
2997 return ERROR_INVALID_ARGUMENTS
;
2999 strcpy(cp
, mnemonic
);
3003 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3004 struct arm_instruction
*instruction
, char *cp
)
3006 /* permanently undefined */
3007 if ((opcode
& 0x07f07000) == 0x07f02000) {
3008 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3009 strcpy(cp
, "UNDEFINED");
3013 switch ((opcode
>> 12) & 0x5) {
3016 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3020 if (((opcode
>> 23) & 0x07) != 0x07)
3021 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3022 if (opcode
& (1 << 26))
3027 switch ((opcode
>> 20) & 0x7f) {
3030 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3031 (int) (opcode
>> 16) & 0x0f);
3034 return t2ev_hint(opcode
, address
, instruction
, cp
);
3036 return t2ev_misc(opcode
, address
, instruction
, cp
);
3038 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3042 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3043 special_name(opcode
& 0xff));
3048 return ERROR_INVALID_ARGUMENTS
;
3051 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3052 struct arm_instruction
*instruction
, char *cp
)
3054 char *mnemonic
= NULL
;
3055 int rn
= (opcode
>> 16) & 0xf;
3056 int rd
= (opcode
>> 8) & 0xf;
3057 unsigned immed
= opcode
& 0xff;
3063 /* ARMv7-M: A5.3.2 Modified immediate constants */
3064 func
= (opcode
>> 11) & 0x0e;
3067 if (opcode
& (1 << 26))
3070 /* "Modified" immediates */
3071 switch (func
>> 1) {
3078 immed
+= immed
<< 16;
3081 immed
+= immed
<< 8;
3082 immed
+= immed
<< 16;
3086 immed
= ror(immed
, func
);
3089 if (opcode
& (1 << 20))
3092 switch ((opcode
>> 21) & 0xf) {
3095 instruction
->type
= ARM_TST
;
3101 instruction
->type
= ARM_AND
;
3106 instruction
->type
= ARM_BIC
;
3111 instruction
->type
= ARM_MOV
;
3116 instruction
->type
= ARM_ORR
;
3122 instruction
->type
= ARM_MVN
;
3126 // instruction->type = ARM_ORN;
3132 instruction
->type
= ARM_TEQ
;
3138 instruction
->type
= ARM_EOR
;
3144 instruction
->type
= ARM_CMN
;
3150 instruction
->type
= ARM_ADD
;
3156 instruction
->type
= ARM_ADC
;
3161 instruction
->type
= ARM_SBC
;
3166 instruction
->type
= ARM_CMP
;
3172 instruction
->type
= ARM_SUB
;
3178 instruction
->type
= ARM_RSB
;
3183 return ERROR_INVALID_ARGUMENTS
;
3187 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3188 mnemonic
, suffix2
,rd
, immed
, immed
);
3190 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3191 mnemonic
, suffix
, suffix2
,
3192 rd
, rn
, immed
, immed
);
3197 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3198 struct arm_instruction
*instruction
, char *cp
)
3200 char *mnemonic
= NULL
;
3201 int rn
= (opcode
>> 16) & 0xf;
3202 int rd
= (opcode
>> 8) & 0xf;
3205 bool is_signed
= false;
3207 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3208 if (opcode
& (1 << 26))
3211 switch ((opcode
>> 20) & 0x1f) {
3220 immed
|= (opcode
>> 4) & 0xf000;
3221 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3229 /* move constant to top 16 bits of register */
3230 immed
|= (opcode
>> 4) & 0xf000;
3231 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rn
, immed
, immed
);
3238 /* signed/unsigned saturated add */
3239 immed
= (opcode
>> 6) & 0x03;
3240 immed
|= (opcode
>> 10) & 0x1c;
3241 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3242 is_signed
? "S" : "U",
3243 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3244 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3245 immed
? immed
: 32);
3251 /* signed/unsigned bitfield extract */
3252 immed
= (opcode
>> 6) & 0x03;
3253 immed
|= (opcode
>> 10) & 0x1c;
3254 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3255 is_signed
? "S" : "U",
3257 (int) (opcode
& 0x1f) + 1);
3260 immed
= (opcode
>> 6) & 0x03;
3261 immed
|= (opcode
>> 10) & 0x1c;
3262 if (rn
== 0xf) /* bitfield clear */
3263 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3265 (int) (opcode
& 0x1f) + 1 - immed
);
3266 else /* bitfield insert */
3267 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3269 (int) (opcode
& 0x1f) + 1 - immed
);
3272 return ERROR_INVALID_ARGUMENTS
;
3275 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3276 rd
, rn
, immed
, immed
);
3280 address
= thumb_alignpc4(address
);
3285 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3286 * not hiding the pc-relative stuff will sometimes be useful.
3288 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3292 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3293 struct arm_instruction
*instruction
, char *cp
)
3295 unsigned op
= (opcode
>> 20) & 0xf;
3301 unsigned rn
= (opcode
>> 16) & 0x0f;
3302 unsigned rt
= (opcode
>> 12) & 0x0f;
3305 return ERROR_INVALID_ARGUMENTS
;
3307 if (opcode
& 0x0800)
3342 return ERROR_INVALID_ARGUMENTS
;
3345 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3346 size
, rt
, rn
, (int) opcode
& 0x0f,
3347 (int) (opcode
>> 4) & 0x03);
3351 immed
= opcode
& 0x0fff;
3352 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3353 size
, rt
, rn
, immed
, immed
);
3357 immed
= opcode
& 0x00ff;
3359 switch (opcode
& 0x700) {
3365 return ERROR_INVALID_ARGUMENTS
;
3368 /* two indexed modes will write back rn */
3369 if (opcode
& 0x100) {
3370 if (opcode
& 0x400) /* pre-indexed */
3372 else { /* post-indexed */
3378 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3379 size
, suffix
, rt
, rn
, p1
,
3380 (opcode
& 0x200) ? "" : "-",
3385 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3386 struct arm_instruction
*instruction
, char *cp
)
3388 int ra
= (opcode
>> 12) & 0xf;
3390 switch (opcode
& 0x007000f0) {
3393 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3394 (int) (opcode
>> 8) & 0xf,
3395 (int) (opcode
>> 16) & 0xf,
3396 (int) (opcode
>> 0) & 0xf);
3398 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3399 (int) (opcode
>> 8) & 0xf,
3400 (int) (opcode
>> 16) & 0xf,
3401 (int) (opcode
>> 0) & 0xf, ra
);
3404 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3405 (int) (opcode
>> 8) & 0xf,
3406 (int) (opcode
>> 16) & 0xf,
3407 (int) (opcode
>> 0) & 0xf, ra
);
3410 return ERROR_INVALID_ARGUMENTS
;
3415 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3416 struct arm_instruction
*instruction
, char *cp
)
3418 int op
= (opcode
>> 4) & 0xf;
3419 char *infix
= "MUL";
3421 op
+= (opcode
>> 16) & 0x70;
3429 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3430 (op
& 0x20) ? 'U' : 'S',
3432 (int) (opcode
>> 12) & 0xf,
3433 (int) (opcode
>> 8) & 0xf,
3434 (int) (opcode
>> 16) & 0xf,
3435 (int) (opcode
>> 0) & 0xf);
3439 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3440 (op
& 0x20) ? 'U' : 'S',
3441 (int) (opcode
>> 8) & 0xf,
3442 (int) (opcode
>> 16) & 0xf,
3443 (int) (opcode
>> 0) & 0xf);
3446 return ERROR_INVALID_ARGUMENTS
;
3452 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3453 struct arm_instruction
*instruction
, char *cp
)
3455 int rn
= (opcode
>> 16) & 0xf;
3456 int op
= (opcode
>> 22) & 0x6;
3457 int t
= (opcode
>> 21) & 1;
3458 unsigned registers
= opcode
& 0xffff;
3461 if (opcode
& (1 << 20))
3469 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3477 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3478 (opcode
>> 16) & 0xf,
3482 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3486 sprintf(cp
, "POP.W\t");
3488 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3492 sprintf(cp
, "PUSH.W\t");
3494 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3497 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3500 return ERROR_INVALID_ARGUMENTS
;
3505 for (t
= 0; registers
; t
++, registers
>>= 1) {
3506 if ((registers
& 1) == 0)
3509 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3518 /* load/store dual or exclusive, table branch */
3519 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3520 struct arm_instruction
*instruction
, char *cp
)
3522 unsigned op1op2
= (opcode
>> 20) & 0x3;
3523 unsigned op3
= (opcode
>> 4) & 0xf;
3525 unsigned rn
= (opcode
>> 16) & 0xf;
3526 unsigned rt
= (opcode
>> 12) & 0xf;
3527 unsigned rd
= (opcode
>> 8) & 0xf;
3528 unsigned imm
= opcode
& 0xff;
3532 op1op2
|= (opcode
>> 21) & 0xc;
3562 mnemonic
= "STREXB";
3565 mnemonic
= "STREXH";
3568 return ERROR_INVALID_ARGUMENTS
;
3576 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3579 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3582 mnemonic
= "LDREXB";
3585 mnemonic
= "LDREXH";
3588 return ERROR_INVALID_ARGUMENTS
;
3593 return ERROR_INVALID_ARGUMENTS
;
3598 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3599 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3601 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3602 mnemonic
, rd
, rt
, rn
);
3608 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3609 mnemonic
, rt
, rn
, imm
, imm
);
3611 sprintf(cp
, "%s\tr%u, [r%u]",
3616 /* two indexed modes will write back rn */
3617 if (opcode
& (1 << 21)) {
3618 if (opcode
& (1 << 24)) /* pre-indexed */
3620 else { /* post-indexed */
3627 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3628 mnemonic
, rt
, rd
, rn
, p1
,
3629 (opcode
& (1 << 23)) ? "" : "-",
3634 address
= thumb_alignpc4(address
);
3636 if (opcode
& (1 << 23))
3640 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3641 mnemonic
, rt
, rd
, address
);
3645 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3646 struct arm_instruction
*instruction
, char *cp
)
3648 int op
= (opcode
>> 21) & 0xf;
3649 int rd
= (opcode
>> 8) & 0xf;
3650 int rn
= (opcode
>> 16) & 0xf;
3651 int type
= (opcode
>> 4) & 0x3;
3652 int immed
= (opcode
>> 6) & 0x3;
3656 immed
|= (opcode
>> 10) & 0x1c;
3657 if (opcode
& (1 << 20))
3663 if (!(opcode
& (1 << 20)))
3664 return ERROR_INVALID_ARGUMENTS
;
3665 instruction
->type
= ARM_TST
;
3670 instruction
->type
= ARM_AND
;
3674 instruction
->type
= ARM_BIC
;
3679 instruction
->type
= ARM_MOV
;
3683 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3685 (int) (opcode
& 0xf));
3698 sprintf(cp
, "RRX%s\tr%d, r%d",
3700 (int) (opcode
& 0xf));
3708 instruction
->type
= ARM_ORR
;
3714 instruction
->type
= ARM_MVN
;
3719 // instruction->type = ARM_ORN;
3725 if (!(opcode
& (1 << 20)))
3726 return ERROR_INVALID_ARGUMENTS
;
3727 instruction
->type
= ARM_TEQ
;
3732 instruction
->type
= ARM_EOR
;
3737 if (!(opcode
& (1 << 20)))
3738 return ERROR_INVALID_ARGUMENTS
;
3739 instruction
->type
= ARM_CMN
;
3744 instruction
->type
= ARM_ADD
;
3748 instruction
->type
= ARM_ADC
;
3752 instruction
->type
= ARM_SBC
;
3757 if (!(opcode
& (1 << 21)))
3758 return ERROR_INVALID_ARGUMENTS
;
3759 instruction
->type
= ARM_CMP
;
3764 instruction
->type
= ARM_SUB
;
3768 instruction
->type
= ARM_RSB
;
3772 return ERROR_INVALID_ARGUMENTS
;
3775 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3776 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3799 strcpy(cp
, ", RRX");
3805 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3809 sprintf(cp
, "%s%s.W\tr%d, r%d",
3810 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3814 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3815 mnemonic
, suffix
, rd
,
3816 (int) (opcode
& 0xf), immed
? immed
: 32);
3820 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3821 struct arm_instruction
*instruction
, char *cp
)
3826 if (((opcode
>> 4) & 0xf) == 0) {
3827 switch ((opcode
>> 21) & 0x7) {
3841 return ERROR_INVALID_ARGUMENTS
;
3844 instruction
->type
= ARM_MOV
;
3845 if (opcode
& (1 << 20))
3847 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3849 (int) (opcode
>> 8) & 0xf,
3850 (int) (opcode
>> 16) & 0xf,
3851 (int) (opcode
>> 0) & 0xf);
3853 } else if (opcode
& (1 << 7)) {
3854 switch ((opcode
>> 20) & 0xf) {
3859 switch ((opcode
>> 4) & 0x3) {
3861 suffix
= ", ROR #8";
3864 suffix
= ", ROR #16";
3867 suffix
= ", ROR #24";
3870 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
3871 (opcode
& (1 << 24)) ? 'U' : 'S',
3872 (opcode
& (1 << 26)) ? 'B' : 'H',
3873 (int) (opcode
>> 8) & 0xf,
3874 (int) (opcode
>> 0) & 0xf,
3881 if (opcode
& (1 << 6))
3882 return ERROR_INVALID_ARGUMENTS
;
3883 if (((opcode
>> 12) & 0xf) != 0xf)
3884 return ERROR_INVALID_ARGUMENTS
;
3885 if (!(opcode
& (1 << 20)))
3886 return ERROR_INVALID_ARGUMENTS
;
3888 switch (((opcode
>> 19) & 0x04)
3889 | ((opcode
>> 4) & 0x3)) {
3894 mnemonic
= "REV16.W";
3900 mnemonic
= "REVSH.W";
3906 return ERROR_INVALID_ARGUMENTS
;
3908 sprintf(cp
, "%s\tr%d, r%d",
3910 (int) (opcode
>> 8) & 0xf,
3911 (int) (opcode
>> 0) & 0xf);
3914 return ERROR_INVALID_ARGUMENTS
;
3921 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
3922 struct arm_instruction
*instruction
, char *cp
)
3924 int rn
= (opcode
>> 16) & 0xf;
3927 instruction
->type
= ARM_LDR
;
3930 immed
= opcode
& 0x0fff;
3931 if ((opcode
& (1 << 23)) == 0)
3933 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
3934 (int) (opcode
>> 12) & 0xf,
3935 thumb_alignpc4(address
) + immed
);
3939 if (opcode
& (1 << 23)) {
3940 immed
= opcode
& 0x0fff;
3941 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
3942 (int) (opcode
>> 12) & 0xf,
3947 if (!(opcode
& (0x3f << 6))) {
3948 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
3949 (int) (opcode
>> 12) & 0xf,
3951 (int) (opcode
>> 0) & 0xf,
3952 (int) (opcode
>> 4) & 0x3);
3957 if (((opcode
>> 8) & 0xf) == 0xe) {
3958 immed
= opcode
& 0x00ff;
3960 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
3961 (int) (opcode
>> 12) & 0xf,
3966 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
3967 char *p1
= "]", *p2
= "";
3969 if (!(opcode
& 0x0500))
3970 return ERROR_INVALID_ARGUMENTS
;
3972 immed
= opcode
& 0x00ff;
3974 /* two indexed modes will write back rn */
3975 if (opcode
& 0x100) {
3976 if (opcode
& 0x400) /* pre-indexed */
3978 else { /* post-indexed */
3984 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3985 (int) (opcode
>> 12) & 0xf,
3987 (opcode
& 0x200) ? "" : "-",
3992 return ERROR_INVALID_ARGUMENTS
;
3995 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
3996 struct arm_instruction
*instruction
, char *cp
)
3998 int rn
= (opcode
>> 16) & 0xf;
3999 int rt
= (opcode
>> 12) & 0xf;
4000 int op2
= (opcode
>> 6) & 0x3f;
4002 char *p1
= "", *p2
= "]";
4005 switch ((opcode
>> 23) & 0x3) {
4007 if ((rn
& rt
) == 0xf) {
4009 immed
= opcode
& 0xfff;
4010 address
= thumb_alignpc4(address
);
4011 if (opcode
& (1 << 23))
4015 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4019 if (rn
== 0x0f && rt
!= 0x0f) {
4021 immed
= opcode
& 0xfff;
4022 address
= thumb_alignpc4(address
);
4023 if (opcode
& (1 << 23))
4027 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4033 if ((op2
& 0x3c) == 0x38) {
4034 immed
= opcode
& 0xff;
4035 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4036 rt
, rn
, immed
, immed
);
4039 if ((op2
& 0x3c) == 0x30) {
4041 immed
= opcode
& 0xff;
4044 p1
= (opcode
& (1 << 21)) ? "W" : "";
4045 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4046 p1
, rn
, immed
, immed
);
4051 immed
= opcode
& 0xff;
4052 if (!(opcode
& 0x200))
4055 /* two indexed modes will write back rn */
4056 if (opcode
& 0x100) {
4057 if (opcode
& 0x400) /* pre-indexed */
4059 else { /* post-indexed */
4065 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4066 mnemonic
, rt
, rn
, p1
,
4070 if ((op2
& 0x24) == 0x24) {
4072 goto ldrxb_immediate_t3
;
4075 int rm
= opcode
& 0xf;
4078 sprintf(cp
, "PLD\t");
4080 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4081 immed
= (opcode
>> 4) & 0x3;
4083 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4088 if ((rn
& rt
) == 0xf)
4091 immed
= opcode
& 0xfff;
4092 goto preload_immediate
;
4096 mnemonic
= "LDRB.W";
4097 immed
= opcode
& 0xfff;
4098 goto ldrxb_immediate_t2
;
4100 if ((rn
& rt
) == 0xf) {
4101 immed
= opcode
& 0xfff;
4102 address
= thumb_alignpc4(address
);
4103 if (opcode
& (1 << 23))
4107 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4110 if (rn
== 0xf && rt
!= 0xf) {
4112 immed
= opcode
& 0xfff;
4113 address
= thumb_alignpc4(address
);
4114 if (opcode
& (1 << 23))
4118 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4123 if ((op2
& 0x3c) == 0x38) {
4124 immed
= opcode
& 0xff;
4125 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4126 rt
, rn
, immed
, immed
);
4129 if ((op2
& 0x3c) == 0x30) {
4131 immed
= opcode
& 0xff;
4132 immed
= -immed
; // pli
4133 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4138 goto ldrxb_immediate_t3
;
4140 if ((op2
& 0x24) == 0x24) {
4142 goto ldrxb_immediate_t3
;
4145 int rm
= opcode
& 0xf;
4148 sprintf(cp
, "PLI\t");
4150 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4151 immed
= (opcode
>> 4) & 0x3;
4153 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4159 immed
= opcode
& 0xfff;
4160 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4166 immed
= opcode
& 0xfff;
4168 goto ldrxb_immediate_t2
;
4171 return ERROR_INVALID_ARGUMENTS
;
4174 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4175 struct arm_instruction
*instruction
, char *cp
)
4177 int rn
= (opcode
>> 16) & 0xf;
4178 int rt
= (opcode
>> 12) & 0xf;
4179 int op2
= (opcode
>> 6) & 0x3f;
4184 sprintf(cp
, "HINT (UNALLOCATED)");
4188 if (opcode
& (1 << 24))
4191 if ((opcode
& (1 << 23)) == 0) {
4194 immed
= opcode
& 0xfff;
4195 address
= thumb_alignpc4(address
);
4196 if (opcode
& (1 << 23))
4200 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4205 int rm
= opcode
& 0xf;
4207 immed
= (opcode
>> 4) & 0x3;
4208 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4209 sign
, rt
, rn
, rm
, immed
);
4212 if ((op2
& 0x3c) == 0x38) {
4213 immed
= opcode
& 0xff;
4214 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4215 sign
, rt
, rn
, immed
, immed
);
4218 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4219 char *p1
= "", *p2
= "]";
4221 immed
= opcode
& 0xff;
4222 if (!(opcode
& 0x200))
4225 /* two indexed modes will write back rn */
4226 if (opcode
& 0x100) {
4227 if (opcode
& 0x400) /* pre-indexed */
4229 else { /* post-indexed */
4234 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4235 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4242 immed
= opcode
& 0xfff;
4243 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4244 sign
, *sign
? "" : ".W",
4245 rt
, rn
, immed
, immed
);
4249 return ERROR_INVALID_ARGUMENTS
;
4253 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4254 * always set. That means eventual arm_simulate_step() support for Thumb2
4255 * will need work in this area.
4257 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4264 /* clear low bit ... it's set on function pointers */
4267 /* clear fields, to avoid confusion */
4268 memset(instruction
, 0, sizeof(struct arm_instruction
));
4270 /* read first halfword, see if this is the only one */
4271 retval
= target_read_u16(target
, address
, &op
);
4272 if (retval
!= ERROR_OK
)
4275 switch (op
& 0xf800) {
4279 /* 32-bit instructions */
4280 instruction
->instruction_size
= 4;
4282 retval
= target_read_u16(target
, address
+ 2, &op
);
4283 if (retval
!= ERROR_OK
)
4286 instruction
->opcode
= opcode
;
4289 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4290 return thumb_evaluate_opcode(op
, address
, instruction
);
4293 snprintf(instruction
->text
, 128,
4294 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4296 cp
= strchr(instruction
->text
, 0);
4297 retval
= ERROR_FAIL
;
4299 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4300 if ((opcode
& 0x1a008000) == 0x10000000)
4301 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4303 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4304 else if ((opcode
& 0x1a008000) == 0x12000000)
4305 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4307 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4308 else if ((opcode
& 0x18008000) == 0x10008000)
4309 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4311 /* ARMv7-M: A5.3.5 Load/store multiple */
4312 else if ((opcode
& 0x1e400000) == 0x08000000)
4313 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4315 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4316 else if ((opcode
& 0x1e400000) == 0x08400000)
4317 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4319 /* ARMv7-M: A5.3.7 Load word */
4320 else if ((opcode
& 0x1f700000) == 0x18500000)
4321 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4323 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4324 else if ((opcode
& 0x1e700000) == 0x18300000)
4325 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4327 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4328 else if ((opcode
& 0x1e700000) == 0x18100000)
4329 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4331 /* ARMv7-M: A5.3.10 Store single data item */
4332 else if ((opcode
& 0x1f100000) == 0x18000000)
4333 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4335 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4336 else if ((opcode
& 0x1e000000) == 0x0a000000)
4337 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4339 /* ARMv7-M: A5.3.12 Data processing (register)
4340 * and A5.3.13 Miscellaneous operations
4342 else if ((opcode
& 0x1f000000) == 0x1a000000)
4343 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4345 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4346 else if ((opcode
& 0x1f800000) == 0x1b000000)
4347 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4349 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4350 else if ((opcode
& 0x1f800000) == 0x1b800000)
4351 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4353 if (retval
== ERROR_OK
)
4357 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4358 * instructions; not yet handled here.
4361 if (retval
== ERROR_INVALID_ARGUMENTS
) {
4362 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4363 strcpy(cp
, "UNDEFINED OPCODE");
4367 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4370 strcpy(cp
, "(32-bit Thumb2 ...)");
4374 int arm_access_size(struct arm_instruction
*instruction
)
4376 if ((instruction
->type
== ARM_LDRB
)
4377 || (instruction
->type
== ARM_LDRBT
)
4378 || (instruction
->type
== ARM_LDRSB
)
4379 || (instruction
->type
== ARM_STRB
)
4380 || (instruction
->type
== ARM_STRBT
))
4384 else if ((instruction
->type
== ARM_LDRH
)
4385 || (instruction
->type
== ARM_LDRSH
)
4386 || (instruction
->type
== ARM_STRH
))
4390 else if ((instruction
->type
== ARM_LDR
)
4391 || (instruction
->type
== ARM_LDRT
)
4392 || (instruction
->type
== ARM_STR
)
4393 || (instruction
->type
== ARM_STRT
))
4397 else if ((instruction
->type
== ARM_LDRD
)
4398 || (instruction
->type
== ARM_STRD
))
4404 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction
->type
);