diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 73 |
1 files changed, 70 insertions, 3 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 7363ccf79512..4e480e870474 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; |
@@ -170,8 +170,12 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, | |||
170 | current->ret_stack[index].ret = ret; | 170 | current->ret_stack[index].ret = ret; |
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 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
174 | current->ret_stack[index].fp = frame_pointer; | 174 | current->ret_stack[index].fp = frame_pointer; |
175 | #endif | ||
176 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
177 | current->ret_stack[index].retp = retp; | ||
178 | #endif | ||
175 | *depth = current->curr_ret_stack; | 179 | *depth = current->curr_ret_stack; |
176 | 180 | ||
177 | return 0; | 181 | return 0; |
@@ -204,7 +208,7 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret, | |||
204 | return; | 208 | return; |
205 | } | 209 | } |
206 | 210 | ||
207 | #if defined(CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST) && !defined(CC_USING_FENTRY) | 211 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
208 | /* | 212 | /* |
209 | * The arch may choose to record the frame pointer used | 213 | * 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 | 214 | * and check it here to make sure that it is what we expect it |
@@ -279,6 +283,64 @@ unsigned long ftrace_return_to_handler(unsigned long frame_pointer) | |||
279 | return ret; | 283 | return ret; |
280 | } | 284 | } |
281 | 285 | ||
286 | /** | ||
287 | * ftrace_graph_ret_addr - convert a potentially modified stack return address | ||
288 | * to its original value | ||
289 | * | ||
290 | * This function can be called by stack unwinding code to convert a found stack | ||
291 | * return address ('ret') to its original value, in case the function graph | ||
292 | * tracer has modified it to be 'return_to_handler'. If the address hasn't | ||
293 | * been modified, the unchanged value of 'ret' is returned. | ||
294 | * | ||
295 | * 'idx' is a state variable which should be initialized by the caller to zero | ||
296 | * before the first call. | ||
297 | * | ||
298 | * 'retp' is a pointer to the return address on the stack. It's ignored if | ||
299 | * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined. | ||
300 | */ | ||
301 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
302 | unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | ||
303 | unsigned long ret, unsigned long *retp) | ||
304 | { | ||
305 | int index = task->curr_ret_stack; | ||
306 | int i; | ||
307 | |||
308 | if (ret != (unsigned long)return_to_handler) | ||
309 | return ret; | ||
310 | |||
311 | if (index < -1) | ||
312 | index += FTRACE_NOTRACE_DEPTH; | ||
313 | |||
314 | if (index < 0) | ||
315 | return ret; | ||
316 | |||
317 | for (i = 0; i <= index; i++) | ||
318 | if (task->ret_stack[i].retp == retp) | ||
319 | return task->ret_stack[i].ret; | ||
320 | |||
321 | return ret; | ||
322 | } | ||
323 | #else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | ||
324 | unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, | ||
325 | unsigned long ret, unsigned long *retp) | ||
326 | { | ||
327 | int task_idx; | ||
328 | |||
329 | if (ret != (unsigned long)return_to_handler) | ||
330 | return ret; | ||
331 | |||
332 | task_idx = task->curr_ret_stack; | ||
333 | |||
334 | if (!task->ret_stack || task_idx < *idx) | ||
335 | return ret; | ||
336 | |||
337 | task_idx -= *idx; | ||
338 | (*idx)++; | ||
339 | |||
340 | return task->ret_stack[task_idx].ret; | ||
341 | } | ||
342 | #endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ | ||
343 | |||
282 | int __trace_graph_entry(struct trace_array *tr, | 344 | int __trace_graph_entry(struct trace_array *tr, |
283 | struct ftrace_graph_ent *trace, | 345 | struct ftrace_graph_ent *trace, |
284 | unsigned long flags, | 346 | unsigned long flags, |
@@ -1120,6 +1182,11 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, | |||
1120 | trace_seq_puts(s, "/* "); | 1182 | trace_seq_puts(s, "/* "); |
1121 | 1183 | ||
1122 | switch (iter->ent->type) { | 1184 | switch (iter->ent->type) { |
1185 | case TRACE_BPUTS: | ||
1186 | ret = trace_print_bputs_msg_only(iter); | ||
1187 | if (ret != TRACE_TYPE_HANDLED) | ||
1188 | return ret; | ||
1189 | break; | ||
1123 | case TRACE_BPRINT: | 1190 | case TRACE_BPRINT: |
1124 | ret = trace_print_bprintk_msg_only(iter); | 1191 | ret = trace_print_bprintk_msg_only(iter); |
1125 | if (ret != TRACE_TYPE_HANDLED) | 1192 | if (ret != TRACE_TYPE_HANDLED) |