Commit 555f386c98cc93890f48fdea098936755270304b
Committed by
Steven Rostedt
1 parent
1f5a6b4541
Exists in
master
and in
7 other branches
ftrace: document function and function graph implementation
While implementing function tracer and function tracer graph support, I found the exact arch implementation details to be a bit lacking (and my x86 foo ain't great). So after pounding out support for the Blackfin arch, start documenting the requirements/details. Signed-off-by: Mike Frysinger <vapier@gentoo.org> LKML-Reference: <1252973415-21264-1-git-send-email-vapier@gentoo.org> Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Showing 3 changed files with 252 additions and 3 deletions Side-by-side Diff
Documentation/trace/ftrace-design.txt
1 | + function tracer guts | |
2 | + ==================== | |
3 | + | |
4 | +Introduction | |
5 | +------------ | |
6 | + | |
7 | +Here we will cover the architecture pieces that the common function tracing | |
8 | +code relies on for proper functioning. Things are broken down into increasing | |
9 | +complexity so that you can start simple and at least get basic functionality. | |
10 | + | |
11 | +Note that this focuses on architecture implementation details only. If you | |
12 | +want more explanation of a feature in terms of common code, review the common | |
13 | +ftrace.txt file. | |
14 | + | |
15 | + | |
16 | +Prerequisites | |
17 | +------------- | |
18 | + | |
19 | +Ftrace relies on these features being implemented: | |
20 | + STACKTRACE_SUPPORT - implement save_stack_trace() | |
21 | + TRACE_IRQFLAGS_SUPPORT - implement include/asm/irqflags.h | |
22 | + | |
23 | + | |
24 | +HAVE_FUNCTION_TRACER | |
25 | +-------------------- | |
26 | + | |
27 | +You will need to implement the mcount and the ftrace_stub functions. | |
28 | + | |
29 | +The exact mcount symbol name will depend on your toolchain. Some call it | |
30 | +"mcount", "_mcount", or even "__mcount". You can probably figure it out by | |
31 | +running something like: | |
32 | + $ echo 'main(){}' | gcc -x c -S -o - - -pg | grep mcount | |
33 | + call mcount | |
34 | +We'll make the assumption below that the symbol is "mcount" just to keep things | |
35 | +nice and simple in the examples. | |
36 | + | |
37 | +Keep in mind that the ABI that is in effect inside of the mcount function is | |
38 | +*highly* architecture/toolchain specific. We cannot help you in this regard, | |
39 | +sorry. Dig up some old documentation and/or find someone more familiar than | |
40 | +you to bang ideas off of. Typically, register usage (argument/scratch/etc...) | |
41 | +is a major issue at this point, especially in relation to the location of the | |
42 | +mcount call (before/after function prologue). You might also want to look at | |
43 | +how glibc has implemented the mcount function for your architecture. It might | |
44 | +be (semi-)relevant. | |
45 | + | |
46 | +The mcount function should check the function pointer ftrace_trace_function | |
47 | +to see if it is set to ftrace_stub. If it is, there is nothing for you to do, | |
48 | +so return immediately. If it isn't, then call that function in the same way | |
49 | +the mcount function normally calls __mcount_internal -- the first argument is | |
50 | +the "frompc" while the second argument is the "selfpc" (adjusted to remove the | |
51 | +size of the mcount call that is embedded in the function). | |
52 | + | |
53 | +For example, if the function foo() calls bar(), when the bar() function calls | |
54 | +mcount(), the arguments mcount() will pass to the tracer are: | |
55 | + "frompc" - the address bar() will use to return to foo() | |
56 | + "selfpc" - the address bar() (with _mcount() size adjustment) | |
57 | + | |
58 | +Also keep in mind that this mcount function will be called *a lot*, so | |
59 | +optimizing for the default case of no tracer will help the smooth running of | |
60 | +your system when tracing is disabled. So the start of the mcount function is | |
61 | +typically the bare min with checking things before returning. That also means | |
62 | +the code flow should usually kept linear (i.e. no branching in the nop case). | |
63 | +This is of course an optimization and not a hard requirement. | |
64 | + | |
65 | +Here is some pseudo code that should help (these functions should actually be | |
66 | +implemented in assembly): | |
67 | + | |
68 | +void ftrace_stub(void) | |
69 | +{ | |
70 | + return; | |
71 | +} | |
72 | + | |
73 | +void mcount(void) | |
74 | +{ | |
75 | + /* save any bare state needed in order to do initial checking */ | |
76 | + | |
77 | + extern void (*ftrace_trace_function)(unsigned long, unsigned long); | |
78 | + if (ftrace_trace_function != ftrace_stub) | |
79 | + goto do_trace; | |
80 | + | |
81 | + /* restore any bare state */ | |
82 | + | |
83 | + return; | |
84 | + | |
85 | +do_trace: | |
86 | + | |
87 | + /* save all state needed by the ABI (see paragraph above) */ | |
88 | + | |
89 | + unsigned long frompc = ...; | |
90 | + unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; | |
91 | + ftrace_trace_function(frompc, selfpc); | |
92 | + | |
93 | + /* restore all state needed by the ABI */ | |
94 | +} | |
95 | + | |
96 | +Don't forget to export mcount for modules ! | |
97 | +extern void mcount(void); | |
98 | +EXPORT_SYMBOL(mcount); | |
99 | + | |
100 | + | |
101 | +HAVE_FUNCTION_TRACE_MCOUNT_TEST | |
102 | +------------------------------- | |
103 | + | |
104 | +This is an optional optimization for the normal case when tracing is turned off | |
105 | +in the system. If you do not enable this Kconfig option, the common ftrace | |
106 | +code will take care of doing the checking for you. | |
107 | + | |
108 | +To support this feature, you only need to check the function_trace_stop | |
109 | +variable in the mcount function. If it is non-zero, there is no tracing to be | |
110 | +done at all, so you can return. | |
111 | + | |
112 | +This additional pseudo code would simply be: | |
113 | +void mcount(void) | |
114 | +{ | |
115 | + /* save any bare state needed in order to do initial checking */ | |
116 | + | |
117 | ++ if (function_trace_stop) | |
118 | ++ return; | |
119 | + | |
120 | + extern void (*ftrace_trace_function)(unsigned long, unsigned long); | |
121 | + if (ftrace_trace_function != ftrace_stub) | |
122 | +... | |
123 | + | |
124 | + | |
125 | +HAVE_FUNCTION_GRAPH_TRACER | |
126 | +-------------------------- | |
127 | + | |
128 | +Deep breath ... time to do some real work. Here you will need to update the | |
129 | +mcount function to check ftrace graph function pointers, as well as implement | |
130 | +some functions to save (hijack) and restore the return address. | |
131 | + | |
132 | +The mcount function should check the function pointers ftrace_graph_return | |
133 | +(compare to ftrace_stub) and ftrace_graph_entry (compare to | |
134 | +ftrace_graph_entry_stub). If either of those are not set to the relevant stub | |
135 | +function, call the arch-specific function ftrace_graph_caller which in turn | |
136 | +calls the arch-specific function prepare_ftrace_return. Neither of these | |
137 | +function names are strictly required, but you should use them anyways to stay | |
138 | +consistent across the architecture ports -- easier to compare & contrast | |
139 | +things. | |
140 | + | |
141 | +The arguments to prepare_ftrace_return are slightly different than what are | |
142 | +passed to ftrace_trace_function. The second argument "selfpc" is the same, | |
143 | +but the first argument should be a pointer to the "frompc". Typically this is | |
144 | +located on the stack. This allows the function to hijack the return address | |
145 | +temporarily to have it point to the arch-specific function return_to_handler. | |
146 | +That function will simply call the common ftrace_return_to_handler function and | |
147 | +that will return the original return address with which, you can return to the | |
148 | +original call site. | |
149 | + | |
150 | +Here is the updated mcount pseudo code: | |
151 | +void mcount(void) | |
152 | +{ | |
153 | +... | |
154 | + if (ftrace_trace_function != ftrace_stub) | |
155 | + goto do_trace; | |
156 | + | |
157 | ++#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
158 | ++ extern void (*ftrace_graph_return)(...); | |
159 | ++ extern void (*ftrace_graph_entry)(...); | |
160 | ++ if (ftrace_graph_return != ftrace_stub || | |
161 | ++ ftrace_graph_entry != ftrace_graph_entry_stub) | |
162 | ++ ftrace_graph_caller(); | |
163 | ++#endif | |
164 | + | |
165 | + /* restore any bare state */ | |
166 | +... | |
167 | + | |
168 | +Here is the pseudo code for the new ftrace_graph_caller assembly function: | |
169 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
170 | +void ftrace_graph_caller(void) | |
171 | +{ | |
172 | + /* save all state needed by the ABI */ | |
173 | + | |
174 | + unsigned long *frompc = &...; | |
175 | + unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; | |
176 | + prepare_ftrace_return(frompc, selfpc); | |
177 | + | |
178 | + /* restore all state needed by the ABI */ | |
179 | +} | |
180 | +#endif | |
181 | + | |
182 | +For information on how to implement prepare_ftrace_return(), simply look at | |
183 | +the x86 version. The only architecture-specific piece in it is the setup of | |
184 | +the fault recovery table (the asm(...) code). The rest should be the same | |
185 | +across architectures. | |
186 | + | |
187 | +Here is the pseudo code for the new return_to_handler assembly function. Note | |
188 | +that the ABI that applies here is different from what applies to the mcount | |
189 | +code. Since you are returning from a function (after the epilogue), you might | |
190 | +be able to skimp on things saved/restored (usually just registers used to pass | |
191 | +return values). | |
192 | + | |
193 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
194 | +void return_to_handler(void) | |
195 | +{ | |
196 | + /* save all state needed by the ABI (see paragraph above) */ | |
197 | + | |
198 | + void (*original_return_point)(void) = ftrace_return_to_handler(); | |
199 | + | |
200 | + /* restore all state needed by the ABI */ | |
201 | + | |
202 | + /* this is usually either a return or a jump */ | |
203 | + original_return_point(); | |
204 | +} | |
205 | +#endif | |
206 | + | |
207 | + | |
208 | +HAVE_FTRACE_NMI_ENTER | |
209 | +--------------------- | |
210 | + | |
211 | +If you can't trace NMI functions, then skip this option. | |
212 | + | |
213 | +<details to be filled> | |
214 | + | |
215 | + | |
216 | +HAVE_FTRACE_SYSCALLS | |
217 | +--------------------- | |
218 | + | |
219 | +<details to be filled> | |
220 | + | |
221 | + | |
222 | +HAVE_FTRACE_MCOUNT_RECORD | |
223 | +------------------------- | |
224 | + | |
225 | +See scripts/recordmcount.pl for more info. | |
226 | + | |
227 | +<details to be filled> | |
228 | + | |
229 | + | |
230 | +HAVE_DYNAMIC_FTRACE | |
231 | +--------------------- | |
232 | + | |
233 | +<details to be filled> |
Documentation/trace/ftrace.txt
kernel/trace/Kconfig
... | ... | @@ -11,12 +11,18 @@ |
11 | 11 | |
12 | 12 | config HAVE_FTRACE_NMI_ENTER |
13 | 13 | bool |
14 | + help | |
15 | + See Documentation/trace/ftrace-implementation.txt | |
14 | 16 | |
15 | 17 | config HAVE_FUNCTION_TRACER |
16 | 18 | bool |
19 | + help | |
20 | + See Documentation/trace/ftrace-implementation.txt | |
17 | 21 | |
18 | 22 | config HAVE_FUNCTION_GRAPH_TRACER |
19 | 23 | bool |
24 | + help | |
25 | + See Documentation/trace/ftrace-implementation.txt | |
20 | 26 | |
21 | 27 | config HAVE_FUNCTION_GRAPH_FP_TEST |
22 | 28 | bool |
23 | 29 | |
24 | 30 | |
25 | 31 | |
... | ... | @@ -28,21 +34,25 @@ |
28 | 34 | config HAVE_FUNCTION_TRACE_MCOUNT_TEST |
29 | 35 | bool |
30 | 36 | help |
31 | - This gets selected when the arch tests the function_trace_stop | |
32 | - variable at the mcount call site. Otherwise, this variable | |
33 | - is tested by the called function. | |
37 | + See Documentation/trace/ftrace-implementation.txt | |
34 | 38 | |
35 | 39 | config HAVE_DYNAMIC_FTRACE |
36 | 40 | bool |
41 | + help | |
42 | + See Documentation/trace/ftrace-implementation.txt | |
37 | 43 | |
38 | 44 | config HAVE_FTRACE_MCOUNT_RECORD |
39 | 45 | bool |
46 | + help | |
47 | + See Documentation/trace/ftrace-implementation.txt | |
40 | 48 | |
41 | 49 | config HAVE_HW_BRANCH_TRACER |
42 | 50 | bool |
43 | 51 | |
44 | 52 | config HAVE_SYSCALL_TRACEPOINTS |
45 | 53 | bool |
54 | + help | |
55 | + See Documentation/trace/ftrace-implementation.txt | |
46 | 56 | |
47 | 57 | config TRACER_MAX_TRACE |
48 | 58 | bool |