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,  /* Add a function return address to the trace stack on thread info.*/  int  ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth, -			 unsigned long frame_pointer) +			 unsigned long frame_pointer, unsigned long *retp)  {  	unsigned long long calltime;  	int index; @@ -170,8 +170,12 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func, int *depth,  	current->ret_stack[index].ret = ret;  	current->ret_stack[index].func = func;  	current->ret_stack[index].calltime = calltime; -	current->ret_stack[index].subtime = 0; +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST  	current->ret_stack[index].fp = frame_pointer; +#endif +#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR +	current->ret_stack[index].retp = retp; +#endif  	*depth = current->curr_ret_stack;  	return 0; @@ -204,7 +208,7 @@ ftrace_pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret,  		return;  	} -#if defined(CONFIG_HAVE_FUNCTION_GRAPH_FP_TEST) && !defined(CC_USING_FENTRY) +#ifdef HAVE_FUNCTION_GRAPH_FP_TEST  	/*  	 * The arch may choose to record the frame pointer used  	 * 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)  	return ret;  } +/** + * ftrace_graph_ret_addr - convert a potentially modified stack return address + *			   to its original value + * + * This function can be called by stack unwinding code to convert a found stack + * return address ('ret') to its original value, in case the function graph + * tracer has modified it to be 'return_to_handler'.  If the address hasn't + * been modified, the unchanged value of 'ret' is returned. + * + * 'idx' is a state variable which should be initialized by the caller to zero + * before the first call. + * + * 'retp' is a pointer to the return address on the stack.  It's ignored if + * the arch doesn't have HAVE_FUNCTION_GRAPH_RET_ADDR_PTR defined. + */ +#ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR +unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, +				    unsigned long ret, unsigned long *retp) +{ +	int index = task->curr_ret_stack; +	int i; + +	if (ret != (unsigned long)return_to_handler) +		return ret; + +	if (index < -1) +		index += FTRACE_NOTRACE_DEPTH; + +	if (index < 0) +		return ret; + +	for (i = 0; i <= index; i++) +		if (task->ret_stack[i].retp == retp) +			return task->ret_stack[i].ret; + +	return ret; +} +#else /* !HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ +unsigned long ftrace_graph_ret_addr(struct task_struct *task, int *idx, +				    unsigned long ret, unsigned long *retp) +{ +	int task_idx; + +	if (ret != (unsigned long)return_to_handler) +		return ret; + +	task_idx = task->curr_ret_stack; + +	if (!task->ret_stack || task_idx < *idx) +		return ret; + +	task_idx -= *idx; +	(*idx)++; + +	return task->ret_stack[task_idx].ret; +} +#endif /* HAVE_FUNCTION_GRAPH_RET_ADDR_PTR */ +  int __trace_graph_entry(struct trace_array *tr,  				struct ftrace_graph_ent *trace,  				unsigned long flags, @@ -1120,6 +1182,11 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,  	trace_seq_puts(s, "/* ");  	switch (iter->ent->type) { +	case TRACE_BPUTS: +		ret = trace_print_bputs_msg_only(iter); +		if (ret != TRACE_TYPE_HANDLED) +			return ret; +		break;  	case TRACE_BPRINT:  		ret = trace_print_bprintk_msg_only(iter);  		if (ret != TRACE_TYPE_HANDLED)  |