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.c73
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.*/
120int 120int
121ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, 121ftrace_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
302unsigned 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 */
324unsigned 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
282int __trace_graph_entry(struct trace_array *tr, 344int __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)