diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 58 |
1 files changed, 58 insertions, 0 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index f7212ec643e2..0cbe38a844fa 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -284,6 +284,64 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
284 | return ret; | 284 | return ret; |
285 | } | 285 | } |
286 | 286 | ||
287 | /** | ||
288 | * ftrace_graph_ret_addr - convert a potentially modified stack return address | ||
289 | * to its original value | ||
290 | * | ||
291 | * This function can be called by stack unwinding code to convert a found stack | ||
292 | * return address ('ret') to its original value, in case the function graph | ||
293 | * tracer has modified it to be 'return_to_handler'. If the address hasn't | ||
294 | * been modified, the unchanged value of 'ret' is returned. | ||
295 | * | ||
296 | * 'idx' is a state variable which should be initialized by the caller to zero | ||
297 | * before the first call. | ||
298 | * | ||
299 | * 'retp' is a pointer to the return address on the stack. It's ignored if | ||
300 | * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined. | ||
301 | */ | ||
302 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
303 | unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | ||
304 | unsigned long ret, unsigned long *retp) | ||
305 | { | ||
306 | int index = task->curr_ret_stack; | ||
307 | int i; | ||
308 | |||
309 | if (ret != (unsigned long)return_to_handler) | ||
310 | return ret; | ||
311 | |||
312 | if (index < -1) | ||
313 | index += FTRACE_NOTRACE_DEPTH; | ||
314 | |||
315 | if (index < 0) | ||
316 | return ret; | ||
317 | |||
318 | for (i = 0; i <= index; i++) | ||
319 | if (task->ret_stack[i].retp == retp) | ||
320 | return task->ret_stack[i].ret; | ||
321 | |||
322 | return ret; | ||
323 | } | ||
324 | #else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | ||
325 | unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | ||
326 | unsigned long ret, unsigned long *retp) | ||
327 | { | ||
328 | int task_idx; | ||
329 | |||
330 | if (ret != (unsigned long)return_to_handler) | ||
331 | return ret; | ||
332 | |||
333 | task_idx = task->curr_ret_stack; | ||
334 | |||
335 | if (!task->ret_stack || task_idx < *idx) | ||
336 | return ret; | ||
337 | |||
338 | task_idx -= *idx; | ||
339 | (*idx)++; | ||
340 | |||
341 | return task->ret_stack[task_idx].ret; | ||
342 | } | ||
343 | #endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | ||
344 | |||
287 | int __trace_graph_entry(struct trace_array *tr, | 345 | int __trace_graph_entry(struct trace_array *tr, |
288 | struct ftrace_graph_ent *trace, | 346 | struct ftrace_graph_ent *trace, |
289 | unsigned long flags, | 347 | unsigned long flags, |