x86_64: Print modules like i386 does
[safe/jmp/linux-2.6] / arch / x86 / kernel / dumpstack_64.c
index d35db59..907a90e 100644 (file)
@@ -5,34 +5,42 @@
 #include <linux/kallsyms.h>
 #include <linux/kprobes.h>
 #include <linux/uaccess.h>
-#include <linux/utsname.h>
 #include <linux/hardirq.h>
 #include <linux/kdebug.h>
 #include <linux/module.h>
 #include <linux/ptrace.h>
 #include <linux/kexec.h>
+#include <linux/sysfs.h>
 #include <linux/bug.h>
 #include <linux/nmi.h>
-#include <linux/sysfs.h>
 
 #include <asm/stacktrace.h>
 
 #include "dumpstack.h"
 
-static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
-                                       unsigned *usedp, char **idp)
-{
-       static char ids[][8] = {
-               [DEBUG_STACK - 1] = "#DB",
-               [NMI_STACK - 1] = "NMI",
-               [DOUBLEFAULT_STACK - 1] = "#DF",
-               [STACKFAULT_STACK - 1] = "#SS",
-               [MCE_STACK - 1] = "#MC",
+#define N_EXCEPTION_STACKS_END \
+               (N_EXCEPTION_STACKS + DEBUG_STKSZ/EXCEPTION_STKSZ - 2)
+
+static char x86_stack_ids[][8] = {
+               [ DEBUG_STACK-1                 ]       = "#DB",
+               [ NMI_STACK-1                   ]       = "NMI",
+               [ DOUBLEFAULT_STACK-1           ]       = "#DF",
+               [ STACKFAULT_STACK-1            ]       = "#SS",
+               [ MCE_STACK-1                   ]       = "#MC",
 #if DEBUG_STKSZ > EXCEPTION_STKSZ
-               [N_EXCEPTION_STACKS ...
-                       N_EXCEPTION_STACKS + DEBUG_STKSZ / EXCEPTION_STKSZ - 2] = "#DB[?]"
+               [ N_EXCEPTION_STACKS ...
+                 N_EXCEPTION_STACKS_END        ]       = "#DB[?]"
 #endif
-       };
+};
+
+int x86_is_stack_id(int id, char *name)
+{
+       return x86_stack_ids[id - 1] == name;
+}
+
+static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
+                                        unsigned *usedp, char **idp)
+{
        unsigned k;
 
        /*
@@ -61,7 +69,7 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        if (*usedp & (1U << k))
                                break;
                        *usedp |= 1U << k;
-                       *idp = ids[k];
+                       *idp = x86_stack_ids[k];
                        return (unsigned long *)end;
                }
                /*
@@ -81,12 +89,13 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
                        do {
                                ++j;
                                end -= EXCEPTION_STKSZ;
-                               ids[j][4] = '1' + (j - N_EXCEPTION_STACKS);
+                               x86_stack_ids[j][4] = '1' +
+                                               (j - N_EXCEPTION_STACKS);
                        } while (stack < end - EXCEPTION_STKSZ);
                        if (*usedp & (1U << j))
                                break;
                        *usedp |= 1U << j;
-                       *idp = ids[j];
+                       *idp = x86_stack_ids[j];
                        return (unsigned long *)end;
                }
 #endif
@@ -94,6 +103,35 @@ static unsigned long *in_exception_stack(unsigned cpu, unsigned long stack,
        return NULL;
 }
 
+static inline int
+in_irq_stack(unsigned long *stack, unsigned long *irq_stack,
+            unsigned long *irq_stack_end)
+{
+       return (stack >= irq_stack && stack < irq_stack_end);
+}
+
+/*
+ * We are returning from the irq stack and go to the previous one.
+ * If the previous stack is also in the irq stack, then bp in the first
+ * frame of the irq stack points to the previous, interrupted one.
+ * Otherwise we have another level of indirection: We first save
+ * the bp of the previous stack, then we switch the stack to the irq one
+ * and save a new bp that links to the previous one.
+ * (See save_args())
+ */
+static inline unsigned long
+fixup_bp_irq_link(unsigned long bp, unsigned long *stack,
+                 unsigned long *irq_stack, unsigned long *irq_stack_end)
+{
+#ifdef CONFIG_FRAME_POINTER
+       struct stack_frame *frame = (struct stack_frame *)bp;
+
+       if (!in_irq_stack(stack, irq_stack, irq_stack_end))
+               return (unsigned long)frame->next_frame;
+#endif
+       return bp;
+}
+
 /*
  * x86-64 can have up to three kernel stacks:
  * process stack
@@ -150,8 +188,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                        if (ops->stack(data, id) < 0)
                                break;
 
-                       bp = print_context_stack(tinfo, stack, bp, ops,
-                                                data, estack_end, &graph);
+                       bp = ops->walk_stack(tinfo, stack, bp, ops,
+                                            data, estack_end, &graph);
                        ops->stack(data, "<EOE>");
                        /*
                         * We link to the next stack via the
@@ -166,7 +204,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                        irq_stack = irq_stack_end -
                                (IRQ_STACK_SIZE - 64) / sizeof(*irq_stack);
 
-                       if (stack >= irq_stack && stack < irq_stack_end) {
+                       if (in_irq_stack(stack, irq_stack, irq_stack_end)) {
                                if (ops->stack(data, "IRQ") < 0)
                                        break;
                                bp = print_context_stack(tinfo, stack, bp,
@@ -177,6 +215,8 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                                 * pointer (index -1 to end) in the IRQ stack:
                                 */
                                stack = (unsigned long *) (irq_stack_end[-1]);
+                               bp = fixup_bp_irq_link(bp, stack, irq_stack,
+                                                      irq_stack_end);
                                irq_stack_end = NULL;
                                ops->stack(data, "EOI");
                                continue;
@@ -195,21 +235,24 @@ EXPORT_SYMBOL(dump_trace);
 
 void
 show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
-               unsigned long *sp, unsigned long bp, char *log_lvl)
+                  unsigned long *sp, unsigned long bp, char *log_lvl)
 {
+       unsigned long *irq_stack_end;
+       unsigned long *irq_stack;
        unsigned long *stack;
+       int cpu;
        int i;
-       const int cpu = smp_processor_id();
-       unsigned long *irq_stack_end =
-               (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
-       unsigned long *irq_stack =
-               (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
+
+       preempt_disable();
+       cpu = smp_processor_id();
+
+       irq_stack_end   = (unsigned long *)(per_cpu(irq_stack_ptr, cpu));
+       irq_stack       = (unsigned long *)(per_cpu(irq_stack_ptr, cpu) - IRQ_STACK_SIZE);
 
        /*
-        * debugging aid: "show_stack(NULL, NULL);" prints the
-        * back trace for this cpu.
+        * Debugging aid: "show_stack(NULL, NULL);" prints the
+        * back trace for this cpu:
         */
-
        if (sp == NULL) {
                if (task)
                        sp = (unsigned long *)task->thread.sp;
@@ -233,6 +276,8 @@ show_stack_log_lvl(struct task_struct *task, struct pt_regs *regs,
                printk(" %016lx", *stack++);
                touch_nmi_watchdog();
        }
+       preempt_enable();
+
        printk("\n");
        show_trace_log_lvl(task, regs, sp, bp, log_lvl);
 }
@@ -246,6 +291,7 @@ void show_registers(struct pt_regs *regs)
 
        sp = regs->sp;
        printk("CPU %d ", cpu);
+       print_modules();
        __show_regs(regs, 1);
        printk("Process %s (pid: %d, threadinfo %p, task %p)\n",
                cur->comm, cur->pid, task_thread_info(cur), cur);
@@ -296,4 +342,3 @@ int is_valid_bugaddr(unsigned long ip)
 
        return ud2 == 0x0b0f;
 }
-