The upstream Linux kernel has introduced a new feature, i.e. funcgraph-retval for the function_graph tracer. (Commit ID: a1be9ccc57f07d54278be34eed6bd679bc941c97). With this feature, the function_graph tracer can record each function's return value along with its execution time at the function_graph exit handler. This is useful for debugging kernel issues, such as syscall errors. This commit enhances 'trace-cmd report' by supporting the function_graph retval feature if the underlying kernel supports it. Once the feature is supported, 'trace-cmd report' will print each function's return value in this format: '(ret=retval)" at the end of every funcgraph leaf entry and exit event. Signed-off-by: Jianfeng Wang <jianfeng.w.wang@xxxxxxxxxx> --- lib/trace-cmd/trace-ftrace.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/lib/trace-cmd/trace-ftrace.c b/lib/trace-cmd/trace-ftrace.c index 89e46c3d..cb05d88c 100644 --- a/lib/trace-cmd/trace-ftrace.c +++ b/lib/trace-cmd/trace-ftrace.c @@ -185,6 +185,8 @@ print_graph_entry_leaf(struct trace_seq *s, unsigned long long rettime, calltime; unsigned long long duration, depth; unsigned long long val; + unsigned long long retval; + bool fgraph_retval_supported = true; const char *func; int ret; int i; @@ -195,6 +197,13 @@ print_graph_entry_leaf(struct trace_seq *s, if (tep_get_field_val(s, finfo->fgraph_ret_event, "calltime", ret_rec, &calltime, 1)) return trace_seq_putc(s, '!'); + if (!tep_find_field(finfo->fgraph_ret_event, "retval")) + fgraph_retval_supported = false; + else { + if (tep_get_field_val(s, finfo->fgraph_ret_event, "retval", ret_rec, &retval, 1)) + return trace_seq_putc(s, '!'); + } + duration = rettime - calltime; /* Overhead */ @@ -222,6 +231,10 @@ print_graph_entry_leaf(struct trace_seq *s, if (ret && fgraph_depth->set) ret = trace_seq_printf(s, " (%lld)", depth); + /* Return Value */ + if (ret && fgraph_retval_supported) + ret = trace_seq_printf(s, " (ret=%lld)", retval); + return ret; } @@ -316,6 +329,8 @@ fgraph_ret_handler(struct trace_seq *s, struct tep_record *record, unsigned long long duration, depth; unsigned long long val; const char *func; + unsigned long long retval; + bool fgraph_retval_supported = true; int i; ret_event_check(finfo, event->tep); @@ -326,6 +341,13 @@ fgraph_ret_handler(struct trace_seq *s, struct tep_record *record, if (tep_get_field_val(s, event, "calltime", record, &calltime, 1)) return trace_seq_putc(s, '!'); + if (!tep_find_field(event, "retval")) + fgraph_retval_supported = false; + else { + if (tep_get_field_val(s, event, "retval", record, &retval, 1)) + return trace_seq_putc(s, '!'); + } + duration = rettime - calltime; /* Overhead */ @@ -355,6 +377,10 @@ fgraph_ret_handler(struct trace_seq *s, struct tep_record *record, if (fgraph_depth->set) trace_seq_printf(s, " (%lld)", depth); + /* Return Value */ + if (fgraph_retval_supported) + trace_seq_printf(s, " (ret=%lld)", retval); + return 0; } -- 2.42.1