diff options
author | comex | 2015-01-16 03:24:12 -0500 |
---|---|---|
committer | comex | 2015-01-16 04:22:55 -0500 |
commit | 8fb40a9c236e58b002e447b1c8ac124732a9dd8a (patch) | |
tree | f5f32cca52ac85eecc950e573640457696616712 /lib | |
parent | add a test assembly file, not used yet (diff) | |
download | substitute-8fb40a9c236e58b002e447b1c8ac124732a9dd8a.tar.gz |
jump dis - seemingly working(!)
Diffstat (limited to 'lib')
-rw-r--r-- | lib/dis-arm-multi.inc.h | 16 | ||||
-rw-r--r-- | lib/dis-arm.inc.h | 113 | ||||
-rw-r--r-- | lib/dis-arm64.inc.h | 33 | ||||
-rw-r--r-- | lib/dis-thumb.inc.h | 46 | ||||
-rw-r--r-- | lib/dis-thumb2.inc.h | 109 | ||||
-rw-r--r-- | lib/dis.h | 33 | ||||
-rw-r--r-- | lib/jump-dis-arm-multi.c | 6 | ||||
-rw-r--r-- | lib/jump-dis.inc.h | 145 | ||||
-rw-r--r-- | lib/transform-dis.inc.h | 43 |
9 files changed, 375 insertions, 169 deletions
diff --git a/lib/dis-arm-multi.inc.h b/lib/dis-arm-multi.inc.h new file mode 100644 index 0000000..56cde35 --- /dev/null +++ b/lib/dis-arm-multi.inc.h @@ -0,0 +1,16 @@ +#include "dis-thumb.inc.h" +#include "dis-thumb2.inc.h" +#include "dis-arm.inc.h" + +static INLINE void P(dis)(tdis_ctx ctx) { + if (ctx->pc_low_bit) { + uint16_t op = *(uint16_t *) ctx->ptr; + bool is_32 = (op >> 13 & 7) == 7 && (op >> 11 & 3) != 0; + if (is_32) + return P(dis_thumb2)(ctx); + else + return P(dis_thumb)(ctx); + } else { + return P(dis_arm)(ctx); + } +} diff --git a/lib/dis-arm.inc.h b/lib/dis-arm.inc.h index 68f5015..4d5f134 100644 --- a/lib/dis-arm.inc.h +++ b/lib/dis-arm.inc.h @@ -19,7 +19,7 @@ LDR: 11111 00 0 U 10 1 1111 */ -static inline enum pcrel_load_mode get_load_mode(unsigned op) { +static inline enum pcrel_load_mode get_arm_load_mode(unsigned op) { if ((op & 0x7000090) == 0x90) { return ((op >> 22) & 1) ? PLM_U8 : PLM_U32; } else { @@ -32,163 +32,170 @@ static inline enum pcrel_load_mode get_load_mode(unsigned op) { } } -static INLINE tdis_ret P(GPRPairOp_Rt_addr_offset_none_addr_unk_Rd_S_2_STLEXD)(tdis_ctx ctx, struct bitslice Rt, struct bitslice Rd, struct bitslice addr) { +static INLINE void P(GPRPairOp_Rt_addr_offset_none_addr_unk_Rd_S_2_STLEXD)(tdis_ctx ctx, struct bitslice Rt, struct bitslice Rd, struct bitslice addr) { data(r(Rt), r(Rd), r(addr)); } -static INLINE tdis_ret P(GPR_Rm_unk_Rd_1_MOVr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd) { +static INLINE void P(GPR_Rm_unk_Rd_1_MOVr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd) { data(rout(Rd), r(Rm)); } -static INLINE tdis_ret P(GPR_Rn_GPR_Rm_unk_Rd_1_ADDrr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPR_Rn_GPR_Rm_unk_Rd_1_ADDrr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd, struct bitslice Rn) { data(rout(Rd), r(Rm), r(Rn)); } -static INLINE tdis_ret P(GPR_Rn_so_reg_imm_shift_unk_Rd_1_ADDrsi)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPR_Rn_so_reg_imm_shift_unk_Rd_1_ADDrsi)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rd, struct bitslice Rn) { data(rs(shift, 0, 4), r(Rn), rout(Rd)); } -static INLINE tdis_ret P(GPR_Rn_so_reg_reg_shift_unk_Rd_1_ADDrsr)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPR_Rn_so_reg_reg_shift_unk_Rd_1_ADDrsr)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rd, struct bitslice Rn) { data(rs(shift, 0, 4), rs(shift, 8, 4), r(Rn), rout(Rd)); } -static INLINE tdis_ret P(GPR_Rn_unk_Rd_1_ADDri)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPR_Rn_unk_Rd_1_ADDri)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rn) { data(rout(Rd), r(Rn)); } -static INLINE tdis_ret P(GPR_Rt_4_MCR)(tdis_ctx ctx, struct bitslice Rt) { +static INLINE void P(GPR_Rt_4_MCR)(tdis_ctx ctx, struct bitslice Rt) { data(r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addr_offset_none_addr_S_3_STL)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(GPR_Rt_addr_offset_none_addr_S_3_STL)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { data(r(addr), rout(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addr_offset_none_addr_am2offset_imm_offset_S_4_STRBT_POST_IMM)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(GPR_Rt_addr_offset_none_addr_am2offset_imm_offset_S_4_STRBT_POST_IMM)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addr_offset_none_addr_am2offset_reg_offset_S_4_STRBT_POST_REG)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(GPR_Rt_addr_offset_none_addr_am2offset_reg_offset_S_4_STRBT_POST_REG)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), rs(offset, 0, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addr_offset_none_addr_am3offset_offset_S_2_STRD_POST)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(GPR_Rt_addr_offset_none_addr_am3offset_offset_S_2_STRD_POST)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), rs(offset, 0, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addr_offset_none_addr_postidx_imm8_offset_S_1_STRHTi)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(GPR_Rt_addr_offset_none_addr_postidx_imm8_offset_S_1_STRHTi)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addrmode3_addr_S_2_STRD)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_addrmode3_addr_S_2_STRD)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 9, 4), rs(addr, 0, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addrmode3_pre_addr_S_2_STRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_addrmode3_pre_addr_S_2_STRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 9, 4), rs(addr, 0, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addrmode_imm12_addr_S_1_STRi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_addrmode_imm12_addr_S_1_STRi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_addrmode_imm12_pre_addr_S_2_STRB_PRE_IMM)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_addrmode_imm12_pre_addr_S_2_STRB_PRE_IMM)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_ldst_so_reg_addr_S_2_STRB_PRE_REG)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_ldst_so_reg_addr_S_2_STRB_PRE_REG)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 0, 4), rs(addr, 13, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_ldst_so_reg_shift_S_1_STRrs)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rt) { +static INLINE void P(GPR_Rt_ldst_so_reg_shift_S_1_STRrs)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rt) { data(rs(shift, 0, 4), rs(shift, 13, 4), r(Rt)); } -static INLINE tdis_ret P(GPRnopc_Rt_4_MCRR)(tdis_ctx ctx, UNUSED struct bitslice Rt) { +static INLINE void P(GPRnopc_Rt_4_MCRR)(tdis_ctx ctx, UNUSED struct bitslice Rt) { /* need Rt2 but whatever */ return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPRnopc_Rt_addrmode_imm12_addr_S_1_STRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPRnopc_Rt_addrmode_imm12_addr_S_1_STRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), r(Rt)); } -static INLINE tdis_ret P(GPRnopc_Rt_ldst_so_reg_shift_S_1_STRBrs)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rt) { +static INLINE void P(GPRnopc_Rt_ldst_so_reg_shift_S_1_STRBrs)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rt) { data(rs(shift, 13, 4), rs(shift, 0, 4), r(Rt)); } -static INLINE tdis_ret P(addr_offset_none_addr_4_LDC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_4_LDC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_S_4_STC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_S_4_STC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_am2offset_imm_offset_unk_Rt_4_LDRBT_POST_IMM)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_am2offset_imm_offset_unk_Rt_4_LDRBT_POST_IMM)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), rout(Rt)); } -static INLINE tdis_ret P(addr_offset_none_addr_am2offset_reg_offset_unk_Rt_4_LDRBT_POST_REG)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_am2offset_reg_offset_unk_Rt_4_LDRBT_POST_REG)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), rs(offset, 0, 4), rout(Rt)); } -static INLINE tdis_ret P(addr_offset_none_addr_am3offset_offset_unk_Rt_4_LDRD_POST)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_am3offset_offset_unk_Rt_4_LDRD_POST)(tdis_ctx ctx, struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), rs(offset, 0, 4), rout(Rt)); } -static INLINE tdis_ret P(addr_offset_none_addr_postidx_imm8_offset_unk_Rt_3_LDRHTi)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_postidx_imm8_offset_unk_Rt_3_LDRHTi)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice addr) { data(r(addr), rout(Rt)); } -static INLINE tdis_ret P(addr_offset_none_addr_postidx_imm8s4_offset_4_LDC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_postidx_imm8s4_offset_4_LDC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_postidx_imm8s4_offset_S_4_STC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_postidx_imm8s4_offset_S_4_STC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_unk_Rt_13_LDA)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_unk_Rt_13_LDA)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { data(r(addr), rout(Rt)); } -static INLINE tdis_ret P(addrmode3_addr_unk_Rt_4_LDRD)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { +static INLINE void P(addrmode3_addr_unk_Rt_4_LDRD)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { /* ignoring Rt2 = Rt + 1, but it isn't supposed to load PC anyway */ data(rs(addr, 9, 4), rs(addr, 0, 4)); } -static INLINE tdis_ret P(addrmode3_pre_addr_unk_Rt_4_LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { +static INLINE void P(addrmode3_pre_addr_unk_Rt_4_LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { data(rs(addr, 9, 4), rs(addr, 0, 4)); } -static INLINE tdis_ret P(addrmode5_addr_8_LDC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_addr_8_LDC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { data(rsout(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode5_addr_S_4_STC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_addr_S_4_STC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode5_pre_addr_4_LDC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_pre_addr_4_LDC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode5_pre_addr_S_4_STC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_pre_addr_S_4_STC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode_imm12_addr_unk_Rt_2_LDRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(addrmode_imm12_addr_unk_Rt_2_LDRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), rout(Rt)); } -static INLINE tdis_ret P(addrmode_imm12_pre_addr_unk_Rt_2_LDRB_PRE_IMM)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(addrmode_imm12_pre_addr_unk_Rt_2_LDRB_PRE_IMM)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), rout(Rt)); } -static INLINE tdis_ret P(adrlabel_label_unk_Rd_1_ADR)(tdis_ctx ctx, struct bitslice label, struct bitslice Rd) { +static INLINE void P(adrlabel_label_unk_Rd_1_ADR)(tdis_ctx ctx, struct bitslice label, struct bitslice Rd) { return P(pcrel)(ctx, ctx->pc + 8 + bs_get(label, ctx->op), bs_get(Rd, ctx->op), PLM_ADR); } -static INLINE tdis_ret P(br_target_target_B_1_Bcc)(tdis_ctx ctx, struct bitslice target) { - return P(branch)(ctx, ctx->pc + 8 + sext(bs_get(target, ctx->op), 24)); +static INLINE void P(br_target_target_B_1_Bcc)(tdis_ctx ctx, struct bitslice target) { + bool cond = (ctx->op >> 28) != 0xe; + return P(branch)(ctx, ctx->pc + 8 + sext(bs_get(target, ctx->op), 24), /*cond*/ cond); } -static INLINE tdis_ret P(ldst_so_reg_addr_unk_Rt_2_LDRB_PRE_REG)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(ldst_so_reg_addr_unk_Rt_2_LDRB_PRE_REG)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 0, 4), rs(addr, 13, 4), rout(Rt)); } -static INLINE tdis_ret P(ldst_so_reg_shift_unk_Rt_2_LDRBrs)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rt) { +static INLINE void P(ldst_so_reg_shift_unk_Rt_2_LDRBrs)(tdis_ctx ctx, struct bitslice shift, struct bitslice Rt) { data(rs(shift, 0, 4), rs(shift, 13, 4), rout(Rt)); } -static INLINE tdis_ret P(tcGPR_Rm_unk_Rd_1_MOVr_TC)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd) { +static INLINE void P(tcGPR_Rm_unk_Rd_1_MOVr_TC)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd) { data(rout(Rd), r(Rm)); } -static INLINE tdis_ret P(unk_Rd_5_MOVTi16)(tdis_ctx ctx, struct bitslice Rd) { +static INLINE void P(unk_Rd_5_MOVTi16)(tdis_ctx ctx, struct bitslice Rd) { data(rout(Rd)); } -static INLINE tdis_ret P(unk_Rt_13_MRC)(tdis_ctx ctx, struct bitslice Rt) { +static INLINE void P(unk_Rt_13_MRC)(tdis_ctx ctx, struct bitslice Rt) { data(rout(Rt)); } -static INLINE tdis_ret P(GPR_Rn_reglist_regs_16_LDMDA)(tdis_ctx ctx, struct bitslice regs, UNUSED struct bitslice Rn) { +static INLINE void P(GPR_Rn_reglist_regs_16_LDMDA)(tdis_ctx ctx, struct bitslice regs, UNUSED struct bitslice Rn) { unsigned regs_val = bs_get(regs, ctx->op); if (regs_val & (1 << 15)) return P(ret)(ctx); return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rn_reglist_regs_S_16_STMDA)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { +static INLINE void P(GPR_Rn_reglist_regs_S_16_STMDA)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { unsigned regs_val = bs_get(regs, ctx->op); if (regs_val & (1 << 15)) return P(bad)(ctx); return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rt_addr_offset_none_addr_unk_Rd_S_6_STLEX)(tdis_ctx ctx, struct bitslice Rt, struct bitslice Rd, struct bitslice addr) { +static INLINE void P(GPR_Rt_addr_offset_none_addr_unk_Rd_S_6_STLEX)(tdis_ctx ctx, struct bitslice Rt, struct bitslice Rd, struct bitslice addr) { data(r(addr), r(Rt), r(Rd)); } -static INLINE tdis_ret P(addr_offset_none_addr_postidx_reg_Rm_unk_Rt_3_LDRHTr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_postidx_reg_Rm_unk_Rt_3_LDRHTr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rt, struct bitslice addr) { data(r(addr), rout(Rt), r(Rm)); } -static INLINE tdis_ret 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) { +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)); } -#define GENERATED_HEADER "../generated/transform-dis-arm.inc.h" +static INLINE void P(dis_arm)(tdis_ctx ctx) { + uint32_t op = ctx->op = *(uint32_t *) ctx->ptr; + ctx->op_size = 4; + #include "../generated/generic-dis-arm.inc.h" + __builtin_abort(); +} +#define GENERATED_HEADER "../generated/generic-dis-arm.inc.h" diff --git a/lib/dis-arm64.inc.h b/lib/dis-arm64.inc.h index 333ecb1..388ac19 100644 --- a/lib/dis-arm64.inc.h +++ b/lib/dis-arm64.inc.h @@ -1,19 +1,19 @@ -static INLINE tdis_ret P(adrlabel_label_unk_Xd_1_ADR)(tdis_ctx ctx, struct bitslice Xd, struct bitslice label) { +static INLINE void P(adrlabel_label_unk_Xd_1_ADR)(tdis_ctx ctx, struct bitslice Xd, struct bitslice label) { return P(pcrel)(ctx, ctx->pc + sext(bs_get(label, ctx->op), 22), bs_get(Xd, ctx->op), PLM_ADR); } -static INLINE tdis_ret P(adrplabel_label_unk_Xd_1_ADRP)(tdis_ctx ctx, struct bitslice Xd, struct bitslice label) { +static INLINE void P(adrplabel_label_unk_Xd_1_ADRP)(tdis_ctx ctx, struct bitslice Xd, struct bitslice label) { return P(pcrel)(ctx, ctx->pc + (sext(bs_get(label, ctx->op), 22) << 12), bs_get(Xd, ctx->op), PLM_ADR); } -static INLINE tdis_ret P(am_b_target_addr_B_1_B)(tdis_ctx ctx, struct bitslice addr) { - return P(branch)(ctx, ctx->pc + sext(bs_get(addr, ctx->op), 26) * 4); +static INLINE void P(am_b_target_addr_B_1_B)(tdis_ctx ctx, struct bitslice addr) { + return P(branch)(ctx, ctx->pc + sext(bs_get(addr, ctx->op), 26) * 4, /*cond*/ false); } -static INLINE tdis_ret P(am_bl_target_addr_1_BL)(tdis_ctx ctx, struct bitslice addr) { - return P(branch)(ctx, ctx->pc + sext(bs_get(addr, ctx->op), 26) * 4); +static INLINE void P(am_bl_target_addr_1_BL)(tdis_ctx ctx, struct bitslice addr) { + return P(branch)(ctx, ctx->pc + sext(bs_get(addr, ctx->op), 26) * 4, /*cond*/ false); } -static INLINE tdis_ret P(am_brcond_target_B_5_Bcc)(tdis_ctx ctx, struct bitslice target) { - return P(branch)(ctx, ctx->pc + sext(bs_get(target, ctx->op), 19) * 4); +static INLINE void P(am_brcond_target_B_5_Bcc)(tdis_ctx ctx, struct bitslice target) { + return P(branch)(ctx, ctx->pc + sext(bs_get(target, ctx->op), 19) * 4, /*cond*/ true); } -static INLINE tdis_ret P(am_ldrlit_label_unk_Rt_6_LDRDl)(tdis_ctx ctx, struct bitslice Rt, struct bitslice label) { +static INLINE void P(am_ldrlit_label_unk_Rt_6_LDRDl)(tdis_ctx ctx, struct bitslice Rt, struct bitslice label) { enum pcrel_load_mode mode; if ((ctx->op >> 26) & 1) { switch (ctx->op >> 30) { @@ -32,11 +32,18 @@ static INLINE tdis_ret P(am_ldrlit_label_unk_Rt_6_LDRDl)(tdis_ctx ctx, struct bi } return P(pcrel)(ctx, ctx->pc + sext(bs_get(label, ctx->op), 19) * 4, bs_get(Rt, ctx->op), mode); } -static INLINE tdis_ret P(am_tbrcond_target_B_4_TBNZW)(tdis_ctx ctx, struct bitslice target) { - return P(branch)(ctx, ctx->pc + sext(bs_get(target, ctx->op), 14) * 4); +static INLINE void P(am_tbrcond_target_B_4_TBNZW)(tdis_ctx ctx, struct bitslice target) { + return P(branch)(ctx, ctx->pc + sext(bs_get(target, ctx->op), 14) * 4, /*cond*/ true); } -static INLINE tdis_ret P(GPR64_Rn_1_RET)(tdis_ctx ctx, UNUSED struct bitslice Rn) { +static INLINE void P(GPR64_Rn_1_RET)(tdis_ctx ctx, UNUSED struct bitslice Rn) { return P(ret)(ctx); } -#define GENERATED_HEADER "../generated/transform-dis-arm64.inc.h" +static INLINE void P(dis)(tdis_ctx ctx) { + uint32_t op = ctx->op = *(uint32_t *) ctx->ptr; + ctx->op_size = 4; + /* clang doesn't realize that this is unreachable and generates code like + * "and ecx, 0x1f; cmp ecx, 0x1f; ja abort". Yeah, nice job there. */ + #include "../generated/generic-dis-arm64.inc.h" + __builtin_abort(); +} diff --git a/lib/dis-thumb.inc.h b/lib/dis-thumb.inc.h index 75b50dc..a0434bc 100644 --- a/lib/dis-thumb.inc.h +++ b/lib/dis-thumb.inc.h @@ -1,16 +1,16 @@ #include "dis.h" -static INLINE tdis_ret P(GPR_Rm_unk_Rdn_1_tADDhirr)(tdis_ctx ctx, struct bitslice Rdn, struct bitslice Rm) { +static INLINE void P(GPR_Rm_unk_Rdn_1_tADDhirr)(tdis_ctx ctx, struct bitslice Rdn, struct bitslice Rm) { data(rout(Rdn), r(Rm), r(Rdn)); /* yes, twice */ } -static INLINE tdis_ret P(unk_Rdn_1_tADDrSP)(tdis_ctx ctx, UNUSED struct bitslice Rdn) { +static INLINE void P(unk_Rdn_1_tADDrSP)(tdis_ctx ctx, UNUSED struct bitslice Rdn) { /* this doesn't support constants, and nobody's going to add pc, sp, so... */ return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rm_1_tADDspr)(tdis_ctx ctx, UNUSED struct bitslice Rm) { +static INLINE void P(GPR_Rm_1_tADDspr)(tdis_ctx ctx, UNUSED struct bitslice Rm) { /* ditto */ return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rm_B_1_tBX)(tdis_ctx ctx, struct bitslice Rm) { +static INLINE void P(GPR_Rm_B_1_tBX)(tdis_ctx ctx, struct bitslice Rm) { unsigned val = bs_get(Rm, ctx->op); if (val == 15) /* bx pc */ return P(bad)(ctx); @@ -18,7 +18,7 @@ static INLINE tdis_ret P(GPR_Rm_B_1_tBX)(tdis_ctx ctx, struct bitslice Rm) { return P(ret)(ctx); return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rm_unk_Rd_1_tMOVr)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rm) { +static INLINE void P(GPR_Rm_unk_Rd_1_tMOVr)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rm) { unsigned Rd_val = bs_get(Rd, ctx->op); unsigned Rm_val = bs_get(Rm, ctx->op); /* does anyone do this? */ @@ -28,26 +28,40 @@ static INLINE tdis_ret P(GPR_Rm_unk_Rd_1_tMOVr)(tdis_ctx ctx, struct bitslice Rd return P(pcrel)(ctx, ctx->pc + 4, Rd_val, PLM_ADR); return P(unidentified)(ctx); } -static INLINE tdis_ret P(tGPR_Rn_reglist_regs_1_tLDMIA)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { +static INLINE void P(tGPR_Rn_reglist_regs_1_tLDMIA)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { return P(unidentified)(ctx); } -static INLINE tdis_ret P(tGPR_Rn_reglist_regs_S_1_tSTMIA_UPD)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { +static INLINE void P(tGPR_Rn_reglist_regs_S_1_tSTMIA_UPD)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { return P(unidentified)(ctx); } -static INLINE tdis_ret P(t_addrmode_pc_addr_unk_Rt_1_tLDRpci)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(reglist_regs_1_tPOP)(tdis_ctx ctx, struct bitslice regs) { + unsigned regs_val = bs_get(regs, ctx->op); + if(regs_val & (1 << 15)) + return P(ret)(ctx); + return P(unidentified)(ctx); +} +static INLINE void P(reglist_regs_S_1_tPUSH)(tdis_ctx ctx, UNUSED struct bitslice regs) { + return P(unidentified)(ctx); +} +static INLINE void P(t_addrmode_pc_addr_unk_Rt_1_tLDRpci)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { return P(pcrel)(ctx, ((ctx->pc + 4) & ~2) + bs_get(addr, ctx->op), bs_get(Rt, ctx->op), PLM_U32); } -static INLINE tdis_ret P(t_adrlabel_addr_unk_Rd_1_tADR)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rd) { +static INLINE void P(t_adrlabel_addr_unk_Rd_1_tADR)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rd) { return P(pcrel)(ctx, ((ctx->pc + 4) & ~2) + bs_get(addr, ctx->op), bs_get(Rd, ctx->op), PLM_ADR); } -static INLINE tdis_ret P(t_bcctarget_target_B_1_tBcc)(tdis_ctx ctx, struct bitslice target) { - return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 8)); +static INLINE void P(t_bcctarget_target_B_1_tBcc)(tdis_ctx ctx, struct bitslice target) { + return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 8), /*cond*/ true); } -static INLINE tdis_ret 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)); +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); } -static INLINE tdis_ret 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)); +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); } -#define GENERATED_HEADER "../generated/transform-dis-thumb.inc.h" +static INLINE void P(dis_thumb)(tdis_ctx ctx) { + uint16_t op = ctx->op = *(uint16_t *) ctx->ptr; + 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 819471d..30053aa 100644 --- a/lib/dis-thumb2.inc.h +++ b/lib/dis-thumb2.inc.h @@ -1,6 +1,6 @@ #include "dis.h" -static inline enum pcrel_load_mode get_load_mode(unsigned op) { +static inline enum pcrel_load_mode get_thumb_load_mode(unsigned op) { bool sign = (op >> 8) & 1; switch ((op >> 5) & 3) { case 0: return sign ? PLM_S8 : PLM_U8; @@ -10,153 +10,158 @@ static inline enum pcrel_load_mode get_load_mode(unsigned op) { } } -static INLINE tdis_ret P(GPR_Rm_unk_Rd_1_t2MOVr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd) { +static INLINE void P(GPR_Rm_unk_Rd_1_t2MOVr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd) { data(rout(Rd), r(Rm)); } -static INLINE tdis_ret P(GPR_Rn_reglist_regs_4_t2LDMDB)(tdis_ctx ctx, struct bitslice regs, UNUSED struct bitslice Rn) { +static INLINE void P(GPR_Rn_reglist_regs_4_t2LDMDB)(tdis_ctx ctx, struct bitslice regs, UNUSED struct bitslice Rn) { unsigned regs_val = bs_get(regs, ctx->op); if(regs_val & (1 << 15)) return P(ret)(ctx); return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rn_reglist_regs_S_4_t2STMDB)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { +static INLINE void P(GPR_Rn_reglist_regs_S_4_t2STMDB)(tdis_ctx ctx, UNUSED struct bitslice regs, UNUSED struct bitslice Rn) { return P(unidentified)(ctx); } -static INLINE tdis_ret P(GPR_Rn_unk_Rd_1_t2ADDri12)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPR_Rn_unk_Rd_1_t2ADDri12)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rn) { data(rout(Rd), r(Rn)); } -static INLINE tdis_ret P(GPR_Rt_8_VMOVDRR)(tdis_ctx ctx, UNUSED struct bitslice Rt) { +static INLINE void P(GPR_Rt_8_VMOVDRR)(tdis_ctx ctx, UNUSED struct bitslice Rt) { return P(unidentified)(ctx); /* don't care */ } -static INLINE tdis_ret P(GPR_Rt_t2addrmode_imm12_addr_S_1_t2STRi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_t2addrmode_imm12_addr_S_1_t2STRi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 13, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_t2addrmode_negimm8_addr_S_1_t2STRi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_t2addrmode_negimm8_addr_S_1_t2STRi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 9, 4), r(Rt)); } -static INLINE tdis_ret P(GPR_Rt_t2addrmode_so_reg_addr_S_1_t2STRs)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPR_Rt_t2addrmode_so_reg_addr_S_1_t2STRs)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 6, 4), rs(addr, 2, 4), r(Rt)); } -static INLINE tdis_ret P(GPRnopc_Rn_rGPR_Rm_unk_Rd_1_t2ADDrr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPRnopc_Rn_rGPR_Rm_unk_Rd_1_t2ADDrr)(tdis_ctx ctx, struct bitslice Rm, struct bitslice Rd, struct bitslice Rn) { data(rout(Rd), r(Rm), r(Rn)); } -static INLINE tdis_ret P(GPRnopc_Rn_unk_Rd_2_t2ADDri)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rn) { +static INLINE void P(GPRnopc_Rn_unk_Rd_2_t2ADDri)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rn) { data(rout(Rd), r(Rn)); } -static INLINE tdis_ret P(GPRnopc_Rt_t2addrmode_imm8_pre_addr_S_1_t2STR_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(GPRnopc_Rt_t2addrmode_imm8_pre_addr_S_1_t2STR_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 9, 4), r(Rt)); } -static INLINE tdis_ret P(GPRnopc_Rt_addr_offset_none_Rn_t2am_imm8_offset_offset_S_1_t2STR_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { +static INLINE void P(GPRnopc_Rt_addr_offset_none_Rn_t2am_imm8_offset_offset_S_1_t2STR_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { data(r(Rt), r(Rn)); } -static INLINE tdis_ret P(rGPR_Rt_addr_offset_none_addr_S_4_t2STL)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(rGPR_Rt_addr_offset_none_addr_S_4_t2STL)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { data(rout(Rt), r(addr)); } -static INLINE tdis_ret P(rGPR_Rt_addr_offset_none_addr_unk_Rd_S_7_t2STLEX)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(rGPR_Rt_addr_offset_none_addr_unk_Rd_S_7_t2STLEX)(tdis_ctx ctx, struct bitslice Rd, struct bitslice Rt, struct bitslice addr) { data(rout(Rd), rout(Rt), r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_4_t2LDC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_4_t2LDC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_S_4_t2STC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_S_4_t2STC2L_OPTION)(tdis_ctx ctx, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_postidx_imm8s4_offset_4_t2LDC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_postidx_imm8s4_offset_4_t2LDC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_postidx_imm8s4_offset_S_4_t2STC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_postidx_imm8s4_offset_S_4_t2STC2L_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice addr) { data(r(addr)); } -static INLINE tdis_ret P(addr_offset_none_addr_unk_Rt_11_t2LDA)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { +static INLINE void P(addr_offset_none_addr_unk_Rt_11_t2LDA)(tdis_ctx ctx, struct bitslice Rt, struct bitslice addr) { data(rout(Rt), r(addr)); } -static INLINE tdis_ret P(addrmode5_addr_8_VLDRD)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_addr_8_VLDRD)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode5_addr_S_4_t2STC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_addr_S_4_t2STC2L_OFFSET)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode5_pre_addr_4_t2LDC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_pre_addr_4_t2LDC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(addrmode5_pre_addr_S_4_t2STC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { +static INLINE void P(addrmode5_pre_addr_S_4_t2STC2L_PRE)(tdis_ctx ctx, struct bitslice addr) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(brtarget_target_B_1_t2Bcc)(tdis_ctx ctx, struct bitslice target) { - return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 20)); +static INLINE void P(brtarget_target_B_1_t2Bcc)(tdis_ctx ctx, struct bitslice target) { + return P(branch)(ctx, ctx->pc + 4 + 2 * sext(bs_get(target, ctx->op), 20), /*cond*/ true); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_imm0_1020s4_addr_unk_Rd_S_1_t2STREX)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt, struct bitslice Rd) { +static INLINE void P(rGPR_Rt_t2addrmode_imm0_1020s4_addr_unk_Rd_S_1_t2STREX)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt, struct bitslice Rd) { data(rout(Rd), r(Rt), rs(addr, 8, 4)); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_imm12_addr_S_2_t2STRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(rGPR_Rt_t2addrmode_imm12_addr_S_2_t2STRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 13, 4)); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_imm8_pre_addr_S_2_t2STRB_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(rGPR_Rt_t2addrmode_imm8_pre_addr_S_2_t2STRB_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_imm8s4_addr_S_1_t2STRDi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(rGPR_Rt_t2addrmode_imm8s4_addr_S_1_t2STRDi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_imm8s4_pre_addr_S_1_t2STRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(rGPR_Rt_t2addrmode_imm8s4_pre_addr_S_1_t2STRD_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_negimm8_addr_S_2_t2STRBi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(rGPR_Rt_t2addrmode_negimm8_addr_S_2_t2STRBi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(rGPR_Rt_t2addrmode_so_reg_addr_S_2_t2STRBs)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(rGPR_Rt_t2addrmode_so_reg_addr_S_2_t2STRBs)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rs(addr, 6, 4), rs(Rt, 2, 4), r(Rt)); } -static INLINE tdis_ret P(rGPR_Rt_addr_offset_none_Rn_t2am_imm8_offset_offset_S_2_t2STRB_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { +static INLINE void P(rGPR_Rt_addr_offset_none_Rn_t2am_imm8_offset_offset_S_2_t2STRB_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { data(r(Rt), r(Rn)); } -static INLINE tdis_ret P(t2addrmode_imm0_1020s4_addr_unk_Rt_1_t2LDREX)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_imm0_1020s4_addr_unk_Rt_1_t2LDREX)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 8, 4)); } -static INLINE tdis_ret P(t2addrmode_imm12_addr_unk_Rt_5_t2LDRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_imm12_addr_unk_Rt_5_t2LDRBi12)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 13, 4)); } -static INLINE tdis_ret P(t2addrmode_imm8_addr_unk_Rt_S_3_t2STRBT)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_imm8_addr_unk_Rt_S_3_t2STRBT)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(r(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(t2addrmode_imm8_pre_addr_unk_Rt_5_t2LDRB_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_imm8_pre_addr_unk_Rt_5_t2LDRB_PRE)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(addr_offset_none_Rn_t2am_imm8_offset_offset_unk_Rt_5_t2LDRB_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { +static INLINE void P(addr_offset_none_Rn_t2am_imm8_offset_offset_unk_Rt_5_t2LDRB_POST)(tdis_ctx ctx, UNUSED struct bitslice offset, struct bitslice Rt, struct bitslice Rn) { data(rout(Rt), r(Rn)); } -static INLINE tdis_ret P(t2addrmode_imm8s4_addr_unk_Rt_1_t2LDRDi8)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { +static INLINE void P(t2addrmode_imm8s4_addr_unk_Rt_1_t2LDRDi8)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(t2addrmode_imm8s4_pre_addr_unk_Rt_1_t2LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { +static INLINE void P(t2addrmode_imm8s4_pre_addr_unk_Rt_1_t2LDRD_PRE)(tdis_ctx ctx, struct bitslice addr, UNUSED struct bitslice Rt) { data(rs(addr, 9, 4)); } -static INLINE tdis_ret P(t2addrmode_negimm8_addr_unk_Rt_5_t2LDRBi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_negimm8_addr_unk_Rt_5_t2LDRBi8)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(t2addrmode_posimm8_addr_unk_Rt_5_t2LDRBT)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_posimm8_addr_unk_Rt_5_t2LDRBT)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 9, 4)); } -static INLINE tdis_ret P(t2addrmode_so_reg_addr_unk_Rt_5_t2LDRBs)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2addrmode_so_reg_addr_unk_Rt_5_t2LDRBs)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { data(rout(Rt), rs(addr, 6, 4), rs(addr, 2, 4)); } -static INLINE tdis_ret P(t2adrlabel_addr_unk_Rd_1_t2ADR)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rd) { +static INLINE void P(t2adrlabel_addr_unk_Rd_1_t2ADR)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rd) { return P(pcrel)(ctx, ((ctx->pc + 4) & ~2) + (bs_get(addr, ctx->op) & ((1 << 12) - 1)), bs_get(Rd, ctx->op), false); } -static INLINE tdis_ret P(t2ldrlabel_addr_unk_Rt_5_t2LDRBpci)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { +static INLINE void P(t2ldrlabel_addr_unk_Rt_5_t2LDRBpci)(tdis_ctx ctx, struct bitslice addr, struct bitslice Rt) { return P(pcrel)(ctx, ((ctx->pc + 4) & ~2) + (bs_get(addr, ctx->op) & ((1 << 12) - 1)), bs_get(Rt, ctx->op), true); } -static INLINE tdis_ret 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)); +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); } -static INLINE tdis_ret P(unk_Rd_3_t2MOVTi16)(tdis_ctx ctx, struct bitslice Rd) { +static INLINE void P(unk_Rd_3_t2MOVTi16)(tdis_ctx ctx, struct bitslice Rd) { data(rout(Rd)); } -static INLINE tdis_ret P(unk_Rm_B_2_t2TBB)(tdis_ctx ctx, UNUSED struct bitslice Rm) { +static INLINE void P(unk_Rm_B_2_t2TBB)(tdis_ctx ctx, UNUSED struct bitslice Rm) { /* Ew. Don't bother for now - this is hard to make show up in the first 8 bytes... */ return P(bad)(ctx); } -static INLINE tdis_ret P(unk_Rt_13_VMOVRRD)(tdis_ctx ctx, UNUSED struct bitslice Rt) { +static INLINE void P(unk_Rt_13_VMOVRRD)(tdis_ctx ctx, UNUSED struct bitslice Rt) { return P(unidentified)(ctx); } -#define GENERATED_HEADER "../generated/transform-dis-thumb2.inc.h" +static INLINE void P(dis_thumb2)(tdis_ctx ctx) { + uint32_t op = ctx->op = *(uint32_t *) ctx->ptr; + ctx->op_size = 4; + #include "../generated/generic-dis-thumb2.inc.h" + __builtin_abort(); +} @@ -1,6 +1,8 @@ #pragma once #include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> #define UNUSED __attribute__((unused)) #define INLINE __attribute__((always_inline)) @@ -71,34 +73,33 @@ enum pcrel_load_mode { PLM_U128_SIMD, }; -static const struct bitslice nullbs = { 0, NULL }; +static const struct bitslice null_bs = { 0, NULL }; +static const unsigned null_op = -0x100; #define r(nn) nn, false, true #define rs(nn, l, s) bs_slice(nn, l, s), false, true #define rout(nn) nn, true, true #define rsout(nn, l, s) bs_slice(nn, l, s), true, true -#define rnull nullbs, false, false +#define rnull null_bs, false, false #define data(...) data_(__VA_ARGS__, rnull, rnull, rnull, rnull) #define data_(...) data__(__VA_ARGS__) #define data__(b1, o1, v1, b2, o2, v2, b3, o3, v3, b4, o4, v4, ...) do { \ - tdis_ret ret = P(data)(ctx, \ - v1 ? bs_get(b1, ctx->op) : -1u, \ - v2 ? bs_get(b2, ctx->op) : -1u, \ - v3 ? bs_get(b3, ctx->op) : -1u, \ - v4 ? bs_get(b4, ctx->op) : -1u, \ + P(data)(ctx, \ + v1 ? bs_get(b1, ctx->op) : null_op, \ + v2 ? bs_get(b2, ctx->op) : null_op, \ + v3 ? bs_get(b3, ctx->op) : null_op, \ + v4 ? bs_get(b4, ctx->op) : null_op, \ (o1 << 0) | \ (o2 << 1) | \ (o3 << 2) | \ (o4 << 3)); \ - IF_BOTHER_WITH_MODIFY( \ - if (ret.modify) { \ + if (TDIS_CTX_MODIFY(ctx)) { \ unsigned new = ctx->op; \ - new = bs_set(b1, ctx->newval[0], new); \ - new = bs_set(b2, ctx->newval[1], new); \ - new = bs_set(b3, ctx->newval[2], new); \ - new = bs_set(b4, ctx->newval[3], new); \ - ctx->newop = new; \ + new = bs_set(b1, TDIS_CTX_NEWVAL(ctx, 0), new); \ + new = bs_set(b2, TDIS_CTX_NEWVAL(ctx, 1), new); \ + new = bs_set(b3, TDIS_CTX_NEWVAL(ctx, 2), new); \ + new = bs_set(b4, TDIS_CTX_NEWVAL(ctx, 3), new); \ + TDIS_CTX_SET_NEWOP(ctx, new); \ } \ - ) \ - return ret; \ + return; \ } while (0) diff --git a/lib/jump-dis-arm-multi.c b/lib/jump-dis-arm-multi.c new file mode 100644 index 0000000..b5967f5 --- /dev/null +++ b/lib/jump-dis-arm-multi.c @@ -0,0 +1,6 @@ +enum { + MIN_INSN_SIZE = 2 +}; +#define P(x) jump_dis_##x +#include "jump-dis.inc.h" +#include "dis-arm-multi.inc.h" diff --git a/lib/jump-dis.inc.h b/lib/jump-dis.inc.h new file mode 100644 index 0000000..0bfa495 --- /dev/null +++ b/lib/jump-dis.inc.h @@ -0,0 +1,145 @@ +#include "dis.h" +#include <stdint.h> +#include <stdbool.h> +#include <string.h> + +/* This pass tries to look through the function to find jumps back to the + * patched code at the beginning to the function. It does not deal with jump + * tables, and has a limited range, so it is only heuristic. If such jumps are + * found, the hook is aborted. In the future it might be possible to fix up + * the jumps rather than merely detect them, but that would require doing + * something weird like extending the patch region to add trampolines... */ + +enum { + JUMP_ANALYSIS_MAX_INSNS = 512, + JUMP_ANALYSIS_MAX_SIZE = JUMP_ANALYSIS_MAX_INSNS * MIN_INSN_SIZE, +}; + +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; + 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; +}; + +#define tdis_ctx struct jump_dis_ctx * +#define TDIS_CTX_MODIFY(ctx) 0 +#define TDIS_CTX_NEWVAL(ctx, n) 0 +#define TDIS_CTX_SET_NEWOP(ctx, new) ((void) 0) + +static void P(add_to_queue)(struct jump_dis_ctx *ctx, uintptr_t pc) { + size_t diff = (pc - ctx->pc_patch_start) / MIN_INSN_SIZE; + if (diff >= JUMP_ANALYSIS_MAX_INSNS) { +#ifdef JUMP_DIS_VERBOSE + printf("jump-dis: not adding %llx - out of range\n", (unsigned long long) pc); +#endif + return; + } + if (ctx->seen_mask[diff / 8] & 1 << (diff % 8)) { +#ifdef JUMP_DIS_VERBOSE + printf("jump-dis: not adding %llx - already seen\n", (unsigned long long) pc); +#endif + return; + } + ctx->seen_mask[diff / 8] |= 1 << (diff % 8); + + if (ctx->queue_write_off == ctx->queue_read_off && (ctx->queue_count || !ctx->queue_size)) { + size_t new_size = ctx->queue_size * 2 + 5; + ctx->queue = realloc(ctx->queue, new_size * sizeof(*ctx->queue)); + size_t new_read_off = new_size - (ctx->queue_size - ctx->queue_read_off); + memmove(ctx->queue + new_read_off, ctx->queue + ctx->queue_read_off, (ctx->queue_size - ctx->queue_read_off) * sizeof(*ctx->queue)); + ctx->queue_read_off = new_read_off % new_size; + ctx->queue_size = new_size; + } + ctx->queue[ctx->queue_write_off] = pc; + ctx->queue_write_off = (ctx->queue_write_off + 1) % ctx->queue_size; + ctx->queue_count++; +} + + +static INLINE inline void P(data)(UNUSED struct jump_dis_ctx *ctx, UNUSED unsigned o0, UNUSED unsigned o1, UNUSED unsigned o2, UNUSED unsigned o3, UNUSED unsigned out_mask) { + /* on ARM, ignore mov PC jumps, as they're unlikely to be in the same function */ +} + +static INLINE inline void P(pcrel)(struct jump_dis_ctx *ctx, uintptr_t dpc, UNUSED unsigned reg, UNUSED bool is_load) { + ctx->bad_insn = dpc >= ctx->pc_patch_start && dpc < ctx->pc_patch_end; +} + +NOINLINE UNUSED +static void P(ret)(struct jump_dis_ctx *ctx) { + ctx->continue_after_this_insn = false; +} + +NOINLINE UNUSED +static void P(branch)(struct jump_dis_ctx *ctx, uintptr_t dpc, bool conditional) { + if (dpc >= ctx->pc_patch_start && dpc < ctx->pc_patch_end) { + ctx->bad_insn = true; + return; + } +#ifdef JUMP_DIS_VERBOSE + printf("jump-dis: enqueueing %llx\n", (unsigned long long) dpc); +#endif + P(add_to_queue)(ctx, dpc); + ctx->continue_after_this_insn = conditional; +} + +NOINLINE UNUSED +static void P(unidentified)(UNUSED struct jump_dis_ctx *ctx) { +} + +NOINLINE UNUSED +static void P(bad)(struct jump_dis_ctx *ctx) { + ctx->continue_after_this_insn = false; +} + +static void P(dis)(tdis_ctx ctx); + +bool P(main)(void *code_ptr, uintptr_t pc_patch_start, uintptr_t pc_patch_end, bool pc_low_bit) { + struct jump_dis_ctx ctx; + memset(&ctx, 0, sizeof(ctx)); + ctx.pc_patch_start = pc_patch_start; + ctx.pc_patch_end = pc_patch_end; + ctx.pc_low_bit = pc_low_bit; + ctx.pc = pc_patch_end; + while (1) { + ctx.bad_insn = false; + ctx.continue_after_this_insn = true; + ctx.ptr = code_ptr + (ctx.pc - pc_patch_start); + P(dis)(&ctx); +#ifdef JUMP_DIS_VERBOSE + printf("jump-dis: pc=%llx op=%08x size=%x bad=%d continue_after=%d\n", + (unsigned long long) ctx.pc, + ctx.op, + ctx.op_size, + ctx.bad_insn, + ctx.continue_after_this_insn); +#endif + if (ctx.bad_insn) + return true; + if (ctx.continue_after_this_insn) + P(add_to_queue)(&ctx, ctx.pc + ctx.op_size); + + /* get next address */ + if (ctx.queue_read_off == ctx.queue_write_off) + break; + ctx.pc = ctx.queue[ctx.queue_read_off]; + ctx.queue_read_off = (ctx.queue_read_off + 1) % ctx.queue_size; + ctx.queue_count--; + } + /* no bad instructions! */ + return false; +} diff --git a/lib/transform-dis.inc.h b/lib/transform-dis.inc.h index 6889127..a229aaf 100644 --- a/lib/transform-dis.inc.h +++ b/lib/transform-dis.inc.h @@ -1,55 +1,60 @@ typedef struct { bool modify; -} tdis_ret; + bool bad; +} void; + typedef struct tc { + uintptr_t pc_patch_start; + uintptr_t pc_patch_end; uintptr_t pc; int op_size; uint32_t op; uint32_t newop; uint32_t newval[4]; - uintptr_t pc_patch_start; - uintptr_t pc_patch_end; - bool got_bad; } *tdis_ctx; NOINLINE UNUSED -static tdis_ret P_data(struct tc *ctx, unsigned o0, unsigned o1, unsigned o2, unsigned o3, unsigned out_mask) { +static void P_data(struct tc *ctx, unsigned o0, unsigned o1, unsigned o2, unsigned o3, unsigned out_mask) { + / + if (((o0 | o1 | o2 | o3) & (MAX_REGS - 1)) == (MAX_REGS - 1)) { + __builtin_abort(); } NOINLINE UNUSED -static tdis_ret P_pcrel(struct tc *ctx, uintptr_t dpc, unsigned reg, bool is_load) { +static void P_pcrel(struct tc *ctx, uintptr_t dpc, unsigned reg, bool is_load) { __builtin_abort(); } NOINLINE UNUSED -static tdis_ret P_ret(struct tc *ctx) { +static void P_ret(struct tc *ctx) { /* ret is okay if it's at the end of the patch */ - if (ctx->pc + op_size < ctx->pc_patch_end) - ctx->got_bad = true; - printf("ret: %08x\n", ctx->op); - return (tdis_ret) {false}; + if (ctx->pc + ctx->op_size >= ctx->pc_patch_end) + return (void) {0}; + else + return (void) {.bad = true}; } NOINLINE UNUSED -static tdis_ret P_branch(struct tc *ctx, uintptr_t dpc) { +static void P_branch(struct tc *ctx, uintptr_t dpc) { if (dpc >= ctx->pc_patch_start && dpc < ctx->pc_patch_end) { /* don't support this for now */ - ctx->got_bad = true; + return (void) {.bad = true}; } - return (tdis_ret) {false}; + /* branch out of bounds is fine */ + return (void) {0}; } NOINLINE UNUSED -static tdis_ret P_unidentified(struct tc *ctx) { - return (tdis_ret) {false}; +static void P_unidentified(struct tc *ctx) { + /* this isn't exhaustive, so unidentified is fine */ + return (void) {0}; } NOINLINE UNUSED -static tdis_ret P_bad(struct tc *ctx) { - ctx->got_bad = true; - return (tdis_ret) {false}; +static void P_bad(struct tc *ctx) { + return (void) {.bad = true}; } #define P(x) transform_dis_##x |