diff options
author | Tim Bird <tim.bird@am.sony.com> | 2010-10-09 12:54:38 -0400 |
---|---|---|
committer | Rabin Vincent <rabin@rab.in> | 2010-11-19 11:13:27 -0500 |
commit | 376cfa8730c08c0394d0aa1d4a80fd8c9971f323 (patch) | |
tree | f1384eb77981241b1ab1028a50b94382c2c6e723 | |
parent | d3b9dc9dd2b994f396741f7086ffe7a48bacb165 (diff) |
ARM: ftrace: function graph tracer support
Cc: Tim Bird <tim.bird@am.sony.com>
[rabin@rab.in: rebase on top of latest code,
keep code in ftrace.c instead of separate file,
check for ftrace_graph_entry also]
Signed-off-by: Rabin Vincent <rabin@rab.in>
-rw-r--r-- | arch/arm/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/arm/kernel/entry-common.S | 46 | ||||
-rw-r--r-- | arch/arm/kernel/ftrace.c | 34 |
3 files changed, 82 insertions, 1 deletions
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index 5b9b268f4fbb..679851a9f589 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) | 5 | CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET) |
6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) | 6 | AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET) |
7 | 7 | ||
8 | ifdef CONFIG_DYNAMIC_FTRACE | 8 | ifdef CONFIG_FUNCTION_TRACER |
9 | CFLAGS_REMOVE_ftrace.o = -pg | 9 | CFLAGS_REMOVE_ftrace.o = -pg |
10 | endif | 10 | endif |
11 | 11 | ||
@@ -33,6 +33,7 @@ obj-$(CONFIG_SMP) += smp.o | |||
33 | obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o | 33 | obj-$(CONFIG_HAVE_ARM_SCU) += smp_scu.o |
34 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o | 34 | obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o |
35 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 35 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
36 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
36 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 37 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
37 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o | 38 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o |
38 | obj-$(CONFIG_ATAGS_PROC) += atags.o | 39 | obj-$(CONFIG_ATAGS_PROC) += atags.o |
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S index fe1d5862b19f..9f1766211668 100644 --- a/arch/arm/kernel/entry-common.S +++ b/arch/arm/kernel/entry-common.S | |||
@@ -148,6 +148,20 @@ ENDPROC(ret_from_fork) | |||
148 | adr r0, .Lftrace_stub | 148 | adr r0, .Lftrace_stub |
149 | cmp r0, r2 | 149 | cmp r0, r2 |
150 | bne 1f | 150 | bne 1f |
151 | |||
152 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
153 | ldr r1, =ftrace_graph_return | ||
154 | ldr r2, [r1] | ||
155 | cmp r0, r2 | ||
156 | bne ftrace_graph_caller\suffix | ||
157 | |||
158 | ldr r1, =ftrace_graph_entry | ||
159 | ldr r2, [r1] | ||
160 | ldr r0, =ftrace_graph_entry_stub | ||
161 | cmp r0, r2 | ||
162 | bne ftrace_graph_caller\suffix | ||
163 | #endif | ||
164 | |||
151 | mcount_exit | 165 | mcount_exit |
152 | 166 | ||
153 | 1: mcount_get_lr r1 @ lr of instrumented func | 167 | 1: mcount_get_lr r1 @ lr of instrumented func |
@@ -172,6 +186,15 @@ ftrace_call\suffix: | |||
172 | mcount_exit | 186 | mcount_exit |
173 | .endm | 187 | .endm |
174 | 188 | ||
189 | .macro __ftrace_graph_caller | ||
190 | sub r0, fp, #4 @ &lr of instrumented routine (&parent) | ||
191 | mov r1, lr @ instrumented routine (func) | ||
192 | sub r1, r1, #MCOUNT_INSN_SIZE | ||
193 | mov r2, fp @ frame pointer | ||
194 | bl prepare_ftrace_return | ||
195 | mcount_exit | ||
196 | .endm | ||
197 | |||
175 | #ifdef CONFIG_OLD_MCOUNT | 198 | #ifdef CONFIG_OLD_MCOUNT |
176 | /* | 199 | /* |
177 | * mcount | 200 | * mcount |
@@ -206,6 +229,12 @@ ENTRY(ftrace_caller_old) | |||
206 | ENDPROC(ftrace_caller_old) | 229 | ENDPROC(ftrace_caller_old) |
207 | #endif | 230 | #endif |
208 | 231 | ||
232 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
233 | ENTRY(ftrace_graph_caller_old) | ||
234 | __ftrace_graph_caller | ||
235 | ENDPROC(ftrace_graph_caller_old) | ||
236 | #endif | ||
237 | |||
209 | .purgem mcount_enter | 238 | .purgem mcount_enter |
210 | .purgem mcount_get_lr | 239 | .purgem mcount_get_lr |
211 | .purgem mcount_exit | 240 | .purgem mcount_exit |
@@ -244,10 +273,27 @@ ENTRY(ftrace_caller) | |||
244 | ENDPROC(ftrace_caller) | 273 | ENDPROC(ftrace_caller) |
245 | #endif | 274 | #endif |
246 | 275 | ||
276 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
277 | ENTRY(ftrace_graph_caller) | ||
278 | __ftrace_graph_caller | ||
279 | ENDPROC(ftrace_graph_caller) | ||
280 | #endif | ||
281 | |||
247 | .purgem mcount_enter | 282 | .purgem mcount_enter |
248 | .purgem mcount_get_lr | 283 | .purgem mcount_get_lr |
249 | .purgem mcount_exit | 284 | .purgem mcount_exit |
250 | 285 | ||
286 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
287 | .globl return_to_handler | ||
288 | return_to_handler: | ||
289 | stmdb sp!, {r0-r3} | ||
290 | mov r0, fp @ frame pointer | ||
291 | bl ftrace_return_to_handler | ||
292 | mov lr, r0 @ r0 has real ret addr | ||
293 | ldmia sp!, {r0-r3} | ||
294 | mov pc, lr | ||
295 | #endif | ||
296 | |||
251 | ENTRY(ftrace_stub) | 297 | ENTRY(ftrace_stub) |
252 | .Lftrace_stub: | 298 | .Lftrace_stub: |
253 | mov pc, lr | 299 | mov pc, lr |
diff --git a/arch/arm/kernel/ftrace.c b/arch/arm/kernel/ftrace.c index 971ac8c36ea7..7a702a502871 100644 --- a/arch/arm/kernel/ftrace.c +++ b/arch/arm/kernel/ftrace.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #define NOP 0xe8bd4000 /* pop {lr} */ | 24 | #define NOP 0xe8bd4000 /* pop {lr} */ |
25 | #endif | 25 | #endif |
26 | 26 | ||
27 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
27 | #ifdef CONFIG_OLD_MCOUNT | 28 | #ifdef CONFIG_OLD_MCOUNT |
28 | #define OLD_MCOUNT_ADDR ((unsigned long) mcount) | 29 | #define OLD_MCOUNT_ADDR ((unsigned long) mcount) |
29 | #define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) | 30 | #define OLD_FTRACE_ADDR ((unsigned long) ftrace_caller_old) |
@@ -193,3 +194,36 @@ int __init ftrace_dyn_arch_init(void *data) | |||
193 | 194 | ||
194 | return 0; | 195 | return 0; |
195 | } | 196 | } |
197 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
198 | |||
199 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
200 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | ||
201 | unsigned long frame_pointer) | ||
202 | { | ||
203 | unsigned long return_hooker = (unsigned long) &return_to_handler; | ||
204 | struct ftrace_graph_ent trace; | ||
205 | unsigned long old; | ||
206 | int err; | ||
207 | |||
208 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
209 | return; | ||
210 | |||
211 | old = *parent; | ||
212 | *parent = return_hooker; | ||
213 | |||
214 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, | ||
215 | frame_pointer); | ||
216 | if (err == -EBUSY) { | ||
217 | *parent = old; | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | trace.func = self_addr; | ||
222 | |||
223 | /* Only trace if the calling function expects to */ | ||
224 | if (!ftrace_graph_entry(&trace)) { | ||
225 | current->curr_ret_stack--; | ||
226 | *parent = old; | ||
227 | } | ||
228 | } | ||
229 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||