From: Andrew Cooper Date: Mon, 21 Dec 2015 10:47:22 +0000 (+0000) Subject: Exception Logging support X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=20767defd3ab3e519e8a9d9892bdfded5892f26d;p=people%2Froyger%2Fxen-test-framework.git Exception Logging support Provide an interface whereby a test can log all exceptions which occur, and query the log after the fact. Signed-off-by: Andrew Cooper --- diff --git a/arch/x86/traps.c b/arch/x86/traps.c index c28becb..9557bde 100644 --- a/arch/x86/traps.c +++ b/arch/x86/traps.c @@ -1,5 +1,6 @@ #include #include +#include #include @@ -59,6 +60,8 @@ void do_exception(struct cpu_regs *regs) unsigned long fixup_addr; bool safe = is_trap_or_interrupt(regs); + xtf_exlog_log_exception(regs); + /* Look in the exception table to see if a redirection has been set up. */ if ( !safe && (fixup_addr = search_extable(regs->ip)) ) { diff --git a/build/files.mk b/build/files.mk index 28fea2b..b09d302 100644 --- a/build/files.mk +++ b/build/files.mk @@ -5,6 +5,7 @@ # obj-$(env) are objects unique to a specific environment obj-perarch += $(ROOT)/common/console.o +obj-perarch += $(ROOT)/common/exlog.o obj-perarch += $(ROOT)/common/extable.o obj-perarch += $(ROOT)/common/heapsort.o obj-perarch += $(ROOT)/common/lib.o diff --git a/common/exlog.c b/common/exlog.c new file mode 100644 index 0000000..b347a49 --- /dev/null +++ b/common/exlog.c @@ -0,0 +1,82 @@ +#include +#include + +static bool logging = false; +static unsigned int log_entries; + +static exlog_entry_t log[8]; + +void xtf_exlog_start(void) +{ + logging = true; + log_entries = 0; +} + +void xtf_exlog_reset(void) +{ + log_entries = 0; +} + +void xtf_exlog_stop(void) +{ + logging = false; +} + + +unsigned int xtf_exlog_entries(void) +{ + return log_entries; +} + +exlog_entry_t *xtf_exlog_entry(unsigned int idx) +{ + if ( idx < ARRAY_SIZE(log) && idx < log_entries ) + return &log[idx]; + return NULL; +} + +void xtf_exlog_log_exception(struct cpu_regs *regs) +{ + if ( !logging ) + return; + + if ( log_entries < ARRAY_SIZE(log) ) + { + exlog_entry_t *e = &log[log_entries]; + + e->ip = regs->ip; + e->cs = regs->cs; + e->ec = regs->error_code; + e->ev = regs->entry_vector; + } + else + { + printk("Exception log full\n"); + xtf_exlog_dump_log(); + panic("Exception log full\n"); + } + + log_entries++; +} + +void xtf_exlog_dump_log(void) +{ + unsigned int i; + + if ( log_entries == 0 ) + printk("No exception log entries\n"); + else + for ( i = 0; i < ARRAY_SIZE(log) && i < log_entries; ++i ) + printk(" exlog[%02u] %04x:%p vec %u[%04x]\n", + i, log[i].cs, _p(log[i].ip), log[i].ev, log[i].ec); +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xtf/exlog.h b/include/xtf/exlog.h new file mode 100644 index 0000000..a17c908 --- /dev/null +++ b/include/xtf/exlog.h @@ -0,0 +1,34 @@ +#ifndef XTF_EXLOG_H +#define XTF_EXLOG_H + +#include +#include + +void xtf_exlog_start(void); +void xtf_exlog_reset(void); +void xtf_exlog_stop(void); + +typedef struct exlog_entry +{ + unsigned long ip; + uint16_t cs, ec, ev; +} exlog_entry_t; + +unsigned int xtf_exlog_entries(void); +exlog_entry_t *xtf_exlog_entry(unsigned int idx); + +void xtf_exlog_log_exception(struct cpu_regs *regs); + +void xtf_exlog_dump_log(void); + +#endif /* XTF_EXLOG_H */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/include/xtf/lib.h b/include/xtf/lib.h index c40f8f2..b4a7579 100644 --- a/include/xtf/lib.h +++ b/include/xtf/lib.h @@ -3,6 +3,7 @@ #include #include +#include #include #include diff --git a/tests/selftest/main.c b/tests/selftest/main.c index fed4c22..2595fba 100644 --- a/tests/selftest/main.c +++ b/tests/selftest/main.c @@ -3,6 +3,10 @@ #include #include +#include + +#include +#include static void test_int3_breakpoint(void) { @@ -26,12 +30,113 @@ static void test_extable(void) _ASM_EXTABLE(1b, 2b)); } +static bool check_nr_entries(unsigned int nr) +{ + unsigned int entries = xtf_exlog_entries(); + + if ( entries != nr ) + { + xtf_failure("Fail: expected %u entries, got %u\n", + nr, entries); + return false; + } + + return true; +} + +static bool check_exlog_entry(unsigned int entry, unsigned int cs, + unsigned long ip, unsigned int ev, + unsigned int ec) +{ + exlog_entry_t *e = xtf_exlog_entry(entry); + + /* Check whether the log entry is available. */ + if ( !e ) + { + xtf_failure("Fail: unable to retrieve log entry %u\n", entry); + return false; + } + + /* Check whether the log entry is correct. */ + if ( (e->ip != ip) || (e->cs != cs) || (e->ec != ec) || (e->ev != ev) ) + { + xtf_failure("Fail: exlog entry:\n" + " Expected: %04x:%p, ec %04x, vec %u\n" + " Got: %04x:%p, ec %04x, vec %u\n", + cs, _p(ip), ec, ev, e->cs, _p(e->ip), e->ec, e->ev); + return false; + } + + return true; +} + +static void test_exlog(void) +{ + extern unsigned long label_test_exlog_int3[], label_test_exlog_ud2a[]; + + printk("Test: Exception Logging\n"); + + xtf_exlog_start(); + + /* Check that no entries have been logged thus far. */ + if ( !check_nr_entries(0) ) + goto out; + + asm volatile ("int3; label_test_exlog_int3:"); + + /* Check that one entry has now been logged. */ + if ( !check_nr_entries(1) || + !check_exlog_entry(0, __KERN_CS, + (unsigned long)&label_test_exlog_int3, + X86_EXC_BP, 0) ) + goto out; + + asm volatile ("label_test_exlog_ud2a: ud2a; 1:" + _ASM_EXTABLE(label_test_exlog_ud2a, 1b)); + + /* Check that two entries have now been logged. */ + if ( !check_nr_entries(2) || + !check_exlog_entry(1, __KERN_CS, + (unsigned long)&label_test_exlog_ud2a, + X86_EXC_UD, 0) ) + goto out; + + xtf_exlog_reset(); + + /* Check that no entries now exist. */ + if ( !check_nr_entries(0) ) + goto out; + + asm volatile ("int3"); + + /* Check that one entry now exists. */ + if ( !check_nr_entries(1) ) + goto out; + + xtf_exlog_stop(); + + /* Check that one entry still exists. */ + if ( !check_nr_entries(1) ) + goto out; + + asm volatile ("int3"); + + /* Check that the previous breakpoint wasn't logged. */ + if ( !check_nr_entries(1) ) + goto out; + + out: + xtf_exlog_reset(); + xtf_exlog_stop(); +} + void test_main(void) { printk("XTF Selftests\n"); test_int3_breakpoint(); test_extable(); + test_exlog(); xtf_success(); }