Commit a9221de6 authored by Russell King's avatar Russell King

ARM: add notify_die() support

Kernel debuggers want to be informed of die() events, so that they
can take some action to allow the problem to be inspected.  Provide
the hook in a similar manner to x86.

Note that we currently don't implement the individual trap hooks.
Acked-by: default avatarJason Wessel <jason.wessel@windriver.com>
Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 2b0d8c25
...@@ -73,8 +73,7 @@ extern unsigned int mem_fclk_21285; ...@@ -73,8 +73,7 @@ extern unsigned int mem_fclk_21285;
struct pt_regs; struct pt_regs;
void die(const char *msg, struct pt_regs *regs, int err) void die(const char *msg, struct pt_regs *regs, int err);
__attribute__((noreturn));
struct siginfo; struct siginfo;
void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info, void arm_notify_die(const char *str, struct pt_regs *regs, struct siginfo *info,
......
...@@ -12,15 +12,17 @@ ...@@ -12,15 +12,17 @@
* 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably * 'linux/arch/arm/lib/traps.S'. Mostly a debugging aid, but will probably
* kill the offending process. * kill the offending process.
*/ */
#include <linux/module.h>
#include <linux/signal.h> #include <linux/signal.h>
#include <linux/spinlock.h>
#include <linux/personality.h> #include <linux/personality.h>
#include <linux/kallsyms.h> #include <linux/kallsyms.h>
#include <linux/delay.h> #include <linux/spinlock.h>
#include <linux/uaccess.h>
#include <linux/hardirq.h> #include <linux/hardirq.h>
#include <linux/kdebug.h>
#include <linux/module.h>
#include <linux/kexec.h>
#include <linux/delay.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/uaccess.h>
#include <asm/atomic.h> #include <asm/atomic.h>
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
...@@ -224,14 +226,21 @@ void show_stack(struct task_struct *tsk, unsigned long *sp) ...@@ -224,14 +226,21 @@ void show_stack(struct task_struct *tsk, unsigned long *sp)
#define S_SMP "" #define S_SMP ""
#endif #endif
static void __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs) static int __die(const char *str, int err, struct thread_info *thread, struct pt_regs *regs)
{ {
struct task_struct *tsk = thread->task; struct task_struct *tsk = thread->task;
static int die_counter; static int die_counter;
int ret;
printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n", printk(KERN_EMERG "Internal error: %s: %x [#%d]" S_PREEMPT S_SMP "\n",
str, err, ++die_counter); str, err, ++die_counter);
sysfs_printk_last_file(); sysfs_printk_last_file();
/* trap and error numbers are mostly meaningless on ARM */
ret = notify_die(DIE_OOPS, str, regs, err, tsk->thread.trap_no, SIGSEGV);
if (ret == NOTIFY_STOP)
return ret;
print_modules(); print_modules();
__show_regs(regs); __show_regs(regs);
printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n", printk(KERN_EMERG "Process %.*s (pid: %d, stack limit = 0x%p)\n",
...@@ -243,6 +252,8 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p ...@@ -243,6 +252,8 @@ static void __die(const char *str, int err, struct thread_info *thread, struct p
dump_backtrace(regs, tsk); dump_backtrace(regs, tsk);
dump_instr(KERN_EMERG, regs); dump_instr(KERN_EMERG, regs);
} }
return ret;
} }
DEFINE_SPINLOCK(die_lock); DEFINE_SPINLOCK(die_lock);
...@@ -250,16 +261,21 @@ DEFINE_SPINLOCK(die_lock); ...@@ -250,16 +261,21 @@ DEFINE_SPINLOCK(die_lock);
/* /*
* This function is protected against re-entrancy. * This function is protected against re-entrancy.
*/ */
NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) void die(const char *str, struct pt_regs *regs, int err)
{ {
struct thread_info *thread = current_thread_info(); struct thread_info *thread = current_thread_info();
int ret;
oops_enter(); oops_enter();
spin_lock_irq(&die_lock); spin_lock_irq(&die_lock);
console_verbose(); console_verbose();
bust_spinlocks(1); bust_spinlocks(1);
__die(str, err, thread, regs); ret = __die(str, err, thread, regs);
if (regs && kexec_should_crash(thread->task))
crash_kexec(regs);
bust_spinlocks(0); bust_spinlocks(0);
add_taint(TAINT_DIE); add_taint(TAINT_DIE);
spin_unlock_irq(&die_lock); spin_unlock_irq(&die_lock);
...@@ -267,11 +283,10 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err) ...@@ -267,11 +283,10 @@ NORET_TYPE void die(const char *str, struct pt_regs *regs, int err)
if (in_interrupt()) if (in_interrupt())
panic("Fatal exception in interrupt"); panic("Fatal exception in interrupt");
if (panic_on_oops) if (panic_on_oops)
panic("Fatal exception"); panic("Fatal exception");
if (ret != NOTIFY_STOP)
do_exit(SIGSEGV); do_exit(SIGSEGV);
} }
void arm_notify_die(const char *str, struct pt_regs *regs, void arm_notify_die(const char *str, struct pt_regs *regs,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment