diff --git a/Makefile b/Makefile index 4aad448..6ab014a 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ VPATH=$(SRCDIR) CFLAGS ?= -g -ALL_CFLAGS = -Wall -D_GNU_SOURCE -DARCH=$(ARCH) $(BUILD_INC) $(CFLAGS) $(EXTRA_CFLAGS) +ALL_CFLAGS = -Wall -D_GNU_SOURCE -DARCH=$(ARCH) -U$(ARCH) $(BUILD_INC) $(CFLAGS) $(EXTRA_CFLAGS) PROG=risu SRCS=risu.c comms.c reginfo.c risu_$(ARCH).c risu_reginfo_$(ARCH).c @@ -49,6 +49,9 @@ $(PROG): $(OBJS) %_$(ARCH).elf: %_$(ARCH).s $(AS) -o $@ $< +%_$(ARCH).elf: %_$(ARCH).S + $(CC) $(CPPFLAGS) -o $@ -c $< + clean: rm -f $(PROG) $(OBJS) $(BINS) diff --git a/risu_reginfo_i386.h b/risu_reginfo_i386.h new file mode 100644 index 0000000..755283a --- /dev/null +++ b/risu_reginfo_i386.h @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2010 Linaro Limited + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Peter Maydell (Linaro) - initial implementation + ******************************************************************************/ + +#ifndef RISU_REGINFO_I386_H +#define RISU_REGINFO_I386_H + +/* + * This is the data structure we pass over the socket. + * It is a simplified and reduced subset of what can + * be obtained with a ucontext_t* + */ +struct reginfo { + uint32_t faulting_insn; + gregset_t gregs; +}; + +/* + * For i386, the defines are named REG_EAX, etc. + * For x86_64, the defines are name REG_RAX, etc. + */ +#ifdef __x86_64__ +# define REG_E(X) REG_R##X +#else +# define REG_E(X) REG_E##X +#endif + +#endif /* RISU_REGINFO_I386_H */ diff --git a/risu_i386.c b/risu_i386.c index 5e7e01d..9962b8f 100644 --- a/risu_i386.c +++ b/risu_i386.c @@ -14,147 +14,39 @@ #include #include "risu.h" - -/* This is the data structure we pass over the socket. - * It is a simplified and reduced subset of what can - * be obtained with a ucontext_t* - */ -struct reginfo { - uint32_t faulting_insn; - gregset_t gregs; -}; - -#ifndef REG_GS -/* Assume that either we get all these defines or none */ -#define REG_GS 0 -#define REG_FS 1 -#define REG_ES 2 -#define REG_DS 3 -#define REG_ESP 7 -#define REG_TRAPNO 12 -#define REG_EIP 14 -#define REG_EFL 16 -#define REG_UESP 17 -#endif - -struct reginfo master_ri, apprentice_ri; - -static int insn_is_ud2(uint32_t insn) -{ - return ((insn & 0xffff) == 0x0b0f); -} +#include "risu_reginfo_i386.h" 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 = (ucontext_t *) vuc; + + /* + * We assume that this is UD1 as per get_risuop below. + * This would need tweaking if we want to test expected undefs. */ - ucontext_t *uc = vuc; - uc->uc_mcontext.gregs[REG_EIP] += 2; + uc->uc_mcontext.gregs[REG_E(IP)] += 3; } -static void fill_reginfo(struct reginfo *ri, ucontext_t * uc) +void set_ucontext_paramreg(void *vuc, uint64_t value) { - int i; - for (i = 0; i < NGREG; i++) { - switch (i) { - case REG_ESP: - case REG_UESP: - case REG_GS: - case REG_FS: - case REG_ES: - case REG_DS: - case REG_TRAPNO: - case REG_EFL: - /* Don't store these registers as it results in mismatches. - * In particular valgrind has different values for some - * segment registers, and they're boring anyway. - * We really shouldn't be ignoring EFL but valgrind doesn't - * seem to set it right and I don't care to investigate. - */ - 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; - } + ucontext_t *uc = (ucontext_t *) vuc; + uc->uc_mcontext.gregs[REG_E(AX)] = value; +} + +uint64_t get_reginfo_paramreg(struct reginfo *ri) +{ + return ri->gregs[REG_E(AX)]; +} + +int get_risuop(struct reginfo *ri) +{ + if ((ri->faulting_insn & 0xf8ffff) == 0xc0b90f) { /* UD1 %xxx,%eax */ + return (ri->faulting_insn >> 16) & 7; } - /* 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]); + return -1; } - -int send_register_info(int sock, void *uc) +uintptr_t get_pc(struct reginfo *ri) { - struct reginfo ri; - fill_reginfo(&ri, uc); - return send_data_pkt(sock, &ri, sizeof(ri)); -} - -/* Read register info from the socket and compare it with that from the - * ucontext. Return 0 for match, 1 for end-of-test, 2 for mismatch. - * NB: called from a signal handler. - */ -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)); - 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; -} - -static char *regname[] = { - "GS", "FS", "ES", "DS", "EDI", "ESI", "EBP", "ESP", - "EBX", "EDX", "ECX", "EAX", "TRAPNO", "ERR", "EIP", - "CS", "EFL", "UESP", "SS", 0 -}; - -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]); - } -} - - -/* Print a useful report on the status of the last comparison - * done in recv_and_compare_register_info(). This is called on - * exit, so need not restrict itself to signal-safe functions. - * Should return 0 if it was a good match (ie end of test) - * and 1 for a mismatch. - */ -int report_match_status(void) -{ - fprintf(stderr, "match status...\n"); - fprintf(stderr, "master reginfo:\n"); - dump_reginfo(&master_ri); - fprintf(stderr, "apprentice reginfo:\n"); - dump_reginfo(&apprentice_ri); - if (memcmp(&master_ri, &apprentice_ri, sizeof(master_ri)) == 0) { - fprintf(stderr, "match!\n"); - return 0; - } - fprintf(stderr, "mismatch!\n"); - return 1; + return ri->gregs[REG_E(IP)]; } diff --git a/risu_reginfo_i386.c b/risu_reginfo_i386.c new file mode 100644 index 0000000..c4dc14a --- /dev/null +++ b/risu_reginfo_i386.c @@ -0,0 +1,153 @@ +/******************************************************************************* + * Copyright (c) 2010 Linaro Limited + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Peter Maydell (Linaro) - initial implementation + ******************************************************************************/ + +#include +#include +#include +#include +#include + +#include "risu.h" +#include "risu_reginfo_i386.h" + +const struct option * const arch_long_opts; +const char * const arch_extra_help; + +void process_arch_opt(int opt, const char *arg) +{ + abort(); +} + +const int reginfo_size(void) +{ + return sizeof(struct reginfo); +} + +/* reginfo_init: initialize with a ucontext */ +void reginfo_init(struct reginfo *ri, ucontext_t *uc) +{ + int i; + + memset(ri, 0, sizeof(*ri)); + + for (i = 0; i < NGREG; i++) { + switch (i) { + case REG_E(IP): + /* Store the offset from the start of the test image. */ + ri->gregs[i] = uc->uc_mcontext.gregs[i] - image_start_address; + break; + case REG_EFL: + /* Store only the "flaggy" bits: SF, ZF, AF, PF, CF. */ + ri->gregs[i] = uc->uc_mcontext.gregs[i] & 0xd5; + break; + case REG_E(SP): + /* Ignore the stack. */ + ri->gregs[i] = 0xdeadbeef; + break; + case REG_E(AX): + case REG_E(BX): + case REG_E(CX): + case REG_E(DX): + case REG_E(DI): + case REG_E(SI): + case REG_E(BP): +#ifdef __x86_64__ + case REG_R8: + case REG_R9: + case REG_R10: + case REG_R11: + case REG_R12: + case REG_R13: + case REG_R14: + case REG_R15: +#endif + ri->gregs[i] = uc->uc_mcontext.gregs[i]; + break; + } + } + + /* + * x86 insns aren't 32 bit but 3 bytes are sufficient to + * distinguish 'do compare' from 'stop'. + */ + ri->faulting_insn = *(uint32_t *)uc->uc_mcontext.gregs[REG_E(IP)]; +} + +/* reginfo_is_eq: compare the reginfo structs, returns nonzero if equal */ +int reginfo_is_eq(struct reginfo *m, struct reginfo *a) +{ + return 0 == memcmp(m, a, sizeof(*m)); +} + +static const char *const regname[NGREG] = { + [REG_EFL] = "eflags", +#ifdef __x86_64__ + [REG_RIP] = "rip", + [REG_RAX] = "rax", + [REG_RBX] = "rbx", + [REG_RCX] = "rcx", + [REG_RDX] = "rdx", + [REG_RDI] = "rdi", + [REG_RSI] = "rsi", + [REG_RBP] = "rbp", + [REG_RSP] = "rsp", + [REG_R8] = "r8", + [REG_R9] = "r9", + [REG_R10] = "r10", + [REG_R11] = "r11", + [REG_R12] = "r12", + [REG_R13] = "r13", + [REG_R14] = "r14", + [REG_R15] = "r15", +#else + [REG_EIP] = "eip", + [REG_EAX] = "eax", + [REG_EBX] = "ebx", + [REG_ECX] = "ecx", + [REG_EDX] = "edx", + [REG_EDI] = "edi", + [REG_ESI] = "esi", + [REG_EBP] = "ebp", + [REG_ESP] = "esp", +#endif +}; + +#ifdef __x86_64__ +# define PRIxREG "%016llx" +#else +# define PRIxREG "%08x" +#endif + +/* reginfo_dump: print state to a stream, returns nonzero on success */ +int reginfo_dump(struct reginfo *ri, FILE *f) +{ + int i; + fprintf(f, " faulting insn %x\n", ri->faulting_insn); + for (i = 0; i < NGREG; i++) { + if (regname[i]) { + fprintf(f, " %-6s: " PRIxREG "\n", regname[i], ri->gregs[i]); + } + } + return !ferror(f); +} + +int reginfo_dump_mismatch(struct reginfo *m, struct reginfo *a, FILE *f) +{ + int i; + for (i = 0; i < NGREG; i++) { + if (m->gregs[i] != a->gregs[i]) { + assert(regname[i]); + fprintf(f, "Mismatch: %s: " PRIxREG " v " PRIxREG "\n", + regname[i], m->gregs[i], a->gregs[i]); + } + } + return !ferror(f); +} diff --git a/configure b/configure index 65e1819..ca2d7db 100755 --- a/configure +++ b/configure @@ -48,12 +48,14 @@ EOF } guess_arch() { - if check_define __m68k__ ; then - ARCH="m68k" + if check_define __aarch64__ ; then + ARCH="aarch64" elif check_define __arm__ ; then ARCH="arm" - elif check_define __aarch64__ ; then - ARCH="aarch64" + elif check_define __i386__ || check_define __x86_64__ ; then + ARCH="i386" + elif check_define __m68k__ ; then + ARCH="m68k" elif check_define __powerpc64__ ; then ARCH="ppc64" else diff --git a/test_i386.S b/test_i386.S new file mode 100644 index 0000000..456b99c --- /dev/null +++ b/test_i386.S @@ -0,0 +1,41 @@ +/*############################################################################# + * Copyright (c) 2010 Linaro Limited + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Peter Maydell (Linaro) - initial implementation + *###########################################################################*/ + +/* A trivial test image for x86 */ + +/* Initialise the registers to avoid spurious mismatches */ + xor %eax, %eax + sahf /* init eflags */ + + mov $0x12345678, %eax + mov $0x9abcdef0, %ebx + mov $0x97361234, %ecx + mov $0x84310284, %edx + mov $0x83624173, %edi + mov $0xfaebfaeb, %esi + mov $0x84610123, %ebp + +#ifdef __x86_64__ + movq $0x123456789abcdef0, %r8 + movq $0xaaaabbbbccccdddd, %r9 + movq $0x1010101010101010, %r10 + movq $0x1111111111111111, %r11 + movq $0x1212121212121212, %r12 + movq $0x1313131313131313, %r13 + movq $0x1414141414141414, %r14 + movq $0x1515151515151515, %r15 +#endif + +/* do compare */ + ud1 %eax, %eax + +/* exit test */ + ud1 %ecx, %eax diff --git a/test_i386.s b/test_i386.s deleted file mode 100644 index a2140a0..0000000 --- a/test_i386.s +++ /dev/null @@ -1,27 +0,0 @@ -;############################################################################### -;# Copyright (c) 2010 Linaro Limited -;# All rights reserved. This program and the accompanying materials -;# are made available under the terms of the Eclipse Public License v1.0 -;# which accompanies this distribution, and is available at -;# http://www.eclipse.org/legal/epl-v10.html -;# -;# Contributors: -;# Peter Maydell (Linaro) - initial implementation -;############################################################################### - -; 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