aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/oprofile
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/oprofile')
-rw-r--r--arch/arm/oprofile/backtrace.c69
1 files changed, 17 insertions, 52 deletions
diff --git a/arch/arm/oprofile/backtrace.c b/arch/arm/oprofile/backtrace.c
index 7c22c12618cc..f5ebf30151fa 100644
--- a/arch/arm/oprofile/backtrace.c
+++ b/arch/arm/oprofile/backtrace.c
@@ -19,6 +19,19 @@
19#include <asm/ptrace.h> 19#include <asm/ptrace.h>
20#include <asm/uaccess.h> 20#include <asm/uaccess.h>
21 21
22#include "../kernel/stacktrace.h"
23
24static int report_trace(struct stackframe *frame, void *d)
25{
26 unsigned int *depth = d;
27
28 if (*depth) {
29 oprofile_add_trace(frame->lr);
30 (*depth)--;
31 }
32
33 return *depth == 0;
34}
22 35
23/* 36/*
24 * The registers we're interested in are at the end of the variable 37 * The registers we're interested in are at the end of the variable
@@ -32,21 +45,6 @@ struct frame_tail {
32 unsigned long lr; 45 unsigned long lr;
33} __attribute__((packed)); 46} __attribute__((packed));
34 47
35
36#ifdef CONFIG_FRAME_POINTER
37static struct frame_tail* kernel_backtrace(struct frame_tail *tail)
38{
39 oprofile_add_trace(tail->lr);
40
41 /* frame pointers should strictly progress back up the stack
42 * (towards higher addresses) */
43 if (tail >= tail->fp)
44 return NULL;
45
46 return tail->fp-1;
47}
48#endif
49
50static struct frame_tail* user_backtrace(struct frame_tail *tail) 48static struct frame_tail* user_backtrace(struct frame_tail *tail)
51{ 49{
52 struct frame_tail buftail[2]; 50 struct frame_tail buftail[2];
@@ -67,47 +65,14 @@ static struct frame_tail* user_backtrace(struct frame_tail *tail)
67 return buftail[0].fp-1; 65 return buftail[0].fp-1;
68} 66}
69 67
70/*
71 * | | /\ Higher addresses
72 * | |
73 * --------------- stack base (address of current_thread_info)
74 * | thread info |
75 * . .
76 * | stack |
77 * --------------- saved regs->ARM_fp value if valid (frame_tail address)
78 * . .
79 * --------------- struct pt_regs stored on stack (struct pt_regs *)
80 * | |
81 * . .
82 * | |
83 * --------------- %esp
84 * | |
85 * | | \/ Lower addresses
86 *
87 * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
88 */
89static int valid_kernel_stack(struct frame_tail *tail, struct pt_regs *regs)
90{
91 unsigned long tailaddr = (unsigned long)tail;
92 unsigned long stack = (unsigned long)regs;
93 unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
94
95 return (tailaddr > stack) && (tailaddr < stack_base);
96}
97
98void arm_backtrace(struct pt_regs * const regs, unsigned int depth) 68void arm_backtrace(struct pt_regs * const regs, unsigned int depth)
99{ 69{
100 struct frame_tail *tail; 70 struct frame_tail *tail = ((struct frame_tail *) regs->ARM_fp) - 1;
101
102 tail = ((struct frame_tail *) regs->ARM_fp) - 1;
103 71
104 if (!user_mode(regs)) { 72 if (!user_mode(regs)) {
105 73 unsigned long base = ((unsigned long)regs) & ~(THREAD_SIZE - 1);
106#ifdef CONFIG_FRAME_POINTER 74 walk_stackframe(regs->ARM_fp, base, base + THREAD_SIZE,
107 while (depth-- && tail && valid_kernel_stack(tail, regs)) { 75 report_trace, &depth);
108 tail = kernel_backtrace(tail);
109 }
110#endif
111 return; 76 return;
112 } 77 }
113 78