]> err.no Git - linux-2.6/blobdiff - arch/x86/kernel/traps_32.c
Merge branch 'master' of ../linux-2.6/
[linux-2.6] / arch / x86 / kernel / traps_32.c
index 2eb6ca0ef672c0a02f53a7dd0db589c8c5c576fe..b22c01e05a1841d4a3960a2e62a2881ee9c5babc 100644 (file)
@@ -102,6 +102,34 @@ asmlinkage void machine_check(void);
 int kstack_depth_to_print = 24;
 static unsigned int code_bytes = 64;
 
+void printk_address(unsigned long address, int reliable)
+{
+#ifdef CONFIG_KALLSYMS
+       unsigned long offset = 0, symsize;
+       const char *symname;
+       char *modname;
+       char *delim = ":";
+       char namebuf[128];
+       char reliab[4] = "";
+
+       symname = kallsyms_lookup(address, &symsize, &offset,
+                                       &modname, namebuf);
+       if (!symname) {
+               printk(" [<%08lx>]\n", address);
+               return;
+       }
+       if (!reliable)
+               strcpy(reliab, "? ");
+
+       if (!modname)
+               modname = delim = "";
+       printk(" [<%08lx>] %s%s%s%s%s+0x%lx/0x%lx\n",
+               address, reliab, delim, modname, delim, symname, offset, symsize);
+#else
+       printk(" [<%08lx>]\n", address);
+#endif
+}
+
 static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size)
 {
        return  p > (void *)tinfo &&
@@ -118,45 +146,32 @@ static inline unsigned long print_context_stack(struct thread_info *tinfo,
                                unsigned long *stack, unsigned long bp,
                                const struct stacktrace_ops *ops, void *data)
 {
-#ifdef CONFIG_FRAME_POINTER
        struct stack_frame *frame = (struct stack_frame *)bp;
-       while (valid_stack_ptr(tinfo, frame, sizeof(*frame))) {
-               struct stack_frame *next;
-               unsigned long addr;
 
-               addr = frame->return_address;
-               ops->address(data, addr);
-               /*
-                * break out of recursive entries (such as
-                * end_of_stack_stop_unwind_function). Also,
-                * we can never allow a frame pointer to
-                * move downwards!
-                */
-               next = frame->next_frame;
-               if (next <= frame)
-                       break;
-               frame = next;
-       }
-#else
        while (valid_stack_ptr(tinfo, stack, sizeof(*stack))) {
                unsigned long addr;
 
-               addr = *stack++;
-               if (__kernel_text_address(addr))
-                       ops->address(data, addr);
+               addr = *stack;
+               if (__kernel_text_address(addr)) {
+                       if ((unsigned long) stack == bp + 4) {
+                               ops->address(data, addr, 1);
+                               frame = frame->next_frame;
+                               bp = (unsigned long) frame;
+                       } else {
+                               ops->address(data, addr, bp == 0);
+                       }
+               }
+               stack++;
        }
-#endif
        return bp;
 }
 
 #define MSG(msg) ops->warning(data, msg)
 
 void dump_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *stack,
+               unsigned long *stack, unsigned long bp,
                const struct stacktrace_ops *ops, void *data)
 {
-       unsigned long bp = 0;
-
        if (!task)
                task = current;
 
@@ -218,9 +233,11 @@ static int print_trace_stack(void *data, char *name)
 /*
  * Print one address/symbol entries per line.
  */
-static void print_trace_address(void *data, unsigned long addr)
+static void print_trace_address(void *data, unsigned long addr, int reliable)
 {
        printk("%s [<%08lx>] ", (char *)data, addr);
+       if (!reliable)
+               printk("? ");
        print_symbol("%s\n", addr);
        touch_nmi_watchdog();
 }
@@ -234,20 +251,20 @@ static const struct stacktrace_ops print_trace_ops = {
 
 static void
 show_trace_log_lvl(struct task_struct *task, struct pt_regs *regs,
-                  unsigned long * stack, char *log_lvl)
+               unsigned long *stack, unsigned long bp, char *log_lvl)
 {
-       dump_trace(task, regs, stack, &print_trace_ops, log_lvl);
+       dump_trace(task, regs, stack, bp, &print_trace_ops, log_lvl);
        printk("%s =======================\n", log_lvl);
 }
 
 void show_trace(struct task_struct *task, struct pt_regs *regs,
-               unsigned long * stack)
+               unsigned long *stack, unsigned long bp)
 {
-       show_trace_log_lvl(task, regs, stack, "");
+       show_trace_log_lvl(task, regs, stack, bp, "");
 }
 
 static void show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-                              unsigned long *sp, char *log_lvl)
+                      unsigned long *sp, unsigned long bp, char *log_lvl)
 {
        unsigned long *stack;
        int i;
@@ -268,13 +285,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, sp, log_lvl);
+       show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
 
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
        printk("       ");
-       show_stack_log_lvl(task, NULL, sp, "");
+       show_stack_log_lvl(task, NULL, sp, 0, "");
 }
 
 /*
@@ -283,13 +300,19 @@ void show_stack(struct task_struct *task, unsigned long *sp)
 void dump_stack(void)
 {
        unsigned long stack;
+       unsigned long bp = 0;
+
+#ifdef CONFIG_FRAME_POINTER
+       if (!bp)
+               asm("movl %%ebp, %0" : "=r" (bp):);
+#endif
 
        printk("Pid: %d, comm: %.20s %s %s %.*s\n",
                current->pid, current->comm, print_tainted(),
                init_utsname()->release,
                (int)strcspn(init_utsname()->version, " "),
                init_utsname()->version);
-       show_trace(current, NULL, &stack);
+       show_trace(current, NULL, &stack, bp);
 }
 
 EXPORT_SYMBOL(dump_stack);
@@ -314,7 +337,7 @@ void show_registers(struct pt_regs *regs)
                unsigned char c;
 
                printk("\n" KERN_EMERG "Stack: ");
-               show_stack_log_lvl(NULL, regs, &regs->sp, KERN_EMERG);
+               show_stack_log_lvl(NULL, regs, &regs->sp, 0, KERN_EMERG);
 
                printk(KERN_EMERG "Code: ");
 
@@ -352,6 +375,45 @@ int is_valid_bugaddr(unsigned long ip)
        return ud2 == 0x0b0f;
 }
 
+static int die_counter;
+
+int __kprobes __die(const char * str, struct pt_regs * regs, long err)
+{
+       unsigned long sp;
+       unsigned short ss;
+
+       printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff, ++die_counter);
+#ifdef CONFIG_PREEMPT
+       printk("PREEMPT ");
+#endif
+#ifdef CONFIG_SMP
+       printk("SMP ");
+#endif
+#ifdef CONFIG_DEBUG_PAGEALLOC
+       printk("DEBUG_PAGEALLOC");
+#endif
+       printk("\n");
+
+       if (notify_die(DIE_OOPS, str, regs, err,
+                               current->thread.trap_no, SIGSEGV) !=
+                       NOTIFY_STOP) {
+               show_registers(regs);
+               /* Executive summary in case the oops scrolled away */
+               sp = (unsigned long) (&regs->sp);
+               savesegment(ss, ss);
+               if (user_mode(regs)) {
+                       sp = regs->sp;
+                       ss = regs->ss & 0xffff;
+               }
+               printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
+               print_symbol("%s", regs->ip);
+               printk(" SS:ESP %04x:%08lx\n", ss, sp);
+               return 0;
+       } else {
+               return 1;
+       }
+}
+
 /*
  * This is gone through when something in the kernel has done something bad and
  * is about to be terminated.
@@ -367,7 +429,6 @@ void die(const char * str, struct pt_regs * regs, long err)
                .lock_owner =           -1,
                .lock_owner_depth =     0
        };
-       static int die_counter;
        unsigned long flags;
 
        oops_enter();
@@ -383,43 +444,13 @@ void die(const char * str, struct pt_regs * regs, long err)
                raw_local_irq_save(flags);
 
        if (++die.lock_owner_depth < 3) {
-               unsigned long sp;
-               unsigned short ss;
-
                report_bug(regs->ip, regs);
 
-               printk(KERN_EMERG "%s: %04lx [#%d] ", str, err & 0xffff,
-                      ++die_counter);
-#ifdef CONFIG_PREEMPT
-               printk("PREEMPT ");
-#endif
-#ifdef CONFIG_SMP
-               printk("SMP ");
-#endif
-#ifdef CONFIG_DEBUG_PAGEALLOC
-               printk("DEBUG_PAGEALLOC");
-#endif
-               printk("\n");
-
-               if (notify_die(DIE_OOPS, str, regs, err,
-                                       current->thread.trap_no, SIGSEGV) !=
-                               NOTIFY_STOP) {
-                       show_registers(regs);
-                       /* Executive summary in case the oops scrolled away */
-                       sp = (unsigned long) (&regs->sp);
-                       savesegment(ss, ss);
-                       if (user_mode(regs)) {
-                               sp = regs->sp;
-                               ss = regs->ss & 0xffff;
-                       }
-                       printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip);
-                       print_symbol("%s", regs->ip);
-                       printk(" SS:ESP %04x:%08lx\n", ss, sp);
-               }
-               else
+               if (__die(str, regs, err))
                        regs = NULL;
-       } else
+       } else {
                printk(KERN_EMERG "Recursive die() failure, output suppressed\n");
+       }
 
        bust_spinlocks(0);
        die.lock_owner = -1;
@@ -606,11 +637,14 @@ void __kprobes do_general_protection(struct pt_regs * regs,
        current->thread.error_code = error_code;
        current->thread.trap_no = 13;
        if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) &&
-           printk_ratelimit())
+           printk_ratelimit()) {
                printk(KERN_INFO
-                   "%s[%d] general protection ip:%lx sp:%lx error:%lx\n",
+                   "%s[%d] general protection ip:%lx sp:%lx error:%lx",
                    current->comm, task_pid_nr(current),
                    regs->ip, regs->sp, error_code);
+               print_vma_addr(" in ", regs->ip);
+               printk("\n");
+       }
 
        force_sig(SIGSEGV, current);
        return;
@@ -1108,11 +1142,11 @@ void __init trap_init(void)
        int i;
 
 #ifdef CONFIG_EISA
-       void __iomem *p = ioremap(0x0FFFD9, 4);
+       void __iomem *p = early_ioremap(0x0FFFD9, 4);
        if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) {
                EISA_bus = 1;
        }
-       iounmap(p);
+       early_iounmap(p, 4);
 #endif
 
 #ifdef CONFIG_X86_LOCAL_APIC
@@ -1142,17 +1176,12 @@ void __init trap_init(void)
 #endif
        set_trap_gate(19,&simd_coprocessor_error);
 
+       /*
+        * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
+        * Generate a build-time error if the alignment is wrong.
+        */
+       BUILD_BUG_ON(offsetof(struct task_struct, thread.i387.fxsave) & 15);
        if (cpu_has_fxsr) {
-               /*
-                * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned.
-                * Generates a compile-time "error: zero width for bit-field" if
-                * the alignment is wrong.
-                */
-               struct fxsrAlignAssert {
-                       int _:!(offsetof(struct task_struct,
-                                       thread.i387.fxsave) & 15);
-               };
-
                printk(KERN_INFO "Enabling fast FPU save and restore... ");
                set_in_cr4(X86_CR4_OSFXSR);
                printk("done.\n");