diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 7363ccf79512..0cbe38a844fa 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -119,7 +119,7 @@ print_graph_duration(struct trace_array *tr, unsigned long long duration, | |||
119 | /* Add a function return address to the trace stack on thread info.*/ | 119 | /* Add a function return address to the trace stack on thread info.*/ |
120 | int | 120 | int |
121 | ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, | 121 | ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, |
122 | unsigned long frame_pointer) | 122 | unsigned long frame_pointer, unsigned long *retp) |
123 | { | 123 | { |
124 | unsigned long long calltime; | 124 | unsigned long long calltime; |
125 | int index; | 125 | int index; |
@@ -171,7 +171,12 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, | |||
171 | current->ret_stack[index].func = func; | 171 | current->ret_stack[index].func = func; |
172 | current->ret_stack[index].calltime = calltime; | 172 | current->ret_stack[index].calltime = calltime; |
173 | current->ret_stack[index].subtime = 0; | 173 | current->ret_stack[index].subtime = 0; |
174 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
174 | current->ret_stack[index].fp = frame_pointer; | 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 | ||
175 | *depth = current->curr_ret_stack; | 180 | *depth = current->curr_ret_stack; |
176 | 181 | ||
177 | return 0; | 182 | return 0; |
@@ -204,7 +209,7 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, | |||
204 | return; | 209 | return; |
205 | } | 210 | } |
206 | 211 | ||
207 | #if defined(CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST) && !defined(CC_USING_FENTRY) | 212 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
208 | /* | 213 | /* |
209 | * The arch may choose to record the frame pointer used | 214 | * The arch may choose to record the frame pointer used |
210 | * and check it here to make sure that it is what we expect it | 215 | * and check it here to make sure that it is what we expect it |
@@ -279,6 +284,64 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
279 | return ret; | 284 | return ret; |
280 | } | 285 | } |
281 | 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 | |||
282 | int __trace_graph_entry(struct trace_array *tr, | 345 | int __trace_graph_entry(struct trace_array *tr, |
283 | struct ftrace_graph_ent *trace, | 346 | struct ftrace_graph_ent *trace, |
284 | unsigned long flags, | 347 | unsigned long flags, |