[ARM] 5382/1: unwind: Reorganise the stacktrace support
[linux-2.6.git] / arch / arm / oprofile / backtrace.c
index 7c22c12..d805a52 100644 (file)
 #include <linux/oprofile.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
+#include <linux/uaccess.h>
 #include <asm/ptrace.h>
-#include <asm/uaccess.h>
+#include <asm/stacktrace.h>
 
+static int report_trace(struct stackframe *frame, void *d)
+{
+       unsigned int *depth = d;
+
+       if (*depth) {
+               oprofile_add_trace(frame->pc);
+               (*depth)--;
+       }
+
+       return *depth == 0;
+}
 
 /*
  * The registers we're interested in are at the end of the variable
@@ -32,21 +44,6 @@ struct frame_tail {
        unsigned long lr;
 } __attribute__((packed));
 
-
-#ifdef CONFIG_FRAME_POINTER
-static struct frame_tail* kernel_backtrace(struct frame_tail *tail)
-{
-       oprofile_add_trace(tail->lr);
-
-       /* frame pointers should strictly progress back up the stack
-        * (towards higher addresses) */
-       if (tail >= tail->fp)
-               return NULL;
-
-       return tail->fp-1;
-}
-#endif
-
 static struct frame_tail* user_backtrace(struct frame_tail *tail)
 {
        struct frame_tail buftail[2];
@@ -67,47 +64,17 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail)
        return buftail[0].fp-1;
 }
 
-/*
- * |             | /\ Higher addresses
- * |             |
- * --------------- stack base (address of current_thread_info)
- * | thread info |
- * .             .
- * |    stack    |
- * --------------- saved regs->ARM_fp value if valid (frame_tail address)
- * .             .
- * --------------- struct pt_regs stored on stack (struct pt_regs *)
- * |             |
- * .             .
- * |             |
- * --------------- %esp
- * |             |
- * |             | \/ Lower addresses
- *
- * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
- */
-static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs)
-{
-       unsigned long tailaddr = (unsigned long)tail;
-       unsigned long stack = (unsigned long)regs;
-       unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
-
-       return (tailaddr > stack) && (tailaddr < stack_base);
-}
-
 void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
 {
-       struct frame_tail *tail;
-
-       tail = ((struct frame_tail *) regs->ARM_fp) - 1;
+       struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
 
        if (!user_mode(regs)) {
-
-#ifdef CONFIG_FRAME_POINTER
-               while (depth-- && tail && valid_kernel_stack(tail, regs)) {
-                       tail = kernel_backtrace(tail);
-               }
-#endif
+               struct stackframe frame;
+               frame.fp = regs->ARM_fp;
+               frame.sp = regs->ARM_sp;
+               frame.lr = regs->ARM_lr;
+               frame.pc = regs->ARM_pc;
+               walk_stackframe(&frame, report_trace, &depth);
                return;
        }