diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 93 | 
1 files changed, 83 insertions, 10 deletions
| diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 203204cadf92..c35fbaab2a47 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c @@ -58,6 +58,12 @@ static struct tracer_opt trace_opts[] = {  	{ TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) },  	/* Display function name after trailing } */  	{ TRACER_OPT(funcgraph-tail, TRACE_GRAPH_PRINT_TAIL) }, +#ifdef CONFIG_FUNCTION_GRAPH_RETVAL +	/* Display function return value ? */ +	{ TRACER_OPT(funcgraph-retval, TRACE_GRAPH_PRINT_RETVAL) }, +	/* Display function return value in hexadecimal format ? */ +	{ TRACER_OPT(funcgraph-retval-hex, TRACE_GRAPH_PRINT_RETVAL_HEX) }, +#endif  	/* Include sleep time (scheduled out) between entry and return */  	{ TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) }, @@ -619,6 +625,56 @@ print_graph_duration(struct trace_array *tr, unsigned long long duration,  	trace_seq_puts(s, "|  ");  } +#ifdef CONFIG_FUNCTION_GRAPH_RETVAL + +#define __TRACE_GRAPH_PRINT_RETVAL TRACE_GRAPH_PRINT_RETVAL + +static void print_graph_retval(struct trace_seq *s, unsigned long retval, +				bool leaf, void *func, bool hex_format) +{ +	unsigned long err_code = 0; + +	if (retval == 0 || hex_format) +		goto done; + +	/* Check if the return value matches the negative format */ +	if (IS_ENABLED(CONFIG_64BIT) && (retval & BIT(31)) && +		(((u64)retval) >> 32) == 0) { +		/* sign extension */ +		err_code = (unsigned long)(s32)retval; +	} else { +		err_code = retval; +	} + +	if (!IS_ERR_VALUE(err_code)) +		err_code = 0; + +done: +	if (leaf) { +		if (hex_format || (err_code == 0)) +			trace_seq_printf(s, "%ps(); /* = 0x%lx */\n", +					func, retval); +		else +			trace_seq_printf(s, "%ps(); /* = %ld */\n", +					func, err_code); +	} else { +		if (hex_format || (err_code == 0)) +			trace_seq_printf(s, "} /* %ps = 0x%lx */\n", +					func, retval); +		else +			trace_seq_printf(s, "} /* %ps = %ld */\n", +					func, err_code); +	} +} + +#else + +#define __TRACE_GRAPH_PRINT_RETVAL 0 + +#define print_graph_retval(_seq, _retval, _leaf, _func, _format) do {} while (0) + +#endif +  /* Case of a leaf function on its call entry */  static enum print_line_t  print_graph_entry_leaf(struct trace_iterator *iter, @@ -663,7 +719,15 @@ print_graph_entry_leaf(struct trace_iterator *iter,  	for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)  		trace_seq_putc(s, ' '); -	trace_seq_printf(s, "%ps();\n", (void *)call->func); +	/* +	 * Write out the function return value if the option function-retval is +	 * enabled. +	 */ +	if (flags & __TRACE_GRAPH_PRINT_RETVAL) +		print_graph_retval(s, graph_ret->retval, true, (void *)call->func, +				!!(flags & TRACE_GRAPH_PRINT_RETVAL_HEX)); +	else +		trace_seq_printf(s, "%ps();\n", (void *)call->func);  	print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET,  			cpu, iter->ent->pid, flags); @@ -942,16 +1006,25 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,  		trace_seq_putc(s, ' ');  	/* -	 * If the return function does not have a matching entry, -	 * then the entry was lost. Instead of just printing -	 * the '}' and letting the user guess what function this -	 * belongs to, write out the function name. Always do -	 * that if the funcgraph-tail option is enabled. +	 * Always write out the function name and its return value if the +	 * function-retval option is enabled.  	 */ -	if (func_match && !(flags & TRACE_GRAPH_PRINT_TAIL)) -		trace_seq_puts(s, "}\n"); -	else -		trace_seq_printf(s, "} /* %ps */\n", (void *)trace->func); +	if (flags & __TRACE_GRAPH_PRINT_RETVAL) { +		print_graph_retval(s, trace->retval, false, (void *)trace->func, +			!!(flags & TRACE_GRAPH_PRINT_RETVAL_HEX)); +	} else { +		/* +		 * If the return function does not have a matching entry, +		 * then the entry was lost. Instead of just printing +		 * the '}' and letting the user guess what function this +		 * belongs to, write out the function name. Always do +		 * that if the funcgraph-tail option is enabled. +		 */ +		if (func_match && !(flags & TRACE_GRAPH_PRINT_TAIL)) +			trace_seq_puts(s, "}\n"); +		else +			trace_seq_printf(s, "} /* %ps */\n", (void *)trace->func); +	}  	/* Overrun */  	if (flags & TRACE_GRAPH_PRINT_OVERRUN) | 
