[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