diff options
Diffstat (limited to 'kernel/trace')
-rw-r--r-- | kernel/trace/trace_sysprof.c | 89 |
1 files changed, 80 insertions, 9 deletions
diff --git a/kernel/trace/trace_sysprof.c b/kernel/trace/trace_sysprof.c index 76dd953eeccd..ebcb66d054cc 100644 --- a/kernel/trace/trace_sysprof.c +++ b/kernel/trace/trace_sysprof.c | |||
@@ -14,6 +14,8 @@ | |||
14 | #include <linux/irq.h> | 14 | #include <linux/irq.h> |
15 | #include <linux/fs.h> | 15 | #include <linux/fs.h> |
16 | 16 | ||
17 | #include <asm/stacktrace.h> | ||
18 | |||
17 | #include "trace.h" | 19 | #include "trace.h" |
18 | 20 | ||
19 | static struct trace_array *sysprof_trace; | 21 | static struct trace_array *sysprof_trace; |
@@ -52,6 +54,77 @@ static int copy_stack_frame(const void __user *fp, struct stack_frame *frame) | |||
52 | return ret; | 54 | return ret; |
53 | } | 55 | } |
54 | 56 | ||
57 | struct backtrace_info { | ||
58 | struct trace_array_cpu *data; | ||
59 | struct trace_array *tr; | ||
60 | int pos; | ||
61 | }; | ||
62 | |||
63 | static void | ||
64 | backtrace_warning_symbol(void *data, char *msg, unsigned long symbol) | ||
65 | { | ||
66 | /* Ignore warnings */ | ||
67 | } | ||
68 | |||
69 | static void backtrace_warning(void *data, char *msg) | ||
70 | { | ||
71 | /* Ignore warnings */ | ||
72 | } | ||
73 | |||
74 | static int backtrace_stack(void *data, char *name) | ||
75 | { | ||
76 | /* Don't bother with IRQ stacks for now */ | ||
77 | return -1; | ||
78 | } | ||
79 | |||
80 | static void backtrace_address(void *data, unsigned long addr, int reliable) | ||
81 | { | ||
82 | struct backtrace_info *info = data; | ||
83 | |||
84 | if (info->pos < sample_max_depth && reliable) { | ||
85 | __trace_special(info->tr, info->data, 1, addr, 0); | ||
86 | |||
87 | info->pos++; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | const static struct stacktrace_ops backtrace_ops = { | ||
92 | .warning = backtrace_warning, | ||
93 | .warning_symbol = backtrace_warning_symbol, | ||
94 | .stack = backtrace_stack, | ||
95 | .address = backtrace_address, | ||
96 | }; | ||
97 | |||
98 | static struct pt_regs * | ||
99 | trace_kernel(struct pt_regs *regs, struct trace_array *tr, | ||
100 | struct trace_array_cpu *data) | ||
101 | { | ||
102 | struct backtrace_info info; | ||
103 | unsigned long bp; | ||
104 | char *user_stack; | ||
105 | char *stack; | ||
106 | |||
107 | info.tr = tr; | ||
108 | info.data = data; | ||
109 | info.pos = 1; | ||
110 | |||
111 | __trace_special(info.tr, info.data, 1, regs->ip, 0); | ||
112 | |||
113 | stack = ((char *)regs + sizeof(struct pt_regs)); | ||
114 | #ifdef CONFIG_FRAME_POINTER | ||
115 | bp = regs->bp; | ||
116 | #else | ||
117 | bp = 0; | ||
118 | #endif | ||
119 | |||
120 | dump_trace(NULL, regs, (void *)stack, bp, &backtrace_ops, &info); | ||
121 | |||
122 | /* Now trace the user stack */ | ||
123 | user_stack = ((char *)current->thread.sp0 - sizeof(struct pt_regs)); | ||
124 | |||
125 | return (struct pt_regs *)user_stack; | ||
126 | } | ||
127 | |||
55 | static void timer_notify(struct pt_regs *regs, int cpu) | 128 | static void timer_notify(struct pt_regs *regs, int cpu) |
56 | { | 129 | { |
57 | struct trace_array_cpu *data; | 130 | struct trace_array_cpu *data; |
@@ -74,17 +147,15 @@ static void timer_notify(struct pt_regs *regs, int cpu) | |||
74 | if (is_user && current->state != TASK_RUNNING) | 147 | if (is_user && current->state != TASK_RUNNING) |
75 | return; | 148 | return; |
76 | 149 | ||
77 | if (!is_user) { | 150 | __trace_special(tr, data, 0, 0, current->pid); |
78 | /* kernel */ | ||
79 | ftrace(tr, data, current->pid, 1, 0); | ||
80 | return; | ||
81 | 151 | ||
82 | } | 152 | if (!is_user) |
83 | 153 | regs = trace_kernel(regs, tr, data); | |
84 | __trace_special(tr, data, 0, current->pid, regs->ip); | ||
85 | 154 | ||
86 | fp = (void __user *)regs->bp; | 155 | fp = (void __user *)regs->bp; |
87 | 156 | ||
157 | __trace_special(tr, data, 2, regs->ip, 0); | ||
158 | |||
88 | for (i = 0; i < sample_max_depth; i++) { | 159 | for (i = 0; i < sample_max_depth; i++) { |
89 | frame.next_fp = 0; | 160 | frame.next_fp = 0; |
90 | frame.return_address = 0; | 161 | frame.return_address = 0; |
@@ -93,12 +164,12 @@ static void timer_notify(struct pt_regs *regs, int cpu) | |||
93 | if ((unsigned long)fp < regs->sp) | 164 | if ((unsigned long)fp < regs->sp) |
94 | break; | 165 | break; |
95 | 166 | ||
96 | __trace_special(tr, data, 1, frame.return_address, | 167 | __trace_special(tr, data, 2, frame.return_address, |
97 | (unsigned long)fp); | 168 | (unsigned long)fp); |
98 | fp = frame.next_fp; | 169 | fp = frame.next_fp; |
99 | } | 170 | } |
100 | 171 | ||
101 | __trace_special(tr, data, 2, current->pid, i); | 172 | __trace_special(tr, data, 3, current->pid, i); |
102 | 173 | ||
103 | /* | 174 | /* |
104 | * Special trace entry if we overflow the max depth: | 175 | * Special trace entry if we overflow the max depth: |