X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fi386%2Fkernel%2Ftraps.c;h=5b65cb8420faccfa1e97262c7c9b084e574ea508;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=05ab8b0fe22c8cd317eead9537aac17febd31e73;hpb=41689045f6a3cbe0550e1d34e9cc20d2e8c432ba;p=linux-2.6.git diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 05ab8b0fe..5b65cb842 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -11,6 +11,7 @@ * 'Traps.c' handles hardware traps and faults after we have saved some * state in 'asm.s'. */ +#include #include #include #include @@ -27,7 +28,6 @@ #include #include #include -#include #ifdef CONFIG_EISA #include @@ -47,11 +47,10 @@ #include #include #include -#include + #include #include #include -#include #include #include @@ -94,11 +93,6 @@ asmlinkage void spurious_interrupt_bug(void); asmlinkage void machine_check(void); static int kstack_depth_to_print = 24; -#ifdef CONFIG_STACK_UNWIND -static int call_trace = 1; -#else -#define call_trace (-1) -#endif ATOMIC_NOTIFIER_HEAD(i386die_chain); extern char last_sysfs_file[]; @@ -108,13 +102,13 @@ int register_die_notifier(struct notifier_block *nb) vmalloc_sync_all(); return atomic_notifier_chain_register(&i386die_chain, nb); } -EXPORT_SYMBOL(register_die_notifier); /* used modular by kdb */ +EXPORT_SYMBOL(register_die_notifier); int unregister_die_notifier(struct notifier_block *nb) { return atomic_notifier_chain_unregister(&i386die_chain, nb); } -EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ +EXPORT_SYMBOL(unregister_die_notifier); static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) { @@ -122,182 +116,92 @@ static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) p < (void *)tinfo + THREAD_SIZE - 3; } +/* + * Print CONFIG_STACK_BACKTRACE_COLS address/symbol entries per line. + */ +static inline int print_addr_and_symbol(unsigned long addr, char *log_lvl, + int printed) +{ + if (!printed) + printk(log_lvl); + +#if CONFIG_STACK_BACKTRACE_COLS == 1 + printk(" [<%08lx>] ", addr); +#else + printk(" <%08lx> ", addr); +#endif + print_symbol("%s", addr); + + printed = (printed + 1) % CONFIG_STACK_BACKTRACE_COLS; + if (printed) + printk(" "); + else + printk("\n"); + + return printed; +} + static inline unsigned long print_context_stack(struct thread_info *tinfo, unsigned long *stack, unsigned long ebp, - struct stacktrace_ops *ops, void *data) + char *log_lvl) { unsigned long addr; + int printed = 0; /* nr of entries already printed on current line */ #ifdef CONFIG_FRAME_POINTER while (valid_stack_ptr(tinfo, (void *)ebp)) { addr = *(unsigned long *)(ebp + 4); - ops->address(data, addr); - /* - * break out of recursive entries (such as - * end_of_stack_stop_unwind_function): - */ - if (ebp == *(unsigned long *)ebp) - break; + printed = print_addr_and_symbol(addr, log_lvl, printed); ebp = *(unsigned long *)ebp; } #else while (valid_stack_ptr(tinfo, stack)) { addr = *stack++; if (__kernel_text_address(addr)) - ops->address(data, addr); + printed = print_addr_and_symbol(addr, log_lvl, printed); } #endif - return ebp; -} + if (printed) + printk("\n"); -struct ops_and_data { - struct stacktrace_ops *ops; - void *data; -}; - -static asmlinkage int -dump_trace_unwind(struct unwind_frame_info *info, void *data) -{ - struct ops_and_data *oad = (struct ops_and_data *)data; - int n = 0; - - while (unwind(info) == 0 && UNW_PC(info)) { - n++; - oad->ops->address(oad->data, UNW_PC(info)); - if (arch_unw_user_mode(info)) - break; - } - return n; + return ebp; } -void dump_trace(struct task_struct *task, struct pt_regs *regs, - unsigned long *stack, - struct stacktrace_ops *ops, void *data) +static void show_trace_log_lvl(struct task_struct *task, + unsigned long *stack, char *log_lvl) { - unsigned long ebp = 0; + unsigned long ebp; if (!task) task = current; - if (call_trace >= 0) { - int unw_ret = 0; - struct unwind_frame_info info; - struct ops_and_data oad = { .ops = ops, .data = data }; - - if (regs) { - if (unwind_init_frame_info(&info, task, regs) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } else if (task == current) - unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); - else { - if (unwind_init_blocked(&info, task) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } - if (unw_ret > 0) { - if (call_trace == 1 && !arch_unw_user_mode(&info)) { - ops->warning_symbol(data, "DWARF2 unwinder stuck at %s", - UNW_PC(&info)); - if (UNW_SP(&info) >= PAGE_OFFSET) { - ops->warning(data, "Leftover inexact backtrace:"); - stack = (void *)UNW_SP(&info); - if (!stack) - return; - ebp = UNW_FP(&info); - } else - ops->warning(data, "Full inexact backtrace again:"); - } else if (call_trace >= 1) - return; - else - ops->warning(data, "Full inexact backtrace again:"); - } else - ops->warning(data, "Inexact backtrace:"); - } - if (!stack) { - unsigned long dummy; - stack = &dummy; - if (task && task != current) - stack = (unsigned long *)task->thread.esp; - } - -#ifdef CONFIG_FRAME_POINTER - if (!ebp) { - if (task == current) { - /* Grab ebp right from our regs */ - asm ("movl %%ebp, %0" : "=r" (ebp) : ); - } else { - /* ebp is the last reg pushed by switch_to */ - ebp = *(unsigned long *) task->thread.esp; - } + if (task == current) { + /* Grab ebp right from our regs */ + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + } else { + /* ebp is the last reg pushed by switch_to */ + ebp = *(unsigned long *) task->thread.esp; } -#endif while (1) { struct thread_info *context; context = (struct thread_info *) ((unsigned long)stack & (~(THREAD_SIZE - 1))); - ebp = print_context_stack(context, stack, ebp, ops, data); - /* Should be after the line below, but somewhere - in early boot context comes out corrupted and we - can't reference it -AK */ - if (ops->stack(data, "IRQ") < 0) - break; + ebp = print_context_stack(context, stack, ebp, log_lvl); stack = (unsigned long*)context->previous_esp; if (!stack) break; + printk("%s =======================\n", log_lvl); } } -EXPORT_SYMBOL(dump_trace); -static void -print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) +void show_trace(struct task_struct *task, unsigned long * stack) { - printk(data); - print_symbol(msg, symbol); - printk("\n"); + show_trace_log_lvl(task, stack, ""); } -static void print_trace_warning(void *data, char *msg) -{ - printk("%s%s\n", (char *)data, msg); -} - -static int print_trace_stack(void *data, char *name) -{ - return 0; -} - -/* - * Print one address/symbol entries per line. - */ -static void print_trace_address(void *data, unsigned long addr) -{ - printk("%s [<%08lx>] ", (char *)data, addr); - print_symbol("%s\n", addr); -} - -static struct stacktrace_ops print_trace_ops = { - .warning = print_trace_warning, - .warning_symbol = print_trace_warning_symbol, - .stack = print_trace_stack, - .address = print_trace_address, -}; - -static void -show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs, - unsigned long * stack, char *log_lvl) -{ - dump_trace(task, regs, stack, &print_trace_ops, log_lvl); - printk("%s =======================\n", log_lvl); -} - -void show_trace(struct task_struct *task, struct pt_regs *regs, - unsigned long * stack) -{ - show_trace_log_lvl(task, regs, stack, ""); -} - -static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, - unsigned long *esp, char *log_lvl) +static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp, + char *log_lvl) { unsigned long *stack; int i; @@ -318,13 +222,13 @@ static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs, printk("%08lx ", *stack++); } printk("\n%sCall Trace:\n", log_lvl); - show_trace_log_lvl(task, regs, esp, log_lvl); + show_trace_log_lvl(task, esp, log_lvl); } void show_stack(struct task_struct *task, unsigned long *esp) { printk(" "); - show_stack_log_lvl(task, NULL, esp, ""); + show_stack_log_lvl(task, esp, ""); } /* @@ -334,7 +238,7 @@ void dump_stack(void) { unsigned long stack; - show_trace(current, NULL, &stack); + show_trace(current, &stack); } EXPORT_SYMBOL(dump_stack); @@ -367,9 +271,9 @@ void show_registers(struct pt_regs *regs) regs->esi, regs->edi, regs->ebp, esp); printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", regs->xds & 0xffff, regs->xes & 0xffff, ss); - printk(KERN_EMERG "Process %.*s (pid: %d[#%u], ti=%p task=%p task.ti=%p)", - TASK_COMM_LEN, current->comm, current->pid, current->xid, - current_thread_info(), current, current->thread_info); + printk(KERN_EMERG "Process %s (pid: %d[#%u], threadinfo=%p task=%p)", + current->comm, current->pid, current->xid, + current_thread_info(), current); /* * When in-kernel, we also print out the stack and code at the * time of the fault.. @@ -378,7 +282,7 @@ void show_registers(struct pt_regs *regs) u8 __user *eip; printk("\n" KERN_EMERG "Stack: "); - show_stack_log_lvl(NULL, regs, (unsigned long *)esp, KERN_EMERG); + show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG); printk(KERN_EMERG "Code: "); @@ -401,35 +305,35 @@ void show_registers(struct pt_regs *regs) static void handle_BUG(struct pt_regs *regs) { - unsigned long eip = regs->eip; unsigned short ud2; + unsigned short line; + char *file; + char c; + unsigned long eip; + + eip = regs->eip; if (eip < PAGE_OFFSET) - return; + goto no_bug; if (__get_user(ud2, (unsigned short __user *)eip)) - return; + goto no_bug; if (ud2 != 0x0b0f) - return; + goto no_bug; + if (__get_user(line, (unsigned short __user *)(eip + 2))) + goto bug; + if (__get_user(file, (char * __user *)(eip + 4)) || + (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) + file = ""; printk(KERN_EMERG "------------[ cut here ]------------\n"); + printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); -#ifdef CONFIG_DEBUG_BUGVERBOSE - do { - unsigned short line; - char *file; - char c; - - if (__get_user(line, (unsigned short __user *)(eip + 2))) - break; - if (__get_user(file, (char * __user *)(eip + 4)) || - (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) - file = ""; +no_bug: + return; - printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); - return; - } while (0); -#endif - printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n"); + /* Here we know it was a BUG but file-n-line is unavailable */ +bug: + printk(KERN_EMERG "Kernel BUG\n"); } /* This is gone through when something in the kernel @@ -524,9 +428,11 @@ void die(const char * str, struct pt_regs * regs, long err) if (in_interrupt()) panic("Fatal exception in interrupt"); - if (panic_on_oops) + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + ssleep(5); panic("Fatal exception"); - + } oops_exit(); do_exit(SIGSEGV); } @@ -840,6 +746,7 @@ void die_nmi (struct pt_regs *regs, const char *msg) printk(" on CPU%d, eip %08lx, registers:\n", smp_processor_id(), regs->eip); show_registers(regs); + printk(KERN_EMERG "console shuts up ...\n"); console_silent(); spin_unlock(&nmi_print_lock); bust_spinlocks(0); @@ -1392,19 +1299,3 @@ static int __init kstack_setup(char *s) return 1; } __setup("kstack=", kstack_setup); - -#ifdef CONFIG_STACK_UNWIND -static int __init call_trace_setup(char *s) -{ - if (strcmp(s, "old") == 0) - call_trace = -1; - else if (strcmp(s, "both") == 0) - call_trace = 0; - else if (strcmp(s, "newfallback") == 0) - call_trace = 1; - else if (strcmp(s, "new") == 2) - call_trace = 2; - return 1; -} -__setup("call_trace=", call_trace_setup); -#endif