This ensures that DTrace memory access faults are non-fatal.
Signed-off-by: Kris Van Hees <kris.van.hees@oracle.com>
/*
* Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice:
+ * terminate things with extreme prejudice, unless a notifier decides
+ * to let this one slide.
*/
+ if (notify_die(DIE_PAGE_FAULT, "page fault", regs, error_code, 14,
+ SIGKILL) == NOTIFY_STOP)
+ return;
+
flags = oops_begin();
show_fault_oops(regs, error_code, address);
--- /dev/null
+#ifndef _DTRACE_CPU_H_
+#define _DTRACE_CPU_H_
+
+#include <linux/ktime.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+
+#define CPUC_SIZE (sizeof (uint16_t) + sizeof(uint8_t) + \
+ sizeof(uintptr_t) + sizeof(struct mutex))
+#define CPUC_PADSIZE (192 - CPUC_SIZE)
+
+typedef struct cpu_core {
+ uint16_t cpuc_dtrace_flags;
+ uint8_t cpuc_dcpc_intr_state;
+ uint8_t cpuc_pad[CPUC_PADSIZE];
+ uintptr_t cpuc_dtrace_illval;
+ struct mutex cpuc_pid_lock;
+
+ uintptr_t cpu_dtrace_caller;
+ ktime_t cpu_dtrace_chillmark;
+ ktime_t cpu_dtrace_chilled;
+} cpu_core_t;
+
+DECLARE_PER_CPU_SHARED_ALIGNED(cpu_core_t, dtrace_cpu_info);
+
+#define per_cpu_core(cpu) (&per_cpu(dtrace_cpu_info, (cpu)))
+#define this_cpu_core (&__get_cpu_var(dtrace_cpu_info))
+
+#define DTRACE_CPUFLAG_ISSET(flag) \
+ (this_cpu_core->cpuc_dtrace_flags & (flag))
+
+#define DTRACE_CPUFLAG_SET(flag) \
+ (this_cpu_core->cpuc_dtrace_flags |= (flag))
+
+#define DTRACE_CPUFLAG_CLEAR(flag) \
+ (this_cpu_core->cpuc_dtrace_flags &= ~(flag))
+
+#define CPU_DTRACE_NOFAULT 0x0001
+#define CPU_DTRACE_DROP 0x0002
+#define CPU_DTRACE_BADADDR 0x0004
+#define CPU_DTRACE_BADALIGN 0x0008
+#define CPU_DTRACE_DIVZERO 0x0010
+#define CPU_DTRACE_ILLOP 0x0020
+#define CPU_DTRACE_NOSCRATCH 0x0040
+#define CPU_DTRACE_KPRIV 0x0080
+#define CPU_DTRACE_UPRIV 0x0100
+#define CPU_DTRACE_TUPOFLOW 0x0200
+#define CPU_DTRACE_ENTRY 0x0800
+#define CPU_DTRACE_BADSTACK 0x1000
+
+#define CPU_DTRACE_FAULT (CPU_DTRACE_BADADDR | CPU_DTRACE_BADALIGN | \
+ CPU_DTRACE_DIVZERO | CPU_DTRACE_ILLOP | \
+ CPU_DTRACE_NOSCRATCH | CPU_DTRACE_KPRIV | \
+ CPU_DTRACE_UPRIV | CPU_DTRACE_TUPOFLOW | \
+ CPU_DTRACE_BADSTACK)
+#define CPU_DTRACE_ERROR (CPU_DTRACE_FAULT | CPU_DTRACE_DROP)
+
+#endif /* _DTRACE_CPU_H_ */
GCOV_PROFILE := y
ifdef CONFIG_DT_CORE
-obj-y += dtrace_os.o dtrace_stubs_x86_64.o \
- sdt_register.o
+obj-y += dtrace_os.o dtrace_cpu.o \
+ dtrace_stubs_x86_64.o sdt_register.o
endif
--- /dev/null
+/*
+ * FILE: dtrace_cpu.c
+ * DESCRIPTION: Dynamic Tracing: CPU info - part of kernel core
+ *
+ * Copyright (C) 2010, 2011 Oracle Corporation
+ */
+
+#include <linux/dtrace_cpu.h>
+#include <asm/percpu.h>
+
+DEFINE_PER_CPU_SHARED_ALIGNED(cpu_core_t, dtrace_cpu_info);
+EXPORT_PER_CPU_SYMBOL(dtrace_cpu_info);
*/
#include <linux/cyclic.h>
+#include <linux/dtrace_cpu.h>
#include <linux/dtrace_os.h>
+#include <linux/fs.h>
#include <linux/hrtimer.h>
#include <linux/kdebug.h>
#include <linux/module.h>
+#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
+#include <asm/insn.h>
#include <asm/stacktrace.h>
-
-#include <linux/fs.h>
-#include <linux/sched.h>
#include <asm/syscalls.h>
/*
dtrace_invop_hdlr_t *hdlr;
int rval = 0;
+ if (val == DIE_PAGE_FAULT) {
+ unsigned long addr = read_cr2();
+ struct insn insn;
+
+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))
+ return NOTIFY_DONE;
+
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_BADADDR);
+ this_cpu_core->cpuc_dtrace_illval = addr;
+
+ kernel_insn_init(&insn, (void *)dargs->regs->ip);
+ insn_get_length(&insn);
+
+ dargs->regs->ip += insn.length;
+
+ return NOTIFY_OK | NOTIFY_STOP_MASK;
+ }
+ if (val == DIE_GPF) {
+ struct insn insn;
+
+ if (!DTRACE_CPUFLAG_ISSET(CPU_DTRACE_NOFAULT))
+ return NOTIFY_DONE;
+
+ DTRACE_CPUFLAG_SET(CPU_DTRACE_ILLOP);
+
+ kernel_insn_init(&insn, (void *)dargs->regs->ip);
+ insn_get_length(&insn);
+
+ dargs->regs->ip += insn.length;
+
+ return NOTIFY_DONE;
+ }
+
if (val != DIE_TRAP || dargs->trapnr != 6)
return NOTIFY_DONE;
-printk(KERN_INFO "dtrace_die_notifier: TRAP %d, IP %lx\n", dargs->trapnr, dargs->regs->ip);
for (hdlr = dtrace_invop_hdlrs; hdlr != NULL; hdlr = hdlr->dtih_next) {
if ((rval = hdlr->dtih_func(dargs->regs)) != 0)
if (rval != 0) {
dargs->regs->ip++;
-printk(KERN_INFO "dtrace_die_notifier: TRAP %d, New IP %lx\n", dargs->trapnr, dargs->regs->ip);
return NOTIFY_OK | NOTIFY_STOP_MASK;
}