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 */ | ||
