aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcomex2015-01-16 03:24:12 -0500
committercomex2015-01-16 04:22:55 -0500
commit8fb40a9c236e58b002e447b1c8ac124732a9dd8a (patch)
treef5f32cca52ac85eecc950e573640457696616712
parentadd a test assembly file, not used yet (diff)
downloadsubstitute-8fb40a9c236e58b002e447b1c8ac124732a9dd8a.tar.gz
jump dis - seemingly working(!)
-rw-r--r--Makefile51
-rw-r--r--lib/dis-arm-multi.inc.h16
-rw-r--r--lib/dis-arm.inc.h113
-rw-r--r--lib/dis-arm64.inc.h33
-rw-r--r--lib/dis-thumb.inc.h46
-rw-r--r--lib/dis-thumb2.inc.h109
-rw-r--r--lib/dis.h33
-rw-r--r--lib/jump-dis-arm-multi.c6
-rw-r--r--lib/jump-dis.inc.h145
-rw-r--r--lib/transform-dis.inc.h43
-rw-r--r--test/insns-arm.S (renamed from test/arm-insns.S)0
-rw-r--r--test/insns-libz-arm.S444
-rw-r--r--test/test-jump-dis.c12
-rw-r--r--test/test-td-simple.c49
14 files changed, 882 insertions, 218 deletions
diff --git a/Makefile b/Makefile
index 7ec6e53..d97b130 100644
--- a/Makefile
+++ b/Makefile
@@ -6,24 +6,20 @@ override CC := $(CC) $(CFLAGS)
override CXX := $(CXX) $(CFLAGS) -fno-exceptions -fno-asynchronous-unwind-tables
IMAON2 := /Users/comex/c/imaon2
-GEN_JS := node $(IMAON2)/tables/gen.js
+GEN_JS := node --harmony --harmony_arrow_functions $(IMAON2)/tables/gen.js
all: \
+ generateds \
out/libsubstitute.dylib
-$(shell mkdir -p out)
-
-HEADERS := lib/*.h \
- generated/transform-dis-arm.inc.h
+$(shell mkdir -p out generated)
+HEADERS := lib/*.h
+GENERATED := generated/generic-dis-arm.inc.h generated/generic-dis-thumb.inc.h generated/generic-dis-thumb2.inc.h generated/generic-dis-arm64.inc.h
define do_prefix
-generated/transform-dis-$(1).inc.h: generated Makefile
+generated/generic-dis-$(1).inc.h: Makefile
$(GEN_JS) --gen-hook-disassembler $(2) --dis-pattern='P(XXX)' $(IMAON2)/out/out-$(3).json > $$@ || rm -f $$@
-all: generated/transform-dis-$(1).inc.h
-#generated/jump-dis-$(1).inc.h: generated Makefile
-# $(GEN_JS) --gen-hook-jump-disassembler $(2) -p jump_dis_$(1)_ $(IMAON2)/out/out-$(3).json > $$@ || rm -f $$@
-#all: generated/jump-dis-$(1).inc.h
-HEADERS := $$(HEADERS) generated/transform-dis-$(1).inc.h
+generateds: generated/generic-dis-$(1).inc.h
endef
$(eval $(call do_prefix,thumb2,-n _thumb2,ARM))
$(eval $(call do_prefix,thumb,-n _thumb,ARM))
@@ -32,35 +28,42 @@ $(eval $(call do_prefix,arm64,,AArch64))
out/%.o: lib/%.c Makefile $(HEADERS)
$(CC) -fvisibility=hidden -std=c11 -c -o $@ $<
+out/jump-dis-arm-multi.o: generated/generic-dis-arm.inc.h generated/generic-dis-thumb.inc.h generated/generic-dis-thumb2.inc.h
-LIB_OBJS := out/find-syms.o out/substrate-compat.o
+LIB_OBJS := \
+ out/find-syms.o \
+ out/substrate-compat.o \
+ out/jump-dis-arm-multi.o
out/libsubstitute.dylib: $(LIB_OBJS)
$(CC) -dynamiclib -fvisibility=hidden -o $@ $(LIB_OBJS)
define define_test
-out/test-$(1): test/test-$(2).c* $(HEADERS) Makefile out/libsubstitute.dylib
+out/test-$(1): test/test-$(2).c* $(HEADERS) $(GENERATED) Makefile out/libsubstitute.dylib
$(3) -o $$@ $$< -Ilib -Isubstrate -Lout -lsubstitute
all: out/test-$(1)
endef
-$(eval $(call define_test,tdarm-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-arm.inc.h"'))
-$(eval $(call define_test,tdthumb-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-thumb.inc.h"'))
-$(eval $(call define_test,tdthumb2-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-thumb2.inc.h"'))
-$(eval $(call define_test,tdarm64-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-arm64.inc.h"'))
+$(eval $(call define_test,tdarm-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-arm.inc.h"' -Dxdis=dis_arm))
+$(eval $(call define_test,tdthumb-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-thumb.inc.h"' -Dxdis=dis_thumb))
+$(eval $(call define_test,tdthumb2-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-thumb2.inc.h"' -Dxdis=dis_thumb2))
+$(eval $(call define_test,tdarm64-simple,td-simple,$(CC) -std=c11 -DHDR='"dis-arm64.inc.h"' -Dxdis=dis))
$(eval $(call define_test,dis,dis,$(CC) -std=c11))
$(eval $(call define_test,find-syms,find-syms,$(CC) -std=c89))
$(eval $(call define_test,find-syms-cpp,find-syms,$(CXX) -x c++ -std=c++98))
$(eval $(call define_test,substrate,substrate,$(CXX) -std=c++98))
+$(eval $(call define_test,jump-dis,jump-dis,$(CC) -std=c11))
-out/arm-insns.o: test/arm-insns.S Makefile
+out/insns-arm.o: test/insns-arm.S Makefile
clang -arch armv7 -c -o $@ $<
-out/thumb2-insns.o: test/arm-insns.S Makefile
+out/insns-thumb2.o: test/insns-arm.S Makefile
clang -arch armv7 -DTHUMB2 -c -o $@ $<
-out/%-insns.bin: out/%-insns.o Makefile
- segedit -extract __TEXT __text $@ $<
-generated: Makefile
- rm -rf generated
- mkdir generated
+out/insns-libz-arm.o: test/insns-libz-arm.S Makefile
+ clang -arch armv7 -c -o $@ $<
+out/insns-libz-thumb2.o: test/insns-libz-arm.S Makefile
+ clang -arch armv7 -c -o $@ $< -DTHUMB2
+
+out/insns-%.bin: out/insns-%.o Makefile
+ segedit -extract __TEXT __text $@ $<
clean:
rm -rf out
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();
+}
diff --git a/lib/dis.h b/lib/dis.h
index ae8c75a..7e89cfa 100644
--- a/lib/dis.h
+++ b/lib/dis.h
@@ -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
diff --git a/test/arm-insns.S b/test/insns-arm.S
index 62b4b48..62b4b48 100644
--- a/test/arm-insns.S
+++ b/test/insns-arm.S
diff --git a/test/insns-libz-arm.S b/test/insns-libz-arm.S
new file mode 100644
index 0000000..e288e79
--- /dev/null
+++ b/test/insns-libz-arm.S
@@ -0,0 +1,444 @@
+#ifdef THUMB2
+.thumb
+.thumb_func
+.syntax unified
+#endif
+_deflateInit2_:
+@ BB#0:
+ push {r4, r5, r6, r7, lr}
+ add r7, sp, #12
+ sub sp, #88
+ ldr.w r9, [r7, #20]
+ ldr.w r12, [r7, #16]
+ ldr.w lr, [r7, #12]
+ ldr r4, [r7, #8]
+ movs r5, #0
+ movt r5, #0
+ movs r6, #1
+ movt r6, #0
+#if 0 /* just cutting out some insns so it all fits */
+ str r0, [sp, #80]
+ str r1, [sp, #76]
+ str r2, [sp, #72]
+ str r3, [sp, #68]
+ str r4, [sp, #64]
+ str.w lr, [sp, #60]
+ str.w r12, [sp, #56]
+ str.w r9, [sp, #52]
+ str r6, [sp, #44]
+ ldr r0, [sp, #56]
+#endif
+ cmp r0, r5
+ beq LBB1_3
+@ BB#1:
+ movw r0, #123
+ movt r0, #456
+LPC1_0:
+ add r0, pc
+ ldr r1, [sp, #56]
+ ldrsb.w r1, [r1]
+ ldrsb.w r0, [r0]
+ cmp r1, r0
+ bne LBB1_3
+@ BB#2:
+ ldr r0, [sp, #52]
+ cmp r0, #56
+ beq LBB1_4
+LBB1_3:
+ movw r0, #65530
+ movt r0, #65535
+ str r0, [sp, #84]
+ b LBB1_37
+LBB1_4:
+ movs r0, #0
+ movt r0, #0
+ ldr r1, [sp, #80]
+ cmp r1, r0
+ bne LBB1_6
+@ BB#5:
+ movw r0, #65534
+ movt r0, #65535
+ str r0, [sp, #84]
+ b LBB1_37
+LBB1_6:
+ movs r0, #0
+ movt r0, #0
+ ldr r1, [sp, #80]
+ str r0, [r1, #24]
+ ldr r1, [sp, #80]
+ ldr r1, [r1, #32]
+ cmp r1, r0
+ bne LBB1_8
+@ BB#7:
+ movs r0, #0
+ movt r0, #0
+ movw r1, #123
+ movt r1, #456
+LPC1_1:
+ add r1, pc
+ ldr r1, [r1]
+ ldr r2, [sp, #80]
+ str r1, [r2, #32]
+ ldr r1, [sp, #80]
+ str r0, [r1, #40]
+LBB1_8:
+ movs r0, #0
+ movt r0, #0
+ ldr r1, [sp, #80]
+ ldr r1, [r1, #36]
+ cmp r1, r0
+ bne LBB1_10
+@ BB#9:
+ movw r0, #123
+ movt r0, #456
+LPC1_2:
+ add r0, pc
+ ldr r0, [r0]
+ ldr r1, [sp, #80]
+ str r0, [r1, #36]
+LBB1_10:
+ ldr r0, [sp, #76]
+ cmn.w r0, #1
+ bne LBB1_12
+@ BB#11:
+ movs r0, #6
+ movt r0, #0
+ str r0, [sp, #76]
+LBB1_12:
+ ldr r0, [sp, #68]
+ cmp r0, #0
+ bge LBB1_14
+@ BB#13:
+ movs r0, #0
+ movt r0, #0
+ str r0, [sp, #44]
+ ldr r1, [sp, #68]
+ subs r0, r0, r1
+ str r0, [sp, #68]
+ b LBB1_17
+LBB1_14:
+ ldr r0, [sp, #68]
+ cmp r0, #15
+ ble LBB1_16
+@ BB#15:
+ movs r0, #2
+ movt r0, #0
+ str r0, [sp, #44]
+ ldr r0, [sp, #68]
+ subs r0, #16
+ str r0, [sp, #68]
+LBB1_16:
+ b LBB1_17
+LBB1_17:
+ ldr r0, [sp, #64]
+ cmp r0, #1
+ blt LBB1_26
+@ BB#18:
+ ldr r0, [sp, #64]
+ cmp r0, #9
+ bgt LBB1_26
+@ BB#19:
+ ldr r0, [sp, #72]
+ cmp r0, #8
+ bne LBB1_26
+@ BB#20:
+ ldr r0, [sp, #68]
+ cmp r0, #8
+ blt LBB1_26
+@ BB#21:
+ ldr r0, [sp, #68]
+ cmp r0, #15
+ bgt LBB1_26
+@ BB#22:
+ ldr r0, [sp, #76]
+ cmp r0, #0
+ blt LBB1_26
+@ BB#23:
+ ldr r0, [sp, #76]
+ cmp r0, #9
+ bgt LBB1_26
+@ BB#24:
+ ldr r0, [sp, #60]
+ cmp r0, #0
+ blt LBB1_26
+@ BB#25:
+ ldr r0, [sp, #60]
+ cmp r0, #4
+ ble LBB1_27
+LBB1_26:
+ movw r0, #65534
+ movt r0, #65535
+ str r0, [sp, #84]
+ b LBB1_37
+LBB1_27:
+ ldr r0, [sp, #68]
+ cmp r0, #8
+ bne LBB1_29
+@ BB#28:
+ movs r0, #9
+ movt r0, #0
+ str r0, [sp, #68]
+LBB1_29:
+ movs r0, #0
+ movt r0, #0
+ movs r1, #1
+ movt r1, #0
+ movw r2, #5828
+ movt r2, #0
+ ldr r3, [sp, #80]
+ ldr r3, [r3, #32]
+ ldr.w r9, [sp, #80]
+ ldr.w r9, [r9, #40]
+ str r0, [sp, #36] @ 4-byte Spill
+ mov r0, r9
+ blx r3
+ str r0, [sp, #48]
+ ldr r0, [sp, #48]
+ ldr r1, [sp, #36] @ 4-byte Reload
+ cmp r0, r1
+ bne LBB1_31
+@ BB#30:
+ movw r0, #65532
+ movt r0, #65535
+ str r0, [sp, #84]
+ b LBB1_37
+LBB1_31:
+ movs r0, #0
+ movt r0, #0
+ movs r2, #4
+ movt r2, #0
+ movs r1, #1
+ movt r1, #0
+ movs r3, #2
+ movt r3, #0
+ movw r9, #3
+ movt r9, #0
+ ldr.w r12, [sp, #48]
+ ldr.w lr, [sp, #80]
+ str.w r12, [lr, #28]
+ ldr.w r12, [sp, #80]
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr]
+ ldr.w r12, [sp, #44]
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #24]
+ ldr.w r12, [sp, #48]
+ str.w r0, [r12, #28]
+ ldr.w r12, [sp, #68]
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #48]
+ ldr.w r12, [sp, #48]
+ ldr.w r12, [r12, #48]
+ lsl.w r12, r1, r12
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #44]
+ ldr.w r12, [sp, #48]
+ ldr.w r12, [r12, #44]
+ sub.w r12, r12, #1
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #52]
+ ldr.w r12, [sp, #64]
+ add.w r12, r12, #7
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #80]
+ ldr.w r12, [sp, #48]
+ ldr.w r12, [r12, #80]
+ lsl.w r12, r1, r12
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #76]
+ ldr.w r12, [sp, #48]
+ ldr.w r12, [r12, #76]
+ sub.w r12, r12, #1
+ ldr.w lr, [sp, #48]
+ str.w r12, [lr, #84]
+ ldr.w r12, [sp, #48]
+ ldr.w r12, [r12, #80]
+ add.w r12, r12, #3
+ sub.w r12, r12, #1
+ str r0, [sp, #32] @ 4-byte Spill
+ mov r0, r12
+ str r1, [sp, #28] @ 4-byte Spill
+ mov r1, r9
+ str r3, [sp, #24] @ 4-byte Spill
+ str r2, [sp, #20] @ 4-byte Spill
+ bl ___udivsi3
+ ldr r1, [sp, #48]
+ str r0, [r1, #88]
+ ldr r0, [sp, #80]
+ ldr r0, [r0, #32]
+ ldr r1, [sp, #80]
+ ldr r1, [r1, #40]
+ ldr r2, [sp, #48]
+ ldr r2, [r2, #44]
+ str r0, [sp, #16] @ 4-byte Spill
+ mov r0, r1
+ mov r1, r2
+ ldr r2, [sp, #24] @ 4-byte Reload
+ ldr r3, [sp, #16] @ 4-byte Reload
+ blx r3
+ ldr r1, [sp, #48]
+ str r0, [r1, #56]
+ ldr r0, [sp, #80]
+ ldr r0, [r0, #32]
+ ldr r1, [sp, #80]
+ ldr r1, [r1, #40]
+ ldr r2, [sp, #48]
+ ldr r2, [r2, #44]
+ str r0, [sp, #12] @ 4-byte Spill
+ mov r0, r1
+ mov r1, r2
+ ldr r2, [sp, #24] @ 4-byte Reload
+ ldr r3, [sp, #12] @ 4-byte Reload
+ blx r3
+ ldr r1, [sp, #48]
+ str r0, [r1, #64]
+ ldr r0, [sp, #80]
+ ldr r0, [r0, #32]
+ ldr r1, [sp, #80]
+ ldr r1, [r1, #40]
+ ldr r2, [sp, #48]
+ ldr r2, [r2, #76]
+ str r0, [sp, #8] @ 4-byte Spill
+ mov r0, r1
+ mov r1, r2
+ ldr r2, [sp, #24] @ 4-byte Reload
+ ldr r3, [sp, #8] @ 4-byte Reload
+ blx r3
+ ldr r1, [sp, #48]
+ str r0, [r1, #68]
+ ldr r0, [sp, #48]
+ add.w r0, r0, #5824
+ ldr r1, [sp, #32] @ 4-byte Reload
+ str r1, [r0]
+ ldr r0, [sp, #64]
+ adds r0, #6
+ ldr r2, [sp, #28] @ 4-byte Reload
+ lsl.w r0, r2, r0
+ ldr r3, [sp, #48]
+ movw r9, #5788
+ movt r9, #0
+ add r3, r9
+ str r0, [r3]
+ ldr r0, [sp, #80]
+ ldr r0, [r0, #32]
+ ldr r3, [sp, #80]
+ ldr r3, [r3, #40]
+ ldr.w r9, [sp, #48]
+ movw r12, #5788
+ movt r12, #0
+ add r9, r12
+ ldr.w r1, [r9]
+ str r0, [sp, #4] @ 4-byte Spill
+ mov r0, r3
+ ldr r2, [sp, #20] @ 4-byte Reload
+ ldr r3, [sp, #4] @ 4-byte Reload
+ blx r3
+ str r0, [sp, #40]
+ ldr r0, [sp, #40]
+ ldr r1, [sp, #48]
+ str r0, [r1, #8]
+ ldr r0, [sp, #48]
+ movw r1, #5788
+ movt r1, #0
+ add r0, r1
+ ldr r0, [r0]
+ lsls r0, r0, #2
+ ldr r1, [sp, #48]
+ str r0, [r1, #12]
+ ldr r0, [sp, #48]
+ ldr r0, [r0, #56]
+ ldr r1, [sp, #32] @ 4-byte Reload
+ cmp r0, r1
+ beq LBB1_35
+@ BB#32:
+ movs r0, #0
+ movt r0, #0
+ ldr r1, [sp, #48]
+ ldr r1, [r1, #64]
+ cmp r1, r0
+ beq LBB1_35
+@ BB#33:
+ movs r0, #0
+ movt r0, #0
+ ldr r1, [sp, #48]
+ ldr r1, [r1, #68]
+ cmp r1, r0
+ beq LBB1_35
+@ BB#34:
+ movs r0, #0
+ movt r0, #0
+ ldr r1, [sp, #48]
+ ldr r1, [r1, #8]
+ cmp r1, r0
+ bne LBB1_36
+LBB1_35:
+ movw r0, #123
+ movt r0, #456
+LPC1_3:
+ add r0, pc
+ ldr r0, [r0]
+ movw r1, #666
+ movt r1, #0
+ ldr r2, [sp, #48]
+ str r1, [r2, #4]
+ ldr r0, [r0, #24]
+ ldr r1, [sp, #80]
+ str r0, [r1, #24]
+ ldr r0, [sp, #80]
+ bl _deflateEnd
+ movw r1, #65532
+ movt r1, #65535
+ str r1, [sp, #84]
+ str r0, [sp] @ 4-byte Spill
+ b LBB1_37
+LBB1_36:
+ ldr r0, [sp, #40]
+ ldr r1, [sp, #48]
+ movw r2, #5788
+ movt r2, #0
+ add r1, r2
+ ldr r1, [r1]
+ movs r2, #1
+ movt r2, #0
+ lsrs r1, r2
+ lsls r1, r1, #1
+ add r0, r1
+ ldr r1, [sp, #48]
+ movw r2, #5796
+ movt r2, #0
+ add r1, r2
+ str r0, [r1]
+ ldr r0, [sp, #48]
+ ldr r0, [r0, #8]
+ ldr r1, [sp, #48]
+ movw r2, #5788
+ movt r2, #0
+ add r1, r2
+ ldr r1, [r1]
+ movs r2, #3
+ movt r2, #0
+ muls r1, r2, r1
+ add r0, r1
+ ldr r1, [sp, #48]
+ movw r2, #5784
+ movt r2, #0
+ add r1, r2
+ str r0, [r1]
+ ldr r0, [sp, #76]
+ ldr r1, [sp, #48]
+ str.w r0, [r1, #132]
+ ldr r0, [sp, #60]
+ ldr r1, [sp, #48]
+ str.w r0, [r1, #136]
+ ldr r0, [sp, #72]
+ ldr r1, [sp, #48]
+ strb.w r0, [r1, #36]
+ ldr r0, [sp, #80]
+ bl _deflateReset
+ str r0, [sp, #84]
+LBB1_37:
+ ldr r0, [sp, #84]
+ add sp, #88
+ pop {r4, r5, r6, r7, pc}
+
+
diff --git a/test/test-jump-dis.c b/test/test-jump-dis.c
new file mode 100644
index 0000000..161c80c
--- /dev/null
+++ b/test/test-jump-dis.c
@@ -0,0 +1,12 @@
+#define JUMP_DIS_VERBOSE
+#include <stdio.h>
+#include "jump-dis-arm-multi.c"
+#include <stdlib.h>
+int main(UNUSED int argc, char **argv) {
+ static char buf[1048576];
+ UNUSED size_t size = fread(buf, 1, sizeof(buf), stdin);
+ int patch_size = atoi(argv[1]);
+ int thumb = atoi(argv[2]);
+ bool bad = P(main)(buf, 0x10000, 0x10000 + patch_size, thumb);
+ printf("final: bad = %d\n", bad);
+}
diff --git a/test/test-td-simple.c b/test/test-td-simple.c
index 7f11423..e1524f5 100644
--- a/test/test-td-simple.c
+++ b/test/test-td-simple.c
@@ -4,18 +4,22 @@
#define IF_BOTHER_WITH_MODIFY(...) __VA_ARGS__
#include "dis.h"
-typedef struct { bool modify; } tdis_ret;
typedef struct tc {
uint32_t pc;
+ void *ptr;
uint32_t op;
uint32_t newop;
uint32_t newval[4];
-
+ bool modify;
+ int op_size;
} *tdis_ctx;
#define P(x) P_##x
+#define TDIS_CTX_MODIFY(ctx) ((ctx)->modify)
+#define TDIS_CTX_NEWVAL(ctx, n) ((ctx)->newval[n])
+#define TDIS_CTX_SET_NEWOP(ctx, new) ((ctx)->newop = (new))
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) {
printf("data: %08x\n", ctx->op);
unsigned os[] = {o0, o1, o2, o3};
for(size_t i = 0; i < 4; i++) {
@@ -25,55 +29,50 @@ static tdis_ret P_data(struct tc *ctx, unsigned o0, unsigned o1, unsigned o2, un
printf(" reg %x: %s\n", val, out_mask & (1 << i) ? "out" : "in");
ctx->newval[i] = i;
}
- return (tdis_ret) {true};
+ ctx->modify = true;
}
NOINLINE UNUSED
-static tdis_ret P_pcrel(struct tc *ctx, uint32_t dpc, unsigned reg, enum pcrel_load_mode lm) {
+static void P_pcrel(struct tc *ctx, uint32_t dpc, unsigned reg, enum pcrel_load_mode lm) {
printf("adr: %08x => %08x r%u lm:%d\n", ctx->op, dpc, reg, lm);
- return (tdis_ret) {false};
+ ctx->modify = false;
}
NOINLINE UNUSED
-static tdis_ret P_ret(struct tc *ctx) {
+static void P_ret(struct tc *ctx) {
printf("ret: %08x\n", ctx->op);
- return (tdis_ret) {false};
+ ctx->modify = false;
}
NOINLINE UNUSED
-static tdis_ret P_branch(struct tc *ctx, uint32_t dpc) {
- printf("branch: %08x => %08x\n", ctx->op, dpc);
- return (tdis_ret) {false};
+static void P_branch(struct tc *ctx, uint32_t dpc, bool cond) {
+ printf("branch(%s): %08x => %08x\n", cond ? "cond" : "uncond", ctx->op, dpc);
+ ctx->modify = false;
}
NOINLINE UNUSED
-static tdis_ret P_unidentified(struct tc *ctx) {
+static void P_unidentified(struct tc *ctx) {
printf("unidentified: %08x\n", ctx->op);
- return (tdis_ret) {false};
+ ctx->modify = false;
}
NOINLINE UNUSED
-static tdis_ret P_bad(struct tc *ctx) {
+static void P_bad(struct tc *ctx) {
printf("bad: %08x\n", ctx->op);
- return (tdis_ret) {false};
+ ctx->modify = false;
}
#include HDR
-static tdis_ret P_dis(tdis_ctx ctx) {
- unsigned op = ctx->op;
- #include GENERATED_HEADER
- /* clang doesn't realize that this is unreachable and generates code like
- * "and ecx, 0x1f; cmp ecx, 0x1f; ja abort". Yeah, nice job there. */
- __builtin_abort();
-}
+#define P_(x) P(x)
int main(UNUSED int argc, char **argv) {
struct tc ctx;
ctx.pc = 0xdead0000;
- ctx.op = (uint32_t) strtoll(argv[1] ? argv[1] : "deadbeef", NULL, 16);
+ uint32_t op = strtoll(argv[1] ? argv[1] : "deadbeef", NULL, 16);
+ ctx.ptr = &op;
ctx.newop = 0;
- P_dis(&ctx);
- printf("==> %x\n", ctx.newop);
+ P_(xdis)(&ctx);
+ printf("==> %x (size=%d)\n", ctx.newop, ctx.op_size);
}