|
@@ -1,16 +1,15 @@
|
|
|
-/* $Id: traps.c,v 1.17 2004/05/02 01:46:30 sugioka Exp $
|
|
|
- *
|
|
|
- * linux/arch/sh/traps.c
|
|
|
+/*
|
|
|
+ * 'traps.c' handles hardware traps and faults after we have saved some
|
|
|
+ * state in 'entry.S'.
|
|
|
*
|
|
|
* SuperH version: Copyright (C) 1999 Niibe Yutaka
|
|
|
* Copyright (C) 2000 Philipp Rumpf
|
|
|
* Copyright (C) 2000 David Howells
|
|
|
- * Copyright (C) 2002, 2003 Paul Mundt
|
|
|
- */
|
|
|
-
|
|
|
-/*
|
|
|
- * 'Traps.c' handles hardware traps and faults after we have saved some
|
|
|
- * state in 'entry.S'.
|
|
|
+ * Copyright (C) 2002 - 2006 Paul Mundt
|
|
|
+ *
|
|
|
+ * This file is subject to the terms and conditions of the GNU General Public
|
|
|
+ * License. See the file "COPYING" in the main directory of this archive
|
|
|
+ * for more details.
|
|
|
*/
|
|
|
#include <linux/sched.h>
|
|
|
#include <linux/kernel.h>
|
|
@@ -53,13 +52,32 @@
|
|
|
#define TRAP_ILLEGAL_SLOT_INST 13
|
|
|
#endif
|
|
|
|
|
|
-/*
|
|
|
- * These constants are for searching for possible module text
|
|
|
- * segments. VMALLOC_OFFSET comes from mm/vmalloc.c; MODULE_RANGE is
|
|
|
- * a guess of how much space is likely to be vmalloced.
|
|
|
- */
|
|
|
-#define VMALLOC_OFFSET (8*1024*1024)
|
|
|
-#define MODULE_RANGE (8*1024*1024)
|
|
|
+static void dump_mem(const char *str, unsigned long bottom, unsigned long top)
|
|
|
+{
|
|
|
+ unsigned long p;
|
|
|
+ int i;
|
|
|
+
|
|
|
+ printk("%s(0x%08lx to 0x%08lx)\n", str, bottom, top);
|
|
|
+
|
|
|
+ for (p = bottom & ~31; p < top; ) {
|
|
|
+ printk("%04lx: ", p & 0xffff);
|
|
|
+
|
|
|
+ for (i = 0; i < 8; i++, p += 4) {
|
|
|
+ unsigned int val;
|
|
|
+
|
|
|
+ if (p < bottom || p >= top)
|
|
|
+ printk(" ");
|
|
|
+ else {
|
|
|
+ if (__get_user(val, (unsigned int __user *)p)) {
|
|
|
+ printk("\n");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ printk("%08x ", val);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ printk("\n");
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
DEFINE_SPINLOCK(die_lock);
|
|
|
|
|
@@ -69,14 +87,28 @@ void die(const char * str, struct pt_regs * regs, long err)
|
|
|
|
|
|
console_verbose();
|
|
|
spin_lock_irq(&die_lock);
|
|
|
+ bust_spinlocks(1);
|
|
|
+
|
|
|
printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
|
|
|
+
|
|
|
CHK_REMOTE_DEBUG(regs);
|
|
|
+ print_modules();
|
|
|
show_regs(regs);
|
|
|
+
|
|
|
+ printk("Process: %s (pid: %d, stack limit = %p)\n",
|
|
|
+ current->comm, current->pid, 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));
|
|
|
+
|
|
|
+ bust_spinlocks(0);
|
|
|
spin_unlock_irq(&die_lock);
|
|
|
do_exit(SIGSEGV);
|
|
|
}
|
|
|
|
|
|
-static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err)
|
|
|
+static inline void die_if_kernel(const char *str, struct pt_regs *regs,
|
|
|
+ long err)
|
|
|
{
|
|
|
if (!user_mode(regs))
|
|
|
die(str, regs, err);
|
|
@@ -93,8 +125,7 @@ static int handle_unaligned_notify_count = 10;
|
|
|
*/
|
|
|
static int die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
|
|
|
{
|
|
|
- if (!user_mode(regs))
|
|
|
- {
|
|
|
+ if (!user_mode(regs)) {
|
|
|
const struct exception_table_entry *fixup;
|
|
|
fixup = search_exception_tables(regs->pc);
|
|
|
if (fixup) {
|
|
@@ -734,52 +765,43 @@ void __init trap_init(void)
|
|
|
per_cpu_trap_init();
|
|
|
}
|
|
|
|
|
|
-void show_stack(struct task_struct *tsk, unsigned long *sp)
|
|
|
+void show_trace(struct task_struct *tsk, unsigned long *sp,
|
|
|
+ struct pt_regs *regs)
|
|
|
{
|
|
|
- unsigned long *stack, addr;
|
|
|
- unsigned long module_start = VMALLOC_START;
|
|
|
- unsigned long module_end = VMALLOC_END;
|
|
|
- int i = 1;
|
|
|
+ unsigned long addr;
|
|
|
|
|
|
- if (!tsk)
|
|
|
- tsk = current;
|
|
|
- if (tsk == current)
|
|
|
- sp = (unsigned long *)current_stack_pointer;
|
|
|
- else
|
|
|
- sp = (unsigned long *)tsk->thread.sp;
|
|
|
-
|
|
|
- stack = sp;
|
|
|
+ if (regs && user_mode(regs))
|
|
|
+ return;
|
|
|
|
|
|
printk("\nCall trace: ");
|
|
|
#ifdef CONFIG_KALLSYMS
|
|
|
printk("\n");
|
|
|
#endif
|
|
|
|
|
|
- while (!kstack_end(stack)) {
|
|
|
- addr = *stack++;
|
|
|
- if (((addr >= (unsigned long)_text) &&
|
|
|
- (addr <= (unsigned long)_etext)) ||
|
|
|
- ((addr >= module_start) && (addr <= module_end))) {
|
|
|
- /*
|
|
|
- * For 80-columns display, 6 entry is maximum.
|
|
|
- * NOTE: '[<8c00abcd>] ' consumes 13 columns .
|
|
|
- */
|
|
|
-#ifndef CONFIG_KALLSYMS
|
|
|
- if (i && ((i % 6) == 0))
|
|
|
- printk("\n ");
|
|
|
-#endif
|
|
|
- printk("[<%08lx>] ", addr);
|
|
|
- print_symbol("%s\n", addr);
|
|
|
- i++;
|
|
|
- }
|
|
|
+ while (!kstack_end(sp)) {
|
|
|
+ addr = *sp++;
|
|
|
+ if (kernel_text_address(addr))
|
|
|
+ print_ip_sym(addr);
|
|
|
}
|
|
|
|
|
|
printk("\n");
|
|
|
}
|
|
|
|
|
|
-void show_task(unsigned long *sp)
|
|
|
+void show_stack(struct task_struct *tsk, unsigned long *sp)
|
|
|
{
|
|
|
- show_stack(NULL, sp);
|
|
|
+ unsigned long stack;
|
|
|
+
|
|
|
+ if (!tsk)
|
|
|
+ tsk = current;
|
|
|
+ if (tsk == current)
|
|
|
+ sp = (unsigned long *)current_stack_pointer;
|
|
|
+ else
|
|
|
+ sp = (unsigned long *)tsk->thread.sp;
|
|
|
+
|
|
|
+ stack = (unsigned long)sp;
|
|
|
+ dump_mem("Stack: ", stack, THREAD_SIZE +
|
|
|
+ (unsigned long)task_stack_page(tsk));
|
|
|
+ show_trace(tsk, sp, NULL);
|
|
|
}
|
|
|
|
|
|
void dump_stack(void)
|