1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * Copyright (C) 2009 by David Brownell *
7 * This program is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; either version 2 of the License, or *
10 * (at your option) any later version. *
12 * This program is distributed in the hope that it will be useful, *
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15 * GNU General Public License for more details. *
17 * You should have received a copy of the GNU General Public License *
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19 ***************************************************************************/
26 #include "arm_disassembler.h"
27 #include <helper/log.h>
30 * This disassembler supports two main functions for OpenOCD:
32 * - Various "disassemble" commands. OpenOCD can serve as a
33 * machine-language debugger, without help from GDB.
35 * - Single stepping. Not all ARM cores support hardware single
36 * stepping. To work without that support, the debugger must
37 * be able to decode instructions to find out where to put a
38 * "next instruction" breakpoint.
40 * In addition, interpretation of ETM trace data needs some of the
41 * decoding mechanisms.
43 * At this writing (September 2009) neither function is complete.
46 * * Old-style syntax (not UAL) is generally used
47 * * VFP instructions are not understood (ARMv5 and later)
48 * except as coprocessor 10/11 operations
49 * * Most ARM instructions through ARMv6 are decoded, but some
50 * of the post-ARMv4 opcodes may not be handled yet
51 * CPS, SDIV, UDIV, LDREX*, STREX*, QASX, ...
52 * * NEON instructions are not understood (ARMv7-A)
54 * - Thumb/Thumb2 decoding
55 * * UAL syntax should be consistently used
56 * * Any Thumb2 instructions used in Cortex-M3 (ARMv7-M) should
57 * be handled properly. Accordingly, so should the subset
58 * used in Cortex-M0/M1; and "original" 16-bit Thumb from
60 * * Conditional effects of Thumb2 "IT" (if-then) instructions
61 * are not handled: the affected instructions are not shown
62 * with their now-conditional suffixes.
63 * * Some ARMv6 and ARMv7-M Thumb2 instructions may not be
64 * handled (minimally for coprocessor access).
65 * * SIMD instructions, and some other Thumb2 instructions
66 * from ARMv7-A, are not understood.
69 * * As a Thumb2 variant, the Thumb2 comments (above) apply.
70 * * Opcodes changed by ThumbEE mode are not handled; these
71 * instructions wrongly decode as LDM and STM.
73 * - Jazelle decoding ... no support whatsoever for Jazelle mode
74 * or decoding. ARM encourages use of the more generic ThumbEE
75 * mode, instead of Jazelle mode, in current chips.
77 * - Single-step/emulation ... spotty support, which is only weakly
78 * tested. Thumb2 is not supported. (Arguably a full simulator
79 * is not needed to support just single stepping. Recognizing
80 * branch vs non-branch instructions suffices, except when the
81 * instruction faults and triggers a synchronous exception which
82 * can be intercepted using other means.)
84 * ARM DDI 0406B "ARM Architecture Reference Manual, ARM v7-A and
85 * ARM v7-R edition" gives the most complete coverage of the various
86 * generations of ARM instructions. At this writing it is publicly
87 * accessible to anyone willing to create an account at the ARM
88 * web site; see http://www.arm.com/documentation/ for information.
90 * ARM DDI 0403C "ARMv7-M Architecture Reference Manual" provides
91 * more details relevant to the Thumb2-only processors (such as
92 * the Cortex-M implementations).
95 /* textual represenation of the condition field
96 * ALways (default) is ommitted (empty string) */
97 static const char *arm_condition_strings
[] = {
98 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
101 /* make up for C's missing ROR */
102 static uint32_t ror(uint32_t value
, int places
)
104 return (value
>> places
) | (value
<< (32 - places
));
107 static int evaluate_unknown(uint32_t opcode
,
108 uint32_t address
, struct arm_instruction
*instruction
)
110 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
111 snprintf(instruction
->text
, 128,
112 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
113 "\tUNDEFINED INSTRUCTION", address
, opcode
);
117 static int evaluate_pld(uint32_t opcode
,
118 uint32_t address
, struct arm_instruction
*instruction
)
121 if ((opcode
& 0x0d70f000) == 0x0550f000) {
122 instruction
->type
= ARM_PLD
;
124 snprintf(instruction
->text
,
126 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tPLD ...TODO...",
133 if ((opcode
& 0x07f000f0) == 0x05700040) {
134 instruction
->type
= ARM_DSB
;
137 switch (opcode
& 0x0000000f) {
166 snprintf(instruction
->text
,
168 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tDSB %s",
169 address
, opcode
, opt
);
174 if ((opcode
& 0x07f000f0) == 0x05700060) {
175 instruction
->type
= ARM_ISB
;
177 snprintf(instruction
->text
,
179 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tISB %s",
181 ((opcode
& 0x0000000f) == 0xf) ? "SY" : "UNK");
185 return evaluate_unknown(opcode
, address
, instruction
);
188 static int evaluate_srs(uint32_t opcode
,
189 uint32_t address
, struct arm_instruction
*instruction
)
191 const char *wback
= (opcode
& (1 << 21)) ? "!" : "";
192 const char *mode
= "";
194 switch ((opcode
>> 23) & 0x3) {
199 /* "IA" is default */
209 switch (opcode
& 0x0e500000) {
211 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
213 "\tSRS%s\tSP%s, #%d",
216 (unsigned)(opcode
& 0x1f));
219 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
224 (unsigned)((opcode
>> 16) & 0xf), wback
);
227 return evaluate_unknown(opcode
, address
, instruction
);
232 static int evaluate_swi(uint32_t opcode
,
233 uint32_t address
, struct arm_instruction
*instruction
)
235 instruction
->type
= ARM_SWI
;
237 snprintf(instruction
->text
, 128,
238 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSVC %#6.6" PRIx32
,
239 address
, opcode
, (opcode
& 0xffffff));
244 static int evaluate_blx_imm(uint32_t opcode
,
245 uint32_t address
, struct arm_instruction
*instruction
)
249 uint32_t target_address
;
251 instruction
->type
= ARM_BLX
;
252 immediate
= opcode
& 0x00ffffff;
254 /* sign extend 24-bit immediate */
255 if (immediate
& 0x00800000)
256 offset
= 0xff000000 | immediate
;
260 /* shift two bits left */
263 /* odd/event halfword */
264 if (opcode
& 0x01000000)
267 target_address
= address
+ 8 + offset
;
269 snprintf(instruction
->text
,
271 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX 0x%8.8" PRIx32
"",
276 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
277 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
282 static int evaluate_b_bl(uint32_t opcode
,
283 uint32_t address
, struct arm_instruction
*instruction
)
288 uint32_t target_address
;
290 immediate
= opcode
& 0x00ffffff;
291 L
= (opcode
& 0x01000000) >> 24;
293 /* sign extend 24-bit immediate */
294 if (immediate
& 0x00800000)
295 offset
= 0xff000000 | immediate
;
299 /* shift two bits left */
302 target_address
= address
+ 8 + offset
;
305 instruction
->type
= ARM_BL
;
307 instruction
->type
= ARM_B
;
309 snprintf(instruction
->text
,
311 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tB%s%s 0x%8.8" PRIx32
,
318 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
319 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
324 /* Coprocessor load/store and double register transfers
325 * both normal and extended instruction space (condition field b1111) */
326 static int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
,
327 uint32_t address
, struct arm_instruction
*instruction
)
329 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
332 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c500000)) {
333 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
336 cp_opcode
= (opcode
& 0xf0) >> 4;
337 Rd
= (opcode
& 0xf000) >> 12;
338 Rn
= (opcode
& 0xf0000) >> 16;
339 CRm
= (opcode
& 0xf);
342 if ((opcode
& 0x0ff00000) == 0x0c400000) {
343 instruction
->type
= ARM_MCRR
;
345 } else if ((opcode
& 0x0ff00000) == 0x0c500000) {
347 instruction
->type
= ARM_MRRC
;
350 LOG_ERROR("Unknown instruction");
354 snprintf(instruction
->text
, 128,
355 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
356 "\t%s%s%s p%i, %x, r%i, r%i, c%i",
357 address
, opcode
, mnemonic
,
358 ((opcode
& 0xf0000000) == 0xf0000000)
359 ? "2" : COND(opcode
),
360 COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
361 } else {/* LDC or STC */
362 uint8_t CRd
, Rn
, offset
;
365 char addressing_mode
[32];
367 CRd
= (opcode
& 0xf000) >> 12;
368 Rn
= (opcode
& 0xf0000) >> 16;
369 offset
= (opcode
& 0xff) << 2;
372 if (opcode
& 0x00100000) {
373 instruction
->type
= ARM_LDC
;
376 instruction
->type
= ARM_STC
;
380 U
= (opcode
& 0x00800000) >> 23;
382 /* addressing modes */
383 if ((opcode
& 0x01200000) == 0x01000000)/* offset */
384 snprintf(addressing_mode
, 32, "[r%i, #%s%d]",
385 Rn
, U
? "" : "-", offset
);
386 else if ((opcode
& 0x01200000) == 0x01200000) /* pre-indexed */
387 snprintf(addressing_mode
, 32, "[r%i, #%s%d]!",
388 Rn
, U
? "" : "-", offset
);
389 else if ((opcode
& 0x01200000) == 0x00200000) /* post-indexed */
390 snprintf(addressing_mode
, 32, "[r%i], #%s%d",
391 Rn
, U
? "" : "-", offset
);
392 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
393 snprintf(addressing_mode
, 32, "[r%i], {%d}",
396 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
398 "\t%s%s%s p%i, c%i, %s",
399 address
, opcode
, mnemonic
,
400 ((opcode
& 0xf0000000) == 0xf0000000)
401 ? "2" : COND(opcode
),
402 (opcode
& (1 << 22)) ? "L" : "",
403 cp_num
, CRd
, addressing_mode
);
409 /* Coprocessor data processing instructions
410 * Coprocessor register transfer instructions
411 * both normal and extended instruction space (condition field b1111) */
412 static int evaluate_cdp_mcr_mrc(uint32_t opcode
,
413 uint32_t address
, struct arm_instruction
*instruction
)
417 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
419 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
420 cp_num
= (opcode
& 0xf00) >> 8;
421 CRd_Rd
= (opcode
& 0xf000) >> 12;
422 CRn
= (opcode
& 0xf0000) >> 16;
423 CRm
= (opcode
& 0xf);
424 opcode_2
= (opcode
& 0xe0) >> 5;
427 if (opcode
& 0x00000010) { /* bit 4 set -> MRC/MCR */
428 if (opcode
& 0x00100000) { /* bit 20 set -> MRC */
429 instruction
->type
= ARM_MRC
;
431 } else {/* bit 20 not set -> MCR */
432 instruction
->type
= ARM_MCR
;
436 opcode_1
= (opcode
& 0x00e00000) >> 21;
438 snprintf(instruction
->text
,
440 "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",
451 } else {/* bit 4 not set -> CDP */
452 instruction
->type
= ARM_CDP
;
455 opcode_1
= (opcode
& 0x00f00000) >> 20;
457 snprintf(instruction
->text
,
459 "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",
475 /* Load/store instructions */
476 static int evaluate_load_store(uint32_t opcode
,
477 uint32_t address
, struct arm_instruction
*instruction
)
479 uint8_t I
, P
, U
, B
, W
, L
;
481 char *operation
;/* "LDR" or "STR" */
482 char *suffix
; /* "", "B", "T", "BT" */
486 I
= (opcode
& 0x02000000) >> 25;
487 P
= (opcode
& 0x01000000) >> 24;
488 U
= (opcode
& 0x00800000) >> 23;
489 B
= (opcode
& 0x00400000) >> 22;
490 W
= (opcode
& 0x00200000) >> 21;
491 L
= (opcode
& 0x00100000) >> 20;
493 /* target register */
494 Rd
= (opcode
& 0xf000) >> 12;
497 Rn
= (opcode
& 0xf0000) >> 16;
499 instruction
->info
.load_store
.Rd
= Rd
;
500 instruction
->info
.load_store
.Rn
= Rn
;
501 instruction
->info
.load_store
.U
= U
;
503 /* determine operation */
509 /* determine instruction type and suffix */
511 if ((P
== 0) && (W
== 1)) {
513 instruction
->type
= ARM_LDRBT
;
515 instruction
->type
= ARM_STRBT
;
519 instruction
->type
= ARM_LDRB
;
521 instruction
->type
= ARM_STRB
;
525 if ((P
== 0) && (W
== 1)) {
527 instruction
->type
= ARM_LDRT
;
529 instruction
->type
= ARM_STRT
;
533 instruction
->type
= ARM_LDR
;
535 instruction
->type
= ARM_STR
;
540 if (!I
) { /* #+-<offset_12> */
541 uint32_t offset_12
= (opcode
& 0xfff);
543 snprintf(offset
, 32, ", #%s0x%" PRIx32
"", (U
) ? "" : "-", offset_12
);
545 snprintf(offset
, 32, "%s", "");
547 instruction
->info
.load_store
.offset_mode
= 0;
548 instruction
->info
.load_store
.offset
.offset
= offset_12
;
549 } else {/* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
550 uint8_t shift_imm
, shift
;
553 shift_imm
= (opcode
& 0xf80) >> 7;
554 shift
= (opcode
& 0x60) >> 5;
557 /* LSR encodes a shift by 32 bit as 0x0 */
558 if ((shift
== 0x1) && (shift_imm
== 0x0))
561 /* ASR encodes a shift by 32 bit as 0x0 */
562 if ((shift
== 0x2) && (shift_imm
== 0x0))
565 /* ROR by 32 bit is actually a RRX */
566 if ((shift
== 0x3) && (shift_imm
== 0x0))
569 instruction
->info
.load_store
.offset_mode
= 1;
570 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
571 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
572 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
574 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
575 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
576 else { /* +-<Rm>, <Shift>, #<shift_imm> */
579 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
582 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
585 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
588 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
591 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
598 if (W
== 0) { /* offset */
599 snprintf(instruction
->text
,
601 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]",
611 instruction
->info
.load_store
.index_mode
= 0;
612 } else {/* pre-indexed */
613 snprintf(instruction
->text
,
615 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i%s]!",
625 instruction
->info
.load_store
.index_mode
= 1;
627 } else {/* post-indexed */
628 snprintf(instruction
->text
,
630 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i]%s",
640 instruction
->info
.load_store
.index_mode
= 2;
646 static int evaluate_extend(uint32_t opcode
, uint32_t address
, char *cp
)
648 unsigned rm
= (opcode
>> 0) & 0xf;
649 unsigned rd
= (opcode
>> 12) & 0xf;
650 unsigned rn
= (opcode
>> 16) & 0xf;
653 switch ((opcode
>> 24) & 0x3) {
658 sprintf(cp
, "UNDEFINED");
659 return ARM_UNDEFINED_INSTRUCTION
;
668 switch ((opcode
>> 10) & 0x3) {
684 sprintf(cp
, "%cXT%s%s\tr%d, r%d%s",
685 (opcode
& (1 << 22)) ? 'U' : 'S',
690 sprintf(cp
, "%cXTA%s%s\tr%d, r%d, r%d%s",
691 (opcode
& (1 << 22)) ? 'U' : 'S',
698 static int evaluate_p_add_sub(uint32_t opcode
, uint32_t address
, char *cp
)
704 switch ((opcode
>> 20) & 0x7) {
727 switch ((opcode
>> 5) & 0x7) {
756 sprintf(cp
, "%s%s%s\tr%d, r%d, r%d", prefix
, op
, COND(opcode
),
757 (int) (opcode
>> 12) & 0xf,
758 (int) (opcode
>> 16) & 0xf,
759 (int) (opcode
>> 0) & 0xf);
763 /* these opcodes might be used someday */
764 sprintf(cp
, "UNDEFINED");
765 return ARM_UNDEFINED_INSTRUCTION
;
768 /* ARMv6 and later support "media" instructions (includes SIMD) */
769 static int evaluate_media(uint32_t opcode
, uint32_t address
,
770 struct arm_instruction
*instruction
)
772 char *cp
= instruction
->text
;
773 char *mnemonic
= NULL
;
776 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t",
780 /* parallel add/subtract */
781 if ((opcode
& 0x01800000) == 0x00000000) {
782 instruction
->type
= evaluate_p_add_sub(opcode
, address
, cp
);
787 if ((opcode
& 0x01f00020) == 0x00800000) {
789 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
791 if (opcode
& (1 << 6)) {
800 sprintf(cp
, "PKH%s%s\tr%d, r%d, r%d, %s #%d",
802 (int) (opcode
>> 12) & 0xf,
803 (int) (opcode
>> 16) & 0xf,
804 (int) (opcode
>> 0) & 0xf,
810 if ((opcode
& 0x01a00020) == 0x00a00000) {
812 unsigned imm
= (unsigned) (opcode
>> 7) & 0x1f;
814 if (opcode
& (1 << 6)) {
821 sprintf(cp
, "%cSAT%s\tr%d, #%d, r%d, %s #%d",
822 (opcode
& (1 << 22)) ? 'U' : 'S',
824 (int) (opcode
>> 12) & 0xf,
825 (int) (opcode
>> 16) & 0x1f,
826 (int) (opcode
>> 0) & 0xf,
832 if ((opcode
& 0x018000f0) == 0x00800070) {
833 instruction
->type
= evaluate_extend(opcode
, address
, cp
);
838 if ((opcode
& 0x01f00080) == 0x01000000) {
839 unsigned rn
= (opcode
>> 12) & 0xf;
842 sprintf(cp
, "SML%cD%s%s\tr%d, r%d, r%d, r%d",
843 (opcode
& (1 << 6)) ? 'S' : 'A',
844 (opcode
& (1 << 5)) ? "X" : "",
846 (int) (opcode
>> 16) & 0xf,
847 (int) (opcode
>> 0) & 0xf,
848 (int) (opcode
>> 8) & 0xf,
851 sprintf(cp
, "SMU%cD%s%s\tr%d, r%d, r%d",
852 (opcode
& (1 << 6)) ? 'S' : 'A',
853 (opcode
& (1 << 5)) ? "X" : "",
855 (int) (opcode
>> 16) & 0xf,
856 (int) (opcode
>> 0) & 0xf,
857 (int) (opcode
>> 8) & 0xf);
860 if ((opcode
& 0x01f00000) == 0x01400000) {
861 sprintf(cp
, "SML%cLD%s%s\tr%d, r%d, r%d, r%d",
862 (opcode
& (1 << 6)) ? 'S' : 'A',
863 (opcode
& (1 << 5)) ? "X" : "",
865 (int) (opcode
>> 12) & 0xf,
866 (int) (opcode
>> 16) & 0xf,
867 (int) (opcode
>> 0) & 0xf,
868 (int) (opcode
>> 8) & 0xf);
871 if ((opcode
& 0x01f00000) == 0x01500000) {
872 unsigned rn
= (opcode
>> 12) & 0xf;
874 switch (opcode
& 0xc0) {
886 sprintf(cp
, "SMML%c%s%s\tr%d, r%d, r%d, r%d",
887 (opcode
& (1 << 6)) ? 'S' : 'A',
888 (opcode
& (1 << 5)) ? "R" : "",
890 (int) (opcode
>> 16) & 0xf,
891 (int) (opcode
>> 0) & 0xf,
892 (int) (opcode
>> 8) & 0xf,
895 sprintf(cp
, "SMMUL%s%s\tr%d, r%d, r%d",
896 (opcode
& (1 << 5)) ? "R" : "",
898 (int) (opcode
>> 16) & 0xf,
899 (int) (opcode
>> 0) & 0xf,
900 (int) (opcode
>> 8) & 0xf);
904 /* simple matches against the remaining decode bits */
905 switch (opcode
& 0x01f000f0) {
908 /* parallel halfword saturate */
909 sprintf(cp
, "%cSAT16%s\tr%d, #%d, r%d",
910 (opcode
& (1 << 22)) ? 'U' : 'S',
912 (int) (opcode
>> 12) & 0xf,
913 (int) (opcode
>> 16) & 0xf,
914 (int) (opcode
>> 0) & 0xf);
927 sprintf(cp
, "SEL%s\tr%d, r%d, r%d", COND(opcode
),
928 (int) (opcode
>> 12) & 0xf,
929 (int) (opcode
>> 16) & 0xf,
930 (int) (opcode
>> 0) & 0xf);
933 /* unsigned sum of absolute differences */
934 if (((opcode
>> 12) & 0xf) == 0xf)
935 sprintf(cp
, "USAD8%s\tr%d, r%d, r%d", COND(opcode
),
936 (int) (opcode
>> 16) & 0xf,
937 (int) (opcode
>> 0) & 0xf,
938 (int) (opcode
>> 8) & 0xf);
940 sprintf(cp
, "USADA8%s\tr%d, r%d, r%d, r%d", COND(opcode
),
941 (int) (opcode
>> 16) & 0xf,
942 (int) (opcode
>> 0) & 0xf,
943 (int) (opcode
>> 8) & 0xf,
944 (int) (opcode
>> 12) & 0xf);
948 unsigned rm
= (opcode
>> 0) & 0xf;
949 unsigned rd
= (opcode
>> 12) & 0xf;
951 sprintf(cp
, "%s%s\tr%d, r%d", mnemonic
, COND(opcode
), rm
, rd
);
956 /* these opcodes might be used someday */
957 sprintf(cp
, "UNDEFINED");
961 /* Miscellaneous load/store instructions */
962 static int evaluate_misc_load_store(uint32_t opcode
,
963 uint32_t address
, struct arm_instruction
*instruction
)
965 uint8_t P
, U
, I
, W
, L
, S
, H
;
967 char *operation
;/* "LDR" or "STR" */
968 char *suffix
; /* "H", "SB", "SH", "D" */
972 P
= (opcode
& 0x01000000) >> 24;
973 U
= (opcode
& 0x00800000) >> 23;
974 I
= (opcode
& 0x00400000) >> 22;
975 W
= (opcode
& 0x00200000) >> 21;
976 L
= (opcode
& 0x00100000) >> 20;
977 S
= (opcode
& 0x00000040) >> 6;
978 H
= (opcode
& 0x00000020) >> 5;
980 /* target register */
981 Rd
= (opcode
& 0xf000) >> 12;
984 Rn
= (opcode
& 0xf0000) >> 16;
986 instruction
->info
.load_store
.Rd
= Rd
;
987 instruction
->info
.load_store
.Rn
= Rn
;
988 instruction
->info
.load_store
.U
= U
;
990 /* determine instruction type and suffix */
995 instruction
->type
= ARM_LDRSH
;
999 instruction
->type
= ARM_LDRSB
;
1002 } else {/* there are no signed stores, so this is used to encode double-register
1007 instruction
->type
= ARM_STRD
;
1010 instruction
->type
= ARM_LDRD
;
1013 } else {/* unsigned */
1017 instruction
->type
= ARM_LDRH
;
1020 instruction
->type
= ARM_STRH
;
1024 if (I
) {/* Immediate offset/index (#+-<offset_8>)*/
1025 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
1026 snprintf(offset
, 32, "#%s0x%" PRIx32
"", (U
) ? "" : "-", offset_8
);
1028 instruction
->info
.load_store
.offset_mode
= 0;
1029 instruction
->info
.load_store
.offset
.offset
= offset_8
;
1030 } else {/* Register offset/index (+-<Rm>) */
1032 Rm
= (opcode
& 0xf);
1033 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
1035 instruction
->info
.load_store
.offset_mode
= 1;
1036 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1037 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
1038 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
1042 if (W
== 0) { /* offset */
1043 snprintf(instruction
->text
,
1045 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]",
1055 instruction
->info
.load_store
.index_mode
= 0;
1056 } else {/* pre-indexed */
1057 snprintf(instruction
->text
,
1059 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i, %s]!",
1069 instruction
->info
.load_store
.index_mode
= 1;
1071 } else {/* post-indexed */
1072 snprintf(instruction
->text
,
1074 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, [r%i], %s",
1084 instruction
->info
.load_store
.index_mode
= 2;
1090 /* Load/store multiples instructions */
1091 static int evaluate_ldm_stm(uint32_t opcode
,
1092 uint32_t address
, struct arm_instruction
*instruction
)
1094 uint8_t P
, U
, S
, W
, L
, Rn
;
1095 uint32_t register_list
;
1096 char *addressing_mode
;
1103 P
= (opcode
& 0x01000000) >> 24;
1104 U
= (opcode
& 0x00800000) >> 23;
1105 S
= (opcode
& 0x00400000) >> 22;
1106 W
= (opcode
& 0x00200000) >> 21;
1107 L
= (opcode
& 0x00100000) >> 20;
1108 register_list
= (opcode
& 0xffff);
1109 Rn
= (opcode
& 0xf0000) >> 16;
1111 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1112 instruction
->info
.load_store_multiple
.register_list
= register_list
;
1113 instruction
->info
.load_store_multiple
.S
= S
;
1114 instruction
->info
.load_store_multiple
.W
= W
;
1117 instruction
->type
= ARM_LDM
;
1120 instruction
->type
= ARM_STM
;
1126 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
1127 addressing_mode
= "IB";
1129 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
1130 addressing_mode
= "DB";
1134 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
1135 /* "IA" is the default in UAL syntax */
1136 addressing_mode
= "";
1138 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
1139 addressing_mode
= "DA";
1143 reg_list_p
= reg_list
;
1144 for (i
= 0; i
<= 15; i
++) {
1145 if ((register_list
>> i
) & 1) {
1148 reg_list_p
+= snprintf(reg_list_p
,
1149 (reg_list
+ 69 - reg_list_p
),
1153 reg_list_p
+= snprintf(reg_list_p
,
1154 (reg_list
+ 69 - reg_list_p
),
1160 snprintf(instruction
->text
, 128,
1161 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
1162 "\t%s%s%s r%i%s, {%s}%s",
1164 mnemonic
, addressing_mode
, COND(opcode
),
1165 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
1170 /* Multiplies, extra load/stores */
1171 static int evaluate_mul_and_extra_ld_st(uint32_t opcode
,
1172 uint32_t address
, struct arm_instruction
*instruction
)
1174 /* Multiply (accumulate) (long) and Swap/swap byte */
1175 if ((opcode
& 0x000000f0) == 0x00000090) {
1176 /* Multiply (accumulate) */
1177 if ((opcode
& 0x0f800000) == 0x00000000) {
1178 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
1180 Rs
= (opcode
& 0xf00) >> 8;
1181 Rn
= (opcode
& 0xf000) >> 12;
1182 Rd
= (opcode
& 0xf0000) >> 16;
1183 S
= (opcode
& 0x00100000) >> 20;
1185 /* examine A bit (accumulate) */
1186 if (opcode
& 0x00200000) {
1187 instruction
->type
= ARM_MLA
;
1188 snprintf(instruction
->text
,
1190 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMLA%s%s r%i, r%i, r%i, r%i",
1200 instruction
->type
= ARM_MUL
;
1201 snprintf(instruction
->text
,
1203 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMUL%s%s r%i, r%i, r%i",
1216 /* Multiply (accumulate) long */
1217 if ((opcode
& 0x0f800000) == 0x00800000) {
1218 char *mnemonic
= NULL
;
1219 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
1221 Rs
= (opcode
& 0xf00) >> 8;
1222 RdHi
= (opcode
& 0xf000) >> 12;
1223 RdLow
= (opcode
& 0xf0000) >> 16;
1224 S
= (opcode
& 0x00100000) >> 20;
1226 switch ((opcode
& 0x00600000) >> 21) {
1228 instruction
->type
= ARM_UMULL
;
1232 instruction
->type
= ARM_UMLAL
;
1236 instruction
->type
= ARM_SMULL
;
1240 instruction
->type
= ARM_SMLAL
;
1245 snprintf(instruction
->text
,
1247 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, r%i, r%i",
1261 /* Swap/swap byte */
1262 if ((opcode
& 0x0f800000) == 0x01000000) {
1265 Rd
= (opcode
& 0xf000) >> 12;
1266 Rn
= (opcode
& 0xf0000) >> 16;
1268 /* examine B flag */
1269 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
1271 snprintf(instruction
->text
,
1273 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, [r%i]",
1276 (opcode
& 0x00400000) ? "SWPB" : "SWP",
1286 return evaluate_misc_load_store(opcode
, address
, instruction
);
1289 static int evaluate_mrs_msr(uint32_t opcode
,
1290 uint32_t address
, struct arm_instruction
*instruction
)
1292 int R
= (opcode
& 0x00400000) >> 22;
1293 char *PSR
= (R
) ? "SPSR" : "CPSR";
1295 /* Move register to status register (MSR) */
1296 if (opcode
& 0x00200000) {
1297 instruction
->type
= ARM_MSR
;
1299 /* immediate variant */
1300 if (opcode
& 0x02000000) {
1301 uint8_t immediate
= (opcode
& 0xff);
1302 uint8_t rotate
= (opcode
& 0xf00);
1304 snprintf(instruction
->text
,
1306 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, 0x%8.8" PRIx32
,
1311 (opcode
& 0x10000) ? "c" : "",
1312 (opcode
& 0x20000) ? "x" : "",
1313 (opcode
& 0x40000) ? "s" : "",
1314 (opcode
& 0x80000) ? "f" : "",
1315 ror(immediate
, (rotate
* 2))
1317 } else {/* register variant */
1318 uint8_t Rm
= opcode
& 0xf;
1319 snprintf(instruction
->text
,
1321 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMSR%s %s_%s%s%s%s, r%i",
1326 (opcode
& 0x10000) ? "c" : "",
1327 (opcode
& 0x20000) ? "x" : "",
1328 (opcode
& 0x40000) ? "s" : "",
1329 (opcode
& 0x80000) ? "f" : "",
1334 } else {/* Move status register to register (MRS) */
1337 instruction
->type
= ARM_MRS
;
1338 Rd
= (opcode
& 0x0000f000) >> 12;
1340 snprintf(instruction
->text
,
1342 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tMRS%s r%i, %s",
1353 /* Miscellaneous instructions */
1354 static int evaluate_misc_instr(uint32_t opcode
,
1355 uint32_t address
, struct arm_instruction
*instruction
)
1358 if ((opcode
& 0x000000f0) == 0x00000000)
1359 evaluate_mrs_msr(opcode
, address
, instruction
);
1362 if ((opcode
& 0x006000f0) == 0x00200010) {
1364 instruction
->type
= ARM_BX
;
1367 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBX%s r%i",
1368 address
, opcode
, COND(opcode
), Rm
);
1370 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1371 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1374 /* BXJ - "Jazelle" support (ARMv5-J) */
1375 if ((opcode
& 0x006000f0) == 0x00200020) {
1377 instruction
->type
= ARM_BX
;
1380 snprintf(instruction
->text
, 128,
1381 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBXJ%s r%i",
1382 address
, opcode
, COND(opcode
), Rm
);
1384 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1385 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1389 if ((opcode
& 0x006000f0) == 0x00600010) {
1391 instruction
->type
= ARM_CLZ
;
1393 Rd
= (opcode
& 0xf000) >> 12;
1395 snprintf(instruction
->text
,
1397 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tCLZ%s r%i, r%i",
1406 if ((opcode
& 0x006000f0) == 0x00200030) {
1408 instruction
->type
= ARM_BLX
;
1411 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tBLX%s r%i",
1412 address
, opcode
, COND(opcode
), Rm
);
1414 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1415 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
1418 /* Enhanced DSP add/subtracts */
1419 if ((opcode
& 0x0000000f0) == 0x00000050) {
1421 char *mnemonic
= NULL
;
1423 Rd
= (opcode
& 0xf000) >> 12;
1424 Rn
= (opcode
& 0xf0000) >> 16;
1426 switch ((opcode
& 0x00600000) >> 21) {
1428 instruction
->type
= ARM_QADD
;
1432 instruction
->type
= ARM_QSUB
;
1436 instruction
->type
= ARM_QDADD
;
1440 instruction
->type
= ARM_QDSUB
;
1445 snprintf(instruction
->text
,
1447 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, r%i, r%i",
1457 /* exception return */
1458 if ((opcode
& 0x0000000f0) == 0x00000060) {
1459 if (((opcode
& 0x600000) >> 21) == 3)
1460 instruction
->type
= ARM_ERET
;
1461 snprintf(instruction
->text
,
1463 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tERET",
1468 /* exception generate instructions */
1469 if ((opcode
& 0x0000000f0) == 0x00000070) {
1470 uint32_t immediate
= 0;
1471 char *mnemonic
= NULL
;
1473 switch ((opcode
& 0x600000) >> 21) {
1475 instruction
->type
= ARM_BKPT
;
1477 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1480 instruction
->type
= ARM_HVC
;
1482 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
1485 instruction
->type
= ARM_SMC
;
1487 immediate
= (opcode
& 0xf);
1491 snprintf(instruction
->text
,
1493 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s 0x%4.4" PRIx32
"",
1500 /* Enhanced DSP multiplies */
1501 if ((opcode
& 0x000000090) == 0x00000080) {
1502 int x
= (opcode
& 0x20) >> 5;
1503 int y
= (opcode
& 0x40) >> 6;
1506 if ((opcode
& 0x00600000) == 0x00000000) {
1507 uint8_t Rd
, Rm
, Rs
, Rn
;
1508 instruction
->type
= ARM_SMLAxy
;
1509 Rd
= (opcode
& 0xf0000) >> 16;
1510 Rm
= (opcode
& 0xf);
1511 Rs
= (opcode
& 0xf00) >> 8;
1512 Rn
= (opcode
& 0xf000) >> 12;
1514 snprintf(instruction
->text
,
1516 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1529 if ((opcode
& 0x00600000) == 0x00400000) {
1530 uint8_t RdLow
, RdHi
, Rm
, Rs
;
1531 instruction
->type
= ARM_SMLAxy
;
1532 RdHi
= (opcode
& 0xf0000) >> 16;
1533 RdLow
= (opcode
& 0xf000) >> 12;
1534 Rm
= (opcode
& 0xf);
1535 Rs
= (opcode
& 0xf00) >> 8;
1537 snprintf(instruction
->text
,
1539 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLA%s%s%s r%i, r%i, r%i, r%i",
1552 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0)) {
1553 uint8_t Rd
, Rm
, Rs
, Rn
;
1554 instruction
->type
= ARM_SMLAWy
;
1555 Rd
= (opcode
& 0xf0000) >> 16;
1556 Rm
= (opcode
& 0xf);
1557 Rs
= (opcode
& 0xf00) >> 8;
1558 Rn
= (opcode
& 0xf000) >> 12;
1560 snprintf(instruction
->text
,
1562 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMLAW%s%s r%i, r%i, r%i, r%i",
1574 if ((opcode
& 0x00600000) == 0x00300000) {
1576 instruction
->type
= ARM_SMULxy
;
1577 Rd
= (opcode
& 0xf0000) >> 16;
1578 Rm
= (opcode
& 0xf);
1579 Rs
= (opcode
& 0xf00) >> 8;
1581 snprintf(instruction
->text
,
1583 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s%s r%i, r%i, r%i",
1595 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1)) {
1597 instruction
->type
= ARM_SMULWy
;
1598 Rd
= (opcode
& 0xf0000) >> 16;
1599 Rm
= (opcode
& 0xf);
1600 Rs
= (opcode
& 0xf00) >> 8;
1602 snprintf(instruction
->text
,
1604 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tSMULW%s%s r%i, r%i, r%i",
1618 static int evaluate_data_proc(uint32_t opcode
,
1619 uint32_t address
, struct arm_instruction
*instruction
)
1621 uint8_t I
, op
, S
, Rn
, Rd
;
1622 char *mnemonic
= NULL
;
1623 char shifter_operand
[32];
1625 I
= (opcode
& 0x02000000) >> 25;
1626 op
= (opcode
& 0x01e00000) >> 21;
1627 S
= (opcode
& 0x00100000) >> 20;
1629 Rd
= (opcode
& 0xf000) >> 12;
1630 Rn
= (opcode
& 0xf0000) >> 16;
1632 instruction
->info
.data_proc
.Rd
= Rd
;
1633 instruction
->info
.data_proc
.Rn
= Rn
;
1634 instruction
->info
.data_proc
.S
= S
;
1638 instruction
->type
= ARM_AND
;
1642 instruction
->type
= ARM_EOR
;
1646 instruction
->type
= ARM_SUB
;
1650 instruction
->type
= ARM_RSB
;
1654 instruction
->type
= ARM_ADD
;
1658 instruction
->type
= ARM_ADC
;
1662 instruction
->type
= ARM_SBC
;
1666 instruction
->type
= ARM_RSC
;
1670 instruction
->type
= ARM_TST
;
1674 instruction
->type
= ARM_TEQ
;
1678 instruction
->type
= ARM_CMP
;
1682 instruction
->type
= ARM_CMN
;
1686 instruction
->type
= ARM_ORR
;
1690 instruction
->type
= ARM_MOV
;
1694 instruction
->type
= ARM_BIC
;
1698 instruction
->type
= ARM_MVN
;
1703 if (I
) {/* immediate shifter operand (#<immediate>)*/
1704 uint8_t immed_8
= opcode
& 0xff;
1705 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1708 immediate
= ror(immed_8
, rotate_imm
* 2);
1710 snprintf(shifter_operand
, 32, "#0x%" PRIx32
"", immediate
);
1712 instruction
->info
.data_proc
.variant
= 0;
1713 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1714 } else {/* register-based shifter operand */
1716 shift
= (opcode
& 0x60) >> 5;
1717 Rm
= (opcode
& 0xf);
1719 if ((opcode
& 0x10) != 0x10) { /* Immediate shifts ("<Rm>" or "<Rm>, <shift>
1720 *#<shift_immediate>") */
1722 shift_imm
= (opcode
& 0xf80) >> 7;
1724 instruction
->info
.data_proc
.variant
= 1;
1725 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1726 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
=
1728 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1730 /* LSR encodes a shift by 32 bit as 0x0 */
1731 if ((shift
== 0x1) && (shift_imm
== 0x0))
1734 /* ASR encodes a shift by 32 bit as 0x0 */
1735 if ((shift
== 0x2) && (shift_imm
== 0x0))
1738 /* ROR by 32 bit is actually a RRX */
1739 if ((shift
== 0x3) && (shift_imm
== 0x0))
1742 if ((shift_imm
== 0x0) && (shift
== 0x0))
1743 snprintf(shifter_operand
, 32, "r%i", Rm
);
1745 if (shift
== 0x0) /* LSL */
1746 snprintf(shifter_operand
,
1751 else if (shift
== 0x1) /* LSR */
1752 snprintf(shifter_operand
,
1757 else if (shift
== 0x2) /* ASR */
1758 snprintf(shifter_operand
,
1763 else if (shift
== 0x3) /* ROR */
1764 snprintf(shifter_operand
,
1769 else if (shift
== 0x4) /* RRX */
1770 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1772 } else {/* Register shifts ("<Rm>, <shift> <Rs>") */
1773 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1775 instruction
->info
.data_proc
.variant
= 2;
1776 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1777 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1778 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1780 if (shift
== 0x0) /* LSL */
1781 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1782 else if (shift
== 0x1) /* LSR */
1783 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1784 else if (shift
== 0x2) /* ASR */
1785 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1786 else if (shift
== 0x3) /* ROR */
1787 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1791 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) { /* <opcode3>{<cond>}{S} <Rd>, <Rn>,
1792 *<shifter_operand> */
1793 snprintf(instruction
->text
,
1795 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, r%i, %s",
1804 } else if ((op
== 0xd) || (op
== 0xf)) { /* <opcode1>{<cond>}{S} <Rd>,
1805 *<shifter_operand> */
1806 if (opcode
== 0xe1a00000) /* print MOV r0,r0 as NOP */
1807 snprintf(instruction
->text
,
1809 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tNOP",
1813 snprintf(instruction
->text
,
1815 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s%s r%i, %s",
1823 } else {/* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1824 snprintf(instruction
->text
, 128, "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\t%s%s r%i, %s",
1825 address
, opcode
, mnemonic
, COND(opcode
),
1826 Rn
, shifter_operand
);
1832 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
,
1833 struct arm_instruction
*instruction
)
1835 /* clear fields, to avoid confusion */
1836 memset(instruction
, 0, sizeof(struct arm_instruction
));
1837 instruction
->opcode
= opcode
;
1838 instruction
->instruction_size
= 4;
1840 /* catch opcodes with condition field [31:28] = b1111 */
1841 if ((opcode
& 0xf0000000) == 0xf0000000) {
1842 /* Undefined instruction (or ARMv5E cache preload PLD) */
1843 if ((opcode
& 0x08000000) == 0x00000000)
1844 return evaluate_pld(opcode
, address
, instruction
);
1846 /* Undefined instruction (or ARMv6+ SRS/RFE) */
1847 if ((opcode
& 0x0e000000) == 0x08000000)
1848 return evaluate_srs(opcode
, address
, instruction
);
1850 /* Branch and branch with link and change to Thumb */
1851 if ((opcode
& 0x0e000000) == 0x0a000000)
1852 return evaluate_blx_imm(opcode
, address
, instruction
);
1854 /* Extended coprocessor opcode space (ARMv5 and higher)
1855 * Coprocessor load/store and double register transfers */
1856 if ((opcode
& 0x0e000000) == 0x0c000000)
1857 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1859 /* Coprocessor data processing */
1860 if ((opcode
& 0x0f000100) == 0x0c000000)
1861 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1863 /* Coprocessor register transfers */
1864 if ((opcode
& 0x0f000010) == 0x0c000010)
1865 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1867 /* Undefined instruction */
1868 if ((opcode
& 0x0f000000) == 0x0f000000) {
1869 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1870 snprintf(instruction
->text
,
1872 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1879 /* catch opcodes with [27:25] = b000 */
1880 if ((opcode
& 0x0e000000) == 0x00000000) {
1881 /* Multiplies, extra load/stores */
1882 if ((opcode
& 0x00000090) == 0x00000090)
1883 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1885 /* Miscellaneous instructions */
1886 if ((opcode
& 0x0f900000) == 0x01000000)
1887 return evaluate_misc_instr(opcode
, address
, instruction
);
1889 return evaluate_data_proc(opcode
, address
, instruction
);
1892 /* catch opcodes with [27:25] = b001 */
1893 if ((opcode
& 0x0e000000) == 0x02000000) {
1894 /* Undefined instruction */
1895 if ((opcode
& 0x0fb00000) == 0x03000000) {
1896 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1897 snprintf(instruction
->text
,
1899 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEFINED INSTRUCTION",
1905 /* Move immediate to status register */
1906 if ((opcode
& 0x0fb00000) == 0x03200000)
1907 return evaluate_mrs_msr(opcode
, address
, instruction
);
1909 return evaluate_data_proc(opcode
, address
, instruction
);
1913 /* catch opcodes with [27:25] = b010 */
1914 if ((opcode
& 0x0e000000) == 0x04000000) {
1915 /* Load/store immediate offset */
1916 return evaluate_load_store(opcode
, address
, instruction
);
1919 /* catch opcodes with [27:25] = b011 */
1920 if ((opcode
& 0x0e000000) == 0x06000000) {
1921 /* Load/store register offset */
1922 if ((opcode
& 0x00000010) == 0x00000000)
1923 return evaluate_load_store(opcode
, address
, instruction
);
1925 /* Architecturally Undefined instruction
1926 * ... don't expect these to ever be used
1928 if ((opcode
& 0x07f000f0) == 0x07f000f0) {
1929 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1930 snprintf(instruction
->text
, 128,
1931 "0x%8.8" PRIx32
"\t0x%8.8" PRIx32
"\tUNDEF",
1936 /* "media" instructions */
1937 return evaluate_media(opcode
, address
, instruction
);
1940 /* catch opcodes with [27:25] = b100 */
1941 if ((opcode
& 0x0e000000) == 0x08000000) {
1942 /* Load/store multiple */
1943 return evaluate_ldm_stm(opcode
, address
, instruction
);
1946 /* catch opcodes with [27:25] = b101 */
1947 if ((opcode
& 0x0e000000) == 0x0a000000) {
1948 /* Branch and branch with link */
1949 return evaluate_b_bl(opcode
, address
, instruction
);
1952 /* catch opcodes with [27:25] = b110 */
1953 if ((opcode
& 0x0e000000) == 0x0c000000) {
1954 /* Coprocessor load/store and double register transfers */
1955 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1958 /* catch opcodes with [27:25] = b111 */
1959 if ((opcode
& 0x0e000000) == 0x0e000000) {
1960 /* Software interrupt */
1961 if ((opcode
& 0x0f000000) == 0x0f000000)
1962 return evaluate_swi(opcode
, address
, instruction
);
1964 /* Coprocessor data processing */
1965 if ((opcode
& 0x0f000010) == 0x0e000000)
1966 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1968 /* Coprocessor register transfers */
1969 if ((opcode
& 0x0f000010) == 0x0e000010)
1970 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1973 LOG_ERROR("ARM: should never reach this point (opcode=%08x)",
1978 static int evaluate_b_bl_blx_thumb(uint16_t opcode
,
1979 uint32_t address
, struct arm_instruction
*instruction
)
1981 uint32_t offset
= opcode
& 0x7ff;
1982 uint32_t opc
= (opcode
>> 11) & 0x3;
1983 uint32_t target_address
;
1984 char *mnemonic
= NULL
;
1986 /* sign extend 11-bit offset */
1987 if (((opc
== 0) || (opc
== 2)) && (offset
& 0x00000400))
1988 offset
= 0xfffff800 | offset
;
1990 target_address
= address
+ 4 + (offset
<< 1);
1993 /* unconditional branch */
1995 instruction
->type
= ARM_B
;
2000 instruction
->type
= ARM_BLX
;
2002 target_address
&= 0xfffffffc;
2006 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
2007 mnemonic
= "prefix";
2008 target_address
= offset
<< 12;
2012 instruction
->type
= ARM_BL
;
2017 /* TODO: deal correctly with dual opcode (prefixed) BL/BLX;
2018 * these are effectively 32-bit instructions even in Thumb1. For
2019 * disassembly, it's simplest to always use the Thumb2 decoder.
2021 * But some cores will evidently handle them as two instructions,
2022 * where exceptions may occur between the two. The ETMv3.2+ ID
2023 * register has a bit which exposes this behavior.
2026 snprintf(instruction
->text
, 128,
2027 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%#8.8" PRIx32
,
2028 address
, opcode
, mnemonic
, target_address
);
2030 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2031 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2036 static int evaluate_add_sub_thumb(uint16_t opcode
,
2037 uint32_t address
, struct arm_instruction
*instruction
)
2039 uint8_t Rd
= (opcode
>> 0) & 0x7;
2040 uint8_t Rn
= (opcode
>> 3) & 0x7;
2041 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
2042 uint32_t opc
= opcode
& (1 << 9);
2043 uint32_t reg_imm
= opcode
& (1 << 10);
2047 instruction
->type
= ARM_SUB
;
2050 /* REVISIT: if reg_imm == 0, display as "MOVS" */
2051 instruction
->type
= ARM_ADD
;
2055 instruction
->info
.data_proc
.Rd
= Rd
;
2056 instruction
->info
.data_proc
.Rn
= Rn
;
2057 instruction
->info
.data_proc
.S
= 1;
2060 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2061 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
2062 snprintf(instruction
->text
, 128,
2063 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%d",
2064 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2066 instruction
->info
.data_proc
.variant
= 1;/*immediate shift*/
2067 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
2068 snprintf(instruction
->text
, 128,
2069 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, r%i",
2070 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
2076 static int evaluate_shift_imm_thumb(uint16_t opcode
,
2077 uint32_t address
, struct arm_instruction
*instruction
)
2079 uint8_t Rd
= (opcode
>> 0) & 0x7;
2080 uint8_t Rm
= (opcode
>> 3) & 0x7;
2081 uint8_t imm
= (opcode
>> 6) & 0x1f;
2082 uint8_t opc
= (opcode
>> 11) & 0x3;
2083 char *mnemonic
= NULL
;
2087 instruction
->type
= ARM_MOV
;
2089 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
2092 instruction
->type
= ARM_MOV
;
2094 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
2097 instruction
->type
= ARM_MOV
;
2099 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
2103 if ((imm
== 0) && (opc
!= 0))
2106 instruction
->info
.data_proc
.Rd
= Rd
;
2107 instruction
->info
.data_proc
.Rn
= -1;
2108 instruction
->info
.data_proc
.S
= 1;
2110 instruction
->info
.data_proc
.variant
= 1;/*immediate_shift*/
2111 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2112 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
2114 snprintf(instruction
->text
, 128,
2115 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i, #%#2.2x",
2116 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
2121 static int evaluate_data_proc_imm_thumb(uint16_t opcode
,
2122 uint32_t address
, struct arm_instruction
*instruction
)
2124 uint8_t imm
= opcode
& 0xff;
2125 uint8_t Rd
= (opcode
>> 8) & 0x7;
2126 uint32_t opc
= (opcode
>> 11) & 0x3;
2127 char *mnemonic
= NULL
;
2129 instruction
->info
.data_proc
.Rd
= Rd
;
2130 instruction
->info
.data_proc
.Rn
= Rd
;
2131 instruction
->info
.data_proc
.S
= 1;
2132 instruction
->info
.data_proc
.variant
= 0;/*immediate*/
2133 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
2137 instruction
->type
= ARM_MOV
;
2139 instruction
->info
.data_proc
.Rn
= -1;
2142 instruction
->type
= ARM_CMP
;
2144 instruction
->info
.data_proc
.Rd
= -1;
2147 instruction
->type
= ARM_ADD
;
2151 instruction
->type
= ARM_SUB
;
2156 snprintf(instruction
->text
, 128,
2157 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, #%#2.2x",
2158 address
, opcode
, mnemonic
, Rd
, imm
);
2163 static int evaluate_data_proc_thumb(uint16_t opcode
,
2164 uint32_t address
, struct arm_instruction
*instruction
)
2166 uint8_t high_reg
, op
, Rm
, Rd
, H1
, H2
;
2167 char *mnemonic
= NULL
;
2170 high_reg
= (opcode
& 0x0400) >> 10;
2171 op
= (opcode
& 0x03C0) >> 6;
2173 Rd
= (opcode
& 0x0007);
2174 Rm
= (opcode
& 0x0038) >> 3;
2175 H1
= (opcode
& 0x0080) >> 7;
2176 H2
= (opcode
& 0x0040) >> 6;
2178 instruction
->info
.data_proc
.Rd
= Rd
;
2179 instruction
->info
.data_proc
.Rn
= Rd
;
2180 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
2181 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
2182 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
2191 instruction
->type
= ARM_ADD
;
2195 instruction
->type
= ARM_CMP
;
2199 instruction
->type
= ARM_MOV
;
2205 if ((opcode
& 0x7) == 0x0) {
2206 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
2208 instruction
->type
= ARM_BLX
;
2209 snprintf(instruction
->text
, 128,
2211 " 0x%4.4x \tBLX\tr%i",
2212 address
, opcode
, Rm
);
2214 instruction
->type
= ARM_BX
;
2215 snprintf(instruction
->text
, 128,
2217 " 0x%4.4x \tBX\tr%i",
2218 address
, opcode
, Rm
);
2221 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2222 snprintf(instruction
->text
, 128,
2225 "UNDEFINED INSTRUCTION",
2234 instruction
->type
= ARM_AND
;
2238 instruction
->type
= ARM_EOR
;
2242 instruction
->type
= ARM_MOV
;
2244 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2245 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
2246 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2247 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2250 instruction
->type
= ARM_MOV
;
2252 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2253 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
2254 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2255 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2258 instruction
->type
= ARM_MOV
;
2260 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2261 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
2262 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2263 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2266 instruction
->type
= ARM_ADC
;
2270 instruction
->type
= ARM_SBC
;
2274 instruction
->type
= ARM_MOV
;
2276 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
2277 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
2278 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
2279 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
2282 instruction
->type
= ARM_TST
;
2286 instruction
->type
= ARM_RSB
;
2288 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
2289 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
2290 instruction
->info
.data_proc
.Rn
= Rm
;
2293 instruction
->type
= ARM_CMP
;
2297 instruction
->type
= ARM_CMN
;
2301 instruction
->type
= ARM_ORR
;
2305 instruction
->type
= ARM_MUL
;
2309 instruction
->type
= ARM_BIC
;
2313 instruction
->type
= ARM_MVN
;
2320 snprintf(instruction
->text
, 128,
2321 "0x%8.8" PRIx32
" 0x%4.4x \tNOP\t\t\t"
2323 address
, opcode
, mnemonic
, Rd
, Rm
);
2325 snprintf(instruction
->text
, 128,
2326 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, r%i",
2327 address
, opcode
, mnemonic
, Rd
, Rm
);
2332 /* PC-relative data addressing is word-aligned even with Thumb */
2333 static inline uint32_t thumb_alignpc4(uint32_t addr
)
2335 return (addr
+ 4) & ~3;
2338 static int evaluate_load_literal_thumb(uint16_t opcode
,
2339 uint32_t address
, struct arm_instruction
*instruction
)
2342 uint8_t Rd
= (opcode
>> 8) & 0x7;
2344 instruction
->type
= ARM_LDR
;
2345 immediate
= opcode
& 0x000000ff;
2348 instruction
->info
.load_store
.Rd
= Rd
;
2349 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
2350 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2351 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2352 instruction
->info
.load_store
.offset
.offset
= immediate
;
2354 snprintf(instruction
->text
, 128,
2355 "0x%8.8" PRIx32
" 0x%4.4x \t"
2356 "LDR\tr%i, [pc, #%#" PRIx32
"]\t; %#8.8" PRIx32
,
2357 address
, opcode
, Rd
, immediate
,
2358 thumb_alignpc4(address
) + immediate
);
2363 static int evaluate_load_store_reg_thumb(uint16_t opcode
,
2364 uint32_t address
, struct arm_instruction
*instruction
)
2366 uint8_t Rd
= (opcode
>> 0) & 0x7;
2367 uint8_t Rn
= (opcode
>> 3) & 0x7;
2368 uint8_t Rm
= (opcode
>> 6) & 0x7;
2369 uint8_t opc
= (opcode
>> 9) & 0x7;
2370 char *mnemonic
= NULL
;
2374 instruction
->type
= ARM_STR
;
2378 instruction
->type
= ARM_STRH
;
2382 instruction
->type
= ARM_STRB
;
2386 instruction
->type
= ARM_LDRSB
;
2390 instruction
->type
= ARM_LDR
;
2394 instruction
->type
= ARM_LDRH
;
2398 instruction
->type
= ARM_LDRB
;
2402 instruction
->type
= ARM_LDRSH
;
2407 snprintf(instruction
->text
, 128,
2408 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [r%i, r%i]",
2409 address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
2411 instruction
->info
.load_store
.Rd
= Rd
;
2412 instruction
->info
.load_store
.Rn
= Rn
;
2413 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2414 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
2415 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
2420 static int evaluate_load_store_imm_thumb(uint16_t opcode
,
2421 uint32_t address
, struct arm_instruction
*instruction
)
2423 uint32_t offset
= (opcode
>> 6) & 0x1f;
2424 uint8_t Rd
= (opcode
>> 0) & 0x7;
2425 uint8_t Rn
= (opcode
>> 3) & 0x7;
2426 uint32_t L
= opcode
& (1 << 11);
2427 uint32_t B
= opcode
& (1 << 12);
2433 instruction
->type
= ARM_LDR
;
2436 instruction
->type
= ARM_STR
;
2440 if ((opcode
&0xF000) == 0x8000) {
2448 snprintf(instruction
->text
, 128,
2449 "0x%8.8" PRIx32
" 0x%4.4x \t%s%c\tr%i, [r%i, #%#" PRIx32
"]",
2450 address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<< shift
);
2452 instruction
->info
.load_store
.Rd
= Rd
;
2453 instruction
->info
.load_store
.Rn
= Rn
;
2454 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2455 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2456 instruction
->info
.load_store
.offset
.offset
= offset
<< shift
;
2461 static int evaluate_load_store_stack_thumb(uint16_t opcode
,
2462 uint32_t address
, struct arm_instruction
*instruction
)
2464 uint32_t offset
= opcode
& 0xff;
2465 uint8_t Rd
= (opcode
>> 8) & 0x7;
2466 uint32_t L
= opcode
& (1 << 11);
2470 instruction
->type
= ARM_LDR
;
2473 instruction
->type
= ARM_STR
;
2477 snprintf(instruction
->text
, 128,
2478 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tr%i, [SP, #%#" PRIx32
"]",
2479 address
, opcode
, mnemonic
, Rd
, offset
*4);
2481 instruction
->info
.load_store
.Rd
= Rd
;
2482 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
2483 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
2484 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
2485 instruction
->info
.load_store
.offset
.offset
= offset
*4;
2490 static int evaluate_add_sp_pc_thumb(uint16_t opcode
,
2491 uint32_t address
, struct arm_instruction
*instruction
)
2493 uint32_t imm
= opcode
& 0xff;
2494 uint8_t Rd
= (opcode
>> 8) & 0x7;
2496 uint32_t SP
= opcode
& (1 << 11);
2497 const char *reg_name
;
2499 instruction
->type
= ARM_ADD
;
2509 snprintf(instruction
->text
, 128,
2510 "0x%8.8" PRIx32
" 0x%4.4x \tADD\tr%i, %s, #%#" PRIx32
,
2511 address
, opcode
, Rd
, reg_name
, imm
* 4);
2513 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2514 instruction
->info
.data_proc
.Rd
= Rd
;
2515 instruction
->info
.data_proc
.Rn
= Rn
;
2516 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2521 static int evaluate_adjust_stack_thumb(uint16_t opcode
,
2522 uint32_t address
, struct arm_instruction
*instruction
)
2524 uint32_t imm
= opcode
& 0x7f;
2525 uint8_t opc
= opcode
& (1 << 7);
2530 instruction
->type
= ARM_SUB
;
2533 instruction
->type
= ARM_ADD
;
2537 snprintf(instruction
->text
, 128,
2538 "0x%8.8" PRIx32
" 0x%4.4x \t%s\tSP, #%#" PRIx32
,
2539 address
, opcode
, mnemonic
, imm
*4);
2541 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
2542 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
2543 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
2544 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
2549 static int evaluate_breakpoint_thumb(uint16_t opcode
,
2550 uint32_t address
, struct arm_instruction
*instruction
)
2552 uint32_t imm
= opcode
& 0xff;
2554 instruction
->type
= ARM_BKPT
;
2556 snprintf(instruction
->text
, 128,
2557 "0x%8.8" PRIx32
" 0x%4.4x \tBKPT\t%#2.2" PRIx32
"",
2558 address
, opcode
, imm
);
2563 static int evaluate_load_store_multiple_thumb(uint16_t opcode
,
2564 uint32_t address
, struct arm_instruction
*instruction
)
2566 uint32_t reg_list
= opcode
& 0xff;
2567 uint32_t L
= opcode
& (1 << 11);
2568 uint32_t R
= opcode
& (1 << 8);
2569 uint8_t Rn
= (opcode
>> 8) & 7;
2570 uint8_t addr_mode
= 0 /* IA */;
2574 char ptr_name
[7] = "";
2577 /* REVISIT: in ThumbEE mode, there are no LDM or STM instructions.
2578 * The STMIA and LDMIA opcodes are used for other instructions.
2581 if ((opcode
& 0xf000) == 0xc000) { /* generic load/store multiple */
2585 instruction
->type
= ARM_LDM
;
2587 if (opcode
& (1 << Rn
))
2590 instruction
->type
= ARM_STM
;
2593 snprintf(ptr_name
, sizeof ptr_name
, "r%i%s, ", Rn
, wback
);
2594 } else {/* push/pop */
2597 instruction
->type
= ARM_LDM
;
2600 reg_list
|= (1 << 15) /*PC*/;
2602 instruction
->type
= ARM_STM
;
2604 addr_mode
= 3; /*DB*/
2606 reg_list
|= (1 << 14) /*LR*/;
2610 reg_names_p
= reg_names
;
2611 for (i
= 0; i
<= 15; i
++) {
2612 if (reg_list
& (1 << i
))
2613 reg_names_p
+= snprintf(reg_names_p
,
2614 (reg_names
+ 40 - reg_names_p
),
2618 if (reg_names_p
> reg_names
)
2619 reg_names_p
[-2] = '\0';
2620 else /* invalid op : no registers */
2621 reg_names
[0] = '\0';
2623 snprintf(instruction
->text
, 128,
2624 "0x%8.8" PRIx32
" 0x%4.4x \t%s\t%s{%s}",
2625 address
, opcode
, mnemonic
, ptr_name
, reg_names
);
2627 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
2628 instruction
->info
.load_store_multiple
.Rn
= Rn
;
2629 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
2634 static int evaluate_cond_branch_thumb(uint16_t opcode
,
2635 uint32_t address
, struct arm_instruction
*instruction
)
2637 uint32_t offset
= opcode
& 0xff;
2638 uint8_t cond
= (opcode
>> 8) & 0xf;
2639 uint32_t target_address
;
2642 instruction
->type
= ARM_SWI
;
2643 snprintf(instruction
->text
, 128,
2644 "0x%8.8" PRIx32
" 0x%4.4x \tSVC\t%#2.2" PRIx32
,
2645 address
, opcode
, offset
);
2647 } else if (cond
== 0xe) {
2648 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2649 snprintf(instruction
->text
, 128,
2650 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2655 /* sign extend 8-bit offset */
2656 if (offset
& 0x00000080)
2657 offset
= 0xffffff00 | offset
;
2659 target_address
= address
+ 4 + (offset
<< 1);
2661 snprintf(instruction
->text
, 128,
2662 "0x%8.8" PRIx32
" 0x%4.4x \tB%s\t%#8.8" PRIx32
,
2664 arm_condition_strings
[cond
], target_address
);
2666 instruction
->type
= ARM_B
;
2667 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2668 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
2673 static int evaluate_cb_thumb(uint16_t opcode
, uint32_t address
,
2674 struct arm_instruction
*instruction
)
2678 /* added in Thumb2 */
2679 offset
= (opcode
>> 3) & 0x1f;
2680 offset
|= (opcode
& 0x0200) >> 4;
2682 snprintf(instruction
->text
, 128,
2683 "0x%8.8" PRIx32
" 0x%4.4x \tCB%sZ\tr%d, %#8.8" PRIx32
,
2685 (opcode
& 0x0800) ? "N" : "",
2686 opcode
& 0x7, address
+ 4 + (offset
<< 1));
2691 static int evaluate_extend_thumb(uint16_t opcode
, uint32_t address
,
2692 struct arm_instruction
*instruction
)
2694 /* added in ARMv6 */
2695 snprintf(instruction
->text
, 128,
2696 "0x%8.8" PRIx32
" 0x%4.4x \t%cXT%c\tr%d, r%d",
2698 (opcode
& 0x0080) ? 'U' : 'S',
2699 (opcode
& 0x0040) ? 'B' : 'H',
2700 opcode
& 0x7, (opcode
>> 3) & 0x7);
2705 static int evaluate_cps_thumb(uint16_t opcode
, uint32_t address
,
2706 struct arm_instruction
*instruction
)
2708 /* added in ARMv6 */
2709 if ((opcode
& 0x0ff0) == 0x0650)
2710 snprintf(instruction
->text
, 128,
2711 "0x%8.8" PRIx32
" 0x%4.4x \tSETEND %s",
2713 (opcode
& 0x80) ? "BE" : "LE");
2714 else /* ASSUME (opcode & 0x0fe0) == 0x0660 */
2715 snprintf(instruction
->text
, 128,
2716 "0x%8.8" PRIx32
" 0x%4.4x \tCPSI%c\t%s%s%s",
2718 (opcode
& 0x0010) ? 'D' : 'E',
2719 (opcode
& 0x0004) ? "A" : "",
2720 (opcode
& 0x0002) ? "I" : "",
2721 (opcode
& 0x0001) ? "F" : "");
2726 static int evaluate_byterev_thumb(uint16_t opcode
, uint32_t address
,
2727 struct arm_instruction
*instruction
)
2731 /* added in ARMv6 */
2732 switch ((opcode
>> 6) & 3) {
2743 snprintf(instruction
->text
, 128,
2744 "0x%8.8" PRIx32
" 0x%4.4x \tREV%s\tr%d, r%d",
2745 address
, opcode
, suffix
,
2746 opcode
& 0x7, (opcode
>> 3) & 0x7);
2751 static int evaluate_hint_thumb(uint16_t opcode
, uint32_t address
,
2752 struct arm_instruction
*instruction
)
2756 switch ((opcode
>> 4) & 0x0f) {
2773 hint
= "HINT (UNRECOGNIZED)";
2777 snprintf(instruction
->text
, 128,
2778 "0x%8.8" PRIx32
" 0x%4.4x \t%s",
2779 address
, opcode
, hint
);
2784 static int evaluate_ifthen_thumb(uint16_t opcode
, uint32_t address
,
2785 struct arm_instruction
*instruction
)
2787 unsigned cond
= (opcode
>> 4) & 0x0f;
2788 char *x
= "", *y
= "", *z
= "";
2791 z
= (opcode
& 0x02) ? "T" : "E";
2793 y
= (opcode
& 0x04) ? "T" : "E";
2795 x
= (opcode
& 0x08) ? "T" : "E";
2797 snprintf(instruction
->text
, 128,
2798 "0x%8.8" PRIx32
" 0x%4.4x \tIT%s%s%s\t%s",
2800 x
, y
, z
, arm_condition_strings
[cond
]);
2802 /* NOTE: strictly speaking, the next 1-4 instructions should
2803 * now be displayed with the relevant conditional suffix...
2809 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, struct arm_instruction
*instruction
)
2811 /* clear fields, to avoid confusion */
2812 memset(instruction
, 0, sizeof(struct arm_instruction
));
2813 instruction
->opcode
= opcode
;
2814 instruction
->instruction_size
= 2;
2816 if ((opcode
& 0xe000) == 0x0000) {
2817 /* add/substract register or immediate */
2818 if ((opcode
& 0x1800) == 0x1800)
2819 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
2820 /* shift by immediate */
2822 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
2825 /* Add/substract/compare/move immediate */
2826 if ((opcode
& 0xe000) == 0x2000)
2827 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
2829 /* Data processing instructions */
2830 if ((opcode
& 0xf800) == 0x4000)
2831 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2833 /* Load from literal pool */
2834 if ((opcode
& 0xf800) == 0x4800)
2835 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2837 /* Load/Store register offset */
2838 if ((opcode
& 0xf000) == 0x5000)
2839 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2841 /* Load/Store immediate offset */
2842 if (((opcode
& 0xe000) == 0x6000)
2843 || ((opcode
& 0xf000) == 0x8000))
2844 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2846 /* Load/Store from/to stack */
2847 if ((opcode
& 0xf000) == 0x9000)
2848 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2851 if ((opcode
& 0xf000) == 0xa000)
2852 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2855 if ((opcode
& 0xf000) == 0xb000) {
2856 switch ((opcode
>> 8) & 0x0f) {
2858 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2863 return evaluate_cb_thumb(opcode
, address
, instruction
);
2865 return evaluate_extend_thumb(opcode
, address
, instruction
);
2870 return evaluate_load_store_multiple_thumb(opcode
, address
,
2873 return evaluate_cps_thumb(opcode
, address
, instruction
);
2875 if ((opcode
& 0x00c0) == 0x0080)
2877 return evaluate_byterev_thumb(opcode
, address
, instruction
);
2879 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2881 if (opcode
& 0x000f)
2882 return evaluate_ifthen_thumb(opcode
, address
,
2885 return evaluate_hint_thumb(opcode
, address
,
2889 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2890 snprintf(instruction
->text
, 128,
2891 "0x%8.8" PRIx32
" 0x%4.4x \tUNDEFINED INSTRUCTION",
2896 /* Load/Store multiple */
2897 if ((opcode
& 0xf000) == 0xc000)
2898 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2900 /* Conditional branch + SWI */
2901 if ((opcode
& 0xf000) == 0xd000)
2902 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2904 if ((opcode
& 0xe000) == 0xe000) {
2905 /* Undefined instructions */
2906 if ((opcode
& 0xf801) == 0xe801) {
2907 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2908 snprintf(instruction
->text
, 128,
2909 "0x%8.8" PRIx32
" 0x%8.8x\t"
2910 "UNDEFINED INSTRUCTION",
2913 } else /* Branch to offset */
2914 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2917 LOG_ERROR("Thumb: should never reach this point (opcode=%04x)", opcode
);
2921 static int t2ev_b_bl(uint32_t opcode
, uint32_t address
,
2922 struct arm_instruction
*instruction
, char *cp
)
2925 unsigned b21
= 1 << 21;
2926 unsigned b22
= 1 << 22;
2928 /* instead of combining two smaller 16-bit branch instructions,
2929 * Thumb2 uses only one larger 32-bit instruction.
2931 offset
= opcode
& 0x7ff;
2932 offset
|= (opcode
& 0x03ff0000) >> 5;
2933 if (opcode
& (1 << 26)) {
2934 offset
|= 0xff << 23;
2935 if ((opcode
& (1 << 11)) == 0)
2937 if ((opcode
& (1 << 13)) == 0)
2940 if (opcode
& (1 << 11))
2942 if (opcode
& (1 << 13))
2950 address
+= offset
<< 1;
2953 switch ((opcode
>> 12) & 0x5) {
2956 instruction
->type
= ARM_B
;
2960 instruction
->type
= ARM_BLX
;
2964 instruction
->type
= ARM_BL
;
2967 return ERROR_COMMAND_SYNTAX_ERROR
;
2969 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
2970 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
2971 sprintf(cp
, "%s\t%#8.8" PRIx32
, inst
, address
);
2976 static int t2ev_cond_b(uint32_t opcode
, uint32_t address
,
2977 struct arm_instruction
*instruction
, char *cp
)
2980 unsigned b17
= 1 << 17;
2981 unsigned b18
= 1 << 18;
2982 unsigned cond
= (opcode
>> 22) & 0x0f;
2984 offset
= opcode
& 0x7ff;
2985 offset
|= (opcode
& 0x003f0000) >> 5;
2986 if (opcode
& (1 << 26)) {
2987 offset
|= 0x1fff << 19;
2988 if ((opcode
& (1 << 11)) == 0)
2990 if ((opcode
& (1 << 13)) == 0)
2993 if (opcode
& (1 << 11))
2995 if (opcode
& (1 << 13))
3002 address
+= offset
<< 1;
3004 instruction
->type
= ARM_B
;
3005 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
3006 instruction
->info
.b_bl_bx_blx
.target_address
= address
;
3007 sprintf(cp
, "B%s.W\t%#8.8" PRIx32
,
3008 arm_condition_strings
[cond
],
3014 static const char *special_name(int number
)
3016 char *special
= "(RESERVED)";
3047 special
= "primask";
3050 special
= "basepri";
3053 special
= "basepri_max";
3056 special
= "faultmask";
3059 special
= "control";
3065 static int t2ev_hint(uint32_t opcode
, uint32_t address
,
3066 struct arm_instruction
*instruction
, char *cp
)
3068 const char *mnemonic
;
3070 if (opcode
& 0x0700) {
3071 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3072 strcpy(cp
, "UNDEFINED");
3076 if (opcode
& 0x00f0) {
3077 sprintf(cp
, "DBG\t#%d", (int) opcode
& 0xf);
3081 switch (opcode
& 0x0f) {
3086 mnemonic
= "YIELD.W";
3098 mnemonic
= "HINT.W (UNRECOGNIZED)";
3101 strcpy(cp
, mnemonic
);
3105 static int t2ev_misc(uint32_t opcode
, uint32_t address
,
3106 struct arm_instruction
*instruction
, char *cp
)
3108 const char *mnemonic
;
3110 switch ((opcode
>> 4) & 0x0f) {
3112 mnemonic
= "LEAVEX";
3115 mnemonic
= "ENTERX";
3130 return ERROR_COMMAND_SYNTAX_ERROR
;
3132 strcpy(cp
, mnemonic
);
3136 static int t2ev_b_misc(uint32_t opcode
, uint32_t address
,
3137 struct arm_instruction
*instruction
, char *cp
)
3139 /* permanently undefined */
3140 if ((opcode
& 0x07f07000) == 0x07f02000) {
3141 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
3142 strcpy(cp
, "UNDEFINED");
3146 switch ((opcode
>> 12) & 0x5) {
3150 return t2ev_b_bl(opcode
, address
, instruction
, cp
);
3152 if (((opcode
>> 23) & 0x07) != 0x07)
3153 return t2ev_cond_b(opcode
, address
, instruction
, cp
);
3154 if (opcode
& (1 << 26))
3159 switch ((opcode
>> 20) & 0x7f) {
3162 sprintf(cp
, "MSR\t%s, r%d", special_name(opcode
& 0xff),
3163 (int) (opcode
>> 16) & 0x0f);
3166 return t2ev_hint(opcode
, address
, instruction
, cp
);
3168 return t2ev_misc(opcode
, address
, instruction
, cp
);
3170 sprintf(cp
, "BXJ\tr%d", (int) (opcode
>> 16) & 0x0f);
3174 sprintf(cp
, "MRS\tr%d, %s", (int) (opcode
>> 8) & 0x0f,
3175 special_name(opcode
& 0xff));
3180 return ERROR_COMMAND_SYNTAX_ERROR
;
3183 static int t2ev_data_mod_immed(uint32_t opcode
, uint32_t address
,
3184 struct arm_instruction
*instruction
, char *cp
)
3186 char *mnemonic
= NULL
;
3187 int rn
= (opcode
>> 16) & 0xf;
3188 int rd
= (opcode
>> 8) & 0xf;
3189 unsigned immed
= opcode
& 0xff;
3195 /* ARMv7-M: A5.3.2 Modified immediate constants */
3196 func
= (opcode
>> 11) & 0x0e;
3199 if (opcode
& (1 << 26))
3202 /* "Modified" immediates */
3203 switch (func
>> 1) {
3210 immed
+= immed
<< 16;
3213 immed
+= immed
<< 8;
3214 immed
+= immed
<< 16;
3218 immed
= ror(immed
, func
);
3221 if (opcode
& (1 << 20))
3224 switch ((opcode
>> 21) & 0xf) {
3227 instruction
->type
= ARM_TST
;
3233 instruction
->type
= ARM_AND
;
3238 instruction
->type
= ARM_BIC
;
3243 instruction
->type
= ARM_MOV
;
3248 instruction
->type
= ARM_ORR
;
3254 instruction
->type
= ARM_MVN
;
3258 /* instruction->type = ARM_ORN; */
3264 instruction
->type
= ARM_TEQ
;
3270 instruction
->type
= ARM_EOR
;
3276 instruction
->type
= ARM_CMN
;
3282 instruction
->type
= ARM_ADD
;
3288 instruction
->type
= ARM_ADC
;
3293 instruction
->type
= ARM_SBC
;
3298 instruction
->type
= ARM_CMP
;
3304 instruction
->type
= ARM_SUB
;
3310 instruction
->type
= ARM_RSB
;
3315 return ERROR_COMMAND_SYNTAX_ERROR
;
3319 sprintf(cp
, "%s%s\tr%d, #%d\t; %#8.8x",
3320 mnemonic
, suffix2
, rd
, immed
, immed
);
3322 sprintf(cp
, "%s%s%s\tr%d, r%d, #%d\t; %#8.8x",
3323 mnemonic
, suffix
, suffix2
,
3324 rd
, rn
, immed
, immed
);
3329 static int t2ev_data_immed(uint32_t opcode
, uint32_t address
,
3330 struct arm_instruction
*instruction
, char *cp
)
3332 char *mnemonic
= NULL
;
3333 int rn
= (opcode
>> 16) & 0xf;
3334 int rd
= (opcode
>> 8) & 0xf;
3337 bool is_signed
= false;
3339 immed
= (opcode
& 0x0ff) | ((opcode
& 0x7000) >> 4);
3340 if (opcode
& (1 << 26))
3343 switch ((opcode
>> 20) & 0x1f) {
3352 immed
|= (opcode
>> 4) & 0xf000;
3353 sprintf(cp
, "MOVW\tr%d, #%d\t; %#3.3x", rd
, immed
, immed
);
3361 /* move constant to top 16 bits of register */
3362 immed
|= (opcode
>> 4) & 0xf000;
3363 sprintf(cp
, "MOVT\tr%d, #%d\t; %#4.4x", rd
, immed
, immed
);
3371 /* signed/unsigned saturated add */
3372 immed
= (opcode
>> 6) & 0x03;
3373 immed
|= (opcode
>> 10) & 0x1c;
3374 sprintf(cp
, "%sSAT\tr%d, #%d, r%d, %s #%d\t",
3375 is_signed
? "S" : "U",
3376 rd
, (int) (opcode
& 0x1f) + is_signed
, rn
,
3377 (opcode
& (1 << 21)) ? "ASR" : "LSL",
3378 immed
? immed
: 32);
3384 /* signed/unsigned bitfield extract */
3385 immed
= (opcode
>> 6) & 0x03;
3386 immed
|= (opcode
>> 10) & 0x1c;
3387 sprintf(cp
, "%sBFX\tr%d, r%d, #%d, #%d\t",
3388 is_signed
? "S" : "U",
3390 (int) (opcode
& 0x1f) + 1);
3393 immed
= (opcode
>> 6) & 0x03;
3394 immed
|= (opcode
>> 10) & 0x1c;
3395 if (rn
== 0xf) /* bitfield clear */
3396 sprintf(cp
, "BFC\tr%d, #%d, #%d\t",
3398 (int) (opcode
& 0x1f) + 1 - immed
);
3399 else /* bitfield insert */
3400 sprintf(cp
, "BFI\tr%d, r%d, #%d, #%d\t",
3402 (int) (opcode
& 0x1f) + 1 - immed
);
3405 return ERROR_COMMAND_SYNTAX_ERROR
;
3408 sprintf(cp
, "%s\tr%d, r%d, #%d\t; %#3.3x", mnemonic
,
3409 rd
, rn
, immed
, immed
);
3413 address
= thumb_alignpc4(address
);
3418 /* REVISIT "ADD/SUB Rd, PC, #const ; 0x..." might be better;
3419 * not hiding the pc-relative stuff will sometimes be useful.
3421 sprintf(cp
, "ADR.W\tr%d, %#8.8" PRIx32
, rd
, address
);
3425 static int t2ev_store_single(uint32_t opcode
, uint32_t address
,
3426 struct arm_instruction
*instruction
, char *cp
)
3428 unsigned op
= (opcode
>> 20) & 0xf;
3434 unsigned rn
= (opcode
>> 16) & 0x0f;
3435 unsigned rt
= (opcode
>> 12) & 0x0f;
3438 return ERROR_COMMAND_SYNTAX_ERROR
;
3440 if (opcode
& 0x0800)
3475 return ERROR_COMMAND_SYNTAX_ERROR
;
3478 sprintf(cp
, "STR%s.W\tr%d, [r%d, r%d, LSL #%d]",
3479 size
, rt
, rn
, (int) opcode
& 0x0f,
3480 (int) (opcode
>> 4) & 0x03);
3484 immed
= opcode
& 0x0fff;
3485 sprintf(cp
, "STR%s.W\tr%d, [r%d, #%u]\t; %#3.3x",
3486 size
, rt
, rn
, immed
, immed
);
3490 immed
= opcode
& 0x00ff;
3492 switch (opcode
& 0x700) {
3498 return ERROR_COMMAND_SYNTAX_ERROR
;
3501 /* two indexed modes will write back rn */
3502 if (opcode
& 0x100) {
3503 if (opcode
& 0x400) /* pre-indexed */
3505 else { /* post-indexed */
3511 sprintf(cp
, "STR%s%s\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
3512 size
, suffix
, rt
, rn
, p1
,
3513 (opcode
& 0x200) ? "" : "-",
3518 static int t2ev_mul32(uint32_t opcode
, uint32_t address
,
3519 struct arm_instruction
*instruction
, char *cp
)
3521 int ra
= (opcode
>> 12) & 0xf;
3523 switch (opcode
& 0x007000f0) {
3526 sprintf(cp
, "MUL\tr%d, r%d, r%d",
3527 (int) (opcode
>> 8) & 0xf,
3528 (int) (opcode
>> 16) & 0xf,
3529 (int) (opcode
>> 0) & 0xf);
3531 sprintf(cp
, "MLA\tr%d, r%d, r%d, r%d",
3532 (int) (opcode
>> 8) & 0xf,
3533 (int) (opcode
>> 16) & 0xf,
3534 (int) (opcode
>> 0) & 0xf, ra
);
3537 sprintf(cp
, "MLS\tr%d, r%d, r%d, r%d",
3538 (int) (opcode
>> 8) & 0xf,
3539 (int) (opcode
>> 16) & 0xf,
3540 (int) (opcode
>> 0) & 0xf, ra
);
3543 return ERROR_COMMAND_SYNTAX_ERROR
;
3548 static int t2ev_mul64_div(uint32_t opcode
, uint32_t address
,
3549 struct arm_instruction
*instruction
, char *cp
)
3551 int op
= (opcode
>> 4) & 0xf;
3552 char *infix
= "MUL";
3554 op
+= (opcode
>> 16) & 0x70;
3562 sprintf(cp
, "%c%sL\tr%d, r%d, r%d, r%d",
3563 (op
& 0x20) ? 'U' : 'S',
3565 (int) (opcode
>> 12) & 0xf,
3566 (int) (opcode
>> 8) & 0xf,
3567 (int) (opcode
>> 16) & 0xf,
3568 (int) (opcode
>> 0) & 0xf);
3572 sprintf(cp
, "%cDIV\tr%d, r%d, r%d",
3573 (op
& 0x20) ? 'U' : 'S',
3574 (int) (opcode
>> 8) & 0xf,
3575 (int) (opcode
>> 16) & 0xf,
3576 (int) (opcode
>> 0) & 0xf);
3579 return ERROR_COMMAND_SYNTAX_ERROR
;
3585 static int t2ev_ldm_stm(uint32_t opcode
, uint32_t address
,
3586 struct arm_instruction
*instruction
, char *cp
)
3588 int rn
= (opcode
>> 16) & 0xf;
3589 int op
= (opcode
>> 22) & 0x6;
3590 int t
= (opcode
>> 21) & 1;
3591 unsigned registers
= opcode
& 0xffff;
3594 if (opcode
& (1 << 20))
3602 sprintf(cp
, "SRS%s\tsp%s, #%d", mode
,
3604 (unsigned) (opcode
& 0x1f));
3610 sprintf(cp
, "RFE%s\tr%d%s", mode
,
3611 (unsigned) ((opcode
>> 16) & 0xf),
3615 sprintf(cp
, "STM.W\tr%d%s, ", rn
, t
? "!" : "");
3619 sprintf(cp
, "POP.W\t");
3621 sprintf(cp
, "LDM.W\tr%d%s, ", rn
, t
? "!" : "");
3625 sprintf(cp
, "PUSH.W\t");
3627 sprintf(cp
, "STMDB\tr%d%s, ", rn
, t
? "!" : "");
3630 sprintf(cp
, "LDMDB.W\tr%d%s, ", rn
, t
? "!" : "");
3633 return ERROR_COMMAND_SYNTAX_ERROR
;
3638 for (t
= 0; registers
; t
++, registers
>>= 1) {
3639 if ((registers
& 1) == 0)
3642 sprintf(cp
, "r%d%s", t
, registers
? ", " : "");
3651 /* load/store dual or exclusive, table branch */
3652 static int t2ev_ldrex_strex(uint32_t opcode
, uint32_t address
,
3653 struct arm_instruction
*instruction
, char *cp
)
3655 unsigned op1op2
= (opcode
>> 20) & 0x3;
3656 unsigned op3
= (opcode
>> 4) & 0xf;
3658 unsigned rn
= (opcode
>> 16) & 0xf;
3659 unsigned rt
= (opcode
>> 12) & 0xf;
3660 unsigned rd
= (opcode
>> 8) & 0xf;
3661 unsigned imm
= opcode
& 0xff;
3665 op1op2
|= (opcode
>> 21) & 0xc;
3695 mnemonic
= "STREXB";
3698 mnemonic
= "STREXH";
3701 return ERROR_COMMAND_SYNTAX_ERROR
;
3709 sprintf(cp
, "TBB\t[r%u, r%u]", rn
, imm
& 0xf);
3712 sprintf(cp
, "TBH\t[r%u, r%u, LSL #1]", rn
, imm
& 0xf);
3715 mnemonic
= "LDREXB";
3718 mnemonic
= "LDREXH";
3721 return ERROR_COMMAND_SYNTAX_ERROR
;
3726 return ERROR_COMMAND_SYNTAX_ERROR
;
3731 sprintf(cp
, "%s\tr%u, r%u, [r%u, #%u]\t; %#2.2x",
3732 mnemonic
, rd
, rt
, rn
, imm
, imm
);
3734 sprintf(cp
, "%s\tr%u, r%u, [r%u]",
3735 mnemonic
, rd
, rt
, rn
);
3741 sprintf(cp
, "%s\tr%u, [r%u, #%u]\t; %#2.2x",
3742 mnemonic
, rt
, rn
, imm
, imm
);
3744 sprintf(cp
, "%s\tr%u, [r%u]",
3749 /* two indexed modes will write back rn */
3750 if (opcode
& (1 << 21)) {
3751 if (opcode
& (1 << 24)) /* pre-indexed */
3753 else { /* post-indexed */
3760 sprintf(cp
, "%s\tr%u, r%u, [r%u%s, #%s%u%s\t; %#2.2x",
3761 mnemonic
, rt
, rd
, rn
, p1
,
3762 (opcode
& (1 << 23)) ? "" : "-",
3767 address
= thumb_alignpc4(address
);
3769 if (opcode
& (1 << 23))
3773 sprintf(cp
, "%s\tr%u, r%u, %#8.8" PRIx32
,
3774 mnemonic
, rt
, rd
, address
);
3778 static int t2ev_data_shift(uint32_t opcode
, uint32_t address
,
3779 struct arm_instruction
*instruction
, char *cp
)
3781 int op
= (opcode
>> 21) & 0xf;
3782 int rd
= (opcode
>> 8) & 0xf;
3783 int rn
= (opcode
>> 16) & 0xf;
3784 int type
= (opcode
>> 4) & 0x3;
3785 int immed
= (opcode
>> 6) & 0x3;
3789 immed
|= (opcode
>> 10) & 0x1c;
3790 if (opcode
& (1 << 20))
3796 if (!(opcode
& (1 << 20)))
3797 return ERROR_COMMAND_SYNTAX_ERROR
;
3798 instruction
->type
= ARM_TST
;
3803 instruction
->type
= ARM_AND
;
3807 instruction
->type
= ARM_BIC
;
3812 instruction
->type
= ARM_MOV
;
3816 sprintf(cp
, "MOV%s.W\tr%d, r%d",
3818 (int) (opcode
& 0xf));
3831 sprintf(cp
, "RRX%s\tr%d, r%d",
3833 (int) (opcode
& 0xf));
3841 instruction
->type
= ARM_ORR
;
3847 instruction
->type
= ARM_MVN
;
3852 /* instruction->type = ARM_ORN; */
3858 if (!(opcode
& (1 << 20)))
3859 return ERROR_COMMAND_SYNTAX_ERROR
;
3860 instruction
->type
= ARM_TEQ
;
3865 instruction
->type
= ARM_EOR
;
3870 if (!(opcode
& (1 << 20)))
3871 return ERROR_COMMAND_SYNTAX_ERROR
;
3872 instruction
->type
= ARM_CMN
;
3877 instruction
->type
= ARM_ADD
;
3881 instruction
->type
= ARM_ADC
;
3885 instruction
->type
= ARM_SBC
;
3890 if (!(opcode
& (1 << 21)))
3891 return ERROR_COMMAND_SYNTAX_ERROR
;
3892 instruction
->type
= ARM_CMP
;
3897 instruction
->type
= ARM_SUB
;
3901 instruction
->type
= ARM_RSB
;
3905 return ERROR_COMMAND_SYNTAX_ERROR
;
3908 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3909 mnemonic
, suffix
, rd
, rn
, (int) (opcode
& 0xf));
3932 strcpy(cp
, ", RRX");
3938 sprintf(cp
, ", %s #%d", suffix
, immed
? immed
: 32);
3942 sprintf(cp
, "%s%s.W\tr%d, r%d",
3943 mnemonic
, suffix
, rn
, (int) (opcode
& 0xf));
3947 sprintf(cp
, "%s%s.W\tr%d, r%d, #%d",
3948 mnemonic
, suffix
, rd
,
3949 (int) (opcode
& 0xf), immed
? immed
: 32);
3953 static int t2ev_data_reg(uint32_t opcode
, uint32_t address
,
3954 struct arm_instruction
*instruction
, char *cp
)
3959 if (((opcode
>> 4) & 0xf) == 0) {
3960 switch ((opcode
>> 21) & 0x7) {
3974 return ERROR_COMMAND_SYNTAX_ERROR
;
3977 instruction
->type
= ARM_MOV
;
3978 if (opcode
& (1 << 20))
3980 sprintf(cp
, "%s%s.W\tr%d, r%d, r%d",
3982 (int) (opcode
>> 8) & 0xf,
3983 (int) (opcode
>> 16) & 0xf,
3984 (int) (opcode
>> 0) & 0xf);
3986 } else if (opcode
& (1 << 7)) {
3987 switch ((opcode
>> 20) & 0xf) {
3992 switch ((opcode
>> 4) & 0x3) {
3994 suffix
= ", ROR #8";
3997 suffix
= ", ROR #16";
4000 suffix
= ", ROR #24";
4003 sprintf(cp
, "%cXT%c.W\tr%d, r%d%s",
4004 (opcode
& (1 << 24)) ? 'U' : 'S',
4005 (opcode
& (1 << 26)) ? 'B' : 'H',
4006 (int) (opcode
>> 8) & 0xf,
4007 (int) (opcode
>> 0) & 0xf,
4014 if (opcode
& (1 << 6))
4015 return ERROR_COMMAND_SYNTAX_ERROR
;
4016 if (((opcode
>> 12) & 0xf) != 0xf)
4017 return ERROR_COMMAND_SYNTAX_ERROR
;
4018 if (!(opcode
& (1 << 20)))
4019 return ERROR_COMMAND_SYNTAX_ERROR
;
4021 switch (((opcode
>> 19) & 0x04)
4022 | ((opcode
>> 4) & 0x3)) {
4027 mnemonic
= "REV16.W";
4033 mnemonic
= "REVSH.W";
4039 return ERROR_COMMAND_SYNTAX_ERROR
;
4041 sprintf(cp
, "%s\tr%d, r%d",
4043 (int) (opcode
>> 8) & 0xf,
4044 (int) (opcode
>> 0) & 0xf);
4047 return ERROR_COMMAND_SYNTAX_ERROR
;
4054 static int t2ev_load_word(uint32_t opcode
, uint32_t address
,
4055 struct arm_instruction
*instruction
, char *cp
)
4057 int rn
= (opcode
>> 16) & 0xf;
4060 instruction
->type
= ARM_LDR
;
4063 immed
= opcode
& 0x0fff;
4064 if ((opcode
& (1 << 23)) == 0)
4066 sprintf(cp
, "LDR\tr%d, %#8.8" PRIx32
,
4067 (int) (opcode
>> 12) & 0xf,
4068 thumb_alignpc4(address
) + immed
);
4072 if (opcode
& (1 << 23)) {
4073 immed
= opcode
& 0x0fff;
4074 sprintf(cp
, "LDR.W\tr%d, [r%d, #%d]\t; %#3.3x",
4075 (int) (opcode
>> 12) & 0xf,
4080 if (!(opcode
& (0x3f << 6))) {
4081 sprintf(cp
, "LDR.W\tr%d, [r%d, r%d, LSL #%d]",
4082 (int) (opcode
>> 12) & 0xf,
4084 (int) (opcode
>> 0) & 0xf,
4085 (int) (opcode
>> 4) & 0x3);
4090 if (((opcode
>> 8) & 0xf) == 0xe) {
4091 immed
= opcode
& 0x00ff;
4093 sprintf(cp
, "LDRT\tr%d, [r%d, #%d]\t; %#2.2x",
4094 (int) (opcode
>> 12) & 0xf,
4099 if (((opcode
>> 8) & 0xf) == 0xc || (opcode
& 0x0900) == 0x0900) {
4100 char *p1
= "]", *p2
= "";
4102 if (!(opcode
& 0x0500))
4103 return ERROR_COMMAND_SYNTAX_ERROR
;
4105 immed
= opcode
& 0x00ff;
4107 /* two indexed modes will write back rn */
4108 if (opcode
& 0x100) {
4109 if (opcode
& 0x400) /* pre-indexed */
4111 else { /* post-indexed */
4117 sprintf(cp
, "LDR\tr%d, [r%d%s, #%s%u%s\t; %#2.2x",
4118 (int) (opcode
>> 12) & 0xf,
4120 (opcode
& 0x200) ? "" : "-",
4125 return ERROR_COMMAND_SYNTAX_ERROR
;
4128 static int t2ev_load_byte_hints(uint32_t opcode
, uint32_t address
,
4129 struct arm_instruction
*instruction
, char *cp
)
4131 int rn
= (opcode
>> 16) & 0xf;
4132 int rt
= (opcode
>> 12) & 0xf;
4133 int op2
= (opcode
>> 6) & 0x3f;
4135 char *p1
= "", *p2
= "]";
4138 switch ((opcode
>> 23) & 0x3) {
4140 if ((rn
& rt
) == 0xf) {
4142 immed
= opcode
& 0xfff;
4143 address
= thumb_alignpc4(address
);
4144 if (opcode
& (1 << 23))
4148 sprintf(cp
, "PLD\tr%d, %#8.8" PRIx32
,
4152 if (rn
== 0x0f && rt
!= 0x0f) {
4154 immed
= opcode
& 0xfff;
4155 address
= thumb_alignpc4(address
);
4156 if (opcode
& (1 << 23))
4160 sprintf(cp
, "LDRB\tr%d, %#8.8" PRIx32
,
4166 if ((op2
& 0x3c) == 0x38) {
4167 immed
= opcode
& 0xff;
4168 sprintf(cp
, "LDRBT\tr%d, [r%d, #%d]\t; %#2.2x",
4169 rt
, rn
, immed
, immed
);
4172 if ((op2
& 0x3c) == 0x30) {
4174 immed
= opcode
& 0xff;
4177 p1
= (opcode
& (1 << 21)) ? "W" : "";
4178 sprintf(cp
, "PLD%s\t[r%d, #%d]\t; %#6.6x",
4179 p1
, rn
, immed
, immed
);
4184 immed
= opcode
& 0xff;
4185 if (!(opcode
& 0x200))
4188 /* two indexed modes will write back rn */
4189 if (opcode
& 0x100) {
4190 if (opcode
& 0x400) /* pre-indexed */
4192 else { /* post-indexed */
4198 sprintf(cp
, "%s\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4199 mnemonic
, rt
, rn
, p1
,
4203 if ((op2
& 0x24) == 0x24) {
4205 goto ldrxb_immediate_t3
;
4208 int rm
= opcode
& 0xf;
4211 sprintf(cp
, "PLD\t");
4213 sprintf(cp
, "LDRB.W\tr%d, ", rt
);
4214 immed
= (opcode
>> 4) & 0x3;
4216 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4221 if ((rn
& rt
) == 0xf)
4224 immed
= opcode
& 0xfff;
4225 goto preload_immediate
;
4229 mnemonic
= "LDRB.W";
4230 immed
= opcode
& 0xfff;
4231 goto ldrxb_immediate_t2
;
4233 if ((rn
& rt
) == 0xf) {
4234 immed
= opcode
& 0xfff;
4235 address
= thumb_alignpc4(address
);
4236 if (opcode
& (1 << 23))
4240 sprintf(cp
, "PLI\t%#8.8" PRIx32
, address
);
4243 if (rn
== 0xf && rt
!= 0xf) {
4245 immed
= opcode
& 0xfff;
4246 address
= thumb_alignpc4(address
);
4247 if (opcode
& (1 << 23))
4251 sprintf(cp
, "LDRSB\t%#8.8" PRIx32
, address
);
4256 if ((op2
& 0x3c) == 0x38) {
4257 immed
= opcode
& 0xff;
4258 sprintf(cp
, "LDRSBT\tr%d, [r%d, #%d]\t; %#2.2x",
4259 rt
, rn
, immed
, immed
);
4262 if ((op2
& 0x3c) == 0x30) {
4264 immed
= opcode
& 0xff;
4265 immed
= -immed
; /* pli */
4266 sprintf(cp
, "PLI\t[r%d, #%d]\t; -%#2.2x",
4271 goto ldrxb_immediate_t3
;
4273 if ((op2
& 0x24) == 0x24) {
4275 goto ldrxb_immediate_t3
;
4278 int rm
= opcode
& 0xf;
4281 sprintf(cp
, "PLI\t");
4283 sprintf(cp
, "LDRSB.W\tr%d, ", rt
);
4284 immed
= (opcode
>> 4) & 0x3;
4286 sprintf(cp
, "[r%d, r%d, LSL #%d]", rn
, rm
, immed
);
4292 immed
= opcode
& 0xfff;
4293 sprintf(cp
, "PLI\t[r%d, #%d]\t; %#3.3x",
4299 immed
= opcode
& 0xfff;
4301 goto ldrxb_immediate_t2
;
4304 return ERROR_COMMAND_SYNTAX_ERROR
;
4307 static int t2ev_load_halfword(uint32_t opcode
, uint32_t address
,
4308 struct arm_instruction
*instruction
, char *cp
)
4310 int rn
= (opcode
>> 16) & 0xf;
4311 int rt
= (opcode
>> 12) & 0xf;
4312 int op2
= (opcode
>> 6) & 0x3f;
4317 sprintf(cp
, "HINT (UNALLOCATED)");
4321 if (opcode
& (1 << 24))
4324 if ((opcode
& (1 << 23)) == 0) {
4327 immed
= opcode
& 0xfff;
4328 address
= thumb_alignpc4(address
);
4329 if (opcode
& (1 << 23))
4333 sprintf(cp
, "LDR%sH\tr%d, %#8.8" PRIx32
,
4338 int rm
= opcode
& 0xf;
4340 immed
= (opcode
>> 4) & 0x3;
4341 sprintf(cp
, "LDR%sH.W\tr%d, [r%d, r%d, LSL #%d]",
4342 sign
, rt
, rn
, rm
, immed
);
4345 if ((op2
& 0x3c) == 0x38) {
4346 immed
= opcode
& 0xff;
4347 sprintf(cp
, "LDR%sHT\tr%d, [r%d, #%d]\t; %#2.2x",
4348 sign
, rt
, rn
, immed
, immed
);
4351 if ((op2
& 0x3c) == 0x30 || (op2
& 0x24) == 0x24) {
4352 char *p1
= "", *p2
= "]";
4354 immed
= opcode
& 0xff;
4355 if (!(opcode
& 0x200))
4358 /* two indexed modes will write back rn */
4359 if (opcode
& 0x100) {
4360 if (opcode
& 0x400) /* pre-indexed */
4362 else { /* post-indexed */
4367 sprintf(cp
, "LDR%sH\tr%d, [r%d%s, #%d%s\t; %#8.8x",
4368 sign
, rt
, rn
, p1
, immed
, p2
, immed
);
4375 immed
= opcode
& 0xfff;
4376 sprintf(cp
, "LDR%sH%s\tr%d, [r%d, #%d]\t; %#6.6x",
4377 sign
, *sign
? "" : ".W",
4378 rt
, rn
, immed
, immed
);
4382 return ERROR_COMMAND_SYNTAX_ERROR
;
4386 * REVISIT for Thumb2 instructions, instruction->type and friends aren't
4387 * always set. That means eventual arm_simulate_step() support for Thumb2
4388 * will need work in this area.
4390 int thumb2_opcode(struct target
*target
, uint32_t address
, struct arm_instruction
*instruction
)
4397 /* clear low bit ... it's set on function pointers */
4400 /* clear fields, to avoid confusion */
4401 memset(instruction
, 0, sizeof(struct arm_instruction
));
4403 /* read first halfword, see if this is the only one */
4404 retval
= target_read_u16(target
, address
, &op
);
4405 if (retval
!= ERROR_OK
)
4408 switch (op
& 0xf800) {
4412 /* 32-bit instructions */
4413 instruction
->instruction_size
= 4;
4415 retval
= target_read_u16(target
, address
+ 2, &op
);
4416 if (retval
!= ERROR_OK
)
4419 instruction
->opcode
= opcode
;
4422 /* 16-bit: Thumb1 + IT + CBZ/CBNZ + ... */
4423 return thumb_evaluate_opcode(op
, address
, instruction
);
4426 snprintf(instruction
->text
, 128,
4427 "0x%8.8" PRIx32
" 0x%8.8" PRIx32
"\t",
4429 cp
= strchr(instruction
->text
, 0);
4430 retval
= ERROR_FAIL
;
4432 /* ARMv7-M: A5.3.1 Data processing (modified immediate) */
4433 if ((opcode
& 0x1a008000) == 0x10000000)
4434 retval
= t2ev_data_mod_immed(opcode
, address
, instruction
, cp
);
4436 /* ARMv7-M: A5.3.3 Data processing (plain binary immediate) */
4437 else if ((opcode
& 0x1a008000) == 0x12000000)
4438 retval
= t2ev_data_immed(opcode
, address
, instruction
, cp
);
4440 /* ARMv7-M: A5.3.4 Branches and miscellaneous control */
4441 else if ((opcode
& 0x18008000) == 0x10008000)
4442 retval
= t2ev_b_misc(opcode
, address
, instruction
, cp
);
4444 /* ARMv7-M: A5.3.5 Load/store multiple */
4445 else if ((opcode
& 0x1e400000) == 0x08000000)
4446 retval
= t2ev_ldm_stm(opcode
, address
, instruction
, cp
);
4448 /* ARMv7-M: A5.3.6 Load/store dual or exclusive, table branch */
4449 else if ((opcode
& 0x1e400000) == 0x08400000)
4450 retval
= t2ev_ldrex_strex(opcode
, address
, instruction
, cp
);
4452 /* ARMv7-M: A5.3.7 Load word */
4453 else if ((opcode
& 0x1f700000) == 0x18500000)
4454 retval
= t2ev_load_word(opcode
, address
, instruction
, cp
);
4456 /* ARMv7-M: A5.3.8 Load halfword, unallocated memory hints */
4457 else if ((opcode
& 0x1e700000) == 0x18300000)
4458 retval
= t2ev_load_halfword(opcode
, address
, instruction
, cp
);
4460 /* ARMv7-M: A5.3.9 Load byte, memory hints */
4461 else if ((opcode
& 0x1e700000) == 0x18100000)
4462 retval
= t2ev_load_byte_hints(opcode
, address
, instruction
, cp
);
4464 /* ARMv7-M: A5.3.10 Store single data item */
4465 else if ((opcode
& 0x1f100000) == 0x18000000)
4466 retval
= t2ev_store_single(opcode
, address
, instruction
, cp
);
4468 /* ARMv7-M: A5.3.11 Data processing (shifted register) */
4469 else if ((opcode
& 0x1e000000) == 0x0a000000)
4470 retval
= t2ev_data_shift(opcode
, address
, instruction
, cp
);
4472 /* ARMv7-M: A5.3.12 Data processing (register)
4473 * and A5.3.13 Miscellaneous operations
4475 else if ((opcode
& 0x1f000000) == 0x1a000000)
4476 retval
= t2ev_data_reg(opcode
, address
, instruction
, cp
);
4478 /* ARMv7-M: A5.3.14 Multiply, and multiply accumulate */
4479 else if ((opcode
& 0x1f800000) == 0x1b000000)
4480 retval
= t2ev_mul32(opcode
, address
, instruction
, cp
);
4482 /* ARMv7-M: A5.3.15 Long multiply, long multiply accumulate, divide */
4483 else if ((opcode
& 0x1f800000) == 0x1b800000)
4484 retval
= t2ev_mul64_div(opcode
, address
, instruction
, cp
);
4486 if (retval
== ERROR_OK
)
4490 * Thumb2 also supports coprocessor, ThumbEE, and DSP/Media (SIMD)
4491 * instructions; not yet handled here.
4494 if (retval
== ERROR_COMMAND_SYNTAX_ERROR
) {
4495 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
4496 strcpy(cp
, "UNDEFINED OPCODE");
4500 LOG_DEBUG("Can't decode 32-bit Thumb2 yet (opcode=%08" PRIx32
")",
4503 strcpy(cp
, "(32-bit Thumb2 ...)");
4507 int arm_access_size(struct arm_instruction
*instruction
)
4509 if ((instruction
->type
== ARM_LDRB
)
4510 || (instruction
->type
== ARM_LDRBT
)
4511 || (instruction
->type
== ARM_LDRSB
)
4512 || (instruction
->type
== ARM_STRB
)
4513 || (instruction
->type
== ARM_STRBT
))
4515 else if ((instruction
->type
== ARM_LDRH
)
4516 || (instruction
->type
== ARM_LDRSH
)
4517 || (instruction
->type
== ARM_STRH
))
4519 else if ((instruction
->type
== ARM_LDR
)
4520 || (instruction
->type
== ARM_LDRT
)
4521 || (instruction
->type
== ARM_STR
)
4522 || (instruction
->type
== ARM_STRT
))
4524 else if ((instruction
->type
== ARM_LDRD
)
4525 || (instruction
->type
== ARM_STRD
))
4528 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction",
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)