2 * \file trc_idec_arminst.cpp
5 * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved.
9 * Redistribution and use in source and binary forms, with or without modification,
10 * are permitted provided that the following conditions are met:
12 * 1. Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
19 * 3. Neither the name of the copyright holder nor the names of its contributors
20 * may be used to endorse or promote products derived from this software without
21 * specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic
37 block identification and trace decode.
40 #include "i_dec/trc_idec_arminst.h"
42 #include <stddef.h> /* for NULL */
46 static ocsd_instr_subtype instr_sub_type = OCSD_S_INSTR_NONE;
48 /* need to spot the architecture version for certain instructions */
49 static uint16_t arch_version = 0x70;
51 ocsd_instr_subtype get_instr_subtype()
53 return instr_sub_type;
56 void clear_instr_subtype()
58 instr_sub_type = OCSD_S_INSTR_NONE;
61 void set_arch_version(uint16_t version)
63 arch_version = version;
66 int inst_ARM_is_direct_branch(uint32_t inst)
68 int is_direct_branch = 1;
69 if ((inst & 0xf0000000) == 0xf0000000) {
71 if ((inst & 0xfe000000) == 0xfa000000){
76 } else if ((inst & 0x0e000000) == 0x0a000000) {
81 return is_direct_branch;
84 int inst_ARM_wfiwfe(uint32_t inst)
86 if ( ((inst & 0xf0000000) != 0xf0000000) &&
87 ((inst & 0x0ffffffe) == 0x0320f002)
89 /* WFI & WFE may be traced as branches in etm4.3 ++ */
94 int inst_ARM_is_indirect_branch(uint32_t inst)
96 int is_indirect_branch = 1;
97 if ((inst & 0xf0000000) == 0xf0000000) {
99 if ((inst & 0xfe500000) == 0xf8100000) {
102 is_indirect_branch = 0;
104 } else if ((inst & 0x0ff000d0) == 0x01200010) {
105 /* BLX (register), BX */
106 if ((inst & 0xFF) == 0x1E)
107 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */
108 } else if ((inst & 0x0ff000f0) == 0x01200020) {
109 /* BXJ: in v8 this behaves like BX */
110 } else if ((inst & 0x0e108000) == 0x08108000) {
111 /* POP {...,pc} or LDMxx {...,pc} */
112 if ((inst & 0x0FFFA000) == 0x08BD8000) /* LDMIA SP!,{...,pc} */
113 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;
114 } else if ((inst & 0x0e50f000) == 0x0410f000) {
115 /* LDR PC,imm... inc. POP {PC} */
116 if ( (inst & 0x01ff0000) == 0x009D0000)
117 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm */
118 } else if ((inst & 0x0e50f010) == 0x0610f000) {
120 } else if ((inst & 0x0fe0f000) == 0x01a0f000) {
122 if ((inst & 0x00100FFF) == 0x00E) /* ensure the S=0, LSL #0 variant - i.e plain MOV */
123 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC, R14 */
124 } else if ((inst & 0x0f900080) == 0x01000000) {
125 /* "Miscellaneous instructions" - in DP space */
126 is_indirect_branch = 0;
127 } else if ((inst & 0x0f9000f0) == 0x01800090) {
128 /* Some extended loads and stores */
129 is_indirect_branch = 0;
130 } else if ((inst & 0x0fb0f000) == 0x0320f000) {
132 is_indirect_branch = 0;
133 } else if ((inst & 0x0e00f000) == 0x0200f000) {
134 /* DP PC,imm shift */
135 if ((inst & 0x0f90f000) == 0x0310f000) {
137 is_indirect_branch = 0;
139 } else if ((inst & 0x0e00f000) == 0x0000f000) {
142 is_indirect_branch = 0;
144 return is_indirect_branch;
147 int inst_Thumb_is_direct_branch(uint32_t inst)
150 return inst_Thumb_is_direct_branch_link(inst, &link, &cond);
153 int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond)
155 int is_direct_branch = 1;
157 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
158 /* B<c> (encoding T1) */
160 } else if ((inst & 0xf8000000) == 0xe0000000) {
161 /* B (encoding T2) */
162 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
163 /* B (encoding T3) */
165 } else if ((inst & 0xf8009000) == 0xf0009000) {
166 /* B (encoding T4); BL (encoding T1) */
167 if (inst & 0x00004000) {
169 instr_sub_type = OCSD_S_INSTR_BR_LINK;
171 } else if ((inst & 0xf800d001) == 0xf000c000) {
172 /* BLX (imm) (encoding T2) */
174 instr_sub_type = OCSD_S_INSTR_BR_LINK;
175 } else if ((inst & 0xf5000000) == 0xb1000000) {
179 is_direct_branch = 0;
181 return is_direct_branch;
184 int inst_Thumb_wfiwfe(uint32_t inst)
187 /* WFI, WFE may be branches in etm4.3++ */
188 if ((inst & 0xfffffffe) == 0xf3af8002) {
189 /* WFI & WFE (encoding T2) */
191 else if ((inst & 0xffef0000) == 0xbf200000) {
192 /* WFI & WFE (encoding T1) */
200 int inst_Thumb_is_indirect_branch(uint32_t inst)
203 return inst_Thumb_is_indirect_branch_link(inst, &link);
206 int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link)
208 /* See e.g. PFT Table 2-3 and Table 2-5 */
211 if ((inst & 0xff000000) == 0x47000000) {
212 /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */
213 if (inst & 0x00800000) {
215 instr_sub_type = OCSD_S_INSTR_BR_LINK;
217 else if ((inst & 0x00780000) == 0x00700000) {
218 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */
220 } else if ((inst & 0xfff0d000) == 0xf3c08000) {
221 /* BXJ: in v8 this behaves like BX */
222 } else if ((inst & 0xff000000) == 0xbd000000) {
224 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET;
225 } else if ((inst & 0xfd870000) == 0x44870000) {
226 /* MOV PC,reg or ADD PC,reg */
227 if ((inst & 0xffff0000) == 0x46f700000)
228 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC,LR */
229 } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) {
231 } else if ((inst & 0xffd00000) == 0xe8100000) {
233 } else if ((inst & 0xffd00000) == 0xe9900000) {
235 } else if ((inst & 0xfff0d000) == 0xf3d08000) {
236 /* SUBS PC,LR,#imm inc.ERET */
237 } else if ((inst & 0xfff0f000) == 0xf8d0f000) {
238 /* LDR PC,imm (T3) */
239 } else if ((inst & 0xff7ff000) == 0xf85ff000) {
240 /* LDR PC,literal (T2) */
241 } else if ((inst & 0xfff0f800) == 0xf850f800) {
242 /* LDR PC,imm (T4) */
243 if((inst & 0x000f0f00) == 0x000d0b00)
244 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm*/
245 } else if ((inst & 0xfff0ffc0) == 0xf850f000) {
246 /* LDR PC,reg (T2) */
247 } else if ((inst & 0xfe508000) == 0xe8108000) {
249 if ((inst & 0x0FFF0000) == 0x08BD0000) /* LDMIA [SP]!, */
250 instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* POP {...,pc} */
257 int inst_A64_is_direct_branch(uint32_t inst)
260 return inst_A64_is_direct_branch_link(inst, &link);
263 int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link)
265 int is_direct_branch = 1;
266 if ((inst & 0x7c000000) == 0x34000000) {
268 } else if ((inst & 0xff000010) == 0x54000000) {
270 } else if ((inst & 0x7c000000) == 0x14000000) {
272 if (inst & 0x80000000) {
274 instr_sub_type = OCSD_S_INSTR_BR_LINK;
277 is_direct_branch = 0;
279 return is_direct_branch;
282 int inst_A64_wfiwfe(uint32_t inst)
284 /* WFI, WFE may be traced as branches in etm 4.3++ */
285 if ((inst & 0xffffffdf) == 0xd503205f)
290 int inst_A64_is_indirect_branch(uint32_t inst)
293 return inst_A64_is_indirect_branch_link(inst, &link);
296 int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link)
298 int is_indirect_branch = 1;
300 if ((inst & 0xffdffc1f) == 0xd61f0000) {
302 if (inst & 0x00200000) {
304 instr_sub_type = OCSD_S_INSTR_BR_LINK;
306 } else if ((inst & 0xfffffc1f) == 0xd65f0000) {
307 instr_sub_type = OCSD_S_INSTR_V8_RET;
309 } else if ((inst & 0xffffffff) == 0xd69f03e0) {
311 instr_sub_type = OCSD_S_INSTR_V8_ERET;
312 } else if (arch_version >= 0x0803) {
313 /* new pointer auth instr for v8.3 arch */
314 if ((inst & 0xffdff800) == 0xd61f0800) {
315 /* BRAA, BRAB, BLRAA, BLRBB */
316 if (inst & 0x00200000) {
318 instr_sub_type = OCSD_S_INSTR_BR_LINK;
320 } else if ((inst & 0xffdff81F) == 0xd71f081F) {
321 /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */
322 if (inst & 0x00200000) {
324 instr_sub_type = OCSD_S_INSTR_BR_LINK;
326 } else if ((inst & 0xfffffbff) == 0xd69f0bff) {
328 instr_sub_type = OCSD_S_INSTR_V8_ERET;
329 } else if ((inst & 0xfffffbff) == 0xd65f0bff) {
331 instr_sub_type = OCSD_S_INSTR_V8_RET;
333 is_indirect_branch = 0;
336 is_indirect_branch = 0;
338 return is_indirect_branch;
341 int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
344 int is_direct_branch = 1;
345 if ((inst & 0x0e000000) == 0x0a000000) {
351 npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6);
352 if ((inst & 0xf0000000) == 0xf0000000) {
353 npc |= 1; /* indicate ISA is now Thumb */
354 npc |= ((inst >> 23) & 2); /* apply the H bit */
357 is_direct_branch = 0;
359 if (is_direct_branch && pnpc != NULL) {
362 return is_direct_branch;
365 int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc)
368 int is_direct_branch = 1;
369 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
370 /* B<c> (encoding T1) */
371 npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23);
373 } else if ((inst & 0xf8000000) == 0xe0000000) {
374 /* B (encoding T2) */
375 npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20);
377 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
378 /* B (encoding T3) */
379 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
380 ((inst & 0x0800) << 19) |
381 ((inst & 0x2000) << 16) |
382 ((inst & 0x003f0000) << 7) |
383 ((inst & 0x000007ff) << 12)) >> 11);
385 } else if ((inst & 0xf8009000) == 0xf0009000) {
386 /* B (encoding T4); BL (encoding T1) */
387 uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */
388 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
389 (((inst^S) & 0x2000) << 17) |
390 (((inst^S) & 0x0800) << 18) |
391 ((inst & 0x03ff0000) << 3) |
392 ((inst & 0x000007ff) << 8)) >> 7);
394 } else if ((inst & 0xf800d001) == 0xf000c000) {
395 /* BLX (encoding T2) */
396 uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */
397 addr &= 0xfffffffc; /* Align(PC,4) */
398 npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) |
399 (((inst^S) & 0x2000) << 17) |
400 (((inst^S) & 0x0800) << 18) |
401 ((inst & 0x03ff0000) << 3) |
402 ((inst & 0x000007fe) << 8)) >> 7);
403 /* don't set the Thumb bit, as we're transferring to ARM */
404 } else if ((inst & 0xf5000000) == 0xb1000000) {
406 /* Note that it's zero-extended - always a forward branch */
407 npc = addr + 4 + ((((inst & 0x02000000) << 6) |
408 ((inst & 0x00f80000) << 7)) >> 25);
411 is_direct_branch = 0;
413 if (is_direct_branch && pnpc != NULL) {
416 return is_direct_branch;
419 int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc)
422 int is_direct_branch = 1;
423 if ((inst & 0xff000010) == 0x54000000) {
425 npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
426 } else if ((inst & 0x7c000000) == 0x14000000) {
428 npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4);
429 } else if ((inst & 0x7e000000) == 0x34000000) {
431 npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11);
432 } else if ((inst & 0x7e000000) == 0x36000000) {
434 npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16);
436 is_direct_branch = 0;
438 if (is_direct_branch && pnpc != NULL) {
441 return is_direct_branch;
444 int inst_ARM_is_branch(uint32_t inst)
446 return inst_ARM_is_indirect_branch(inst) ||
447 inst_ARM_is_direct_branch(inst);
450 int inst_Thumb_is_branch(uint32_t inst)
452 return inst_Thumb_is_indirect_branch(inst) ||
453 inst_Thumb_is_direct_branch(inst);
456 int inst_A64_is_branch(uint32_t inst)
458 return inst_A64_is_indirect_branch(inst) ||
459 inst_A64_is_direct_branch(inst);
462 int inst_ARM_is_branch_and_link(uint32_t inst)
465 if ((inst & 0xf0000000) == 0xf0000000) {
466 if ((inst & 0xfe000000) == 0xfa000000){
467 instr_sub_type = OCSD_S_INSTR_BR_LINK;
472 } else if ((inst & 0x0f000000) == 0x0b000000) {
473 instr_sub_type = OCSD_S_INSTR_BR_LINK;
475 } else if ((inst & 0x0ff000f0) == 0x01200030) {
476 instr_sub_type = OCSD_S_INSTR_BR_LINK;
484 int inst_Thumb_is_branch_and_link(uint32_t inst)
487 if ((inst & 0xff800000) == 0x47800000) {
488 instr_sub_type = OCSD_S_INSTR_BR_LINK;
490 } else if ((inst & 0xf800c000) == 0xf000c000) {
491 instr_sub_type = OCSD_S_INSTR_BR_LINK;
499 int inst_A64_is_branch_and_link(uint32_t inst)
502 if ((inst & 0xfffffc1f) == 0xd63f0000) {
504 instr_sub_type = OCSD_S_INSTR_BR_LINK;
505 } else if ((inst & 0xfc000000) == 0x94000000) {
507 instr_sub_type = OCSD_S_INSTR_BR_LINK;
508 } else if (arch_version >= 0x0803) {
509 /* new pointer auth instr for v8.3 arch */
510 if ((inst & 0xfffff800) == 0xd73f0800) {
512 instr_sub_type = OCSD_S_INSTR_BR_LINK;
513 } else if ((inst & 0xfffff81F) == 0xd63f081F) {
515 instr_sub_type = OCSD_S_INSTR_BR_LINK;
525 int inst_ARM_is_conditional(uint32_t inst)
527 return (inst & 0xe0000000) != 0xe0000000;
530 int inst_Thumb_is_conditional(uint32_t inst)
532 if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) {
533 /* B<c> (encoding T1) */
535 } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) {
536 /* B<c> (encoding T3) */
538 } else if ((inst & 0xf5000000) == 0xb1000000) {
545 unsigned int inst_Thumb_is_IT(uint32_t inst)
547 if ((inst & 0xff000000) == 0xbf000000 &&
548 (inst & 0x000f0000) != 0x00000000) {
549 if (inst & 0x00010000) {
551 } else if (inst & 0x00020000) {
553 } else if (inst & 0x00040000) {
556 assert(inst & 0x00080000);
565 Test whether an A64 instruction is conditional.
567 Instructions like CSEL, CSINV, CCMP are not classed as conditional.
568 They use the condition code but do one of two things with it,
569 neither a NOP. The "intruction categories" section of ETMv4
570 lists no (non branch) conditional instructions for A64.
572 int inst_A64_is_conditional(uint32_t inst)
574 if ((inst & 0x7c000000) == 0x34000000) {
577 } else if ((inst & 0xff000010) == 0x54000000) {
584 arm_barrier_t inst_ARM_barrier(uint32_t inst)
586 if ((inst & 0xfff00000) == 0xf5700000) {
587 switch (inst & 0xf0) {
589 return ARM_BARRIER_DSB;
591 return ARM_BARRIER_DMB;
593 return ARM_BARRIER_ISB;
595 return ARM_BARRIER_NONE;
597 } else if ((inst & 0x0fff0f00) == 0x0e070f00) {
598 switch (inst & 0xff) {
600 return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
602 return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
604 return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
606 return ARM_BARRIER_NONE;
609 return ARM_BARRIER_NONE;
613 arm_barrier_t inst_Thumb_barrier(uint32_t inst)
615 if ((inst & 0xffffff00) == 0xf3bf8f00) {
616 switch (inst & 0xf0) {
618 return ARM_BARRIER_DSB;
620 return ARM_BARRIER_DMB;
622 return ARM_BARRIER_ISB;
624 return ARM_BARRIER_NONE;
626 } else if ((inst & 0xffff0f00) == 0xee070f00) {
627 /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */
628 switch (inst & 0xff) {
630 return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */
632 return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */
634 return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */
636 return ARM_BARRIER_NONE;
638 return ARM_BARRIER_NONE;
640 return ARM_BARRIER_NONE;
644 arm_barrier_t inst_A64_barrier(uint32_t inst)
646 if ((inst & 0xfffff09f) == 0xd503309f) {
647 switch (inst & 0x60) {
649 return ARM_BARRIER_DSB;
651 return ARM_BARRIER_DMB;
653 return ARM_BARRIER_ISB;
655 return ARM_BARRIER_NONE;
658 return ARM_BARRIER_NONE;
662 int inst_ARM_is_UDF(uint32_t inst)
664 return (inst & 0xfff000f0) == 0xe7f000f0;
667 int inst_Thumb_is_UDF(uint32_t inst)
669 return (inst & 0xff000000) == 0xde000000 || /* T1 */
670 (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */
673 int inst_A64_is_UDF(uint32_t inst)
675 /* No A64 encodings are formally allocated as permanently undefined,
676 but it is intended not to allocate any instructions in the 21-bit
677 regions at the bottom or top of the range. */
678 return (inst & 0xffe00000) == 0x00000000 ||
679 (inst & 0xffe00000) == 0xffe00000;
682 /* End of File trc_idec_arminst.cpp */