summaryrefslogtreecommitdiffstats
path: root/arch/sh/kernel/traps.c
diff options
context:
space:
mode:
authorAnton Arapov <anton@redhat.com>2012-10-29 11:15:37 +0100
committerAnton Arapov <anton@redhat.com>2012-10-29 11:15:37 +0100
commit7d558cd9c7b18e4b16953265aa0da45e63f3b968 (patch)
tree7135d5a810768c9c619346282ee9cfdf1765e225 /arch/sh/kernel/traps.c
parent985ef6b2108ed28ffd5f6630e1e0fce2e2a775f2 (diff)
downloadkernel-uprobes-f17.tar.gz
kernel-uprobes-f17.tar.xz
kernel-uprobes-f17.zip
fedora kernel: cd394142aac30b5c751f25b517572e2448695641v3.6.3-2f17
Signed-off-by: Anton Arapov <anton@redhat.com>
Diffstat (limited to 'arch/sh/kernel/traps.c')
-rw-r--r--arch/sh/kernel/traps.c71
1 files changed, 71 insertions, 0 deletions
diff --git a/arch/sh/kernel/traps.c b/arch/sh/kernel/traps.c
index a87e58a9e38..72246bc0688 100644
--- a/arch/sh/kernel/traps.c
+++ b/arch/sh/kernel/traps.c
@@ -6,9 +6,80 @@
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h>
+#include <linux/kernel.h>
+#include <linux/kexec.h>
+#include <linux/module.h>
#include <asm/unwinder.h>
#include <asm/traps.h>
+static DEFINE_SPINLOCK(die_lock);
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+ static int die_counter;
+
+ oops_enter();
+
+ spin_lock_irq(&die_lock);
+ console_verbose();
+ bust_spinlocks(1);
+
+ printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
+ print_modules();
+ show_regs(regs);
+
+ printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
+ task_pid_nr(current), task_stack_page(current) + 1);
+
+ if (!user_mode(regs) || in_interrupt())
+ dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
+ (unsigned long)task_stack_page(current));
+
+ notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
+
+ bust_spinlocks(0);
+ add_taint(TAINT_DIE);
+ spin_unlock_irq(&die_lock);
+ oops_exit();
+
+ if (kexec_should_crash(current))
+ crash_kexec(regs);
+
+ if (in_interrupt())
+ panic("Fatal exception in interrupt");
+
+ if (panic_on_oops)
+ panic("Fatal exception");
+
+ do_exit(SIGSEGV);
+}
+
+void die_if_kernel(const char *str, struct pt_regs *regs, long err)
+{
+ if (!user_mode(regs))
+ die(str, regs, err);
+}
+
+/*
+ * try and fix up kernelspace address errors
+ * - userspace errors just cause EFAULT to be returned, resulting in SEGV
+ * - kernel/userspace interfaces cause a jump to an appropriate handler
+ * - other kernel errors are bad
+ */
+void die_if_no_fixup(const char *str, struct pt_regs *regs, long err)
+{
+ if (!user_mode(regs)) {
+ const struct exception_table_entry *fixup;
+ fixup = search_exception_tables(regs->pc);
+ if (fixup) {
+ regs->pc = fixup->fixup;
+ return;
+ }
+
+ die(str, regs, err);
+ }
+}
+
#ifdef CONFIG_GENERIC_BUG
static void handle_BUG(struct pt_regs *regs)
{