summaryrefslogtreecommitdiff
path: root/decoder/source/i_dec
diff options
context:
space:
mode:
authorRuslan Bukin <br@FreeBSD.org>2019-10-10 13:19:21 +0000
committerRuslan Bukin <br@FreeBSD.org>2019-10-10 13:19:21 +0000
commitcf98ba14dc260458f757fa46419575cf69f45a44 (patch)
tree1cafc844f372337d2a95c8a416b915d46bf4daf8 /decoder/source/i_dec
parenta6157d81121ac9559d806dafa346039199598442 (diff)
Notes
Diffstat (limited to 'decoder/source/i_dec')
-rw-r--r--decoder/source/i_dec/trc_i_decode.cpp63
-rw-r--r--decoder/source/i_dec/trc_idec_arminst.cpp167
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,