aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dis-arm.inc.h3
-rw-r--r--lib/dis-thumb.inc.h14
-rw-r--r--lib/dis-thumb2.inc.h5
-rw-r--r--lib/dis.h4
-rw-r--r--lib/jump-dis.c38
-rw-r--r--lib/transform-dis.inc.h2
-rw-r--r--test/test-td-simple.c1
7 files changed, 47 insertions, 20 deletions
diff --git a/lib/dis-arm.inc.h b/lib/dis-arm.inc.h
index c95e450..0779205 100644
--- a/lib/dis-arm.inc.h
+++ b/lib/dis-arm.inc.h
@@ -193,6 +193,9 @@ static INLINE void P(addr_offset_none_addr_postidx_reg_Rm_unk_Rt_3_LDRHTr)(tdis_
static INLINE void P(GPR_Rt_addr_offset_none_addr_postidx_reg_Rm_S_1_STRHTr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rt, struct bitslice addr) {
data(r(addr), r(Rt), r(Rm));
}
+static INLINE void P(GPR_dst_B_2_BX)(tdis_ctx ctx, UNUSED struct bitslice dst) {
+ return P(ret)(ctx);
+}
static INLINE void P(dis_arm)(tdis_ctx ctx) {
uint32_t op = ctx->op = *(uint32_t *) ctx->ptr;
diff --git a/lib/dis-thumb.inc.h b/lib/dis-thumb.inc.h
index a0434bc..6d9683e 100644
--- a/lib/dis-thumb.inc.h
+++ b/lib/dis-thumb.inc.h
@@ -53,14 +53,26 @@ static INLINE void P(t_bcctarget_target_B_1_tBcc)(tdis_ctx ctx, struct bitslice
return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 8), /*cond*/ true);
}
static INLINE void P(t_brtarget_target_B_1_tB)(tdis_ctx ctx, struct bitslice target) {
- return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 11), /*cond*/ false);
+ bool cond = ctx->arch.thumb_it_length > 0;
+ return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 11), cond);
}
static INLINE void P(t_cbtarget_target_B_2_tCBNZ)(tdis_ctx ctx, struct bitslice target) {
return P(branch)(ctx, ctx->pc + 4 + 2 * bs_get(target, ctx->op), /*cond*/ true);
}
+static INLINE void P(it_pred_cc_it_mask_mask_1_t2IT)(tdis_ctx ctx, struct bitslice mask, UNUSED struct bitslice cc) {
+ /* why */
+ unsigned mask_val = bs_get(mask, ctx->op);
+ unsigned length = __builtin_ctz(mask_val);
+ if (length >= 3)
+ return P(unidentified)(ctx); /* nop */
+ ctx->arch.thumb_it_length = length;
+ return P(unidentified)(ctx);
+}
static INLINE void P(dis_thumb)(tdis_ctx ctx) {
uint16_t op = ctx->op = *(uint16_t *) ctx->ptr;
+ if (ctx->arch.thumb_it_length)
+ ctx->arch.thumb_it_length--;
ctx->op_size = 2;
#include "../generated/generic-dis-thumb.inc.h"
__builtin_abort();
diff --git a/lib/dis-thumb2.inc.h b/lib/dis-thumb2.inc.h
index 36d341e..632e2a2 100644
--- a/lib/dis-thumb2.inc.h
+++ b/lib/dis-thumb2.inc.h
@@ -148,7 +148,8 @@ static INLINE void P(t2ldrlabel_addr_unk_Rt_5_t2LDRBpci)(tdis_ctx ctx, struct bi
return P(pcrel)(ctx, ((ctx->pc + 4) & ~2) + (bs_get(addr, ctx->op) & ((1 << 12) - 1)), bs_get(Rt, ctx->op), get_thumb2_load_mode(ctx->op));
}
static INLINE void P(uncondbrtarget_target_B_1_t2B)(tdis_ctx ctx, struct bitslice target) {
- return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 24), /*cond*/ false);
+ bool cond = ctx->arch.thumb_it_length > 0;
+ return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 24), cond);
}
static INLINE void P(unk_Rd_3_t2MOVTi16)(tdis_ctx ctx, struct bitslice Rd) {
data(rout(Rd));
@@ -163,6 +164,8 @@ static INLINE void P(unk_Rt_13_VMOVRRD)(tdis_ctx ctx, UNUSED struct bitslice Rt)
static INLINE void P(dis_thumb2)(tdis_ctx ctx) {
uint32_t op = ctx->op = *(uint32_t *) ctx->ptr;
+ if (ctx->arch.thumb_it_length)
+ ctx->arch.thumb_it_length--;
ctx->op_size = 4;
#include "../generated/generic-dis-thumb2.inc.h"
__builtin_abort();
diff --git a/lib/dis.h b/lib/dis.h
index 5a49723..37c0889 100644
--- a/lib/dis.h
+++ b/lib/dis.h
@@ -107,14 +107,18 @@ static const unsigned null_op = -0x100;
#if defined(TARGET_x86_64)
#define MIN_INSN_SIZE 1
#error "no x86 dis yet"
+ struct arch_dis_ctx {};
#elif defined(TARGET_i386)
#define MIN_INSN_SIZE 1
#error "no x86 dis yet"
+ struct arch_dis_ctx {};
#elif defined(TARGET_arm)
#define MIN_INSN_SIZE 2
#define TARGET_DIS_HEADER "dis-arm-multi.inc.h"
+ struct arch_dis_ctx { unsigned thumb_it_length; };
#elif defined(TARGET_arm64)
#define MIN_INSN_SIZE 4
#define TARGET_DIS_HEADER "dis-arm64.inc.h"
+ struct arch_dis_ctx {};
#endif
diff --git a/lib/jump-dis.c b/lib/jump-dis.c
index aa3b5f3..b6ddd13 100644
--- a/lib/jump-dis.c
+++ b/lib/jump-dis.c
@@ -18,24 +18,26 @@ enum {
};
struct jump_dis_ctx {
- /* outputs */
- bool bad_insn;
- bool continue_after_this_insn;
-
- uintptr_t pc;
- uintptr_t pc_patch_start;
- uintptr_t pc_patch_end;
- bool pc_low_bit;
- unsigned op;
- const void *ptr;
- int op_size;
- uint8_t seen_mask[JUMP_ANALYSIS_MAX_INSNS / 8];
- /* queue of instructions to visit */
- uintptr_t *queue;
- size_t queue_write_off;
- size_t queue_read_off;
- size_t queue_size;
- size_t queue_count;
+ /* outputs */
+ bool bad_insn;
+ bool continue_after_this_insn;
+
+ uintptr_t pc;
+ uintptr_t pc_patch_start;
+ uintptr_t pc_patch_end;
+ bool pc_low_bit;
+ unsigned op;
+ const void *ptr;
+ int op_size;
+ uint8_t seen_mask[JUMP_ANALYSIS_MAX_INSNS / 8];
+ /* queue of instructions to visit */
+ uintptr_t *queue;
+ size_t queue_write_off;
+ size_t queue_read_off;
+ size_t queue_size;
+ size_t queue_count;
+
+ struct arch_dis_ctx arch;
};
#undef P
diff --git a/lib/transform-dis.inc.h b/lib/transform-dis.inc.h
index b20012a..04cd7f2 100644
--- a/lib/transform-dis.inc.h
+++ b/lib/transform-dis.inc.h
@@ -22,6 +22,8 @@ struct transform_dis_ctx {
const void *ptr;
void **rewritten_ptr_ptr;
void *write_newop_here;
+
+ struct arch_dis_ctx arch;
};
#define tdis_ctx struct transform_dis_ctx *
diff --git a/test/test-td-simple.c b/test/test-td-simple.c
index e1524f5..4464091 100644
--- a/test/test-td-simple.c
+++ b/test/test-td-simple.c
@@ -12,6 +12,7 @@ typedef struct tc {
uint32_t newval[4];
bool modify;
int op_size;
+ struct arch_dis_ctx arch;
} *tdis_ctx;
#define P(x) P_##x
#define TDIS_CTX_MODIFY(ctx) ((ctx)->modify)