diff options
author | Michal Simek <monstr@monstr.eu> | 2009-11-16 04:32:10 -0500 |
---|---|---|
committer | Michal Simek <monstr@monstr.eu> | 2009-12-14 02:44:53 -0500 |
commit | a0d3e66522e8f6119f002cf31e5d92d7ae73b409 (patch) | |
tree | 717d36ef5a2e103669403011317a88b1af84c9d3 /arch | |
parent | 7d241ff0567b9503d79ee775c40927d09b509f83 (diff) |
microblaze: ftrace: add function graph support
For more information look at Documentation/trace folder.
Signed-off-by: Michal Simek <monstr@monstr.eu>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/microblaze/Kconfig | 1 | ||||
-rw-r--r-- | arch/microblaze/kernel/ftrace.c | 58 | ||||
-rw-r--r-- | arch/microblaze/kernel/mcount.S | 41 |
3 files changed, 100 insertions, 0 deletions
diff --git a/arch/microblaze/Kconfig b/arch/microblaze/Kconfig index 102d73aa1063..e297802b8321 100644 --- a/arch/microblaze/Kconfig +++ b/arch/microblaze/Kconfig | |||
@@ -8,6 +8,7 @@ config MICROBLAZE | |||
8 | select HAVE_LMB | 8 | select HAVE_LMB |
9 | select HAVE_FUNCTION_TRACER | 9 | select HAVE_FUNCTION_TRACER |
10 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST | 10 | select HAVE_FUNCTION_TRACE_MCOUNT_TEST |
11 | select HAVE_FUNCTION_GRAPH_TRACER | ||
11 | select HAVE_DYNAMIC_FTRACE | 12 | select HAVE_DYNAMIC_FTRACE |
12 | select HAVE_FTRACE_MCOUNT_RECORD | 13 | select HAVE_FTRACE_MCOUNT_RECORD |
13 | select USB_ARCH_HAS_EHCI | 14 | select USB_ARCH_HAS_EHCI |
diff --git a/arch/microblaze/kernel/ftrace.c b/arch/microblaze/kernel/ftrace.c index c1889b101cb8..0952a8b52c35 100644 --- a/arch/microblaze/kernel/ftrace.c +++ b/arch/microblaze/kernel/ftrace.c | |||
@@ -14,6 +14,64 @@ | |||
14 | #include <asm/cacheflush.h> | 14 | #include <asm/cacheflush.h> |
15 | #include <linux/ftrace.h> | 15 | #include <linux/ftrace.h> |
16 | 16 | ||
17 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
18 | /* | ||
19 | * Hook the return address and push it in the stack of return addrs | ||
20 | * in current thread info. | ||
21 | */ | ||
22 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr) | ||
23 | { | ||
24 | unsigned long old; | ||
25 | int faulted, err; | ||
26 | struct ftrace_graph_ent trace; | ||
27 | unsigned long return_hooker = (unsigned long) | ||
28 | &return_to_handler; | ||
29 | |||
30 | if (unlikely(atomic_read(¤t->tracing_graph_pause))) | ||
31 | return; | ||
32 | |||
33 | /* | ||
34 | * Protect against fault, even if it shouldn't | ||
35 | * happen. This tool is too much intrusive to | ||
36 | * ignore such a protection. | ||
37 | */ | ||
38 | asm volatile(" 1: lwi %0, %2, 0; \ | ||
39 | 2: swi %3, %2, 0; \ | ||
40 | addik %1, r0, 0; \ | ||
41 | 3: \ | ||
42 | .section .fixup, \"ax\"; \ | ||
43 | 4: brid 3b; \ | ||
44 | addik %1, r0, 1; \ | ||
45 | .previous; \ | ||
46 | .section __ex_table,\"a\"; \ | ||
47 | .word 1b,4b; \ | ||
48 | .word 2b,4b; \ | ||
49 | .previous;" \ | ||
50 | : "=&r" (old), "=r" (faulted) | ||
51 | : "r" (parent), "r" (return_hooker) | ||
52 | ); | ||
53 | |||
54 | if (unlikely(faulted)) { | ||
55 | ftrace_graph_stop(); | ||
56 | WARN_ON(1); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, 0); | ||
61 | if (err == -EBUSY) { | ||
62 | *parent = old; | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | trace.func = self_addr; | ||
67 | /* Only trace if the calling function expects to */ | ||
68 | if (!ftrace_graph_entry(&trace)) { | ||
69 | current->curr_ret_stack--; | ||
70 | *parent = old; | ||
71 | } | ||
72 | } | ||
73 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
74 | |||
17 | #ifdef CONFIG_DYNAMIC_FTRACE | 75 | #ifdef CONFIG_DYNAMIC_FTRACE |
18 | /* save value to addr - it is save to do it in asm */ | 76 | /* save value to addr - it is save to do it in asm */ |
19 | static int ftrace_modify_code(unsigned long addr, unsigned int value) | 77 | static int ftrace_modify_code(unsigned long addr, unsigned int value) |
diff --git a/arch/microblaze/kernel/mcount.S b/arch/microblaze/kernel/mcount.S index 30aaf8fb55b2..84a19458c74d 100644 --- a/arch/microblaze/kernel/mcount.S +++ b/arch/microblaze/kernel/mcount.S | |||
@@ -96,6 +96,27 @@ ENTRY(ftrace_caller) | |||
96 | bneid r5, end; | 96 | bneid r5, end; |
97 | nop; | 97 | nop; |
98 | /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST end of checking */ | 98 | /* MS: HAVE_FUNCTION_TRACE_MCOUNT_TEST end of checking */ |
99 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
100 | lwi r5, r0, ftrace_graph_return; | ||
101 | addik r6, r0, ftrace_stub; /* asm implementation */ | ||
102 | cmpu r5, r5, r6; /* ftrace_graph_return != ftrace_stub */ | ||
103 | beqid r5, end_graph_tracer; | ||
104 | nop; | ||
105 | |||
106 | lwi r6, r0, ftrace_graph_entry; | ||
107 | addik r5, r0, ftrace_graph_entry_stub; /* implemented in C */ | ||
108 | cmpu r5, r5, r6; /* ftrace_graph_entry != ftrace_graph_entry_stub */ | ||
109 | beqid r5, end_graph_tracer; | ||
110 | nop; | ||
111 | addik r5, r1, 120; /* MS: load parent addr */ | ||
112 | addik r6, r15, 0; /* MS: load current function addr */ | ||
113 | bralid r15, prepare_ftrace_return; | ||
114 | nop; | ||
115 | /* MS: graph was taken that's why - can jump over function trace */ | ||
116 | brid end; | ||
117 | nop; | ||
118 | end_graph_tracer: | ||
119 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
99 | #ifndef CONFIG_DYNAMIC_FTRACE | 120 | #ifndef CONFIG_DYNAMIC_FTRACE |
100 | /* MS: test function trace if is taken or not */ | 121 | /* MS: test function trace if is taken or not */ |
101 | lwi r20, r0, ftrace_trace_function; | 122 | lwi r20, r0, ftrace_trace_function; |
@@ -121,3 +142,23 @@ end: | |||
121 | 142 | ||
122 | rtsd r15, 8; /* MS: jump back */ | 143 | rtsd r15, 8; /* MS: jump back */ |
123 | nop; | 144 | nop; |
145 | |||
146 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
147 | ENTRY(return_to_handler) | ||
148 | nop; /* MS: just barrier for rtsd r15, 8 */ | ||
149 | nop; | ||
150 | SAVE_REGS | ||
151 | swi r15, r1, 0; | ||
152 | |||
153 | /* MS: find out returning address */ | ||
154 | bralid r15, ftrace_return_to_handler; | ||
155 | nop; | ||
156 | |||
157 | /* MS: return value from ftrace_return_to_handler is my returning addr | ||
158 | * must be before restore regs because I have to restore r3 content */ | ||
159 | addik r15, r3, 0; | ||
160 | RESTORE_REGS | ||
161 | |||
162 | rtsd r15, 8; /* MS: jump back */ | ||
163 | nop; | ||
164 | #endif /* CONFIG_FUNCTION_TRACER */ | ||