Commit | Line | Data |
---|---|---|
555f386c MF |
1 | function tracer guts |
2 | ==================== | |
03688970 | 3 | By Mike Frysinger |
555f386c MF |
4 | |
5 | Introduction | |
6 | ------------ | |
7 | ||
8 | Here we will cover the architecture pieces that the common function tracing | |
9 | code relies on for proper functioning. Things are broken down into increasing | |
10 | complexity so that you can start simple and at least get basic functionality. | |
11 | ||
12 | Note that this focuses on architecture implementation details only. If you | |
13 | want more explanation of a feature in terms of common code, review the common | |
14 | ftrace.txt file. | |
15 | ||
16 | ||
17 | Prerequisites | |
18 | ------------- | |
19 | ||
20 | Ftrace relies on these features being implemented: | |
21 | STACKTRACE_SUPPORT - implement save_stack_trace() | |
22 | TRACE_IRQFLAGS_SUPPORT - implement include/asm/irqflags.h | |
23 | ||
24 | ||
25 | HAVE_FUNCTION_TRACER | |
26 | -------------------- | |
27 | ||
28 | You will need to implement the mcount and the ftrace_stub functions. | |
29 | ||
30 | The exact mcount symbol name will depend on your toolchain. Some call it | |
31 | "mcount", "_mcount", or even "__mcount". You can probably figure it out by | |
32 | running something like: | |
33 | $ echo 'main(){}' | gcc -x c -S -o - - -pg | grep mcount | |
34 | call mcount | |
35 | We'll make the assumption below that the symbol is "mcount" just to keep things | |
36 | nice and simple in the examples. | |
37 | ||
38 | Keep in mind that the ABI that is in effect inside of the mcount function is | |
39 | *highly* architecture/toolchain specific. We cannot help you in this regard, | |
40 | sorry. Dig up some old documentation and/or find someone more familiar than | |
41 | you to bang ideas off of. Typically, register usage (argument/scratch/etc...) | |
42 | is a major issue at this point, especially in relation to the location of the | |
43 | mcount call (before/after function prologue). You might also want to look at | |
44 | how glibc has implemented the mcount function for your architecture. It might | |
45 | be (semi-)relevant. | |
46 | ||
47 | The mcount function should check the function pointer ftrace_trace_function | |
48 | to see if it is set to ftrace_stub. If it is, there is nothing for you to do, | |
49 | so return immediately. If it isn't, then call that function in the same way | |
50 | the mcount function normally calls __mcount_internal -- the first argument is | |
51 | the "frompc" while the second argument is the "selfpc" (adjusted to remove the | |
52 | size of the mcount call that is embedded in the function). | |
53 | ||
54 | For example, if the function foo() calls bar(), when the bar() function calls | |
55 | mcount(), the arguments mcount() will pass to the tracer are: | |
56 | "frompc" - the address bar() will use to return to foo() | |
7e25f44c | 57 | "selfpc" - the address bar() (with mcount() size adjustment) |
555f386c MF |
58 | |
59 | Also keep in mind that this mcount function will be called *a lot*, so | |
60 | optimizing for the default case of no tracer will help the smooth running of | |
61 | your system when tracing is disabled. So the start of the mcount function is | |
7e25f44c RD |
62 | typically the bare minimum with checking things before returning. That also |
63 | means the code flow should usually be kept linear (i.e. no branching in the nop | |
64 | case). This is of course an optimization and not a hard requirement. | |
555f386c MF |
65 | |
66 | Here is some pseudo code that should help (these functions should actually be | |
67 | implemented in assembly): | |
68 | ||
69 | void ftrace_stub(void) | |
70 | { | |
71 | return; | |
72 | } | |
73 | ||
74 | void mcount(void) | |
75 | { | |
76 | /* save any bare state needed in order to do initial checking */ | |
77 | ||
78 | extern void (*ftrace_trace_function)(unsigned long, unsigned long); | |
79 | if (ftrace_trace_function != ftrace_stub) | |
80 | goto do_trace; | |
81 | ||
82 | /* restore any bare state */ | |
83 | ||
84 | return; | |
85 | ||
86 | do_trace: | |
87 | ||
88 | /* save all state needed by the ABI (see paragraph above) */ | |
89 | ||
90 | unsigned long frompc = ...; | |
91 | unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; | |
92 | ftrace_trace_function(frompc, selfpc); | |
93 | ||
94 | /* restore all state needed by the ABI */ | |
95 | } | |
96 | ||
97 | Don't forget to export mcount for modules ! | |
98 | extern void mcount(void); | |
99 | EXPORT_SYMBOL(mcount); | |
100 | ||
101 | ||
102 | HAVE_FUNCTION_TRACE_MCOUNT_TEST | |
103 | ------------------------------- | |
104 | ||
105 | This is an optional optimization for the normal case when tracing is turned off | |
106 | in the system. If you do not enable this Kconfig option, the common ftrace | |
107 | code will take care of doing the checking for you. | |
108 | ||
109 | To support this feature, you only need to check the function_trace_stop | |
110 | variable in the mcount function. If it is non-zero, there is no tracing to be | |
111 | done at all, so you can return. | |
112 | ||
113 | This additional pseudo code would simply be: | |
114 | void mcount(void) | |
115 | { | |
116 | /* save any bare state needed in order to do initial checking */ | |
117 | ||
118 | + if (function_trace_stop) | |
119 | + return; | |
120 | ||
121 | extern void (*ftrace_trace_function)(unsigned long, unsigned long); | |
122 | if (ftrace_trace_function != ftrace_stub) | |
123 | ... | |
124 | ||
125 | ||
126 | HAVE_FUNCTION_GRAPH_TRACER | |
127 | -------------------------- | |
128 | ||
129 | Deep breath ... time to do some real work. Here you will need to update the | |
130 | mcount function to check ftrace graph function pointers, as well as implement | |
131 | some functions to save (hijack) and restore the return address. | |
132 | ||
133 | The mcount function should check the function pointers ftrace_graph_return | |
134 | (compare to ftrace_stub) and ftrace_graph_entry (compare to | |
7e25f44c | 135 | ftrace_graph_entry_stub). If either of those is not set to the relevant stub |
555f386c MF |
136 | function, call the arch-specific function ftrace_graph_caller which in turn |
137 | calls the arch-specific function prepare_ftrace_return. Neither of these | |
7e25f44c | 138 | function names is strictly required, but you should use them anyway to stay |
555f386c MF |
139 | consistent across the architecture ports -- easier to compare & contrast |
140 | things. | |
141 | ||
142 | The arguments to prepare_ftrace_return are slightly different than what are | |
143 | passed to ftrace_trace_function. The second argument "selfpc" is the same, | |
144 | but the first argument should be a pointer to the "frompc". Typically this is | |
145 | located on the stack. This allows the function to hijack the return address | |
146 | temporarily to have it point to the arch-specific function return_to_handler. | |
147 | That function will simply call the common ftrace_return_to_handler function and | |
7e25f44c | 148 | that will return the original return address with which you can return to the |
555f386c MF |
149 | original call site. |
150 | ||
151 | Here is the updated mcount pseudo code: | |
152 | void mcount(void) | |
153 | { | |
154 | ... | |
155 | if (ftrace_trace_function != ftrace_stub) | |
156 | goto do_trace; | |
157 | ||
158 | +#ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
159 | + extern void (*ftrace_graph_return)(...); | |
160 | + extern void (*ftrace_graph_entry)(...); | |
161 | + if (ftrace_graph_return != ftrace_stub || | |
162 | + ftrace_graph_entry != ftrace_graph_entry_stub) | |
163 | + ftrace_graph_caller(); | |
164 | +#endif | |
165 | ||
166 | /* restore any bare state */ | |
167 | ... | |
168 | ||
169 | Here is the pseudo code for the new ftrace_graph_caller assembly function: | |
170 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
171 | void ftrace_graph_caller(void) | |
172 | { | |
173 | /* save all state needed by the ABI */ | |
174 | ||
175 | unsigned long *frompc = &...; | |
176 | unsigned long selfpc = <return address> - MCOUNT_INSN_SIZE; | |
03688970 MF |
177 | /* passing frame pointer up is optional -- see below */ |
178 | prepare_ftrace_return(frompc, selfpc, frame_pointer); | |
555f386c MF |
179 | |
180 | /* restore all state needed by the ABI */ | |
181 | } | |
182 | #endif | |
183 | ||
03688970 MF |
184 | For information on how to implement prepare_ftrace_return(), simply look at the |
185 | x86 version (the frame pointer passing is optional; see the next section for | |
186 | more information). The only architecture-specific piece in it is the setup of | |
555f386c MF |
187 | the fault recovery table (the asm(...) code). The rest should be the same |
188 | across architectures. | |
189 | ||
190 | Here is the pseudo code for the new return_to_handler assembly function. Note | |
191 | that the ABI that applies here is different from what applies to the mcount | |
192 | code. Since you are returning from a function (after the epilogue), you might | |
193 | be able to skimp on things saved/restored (usually just registers used to pass | |
194 | return values). | |
195 | ||
196 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | |
197 | void return_to_handler(void) | |
198 | { | |
199 | /* save all state needed by the ABI (see paragraph above) */ | |
200 | ||
201 | void (*original_return_point)(void) = ftrace_return_to_handler(); | |
202 | ||
203 | /* restore all state needed by the ABI */ | |
204 | ||
205 | /* this is usually either a return or a jump */ | |
206 | original_return_point(); | |
207 | } | |
208 | #endif | |
209 | ||
210 | ||
03688970 MF |
211 | HAVE_FUNCTION_GRAPH_FP_TEST |
212 | --------------------------- | |
213 | ||
214 | An arch may pass in a unique value (frame pointer) to both the entering and | |
215 | exiting of a function. On exit, the value is compared and if it does not | |
216 | match, then it will panic the kernel. This is largely a sanity check for bad | |
217 | code generation with gcc. If gcc for your port sanely updates the frame | |
218 | pointer under different opitmization levels, then ignore this option. | |
219 | ||
220 | However, adding support for it isn't terribly difficult. In your assembly code | |
221 | that calls prepare_ftrace_return(), pass the frame pointer as the 3rd argument. | |
222 | Then in the C version of that function, do what the x86 port does and pass it | |
223 | along to ftrace_push_return_trace() instead of a stub value of 0. | |
224 | ||
225 | Similarly, when you call ftrace_return_to_handler(), pass it the frame pointer. | |
226 | ||
227 | ||
555f386c MF |
228 | HAVE_FTRACE_NMI_ENTER |
229 | --------------------- | |
230 | ||
231 | If you can't trace NMI functions, then skip this option. | |
232 | ||
233 | <details to be filled> | |
234 | ||
235 | ||
459c6d15 | 236 | HAVE_SYSCALL_TRACEPOINTS |
555f386c MF |
237 | --------------------- |
238 | ||
459c6d15 FW |
239 | You need very few things to get the syscalls tracing in an arch. |
240 | ||
241 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number | |
242 | of syscalls supported by the arch. | |
243 | - Implement arch_syscall_addr() that resolves a syscall address from a | |
244 | syscall number. | |
245 | - Support the TIF_SYSCALL_TRACEPOINT thread flags | |
246 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace | |
247 | in the ptrace syscalls tracing path. | |
248 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. | |
555f386c MF |
249 | |
250 | ||
251 | HAVE_FTRACE_MCOUNT_RECORD | |
252 | ------------------------- | |
253 | ||
254 | See scripts/recordmcount.pl for more info. | |
255 | ||
256 | <details to be filled> | |
257 | ||
258 | ||
259 | HAVE_DYNAMIC_FTRACE | |
260 | --------------------- | |
261 | ||
262 | <details to be filled> |