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