X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=arch%2Fx86_64%2Fkernel%2Ftraps.c;fp=arch%2Fx86_64%2Fkernel%2Ftraps.c;h=dd879d5fe4892957de480b488112fc73b47502f0;hb=64ba3f394c830ec48a1c31b53dcae312c56f1604;hp=6d38a2d585018c9551284e59d211b67768f0d504;hpb=be1e6109ac94a859551f8e1774eb9a8469fe055c;p=linux-2.6.git diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c index 6d38a2d58..dd879d5fe 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,14 @@ #include #include #include -#include + #include #include #include #include #include -#include + +extern struct gate_struct idt_table[256]; asmlinkage void divide_error(void); asmlinkage void debug(void); @@ -69,23 +72,18 @@ asmlinkage void alignment_check(void); 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[]; +struct notifier_block *die_chain; +static DEFINE_SPINLOCK(die_notifier_lock); 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 */ - -int unregister_die_notifier(struct notifier_block *nb) -{ - return atomic_notifier_chain_unregister(&die_chain, nb); + int err = 0; + unsigned long flags; + spin_lock_irqsave(&die_notifier_lock, flags); + err = notifier_chain_register(&die_chain, nb); + spin_unlock_irqrestore(&die_notifier_lock, flags); + return err; } -EXPORT_SYMBOL(unregister_die_notifier); /* used modular by kdb */ static inline void conditional_sti(struct pt_regs *regs) { @@ -104,48 +102,38 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) { if (regs->eflags & X86_EFLAGS_IF) local_irq_disable(); - /* Make sure to not schedule here because we could be running - on an exception stack. */ 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 +147,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 +189,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 +196,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 +223,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 +246,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 +292,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 +305,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,15 +333,16 @@ 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) + if(regs->rip < PAGE_OFFSET) goto bad; - for (i=0; i<20; i++) { + for(i=0;i<20;i++) + { unsigned char c; - if (__get_user(c, &((unsigned char*)regs->rip)[i])) { + if(__get_user(c, &((unsigned char*)regs->rip)[i])) { bad: printk(" Bad RIP value."); break; @@ -552,12 +383,10 @@ void out_of_line_bug(void) { BUG(); } -EXPORT_SYMBOL(out_of_line_bug); #endif static DEFINE_SPINLOCK(die_lock); static int die_owner = -1; -static unsigned int die_nest_count; unsigned __kprobes long oops_begin(void) { @@ -572,7 +401,6 @@ unsigned __kprobes long oops_begin(void) else spin_lock(&die_lock); } - die_nest_count++; die_owner = cpu; console_verbose(); bust_spinlocks(1); @@ -583,15 +411,9 @@ void __kprobes oops_end(unsigned long flags) { die_owner = -1; bust_spinlocks(0); - die_nest_count--; - if (die_nest_count) - /* We still own the lock */ - local_irq_restore(flags); - else - /* Nest count reaches zero, release the lock. */ - spin_unlock_irqrestore(&die_lock, flags); + 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) @@ -608,9 +430,6 @@ void __kprobes __die(const char * str, struct pt_regs * regs, long err) printk("DEBUG_PAGEALLOC"); #endif printk("\n"); -#ifdef CONFIG_SYSFS - printk(KERN_ALERT "last sysfs file: %s\n", last_sysfs_file); -#endif notify_die(DIE_OOPS, str, regs, err, current->thread.trap_no, SIGSEGV); show_registers(regs); /* Executive summary in case the oops scrolled away */ @@ -647,8 +466,6 @@ void __kprobes die_nmi(char *str, struct pt_regs *regs) panic("nmi watchdog"); printk("console shuts up ...\n"); oops_end(flags); - nmi_exit(); - local_irq_enable(); do_exit(SIGSEGV); } @@ -658,6 +475,8 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, { struct task_struct *tsk = current; + conditional_sti(regs); + tsk->thread.error_code = error_code; tsk->thread.trap_no = trapnr; @@ -666,7 +485,7 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, printk(KERN_INFO "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", tsk->comm, tsk->pid, str, - regs->rip, regs->rsp, error_code); + regs->rip,regs->rsp,error_code); if (info) force_sig_info(signr, info, tsk); @@ -680,9 +499,9 @@ static void __kprobes do_trap(int trapnr, int signr, char *str, { const struct exception_table_entry *fixup; fixup = search_exception_tables(regs->rip); - if (fixup) + if (fixup) { regs->rip = fixup->fixup; - else + } else die(str, regs, error_code); return; } @@ -694,7 +513,6 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ == NOTIFY_STOP) \ return; \ - conditional_sti(regs); \ do_trap(trapnr, signr, str, regs, error_code, NULL); \ } @@ -709,7 +527,6 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ == NOTIFY_STOP) \ return; \ - conditional_sti(regs); \ do_trap(trapnr, signr, str, regs, error_code, &info); \ } @@ -723,17 +540,7 @@ DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) DO_ERROR(18, SIGSEGV, "reserved", reserved) - -/* Runs on IST stack */ -asmlinkage void do_stack_segment(struct pt_regs *regs, long error_code) -{ - if (notify_die(DIE_TRAP, "stack segment", regs, error_code, - 12, SIGBUS) == NOTIFY_STOP) - return; - preempt_conditional_sti(regs); - do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL); - preempt_conditional_cli(regs); -} +DO_ERROR(12, SIGBUS, "stack segment", stack_segment) asmlinkage void do_double_fault(struct pt_regs * regs, long error_code) { @@ -767,7 +574,7 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs, printk(KERN_INFO "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", tsk->comm, tsk->pid, - regs->rip, regs->rsp, error_code); + regs->rip,regs->rsp,error_code); force_sig(SIGSEGV, tsk); return; @@ -867,9 +674,8 @@ asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code) if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) { return; } - preempt_conditional_sti(regs); do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); - preempt_conditional_cli(regs); + return; } /* Help handler running on IST stack to switch back to user stack @@ -1174,29 +980,14 @@ void __init trap_init(void) static int __init oops_dummy(char *s) { panic_on_oops = 1; - return 1; + return -1; } __setup("oops=", oops_dummy); static int __init kstack_setup(char *s) { kstack_depth_to_print = simple_strtoul(s,NULL,0); - return 1; + return 0; } __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