diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-31 14:46:59 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2018-12-31 14:46:59 -0500 |
commit | 495d714ad140e1732e66c45d0409054b24c1a0d6 (patch) | |
tree | 373ec6619adea47d848d36f140b32def27164bbd /kernel/trace/trace_functions_graph.c | |
parent | f12e840c819bab42621685558a01d3f46ab9a226 (diff) | |
parent | 3d739c1f6156c70eb0548aa288dcfbac9e0bd162 (diff) |
Merge tag 'trace-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace
Pull tracing updates from Steven Rostedt:
- Rework of the kprobe/uprobe and synthetic events to consolidate all
the dynamic event code. This will make changes in the future easier.
- Partial rewrite of the function graph tracing infrastructure. This
will allow for multiple users of hooking onto functions to get the
callback (return) of the function. This is the ground work for having
kprobes and function graph tracer using one code base.
- Clean up of the histogram code that will facilitate adding more
features to the histograms in the future.
- Addition of str_has_prefix() and a few use cases. There currently is
a similar function strstart() that is used in a few places, but only
returns a bool and not a length. These instances will be removed in
the future to use str_has_prefix() instead.
- A few other various clean ups as well.
* tag 'trace-v4.21' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace: (57 commits)
tracing: Use the return of str_has_prefix() to remove open coded numbers
tracing: Have the historgram use the result of str_has_prefix() for len of prefix
tracing: Use str_has_prefix() instead of using fixed sizes
tracing: Use str_has_prefix() helper for histogram code
string.h: Add str_has_prefix() helper function
tracing: Make function ‘ftrace_exports’ static
tracing: Simplify printf'ing in seq_print_sym
tracing: Avoid -Wformat-nonliteral warning
tracing: Merge seq_print_sym_short() and seq_print_sym_offset()
tracing: Add hist trigger comments for variable-related fields
tracing: Remove hist trigger synth_var_refs
tracing: Use hist trigger's var_ref array to destroy var_refs
tracing: Remove open-coding of hist trigger var_ref management
tracing: Use var_refs[] for hist trigger reference checking
tracing: Change strlen to sizeof for hist trigger static strings
tracing: Remove unnecessary hist trigger struct field
tracing: Fix ftrace_graph_get_ret_stack() to use task and not current
seq_buf: Use size_t for len in seq_buf_puts()
seq_buf: Make seq_buf_puts() null-terminate the buffer
arm64: Use ftrace_graph_get_ret_stack() instead of curr_ret_stack
...
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 334 |
1 files changed, 42 insertions, 292 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 086af4f5c3e8..c2af1560e856 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -16,33 +16,6 @@ | |||
16 | #include "trace.h" | 16 | #include "trace.h" |
17 | #include "trace_output.h" | 17 | #include "trace_output.h" |
18 | 18 | ||
19 | static bool kill_ftrace_graph; | ||
20 | |||
21 | /** | ||
22 | * ftrace_graph_is_dead - returns true if ftrace_graph_stop() was called | ||
23 | * | ||
24 | * ftrace_graph_stop() is called when a severe error is detected in | ||
25 | * the function graph tracing. This function is called by the critical | ||
26 | * paths of function graph to keep those paths from doing any more harm. | ||
27 | */ | ||
28 | bool ftrace_graph_is_dead(void) | ||
29 | { | ||
30 | return kill_ftrace_graph; | ||
31 | } | ||
32 | |||
33 | /** | ||
34 | * ftrace_graph_stop - set to permanently disable function graph tracincg | ||
35 | * | ||
36 | * In case of an error int function graph tracing, this is called | ||
37 | * to try to keep function graph tracing from causing any more harm. | ||
38 | * Usually this is pretty severe and this is called to try to at least | ||
39 | * get a warning out to the user. | ||
40 | */ | ||
41 | void ftrace_graph_stop(void) | ||
42 | { | ||
43 | kill_ftrace_graph = true; | ||
44 | } | ||
45 | |||
46 | /* When set, irq functions will be ignored */ | 19 | /* When set, irq functions will be ignored */ |
47 | static int ftrace_graph_skip_irqs; | 20 | static int ftrace_graph_skip_irqs; |
48 | 21 | ||
@@ -87,8 +60,12 @@ static struct tracer_opt trace_opts[] = { | |||
87 | { TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) }, | 60 | { TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) }, |
88 | /* Include sleep time (scheduled out) between entry and return */ | 61 | /* Include sleep time (scheduled out) between entry and return */ |
89 | { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, | 62 | { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, |
63 | |||
64 | #ifdef CONFIG_FUNCTION_PROFILER | ||
90 | /* Include time within nested functions */ | 65 | /* Include time within nested functions */ |
91 | { TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) }, | 66 | { TRACER_OPT(graph-time, TRACE_GRAPH_GRAPH_TIME) }, |
67 | #endif | ||
68 | |||
92 | { } /* Empty entry */ | 69 | { } /* Empty entry */ |
93 | }; | 70 | }; |
94 | 71 | ||
@@ -117,258 +94,6 @@ static void | |||
117 | print_graph_duration(struct trace_array *tr, unsigned long long duration, | 94 | print_graph_duration(struct trace_array *tr, unsigned long long duration, |
118 | struct trace_seq *s, u32 flags); | 95 | struct trace_seq *s, u32 flags); |
119 | 96 | ||
120 | /* Add a function return address to the trace stack on thread info.*/ | ||
121 | static int | ||
122 | ftrace_push_return_trace(unsigned long ret, unsigned long func, | ||
123 | unsigned long frame_pointer, unsigned long *retp) | ||
124 | { | ||
125 | unsigned long long calltime; | ||
126 | int index; | ||
127 | |||
128 | if (unlikely(ftrace_graph_is_dead())) | ||
129 | return -EBUSY; | ||
130 | |||
131 | if (!current->ret_stack) | ||
132 | return -EBUSY; | ||
133 | |||
134 | /* | ||
135 | * We must make sure the ret_stack is tested before we read | ||
136 | * anything else. | ||
137 | */ | ||
138 | smp_rmb(); | ||
139 | |||
140 | /* The return trace stack is full */ | ||
141 | if (current->curr_ret_stack == FTRACE_RETFUNC_DEPTH - 1) { | ||
142 | atomic_inc(¤t->trace_overrun); | ||
143 | return -EBUSY; | ||
144 | } | ||
145 | |||
146 | /* | ||
147 | * The curr_ret_stack is an index to ftrace return stack of | ||
148 | * current task. Its value should be in [0, FTRACE_RETFUNC_ | ||
149 | * DEPTH) when the function graph tracer is used. To support | ||
150 | * filtering out specific functions, it makes the index | ||
151 | * negative by subtracting huge value (FTRACE_NOTRACE_DEPTH) | ||
152 | * so when it sees a negative index the ftrace will ignore | ||
153 | * the record. And the index gets recovered when returning | ||
154 | * from the filtered function by adding the FTRACE_NOTRACE_ | ||
155 | * DEPTH and then it'll continue to record functions normally. | ||
156 | * | ||
157 | * The curr_ret_stack is initialized to -1 and get increased | ||
158 | * in this function. So it can be less than -1 only if it was | ||
159 | * filtered out via ftrace_graph_notrace_addr() which can be | ||
160 | * set from set_graph_notrace file in tracefs by user. | ||
161 | */ | ||
162 | if (current->curr_ret_stack < -1) | ||
163 | return -EBUSY; | ||
164 | |||
165 | calltime = trace_clock_local(); | ||
166 | |||
167 | index = ++current->curr_ret_stack; | ||
168 | if (ftrace_graph_notrace_addr(func)) | ||
169 | current->curr_ret_stack -= FTRACE_NOTRACE_DEPTH; | ||
170 | barrier(); | ||
171 | current->ret_stack[index].ret = ret; | ||
172 | current->ret_stack[index].func = func; | ||
173 | current->ret_stack[index].calltime = calltime; | ||
174 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
175 | current->ret_stack[index].fp = frame_pointer; | ||
176 | #endif | ||
177 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
178 | current->ret_stack[index].retp = retp; | ||
179 | #endif | ||
180 | return 0; | ||
181 | } | ||
182 | |||
183 | int function_graph_enter(unsigned long ret, unsigned long func, | ||
184 | unsigned long frame_pointer, unsigned long *retp) | ||
185 | { | ||
186 | struct ftrace_graph_ent trace; | ||
187 | |||
188 | trace.func = func; | ||
189 | trace.depth = ++current->curr_ret_depth; | ||
190 | |||
191 | if (ftrace_push_return_trace(ret, func, | ||
192 | frame_pointer, retp)) | ||
193 | goto out; | ||
194 | |||
195 | /* Only trace if the calling function expects to */ | ||
196 | if (!ftrace_graph_entry(&trace)) | ||
197 | goto out_ret; | ||
198 | |||
199 | return 0; | ||
200 | out_ret: | ||
201 | current->curr_ret_stack--; | ||
202 | out: | ||
203 | current->curr_ret_depth--; | ||
204 | return -EBUSY; | ||
205 | } | ||
206 | |||
207 | /* Retrieve a function return address to the trace stack on thread info.*/ | ||
208 | static void | ||
209 | ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, | ||
210 | unsigned long frame_pointer) | ||
211 | { | ||
212 | int index; | ||
213 | |||
214 | index = current->curr_ret_stack; | ||
215 | |||
216 | /* | ||
217 | * A negative index here means that it's just returned from a | ||
218 | * notrace'd function. Recover index to get an original | ||
219 | * return address. See ftrace_push_return_trace(). | ||
220 | * | ||
221 | * TODO: Need to check whether the stack gets corrupted. | ||
222 | */ | ||
223 | if (index < 0) | ||
224 | index += FTRACE_NOTRACE_DEPTH; | ||
225 | |||
226 | if (unlikely(index < 0 || index >= FTRACE_RETFUNC_DEPTH)) { | ||
227 | ftrace_graph_stop(); | ||
228 | WARN_ON(1); | ||
229 | /* Might as well panic, otherwise we have no where to go */ | ||
230 | *ret = (unsigned long)panic; | ||
231 | return; | ||
232 | } | ||
233 | |||
234 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
235 | /* | ||
236 | * The arch may choose to record the frame pointer used | ||
237 | * and check it here to make sure that it is what we expect it | ||
238 | * to be. If gcc does not set the place holder of the return | ||
239 | * address in the frame pointer, and does a copy instead, then | ||
240 | * the function graph trace will fail. This test detects this | ||
241 | * case. | ||
242 | * | ||
243 | * Currently, x86_32 with optimize for size (-Os) makes the latest | ||
244 | * gcc do the above. | ||
245 | * | ||
246 | * Note, -mfentry does not use frame pointers, and this test | ||
247 | * is not needed if CC_USING_FENTRY is set. | ||
248 | */ | ||
249 | if (unlikely(current->ret_stack[index].fp != frame_pointer)) { | ||
250 | ftrace_graph_stop(); | ||
251 | WARN(1, "Bad frame pointer: expected %lx, received %lx\n" | ||
252 | " from func %ps return to %lx\n", | ||
253 | current->ret_stack[index].fp, | ||
254 | frame_pointer, | ||
255 | (void *)current->ret_stack[index].func, | ||
256 | current->ret_stack[index].ret); | ||
257 | *ret = (unsigned long)panic; | ||
258 | return; | ||
259 | } | ||
260 | #endif | ||
261 | |||
262 | *ret = current->ret_stack[index].ret; | ||
263 | trace->func = current->ret_stack[index].func; | ||
264 | trace->calltime = current->ret_stack[index].calltime; | ||
265 | trace->overrun = atomic_read(¤t->trace_overrun); | ||
266 | trace->depth = current->curr_ret_depth--; | ||
267 | /* | ||
268 | * We still want to trace interrupts coming in if | ||
269 | * max_depth is set to 1. Make sure the decrement is | ||
270 | * seen before ftrace_graph_return. | ||
271 | */ | ||
272 | barrier(); | ||
273 | } | ||
274 | |||
275 | /* | ||
276 | * Send the trace to the ring-buffer. | ||
277 | * @return the original return address. | ||
278 | */ | ||
279 | unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | ||
280 | { | ||
281 | struct ftrace_graph_ret trace; | ||
282 | unsigned long ret; | ||
283 | |||
284 | ftrace_pop_return_trace(&trace, &ret, frame_pointer); | ||
285 | trace.rettime = trace_clock_local(); | ||
286 | ftrace_graph_return(&trace); | ||
287 | /* | ||
288 | * The ftrace_graph_return() may still access the current | ||
289 | * ret_stack structure, we need to make sure the update of | ||
290 | * curr_ret_stack is after that. | ||
291 | */ | ||
292 | barrier(); | ||
293 | current->curr_ret_stack--; | ||
294 | /* | ||
295 | * The curr_ret_stack can be less than -1 only if it was | ||
296 | * filtered out and it's about to return from the function. | ||
297 | * Recover the index and continue to trace normal functions. | ||
298 | */ | ||
299 | if (current->curr_ret_stack < -1) { | ||
300 | current->curr_ret_stack += FTRACE_NOTRACE_DEPTH; | ||
301 | return ret; | ||
302 | } | ||
303 | |||
304 | if (unlikely(!ret)) { | ||
305 | ftrace_graph_stop(); | ||
306 | WARN_ON(1); | ||
307 | /* Might as well panic. What else to do? */ | ||
308 | ret = (unsigned long)panic; | ||
309 | } | ||
310 | |||
311 | return ret; | ||
312 | } | ||
313 | |||
314 | /** | ||
315 | * ftrace_graph_ret_addr - convert a potentially modified stack return address | ||
316 | * to its original value | ||
317 | * | ||
318 | * This function can be called by stack unwinding code to convert a found stack | ||
319 | * return address ('ret') to its original value, in case the function graph | ||
320 | * tracer has modified it to be 'return_to_handler'. If the address hasn't | ||
321 | * been modified, the unchanged value of 'ret' is returned. | ||
322 | * | ||
323 | * 'idx' is a state variable which should be initialized by the caller to zero | ||
324 | * before the first call. | ||
325 | * | ||
326 | * 'retp' is a pointer to the return address on the stack. It's ignored if | ||
327 | * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined. | ||
328 | */ | ||
329 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
330 | unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | ||
331 | unsigned long ret, unsigned long *retp) | ||
332 | { | ||
333 | int index = task->curr_ret_stack; | ||
334 | int i; | ||
335 | |||
336 | if (ret != (unsigned long)return_to_handler) | ||
337 | return ret; | ||
338 | |||
339 | if (index < -1) | ||
340 | index += FTRACE_NOTRACE_DEPTH; | ||
341 | |||
342 | if (index < 0) | ||
343 | return ret; | ||
344 | |||
345 | for (i = 0; i <= index; i++) | ||
346 | if (task->ret_stack[i].retp == retp) | ||
347 | return task->ret_stack[i].ret; | ||
348 | |||
349 | return ret; | ||
350 | } | ||
351 | #else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | ||
352 | unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | ||
353 | unsigned long ret, unsigned long *retp) | ||
354 | { | ||
355 | int task_idx; | ||
356 | |||
357 | if (ret != (unsigned long)return_to_handler) | ||
358 | return ret; | ||
359 | |||
360 | task_idx = task->curr_ret_stack; | ||
361 | |||
362 | if (!task->ret_stack || task_idx < *idx) | ||
363 | return ret; | ||
364 | |||
365 | task_idx -= *idx; | ||
366 | (*idx)++; | ||
367 | |||
368 | return task->ret_stack[task_idx].ret; | ||
369 | } | ||
370 | #endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | ||
371 | |||
372 | int __trace_graph_entry(struct trace_array *tr, | 97 | int __trace_graph_entry(struct trace_array *tr, |
373 | struct ftrace_graph_ent *trace, | 98 | struct ftrace_graph_ent *trace, |
374 | unsigned long flags, | 99 | unsigned long flags, |
@@ -409,6 +134,18 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
409 | int cpu; | 134 | int cpu; |
410 | int pc; | 135 | int pc; |
411 | 136 | ||
137 | if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) | ||
138 | return 0; | ||
139 | |||
140 | if (ftrace_graph_notrace_addr(trace->func)) { | ||
141 | trace_recursion_set(TRACE_GRAPH_NOTRACE_BIT); | ||
142 | /* | ||
143 | * Need to return 1 to have the return called | ||
144 | * that will clear the NOTRACE bit. | ||
145 | */ | ||
146 | return 1; | ||
147 | } | ||
148 | |||
412 | if (!ftrace_trace_task(tr)) | 149 | if (!ftrace_trace_task(tr)) |
413 | return 0; | 150 | return 0; |
414 | 151 | ||
@@ -511,6 +248,11 @@ void trace_graph_return(struct ftrace_graph_ret *trace) | |||
511 | 248 | ||
512 | ftrace_graph_addr_finish(trace); | 249 | ftrace_graph_addr_finish(trace); |
513 | 250 | ||
251 | if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) { | ||
252 | trace_recursion_clear(TRACE_GRAPH_NOTRACE_BIT); | ||
253 | return; | ||
254 | } | ||
255 | |||
514 | local_irq_save(flags); | 256 | local_irq_save(flags); |
515 | cpu = raw_smp_processor_id(); | 257 | cpu = raw_smp_processor_id(); |
516 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); | 258 | data = per_cpu_ptr(tr->trace_buffer.data, cpu); |
@@ -536,6 +278,11 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace) | |||
536 | { | 278 | { |
537 | ftrace_graph_addr_finish(trace); | 279 | ftrace_graph_addr_finish(trace); |
538 | 280 | ||
281 | if (trace_recursion_test(TRACE_GRAPH_NOTRACE_BIT)) { | ||
282 | trace_recursion_clear(TRACE_GRAPH_NOTRACE_BIT); | ||
283 | return; | ||
284 | } | ||
285 | |||
539 | if (tracing_thresh && | 286 | if (tracing_thresh && |
540 | (trace->rettime - trace->calltime < tracing_thresh)) | 287 | (trace->rettime - trace->calltime < tracing_thresh)) |
541 | return; | 288 | return; |
@@ -543,17 +290,25 @@ static void trace_graph_thresh_return(struct ftrace_graph_ret *trace) | |||
543 | trace_graph_return(trace); | 290 | trace_graph_return(trace); |
544 | } | 291 | } |
545 | 292 | ||
293 | static struct fgraph_ops funcgraph_thresh_ops = { | ||
294 | .entryfunc = &trace_graph_entry, | ||
295 | .retfunc = &trace_graph_thresh_return, | ||
296 | }; | ||
297 | |||
298 | static struct fgraph_ops funcgraph_ops = { | ||
299 | .entryfunc = &trace_graph_entry, | ||
300 | .retfunc = &trace_graph_return, | ||
301 | }; | ||
302 | |||
546 | static int graph_trace_init(struct trace_array *tr) | 303 | static int graph_trace_init(struct trace_array *tr) |
547 | { | 304 | { |
548 | int ret; | 305 | int ret; |
549 | 306 | ||
550 | set_graph_array(tr); | 307 | set_graph_array(tr); |
551 | if (tracing_thresh) | 308 | if (tracing_thresh) |
552 | ret = register_ftrace_graph(&trace_graph_thresh_return, | 309 | ret = register_ftrace_graph(&funcgraph_thresh_ops); |
553 | &trace_graph_entry); | ||
554 | else | 310 | else |
555 | ret = register_ftrace_graph(&trace_graph_return, | 311 | ret = register_ftrace_graph(&funcgraph_ops); |
556 | &trace_graph_entry); | ||
557 | if (ret) | 312 | if (ret) |
558 | return ret; | 313 | return ret; |
559 | tracing_start_cmdline_record(); | 314 | tracing_start_cmdline_record(); |
@@ -564,7 +319,10 @@ static int graph_trace_init(struct trace_array *tr) | |||
564 | static void graph_trace_reset(struct trace_array *tr) | 319 | static void graph_trace_reset(struct trace_array *tr) |
565 | { | 320 | { |
566 | tracing_stop_cmdline_record(); | 321 | tracing_stop_cmdline_record(); |
567 | unregister_ftrace_graph(); | 322 | if (tracing_thresh) |
323 | unregister_ftrace_graph(&funcgraph_thresh_ops); | ||
324 | else | ||
325 | unregister_ftrace_graph(&funcgraph_ops); | ||
568 | } | 326 | } |
569 | 327 | ||
570 | static int graph_trace_update_thresh(struct trace_array *tr) | 328 | static int graph_trace_update_thresh(struct trace_array *tr) |
@@ -874,10 +632,6 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
874 | 632 | ||
875 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | 633 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); |
876 | 634 | ||
877 | /* If a graph tracer ignored set_graph_notrace */ | ||
878 | if (call->depth < -1) | ||
879 | call->depth += FTRACE_NOTRACE_DEPTH; | ||
880 | |||
881 | /* | 635 | /* |
882 | * Comments display at + 1 to depth. Since | 636 | * Comments display at + 1 to depth. Since |
883 | * this is a leaf function, keep the comments | 637 | * this is a leaf function, keep the comments |
@@ -920,10 +674,6 @@ print_graph_entry_nested(struct trace_iterator *iter, | |||
920 | struct fgraph_cpu_data *cpu_data; | 674 | struct fgraph_cpu_data *cpu_data; |
921 | int cpu = iter->cpu; | 675 | int cpu = iter->cpu; |
922 | 676 | ||
923 | /* If a graph tracer ignored set_graph_notrace */ | ||
924 | if (call->depth < -1) | ||
925 | call->depth += FTRACE_NOTRACE_DEPTH; | ||
926 | |||
927 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | 677 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); |
928 | cpu_data->depth = call->depth; | 678 | cpu_data->depth = call->depth; |
929 | 679 | ||