diff options
author | Ruslan Bukin <br@FreeBSD.org> | 2019-10-10 13:19:21 +0000 |
---|---|---|
committer | Ruslan Bukin <br@FreeBSD.org> | 2019-10-10 13:19:21 +0000 |
commit | cf98ba14dc260458f757fa46419575cf69f45a44 (patch) | |
tree | 1cafc844f372337d2a95c8a416b915d46bf4daf8 /decoder/source/i_dec | |
parent | a6157d81121ac9559d806dafa346039199598442 (diff) |
Notes
Diffstat (limited to 'decoder/source/i_dec')
-rw-r--r-- | decoder/source/i_dec/trc_i_decode.cpp | 63 | ||||
-rw-r--r-- | decoder/source/i_dec/trc_idec_arminst.cpp | 167 |
2 files changed, 194 insertions, 36 deletions
diff --git a/decoder/source/i_dec/trc_i_decode.cpp b/decoder/source/i_dec/trc_i_decode.cpp index 47b4867e6c5c..ab93284848bb 100644 --- a/decoder/source/i_dec/trc_i_decode.cpp +++ b/decoder/source/i_dec/trc_i_decode.cpp @@ -40,6 +40,8 @@ ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info) { ocsd_err_t err = OCSD_OK; clear_instr_subtype(); + SetArchVersion(instr_info); + switch(instr_info->isa) { case ocsd_isa_arm: @@ -65,6 +67,22 @@ ocsd_err_t TrcIDecode::DecodeInstruction(ocsd_instr_info *instr_info) return err; } +void TrcIDecode::SetArchVersion(ocsd_instr_info *instr_info) +{ + uint16_t arch = 0x0700; + + switch (instr_info->pe_type.arch) + { + case ARCH_V8: arch = 0x0800; break; + case ARCH_V8r3: arch = 0x0803; break; + case ARCH_V7: + default: + break; + } + set_arch_version(arch); +} + + ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info) { uint32_t branchAddr = 0; @@ -107,7 +125,13 @@ ocsd_err_t TrcIDecode::DecodeA32(ocsd_instr_info *instr_info) 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; @@ -123,17 +147,17 @@ ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info) instr_info->next_isa = instr_info->isa; // assume same ISA instr_info->is_link = 0; - if(inst_A64_is_indirect_branch(instr_info->opcode)) + if(inst_A64_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link)) { instr_info->type = OCSD_INSTR_BR_INDIRECT; - instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); +// instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); } - else if(inst_A64_is_direct_branch(instr_info->opcode)) + else if(inst_A64_is_direct_branch_link(instr_info->opcode, &instr_info->is_link)) { 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; - instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); +// instr_info->is_link = inst_A64_is_branch_and_link(instr_info->opcode); } else if((barrier = inst_A64_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) { @@ -150,6 +174,13 @@ ocsd_err_t TrcIDecode::DecodeA64(ocsd_instr_info *instr_info) break; } } + else if (instr_info->wfi_wfe_branch) + { + if (inst_A64_wfiwfe(instr_info->opcode)) + { + instr_info->type = OCSD_INSTR_WFI_WFE; + } + } instr_info->is_conditional = inst_A64_is_conditional(instr_info->opcode); @@ -172,20 +203,20 @@ ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info) 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_indirect_branch(instr_info->opcode)) - { - instr_info->type = OCSD_INSTR_BR_INDIRECT; - instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode); - } - else if(inst_Thumb_is_direct_branch(instr_info->opcode)) + + if(inst_Thumb_is_direct_branch_link(instr_info->opcode,&instr_info->is_link, &instr_info->is_conditional)) { 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; - instr_info->is_link = inst_Thumb_is_branch_and_link(instr_info->opcode); + } + else if (inst_Thumb_is_indirect_branch_link(instr_info->opcode, &instr_info->is_link)) + { + instr_info->type = OCSD_INSTR_BR_INDIRECT; } else if((barrier = inst_Thumb_barrier(instr_info->opcode)) != ARM_BARRIER_NONE) { @@ -202,7 +233,13 @@ ocsd_err_t TrcIDecode::DecodeT32(ocsd_instr_info *instr_info) 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); 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, |