diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile | 8 | ||||
-rw-r--r-- | risu.c | 65 | ||||
-rw-r--r-- | risu.h | 6 | ||||
-rw-r--r-- | risu_i386.c | 64 | ||||
-rw-r--r-- | test_i386.s | 16 |
6 files changed, 149 insertions, 11 deletions
@@ -1,4 +1,5 @@ # Ignore binaries and any lurking coredumps *.o +*.bin risu core @@ -4,8 +4,11 @@ ARCH=$(shell dpkg-architecture -qDEB_HOST_ARCH_CPU) PROG=risu SRCS=risu.c comms.c risu_$(ARCH).c HDRS=risu.h +BINS=test_i386.bin + OBJS=$(SRCS:.c=.o) +all: $(PROG) $(BINS) $(PROG): $(OBJS) $(CC) -g -Wall -Werror -o $@ $^ @@ -13,5 +16,8 @@ $(PROG): $(OBJS) %.o: %.c $(HDRS) $(CC) -g -Wall -Werror -o $@ -c $< +%.bin: %.s + nasm -f bin -o $@ $< + clean: - rm -f $(PROG) $(OBJS) + rm -f $(PROG) $(OBJS) $(BINS) @@ -12,6 +12,9 @@ #include <getopt.h> #include <setjmp.h> #include <assert.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> #include "risu.h" @@ -29,6 +32,7 @@ void master_sigill(int sig, siginfo_t *si, void *uc) { case 0: /* match OK */ + advance_pc(uc); return; default: /* mismatch, or end of test */ @@ -42,6 +46,7 @@ void apprentice_sigill(int sig, siginfo_t *si, void *uc) { case 0: /* match OK */ + advance_pc(uc); return; case 1: /* end of test */ @@ -65,6 +70,41 @@ static void set_sigill_handler(sighandler_fn_t *fn) } } +typedef void entrypoint_fn(void); + +uint32_t image_start_address; +entrypoint_fn *image_start; + +void load_image(const char *imgfile) +{ + /* Load image file into memory as executable */ + struct stat st; + fprintf(stderr, "loading test image %s...\n", imgfile); + int fd = open(imgfile, O_RDONLY); + if (fd < 0) + { + fprintf(stderr, "failed to open image file %s\n", imgfile); + exit(1); + } + if (fstat(fd, &st) != 0) + { + perror("fstat"); + exit(1); + } + size_t len = st.st_size; + void *addr; + + addr = mmap(0, len, PROT_READ|PROT_EXEC, MAP_SHARED, fd, 0); + if (!addr) + { + perror("mmap"); + exit(1); + } + close(fd); + image_start = addr; + image_start_address = (uint32_t)addr; +} + int master(int sock) { if (sigsetjmp(jmpbuf, 1)) @@ -73,18 +113,20 @@ int master(int sock) } master_socket = sock; set_sigill_handler(master_sigill); - fprintf(stderr, "raising SIGILL\n"); - raise(SIGILL); - assert(!"should never get here"); + fprintf(stderr, "starting image\n"); + image_start(); + fprintf(stderr, "image returned unexpectedly\n"); + exit(1); } int apprentice(int sock) { apprentice_socket = sock; set_sigill_handler(apprentice_sigill); - fprintf(stderr, "raising SIGILL\n"); - raise(SIGILL); - assert(!"should never get here"); + fprintf(stderr, "starting image\n"); + image_start(); + fprintf(stderr, "image returned unexpectedly\n"); + exit(1); } int ismaster; @@ -94,8 +136,8 @@ int main(int argc, char **argv) // some handy defaults to make testing easier uint16_t port = 9191; char *hostname = "localhost"; + char *imgfile; int sock; - // TODO clean this up later @@ -143,6 +185,15 @@ int main(int argc, char **argv) } } + imgfile = argv[optind]; + if (!imgfile) + { + fprintf(stderr, "must specify image file name\n"); + exit(1); + } + + load_image(imgfile); + if (ismaster) { fprintf(stderr, "master port %d\n", port); @@ -12,7 +12,7 @@ int send_data_pkt(int sock, void *pkt, int pktlen); void recv_data_pkt(int sock, void *pkt, int pktlen); void send_response_byte(int sock, int resp); - +extern uint32_t image_start_address; /* Interface provided by CPU-specific code: */ @@ -36,4 +36,8 @@ int recv_and_compare_register_info(int sock, void *uc); */ int report_match_status(void); +/* Move the PC past this faulting insn by adjusting ucontext + */ +void advance_pc(void *uc); + #endif /* RISU_H */ diff --git a/risu_i386.c b/risu_i386.c index dc83fa1..3b5a22c 100644 --- a/risu_i386.c +++ b/risu_i386.c @@ -12,18 +12,62 @@ */ struct reginfo { + uint32_t faulting_insn; gregset_t gregs; }; +#ifndef REG_ESP +#define REG_ESP 7 +#endif +#ifndef REG_UESP +#define REG_UESP 17 +#endif +#ifndef REG_EIP +#define REG_EIP 14 +#endif + struct reginfo master_ri, apprentice_ri; +static int insn_is_ud2(uint32_t insn) +{ + return ((insn & 0xffff) == 0x0b0f); +} + +void advance_pc(void *vuc) +{ + /* We assume that this is either UD1 or UD2. + * This would need tweaking if we want to test + * expected undefs on x86. + */ + ucontext_t *uc = vuc; + uc->uc_mcontext.gregs[REG_EIP] += 2; +} + static void fill_reginfo(struct reginfo *ri, ucontext_t *uc) { int i; for (i = 0; i < NGREG; i++) { - ri->gregs[i] = uc->uc_mcontext.gregs[i]; + switch(i) + { + case REG_ESP: + case REG_UESP: + /* Don't store these registers as it results in mismatches. */ + ri->gregs[i] = 0xDEADBEEF; + break; + case REG_EIP: + /* Store the offset from the start of the test image */ + ri->gregs[i] = uc->uc_mcontext.gregs[i] - image_start_address; + break; + default: + ri->gregs[i] = uc->uc_mcontext.gregs[i]; + break; + } } + /* x86 insns aren't 32 bit but we're not really testing x86 so + * this is just to distinguish 'do compare' from 'stop' + */ + ri->faulting_insn = *((uint32_t*)uc->uc_mcontext.gregs[REG_EIP]); } @@ -40,9 +84,24 @@ int send_register_info(int sock, void *uc) */ int recv_and_compare_register_info(int sock, void *uc) { + int resp; fill_reginfo(&master_ri, uc); recv_data_pkt(sock, &apprentice_ri, sizeof(apprentice_ri)); - int resp = 1; + if (memcmp(&master_ri, &apprentice_ri, sizeof(master_ri)) != 0) + { + /* mismatch */ + resp = 2; + } + else if (insn_is_ud2(master_ri.faulting_insn)) + { + /* end of test */ + resp = 1; + } + else + { + /* either successful match or expected undef */ + resp = 0; + } send_response_byte(sock, resp); return resp; } @@ -57,6 +116,7 @@ static char *regname[] = static void dump_reginfo(struct reginfo *ri) { int i; + fprintf(stderr, " faulting insn %x\n", ri->faulting_insn); for (i = 0; i < NGREG; i++) { fprintf(stderr, " %s: %x\n", regname[i] ? regname[i] : "???", ri->gregs[i]); diff --git a/test_i386.s b/test_i386.s new file mode 100644 index 0000000..15f34f2 --- /dev/null +++ b/test_i386.s @@ -0,0 +1,16 @@ +; A trivial test image for x86 + +BITS 32 +; Initialise the registers to avoid spurious mismatches +mov eax, 0x12345678 +mov ebx, 0x9abcdef0 +mov ecx, 0x97361234 +mov edx, 0x84310284 +mov edi, 0x83624173 +mov esi, 0xfaebfaeb +mov ebp, 0x84610123 +; UD1 : do compare +UD1 + +; UD2 : exit test +UD2 |