]> xenbits.xensource.com Git - people/royger/xen-test-framework.git/commitdiff
Exception Logging support
authorAndrew Cooper <andrew.cooper3@citrix.com>
Mon, 21 Dec 2015 10:47:22 +0000 (10:47 +0000)
committerAndrew Cooper <andrew.cooper3@citrix.com>
Tue, 22 Dec 2015 20:57:37 +0000 (20:57 +0000)
Provide an interface whereby a test can log all exceptions which occur, and
query the log after the fact.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
arch/x86/traps.c
build/files.mk
common/exlog.c [new file with mode: 0644]
include/xtf/exlog.h [new file with mode: 0644]
include/xtf/lib.h
tests/selftest/main.c

index c28becbf034e4e10f88b0f647b6e1d79b68a8acd..9557bdee574f348fa43138efe6dd744ef4c271d9 100644 (file)
@@ -1,5 +1,6 @@
 #include <xtf/lib.h>
 #include <xtf/traps.h>
+#include <xtf/exlog.h>
 
 #include <arch/x86/processor.h>
 
@@ -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)) )
     {
index 28fea2b50c153144408f71b3739cc7d74f6f1eeb..b09d3026fca74c1e2faf9a33f74ecec319db0e66 100644 (file)
@@ -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 (file)
index 0000000..b347a49
--- /dev/null
@@ -0,0 +1,82 @@
+#include <xtf/lib.h>
+#include <xtf/exlog.h>
+
+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 (file)
index 0000000..a17c908
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef XTF_EXLOG_H
+#define XTF_EXLOG_H
+
+#include <xtf/types.h>
+#include <arch/x86/regs.h>
+
+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:
+ */
index c40f8f2690e676c0482b34cd56e7cef2de9a9311..b4a75798d1bd92935a5bd304e6a77029ea7cb5db 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <xtf/types.h>
 #include <xtf/compiler.h>
+#include <xtf/console.h>
 #include <xtf/numbers.h>
 
 #include <arch/x86/lib.h>
index fed4c22add3841a8f20948f51298e0b6d99f8f09..2595fba694b7a1c0136189b8f44aec1efb246435 100644 (file)
@@ -3,6 +3,10 @@
 #include <xtf/console.h>
 
 #include <xtf/traps.h>
+#include <xtf/exlog.h>
+
+#include <arch/x86/processor.h>
+#include <arch/x86/segment.h>
 
 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();
 }