Commit | Line | Data |
---|---|---|
555f386c MF |
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 | ||
459c6d15 | 216 | HAVE_SYSCALL_TRACEPOINTS |
555f386c MF |
217 | --------------------- |
218 | ||
459c6d15 FW |
219 | You need very few things to get the syscalls tracing in an arch. |
220 | ||
221 | - Have a NR_syscalls variable in <asm/unistd.h> that provides the number | |
222 | of syscalls supported by the arch. | |
223 | - Implement arch_syscall_addr() that resolves a syscall address from a | |
224 | syscall number. | |
225 | - Support the TIF_SYSCALL_TRACEPOINT thread flags | |
226 | - Put the trace_sys_enter() and trace_sys_exit() tracepoints calls from ptrace | |
227 | in the ptrace syscalls tracing path. | |
228 | - Tag this arch as HAVE_SYSCALL_TRACEPOINTS. | |
555f386c MF |
229 | |
230 | ||
231 | HAVE_FTRACE_MCOUNT_RECORD | |
232 | ------------------------- | |
233 | ||
234 | See scripts/recordmcount.pl for more info. | |
235 | ||
236 | <details to be filled> | |
237 | ||
238 | ||
239 | HAVE_DYNAMIC_FTRACE | |
240 | --------------------- | |
241 | ||
242 | <details to be filled> |