aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile8
-rw-r--r--risu.c65
-rw-r--r--risu.h6
-rw-r--r--risu_i386.c64
-rw-r--r--test_i386.s16
6 files changed, 149 insertions, 11 deletions
diff --git a/.gitignore b/.gitignore
index 54caa25..6713c56 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
# Ignore binaries and any lurking coredumps
*.o
+*.bin
risu
core
diff --git a/Makefile b/Makefile
index 0dc8871..b7319e1 100644
--- a/Makefile
+++ b/Makefile
@@ -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)
diff --git a/risu.c b/risu.c
index 9d58dbd..75cfd32 100644
--- a/risu.c
+++ b/risu.c
@@ -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);
diff --git a/risu.h b/risu.h
index 8964e30..a594cc4 100644
--- a/risu.h
+++ b/risu.h
@@ -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