OSDN Git Service

Merge branch 'akpm' (patches from Andrew)
[uclinux-h8/linux.git] / arch / s390 / kernel / dumpstack.c
index 14c1ed3..1b6081c 100644 (file)
 #include <asm/ipl.h>
 
 /*
- * For show_trace we have tree different stack to consider:
+ * For dump_trace we have tree different stack to consider:
  *   - the panic stack which is used if the kernel stack has overflown
  *   - the asynchronous interrupt stack (cpu related)
  *   - the synchronous kernel stack (process related)
- * The stack trace can start at any of the three stack and can potentially
+ * The stack trace can start at any of the three stacks and can potentially
  * touch all of them. The order is: panic stack, async stack, sync stack.
  */
 static unsigned long
-__show_trace(unsigned long sp, unsigned long low, unsigned long high)
+__dump_trace(dump_trace_func_t func, void *data, unsigned long sp,
+            unsigned long low, unsigned long high)
 {
        struct stack_frame *sf;
        struct pt_regs *regs;
-       unsigned long addr;
 
        while (1) {
                if (sp < low || sp > high - sizeof(*sf))
                        return sp;
                sf = (struct stack_frame *) sp;
-               addr = sf->gprs[8];
-               printk("([<%016lx>] %pSR)\n", addr, (void *)addr);
                /* Follow the backchain. */
                while (1) {
+                       if (func(data, sf->gprs[8]))
+                               return sp;
                        low = sp;
                        sp = sf->back_chain;
                        if (!sp)
@@ -49,46 +49,58 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high)
                        if (sp <= low || sp > high - sizeof(*sf))
                                return sp;
                        sf = (struct stack_frame *) sp;
-                       addr = sf->gprs[8];
-                       printk(" [<%016lx>] %pSR\n", addr, (void *)addr);
                }
                /* Zero backchain detected, check for interrupt frame. */
                sp = (unsigned long) (sf + 1);
                if (sp <= low || sp > high - sizeof(*regs))
                        return sp;
                regs = (struct pt_regs *) sp;
-               addr = regs->psw.addr;
-               printk(" [<%016lx>] %pSR\n", addr, (void *)addr);
+               if (!user_mode(regs)) {
+                       if (func(data, regs->psw.addr))
+                               return sp;
+               }
                low = sp;
                sp = regs->gprs[15];
        }
 }
 
-static void show_trace(struct task_struct *task, unsigned long *stack)
+void dump_trace(dump_trace_func_t func, void *data, struct task_struct *task,
+               unsigned long sp)
 {
-       const unsigned long frame_size =
-               STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
-       register unsigned long __r15 asm ("15");
-       unsigned long sp;
+       unsigned long frame_size;
 
-       sp = (unsigned long) stack;
-       if (!sp)
-               sp = task ? task->thread.ksp : __r15;
-       printk("Call Trace:\n");
+       frame_size = STACK_FRAME_OVERHEAD + sizeof(struct pt_regs);
 #ifdef CONFIG_CHECK_STACK
-       sp = __show_trace(sp,
+       sp = __dump_trace(func, data, sp,
                          S390_lowcore.panic_stack + frame_size - 4096,
                          S390_lowcore.panic_stack + frame_size);
 #endif
-       sp = __show_trace(sp,
+       sp = __dump_trace(func, data, sp,
                          S390_lowcore.async_stack + frame_size - ASYNC_SIZE,
                          S390_lowcore.async_stack + frame_size);
        if (task)
-               __show_trace(sp, (unsigned long) task_stack_page(task),
-                            (unsigned long) task_stack_page(task) + THREAD_SIZE);
+               __dump_trace(func, data, sp,
+                            (unsigned long)task_stack_page(task),
+                            (unsigned long)task_stack_page(task) + THREAD_SIZE);
        else
-               __show_trace(sp, S390_lowcore.thread_info,
+               __dump_trace(func, data, sp,
+                            S390_lowcore.thread_info,
                             S390_lowcore.thread_info + THREAD_SIZE);
+}
+EXPORT_SYMBOL_GPL(dump_trace);
+
+static int show_address(void *data, unsigned long address)
+{
+       printk("([<%016lx>] %pSR)\n", address, (void *)address);
+       return 0;
+}
+
+static void show_trace(struct task_struct *task, unsigned long sp)
+{
+       if (!sp)
+               sp = task ? task->thread.ksp : current_stack_pointer();
+       printk("Call Trace:\n");
+       dump_trace(show_address, NULL, task, sp);
        if (!task)
                task = current;
        debug_show_held_locks(task);
@@ -96,15 +108,16 @@ static void show_trace(struct task_struct *task, unsigned long *stack)
 
 void show_stack(struct task_struct *task, unsigned long *sp)
 {
-       register unsigned long *__r15 asm ("15");
        unsigned long *stack;
        int i;
 
-       if (!sp)
-               stack = task ? (unsigned long *) task->thread.ksp : __r15;
-       else
-               stack = sp;
-
+       stack = sp;
+       if (!stack) {
+               if (!task)
+                       stack = (unsigned long *)current_stack_pointer();
+               else
+                       stack = (unsigned long *)task->thread.ksp;
+       }
        for (i = 0; i < 20; i++) {
                if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
                        break;
@@ -113,7 +126,7 @@ void show_stack(struct task_struct *task, unsigned long *sp)
                printk("%016lx ", *stack++);
        }
        printk("\n");
-       show_trace(task, sp);
+       show_trace(task, (unsigned long)sp);
 }
 
 static void show_last_breaking_event(struct pt_regs *regs)
@@ -122,13 +135,9 @@ static void show_last_breaking_event(struct pt_regs *regs)
        printk(" [<%016lx>] %pSR\n", regs->args[0], (void *)regs->args[0]);
 }
 
-static inline int mask_bits(struct pt_regs *regs, unsigned long bits)
-{
-       return (regs->psw.mask & bits) / ((~bits + 1) & bits);
-}
-
 void show_registers(struct pt_regs *regs)
 {
+       struct psw_bits *psw = &psw_bits(regs->psw);
        char *mode;
 
        mode = user_mode(regs) ? "User" : "Krnl";
@@ -137,13 +146,9 @@ void show_registers(struct pt_regs *regs)
                printk(" (%pSR)", (void *)regs->psw.addr);
        printk("\n");
        printk("           R:%x T:%x IO:%x EX:%x Key:%x M:%x W:%x "
-              "P:%x AS:%x CC:%x PM:%x", mask_bits(regs, PSW_MASK_PER),
-              mask_bits(regs, PSW_MASK_DAT), mask_bits(regs, PSW_MASK_IO),
-              mask_bits(regs, PSW_MASK_EXT), mask_bits(regs, PSW_MASK_KEY),
-              mask_bits(regs, PSW_MASK_MCHECK), mask_bits(regs, PSW_MASK_WAIT),
-              mask_bits(regs, PSW_MASK_PSTATE), mask_bits(regs, PSW_MASK_ASC),
-              mask_bits(regs, PSW_MASK_CC), mask_bits(regs, PSW_MASK_PM));
-       printk(" EA:%x", mask_bits(regs, PSW_MASK_EA | PSW_MASK_BA));
+              "P:%x AS:%x CC:%x PM:%x", psw->r, psw->t, psw->i, psw->e,
+              psw->key, psw->m, psw->w, psw->p, psw->as, psw->cc, psw->pm);
+       printk(" RI:%x EA:%x", psw->ri, psw->eaba);
        printk("\n%s GPRS: %016lx %016lx %016lx %016lx\n", mode,
               regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
        printk("           %016lx %016lx %016lx %016lx\n",
@@ -161,7 +166,7 @@ void show_regs(struct pt_regs *regs)
        show_registers(regs);
        /* Show stack backtrace if pt_regs is from kernel mode */
        if (!user_mode(regs))
-               show_trace(NULL, (unsigned long *) regs->gprs[15]);
+               show_trace(NULL, regs->gprs[15]);
        show_last_breaking_event(regs);
 }