Commit 76fe0337 authored by Sven Schnelle's avatar Sven Schnelle Committed by Steven Rostedt (Google)
Browse files

ftrace: Add arguments to function tracer

Wire up the code to print function arguments in the function tracer.
This functionality can be enabled/disabled during runtime with
options/func-args.

        ping-689     [004] b....    77.170220: dummy_xmit(skb = 0x82904800, dev = 0x882d0000) <-dev_hard_start_xmit

Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Palmer Dabbelt <palmer@dabbelt.com>
Cc: Albert Ou <aou@eecs.berkeley.edu>
Cc: Guo Ren <guoren@kernel.org>
Cc: Donglin Peng <dolinux.peng@gmail.com>
Cc: Zheng Yejian <zhengyejian@huaweicloud.com>
Link: https://lore.kernel.org/20250227185823.154996172@goodmis.org


Reviewed-by: default avatarMasami Hiramatsu (Google) <mhiramat@kernel.org>
Co-developed-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: default avatarSven Schnelle <svens@linux.ibm.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent c7a60a73
Loading
Loading
Loading
Loading
+12 −2
Original line number Diff line number Diff line
@@ -2878,13 +2878,16 @@ trace_buffer_unlock_commit_nostack(struct trace_buffer *buffer,

void
trace_function(struct trace_array *tr, unsigned long ip, unsigned long
	       parent_ip, unsigned int trace_ctx)
	       parent_ip, unsigned int trace_ctx, struct ftrace_regs *fregs)
{
	struct trace_buffer *buffer = tr->array_buffer.buffer;
	struct ring_buffer_event *event;
	struct ftrace_entry *entry;
	int size = sizeof(*entry);

	event = __trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry),
	size += FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long);

	event = __trace_buffer_lock_reserve(buffer, TRACE_FN, size,
					    trace_ctx);
	if (!event)
		return;
@@ -2892,6 +2895,13 @@ trace_function(struct trace_array *tr, unsigned long ip, unsigned long
	entry->ip			= ip;
	entry->parent_ip		= parent_ip;

#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
	if (fregs) {
		for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++)
			entry->args[i] = ftrace_regs_get_argument(fregs, i);
	}
#endif

	if (static_branch_unlikely(&trace_function_exports_enabled))
		ftrace_exports(event, TRACE_EXPORT_FUNCTION);
	__buffer_unlock_commit(buffer, event);
+3 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#include <linux/workqueue.h>
#include <linux/ctype.h>
#include <linux/once_lite.h>
#include <linux/ftrace_regs.h>

#include "pid_list.h"

@@ -697,7 +698,8 @@ unsigned long trace_total_entries(struct trace_array *tr);
void trace_function(struct trace_array *tr,
		    unsigned long ip,
		    unsigned long parent_ip,
		    unsigned int trace_ctx);
		    unsigned int trace_ctx,
		    struct ftrace_regs *regs);
void trace_graph_function(struct trace_array *tr,
		    unsigned long ip,
		    unsigned long parent_ip,
+3 −2
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
	F_STRUCT(
		__field_fn(	unsigned long,		ip		)
		__field_fn(	unsigned long,		parent_ip	)
		__dynamic_array( unsigned long,		args		)
	),

	F_printk(" %ps <-- %ps",
+41 −5
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ static void
function_trace_call(unsigned long ip, unsigned long parent_ip,
		    struct ftrace_ops *op, struct ftrace_regs *fregs);
static void
function_args_trace_call(unsigned long ip, unsigned long parent_ip,
			 struct ftrace_ops *op, struct ftrace_regs *fregs);
static void
function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
			  struct ftrace_ops *op, struct ftrace_regs *fregs);
static void
@@ -42,9 +45,10 @@ enum {
	TRACE_FUNC_NO_OPTS		= 0x0, /* No flags set. */
	TRACE_FUNC_OPT_STACK		= 0x1,
	TRACE_FUNC_OPT_NO_REPEATS	= 0x2,
	TRACE_FUNC_OPT_ARGS		= 0x4,

	/* Update this to next highest bit. */
	TRACE_FUNC_OPT_HIGHEST_BIT	= 0x4
	TRACE_FUNC_OPT_HIGHEST_BIT	= 0x8
};

#define TRACE_FUNC_OPT_MASK	(TRACE_FUNC_OPT_HIGHEST_BIT - 1)
@@ -114,6 +118,8 @@ static ftrace_func_t select_trace_function(u32 flags_val)
	switch (flags_val & TRACE_FUNC_OPT_MASK) {
	case TRACE_FUNC_NO_OPTS:
		return function_trace_call;
	case TRACE_FUNC_OPT_ARGS:
		return function_args_trace_call;
	case TRACE_FUNC_OPT_STACK:
		return function_stack_trace_call;
	case TRACE_FUNC_OPT_NO_REPEATS:
@@ -220,7 +226,34 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,

	data = this_cpu_ptr(tr->array_buffer.data);
	if (!atomic_read(&data->disabled))
		trace_function(tr, ip, parent_ip, trace_ctx);
		trace_function(tr, ip, parent_ip, trace_ctx, NULL);

	ftrace_test_recursion_unlock(bit);
}

static void
function_args_trace_call(unsigned long ip, unsigned long parent_ip,
			 struct ftrace_ops *op, struct ftrace_regs *fregs)
{
	struct trace_array *tr = op->private;
	struct trace_array_cpu *data;
	unsigned int trace_ctx;
	int bit;
	int cpu;

	if (unlikely(!tr->function_enabled))
		return;

	bit = ftrace_test_recursion_trylock(ip, parent_ip);
	if (bit < 0)
		return;

	trace_ctx = tracing_gen_ctx();

	cpu = smp_processor_id();
	data = per_cpu_ptr(tr->array_buffer.data, cpu);
	if (!atomic_read(&data->disabled))
		trace_function(tr, ip, parent_ip, trace_ctx, fregs);

	ftrace_test_recursion_unlock(bit);
}
@@ -270,7 +303,7 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip,

	if (likely(disabled == 1)) {
		trace_ctx = tracing_gen_ctx_flags(flags);
		trace_function(tr, ip, parent_ip, trace_ctx);
		trace_function(tr, ip, parent_ip, trace_ctx, NULL);
#ifdef CONFIG_UNWINDER_FRAME_POINTER
		if (ftrace_pids_enabled(op))
			skip++;
@@ -349,7 +382,7 @@ function_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
	trace_ctx = tracing_gen_ctx_dec();
	process_repeats(tr, ip, parent_ip, last_info, trace_ctx);

	trace_function(tr, ip, parent_ip, trace_ctx);
	trace_function(tr, ip, parent_ip, trace_ctx, NULL);

out:
	ftrace_test_recursion_unlock(bit);
@@ -389,7 +422,7 @@ function_stack_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
		trace_ctx = tracing_gen_ctx_flags(flags);
		process_repeats(tr, ip, parent_ip, last_info, trace_ctx);

		trace_function(tr, ip, parent_ip, trace_ctx);
		trace_function(tr, ip, parent_ip, trace_ctx, NULL);
		__trace_stack(tr, trace_ctx, STACK_SKIP);
	}

@@ -403,6 +436,9 @@ static struct tracer_opt func_opts[] = {
	{ TRACER_OPT(func_stack_trace, TRACE_FUNC_OPT_STACK) },
#endif
	{ TRACER_OPT(func-no-repeats, TRACE_FUNC_OPT_NO_REPEATS) },
#ifdef CONFIG_FUNCTION_TRACE_ARGS
	{ TRACER_OPT(func-args, TRACE_FUNC_OPT_ARGS) },
#endif
	{ } /* Always set a last empty entry */
};

+9 −3
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip,

	trace_ctx = tracing_gen_ctx_flags(flags);

	trace_function(tr, ip, parent_ip, trace_ctx);
	trace_function(tr, ip, parent_ip, trace_ctx, fregs);

	atomic_dec(&data->disabled);
}
@@ -295,11 +295,17 @@ __trace_function(struct trace_array *tr,
	if (is_graph(tr))
		trace_graph_function(tr, ip, parent_ip, trace_ctx);
	else
		trace_function(tr, ip, parent_ip, trace_ctx);
		trace_function(tr, ip, parent_ip, trace_ctx, NULL);
}

#else
#define __trace_function trace_function
static inline void
__trace_function(struct trace_array *tr,
		 unsigned long ip, unsigned long parent_ip,
		 unsigned int trace_ctx)
{
	return trace_function(tr, ip, parent_ip, trace_ctx, NULL);
}

static enum print_line_t irqsoff_print_line(struct trace_iterator *iter)
{
Loading