[PATCH v4 5/6] libtracecmd: Add printing of arguments for function graph tracer
Steven Rostedt <[email protected]> Tue, 3 Feb 2026 18:32:28 -0500
| Newsgroups | org.kernel.vger.linux-trace-devel |
|---|---|
| Message-ID | <[email protected]> |
From: "Steven Rostedt (Google)" <[email protected]> If the function graph tracer was recorded with the funcgraph-args option set, then the BTF file would also be recorded. Print the contents of the arguments with the information provided by BTF. The output will look like this: cat-43792 [006] ..... 147894.472393: funcgraph_entry: | mutex_unlock(lock=0xffffffff831dbbe0) { cat-43792 [006] ..... 147894.472394: funcgraph_entry: 1.005 us | __mutex_unlock_slowpath(lock=0xffffffff831dbbe0, ip=0xffffffff812f2e30); (ret=0x0) cat-43792 [006] ..... 147894.472396: funcgraph_exit: 3.581 us | } (ret=0x0) cat-43792 [006] ..... 147894.472397: funcgraph_entry: | __f_unlock_pos(f=0xffff8881538df980) { cat-43792 [006] ..... 147894.472397: funcgraph_entry: | mutex_unlock(lock=0xffff8881538dfa10) { cat-43792 [006] ..... 147894.472397: funcgraph_entry: 0.434 us | __mutex_unlock_slowpath(lock=0xffff8881538dfa10, ip=0xffffffff812f2e30); (ret=0x0) cat-43792 [006] ..... 147894.472398: funcgraph_exit: 1.216 us | } (ret=0x0) cat-43792 [006] ..... 147894.472399: funcgraph_exit: 2.152 us | } (ret=0x0) cat-43792 [006] d.... 147894.472399: funcgraph_entry: 0.360 us | fpregs_assert_state_consistent(); (ret=0x6) cat-43792 [006] ..... 147894.472403: funcgraph_entry: | __x64_sys_execve(regs=0xffffc900029f3f58) { cat-43792 [006] ..... 147894.472404: funcgraph_entry: | getname_flags(filename=0x7fff4a902080, flags=0) { cat-43792 [006] ..... 147894.472404: funcgraph_entry: | getname_flags.part.0(7fff4a902080, 0, 0, 0, 0, 0) { cat-43792 [006] ..... 147894.472405: funcgraph_entry: | kmem_cache_alloc_noprof(s=0xffff8881001d3800, gfpflags=0xcc0) { cat-43792 [006] ..... 147894.472405: funcgraph_entry: 0.618 us | fs_reclaim_acquire(gfp_mask=0xcc0); (ret=0x0) cat-43792 [006] ..... 147894.472406: funcgraph_entry: 0.380 us | fs_reclaim_release(gfp_mask=0xcc0); (ret=0x0) cat-43792 [006] ..... 147894.472407: funcgraph_entry: | kmemleak_alloc(ptr=0xffff8881120b0000, size=0x1000, min_count=1, gfp=0xcc0) { cat-43792 [006] ..... 147894.472408: funcgraph_entry: | __create_object(ptr=0xffff8881120b0000, size=0x1000, min_count=1, gfp=0xcc0, objflags=0x0) { cat-43792 [006] ..... 147894.472408: funcgraph_entry: | __alloc_object(gfp=0xcc0) { cat-43792 [006] ..... 147894.472408: funcgraph_entry: | kmem_cache_alloc_noprof(s=0xffff888100045700, gfpflags=0x92cc0) { cat-43792 [006] ..... 147894.472409: funcgraph_entry: 0.570 us | fs_reclaim_acquire(gfp_mask=0x92cc0); (ret=0x0) cat-43792 [006] ..... 147894.472410: funcgraph_entry: 0.370 us | fs_reclaim_release(gfp_mask=0x92cc0); (ret=0x0) cat-43792 [006] ..... 147894.472411: funcgraph_exit: 2.226 us | } (ret=0xffff88814bbcf6a8) Even if libtraceevent 1.9 is not available, print the raw arg registers if they exist in the function entry event. Signed-off-by: Steven Rostedt (Google) <[email protected]> --- lib/trace-cmd/trace-ftrace.c | 58 ++++++++++++++++++++++++++++++++---- 1 file changed, 52 insertions(+), 6 deletions(-) diff --git a/lib/trace-cmd/trace-ftrace.c b/lib/trace-cmd/trace-ftrace.c index d0e6a8e7ac0d..c61dd543e250 100644 --- a/lib/trace-cmd/trace-ftrace.c +++ b/lib/trace-cmd/trace-ftrace.c @@ -198,6 +198,48 @@ static void print_graph_duration(struct trace_seq *s, unsigned long long duratio trace_seq_puts(s, "| "); } +/* Returns true if it printed args, otherwise it returns false */ +static bool print_args(struct trace_seq *s, struct tep_event *event, + struct tep_record *record, const char *func) +{ + struct tep_format_field *field; + int long_size = tep_get_long_size(event->tep); + void *args; + int len; + + if (!long_size) + long_size = sizeof(long); + + field = tep_find_field(event, "args"); + if (!field) + return false; + + len = record->size - field->offset; + + len /= long_size; + + args = record->data + field->offset; + +#ifdef HAVE_KERNEL_BTF + tep_btf_print_args(event->tep, s, args, len, long_size, func); +#else + for (int i = 0; i < len; i++) { + void *arg; + + if (i) + trace_seq_puts(s, ", "); + + arg = args + i * long_size; + if (long_size == 4) + trace_seq_printf(s, "%x", *(unsigned int *)arg); + else + trace_seq_printf(s, "%llx", *(unsigned long long *)arg); + } +#endif + + return true; +} + static int print_graph_entry_leaf(struct trace_seq *s, struct tep_event *event, @@ -247,9 +289,11 @@ print_graph_entry_leaf(struct trace_seq *s, return trace_seq_putc(s, '!'); func = tep_find_function(pevent, val); - if (func) - ret = trace_seq_printf(s, "%s();", func); - else + if (func) { + ret = trace_seq_printf(s, "%s(", func); + print_args(s, event, record, func); + ret = trace_seq_puts(s, ");"); + } else ret = trace_seq_printf(s, "%llx();", val); if (ret && fgraph_depth->set) @@ -302,9 +346,11 @@ static int print_graph_nested(struct trace_seq *s, func = tep_find_function(pevent, val); - if (func) - ret = trace_seq_printf(s, "%s() {", func); - else + if (func) { + ret = trace_seq_printf(s, "%s(", func); + print_args(s, event, record, func); + ret = trace_seq_puts(s, ") {"); + } else ret = trace_seq_printf(s, "%llx() {", val); if (ret && fgraph_depth->set) -- 2.51.0