diff options
author | Mike Frysinger <vapier@gentoo.org> | 2009-06-10 04:45:29 -0400 |
---|---|---|
committer | Mike Frysinger <vapier@gentoo.org> | 2009-06-13 07:20:16 -0400 |
commit | 1ee76d7e169ff2b0ff1df4b40b9d5276eec9ffb4 (patch) | |
tree | 384f296a2e24ee0156a81d9b62cdf6bc48d10650 | |
parent | 1c873be744410e26fb91ee9228c90adff6eabe15 (diff) |
Blackfin: initial support for ftrace grapher
Signed-off-by: Mike Frysinger <vapier@gentoo.org>
-rw-r--r-- | arch/blackfin/Kconfig | 1 | ||||
-rw-r--r-- | arch/blackfin/kernel/Makefile | 3 | ||||
-rw-r--r-- | arch/blackfin/kernel/ftrace-entry.S | 68 | ||||
-rw-r--r-- | arch/blackfin/kernel/ftrace.c | 42 | ||||
-rw-r--r-- | arch/blackfin/kernel/vmlinux.lds.S | 1 |
5 files changed, 115 insertions, 0 deletions
diff --git a/arch/blackfin/Kconfig b/arch/blackfin/Kconfig index ea8d92c1d447..5bc1360de2ee 100644 --- a/arch/blackfin/Kconfig +++ b/arch/blackfin/Kconfig | |||
@@ -19,6 +19,7 @@ config RWSEM_XCHGADD_ALGORITHM | |||
19 | 19 | ||
20 | config BLACKFIN | 20 | config BLACKFIN |
21 | def_bool y | 21 | def_bool y |
22 | select HAVE_FUNCTION_GRAPH_TRACER | ||
22 | select HAVE_FUNCTION_TRACER | 23 | select HAVE_FUNCTION_TRACER |
23 | select HAVE_IDE | 24 | select HAVE_IDE |
24 | select HAVE_KERNEL_GZIP | 25 | select HAVE_KERNEL_GZIP |
diff --git a/arch/blackfin/kernel/Makefile b/arch/blackfin/kernel/Makefile index d2ae285e5b6e..3731088e181b 100644 --- a/arch/blackfin/kernel/Makefile +++ b/arch/blackfin/kernel/Makefile | |||
@@ -16,6 +16,9 @@ else | |||
16 | endif | 16 | endif |
17 | 17 | ||
18 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o | 18 | obj-$(CONFIG_FUNCTION_TRACER) += ftrace-entry.o |
19 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | ||
20 | CFLAGS_REMOVE_ftrace.o = -pg | ||
21 | |||
19 | obj-$(CONFIG_IPIPE) += ipipe.o | 22 | obj-$(CONFIG_IPIPE) += ipipe.o |
20 | obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o | 23 | obj-$(CONFIG_IPIPE_TRACE_MCOUNT) += mcount.o |
21 | obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o | 24 | obj-$(CONFIG_BFIN_GPTIMERS) += gptimers.o |
diff --git a/arch/blackfin/kernel/ftrace-entry.S b/arch/blackfin/kernel/ftrace-entry.S index ce71487b515f..6980b7a0615d 100644 --- a/arch/blackfin/kernel/ftrace-entry.S +++ b/arch/blackfin/kernel/ftrace-entry.S | |||
@@ -35,6 +35,28 @@ ENTRY(__mcount) | |||
35 | cc = r2 == r3; | 35 | cc = r2 == r3; |
36 | if ! cc jump .Ldo_trace; | 36 | if ! cc jump .Ldo_trace; |
37 | 37 | ||
38 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
39 | /* if the ftrace_graph_return function pointer is not set to | ||
40 | * the ftrace_stub entry, call prepare_ftrace_return(). | ||
41 | */ | ||
42 | p0.l = _ftrace_graph_return; | ||
43 | p0.h = _ftrace_graph_return; | ||
44 | r3 = [p0]; | ||
45 | cc = r2 == r3; | ||
46 | if ! cc jump _ftrace_graph_caller; | ||
47 | |||
48 | /* similarly, if the ftrace_graph_entry function pointer is not | ||
49 | * set to the ftrace_graph_entry_stub entry, ... | ||
50 | */ | ||
51 | p0.l = _ftrace_graph_entry; | ||
52 | p0.h = _ftrace_graph_entry; | ||
53 | r2.l = _ftrace_graph_entry_stub; | ||
54 | r2.h = _ftrace_graph_entry_stub; | ||
55 | r3 = [p0]; | ||
56 | cc = r2 == r3; | ||
57 | if ! cc jump _ftrace_graph_caller; | ||
58 | #endif | ||
59 | |||
38 | r2 = [sp++]; | 60 | r2 = [sp++]; |
39 | rts; | 61 | rts; |
40 | 62 | ||
@@ -61,6 +83,7 @@ ENTRY(__mcount) | |||
61 | call (p0); | 83 | call (p0); |
62 | 84 | ||
63 | /* restore state and get out of dodge */ | 85 | /* restore state and get out of dodge */ |
86 | .Lfinish_trace: | ||
64 | rets = [sp++]; | 87 | rets = [sp++]; |
65 | r1 = [sp++]; | 88 | r1 = [sp++]; |
66 | r0 = [sp++]; | 89 | r0 = [sp++]; |
@@ -70,3 +93,48 @@ ENTRY(__mcount) | |||
70 | _ftrace_stub: | 93 | _ftrace_stub: |
71 | rts; | 94 | rts; |
72 | ENDPROC(__mcount) | 95 | ENDPROC(__mcount) |
96 | |||
97 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
98 | /* The prepare_ftrace_return() function is similar to the trace function | ||
99 | * except it takes a pointer to the location of the frompc. This is so | ||
100 | * the prepare_ftrace_return() can hijack it temporarily for probing | ||
101 | * purposes. | ||
102 | */ | ||
103 | ENTRY(_ftrace_graph_caller) | ||
104 | /* save first/second function arg and the return register */ | ||
105 | [--sp] = r0; | ||
106 | [--sp] = r1; | ||
107 | [--sp] = rets; | ||
108 | |||
109 | r0 = fp; | ||
110 | r1 = rets; | ||
111 | r0 += 4; | ||
112 | r1 += -MCOUNT_INSN_SIZE; | ||
113 | call _prepare_ftrace_return; | ||
114 | |||
115 | jump .Lfinish_trace; | ||
116 | ENDPROC(_ftrace_graph_caller) | ||
117 | |||
118 | /* Undo the rewrite caused by ftrace_graph_caller(). The common function | ||
119 | * ftrace_return_to_handler() will return the original rets so we can | ||
120 | * restore it and be on our way. | ||
121 | */ | ||
122 | ENTRY(_return_to_handler) | ||
123 | /* make sure original return values are saved */ | ||
124 | [--sp] = p0; | ||
125 | [--sp] = r0; | ||
126 | [--sp] = r1; | ||
127 | |||
128 | /* get original return address */ | ||
129 | call _ftrace_return_to_handler; | ||
130 | rets = r0; | ||
131 | |||
132 | /* anomaly 05000371 - make sure we have at least three instructions | ||
133 | * between rets setting and the return | ||
134 | */ | ||
135 | r1 = [sp++]; | ||
136 | r0 = [sp++]; | ||
137 | p0 = [sp++]; | ||
138 | rts; | ||
139 | ENDPROC(_return_to_handler) | ||
140 | #endif | ||
diff --git a/arch/blackfin/kernel/ftrace.c b/arch/blackfin/kernel/ftrace.c new file mode 100644 index 000000000000..905bfc40a00b --- /dev/null +++ b/arch/blackfin/kernel/ftrace.c | |||
@@ -0,0 +1,42 @@ | |||
1 | /* | ||
2 | * ftrace graph code | ||
3 | * | ||
4 | * Copyright (C) 2009 Analog Devices Inc. | ||
5 | * Licensed under the GPL-2 or later. | ||
6 | */ | ||
7 | |||
8 | #include <linux/ftrace.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <asm/atomic.h> | ||
12 | |||
13 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
14 | |||
15 | /* | ||
16 | * Hook the return address and push it in the stack of return addrs | ||
17 | * in current thread info. | ||
18 | */ | ||
19 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | ||
20 | { | ||
21 | struct ftrace_graph_ent trace; | ||
22 | unsigned long return_hooker = (unsigned long)&return_to_handler; | ||
23 | |||
24 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
25 | return; | ||
26 | |||
27 | if (ftrace_push_return_trace(*parent, self_addr, &trace.depth) == -EBUSY) | ||
28 | return; | ||
29 | |||
30 | trace.func = self_addr; | ||
31 | |||
32 | /* Only trace if the calling function expects to */ | ||
33 | if (!ftrace_graph_entry(&trace)) { | ||
34 | current->curr_ret_stack--; | ||
35 | return; | ||
36 | } | ||
37 | |||
38 | /* all is well in the world ! hijack RETS ... */ | ||
39 | *parent = return_hooker; | ||
40 | } | ||
41 | |||
42 | #endif | ||
diff --git a/arch/blackfin/kernel/vmlinux.lds.S b/arch/blackfin/kernel/vmlinux.lds.S index 119fbdb46475..6ac307ca0d80 100644 --- a/arch/blackfin/kernel/vmlinux.lds.S +++ b/arch/blackfin/kernel/vmlinux.lds.S | |||
@@ -54,6 +54,7 @@ SECTIONS | |||
54 | SCHED_TEXT | 54 | SCHED_TEXT |
55 | #endif | 55 | #endif |
56 | LOCK_TEXT | 56 | LOCK_TEXT |
57 | IRQENTRY_TEXT | ||
57 | KPROBES_TEXT | 58 | KPROBES_TEXT |
58 | *(.text.*) | 59 | *(.text.*) |
59 | *(.fixup) | 60 | *(.fixup) |