aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions_graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r--kernel/trace/trace_functions_graph.c334
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
19static 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 */
28bool 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 */
41void 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 */
47static int ftrace_graph_skip_irqs; 20static 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
117print_graph_duration(struct trace_array *tr, unsigned long long duration, 94print_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.*/
121static int
122ftrace_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(&current->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
183int 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.*/
208static void
209ftrace_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(&current->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 */
279unsigned 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
330unsigned 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 */
352unsigned 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
372int __trace_graph_entry(struct trace_array *tr, 97int __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
293static struct fgraph_ops funcgraph_thresh_ops = {
294 .entryfunc = &trace_graph_entry,
295 .retfunc = &trace_graph_thresh_return,
296};
297
298static struct fgraph_ops funcgraph_ops = {
299 .entryfunc = &trace_graph_entry,
300 .retfunc = &trace_graph_return,
301};
302
546static int graph_trace_init(struct trace_array *tr) 303static 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)
564static void graph_trace_reset(struct trace_array *tr) 319static 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
570static int graph_trace_update_thresh(struct trace_array *tr) 328static 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