aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcomex2015-02-09 01:35:40 -0500
committercomex2015-02-09 01:35:40 -0500
commitd4154d33d9768d9671ee1a105ea8f5ff725ae4d5 (patch)
tree5b3539a1dacef1f10a5dceb8ebdccbb1fc590a78
parenttheoretically support x86 PIC (diff)
downloadsubstitute-d4154d33d9768d9671ee1a105ea8f5ff725ae4d5.tar.gz
test harness
-rw-r--r--Makefile3
-rw-r--r--test/test-transform-dis.c150
-rw-r--r--test/transform-dis-cases-i386.S16
3 files changed, 154 insertions, 15 deletions
diff --git a/Makefile b/Makefile
index afe0e86..137cf12 100644
--- a/Makefile
+++ b/Makefile
@@ -157,6 +157,9 @@ out/insns-libz-arm.o: test/insns-libz-arm.S Makefile
out/insns-libz-thumb2.o: test/insns-libz-arm.S Makefile
clang -arch armv7 -c -o $@ $< -DTHUMB2
+out/transform-dis-cases-i386.o: test/transform-dis-cases-i386.S Makefile
+ clang -arch i386 -c -o $@ $<
+
# iOS bootstrap...
ifneq (,$(IS_IOS))
SD_OBJS := out/safety-dance/main.o out/safety-dance/AutoGrid.o
diff --git a/test/test-transform-dis.c b/test/test-transform-dis.c
index 5869fff..f55daa9 100644
--- a/test/test-transform-dis.c
+++ b/test/test-transform-dis.c
@@ -2,22 +2,29 @@
#define TRANSFORM_DIS_VERBOSE 1
#include "transform-dis.c"
#include <stdlib.h>
-int main(UNUSED int argc, char **argv) {
- static uint8_t in[1048576];
- UNUSED size_t size = fread(in, 1, sizeof(in), stdin);
- int patch_size = atoi(argv[1]);
- struct arch_dis_ctx arch;
- arch_dis_ctx_init(&arch);
-#ifdef TARGET_arm
- int thumb = atoi(argv[2]);
- arch.pc_low_bit = thumb;
-#endif
- uint8_t out[patch_size * 10];
- /* patch_size bytes of patch
- * max 2 bytes of tail
- * max 12 more bytes of ITted insns
- * 1 off-by-one written to simplify the code */
+#include <string.h>
+#include <assert.h>
+
+_Noreturn
+static void usage() {
+ printf("usage: test-transform-dis (manual patch_size | auto) <thumb if arm>\n");
+ exit(1);
+}
+
+static void do_manual(uint8_t *in, size_t in_size, int patch_size,
+ struct arch_dis_ctx arch) {
+ (void) in_size;
+ /* on ARM:
+ * patch_size bytes of patch
+ * max 2 bytes of tail
+ * max 12 more bytes of ITted insns
+ * on x86:
+ * max 14 bytes of tail
+ * everywhere:
+ * 1 off-by-one written to simplify the code
+ */
int offsets[patch_size + 15];
+ uint8_t out[patch_size * 10];
void *rewritten_ptr = out;
printf("\n#if 0\n");
uint_tptr pc_patch_start = 0x10000;
@@ -57,3 +64,116 @@ int main(UNUSED int argc, char **argv) {
}
}
}
+
+static void hex_dump(const uint8_t *buf, size_t size) {
+ printf(" .byte ");
+ for (size_t i = 0; i < size; i++) {
+ if (i)
+ printf(", ");
+ printf("0x%02x", buf[i]);
+ }
+ printf("\n");
+}
+
+static void print_given(const uint8_t *given, size_t given_size) {
+ printf("given:\n");
+ hex_dump(given, given_size);
+}
+
+static void do_auto(uint8_t *in, size_t in_size, struct arch_dis_ctx arch) {
+ uint8_t *end = in + in_size;
+ assert(!memcmp(in, "GIVEN", 5)); in += 5;
+ while (in < end) {
+ uint8_t *given = in;
+ uint8_t *expect = memmem(in, end - in, "EXPECT", 6);
+ assert(expect);
+ size_t given_size = expect - given;
+ expect += 6;
+ in = expect;
+ bool expect_err = false;
+ size_t expect_size;
+ if (!memcmp(expect, "_ERR", 4)) {
+ expect_err = true;
+ in += 4;
+ } else {
+ uint8_t *next = memmem(in, end - in, "GIVEN", 5);
+ if (!next)
+ next = end;
+ expect_size = next - expect;
+ in = next;
+ }
+ size_t patch_size = given_size;
+ int offsets[patch_size + 15];
+ uint8_t out[patch_size * 10];
+ void *rewritten_ptr = out;
+ uint_tptr pc_patch_start = 0xdead0000;
+ uint_tptr pc_patch_end = pc_patch_start + patch_size;
+ int ret = transform_dis_main(
+ given,
+ &rewritten_ptr,
+ pc_patch_start,
+ &pc_patch_end,
+ &arch,
+ offsets);
+ if (ret) {
+ if (!expect_err) {
+ print_given(given, given_size);
+ printf("got ret %d, expected success\n\n", ret);
+ }
+ } else {
+ if (expect_err) {
+ print_given(given, given_size);
+ printf("got OK, expected error\n\n");
+ } else if (rewritten_ptr != out + expect_size ||
+ memcmp(out, expect, expect_size)) {
+ print_given(given, given_size);
+ printf("got:\n");
+ hex_dump(out, (uint8_t *) rewritten_ptr - out);
+ printf("but expected:\n");
+ hex_dump(expect, expect_size);
+ printf("\n");
+ }
+ }
+
+ }
+
+}
+
+int main(UNUSED int argc, char **argv) {
+ argv++;
+ if (!*argv)
+ usage();
+ enum { MANUAL, AUTO } mode;
+ if (!strcmp(*argv, "manual"))
+ mode = MANUAL;
+ else if (!strcmp(*argv, "auto"))
+ mode = AUTO;
+ else
+ usage();
+ argv++;
+
+ int patch_size;
+ if (mode == MANUAL) {
+ if (!*argv)
+ usage();
+ patch_size = atoi(*argv++);
+ }
+
+ struct arch_dis_ctx arch;
+ arch_dis_ctx_init(&arch);
+#ifdef TARGET_arm
+ if (!*argv)
+ usage();
+ int thumb = atoi(*argv++);
+ arch.pc_low_bit = thumb;
+#endif
+
+
+ static uint8_t in[1048576];
+ size_t in_size = fread(in, 1, sizeof(in), stdin);
+
+ if (mode == MANUAL)
+ do_manual(in, in_size, patch_size, arch);
+ else
+ do_auto(in, in_size, arch);
+}
diff --git a/test/transform-dis-cases-i386.S b/test/transform-dis-cases-i386.S
new file mode 100644
index 0000000..31508ca
--- /dev/null
+++ b/test/transform-dis-cases-i386.S
@@ -0,0 +1,16 @@
+#define GIVEN .ascii "GIVEN";
+#define EXPECT .ascii "EXPECT";
+#define EXPECT_ERR .ascii "EXPECT_ERR";
+
+GIVEN call .; pop %edx
+/* XXX the extra push isn't necessary in 32-bit mode */
+EXPECT push %eax; push %eax; mov $0xdead0005, %eax; pop %eax; pop %edx
+
+GIVEN jmp 0f; 0:
+EXPECT_ERR
+
+GIVEN jne 0xdead1000
+EXPECT jne 0f; jmp 1f; 0: jmp 0xdead1000; 1:
+
+GIVEN loopne 0xdead0080
+EXPECT loopne 0f; jmp 1f; 0: jmp 0xdead1000; 1: