aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sh/oprofile/backtrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/sh/oprofile/backtrace.c')
-rw-r--r--arch/sh/oprofile/backtrace.c84
1 files changed, 37 insertions, 47 deletions
diff --git a/arch/sh/oprofile/backtrace.c b/arch/sh/oprofile/backtrace.c
index 9499a2914f89..2bc74de23f08 100644
--- a/arch/sh/oprofile/backtrace.c
+++ b/arch/sh/oprofile/backtrace.c
@@ -17,9 +17,43 @@
17#include <linux/sched.h> 17#include <linux/sched.h>
18#include <linux/kallsyms.h> 18#include <linux/kallsyms.h>
19#include <linux/mm.h> 19#include <linux/mm.h>
20#include <asm/unwinder.h>
20#include <asm/ptrace.h> 21#include <asm/ptrace.h>
21#include <asm/uaccess.h> 22#include <asm/uaccess.h>
22#include <asm/sections.h> 23#include <asm/sections.h>
24#include <asm/stacktrace.h>
25
26static void backtrace_warning_symbol(void *data, char *msg,
27 unsigned long symbol)
28{
29 /* Ignore warnings */
30}
31
32static void backtrace_warning(void *data, char *msg)
33{
34 /* Ignore warnings */
35}
36
37static int backtrace_stack(void *data, char *name)
38{
39 /* Yes, we want all stacks */
40 return 0;
41}
42
43static void backtrace_address(void *data, unsigned long addr, int reliable)
44{
45 unsigned int *depth = data;
46
47 if ((*depth)--)
48 oprofile_add_trace(addr);
49}
50
51static struct stacktrace_ops backtrace_ops = {
52 .warning = backtrace_warning,
53 .warning_symbol = backtrace_warning_symbol,
54 .stack = backtrace_stack,
55 .address = backtrace_address,
56};
23 57
24/* Limit to stop backtracing too far. */ 58/* Limit to stop backtracing too far. */
25static int backtrace_limit = 20; 59static int backtrace_limit = 20;
@@ -47,50 +81,6 @@ user_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
47 return stackaddr; 81 return stackaddr;
48} 82}
49 83
50/*
51 * | | /\ Higher addresses
52 * | |
53 * --------------- stack base (address of current_thread_info)
54 * | thread info |
55 * . .
56 * | stack |
57 * --------------- saved regs->regs[15] value if valid
58 * . .
59 * --------------- struct pt_regs stored on stack (struct pt_regs *)
60 * | |
61 * . .
62 * | |
63 * --------------- ???
64 * | |
65 * | | \/ Lower addresses
66 *
67 * Thus, &pt_regs <-> stack base restricts the valid(ish) fp values
68 */
69static int valid_kernel_stack(unsigned long *stackaddr, struct pt_regs *regs)
70{
71 unsigned long stack = (unsigned long)regs;
72 unsigned long stack_base = (stack & ~(THREAD_SIZE - 1)) + THREAD_SIZE;
73
74 return ((unsigned long)stackaddr > stack) && ((unsigned long)stackaddr < stack_base);
75}
76
77static unsigned long *
78kernel_backtrace(unsigned long *stackaddr, struct pt_regs *regs)
79{
80 unsigned long addr;
81
82 /*
83 * If not a valid kernel address, keep going till we find one
84 * or the SP stops being a valid address.
85 */
86 do {
87 addr = *stackaddr++;
88 oprofile_add_trace(addr);
89 } while (valid_kernel_stack(stackaddr, regs));
90
91 return stackaddr;
92}
93
94void sh_backtrace(struct pt_regs * const regs, unsigned int depth) 84void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
95{ 85{
96 unsigned long *stackaddr; 86 unsigned long *stackaddr;
@@ -103,9 +93,9 @@ void sh_backtrace(struct pt_regs * const regs, unsigned int depth)
103 93
104 stackaddr = (unsigned long *)regs->regs[15]; 94 stackaddr = (unsigned long *)regs->regs[15];
105 if (!user_mode(regs)) { 95 if (!user_mode(regs)) {
106 while (depth-- && valid_kernel_stack(stackaddr, regs)) 96 if (depth)
107 stackaddr = kernel_backtrace(stackaddr, regs); 97 unwind_stack(NULL, regs, stackaddr,
108 98 &backtrace_ops, &depth);
109 return; 99 return;
110 } 100 }
111 101