X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fkernel%2Ftraps.c;h=584f5dd71fd2dc3ccaa6a6bd85d6c785f4981b23;hb=9464c7cf61b9433057924c36e6e02f303a00e768;hp=2df603e12daaf696246fb0c7b6a827cf203904bd;hpb=3944158a6d33f94668dbd6bdc32ff5c67bb53ec2;p=linux-2.6.git diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 2df603e12..584f5dd71 100644 --- a/arch/x86_64/kernel/traps.c +++ b/arch/x86_64/kernel/traps.c @@ -6,12 +6,15 @@ * * Pentium III FXSR, SSE support * Gareth Hughes , May 2000 + * + * $Id: traps.c,v 1.36 2002/03/24 11:09:10 ak Exp $ */ /* * 'Traps.c' handles hardware traps and faults after we have saved some * state in 'entry.S'. */ +#include #include #include #include @@ -28,7 +31,6 @@ #include #include #include -#include #include #include @@ -39,13 +41,12 @@ #include #include #include -#include + #include #include #include #include #include -#include asmlinkage void divide_error(void); asmlinkage void debug(void); @@ -70,7 +71,6 @@ asmlinkage void machine_check(void); asmlinkage void spurious_interrupt_bug(void); ATOMIC_NOTIFIER_HEAD(die_chain); -EXPORT_SYMBOL(die_chain); extern char last_sysfs_file[]; @@ -79,13 +79,13 @@ int register_die_notifier(struct notifier_block *nb) vmalloc_sync_all(); return atomic_notifier_chain_register(&die_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(&die_chain, nb); } -EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ +EXPORT_SYMBOL(unregister_die_notifier); static inline void conditional_sti(struct pt_regs *regs) { @@ -109,43 +109,35 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) preempt_enable_no_resched(); } -static int kstack_depth_to_print = 12; -#ifdef CONFIG_STACK_UNWIND -static int call_trace = 1; -#else -#define call_trace (-1) -#endif +static int kstack_depth_to_print = 10; #ifdef CONFIG_KALLSYMS -# include -void printk_address(unsigned long address) -{ +#include +int printk_address(unsigned long address) +{ unsigned long offset = 0, symsize; const char *symname; char *modname; - char *delim = ":"; + char *delim = ":"; char namebuf[128]; - symname = kallsyms_lookup(address, &symsize, &offset, - &modname, namebuf); - if (!symname) { - printk(" [<%016lx>]\n", address); - return; - } - if (!modname) + symname = kallsyms_lookup(address, &symsize, &offset, &modname, namebuf); + if (!symname) + return printk("[<%016lx>]", address); + if (!modname) modname = delim = ""; - printk(" [<%016lx>] %s%s%s%s+0x%lx/0x%lx\n", - address, delim, modname, delim, symname, offset, symsize); -} + return printk("<%016lx>{%s%s%s%s%+ld}", + address, delim, modname, delim, symname, offset); +} #else -void printk_address(unsigned long address) -{ - printk(" [<%016lx>]\n", address); -} +int printk_address(unsigned long address) +{ + return printk("[<%016lx>]", address); +} #endif static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, - unsigned *usedp, char **idp) + unsigned *usedp, const char **idp) { static char ids[][8] = { [DEBUG_STACK - 1] = "#DB", @@ -159,68 +151,32 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, }; unsigned k; - /* - * Iterate over all exception stacks, and figure out whether - * 'stack' is in one of them: - */ for (k = 0; k < N_EXCEPTION_STACKS; k++) { unsigned long end; - /* - * set 'end' to the end of the exception stack. - */ switch (k + 1) { - /* - * TODO: this block is not needed i think, because - * setup64.c:cpu_init() sets up t->ist[DEBUG_STACK] - * properly too. - */ #if DEBUG_STKSZ > EXCEPTION_STKSZ case DEBUG_STACK: end = cpu_pda(cpu)->debugstack + DEBUG_STKSZ; break; #endif default: - end = per_cpu(orig_ist, cpu).ist[k]; + end = per_cpu(init_tss, cpu).ist[k]; break; } - /* - * Is 'stack' above this exception frame's end? - * If yes then skip to the next frame. - */ if (stack >= end) continue; - /* - * Is 'stack' above this exception frame's start address? - * If yes then we found the right frame. - */ if (stack >= end - EXCEPTION_STKSZ) { - /* - * Make sure we only iterate through an exception - * stack once. If it comes up for the second time - * then there's something wrong going on - just - * break out and return NULL: - */ if (*usedp & (1U << k)) break; *usedp |= 1U << k; *idp = ids[k]; return (unsigned long *)end; } - /* - * If this is a debug stack, and if it has a larger size than - * the usual exception stacks, then 'stack' might still - * be within the lower portion of the debug stack: - */ #if DEBUG_STKSZ > EXCEPTION_STKSZ if (k == DEBUG_STACK - 1 && stack >= end - DEBUG_STKSZ) { unsigned j = N_EXCEPTION_STACKS - 1; - /* - * Black magic. A large debug stack is composed of - * multiple exception stack entries, which we - * iterate through now. Dont look: - */ do { ++j; end -= EXCEPTION_STKSZ; @@ -237,25 +193,6 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack, return NULL; } -struct ops_and_data { - struct stacktrace_ops *ops; - void *data; -}; - -static int dump_trace_unwind(struct unwind_frame_info *info, void *context) -{ - struct ops_and_data *oad = (struct ops_and_data *)context; - 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; -} - /* * x86-64 can have upto three kernel stacks: * process stack @@ -263,64 +200,25 @@ static int dump_trace_unwind(struct unwind_frame_info *info, void *context) * severe exception (double fault, nmi, stack fault, debug, mce) hardware stack */ -void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * stack, - struct stacktrace_ops *ops, void *data) +void show_trace(unsigned long *stack) { const unsigned cpu = safe_smp_processor_id(); unsigned long *irqstack_end = (unsigned long *)cpu_pda(cpu)->irqstackptr; + int i; unsigned used = 0; - if (!tsk) - tsk = 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, tsk, regs) == 0) - unw_ret = dump_trace_unwind(&info, &oad); - } else if (tsk == current) - unw_ret = unwind_init_running(&info, dump_trace_unwind, &oad); - else { - if (unwind_init_blocked(&info, tsk) == 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 ((long)UNW_SP(&info) < 0) { - ops->warning(data, "Leftover inexact backtrace:"); - stack = (unsigned long *)UNW_SP(&info); - if (!stack) - return; - } 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 (tsk && tsk != current) - stack = (unsigned long *)tsk->thread.rsp; - } + printk("\nCall Trace:"); - /* - * Print function call entries within a stack. 'cond' is the - * "end of stackframe" condition, that the 'stack++' - * iteration will eventually trigger. - */ #define HANDLE_STACK(cond) \ do while (cond) { \ unsigned long addr = *stack++; \ if (kernel_text_address(addr)) { \ + if (i > 50) { \ + printk("\n "); \ + i = 0; \ + } \ + else \ + i += printk(" "); \ /* \ * If the address is either in the text segment of the \ * kernel, or in the region which contains vmalloc'ed \ @@ -329,31 +227,20 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s * down the cause of the crash will be able to figure \ * out the call path that was taken. \ */ \ - ops->address(data, addr); \ + i += printk_address(addr); \ } \ } while (0) - /* - * Print function call entries in all stacks, starting at the - * current stack address. If the stacks consist of nested - * exceptions - */ - for (;;) { - char *id; + for(i = 11; ; ) { + const char *id; unsigned long *estack_end; estack_end = in_exception_stack(cpu, (unsigned long)stack, &used, &id); if (estack_end) { - if (ops->stack(data, id) < 0) - break; + i += printk(" <%s>", id); HANDLE_STACK (stack < estack_end); - ops->stack(data, ""); - /* - * We link to the next stack via the - * second-to-last pointer (index -2 to end) in the - * exception stack: - */ + i += printk(" "); stack = (unsigned long *) estack_end[-2]; continue; } @@ -363,71 +250,23 @@ void dump_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long * s (IRQSTACKSIZE - 64) / sizeof(*irqstack); if (stack >= irqstack && stack < irqstack_end) { - if (ops->stack(data, "IRQ") < 0) - break; + i += printk(" "); HANDLE_STACK (stack < irqstack_end); - /* - * We link to the next stack (which would be - * the process stack normally) the last - * pointer (index -1 to end) in the IRQ stack: - */ stack = (unsigned long *) (irqstack_end[-1]); irqstack_end = NULL; - ops->stack(data, "EOI"); + i += printk(" "); continue; } } break; } - /* - * This handles the process stack: - */ HANDLE_STACK (((long) stack & (THREAD_SIZE-1)) != 0); #undef HANDLE_STACK -} -EXPORT_SYMBOL(dump_trace); - -static void -print_trace_warning_symbol(void *data, char *msg, unsigned long symbol) -{ - print_symbol(msg, symbol); - printk("\n"); -} - -static void print_trace_warning(void *data, char *msg) -{ - printk("%s\n", msg); -} - -static int print_trace_stack(void *data, char *name) -{ - printk(" <%s> ", name); - return 0; -} - -static void print_trace_address(void *data, unsigned long addr) -{ - printk_address(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, -}; - -void -show_trace(struct task_struct *tsk, struct pt_regs *regs, unsigned long *stack) -{ - printk("\nCall Trace:\n"); - dump_trace(tsk, regs, stack, &print_trace_ops, NULL); printk("\n"); } -static void -_show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *rsp) +void show_stack(struct task_struct *tsk, unsigned long * rsp) { unsigned long *stack; int i; @@ -457,16 +296,11 @@ _show_stack(struct task_struct *tsk, struct pt_regs *regs, unsigned long *rsp) break; } if (i && ((i % 4) == 0)) - printk("\n"); - printk(" %016lx", *stack++); + printk("\n "); + printk("%016lx ", *stack++); touch_nmi_watchdog(); } - show_trace(tsk, regs, rsp); -} - -void show_stack(struct task_struct *tsk, unsigned long * rsp) -{ - _show_stack(tsk, NULL, rsp); + show_trace((unsigned long *)rsp); } /* @@ -475,7 +309,7 @@ void show_stack(struct task_struct *tsk, unsigned long * rsp) void dump_stack(void) { unsigned long dummy; - show_trace(NULL, NULL, &dummy); + show_trace(&dummy); } EXPORT_SYMBOL(dump_stack); @@ -503,7 +337,7 @@ void show_registers(struct pt_regs *regs) if (in_kernel) { printk("Stack: "); - _show_stack(NULL, regs, (unsigned long*)rsp); + show_stack(NULL, (unsigned long*)rsp); printk("\nCode: "); if (regs->rip < PAGE_OFFSET) @@ -552,7 +386,6 @@ void out_of_line_bug(void) { BUG(); } -EXPORT_SYMBOL(out_of_line_bug); #endif static DEFINE_SPINLOCK(die_lock); @@ -591,7 +424,7 @@ void __kprobes oops_end(unsigned long flags) /* Nest count reaches zero, release the lock. */ spin_unlock_irqrestore(&die_lock, flags); if (panic_on_oops) - panic("Fatal exception"); + panic("Oops"); } void __kprobes __die(const char * str, struct pt_regs * regs, long err) @@ -931,6 +764,14 @@ asmlinkage void __kprobes do_debug(struct pt_regs * regs, */ if (!user_mode(regs)) goto clear_TF_reenable; + /* + * Was the TF flag set by a debugger? If so, clear it now, + * so that register information is correct. + */ + if (tsk->ptrace & PT_DTRACE) { + regs->eflags &= ~TF_MASK; + tsk->ptrace &= ~PT_DTRACE; + } } /* Ok, finally something we can handle */ @@ -1177,18 +1018,3 @@ static int __init kstack_setup(char *s) } __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") == 0) - call_trace = 2; - return 1; -} -__setup("call_trace=", call_trace_setup); -#endif