1 /***************************************************************************
2 * Copyright (C) 2006 by Dominic Rath *
3 * Dominic.Rath@gmx.de *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
24 #include "arm_disassembler.h"
28 /* textual represenation of the condition field */
29 /* ALways (default) is ommitted (empty string) */
30 char *arm_condition_strings
[] =
32 "EQ", "NE", "CS", "CC", "MI", "PL", "VS", "VC", "HI", "LS", "GE", "LT", "GT", "LE", "", "NV"
35 /* make up for C's missing ROR */
36 uint32_t ror(uint32_t value
, int places
)
38 return (value
>> places
) | (value
<< (32 - places
));
41 int evaluate_pld(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
44 if ((opcode
& 0x0d70f0000) == 0x0550f000)
46 instruction
->type
= ARM_PLD
;
48 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tPLD ...TODO...", address
, opcode
);
54 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
58 LOG_ERROR("should never reach this point");
62 int evaluate_swi(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
64 instruction
->type
= ARM_SWI
;
66 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSWI 0x%6.6x", address
, opcode
, (opcode
& 0xffffff));
71 int evaluate_blx_imm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
75 uint32_t target_address
;
77 instruction
->type
= ARM_BLX
;
78 immediate
= opcode
& 0x00ffffff;
80 /* sign extend 24-bit immediate */
81 if (immediate
& 0x00800000)
82 offset
= 0xff000000 | immediate
;
86 /* shift two bits left */
89 /* odd/event halfword */
90 if (opcode
& 0x01000000)
93 target_address
= address
+ 8 + offset
;
95 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX 0x%8.8x", address
, opcode
, target_address
);
97 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
98 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
103 int evaluate_b_bl(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
108 uint32_t target_address
;
110 immediate
= opcode
& 0x00ffffff;
111 L
= (opcode
& 0x01000000) >> 24;
113 /* sign extend 24-bit immediate */
114 if (immediate
& 0x00800000)
115 offset
= 0xff000000 | immediate
;
119 /* shift two bits left */
122 target_address
= address
+ 8 + offset
;
125 instruction
->type
= ARM_BL
;
127 instruction
->type
= ARM_B
;
129 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tB%s%s 0x%8.8x", address
, opcode
,
130 (L
) ? "L" : "", COND(opcode
), target_address
);
132 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
133 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
138 /* Coprocessor load/store and double register transfers */
139 /* both normal and extended instruction space (condition field b1111) */
140 int evaluate_ldc_stc_mcrr_mrrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
142 uint8_t cp_num
= (opcode
& 0xf00) >> 8;
145 if (((opcode
& 0x0ff00000) == 0x0c400000) || ((opcode
& 0x0ff00000) == 0x0c400000))
147 uint8_t cp_opcode
, Rd
, Rn
, CRm
;
150 cp_opcode
= (opcode
& 0xf0) >> 4;
151 Rd
= (opcode
& 0xf000) >> 12;
152 Rn
= (opcode
& 0xf0000) >> 16;
153 CRm
= (opcode
& 0xf);
156 if ((opcode
& 0x0ff00000) == 0x0c400000)
158 instruction
->type
= ARM_MCRR
;
163 if ((opcode
& 0x0ff00000) == 0x0c500000)
165 instruction
->type
= ARM_MRRC
;
169 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, %x, r%i, r%i, c%i",
170 address
, opcode
, mnemonic
, COND(opcode
), cp_num
, cp_opcode
, Rd
, Rn
, CRm
);
172 else /* LDC or STC */
174 uint8_t CRd
, Rn
, offset
;
177 char addressing_mode
[32];
179 CRd
= (opcode
& 0xf000) >> 12;
180 Rn
= (opcode
& 0xf0000) >> 16;
181 offset
= (opcode
& 0xff);
184 if (opcode
& 0x00100000)
186 instruction
->type
= ARM_LDC
;
191 instruction
->type
= ARM_STC
;
195 U
= (opcode
& 0x00800000) >> 23;
196 N
= (opcode
& 0x00400000) >> 22;
198 /* addressing modes */
199 if ((opcode
& 0x01200000) == 0x01000000) /* immediate offset */
200 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]", Rn
, (U
) ? "" : "-", offset
);
201 else if ((opcode
& 0x01200000) == 0x01200000) /* immediate pre-indexed */
202 snprintf(addressing_mode
, 32, "[r%i, #%s0x%2.2x*4]!", Rn
, (U
) ? "" : "-", offset
);
203 else if ((opcode
& 0x01200000) == 0x00200000) /* immediate post-indexed */
204 snprintf(addressing_mode
, 32, "[r%i], #%s0x%2.2x*4", Rn
, (U
) ? "" : "-", offset
);
205 else if ((opcode
& 0x01200000) == 0x00000000) /* unindexed */
206 snprintf(addressing_mode
, 32, "[r%i], #0x%2.2x", Rn
, offset
);
208 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s p%i, c%i, %s",
209 address
, opcode
, mnemonic
, ((opcode
& 0xf0000000) == 0xf0000000) ? COND(opcode
) : "2",
211 cp_num
, CRd
, addressing_mode
);
217 /* Coprocessor data processing instructions */
218 /* Coprocessor register transfer instructions */
219 /* both normal and extended instruction space (condition field b1111) */
220 int evaluate_cdp_mcr_mrc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
224 uint8_t cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
;
226 cond
= ((opcode
& 0xf0000000) == 0xf0000000) ? "2" : COND(opcode
);
227 cp_num
= (opcode
& 0xf00) >> 8;
228 CRd_Rd
= (opcode
& 0xf000) >> 12;
229 CRn
= (opcode
& 0xf0000) >> 16;
230 CRm
= (opcode
& 0xf);
231 opcode_2
= (opcode
& 0xe0) >> 5;
234 if (opcode
& 0x00000010) /* bit 4 set -> MRC/MCR */
236 if (opcode
& 0x00100000) /* bit 20 set -> MRC */
238 instruction
->type
= ARM_MRC
;
241 else /* bit 20 not set -> MCR */
243 instruction
->type
= ARM_MCR
;
247 opcode_1
= (opcode
& 0x00e00000) >> 21;
249 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, r%i, c%i, c%i, 0x%2.2x",
250 address
, opcode
, mnemonic
, cond
,
251 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
253 else /* bit 4 not set -> CDP */
255 instruction
->type
= ARM_CDP
;
258 opcode_1
= (opcode
& 0x00f00000) >> 20;
260 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s p%i, 0x%2.2x, c%i, c%i, c%i, 0x%2.2x",
261 address
, opcode
, mnemonic
, cond
,
262 cp_num
, opcode_1
, CRd_Rd
, CRn
, CRm
, opcode_2
);
268 /* Load/store instructions */
269 int evaluate_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
271 uint8_t I
, P
, U
, B
, W
, L
;
273 char *operation
; /* "LDR" or "STR" */
274 char *suffix
; /* "", "B", "T", "BT" */
278 I
= (opcode
& 0x02000000) >> 25;
279 P
= (opcode
& 0x01000000) >> 24;
280 U
= (opcode
& 0x00800000) >> 23;
281 B
= (opcode
& 0x00400000) >> 22;
282 W
= (opcode
& 0x00200000) >> 21;
283 L
= (opcode
& 0x00100000) >> 20;
285 /* target register */
286 Rd
= (opcode
& 0xf000) >> 12;
289 Rn
= (opcode
& 0xf0000) >> 16;
291 instruction
->info
.load_store
.Rd
= Rd
;
292 instruction
->info
.load_store
.Rn
= Rn
;
293 instruction
->info
.load_store
.U
= U
;
295 /* determine operation */
301 /* determine instruction type and suffix */
304 if ((P
== 0) && (W
== 1))
307 instruction
->type
= ARM_LDRBT
;
309 instruction
->type
= ARM_STRBT
;
315 instruction
->type
= ARM_LDRB
;
317 instruction
->type
= ARM_STRB
;
323 if ((P
== 0) && (W
== 1))
326 instruction
->type
= ARM_LDRT
;
328 instruction
->type
= ARM_STRT
;
334 instruction
->type
= ARM_LDR
;
336 instruction
->type
= ARM_STR
;
341 if (!I
) /* #+-<offset_12> */
343 uint32_t offset_12
= (opcode
& 0xfff);
345 snprintf(offset
, 32, ", #%s0x%x", (U
) ? "" : "-", offset_12
);
347 snprintf(offset
, 32, "%s", "");
349 instruction
->info
.load_store
.offset_mode
= 0;
350 instruction
->info
.load_store
.offset
.offset
= offset_12
;
352 else /* either +-<Rm> or +-<Rm>, <shift>, #<shift_imm> */
354 uint8_t shift_imm
, shift
;
357 shift_imm
= (opcode
& 0xf80) >> 7;
358 shift
= (opcode
& 0x60) >> 5;
361 /* LSR encodes a shift by 32 bit as 0x0 */
362 if ((shift
== 0x1) && (shift_imm
== 0x0))
365 /* ASR encodes a shift by 32 bit as 0x0 */
366 if ((shift
== 0x2) && (shift_imm
== 0x0))
369 /* ROR by 32 bit is actually a RRX */
370 if ((shift
== 0x3) && (shift_imm
== 0x0))
373 instruction
->info
.load_store
.offset_mode
= 1;
374 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
375 instruction
->info
.load_store
.offset
.reg
.shift
= shift
;
376 instruction
->info
.load_store
.offset
.reg
.shift_imm
= shift_imm
;
378 if ((shift_imm
== 0x0) && (shift
== 0x0)) /* +-<Rm> */
380 snprintf(offset
, 32, ", %sr%i", (U
) ? "" : "-", Rm
);
382 else /* +-<Rm>, <Shift>, #<shift_imm> */
387 snprintf(offset
, 32, ", %sr%i, LSL #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
390 snprintf(offset
, 32, ", %sr%i, LSR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
393 snprintf(offset
, 32, ", %sr%i, ASR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
396 snprintf(offset
, 32, ", %sr%i, ROR #0x%x", (U
) ? "" : "-", Rm
, shift_imm
);
399 snprintf(offset
, 32, ", %sr%i, RRX", (U
) ? "" : "-", Rm
);
407 if (W
== 0) /* offset */
409 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]",
410 address
, opcode
, operation
, COND(opcode
), suffix
,
413 instruction
->info
.load_store
.index_mode
= 0;
415 else /* pre-indexed */
417 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i%s]!",
418 address
, opcode
, operation
, COND(opcode
), suffix
,
421 instruction
->info
.load_store
.index_mode
= 1;
424 else /* post-indexed */
426 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i]%s",
427 address
, opcode
, operation
, COND(opcode
), suffix
,
430 instruction
->info
.load_store
.index_mode
= 2;
436 /* Miscellaneous load/store instructions */
437 int evaluate_misc_load_store(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
439 uint8_t P
, U
, I
, W
, L
, S
, H
;
441 char *operation
; /* "LDR" or "STR" */
442 char *suffix
; /* "H", "SB", "SH", "D" */
446 P
= (opcode
& 0x01000000) >> 24;
447 U
= (opcode
& 0x00800000) >> 23;
448 I
= (opcode
& 0x00400000) >> 22;
449 W
= (opcode
& 0x00200000) >> 21;
450 L
= (opcode
& 0x00100000) >> 20;
451 S
= (opcode
& 0x00000040) >> 6;
452 H
= (opcode
& 0x00000020) >> 5;
454 /* target register */
455 Rd
= (opcode
& 0xf000) >> 12;
458 Rn
= (opcode
& 0xf0000) >> 16;
460 instruction
->info
.load_store
.Rd
= Rd
;
461 instruction
->info
.load_store
.Rn
= Rn
;
462 instruction
->info
.load_store
.U
= U
;
464 /* determine instruction type and suffix */
472 instruction
->type
= ARM_LDRSH
;
478 instruction
->type
= ARM_LDRSB
;
482 else /* there are no signed stores, so this is used to encode double-register load/stores */
488 instruction
->type
= ARM_STRD
;
493 instruction
->type
= ARM_LDRD
;
503 instruction
->type
= ARM_LDRH
;
508 instruction
->type
= ARM_STRH
;
512 if (I
) /* Immediate offset/index (#+-<offset_8>)*/
514 uint32_t offset_8
= ((opcode
& 0xf00) >> 4) | (opcode
& 0xf);
515 snprintf(offset
, 32, "#%s0x%x", (U
) ? "" : "-", offset_8
);
517 instruction
->info
.load_store
.offset_mode
= 0;
518 instruction
->info
.load_store
.offset
.offset
= offset_8
;
520 else /* Register offset/index (+-<Rm>) */
524 snprintf(offset
, 32, "%sr%i", (U
) ? "" : "-", Rm
);
526 instruction
->info
.load_store
.offset_mode
= 1;
527 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
528 instruction
->info
.load_store
.offset
.reg
.shift
= 0x0;
529 instruction
->info
.load_store
.offset
.reg
.shift_imm
= 0x0;
534 if (W
== 0) /* offset */
536 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]",
537 address
, opcode
, operation
, COND(opcode
), suffix
,
540 instruction
->info
.load_store
.index_mode
= 0;
542 else /* pre-indexed */
544 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i, %s]!",
545 address
, opcode
, operation
, COND(opcode
), suffix
,
548 instruction
->info
.load_store
.index_mode
= 1;
551 else /* post-indexed */
553 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, [r%i], %s",
554 address
, opcode
, operation
, COND(opcode
), suffix
,
557 instruction
->info
.load_store
.index_mode
= 2;
563 /* Load/store multiples instructions */
564 int evaluate_ldm_stm(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
566 uint8_t P
, U
, S
, W
, L
, Rn
;
567 uint32_t register_list
;
568 char *addressing_mode
;
575 P
= (opcode
& 0x01000000) >> 24;
576 U
= (opcode
& 0x00800000) >> 23;
577 S
= (opcode
& 0x00400000) >> 22;
578 W
= (opcode
& 0x00200000) >> 21;
579 L
= (opcode
& 0x00100000) >> 20;
580 register_list
= (opcode
& 0xffff);
581 Rn
= (opcode
& 0xf0000) >> 16;
583 instruction
->info
.load_store_multiple
.Rn
= Rn
;
584 instruction
->info
.load_store_multiple
.register_list
= register_list
;
585 instruction
->info
.load_store_multiple
.S
= S
;
586 instruction
->info
.load_store_multiple
.W
= W
;
590 instruction
->type
= ARM_LDM
;
595 instruction
->type
= ARM_STM
;
603 instruction
->info
.load_store_multiple
.addressing_mode
= 1;
604 addressing_mode
= "IB";
608 instruction
->info
.load_store_multiple
.addressing_mode
= 3;
609 addressing_mode
= "DB";
616 instruction
->info
.load_store_multiple
.addressing_mode
= 0;
617 addressing_mode
= "IA";
621 instruction
->info
.load_store_multiple
.addressing_mode
= 2;
622 addressing_mode
= "DA";
626 reg_list_p
= reg_list
;
627 for (i
= 0; i
<= 15; i
++)
629 if ((register_list
>> i
) & 1)
634 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), "r%i", i
);
638 reg_list_p
+= snprintf(reg_list_p
, (reg_list
+ 69 - reg_list_p
), ", r%i", i
);
643 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i%s, {%s}%s",
644 address
, opcode
, mnemonic
, COND(opcode
), addressing_mode
,
645 Rn
, (W
) ? "!" : "", reg_list
, (S
) ? "^" : "");
650 /* Multiplies, extra load/stores */
651 int evaluate_mul_and_extra_ld_st(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
653 /* Multiply (accumulate) (long) and Swap/swap byte */
654 if ((opcode
& 0x000000f0) == 0x00000090)
656 /* Multiply (accumulate) */
657 if ((opcode
& 0x0f800000) == 0x00000000)
659 uint8_t Rm
, Rs
, Rn
, Rd
, S
;
661 Rs
= (opcode
& 0xf00) >> 8;
662 Rn
= (opcode
& 0xf000) >> 12;
663 Rd
= (opcode
& 0xf0000) >> 16;
664 S
= (opcode
& 0x00100000) >> 20;
666 /* examine A bit (accumulate) */
667 if (opcode
& 0x00200000)
669 instruction
->type
= ARM_MLA
;
670 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMLA%s%s r%i, r%i, r%i, r%i",
671 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
, Rn
);
675 instruction
->type
= ARM_MUL
;
676 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMUL%s%s r%i, r%i, r%i",
677 address
, opcode
, COND(opcode
), (S
) ? "S" : "", Rd
, Rm
, Rs
);
683 /* Multiply (accumulate) long */
684 if ((opcode
& 0x0f800000) == 0x00800000)
686 char* mnemonic
= NULL
;
687 uint8_t Rm
, Rs
, RdHi
, RdLow
, S
;
689 Rs
= (opcode
& 0xf00) >> 8;
690 RdHi
= (opcode
& 0xf000) >> 12;
691 RdLow
= (opcode
& 0xf0000) >> 16;
692 S
= (opcode
& 0x00100000) >> 20;
694 switch ((opcode
& 0x00600000) >> 21)
697 instruction
->type
= ARM_UMULL
;
701 instruction
->type
= ARM_UMLAL
;
705 instruction
->type
= ARM_SMULL
;
709 instruction
->type
= ARM_SMLAL
;
714 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, r%i, r%i",
715 address
, opcode
, mnemonic
, COND(opcode
), (S
) ? "S" : "",
716 RdLow
, RdHi
, Rm
, Rs
);
722 if ((opcode
& 0x0f800000) == 0x01000000)
726 Rd
= (opcode
& 0xf000) >> 12;
727 Rn
= (opcode
& 0xf0000) >> 16;
730 instruction
->type
= (opcode
& 0x00400000) ? ARM_SWPB
: ARM_SWP
;
732 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, [r%i]",
733 address
, opcode
, (opcode
& 0x00400000) ? "SWPB" : "SWP", COND(opcode
), Rd
, Rm
, Rn
);
739 return evaluate_misc_load_store(opcode
, address
, instruction
);
742 int evaluate_mrs_msr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
744 int R
= (opcode
& 0x00400000) >> 22;
745 char *PSR
= (R
) ? "SPSR" : "CPSR";
747 /* Move register to status register (MSR) */
748 if (opcode
& 0x00200000)
750 instruction
->type
= ARM_MSR
;
752 /* immediate variant */
753 if (opcode
& 0x02000000)
755 uint8_t immediate
= (opcode
& 0xff);
756 uint8_t rotate
= (opcode
& 0xf00);
758 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, 0x%8.8x",
759 address
, opcode
, COND(opcode
), PSR
,
760 (opcode
& 0x10000) ? "c" : "",
761 (opcode
& 0x20000) ? "x" : "",
762 (opcode
& 0x40000) ? "s" : "",
763 (opcode
& 0x80000) ? "f" : "",
764 ror(immediate
, (rotate
* 2))
767 else /* register variant */
769 uint8_t Rm
= opcode
& 0xf;
770 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMSR%s %s_%s%s%s%s, r%i",
771 address
, opcode
, COND(opcode
), PSR
,
772 (opcode
& 0x10000) ? "c" : "",
773 (opcode
& 0x20000) ? "x" : "",
774 (opcode
& 0x40000) ? "s" : "",
775 (opcode
& 0x80000) ? "f" : "",
781 else /* Move status register to register (MRS) */
785 instruction
->type
= ARM_MRS
;
786 Rd
= (opcode
& 0x0000f000) >> 12;
788 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tMRS%s r%i, %s",
789 address
, opcode
, COND(opcode
), Rd
, PSR
);
795 /* Miscellaneous instructions */
796 int evaluate_misc_instr(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
799 if ((opcode
& 0x000000f0) == 0x00000000)
801 evaluate_mrs_msr(opcode
, address
, instruction
);
805 if ((opcode
& 0x006000f0) == 0x00200010)
808 instruction
->type
= ARM_BX
;
811 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBX%s r%i",
812 address
, opcode
, COND(opcode
), Rm
);
814 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
815 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
819 if ((opcode
& 0x006000f0) == 0x00600010)
822 instruction
->type
= ARM_CLZ
;
824 Rd
= (opcode
& 0xf000) >> 12;
826 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tCLZ%s r%i, r%i",
827 address
, opcode
, COND(opcode
), Rd
, Rm
);
831 if ((opcode
& 0x006000f0) == 0x00200030)
834 instruction
->type
= ARM_BLX
;
837 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBLX%s r%i",
838 address
, opcode
, COND(opcode
), Rm
);
840 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
841 instruction
->info
.b_bl_bx_blx
.target_address
= -1;
844 /* Enhanced DSP add/subtracts */
845 if ((opcode
& 0x0000000f0) == 0x00000050)
848 char *mnemonic
= NULL
;
850 Rd
= (opcode
& 0xf000) >> 12;
851 Rn
= (opcode
& 0xf0000) >> 16;
853 switch ((opcode
& 0x00600000) >> 21)
856 instruction
->type
= ARM_QADD
;
860 instruction
->type
= ARM_QSUB
;
864 instruction
->type
= ARM_QDADD
;
868 instruction
->type
= ARM_QDSUB
;
873 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, r%i, r%i",
874 address
, opcode
, mnemonic
, COND(opcode
), Rd
, Rm
, Rn
);
877 /* Software breakpoints */
878 if ((opcode
& 0x0000000f0) == 0x00000070)
881 instruction
->type
= ARM_BKPT
;
882 immediate
= ((opcode
& 0x000fff00) >> 4) | (opcode
& 0xf);
884 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tBKPT 0x%4.4x",
885 address
, opcode
, immediate
);
888 /* Enhanced DSP multiplies */
889 if ((opcode
& 0x000000090) == 0x00000080)
891 int x
= (opcode
& 0x20) >> 5;
892 int y
= (opcode
& 0x40) >> 6;
895 if ((opcode
& 0x00600000) == 0x00000000)
897 uint8_t Rd
, Rm
, Rs
, Rn
;
898 instruction
->type
= ARM_SMLAxy
;
899 Rd
= (opcode
& 0xf0000) >> 16;
901 Rs
= (opcode
& 0xf00) >> 8;
902 Rn
= (opcode
& 0xf000) >> 12;
904 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
905 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
910 if ((opcode
& 0x00600000) == 0x00400000)
912 uint8_t RdLow
, RdHi
, Rm
, Rs
;
913 instruction
->type
= ARM_SMLAxy
;
914 RdHi
= (opcode
& 0xf0000) >> 16;
915 RdLow
= (opcode
& 0xf000) >> 12;
917 Rs
= (opcode
& 0xf00) >> 8;
919 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLA%s%s%s r%i, r%i, r%i, r%i",
920 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
921 RdLow
, RdHi
, Rm
, Rs
);
925 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 0))
927 uint8_t Rd
, Rm
, Rs
, Rn
;
928 instruction
->type
= ARM_SMLAWy
;
929 Rd
= (opcode
& 0xf0000) >> 16;
931 Rs
= (opcode
& 0xf00) >> 8;
932 Rn
= (opcode
& 0xf000) >> 12;
934 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMLAW%s%s r%i, r%i, r%i, r%i",
935 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
940 if ((opcode
& 0x00600000) == 0x00300000)
943 instruction
->type
= ARM_SMULxy
;
944 Rd
= (opcode
& 0xf0000) >> 16;
946 Rs
= (opcode
& 0xf00) >> 8;
948 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s%s r%i, r%i, r%i",
949 address
, opcode
, (x
) ? "T" : "B", (y
) ? "T" : "B", COND(opcode
),
954 if (((opcode
& 0x00600000) == 0x00100000) && (x
== 1))
957 instruction
->type
= ARM_SMULWy
;
958 Rd
= (opcode
& 0xf0000) >> 16;
960 Rs
= (opcode
& 0xf00) >> 8;
962 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tSMULW%s%s r%i, r%i, r%i",
963 address
, opcode
, (y
) ? "T" : "B", COND(opcode
),
971 int evaluate_data_proc(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
973 uint8_t I
, op
, S
, Rn
, Rd
;
974 char *mnemonic
= NULL
;
975 char shifter_operand
[32];
977 I
= (opcode
& 0x02000000) >> 25;
978 op
= (opcode
& 0x01e00000) >> 21;
979 S
= (opcode
& 0x00100000) >> 20;
981 Rd
= (opcode
& 0xf000) >> 12;
982 Rn
= (opcode
& 0xf0000) >> 16;
984 instruction
->info
.data_proc
.Rd
= Rd
;
985 instruction
->info
.data_proc
.Rn
= Rn
;
986 instruction
->info
.data_proc
.S
= S
;
991 instruction
->type
= ARM_AND
;
995 instruction
->type
= ARM_EOR
;
999 instruction
->type
= ARM_SUB
;
1003 instruction
->type
= ARM_RSB
;
1007 instruction
->type
= ARM_ADD
;
1011 instruction
->type
= ARM_ADC
;
1015 instruction
->type
= ARM_SBC
;
1019 instruction
->type
= ARM_RSC
;
1023 instruction
->type
= ARM_TST
;
1027 instruction
->type
= ARM_TEQ
;
1031 instruction
->type
= ARM_CMP
;
1035 instruction
->type
= ARM_CMN
;
1039 instruction
->type
= ARM_ORR
;
1043 instruction
->type
= ARM_MOV
;
1047 instruction
->type
= ARM_BIC
;
1051 instruction
->type
= ARM_MVN
;
1056 if (I
) /* immediate shifter operand (#<immediate>)*/
1058 uint8_t immed_8
= opcode
& 0xff;
1059 uint8_t rotate_imm
= (opcode
& 0xf00) >> 8;
1062 immediate
= ror(immed_8
, rotate_imm
* 2);
1064 snprintf(shifter_operand
, 32, "#0x%x", immediate
);
1066 instruction
->info
.data_proc
.variant
= 0;
1067 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= immediate
;
1069 else /* register-based shifter operand */
1072 shift
= (opcode
& 0x60) >> 5;
1073 Rm
= (opcode
& 0xf);
1075 if ((opcode
& 0x10) != 0x10) /* Immediate shifts ("<Rm>" or "<Rm>, <shift> #<shift_immediate>") */
1078 shift_imm
= (opcode
& 0xf80) >> 7;
1080 instruction
->info
.data_proc
.variant
= 1;
1081 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1082 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= shift_imm
;
1083 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= shift
;
1085 /* LSR encodes a shift by 32 bit as 0x0 */
1086 if ((shift
== 0x1) && (shift_imm
== 0x0))
1089 /* ASR encodes a shift by 32 bit as 0x0 */
1090 if ((shift
== 0x2) && (shift_imm
== 0x0))
1093 /* ROR by 32 bit is actually a RRX */
1094 if ((shift
== 0x3) && (shift_imm
== 0x0))
1097 if ((shift_imm
== 0x0) && (shift
== 0x0))
1099 snprintf(shifter_operand
, 32, "r%i", Rm
);
1103 if (shift
== 0x0) /* LSL */
1105 snprintf(shifter_operand
, 32, "r%i, LSL #0x%x", Rm
, shift_imm
);
1107 else if (shift
== 0x1) /* LSR */
1109 snprintf(shifter_operand
, 32, "r%i, LSR #0x%x", Rm
, shift_imm
);
1111 else if (shift
== 0x2) /* ASR */
1113 snprintf(shifter_operand
, 32, "r%i, ASR #0x%x", Rm
, shift_imm
);
1115 else if (shift
== 0x3) /* ROR */
1117 snprintf(shifter_operand
, 32, "r%i, ROR #0x%x", Rm
, shift_imm
);
1119 else if (shift
== 0x4) /* RRX */
1121 snprintf(shifter_operand
, 32, "r%i, RRX", Rm
);
1125 else /* Register shifts ("<Rm>, <shift> <Rs>") */
1127 uint8_t Rs
= (opcode
& 0xf00) >> 8;
1129 instruction
->info
.data_proc
.variant
= 2;
1130 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rm
;
1131 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rs
;
1132 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= shift
;
1134 if (shift
== 0x0) /* LSL */
1136 snprintf(shifter_operand
, 32, "r%i, LSL r%i", Rm
, Rs
);
1138 else if (shift
== 0x1) /* LSR */
1140 snprintf(shifter_operand
, 32, "r%i, LSR r%i", Rm
, Rs
);
1142 else if (shift
== 0x2) /* ASR */
1144 snprintf(shifter_operand
, 32, "r%i, ASR r%i", Rm
, Rs
);
1146 else if (shift
== 0x3) /* ROR */
1148 snprintf(shifter_operand
, 32, "r%i, ROR r%i", Rm
, Rs
);
1153 if ((op
< 0x8) || (op
== 0xc) || (op
== 0xe)) /* <opcode3>{<cond>}{S} <Rd>, <Rn>, <shifter_operand> */
1155 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, r%i, %s",
1156 address
, opcode
, mnemonic
, COND(opcode
),
1157 (S
) ? "S" : "", Rd
, Rn
, shifter_operand
);
1159 else if ((op
== 0xd) || (op
== 0xf)) /* <opcode1>{<cond>}{S} <Rd>, <shifter_operand> */
1161 if (opcode
==0xe1a00000) /* print MOV r0,r0 as NOP */
1162 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tNOP",address
, opcode
);
1164 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s%s r%i, %s",
1165 address
, opcode
, mnemonic
, COND(opcode
),
1166 (S
) ? "S" : "", Rd
, shifter_operand
);
1168 else /* <opcode2>{<cond>} <Rn>, <shifter_operand> */
1170 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\t%s%s r%i, %s",
1171 address
, opcode
, mnemonic
, COND(opcode
),
1172 Rn
, shifter_operand
);
1178 int arm_evaluate_opcode(uint32_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1180 /* clear fields, to avoid confusion */
1181 memset(instruction
, 0, sizeof(arm_instruction_t
));
1182 instruction
->opcode
= opcode
;
1184 /* catch opcodes with condition field [31:28] = b1111 */
1185 if ((opcode
& 0xf0000000) == 0xf0000000)
1187 /* Undefined instruction (or ARMv5E cache preload PLD) */
1188 if ((opcode
& 0x08000000) == 0x00000000)
1189 return evaluate_pld(opcode
, address
, instruction
);
1191 /* Undefined instruction */
1192 if ((opcode
& 0x0e000000) == 0x08000000)
1194 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1195 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1199 /* Branch and branch with link and change to Thumb */
1200 if ((opcode
& 0x0e000000) == 0x0a000000)
1201 return evaluate_blx_imm(opcode
, address
, instruction
);
1203 /* Extended coprocessor opcode space (ARMv5 and higher )*/
1204 /* Coprocessor load/store and double register transfers */
1205 if ((opcode
& 0x0e000000) == 0x0c000000)
1206 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1208 /* Coprocessor data processing */
1209 if ((opcode
& 0x0f000100) == 0x0c000000)
1210 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1212 /* Coprocessor register transfers */
1213 if ((opcode
& 0x0f000010) == 0x0c000010)
1214 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1216 /* Undefined instruction */
1217 if ((opcode
& 0x0f000000) == 0x0f000000)
1219 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1220 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1225 /* catch opcodes with [27:25] = b000 */
1226 if ((opcode
& 0x0e000000) == 0x00000000)
1228 /* Multiplies, extra load/stores */
1229 if ((opcode
& 0x00000090) == 0x00000090)
1230 return evaluate_mul_and_extra_ld_st(opcode
, address
, instruction
);
1232 /* Miscellaneous instructions */
1233 if ((opcode
& 0x0f900000) == 0x01000000)
1234 return evaluate_misc_instr(opcode
, address
, instruction
);
1236 return evaluate_data_proc(opcode
, address
, instruction
);
1239 /* catch opcodes with [27:25] = b001 */
1240 if ((opcode
& 0x0e000000) == 0x02000000)
1242 /* Undefined instruction */
1243 if ((opcode
& 0x0fb00000) == 0x03000000)
1245 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1246 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1250 /* Move immediate to status register */
1251 if ((opcode
& 0x0fb00000) == 0x03200000)
1252 return evaluate_mrs_msr(opcode
, address
, instruction
);
1254 return evaluate_data_proc(opcode
, address
, instruction
);
1258 /* catch opcodes with [27:25] = b010 */
1259 if ((opcode
& 0x0e000000) == 0x04000000)
1261 /* Load/store immediate offset */
1262 return evaluate_load_store(opcode
, address
, instruction
);
1265 /* catch opcodes with [27:25] = b011 */
1266 if ((opcode
& 0x0e000000) == 0x06000000)
1268 /* Undefined instruction */
1269 if ((opcode
& 0x00000010) == 0x00000010)
1271 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1272 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
1276 /* Load/store register offset */
1277 return evaluate_load_store(opcode
, address
, instruction
);
1281 /* catch opcodes with [27:25] = b100 */
1282 if ((opcode
& 0x0e000000) == 0x08000000)
1284 /* Load/store multiple */
1285 return evaluate_ldm_stm(opcode
, address
, instruction
);
1288 /* catch opcodes with [27:25] = b101 */
1289 if ((opcode
& 0x0e000000) == 0x0a000000)
1291 /* Branch and branch with link */
1292 return evaluate_b_bl(opcode
, address
, instruction
);
1295 /* catch opcodes with [27:25] = b110 */
1296 if ((opcode
& 0x0e000000) == 0x0a000000)
1298 /* Coprocessor load/store and double register transfers */
1299 return evaluate_ldc_stc_mcrr_mrrc(opcode
, address
, instruction
);
1302 /* catch opcodes with [27:25] = b111 */
1303 if ((opcode
& 0x0e000000) == 0x0e000000)
1305 /* Software interrupt */
1306 if ((opcode
& 0x0f000000) == 0x0f000000)
1307 return evaluate_swi(opcode
, address
, instruction
);
1309 /* Coprocessor data processing */
1310 if ((opcode
& 0x0f000010) == 0x0e000000)
1311 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1313 /* Coprocessor register transfers */
1314 if ((opcode
& 0x0f000010) == 0x0e000010)
1315 return evaluate_cdp_mcr_mrc(opcode
, address
, instruction
);
1318 LOG_ERROR("should never reach this point");
1322 int evaluate_b_bl_blx_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1324 uint32_t offset
= opcode
& 0x7ff;
1325 uint32_t opc
= (opcode
>> 11) & 0x3;
1326 uint32_t target_address
;
1327 char *mnemonic
= NULL
;
1329 /* sign extend 11-bit offset */
1330 if (((opc
==0) || (opc
==2)) && (offset
& 0x00000400))
1331 offset
= 0xfffff800 | offset
;
1333 target_address
= address
+ 4 + (offset
<<1);
1337 /* unconditional branch */
1339 instruction
->type
= ARM_B
;
1344 instruction
->type
= ARM_BLX
;
1349 instruction
->type
= ARM_UNKNOWN_INSTUCTION
;
1350 mnemonic
= "prefix";
1351 target_address
= offset
<<12;
1355 instruction
->type
= ARM_BL
;
1359 /* TODO: deals correctly with dual opcodes BL/BLX ... */
1361 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s 0x%8.8x", address
, opcode
,mnemonic
, target_address
);
1363 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1364 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1369 int evaluate_add_sub_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1371 uint8_t Rd
= (opcode
>> 0) & 0x7;
1372 uint8_t Rn
= (opcode
>> 3) & 0x7;
1373 uint8_t Rm_imm
= (opcode
>> 6) & 0x7;
1374 uint32_t opc
= opcode
& (1<<9);
1375 uint32_t reg_imm
= opcode
& (1<<10);
1380 instruction
->type
= ARM_SUB
;
1385 instruction
->type
= ARM_ADD
;
1389 instruction
->info
.data_proc
.Rd
= Rd
;
1390 instruction
->info
.data_proc
.Rn
= Rn
;
1391 instruction
->info
.data_proc
.S
= 1;
1395 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1396 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= Rm_imm
;
1397 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #%d",
1398 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1402 instruction
->info
.data_proc
.variant
= 1; /*immediate shift*/
1403 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm_imm
;
1404 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, r%i",
1405 address
, opcode
, mnemonic
, Rd
, Rn
, Rm_imm
);
1411 int evaluate_shift_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1413 uint8_t Rd
= (opcode
>> 0) & 0x7;
1414 uint8_t Rm
= (opcode
>> 3) & 0x7;
1415 uint8_t imm
= (opcode
>> 6) & 0x1f;
1416 uint8_t opc
= (opcode
>> 11) & 0x3;
1417 char *mnemonic
= NULL
;
1422 instruction
->type
= ARM_MOV
;
1424 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 0;
1427 instruction
->type
= ARM_MOV
;
1429 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 1;
1432 instruction
->type
= ARM_MOV
;
1434 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift
= 2;
1438 if ((imm
==0) && (opc
!=0))
1441 instruction
->info
.data_proc
.Rd
= Rd
;
1442 instruction
->info
.data_proc
.Rn
= -1;
1443 instruction
->info
.data_proc
.S
= 1;
1445 instruction
->info
.data_proc
.variant
= 1; /*immediate_shift*/
1446 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1447 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.shift_imm
= imm
;
1449 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i, #0x%02x",
1450 address
, opcode
, mnemonic
, Rd
, Rm
, imm
);
1455 int evaluate_data_proc_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1457 uint8_t imm
= opcode
& 0xff;
1458 uint8_t Rd
= (opcode
>> 8) & 0x7;
1459 uint32_t opc
= (opcode
>> 11) & 0x3;
1460 char *mnemonic
= NULL
;
1462 instruction
->info
.data_proc
.Rd
= Rd
;
1463 instruction
->info
.data_proc
.Rn
= Rd
;
1464 instruction
->info
.data_proc
.S
= 1;
1465 instruction
->info
.data_proc
.variant
= 0; /*immediate*/
1466 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
;
1471 instruction
->type
= ARM_MOV
;
1473 instruction
->info
.data_proc
.Rn
= -1;
1476 instruction
->type
= ARM_CMP
;
1478 instruction
->info
.data_proc
.Rd
= -1;
1481 instruction
->type
= ARM_ADD
;
1485 instruction
->type
= ARM_SUB
;
1490 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, #0x%02x",
1491 address
, opcode
, mnemonic
, Rd
, imm
);
1496 int evaluate_data_proc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1498 uint8_t high_reg
, op
, Rm
, Rd
,H1
,H2
;
1499 char *mnemonic
= NULL
;
1501 high_reg
= (opcode
& 0x0400) >> 10;
1502 op
= (opcode
& 0x03C0) >> 6;
1504 Rd
= (opcode
& 0x0007);
1505 Rm
= (opcode
& 0x0038) >> 3;
1506 H1
= (opcode
& 0x0080) >> 7;
1507 H2
= (opcode
& 0x0040) >> 6;
1509 instruction
->info
.data_proc
.Rd
= Rd
;
1510 instruction
->info
.data_proc
.Rn
= Rd
;
1511 instruction
->info
.data_proc
.S
= (!high_reg
|| (instruction
->type
== ARM_CMP
));
1512 instruction
->info
.data_proc
.variant
= 1 /*immediate shift*/;
1513 instruction
->info
.data_proc
.shifter_operand
.immediate_shift
.Rm
= Rm
;
1524 instruction
->type
= ARM_ADD
;
1528 instruction
->type
= ARM_CMP
;
1532 instruction
->type
= ARM_MOV
;
1536 if ((opcode
& 0x7) == 0x0)
1538 instruction
->info
.b_bl_bx_blx
.reg_operand
= Rm
;
1541 instruction
->type
= ARM_BLX
;
1542 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBLX r%i", address
, opcode
, Rm
);
1546 instruction
->type
= ARM_BX
;
1547 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBX r%i", address
, opcode
, Rm
);
1552 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1553 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
1564 instruction
->type
= ARM_AND
;
1568 instruction
->type
= ARM_EOR
;
1572 instruction
->type
= ARM_MOV
;
1574 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1575 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 0;
1576 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1577 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1580 instruction
->type
= ARM_MOV
;
1582 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1583 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 1;
1584 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1585 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1588 instruction
->type
= ARM_MOV
;
1590 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1591 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 2;
1592 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1593 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1596 instruction
->type
= ARM_ADC
;
1600 instruction
->type
= ARM_SBC
;
1604 instruction
->type
= ARM_MOV
;
1606 instruction
->info
.data_proc
.variant
= 2 /*register shift*/;
1607 instruction
->info
.data_proc
.shifter_operand
.register_shift
.shift
= 3;
1608 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rm
= Rd
;
1609 instruction
->info
.data_proc
.shifter_operand
.register_shift
.Rs
= Rm
;
1612 instruction
->type
= ARM_TST
;
1616 instruction
->type
= ARM_RSB
;
1618 instruction
->info
.data_proc
.variant
= 0 /*immediate*/;
1619 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= 0;
1620 instruction
->info
.data_proc
.Rn
= Rm
;
1623 instruction
->type
= ARM_CMP
;
1627 instruction
->type
= ARM_CMN
;
1631 instruction
->type
= ARM_ORR
;
1635 instruction
->type
= ARM_MUL
;
1639 instruction
->type
= ARM_BIC
;
1643 instruction
->type
= ARM_MVN
;
1649 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, r%i",
1650 address
, opcode
, mnemonic
, Rd
, Rm
);
1655 int evaluate_load_literal_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1658 uint8_t Rd
= (opcode
>> 8) & 0x7;
1660 instruction
->type
= ARM_LDR
;
1661 immediate
= opcode
& 0x000000ff;
1663 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tLDR r%i, [PC, #0x%x]", address
, opcode
, Rd
, immediate
*4);
1665 instruction
->info
.load_store
.Rd
= Rd
;
1666 instruction
->info
.load_store
.Rn
= 15 /*PC*/;
1667 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1668 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1669 instruction
->info
.load_store
.offset
.offset
= immediate
*4;
1674 int evaluate_load_store_reg_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1676 uint8_t Rd
= (opcode
>> 0) & 0x7;
1677 uint8_t Rn
= (opcode
>> 3) & 0x7;
1678 uint8_t Rm
= (opcode
>> 6) & 0x7;
1679 uint8_t opc
= (opcode
>> 9) & 0x7;
1680 char *mnemonic
= NULL
;
1685 instruction
->type
= ARM_STR
;
1689 instruction
->type
= ARM_STRH
;
1693 instruction
->type
= ARM_STRB
;
1697 instruction
->type
= ARM_LDRSB
;
1701 instruction
->type
= ARM_LDR
;
1705 instruction
->type
= ARM_LDRH
;
1709 instruction
->type
= ARM_LDRB
;
1713 instruction
->type
= ARM_LDRSH
;
1718 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [r%i, r%i]", address
, opcode
, mnemonic
, Rd
, Rn
, Rm
);
1720 instruction
->info
.load_store
.Rd
= Rd
;
1721 instruction
->info
.load_store
.Rn
= Rn
;
1722 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1723 instruction
->info
.load_store
.offset_mode
= 1; /*register*/
1724 instruction
->info
.load_store
.offset
.reg
.Rm
= Rm
;
1729 int evaluate_load_store_imm_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1731 uint32_t offset
= (opcode
>> 6) & 0x1f;
1732 uint8_t Rd
= (opcode
>> 0) & 0x7;
1733 uint8_t Rn
= (opcode
>> 3) & 0x7;
1734 uint32_t L
= opcode
& (1<<11);
1735 uint32_t B
= opcode
& (1<<12);
1742 instruction
->type
= ARM_LDR
;
1747 instruction
->type
= ARM_STR
;
1751 if ((opcode
&0xF000)==0x8000)
1762 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s%c r%i, [r%i, #0x%x]", address
, opcode
, mnemonic
, suffix
, Rd
, Rn
, offset
<<shift
);
1764 instruction
->info
.load_store
.Rd
= Rd
;
1765 instruction
->info
.load_store
.Rn
= Rn
;
1766 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1767 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1768 instruction
->info
.load_store
.offset
.offset
= offset
<<shift
;
1773 int evaluate_load_store_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1775 uint32_t offset
= opcode
& 0xff;
1776 uint8_t Rd
= (opcode
>> 8) & 0x7;
1777 uint32_t L
= opcode
& (1<<11);
1782 instruction
->type
= ARM_LDR
;
1787 instruction
->type
= ARM_STR
;
1791 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s r%i, [SP, #0x%x]", address
, opcode
, mnemonic
, Rd
, offset
*4);
1793 instruction
->info
.load_store
.Rd
= Rd
;
1794 instruction
->info
.load_store
.Rn
= 13 /*SP*/;
1795 instruction
->info
.load_store
.index_mode
= 0; /*offset*/
1796 instruction
->info
.load_store
.offset_mode
= 0; /*immediate*/
1797 instruction
->info
.load_store
.offset
.offset
= offset
*4;
1802 int evaluate_add_sp_pc_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1804 uint32_t imm
= opcode
& 0xff;
1805 uint8_t Rd
= (opcode
>> 8) & 0x7;
1807 uint32_t SP
= opcode
& (1<<11);
1810 instruction
->type
= ARM_ADD
;
1823 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tADD r%i, %s, #0x%x", address
, opcode
, Rd
,reg_name
, imm
*4);
1825 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1826 instruction
->info
.data_proc
.Rd
= Rd
;
1827 instruction
->info
.data_proc
.Rn
= Rn
;
1828 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1833 int evaluate_adjust_stack_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1835 uint32_t imm
= opcode
& 0x7f;
1836 uint8_t opc
= opcode
& (1<<7);
1842 instruction
->type
= ARM_SUB
;
1847 instruction
->type
= ARM_ADD
;
1851 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s SP, #0x%x", address
, opcode
, mnemonic
, imm
*4);
1853 instruction
->info
.data_proc
.variant
= 0 /* immediate */;
1854 instruction
->info
.data_proc
.Rd
= 13 /*SP*/;
1855 instruction
->info
.data_proc
.Rn
= 13 /*SP*/;
1856 instruction
->info
.data_proc
.shifter_operand
.immediate
.immediate
= imm
*4;
1861 int evaluate_breakpoint_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1863 uint32_t imm
= opcode
& 0xff;
1865 instruction
->type
= ARM_BKPT
;
1867 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tBKPT 0x%02x", address
, opcode
, imm
);
1872 int evaluate_load_store_multiple_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1874 uint32_t reg_list
= opcode
& 0xff;
1875 uint32_t L
= opcode
& (1<<11);
1876 uint32_t R
= opcode
& (1<<8);
1877 uint8_t Rn
= (opcode
>> 8) & 7;
1878 uint8_t addr_mode
= 0 /* IA */;
1882 char ptr_name
[7] = "";
1885 if ((opcode
& 0xf000) == 0xc000)
1886 { /* generic load/store multiple */
1889 instruction
->type
= ARM_LDM
;
1894 instruction
->type
= ARM_STM
;
1897 snprintf(ptr_name
,7,"r%i!, ",Rn
);
1904 instruction
->type
= ARM_LDM
;
1907 reg_list
|= (1<<15) /*PC*/;
1911 instruction
->type
= ARM_STM
;
1913 addr_mode
= 3; /*DB*/
1915 reg_list
|= (1<<14) /*LR*/;
1919 reg_names_p
= reg_names
;
1920 for (i
= 0; i
<= 15; i
++)
1922 if (reg_list
& (1<<i
))
1923 reg_names_p
+= snprintf(reg_names_p
, (reg_names
+ 40 - reg_names_p
), "r%i, ", i
);
1925 if (reg_names_p
>reg_names
)
1926 reg_names_p
[-2] = '\0';
1927 else /* invalid op : no registers */
1928 reg_names
[0] = '\0';
1930 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\t%s %s{%s}", address
, opcode
, mnemonic
, ptr_name
,reg_names
);
1932 instruction
->info
.load_store_multiple
.register_list
= reg_list
;
1933 instruction
->info
.load_store_multiple
.Rn
= Rn
;
1934 instruction
->info
.load_store_multiple
.addressing_mode
= addr_mode
;
1939 int evaluate_cond_branch_thumb(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1941 uint32_t offset
= opcode
& 0xff;
1942 uint8_t cond
= (opcode
>> 8) & 0xf;
1943 uint32_t target_address
;
1947 instruction
->type
= ARM_SWI
;
1948 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tSWI 0x%02x", address
, opcode
, offset
);
1951 else if (cond
== 0xe)
1953 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
1954 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
1958 /* sign extend 8-bit offset */
1959 if (offset
& 0x00000080)
1960 offset
= 0xffffff00 | offset
;
1962 target_address
= address
+ 4 + (offset
<<1);
1964 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tB%s 0x%8.8x", address
, opcode
,
1965 arm_condition_strings
[cond
], target_address
);
1967 instruction
->type
= ARM_B
;
1968 instruction
->info
.b_bl_bx_blx
.reg_operand
= -1;
1969 instruction
->info
.b_bl_bx_blx
.target_address
= target_address
;
1974 int thumb_evaluate_opcode(uint16_t opcode
, uint32_t address
, arm_instruction_t
*instruction
)
1976 /* clear fields, to avoid confusion */
1977 memset(instruction
, 0, sizeof(arm_instruction_t
));
1978 instruction
->opcode
= opcode
;
1980 if ((opcode
& 0xe000) == 0x0000)
1982 /* add/substract register or immediate */
1983 if ((opcode
& 0x1800) == 0x1800)
1984 return evaluate_add_sub_thumb(opcode
, address
, instruction
);
1985 /* shift by immediate */
1987 return evaluate_shift_imm_thumb(opcode
, address
, instruction
);
1990 /* Add/substract/compare/move immediate */
1991 if ((opcode
& 0xe000) == 0x2000)
1993 return evaluate_data_proc_imm_thumb(opcode
, address
, instruction
);
1996 /* Data processing instructions */
1997 if ((opcode
& 0xf800) == 0x4000)
1999 return evaluate_data_proc_thumb(opcode
, address
, instruction
);
2002 /* Load from literal pool */
2003 if ((opcode
& 0xf800) == 0x4800)
2005 return evaluate_load_literal_thumb(opcode
, address
, instruction
);
2008 /* Load/Store register offset */
2009 if ((opcode
& 0xf000) == 0x5000)
2011 return evaluate_load_store_reg_thumb(opcode
, address
, instruction
);
2014 /* Load/Store immediate offset */
2015 if (((opcode
& 0xe000) == 0x6000)
2016 ||((opcode
& 0xf000) == 0x8000))
2018 return evaluate_load_store_imm_thumb(opcode
, address
, instruction
);
2021 /* Load/Store from/to stack */
2022 if ((opcode
& 0xf000) == 0x9000)
2024 return evaluate_load_store_stack_thumb(opcode
, address
, instruction
);
2028 if ((opcode
& 0xf000) == 0xa000)
2030 return evaluate_add_sp_pc_thumb(opcode
, address
, instruction
);
2034 if ((opcode
& 0xf000) == 0xb000)
2036 if ((opcode
& 0x0f00) == 0x0000)
2037 return evaluate_adjust_stack_thumb(opcode
, address
, instruction
);
2038 else if ((opcode
& 0x0f00) == 0x0e00)
2039 return evaluate_breakpoint_thumb(opcode
, address
, instruction
);
2040 else if ((opcode
& 0x0600) == 0x0400) /* push pop */
2041 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2044 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2045 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%4.4x\tUNDEFINED INSTRUCTION", address
, opcode
);
2050 /* Load/Store multiple */
2051 if ((opcode
& 0xf000) == 0xc000)
2053 return evaluate_load_store_multiple_thumb(opcode
, address
, instruction
);
2056 /* Conditional branch + SWI */
2057 if ((opcode
& 0xf000) == 0xd000)
2059 return evaluate_cond_branch_thumb(opcode
, address
, instruction
);
2062 if ((opcode
& 0xe000) == 0xe000)
2064 /* Undefined instructions */
2065 if ((opcode
& 0xf801) == 0xe801)
2067 instruction
->type
= ARM_UNDEFINED_INSTRUCTION
;
2068 snprintf(instruction
->text
, 128, "0x%8.8x\t0x%8.8x\tUNDEFINED INSTRUCTION", address
, opcode
);
2072 { /* Branch to offset */
2073 return evaluate_b_bl_blx_thumb(opcode
, address
, instruction
);
2077 LOG_ERROR("should never reach this point (opcode=%04x)",opcode
);
2081 int arm_access_size(arm_instruction_t
*instruction
)
2083 if ((instruction
->type
== ARM_LDRB
)
2084 || (instruction
->type
== ARM_LDRBT
)
2085 || (instruction
->type
== ARM_LDRSB
)
2086 || (instruction
->type
== ARM_STRB
)
2087 || (instruction
->type
== ARM_STRBT
))
2091 else if ((instruction
->type
== ARM_LDRH
)
2092 || (instruction
->type
== ARM_LDRSH
)
2093 || (instruction
->type
== ARM_STRH
))
2097 else if ((instruction
->type
== ARM_LDR
)
2098 || (instruction
->type
== ARM_LDRT
)
2099 || (instruction
->type
== ARM_STR
)
2100 || (instruction
->type
== ARM_STRT
))
2104 else if ((instruction
->type
== ARM_LDRD
)
2105 || (instruction
->type
== ARM_STRD
))
2111 LOG_ERROR("BUG: instruction type %i isn't a load/store instruction", instruction
->type
);