diff options
Diffstat (limited to 'decoder/source/i_dec/trc_idec_arminst.cpp')
| -rw-r--r-- | decoder/source/i_dec/trc_idec_arminst.cpp | 167 |
1 files changed, 144 insertions, 23 deletions
diff --git a/decoder/source/i_dec/trc_idec_arminst.cpp b/decoder/source/i_dec/trc_idec_arminst.cpp index ed7eb247d3be..09964a15e7b3 100644 --- a/decoder/source/i_dec/trc_idec_arminst.cpp +++ b/decoder/source/i_dec/trc_idec_arminst.cpp @@ -5,7 +5,6 @@ * \copyright Copyright (c) 2015, ARM Limited. All Rights Reserved. */ - /* * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: @@ -40,13 +39,15 @@ block identification and trace decode. #include "i_dec/trc_idec_arminst.h" - #include <stddef.h> /* for NULL */ #include <assert.h> static ocsd_instr_subtype instr_sub_type = OCSD_S_INSTR_NONE; +/* need to spot the architecture version for certain instructions */ +static uint16_t arch_version = 0x70; + ocsd_instr_subtype get_instr_subtype() { return instr_sub_type; @@ -57,6 +58,11 @@ void clear_instr_subtype() instr_sub_type = OCSD_S_INSTR_NONE; } +void set_arch_version(uint16_t version) +{ + arch_version = version; +} + int inst_ARM_is_direct_branch(uint32_t inst) { int is_direct_branch = 1; @@ -75,6 +81,15 @@ int inst_ARM_is_direct_branch(uint32_t inst) return is_direct_branch; } +int inst_ARM_wfiwfe(uint32_t inst) +{ + if ( ((inst & 0xf0000000) != 0xf0000000) && + ((inst & 0x0ffffffe) == 0x0320f002) + ) + /* WFI & WFE may be traced as branches in etm4.3 ++ */ + return 1; + return 0; +} int inst_ARM_is_indirect_branch(uint32_t inst) { @@ -88,14 +103,24 @@ int inst_ARM_is_indirect_branch(uint32_t inst) } } else if ((inst & 0x0ff000d0) == 0x01200010) { /* BLX (register), BX */ + if ((inst & 0xFF) == 0x1E) + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */ + } else if ((inst & 0x0ff000f0) == 0x01200020) { + /* BXJ: in v8 this behaves like BX */ } else if ((inst & 0x0e108000) == 0x08108000) { /* POP {...,pc} or LDMxx {...,pc} */ + if ((inst & 0x0FFFA000) == 0x08BD8000) /* LDMIA SP!,{...,pc} */ + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; } else if ((inst & 0x0e50f000) == 0x0410f000) { /* LDR PC,imm... inc. POP {PC} */ + if ( (inst & 0x01ff0000) == 0x009D0000) + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm */ } else if ((inst & 0x0e50f010) == 0x0610f000) { /* LDR PC,reg */ } else if ((inst & 0x0fe0f000) == 0x01a0f000) { /* MOV PC,rx */ + if ((inst & 0x00100FFF) == 0x00E) /* ensure the S=0, LSL #0 variant - i.e plain MOV */ + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC, R14 */ } else if ((inst & 0x0f900080) == 0x01000000) { /* "Miscellaneous instructions" - in DP space */ is_indirect_branch = 0; @@ -119,39 +144,88 @@ int inst_ARM_is_indirect_branch(uint32_t inst) return is_indirect_branch; } - int inst_Thumb_is_direct_branch(uint32_t inst) { + uint8_t link, cond; + return inst_Thumb_is_direct_branch_link(inst, &link, &cond); +} + +int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond) +{ int is_direct_branch = 1; + if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { /* B<c> (encoding T1) */ + *is_cond = 1; } else if ((inst & 0xf8000000) == 0xe0000000) { /* B (encoding T2) */ } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { /* B (encoding T3) */ + *is_cond = 1; } else if ((inst & 0xf8009000) == 0xf0009000) { /* B (encoding T4); BL (encoding T1) */ + if (inst & 0x00004000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } } else if ((inst & 0xf800d001) == 0xf000c000) { /* BLX (imm) (encoding T2) */ + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; } else if ((inst & 0xf5000000) == 0xb1000000) { /* CB(NZ) */ + *is_cond = 1; } else { is_direct_branch = 0; } return is_direct_branch; } +int inst_Thumb_wfiwfe(uint32_t inst) +{ + int is_wfiwfe = 1; + /* WFI, WFE may be branches in etm4.3++ */ + if ((inst & 0xfffffffe) == 0xf3af8002) { + /* WFI & WFE (encoding T2) */ + } + else if ((inst & 0xffef0000) == 0xbf200000) { + /* WFI & WFE (encoding T1) */ + } + else { + is_wfiwfe = 0; + } + return is_wfiwfe; +} int inst_Thumb_is_indirect_branch(uint32_t inst) { + uint8_t link; + return inst_Thumb_is_indirect_branch_link(inst, &link); +} + +int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link) +{ /* See e.g. PFT Table 2-3 and Table 2-5 */ int is_branch = 1; + if ((inst & 0xff000000) == 0x47000000) { - /* BX, BLX (reg) */ + /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */ + if (inst & 0x00800000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + else if ((inst & 0x00780000) == 0x00700000) { + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* BX LR */ + } + } else if ((inst & 0xfff0d000) == 0xf3c08000) { + /* BXJ: in v8 this behaves like BX */ } else if ((inst & 0xff000000) == 0xbd000000) { /* POP {pc} */ + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; } else if ((inst & 0xfd870000) == 0x44870000) { /* MOV PC,reg or ADD PC,reg */ + if ((inst & 0xffff0000) == 0x46f700000) + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC,LR */ } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) { /* TBB/TBH */ } else if ((inst & 0xffd00000) == 0xe8100000) { @@ -166,19 +240,28 @@ int inst_Thumb_is_indirect_branch(uint32_t inst) /* LDR PC,literal (T2) */ } else if ((inst & 0xfff0f800) == 0xf850f800) { /* LDR PC,imm (T4) */ + if((inst & 0x000f0f00) == 0x000d0b00) + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* LDR PC, [SP], #imm*/ } else if ((inst & 0xfff0ffc0) == 0xf850f000) { /* LDR PC,reg (T2) */ } else if ((inst & 0xfe508000) == 0xe8108000) { /* LDM PC */ + if ((inst & 0x0FFF0000) == 0x08BD0000) /* LDMIA [SP]!, */ + instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* POP {...,pc} */ } else { is_branch = 0; } return is_branch; } - int inst_A64_is_direct_branch(uint32_t inst) { + uint8_t link = 0; + return inst_A64_is_direct_branch_link(inst, &link); +} + +int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link) +{ int is_direct_branch = 1; if ((inst & 0x7c000000) == 0x34000000) { /* CB, TB */ @@ -186,31 +269,75 @@ int inst_A64_is_direct_branch(uint32_t inst) /* B<cond> */ } else if ((inst & 0x7c000000) == 0x14000000) { /* B, BL imm */ + if (inst & 0x80000000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } } else { is_direct_branch = 0; } return is_direct_branch; } +int inst_A64_wfiwfe(uint32_t inst) +{ + /* WFI, WFE may be traced as branches in etm 4.3++ */ + if ((inst & 0xffffffdf) == 0xd503205f) + return 1; + return 0; +} int inst_A64_is_indirect_branch(uint32_t inst) { + uint8_t link = 0; + return inst_A64_is_indirect_branch_link(inst, &link); +} + +int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link) +{ int is_indirect_branch = 1; + if ((inst & 0xffdffc1f) == 0xd61f0000) { /* BR, BLR */ + if (inst & 0x00200000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } } else if ((inst & 0xfffffc1f) == 0xd65f0000) { instr_sub_type = OCSD_S_INSTR_V8_RET; /* RET */ } else if ((inst & 0xffffffff) == 0xd69f03e0) { /* ERET */ instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else if (arch_version >= 0x0803) { + /* new pointer auth instr for v8.3 arch */ + if ((inst & 0xffdff800) == 0xd61f0800) { + /* BRAA, BRAB, BLRAA, BLRBB */ + if (inst & 0x00200000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xffdff81F) == 0xd71f081F) { + /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */ + if (inst & 0x00200000) { + *is_link = 1; + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xfffffbff) == 0xd69f0bff) { + /* ERETAA, ERETAB */ + instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else if ((inst & 0xfffffbff) == 0xd65f0bff) { + /* RETAA, RETAB */ + instr_sub_type = OCSD_S_INSTR_V8_RET; + } else { + is_indirect_branch = 0; + } } else { is_indirect_branch = 0; } return is_indirect_branch; } - int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) { uint32_t npc; @@ -235,7 +362,6 @@ int inst_ARM_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) return is_direct_branch; } - int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) { uint32_t npc; @@ -290,7 +416,6 @@ int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) return is_direct_branch; } - int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc) { uint64_t npc; @@ -322,21 +447,18 @@ int inst_ARM_is_branch(uint32_t inst) inst_ARM_is_direct_branch(inst); } - int inst_Thumb_is_branch(uint32_t inst) { return inst_Thumb_is_indirect_branch(inst) || inst_Thumb_is_direct_branch(inst); } - int inst_A64_is_branch(uint32_t inst) { return inst_A64_is_indirect_branch(inst) || inst_A64_is_direct_branch(inst); } - int inst_ARM_is_branch_and_link(uint32_t inst) { int is_branch = 1; @@ -359,7 +481,6 @@ int inst_ARM_is_branch_and_link(uint32_t inst) return is_branch; } - int inst_Thumb_is_branch_and_link(uint32_t inst) { int is_branch = 1; @@ -375,7 +496,6 @@ int inst_Thumb_is_branch_and_link(uint32_t inst) return is_branch; } - int inst_A64_is_branch_and_link(uint32_t inst) { int is_branch = 1; @@ -385,19 +505,28 @@ int inst_A64_is_branch_and_link(uint32_t inst) } else if ((inst & 0xfc000000) == 0x94000000) { /* BL */ instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if (arch_version >= 0x0803) { + /* new pointer auth instr for v8.3 arch */ + if ((inst & 0xfffff800) == 0xd73f0800) { + /* BLRAA, BLRBB */ + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if ((inst & 0xfffff81F) == 0xd63f081F) { + /* BLRAAZ, BLRBBZ */ + instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else { + is_branch = 0; + } } else { is_branch = 0; } return is_branch; } - int inst_ARM_is_conditional(uint32_t inst) { return (inst & 0xe0000000) != 0xe0000000; } - int inst_Thumb_is_conditional(uint32_t inst) { if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { @@ -413,7 +542,6 @@ int inst_Thumb_is_conditional(uint32_t inst) return 0; } - unsigned int inst_Thumb_is_IT(uint32_t inst) { if ((inst & 0xff000000) == 0xbf000000 && @@ -433,7 +561,6 @@ unsigned int inst_Thumb_is_IT(uint32_t inst) } } - /* Test whether an A64 instruction is conditional. @@ -454,7 +581,6 @@ int inst_A64_is_conditional(uint32_t inst) return 0; } - arm_barrier_t inst_ARM_barrier(uint32_t inst) { if ((inst & 0xfff00000) == 0xf5700000) { @@ -484,7 +610,6 @@ arm_barrier_t inst_ARM_barrier(uint32_t inst) } } - arm_barrier_t inst_Thumb_barrier(uint32_t inst) { if ((inst & 0xffffff00) == 0xf3bf8f00) { @@ -516,7 +641,6 @@ arm_barrier_t inst_Thumb_barrier(uint32_t inst) } } - arm_barrier_t inst_A64_barrier(uint32_t inst) { if ((inst & 0xfffff09f) == 0xd503309f) { @@ -535,20 +659,17 @@ arm_barrier_t inst_A64_barrier(uint32_t inst) } } - int inst_ARM_is_UDF(uint32_t inst) { return (inst & 0xfff000f0) == 0xe7f000f0; } - int inst_Thumb_is_UDF(uint32_t inst) { return (inst & 0xff000000) == 0xde000000 || /* T1 */ (inst & 0xfff0f000) == 0xf7f0a000; /* T2 */ } - int inst_A64_is_UDF(uint32_t inst) { /* No A64 encodings are formally allocated as permanently undefined, |
