--- /dev/null
+#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:
+ */
--- /dev/null
+#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:
+ */
#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)
{
_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();
}