diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:24:57 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 07:24:57 +0000 |
commit | 070852d8604cece0c31f28ff3eb8d21d9ba415fb (patch) | |
tree | 9097175a6a5b8b7e37af9a96269ac0b61a0189cd /decoder/source/i_dec | |
parent | Initial commit. (diff) | |
download | libopencsd-070852d8604cece0c31f28ff3eb8d21d9ba415fb.tar.xz libopencsd-070852d8604cece0c31f28ff3eb8d21d9ba415fb.zip |
Adding upstream version 1.3.3.upstream/1.3.3upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'decoder/source/i_dec')
-rw-r--r-- | decoder/source/i_dec/trc_i_decode.cpp | 236 | ||||
-rw-r--r-- | decoder/source/i_dec/trc_idec_arminst.cpp | 679 |
2 files changed, 915 insertions, 0 deletions
diff --git a/decoder/source/i_dec/trc_i_decode.cpp b/decoder/source/i_dec/trc_i_decode.cpp new file mode 100644 index 0000000..0e05895 --- /dev/null +++ b/decoder/source/i_dec/trc_i_decode.cpp @@ -0,0 +1,236 @@ +/* + * \file trc_i_decode.cpp + * \brief OpenCSD : + * + * \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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "opencsd/ocsd_if_types.h" +#include "i_dec/trc_i_decode.h" +#include "i_dec/trc_idec_arminst.h" + +ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info) +{ + ocsd_err_t err = OCSD_OK; + struct decode_info info; + + info.instr_sub_type = OCSD_S_INSTR_NONE; + info.arch_version = instr_info->pe_type.arch; + + switch(instr_info->isa) + { + case ocsd_isa_arm: + err = DecodeA32(instr_info, &info); + break; + + case ocsd_isa_thumb2: + err = DecodeT32(instr_info, &info); + break; + + case ocsd_isa_aarch64: + err = DecodeA64(instr_info, &info); + break; + + case ocsd_isa_tee: + case ocsd_isa_jazelle: + default: + // unsupported ISA + err = OCSD_ERR_UNSUPPORTED_ISA; + break; + } + instr_info->sub_type = info.instr_sub_type; + return err; +} + +ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info, struct decode_info *info) +{ + uint32_t branchAddr = 0; + arm_barrier_t barrier; + + instr_info->instr_size = 4; // instruction size A32 + instr_info->type = OCSD_INSTR_OTHER; // default type + instr_info->next_isa = instr_info->isa; // assume same ISA + instr_info->is_link = 0; + + if(inst_ARM_is_indirect_branch(instr_info->opcode, info)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; + instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info); + } + else if(inst_ARM_is_direct_branch(instr_info->opcode)) + { + inst_ARM_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr); + instr_info->type = OCSD_INSTR_BR; + if (branchAddr & 0x1) + { + instr_info->next_isa = ocsd_isa_thumb2; + branchAddr &= ~0x1; + } + instr_info->branch_addr = (ocsd_vaddr_t)branchAddr; + instr_info->is_link = inst_ARM_is_branch_and_link(instr_info->opcode, info); + } + else if((barrier = inst_ARM_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) + { + switch(barrier) + { + case ARM_BARRIER_ISB: + instr_info->type = OCSD_INSTR_ISB; + break; + + case ARM_BARRIER_DSB: + case ARM_BARRIER_DMB: + if(instr_info->dsb_dmb_waypoints) + instr_info->type = OCSD_INSTR_DSB_DMB; + break; + } + } + else if (instr_info->wfi_wfe_branch) + { + if (inst_ARM_wfiwfe(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_WFI_WFE; + } + } + instr_info->is_conditional = inst_ARM_is_conditional(instr_info->opcode); + + return OCSD_OK; +} + +ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info, struct decode_info *info) +{ + uint64_t branchAddr = 0; + arm_barrier_t barrier; + + instr_info->instr_size = 4; // default address update + instr_info->type = OCSD_INSTR_OTHER; // default type + instr_info->next_isa = instr_info->isa; // assume same ISA + instr_info->is_link = 0; + + if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; + } + else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link, info)) + { + inst_A64_branch_destination(instr_info->instr_addr,instr_info->opcode,&branchAddr); + instr_info->type = OCSD_INSTR_BR; + instr_info->branch_addr = (ocsd_vaddr_t)branchAddr; + } + else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) + { + switch(barrier) + { + case ARM_BARRIER_ISB: + instr_info->type = OCSD_INSTR_ISB; + break; + + case ARM_BARRIER_DSB: + case ARM_BARRIER_DMB: + if(instr_info->dsb_dmb_waypoints) + instr_info->type = OCSD_INSTR_DSB_DMB; + break; + } + } + else if (instr_info->wfi_wfe_branch && + inst_A64_wfiwfe(instr_info->opcode, info)) + { + instr_info->type = OCSD_INSTR_WFI_WFE; + } + else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64)) + { + if (inst_A64_Tstart(instr_info->opcode)) + instr_info->type = OCSD_INSTR_TSTART; + } + + instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode); + + return OCSD_OK; +} + +ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info, struct decode_info *info) +{ + uint32_t branchAddr = 0; + arm_barrier_t barrier; + + // need to align the 32 bit opcode as 2 16 bit, with LS 16 as in top 16 bit of + // 32 bit word - T2 routines assume 16 bit in top 16 bit of 32 bit opcode. + uint32_t op_temp = (instr_info->opcode >> 16) & 0xFFFF; + op_temp |= ((instr_info->opcode & 0xFFFF) << 16); + instr_info->opcode = op_temp; + + + instr_info->instr_size = is_wide_thumb((uint16_t)(instr_info->opcode >> 16)) ? 4 : 2; + instr_info->type = OCSD_INSTR_OTHER; // default type + instr_info->next_isa = instr_info->isa; // assume same ISA + instr_info->is_link = 0; + instr_info->is_conditional = 0; + + + if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional, info)) + { + inst_Thumb_branch_destination((uint32_t)instr_info->instr_addr,instr_info->opcode,&branchAddr); + instr_info->type = OCSD_INSTR_BR; + instr_info->branch_addr = (ocsd_vaddr_t)(branchAddr & ~0x1); + if((branchAddr & 0x1) == 0) + instr_info->next_isa = ocsd_isa_arm; + } + else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link, info)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; + } + else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) + { + switch(barrier) + { + case ARM_BARRIER_ISB: + instr_info->type = OCSD_INSTR_ISB; + break; + + case ARM_BARRIER_DSB: + case ARM_BARRIER_DMB: + if(instr_info->dsb_dmb_waypoints) + instr_info->type = OCSD_INSTR_DSB_DMB; + break; + } + } + else if (instr_info->wfi_wfe_branch) + { + if (inst_Thumb_wfiwfe(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_WFI_WFE; + } + } + instr_info->is_conditional = inst_Thumb_is_conditional(instr_info->opcode); + instr_info->thumb_it_conditions = inst_Thumb_is_IT(instr_info->opcode); + + return OCSD_OK; +} + +/* End of File trc_i_decode.cpp */ diff --git a/decoder/source/i_dec/trc_idec_arminst.cpp b/decoder/source/i_dec/trc_idec_arminst.cpp new file mode 100644 index 0000000..76951fd --- /dev/null +++ b/decoder/source/i_dec/trc_idec_arminst.cpp @@ -0,0 +1,679 @@ +/* + * \file trc_idec_arminst.cpp + * \brief OpenCSD : + * + * \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: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* +Basic ARM/Thumb/A64 instruction decode, suitable for e.g. basic +block identification and trace decode. +*/ + +#include "i_dec/trc_idec_arminst.h" + +#include <stddef.h> /* for NULL */ +#include <assert.h> + +int inst_ARM_is_direct_branch(uint32_t inst) +{ + int is_direct_branch = 1; + if ((inst & 0xf0000000) == 0xf0000000) { + /* NV space */ + if ((inst & 0xfe000000) == 0xfa000000){ + /* BLX (imm) */ + } else { + is_direct_branch = 0; + } + } else if ((inst & 0x0e000000) == 0x0a000000) { + /* B, BL */ + } else { + is_direct_branch = 0; + } + 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, struct decode_info *info) +{ + int is_indirect_branch = 1; + if ((inst & 0xf0000000) == 0xf0000000) { + /* NV space */ + if ((inst & 0xfe500000) == 0xf8100000) { + /* RFE */ + } else { + is_indirect_branch = 0; + } + } else if ((inst & 0x0ff000d0) == 0x01200010) { + /* BLX (register), BX */ + if ((inst & 0xFF) == 0x1E) + info->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} */ + info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; + } else if ((inst & 0x0e50f000) == 0x0410f000) { + /* LDR PC,imm... inc. POP {PC} */ + if ( (inst & 0x01ff0000) == 0x009D0000) + info->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 */ + info->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; + } else if ((inst & 0x0f9000f0) == 0x01800090) { + /* Some extended loads and stores */ + is_indirect_branch = 0; + } else if ((inst & 0x0fb0f000) == 0x0320f000) { + /* MSR #imm */ + is_indirect_branch = 0; + } else if ((inst & 0x0e00f000) == 0x0200f000) { + /* DP PC,imm shift */ + if ((inst & 0x0f90f000) == 0x0310f000) { + /* TST/CMP */ + is_indirect_branch = 0; + } + } else if ((inst & 0x0e00f000) == 0x0000f000) { + /* DP PC,reg */ + } else { + is_indirect_branch = 0; + } + return is_indirect_branch; +} + +int inst_Thumb_is_direct_branch(uint32_t inst, struct decode_info *info) +{ + uint8_t link, cond; + return inst_Thumb_is_direct_branch_link(inst, &link, &cond, info); +} + +int inst_Thumb_is_direct_branch_link(uint32_t inst, uint8_t *is_link, uint8_t *is_cond, struct decode_info *info) +{ + 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; + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xf800d001) == 0xf000c000) { + /* BLX (imm) (encoding T2) */ + *is_link = 1; + info->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, struct decode_info *info) +{ + uint8_t link; + return inst_Thumb_is_indirect_branch_link(inst, &link, info); +} + +int inst_Thumb_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info) +{ + /* See e.g. PFT Table 2-3 and Table 2-5 */ + int is_branch = 1; + + if ((inst & 0xff000000) == 0x47000000) { + /* BX, BLX (reg) [v8M includes BXNS, BLXNS] */ + if (inst & 0x00800000) { + *is_link = 1; + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + else if ((inst & 0x00780000) == 0x00700000) { + info->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} */ + info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; + } else if ((inst & 0xfd870000) == 0x44870000) { + /* MOV PC,reg or ADD PC,reg */ + if ((inst & 0xffff0000) == 0x46f70000) + info->instr_sub_type = OCSD_S_INSTR_V7_IMPLIED_RET; /* MOV PC,LR */ + } else if ((inst & 0xfff0ffe0) == 0xe8d0f000) { + /* TBB/TBH */ + } else if ((inst & 0xffd00000) == 0xe8100000) { + /* RFE (T1) */ + } else if ((inst & 0xffd00000) == 0xe9900000) { + /* RFE (T2) */ + } else if ((inst & 0xfff0d000) == 0xf3d08000) { + /* SUBS PC,LR,#imm inc.ERET */ + } else if ((inst & 0xfff0f000) == 0xf8d0f000) { + /* LDR PC,imm (T3) */ + } else if ((inst & 0xff7ff000) == 0xf85ff000) { + /* LDR PC,literal (T2) */ + } else if ((inst & 0xfff0f800) == 0xf850f800) { + /* LDR PC,imm (T4) */ + if((inst & 0x000f0f00) == 0x000d0b00) + info->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]!, */ + info->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, struct decode_info *info) +{ + uint8_t link = 0; + return inst_A64_is_direct_branch_link(inst, &link, info); +} + +int inst_A64_is_direct_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info) +{ + int is_direct_branch = 1; + if ((inst & 0x7c000000) == 0x34000000) { + /* CB, TB */ + } else if ((inst & 0xff000000) == 0x54000000) { + /* B<cond> */ + /* BC<cond> 8.8 / 9.3 arch - bit 4 = 1'b1 */ + } else if ((inst & 0x7c000000) == 0x14000000) { + /* B, BL imm */ + if (inst & 0x80000000) { + *is_link = 1; + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else { + is_direct_branch = 0; + } + return is_direct_branch; +} + +int inst_A64_wfiwfe(uint32_t inst, struct decode_info *info) +{ + /* WFI, WFE may be traced as branches in etm 4.3++ */ + if ((inst & 0xffffffdf) == 0xd503205f) + return 1; + + /* new feature introduced post v8.3 */ + if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_AA64)) + { + /* WFIT / WFET for later archs */ + if ((inst & 0xffffffc0) == 0xd5031000) + return 1; + } + return 0; +} + +int inst_A64_Tstart(uint32_t inst) +{ + if ((inst & 0xffffffe0) == 0xd5233060) + return 1; + return 0; +} + +int inst_A64_is_indirect_branch(uint32_t inst, struct decode_info *info) +{ + uint8_t link = 0; + return inst_A64_is_indirect_branch_link(inst, &link, info); +} + +int inst_A64_is_indirect_branch_link(uint32_t inst, uint8_t *is_link, struct decode_info *info) +{ + int is_indirect_branch = 1; + + if ((inst & 0xffdffc1f) == 0xd61f0000) { + /* BR, BLR */ + if (inst & 0x00200000) { + *is_link = 1; + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xfffffc1f) == 0xd65f0000) { + info->instr_sub_type = OCSD_S_INSTR_V8_RET; + /* RET */ + } else if ((inst & 0xffffffff) == 0xd69f03e0) { + /* ERET */ + info->instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) { + /* new pointer auth instr for v8.3 arch */ + if ((inst & 0xffdff800) == 0xd71f0800) { + /* BRAA, BRAB, BLRAA, BLRBB */ + if (inst & 0x00200000) { + *is_link = 1; + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xffdff81F) == 0xd61f081F) { + /* BRAAZ, BRABZ, BLRAAZ, BLRBBZ */ + if (inst & 0x00200000) { + *is_link = 1; + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } + } else if ((inst & 0xfffffbff) == 0xd69f0bff) { + /* ERETAA, ERETAB */ + info->instr_sub_type = OCSD_S_INSTR_V8_ERET; + } else if ((inst & 0xfffffbff) == 0xd65f0bff) { + /* RETAA, RETAB */ + info->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; + int is_direct_branch = 1; + if ((inst & 0x0e000000) == 0x0a000000) { + /* + B: cccc:1010:imm24 + BL: cccc:1011:imm24 + BLX: 1111:101H:imm24 + */ + npc = addr + 8 + ((int32_t)((inst & 0xffffff) << 8) >> 6); + if ((inst & 0xf0000000) == 0xf0000000) { + npc |= 1; /* indicate ISA is now Thumb */ + npc |= ((inst >> 23) & 2); /* apply the H bit */ + } + } else { + is_direct_branch = 0; + } + if (is_direct_branch && pnpc != NULL) { + *pnpc = npc; + } + return is_direct_branch; +} + +int inst_Thumb_branch_destination(uint32_t addr, uint32_t inst, uint32_t *pnpc) +{ + uint32_t npc; + int is_direct_branch = 1; + if ((inst & 0xf0000000) == 0xd0000000 && (inst & 0x0e000000) != 0x0e000000) { + /* B<c> (encoding T1) */ + npc = addr + 4 + ((int32_t)((inst & 0x00ff0000) << 8) >> 23); + npc |= 1; + } else if ((inst & 0xf8000000) == 0xe0000000) { + /* B (encoding T2) */ + npc = addr + 4 + ((int32_t)((inst & 0x07ff0000) << 5) >> 20); + npc |= 1; + } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { + /* B (encoding T3) */ + npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) | + ((inst & 0x0800) << 19) | + ((inst & 0x2000) << 16) | + ((inst & 0x003f0000) << 7) | + ((inst & 0x000007ff) << 12)) >> 11); + npc |= 1; + } else if ((inst & 0xf8009000) == 0xf0009000) { + /* B (encoding T4); BL (encoding T1) */ + uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */ + npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) | + (((inst^S) & 0x2000) << 17) | + (((inst^S) & 0x0800) << 18) | + ((inst & 0x03ff0000) << 3) | + ((inst & 0x000007ff) << 8)) >> 7); + npc |= 1; + } else if ((inst & 0xf800d001) == 0xf000c000) { + /* BLX (encoding T2) */ + uint32_t S = ((inst & 0x04000000) >> 26)-1; /* ffffffff or 0 according to S bit */ + addr &= 0xfffffffc; /* Align(PC,4) */ + npc = addr + 4 + ((int32_t)(((inst & 0x04000000) << 5) | + (((inst^S) & 0x2000) << 17) | + (((inst^S) & 0x0800) << 18) | + ((inst & 0x03ff0000) << 3) | + ((inst & 0x000007fe) << 8)) >> 7); + /* don't set the Thumb bit, as we're transferring to ARM */ + } else if ((inst & 0xf5000000) == 0xb1000000) { + /* CB(NZ) */ + /* Note that it's zero-extended - always a forward branch */ + npc = addr + 4 + ((((inst & 0x02000000) << 6) | + ((inst & 0x00f80000) << 7)) >> 25); + npc |= 1; + } else { + is_direct_branch = 0; + } + if (is_direct_branch && pnpc != NULL) { + *pnpc = npc; + } + return is_direct_branch; +} + +int inst_A64_branch_destination(uint64_t addr, uint32_t inst, uint64_t *pnpc) +{ + uint64_t npc; + int is_direct_branch = 1; + if ((inst & 0xff000000) == 0x54000000) { + /* B<cond> */ + /* BC<cond> */ + npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); + } else if ((inst & 0x7c000000) == 0x14000000) { + /* B, BL imm */ + npc = addr + ((int32_t)((inst & 0x03ffffff) << 6) >> 4); + } else if ((inst & 0x7e000000) == 0x34000000) { + /* CB */ + npc = addr + ((int32_t)((inst & 0x00ffffe0) << 8) >> 11); + } else if ((inst & 0x7e000000) == 0x36000000) { + /* TB */ + npc = addr + ((int32_t)((inst & 0x0007ffe0) << 13) >> 16); + } else { + is_direct_branch = 0; + } + if (is_direct_branch && pnpc != NULL) { + *pnpc = npc; + } + return is_direct_branch; +} + +int inst_ARM_is_branch(uint32_t inst, struct decode_info *info) +{ + return inst_ARM_is_indirect_branch(inst, info) || + inst_ARM_is_direct_branch(inst); +} + +int inst_Thumb_is_branch(uint32_t inst, struct decode_info *info) +{ + return inst_Thumb_is_indirect_branch(inst, info) || + inst_Thumb_is_direct_branch(inst, info); +} + +int inst_A64_is_branch(uint32_t inst, struct decode_info *info) +{ + return inst_A64_is_indirect_branch(inst, info) || + inst_A64_is_direct_branch(inst, info); +} + +int inst_ARM_is_branch_and_link(uint32_t inst, struct decode_info *info) +{ + int is_branch = 1; + if ((inst & 0xf0000000) == 0xf0000000) { + if ((inst & 0xfe000000) == 0xfa000000){ + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BLX (imm) */ + } else { + is_branch = 0; + } + } else if ((inst & 0x0f000000) == 0x0b000000) { + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BL */ + } else if ((inst & 0x0ff000f0) == 0x01200030) { + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BLX (reg) */ + } else { + is_branch = 0; + } + return is_branch; +} + +int inst_Thumb_is_branch_and_link(uint32_t inst, struct decode_info *info) +{ + int is_branch = 1; + if ((inst & 0xff800000) == 0x47800000) { + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BLX (reg) */ + } else if ((inst & 0xf800c000) == 0xf000c000) { + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + /* BL, BLX (imm) */ + } else { + is_branch = 0; + } + return is_branch; +} + +int inst_A64_is_branch_and_link(uint32_t inst, struct decode_info *info) +{ + int is_branch = 1; + if ((inst & 0xfffffc1f) == 0xd63f0000) { + /* BLR */ + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if ((inst & 0xfc000000) == 0x94000000) { + /* BL */ + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if (OCSD_IS_ARCH_MINVER(info->arch_version, ARCH_V8r3)) { + /* new pointer auth instr for v8.3 arch */ + if ((inst & 0xfffff800) == 0xd73f0800) { + /* BLRAA, BLRBB */ + info->instr_sub_type = OCSD_S_INSTR_BR_LINK; + } else if ((inst & 0xfffff81F) == 0xd63f081F) { + /* BLRAAZ, BLRBBZ */ + info->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) { + /* B<c> (encoding T1) */ + return 1; + } else if ((inst & 0xf800d000) == 0xf0008000 && (inst & 0x03800000) != 0x03800000) { + /* B<c> (encoding T3) */ + return 1; + } else if ((inst & 0xf5000000) == 0xb1000000) { + /* CB(N)Z */ + return 1; + } + return 0; +} + +unsigned int inst_Thumb_is_IT(uint32_t inst) +{ + if ((inst & 0xff000000) == 0xbf000000 && + (inst & 0x000f0000) != 0x00000000) { + if (inst & 0x00010000) { + return 4; + } else if (inst & 0x00020000) { + return 3; + } else if (inst & 0x00040000) { + return 2; + } else { + assert(inst & 0x00080000); + return 1; + } + } else { + return 0; + } +} + +/* +Test whether an A64 instruction is conditional. + +Instructions like CSEL, CSINV, CCMP are not classed as conditional. +They use the condition code but do one of two things with it, +neither a NOP. The "intruction categories" section of ETMv4 +lists no (non branch) conditional instructions for A64. +*/ +int inst_A64_is_conditional(uint32_t inst) +{ + if ((inst & 0x7c000000) == 0x34000000) { + /* CB, TB */ + return 1; + } else if ((inst & 0xff000000) == 0x54000000) { + /* B.cond */ + /* BC.cond */ + return 1; + } + return 0; +} + +arm_barrier_t inst_ARM_barrier(uint32_t inst) +{ + if ((inst & 0xfff00000) == 0xf5700000) { + switch (inst & 0xf0) { + case 0x40: + return ARM_BARRIER_DSB; + case 0x50: + return ARM_BARRIER_DMB; + case 0x60: + return ARM_BARRIER_ISB; + default: + return ARM_BARRIER_NONE; + } + } else if ((inst & 0x0fff0f00) == 0x0e070f00) { + switch (inst & 0xff) { + case 0x9a: + return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */ + case 0xba: + return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */ + case 0x95: + return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */ + default: + return ARM_BARRIER_NONE; + } + } else { + return ARM_BARRIER_NONE; + } +} + +arm_barrier_t inst_Thumb_barrier(uint32_t inst) +{ + if ((inst & 0xffffff00) == 0xf3bf8f00) { + switch (inst & 0xf0) { + case 0x40: + return ARM_BARRIER_DSB; + case 0x50: + return ARM_BARRIER_DMB; + case 0x60: + return ARM_BARRIER_ISB; + default: + return ARM_BARRIER_NONE; + } + } else if ((inst & 0xffff0f00) == 0xee070f00) { + /* Thumb2 CP15 barriers are unlikely... 1156T2 only? */ + switch (inst & 0xff) { + case 0x9a: + return ARM_BARRIER_DSB; /* mcr p15,0,Rt,c7,c10,4 */ + case 0xba: + return ARM_BARRIER_DMB; /* mcr p15,0,Rt,c7,c10,5 */ + case 0x95: + return ARM_BARRIER_ISB; /* mcr p15,0,Rt,c7,c5,4 */ + default: + return ARM_BARRIER_NONE; + } + return ARM_BARRIER_NONE; + } else { + return ARM_BARRIER_NONE; + } +} + +arm_barrier_t inst_A64_barrier(uint32_t inst) +{ + if ((inst & 0xfffff09f) == 0xd503309f) { + switch (inst & 0x60) { + case 0x0: + return ARM_BARRIER_DSB; + case 0x20: + return ARM_BARRIER_DMB; + case 0x40: + return ARM_BARRIER_ISB; + default: + return ARM_BARRIER_NONE; + } + } else { + return ARM_BARRIER_NONE; + } +} + +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, + but it is intended not to allocate any instructions in the 21-bit + regions at the bottom or top of the range. */ + return (inst & 0xffe00000) == 0x00000000 || + (inst & 0xffe00000) == 0xffe00000; +} + +/* End of File trc_idec_arminst.cpp */ |