* [PATCH v3 0/4] ftrace: Add function arguments to function tracers
@ 2025-02-25 22:26 Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 1/4] ftrace: Add print_function_args() Steven Rostedt
` (3 more replies)
0 siblings, 4 replies; 8+ messages in thread
From: Steven Rostedt @ 2025-02-25 22:26 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Sven Schnelle, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
Donglin Peng, Zheng Yejian, bpf
These patches add support for printing function arguments in ftrace.
Example usage:
function tracer:
~# cd /sys/kernel/tracing/
~# echo icmp_rcv >set_ftrace_filter
~# echo function >current_tracer
~# echo 1 >options/func-args
~# ping -c 10 127.0.0.1
[..]
~# cat trace
[..]
ping-1277 [030] ..s1. 39.120939: icmp_rcv(skb=0xa0ecab00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 39.120946: icmp_rcv(skb=0xa0ecac00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 40.179724: icmp_rcv(skb=0xa0ecab00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 40.179730: icmp_rcv(skb=0xa0ecac00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 41.219700: icmp_rcv(skb=0xa0ecab00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 41.219706: icmp_rcv(skb=0xa0ecac00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 42.259717: icmp_rcv(skb=0xa0ecab00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 42.259725: icmp_rcv(skb=0xa0ecac00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 43.299735: icmp_rcv(skb=0xa0ecab00) <-ip_protocol_deliver_rcu
ping-1277 [030] ..s1. 43.299742: icmp_rcv(skb=0xa0ecac00) <-ip_protocol_deliver_rcu
function graph:
~# cd /sys/kernel/tracing
~# echo icmp_rcv >set_graph_function
~# echo function_graph >current_tracer
~# echo 1 >options/funcgraph-args
~# ping -c 1 127.0.0.1
~# cat trace
30) | icmp_rcv(skb=0xa0ecab00) {
30) | __skb_checksum_complete(skb=0xa0ecab00) {
30) | skb_checksum(skb=0xa0ecab00, offset=0, len=64, csum=0) {
30) | __skb_checksum(skb=0xa0ecab00, offset=0, len=64, csum=0, ops=0x232e0327a88) {
30) 0.418 us | csum_partial(buff=0xa0d20924, len=64, sum=0)
30) 0.985 us | }
30) 1.463 us | }
30) 2.039 us | }
[..]
This was last posted by Sven Schnelle here:
https://lore.kernel.org/all/20240904065908.1009086-1-svens@linux.ibm.com/
As Sven hasn't worked on it since, I decided to continue to push it
through. I'm keeping Sven as original author and added myself as
"Co-developed-by".
Changes since v2: https://lore.kernel.org/linux-trace-kernel/20241223201347.609298489@goodmis.org/
- Removed unneeded headers
- Put back removed '\n' that was accidentally erased.
- Do not use bpf_get_btf_vmlinux() to get btf element as
btf_find_func_proto() will handle that.
- Fixed how structures are printed
Changes since Sven's work:
- Made the kconfig option unconditional if all the dependencies are set.
- Not save ftrace_regs in the ring buffer, as that is an abstract
descriptor defined by the architectures and should remain opaque from
generic code. Instead, the args are read at the time they are recorded
(with the ftrace_regs passed to the callback function), and saved into
the ring buffer. Then the print function only takes an array of elements.
This could allow archs to retrieve arguments that are on the stack where
as, post processing ftrace_regs could cause undesirable results.
- Made the function and function graph entry events dynamically sized
to allow the arguments to be appended to the event in the ring buffer.
The print function only looks to see if the event saved in the ring
buffer is big enough to hold all the arguments defined by the new
FTRACE_REGS_MAX_ARGS macro and if so, it will assume there are arguments
there and print them. This also means user space will not break on
reading these events as arguments will simply be ignored.
- The printing of the arguments has some more data when things are not
processed by BPF. Any unsupported argument will have the type printed
out in the ring buffer.
- Also removed the spaces around the '=' as that's more in line to how
trace events show their fields.
- One new patch I added to convert function graph tracing over to using
args as soon as the user sets the option even if function graph tracing
is enabled. Function tracer did this already by default.
Steven Rostedt (1):
ftrace: Have funcgraph-args take affect during tracing
Sven Schnelle (3):
ftrace: Add print_function_args()
ftrace: Add support for function argument to graph tracer
ftrace: Add arguments to function tracer
----
include/linux/ftrace_regs.h | 5 ++
kernel/trace/Kconfig | 12 +++
kernel/trace/trace.c | 12 ++-
kernel/trace/trace.h | 4 +-
kernel/trace/trace_entries.h | 12 +--
kernel/trace/trace_functions.c | 46 ++++++++--
kernel/trace/trace_functions_graph.c | 170 ++++++++++++++++++++++++++++-------
kernel/trace/trace_irqsoff.c | 4 +-
kernel/trace/trace_output.c | 103 ++++++++++++++++++++-
kernel/trace/trace_output.h | 9 ++
kernel/trace/trace_sched_wakeup.c | 4 +-
11 files changed, 328 insertions(+), 53 deletions(-)
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 1/4] ftrace: Add print_function_args()
2025-02-25 22:26 [PATCH v3 0/4] ftrace: Add function arguments to function tracers Steven Rostedt
@ 2025-02-25 22:26 ` Steven Rostedt
2025-02-26 14:48 ` Masami Hiramatsu
2025-02-25 22:26 ` [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer Steven Rostedt
` (2 subsequent siblings)
3 siblings, 1 reply; 8+ messages in thread
From: Steven Rostedt @ 2025-02-25 22:26 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Sven Schnelle, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
Donglin Peng, Zheng Yejian, bpf
From: Sven Schnelle <svens@linux.ibm.com>
Add a function to decode argument types with the help of BTF. Will
be used to display arguments in the function and function graph
tracer.
It can only handle simply arguments and up to FTRACE_REGS_MAX_ARGS number
of arguments. When it hits a max, it will print ", ...":
page_to_skb(vi=0xffff8d53842dc980, rq=0xffff8d53843a0800, page=0xfffffc2e04337c00, offset=6160, len=64, truesize=1536, ...)
And if it hits an argument that is not recognized, it will print the raw
value and the type of argument it is:
make_vfsuid(idmap=0xffffffff87f99db8, fs_userns=0xffffffff87e543c0, kuid=0x0 (STRUCT))
__pti_set_user_pgtbl(pgdp=0xffff8d5384ab47f8, pgd=0x110e74067 (STRUCT))
Cc: Masami Hiramatsu <mhiramat@kernel.org>
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/20241223201541.898496620@goodmis.org
Co-developed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
include/linux/ftrace_regs.h | 5 +++
kernel/trace/Kconfig | 6 +++
kernel/trace/trace_output.c | 85 +++++++++++++++++++++++++++++++++++++
kernel/trace/trace_output.h | 9 ++++
4 files changed, 105 insertions(+)
diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
index bbc1873ca6b8..15627ceea9bc 100644
--- a/include/linux/ftrace_regs.h
+++ b/include/linux/ftrace_regs.h
@@ -35,4 +35,9 @@ struct ftrace_regs;
#endif /* HAVE_ARCH_FTRACE_REGS */
+/* This can be overridden by the architectures */
+#ifndef FTRACE_REGS_MAX_ARGS
+# define FTRACE_REGS_MAX_ARGS 6
+#endif
+
#endif /* _LINUX_FTRACE_REGS_H */
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index d570b8b9c0a9..60412c1012ef 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -263,6 +263,12 @@ config FUNCTION_GRAPH_RETADDR
the function is called. This feature is off by default, and you can
enable it via the trace option funcgraph-retaddr.
+config FUNCTION_TRACE_ARGS
+ bool
+ depends on HAVE_FUNCTION_ARG_ACCESS_API
+ depends on DEBUG_INFO_BTF
+ default y
+
config DYNAMIC_FTRACE
bool "enable/disable function tracing dynamically"
depends on FUNCTION_TRACER
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 03d56f711ad1..4b721cd4f21d 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -12,8 +12,11 @@
#include <linux/sched/clock.h>
#include <linux/sched/mm.h>
#include <linux/idr.h>
+#include <linux/btf.h>
+#include <linux/bpf.h>
#include "trace_output.h"
+#include "trace_btf.h"
/* must be a power of 2 */
#define EVENT_HASHSIZE 128
@@ -684,6 +687,88 @@ int trace_print_lat_context(struct trace_iterator *iter)
return !trace_seq_has_overflowed(s);
}
+#ifdef CONFIG_FUNCTION_TRACE_ARGS
+void print_function_args(struct trace_seq *s, unsigned long *args,
+ unsigned long func)
+{
+ const struct btf_param *param;
+ const struct btf_type *t;
+ const char *param_name;
+ char name[KSYM_NAME_LEN];
+ unsigned long arg;
+ struct btf *btf;
+ s32 tid, nr = 0;
+ int a, p, x;
+
+ trace_seq_printf(s, "(");
+
+ if (!args)
+ goto out;
+ if (lookup_symbol_name(func, name))
+ goto out;
+
+ /* TODO: Pass module name here too */
+ t = btf_find_func_proto(name, &btf);
+ if (IS_ERR_OR_NULL(t))
+ goto out;
+
+ param = btf_get_func_param(t, &nr);
+ if (!param)
+ goto out_put;
+
+ for (a = 0, p = 0; p < nr; a++, p++) {
+ if (p)
+ trace_seq_puts(s, ", ");
+
+ /* This only prints what the arch allows (6 args by default) */
+ if (a == FTRACE_REGS_MAX_ARGS) {
+ trace_seq_puts(s, "...");
+ break;
+ }
+
+ arg = args[a];
+
+ param_name = btf_name_by_offset(btf, param[p].name_off);
+ if (param_name)
+ trace_seq_printf(s, "%s=", param_name);
+ t = btf_type_skip_modifiers(btf, param[p].type, &tid);
+
+ switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) {
+ case BTF_KIND_UNKN:
+ trace_seq_putc(s, '?');
+ /* Still print unknown type values */
+ fallthrough;
+ case BTF_KIND_PTR:
+ trace_seq_printf(s, "0x%lx", arg);
+ break;
+ case BTF_KIND_INT:
+ trace_seq_printf(s, "%ld", arg);
+ break;
+ case BTF_KIND_ENUM:
+ trace_seq_printf(s, "%ld", arg);
+ break;
+ default:
+ /* This does not handle complex arguments */
+ trace_seq_printf(s, "(%s)[0x%lx", btf_type_str(t), arg);
+ for (x = sizeof(long); x < t->size; x += sizeof(long)) {
+ trace_seq_putc(s, ':');
+ if (++a == FTRACE_REGS_MAX_ARGS) {
+ trace_seq_puts(s, "...]");
+ goto out_put;
+ }
+ trace_seq_printf(s, "0x%lx", args[a]);
+ }
+ trace_seq_putc(s, ']');
+ break;
+ }
+ }
+out_put:
+ btf_put(btf);
+out:
+ trace_seq_printf(s, ")");
+}
+#endif
+
/**
* ftrace_find_event - find a registered event
* @type: the type of event to look for
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
index dca40f1f1da4..2e305364f2a9 100644
--- a/kernel/trace/trace_output.h
+++ b/kernel/trace/trace_output.h
@@ -41,5 +41,14 @@ extern struct rw_semaphore trace_event_sem;
#define SEQ_PUT_HEX_FIELD(s, x) \
trace_seq_putmem_hex(s, &(x), sizeof(x))
+#ifdef CONFIG_FUNCTION_TRACE_ARGS
+void print_function_args(struct trace_seq *s, unsigned long *args,
+ unsigned long func);
+#else
+static inline void print_function_args(struct trace_seq *s, unsigned long *args,
+ unsigned long func) {
+ trace_seq_puts(s, "()");
+}
+#endif
#endif
--
2.47.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer
2025-02-25 22:26 [PATCH v3 0/4] ftrace: Add function arguments to function tracers Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 1/4] ftrace: Add print_function_args() Steven Rostedt
@ 2025-02-25 22:26 ` Steven Rostedt
2025-02-26 14:48 ` Masami Hiramatsu
2025-02-25 22:26 ` [PATCH v3 3/4] ftrace: Have funcgraph-args take affect during tracing Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 4/4] ftrace: Add arguments to function tracer Steven Rostedt
3 siblings, 1 reply; 8+ messages in thread
From: Steven Rostedt @ 2025-02-25 22:26 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Sven Schnelle, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
Donglin Peng, Zheng Yejian, bpf
From: Sven Schnelle <svens@linux.ibm.com>
Wire up the code to print function arguments in the function graph
tracer. This functionality can be enabled/disabled during runtime with
options/funcgraph-args.
Example usage:
6) | dummy_xmit [dummy](skb = 0x8887c100, dev = 0x872ca000) {
6) | consume_skb(skb = 0x8887c100) {
6) | skb_release_head_state(skb = 0x8887c100) {
6) 0.178 us | sock_wfree(skb = 0x8887c100)
6) 0.627 us | }
Cc: Masami Hiramatsu <mhiramat@kernel.org>
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/20241223201542.067076254@goodmis.org
Co-developed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
kernel/trace/Kconfig | 6 ++
kernel/trace/trace.h | 1 +
kernel/trace/trace_entries.h | 7 +-
kernel/trace/trace_functions_graph.c | 143 +++++++++++++++++++++------
4 files changed, 122 insertions(+), 35 deletions(-)
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index 60412c1012ef..033fba0633cf 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -268,6 +268,12 @@ config FUNCTION_TRACE_ARGS
depends on HAVE_FUNCTION_ARG_ACCESS_API
depends on DEBUG_INFO_BTF
default y
+ help
+ If supported with function argument access API and BTF, then
+ the function tracer and function graph tracer will support printing
+ of function arguments. This feature is off by default, and can be
+ enabled via the trace option func-args (for the function tracer) and
+ funcgraph-args (for the function graph tracer)
config DYNAMIC_FTRACE
bool "enable/disable function tracing dynamically"
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 9c21ba45b7af..6963cd83b6da 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -897,6 +897,7 @@ static __always_inline bool ftrace_hash_empty(struct ftrace_hash *hash)
#define TRACE_GRAPH_PRINT_RETVAL 0x800
#define TRACE_GRAPH_PRINT_RETVAL_HEX 0x1000
#define TRACE_GRAPH_PRINT_RETADDR 0x2000
+#define TRACE_GRAPH_ARGS 0x4000
#define TRACE_GRAPH_PRINT_FILL_SHIFT 28
#define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index fbfb396905a6..77a8ba3bc1e3 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -72,17 +72,18 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
);
/* Function call entry */
-FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry,
+FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
TRACE_GRAPH_ENT,
F_STRUCT(
__field_struct( struct ftrace_graph_ent, graph_ent )
__field_packed( unsigned long, graph_ent, func )
- __field_packed( int, graph_ent, depth )
+ __field_packed( unsigned long, graph_ent, depth )
+ __dynamic_array(unsigned long, args )
),
- F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth)
+ F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth)
);
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 136c750b0b4d..406b21472bde 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -70,6 +70,10 @@ static struct tracer_opt trace_opts[] = {
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
/* Display function return address ? */
{ TRACER_OPT(funcgraph-retaddr, TRACE_GRAPH_PRINT_RETADDR) },
+#endif
+#ifdef CONFIG_FUNCTION_TRACE_ARGS
+ /* Display function arguments ? */
+ { TRACER_OPT(funcgraph-args, TRACE_GRAPH_ARGS) },
#endif
/* Include sleep time (scheduled out) between entry and return */
{ TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) },
@@ -110,25 +114,41 @@ static void
print_graph_duration(struct trace_array *tr, unsigned long long duration,
struct trace_seq *s, u32 flags);
-int __trace_graph_entry(struct trace_array *tr,
- struct ftrace_graph_ent *trace,
- unsigned int trace_ctx)
+static int __graph_entry(struct trace_array *tr, struct ftrace_graph_ent *trace,
+ unsigned int trace_ctx, struct ftrace_regs *fregs)
{
struct ring_buffer_event *event;
struct trace_buffer *buffer = tr->array_buffer.buffer;
struct ftrace_graph_ent_entry *entry;
+ int size;
- event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
- sizeof(*entry), trace_ctx);
+ /* If fregs is defined, add FTRACE_REGS_MAX_ARGS long size words */
+ size = sizeof(*entry) + (FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long));
+
+ event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, size, trace_ctx);
if (!event)
return 0;
- entry = ring_buffer_event_data(event);
- entry->graph_ent = *trace;
+
+ entry = ring_buffer_event_data(event);
+ entry->graph_ent = *trace;
+
+ if (fregs) {
+ for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++)
+ entry->args[i] = ftrace_regs_get_argument(fregs, i);
+ }
+
trace_buffer_unlock_commit_nostack(buffer, event);
return 1;
}
+int __trace_graph_entry(struct trace_array *tr,
+ struct ftrace_graph_ent *trace,
+ unsigned int trace_ctx)
+{
+ return __graph_entry(tr, trace, trace_ctx, NULL);
+}
+
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
int __trace_graph_retaddr_entry(struct trace_array *tr,
struct ftrace_graph_ent *trace,
@@ -174,9 +194,9 @@ struct fgraph_times {
unsigned long long sleeptime; /* may be optional! */
};
-int trace_graph_entry(struct ftrace_graph_ent *trace,
- struct fgraph_ops *gops,
- struct ftrace_regs *fregs)
+static int graph_entry(struct ftrace_graph_ent *trace,
+ struct fgraph_ops *gops,
+ struct ftrace_regs *fregs)
{
unsigned long *task_var = fgraph_get_task_var(gops);
struct trace_array *tr = gops->private;
@@ -246,7 +266,7 @@ int trace_graph_entry(struct ftrace_graph_ent *trace,
unsigned long retaddr = ftrace_graph_top_ret_addr(current);
ret = __trace_graph_retaddr_entry(tr, trace, trace_ctx, retaddr);
} else {
- ret = __trace_graph_entry(tr, trace, trace_ctx);
+ ret = __graph_entry(tr, trace, trace_ctx, fregs);
}
}
preempt_enable_notrace();
@@ -254,6 +274,20 @@ int trace_graph_entry(struct ftrace_graph_ent *trace,
return ret;
}
+int trace_graph_entry(struct ftrace_graph_ent *trace,
+ struct fgraph_ops *gops,
+ struct ftrace_regs *fregs)
+{
+ return graph_entry(trace, gops, NULL);
+}
+
+static int trace_graph_entry_args(struct ftrace_graph_ent *trace,
+ struct fgraph_ops *gops,
+ struct ftrace_regs *fregs)
+{
+ return graph_entry(trace, gops, fregs);
+}
+
static void
__trace_graph_function(struct trace_array *tr,
unsigned long ip, unsigned int trace_ctx)
@@ -418,7 +452,10 @@ static int graph_trace_init(struct trace_array *tr)
{
int ret;
- tr->gops->entryfunc = trace_graph_entry;
+ if (tracer_flags_is_set(TRACE_GRAPH_ARGS))
+ tr->gops->entryfunc = trace_graph_entry_args;
+ else
+ tr->gops->entryfunc = trace_graph_entry;
if (tracing_thresh)
tr->gops->retfunc = trace_graph_thresh_return;
@@ -775,7 +812,7 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e
static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry,
struct ftrace_graph_ret *graph_ret, void *func,
- u32 opt_flags, u32 trace_flags)
+ u32 opt_flags, u32 trace_flags, int args_size)
{
unsigned long err_code = 0;
unsigned long retval = 0;
@@ -809,7 +846,14 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr
if (entry->ent.type != TRACE_GRAPH_RETADDR_ENT)
print_retaddr = false;
- trace_seq_printf(s, "%ps();", func);
+ trace_seq_printf(s, "%ps", func);
+
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) {
+ print_function_args(s, entry->args, (unsigned long)func);
+ trace_seq_putc(s, ';');
+ } else
+ trace_seq_puts(s, "();");
+
if (print_retval || print_retaddr)
trace_seq_puts(s, " /*");
else
@@ -836,7 +880,8 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr
#else
-#define print_graph_retval(_seq, _ent, _ret, _func, _opt_flags, _trace_flags) do {} while (0)
+#define print_graph_retval(_seq, _ent, _ret, _func, _opt_flags, _trace_flags, args_size) \
+ do {} while (0)
#endif
@@ -852,10 +897,14 @@ print_graph_entry_leaf(struct trace_iterator *iter,
struct ftrace_graph_ret *graph_ret;
struct ftrace_graph_ent *call;
unsigned long long duration;
+ unsigned long ret_func;
unsigned long func;
+ int args_size;
int cpu = iter->cpu;
int i;
+ args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args);
+
graph_ret = &ret_entry->ret;
call = &entry->graph_ent;
duration = ret_entry->rettime - ret_entry->calltime;
@@ -887,16 +936,25 @@ print_graph_entry_leaf(struct trace_iterator *iter,
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)
trace_seq_putc(s, ' ');
+ ret_func = graph_ret->func + iter->tr->text_delta;
+
/*
* Write out the function return value or return address
*/
if (flags & (__TRACE_GRAPH_PRINT_RETVAL | __TRACE_GRAPH_PRINT_RETADDR)) {
print_graph_retval(s, entry, graph_ret,
(void *)graph_ret->func + iter->tr->text_delta,
- flags, tr->trace_flags);
+ flags, tr->trace_flags, args_size);
} else {
- trace_seq_printf(s, "%ps();\n", (void *)func);
+ trace_seq_printf(s, "%ps", (void *)ret_func);
+
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) {
+ print_function_args(s, entry->args, ret_func);
+ trace_seq_putc(s, ';');
+ } else
+ trace_seq_puts(s, "();");
}
+ trace_seq_printf(s, "\n");
print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET,
cpu, iter->ent->pid, flags);
@@ -913,6 +971,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
struct fgraph_data *data = iter->private;
struct trace_array *tr = iter->tr;
unsigned long func;
+ int args_size;
int i;
if (data) {
@@ -937,7 +996,17 @@ print_graph_entry_nested(struct trace_iterator *iter,
func = call->func + iter->tr->text_delta;
- trace_seq_printf(s, "%ps() {", (void *)func);
+ trace_seq_printf(s, "%ps", (void *)func);
+
+ args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args);
+
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long))
+ print_function_args(s, entry->args, func);
+ else
+ trace_seq_puts(s, "()");
+
+ trace_seq_puts(s, " {");
+
if (flags & __TRACE_GRAPH_PRINT_RETADDR &&
entry->ent.type == TRACE_GRAPH_RETADDR_ENT)
print_graph_retaddr(s, (struct fgraph_retaddr_ent_entry *)entry,
@@ -1107,21 +1176,38 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
struct trace_iterator *iter, u32 flags)
{
struct fgraph_data *data = iter->private;
- struct ftrace_graph_ent *call = &field->graph_ent;
+ struct ftrace_graph_ent *call;
struct ftrace_graph_ret_entry *leaf_ret;
static enum print_line_t ret;
int cpu = iter->cpu;
+ /*
+ * print_graph_entry() may consume the current event,
+ * thus @field may become invalid, so we need to save it.
+ * sizeof(struct ftrace_graph_ent_entry) is very small,
+ * it can be safely saved at the stack.
+ */
+ struct ftrace_graph_ent_entry *entry;
+ u8 save_buf[sizeof(*entry) + FTRACE_REGS_MAX_ARGS * sizeof(long)];
+
+ /* The ent_size is expected to be as big as the entry */
+ if (iter->ent_size > sizeof(save_buf))
+ iter->ent_size = sizeof(save_buf);
+
+ entry = (void *)save_buf;
+ memcpy(entry, field, iter->ent_size);
+
+ call = &entry->graph_ent;
if (check_irq_entry(iter, flags, call->func, call->depth))
return TRACE_TYPE_HANDLED;
print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags);
- leaf_ret = get_return_for_leaf(iter, field);
+ leaf_ret = get_return_for_leaf(iter, entry);
if (leaf_ret)
- ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags);
+ ret = print_graph_entry_leaf(iter, entry, leaf_ret, s, flags);
else
- ret = print_graph_entry_nested(iter, field, s, cpu, flags);
+ ret = print_graph_entry_nested(iter, entry, s, cpu, flags);
if (data) {
/*
@@ -1195,7 +1281,8 @@ print_graph_return(struct ftrace_graph_ret_entry *retentry, struct trace_seq *s,
* funcgraph-retval option is enabled.
*/
if (flags & __TRACE_GRAPH_PRINT_RETVAL) {
- print_graph_retval(s, NULL, trace, (void *)func, flags, tr->trace_flags);
+ print_graph_retval(s, NULL, trace, (void *)func, flags,
+ tr->trace_flags, 0);
} else {
/*
* If the return function does not have a matching entry,
@@ -1323,16 +1410,8 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
switch (entry->type) {
case TRACE_GRAPH_ENT: {
- /*
- * print_graph_entry() may consume the current event,
- * thus @field may become invalid, so we need to save it.
- * sizeof(struct ftrace_graph_ent_entry) is very small,
- * it can be safely saved at the stack.
- */
- struct ftrace_graph_ent_entry saved;
trace_assign_type(field, entry);
- saved = *field;
- return print_graph_entry(&saved, s, iter, flags);
+ return print_graph_entry(field, s, iter, flags);
}
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
case TRACE_GRAPH_RETADDR_ENT: {
--
2.47.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 3/4] ftrace: Have funcgraph-args take affect during tracing
2025-02-25 22:26 [PATCH v3 0/4] ftrace: Add function arguments to function tracers Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 1/4] ftrace: Add print_function_args() Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer Steven Rostedt
@ 2025-02-25 22:26 ` Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 4/4] ftrace: Add arguments to function tracer Steven Rostedt
3 siblings, 0 replies; 8+ messages in thread
From: Steven Rostedt @ 2025-02-25 22:26 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Sven Schnelle, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
Donglin Peng, Zheng Yejian, bpf
From: Steven Rostedt <rostedt@goodmis.org>
Currently, when function_graph is started, it looks at the option
funcgraph-args, and if it is set, it will enable tracing of the arguments.
But if tracing is already running, and the user enables funcgraph-args, it
will have no effect. Instead, it should enable argument tracing when it is
enabled, even if it means disabling the function graph tracing for a short
time in order to do the transition.
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Sven Schnelle <svens@linux.ibm.com>
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/20241223201542.240760965@goodmis.org
Acked-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
kernel/trace/trace_functions_graph.c | 27 ++++++++++++++++++++++++++-
1 file changed, 26 insertions(+), 1 deletion(-)
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 406b21472bde..49fcf665cb58 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -462,7 +462,7 @@ static int graph_trace_init(struct trace_array *tr)
else
tr->gops->retfunc = trace_graph_return;
- /* Make gops functions are visible before we start tracing */
+ /* Make gops functions visible before we start tracing */
smp_mb();
ret = register_ftrace_graph(tr->gops);
@@ -473,6 +473,28 @@ static int graph_trace_init(struct trace_array *tr)
return 0;
}
+static int ftrace_graph_trace_args(struct trace_array *tr, int set)
+{
+ trace_func_graph_ent_t entry;
+
+ if (set)
+ entry = trace_graph_entry_args;
+ else
+ entry = trace_graph_entry;
+
+ /* See if there's any changes */
+ if (tr->gops->entryfunc == entry)
+ return 0;
+
+ unregister_ftrace_graph(tr->gops);
+
+ tr->gops->entryfunc = entry;
+
+ /* Make gops functions visible before we start tracing */
+ smp_mb();
+ return register_ftrace_graph(tr->gops);
+}
+
static void graph_trace_reset(struct trace_array *tr)
{
tracing_stop_cmdline_record();
@@ -1605,6 +1627,9 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
if (bit == TRACE_GRAPH_GRAPH_TIME)
ftrace_graph_graph_time_control(set);
+ if (bit == TRACE_GRAPH_ARGS)
+ return ftrace_graph_trace_args(tr, set);
+
return 0;
}
--
2.47.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 4/4] ftrace: Add arguments to function tracer
2025-02-25 22:26 [PATCH v3 0/4] ftrace: Add function arguments to function tracers Steven Rostedt
` (2 preceding siblings ...)
2025-02-25 22:26 ` [PATCH v3 3/4] ftrace: Have funcgraph-args take affect during tracing Steven Rostedt
@ 2025-02-25 22:26 ` Steven Rostedt
3 siblings, 0 replies; 8+ messages in thread
From: Steven Rostedt @ 2025-02-25 22:26 UTC (permalink / raw)
To: linux-kernel, linux-trace-kernel
Cc: Masami Hiramatsu, Mark Rutland, Mathieu Desnoyers, Andrew Morton,
Sven Schnelle, Paul Walmsley, Palmer Dabbelt, Albert Ou, Guo Ren,
Donglin Peng, Zheng Yejian, bpf
From: Sven Schnelle <svens@linux.ibm.com>
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/20241223201542.415861522@goodmis.org
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Co-developed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
kernel/trace/trace.c | 12 ++++++--
kernel/trace/trace.h | 3 +-
kernel/trace/trace_entries.h | 5 ++--
kernel/trace/trace_functions.c | 46 +++++++++++++++++++++++++++----
kernel/trace/trace_irqsoff.c | 4 +--
kernel/trace/trace_output.c | 18 ++++++++++--
kernel/trace/trace_sched_wakeup.c | 4 +--
7 files changed, 75 insertions(+), 17 deletions(-)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 0e6d517e74e0..86d828b9dc7c 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -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,11 @@ trace_function(struct trace_array *tr, unsigned long ip, unsigned long
entry->ip = ip;
entry->parent_ip = parent_ip;
+ if (fregs) {
+ for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++)
+ entry->args[i] = ftrace_regs_get_argument(fregs, i);
+ }
+
if (static_branch_unlikely(&trace_function_exports_enabled))
ftrace_exports(event, TRACE_EXPORT_FUNCTION);
__buffer_unlock_commit(buffer, event);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 6963cd83b6da..472ec5d623db 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -697,7 +697,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,
diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
index 77a8ba3bc1e3..ee40d4e6ad1c 100644
--- a/kernel/trace/trace_entries.h
+++ b/kernel/trace/trace_entries.h
@@ -61,8 +61,9 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
TRACE_FN,
F_STRUCT(
- __field_fn( unsigned long, ip )
- __field_fn( unsigned long, parent_ip )
+ __field_fn( unsigned long, ip )
+ __field_fn( unsigned long, parent_ip )
+ __dynamic_array( unsigned long, args )
),
F_printk(" %ps <-- %ps",
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index df56f9b76010..98ccf3f00c51 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -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 */
};
diff --git a/kernel/trace/trace_irqsoff.c b/kernel/trace/trace_irqsoff.c
index 7294ad676379..0ce00fe66d0c 100644
--- a/kernel/trace/trace_irqsoff.c
+++ b/kernel/trace/trace_irqsoff.c
@@ -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,7 +295,7 @@ __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
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index 4b721cd4f21d..b51ee9373773 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -1090,12 +1090,15 @@ enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags,
}
static void print_fn_trace(struct trace_seq *s, unsigned long ip,
- unsigned long parent_ip, long delta, int flags)
+ unsigned long parent_ip, long delta,
+ unsigned long *args, int flags)
{
ip += delta;
parent_ip += delta;
seq_print_ip_sym(s, ip, flags);
+ if (args)
+ print_function_args(s, args, ip);
if ((flags & TRACE_ITER_PRINT_PARENT) && parent_ip) {
trace_seq_puts(s, " <-");
@@ -1109,10 +1112,19 @@ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags,
{
struct ftrace_entry *field;
struct trace_seq *s = &iter->seq;
+ unsigned long *args;
+ int args_size;
trace_assign_type(field, iter->ent);
- print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, flags);
+ args_size = iter->ent_size - offsetof(struct ftrace_entry, args);
+ if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long))
+ args = field->args;
+ else
+ args = NULL;
+
+ print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta,
+ args, flags);
trace_seq_putc(s, '\n');
return trace_handle_return(s);
@@ -1785,7 +1797,7 @@ trace_func_repeats_print(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, flags);
+ print_fn_trace(s, field->ip, field->parent_ip, iter->tr->text_delta, NULL, flags);
trace_seq_printf(s, " (repeats: %u, last_ts:", field->count);
trace_print_time(s, iter,
iter->ts - FUNC_REPEATS_GET_DELTA_TS(field));
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index af30586f1aea..c9ba4259e03e 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -242,7 +242,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip,
return;
local_irq_save(flags);
- trace_function(tr, ip, parent_ip, trace_ctx);
+ trace_function(tr, ip, parent_ip, trace_ctx, fregs);
local_irq_restore(flags);
atomic_dec(&data->disabled);
@@ -327,7 +327,7 @@ __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);
}
static int wakeup_flag_changed(struct trace_array *tr, u32 mask, int set)
--
2.47.2
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 1/4] ftrace: Add print_function_args()
2025-02-25 22:26 ` [PATCH v3 1/4] ftrace: Add print_function_args() Steven Rostedt
@ 2025-02-26 14:48 ` Masami Hiramatsu
0 siblings, 0 replies; 8+ messages in thread
From: Masami Hiramatsu @ 2025-02-26 14:48 UTC (permalink / raw)
To: Steven Rostedt
Cc: linux-kernel, linux-trace-kernel, Masami Hiramatsu, Mark Rutland,
Mathieu Desnoyers, Andrew Morton, Sven Schnelle, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Guo Ren, Donglin Peng, Zheng Yejian,
bpf
On Tue, 25 Feb 2025 17:26:02 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:
> From: Sven Schnelle <svens@linux.ibm.com>
>
> Add a function to decode argument types with the help of BTF. Will
> be used to display arguments in the function and function graph
> tracer.
>
> It can only handle simply arguments and up to FTRACE_REGS_MAX_ARGS number
> of arguments. When it hits a max, it will print ", ...":
>
> page_to_skb(vi=0xffff8d53842dc980, rq=0xffff8d53843a0800, page=0xfffffc2e04337c00, offset=6160, len=64, truesize=1536, ...)
>
> And if it hits an argument that is not recognized, it will print the raw
> value and the type of argument it is:
>
> make_vfsuid(idmap=0xffffffff87f99db8, fs_userns=0xffffffff87e543c0, kuid=0x0 (STRUCT))
> __pti_set_user_pgtbl(pgdp=0xffff8d5384ab47f8, pgd=0x110e74067 (STRUCT))
>
This looks good to me.
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Thank you,
> Cc: Masami Hiramatsu <mhiramat@kernel.org>
> 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/20241223201541.898496620@goodmis.org
> Co-developed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
> include/linux/ftrace_regs.h | 5 +++
> kernel/trace/Kconfig | 6 +++
> kernel/trace/trace_output.c | 85 +++++++++++++++++++++++++++++++++++++
> kernel/trace/trace_output.h | 9 ++++
> 4 files changed, 105 insertions(+)
>
> diff --git a/include/linux/ftrace_regs.h b/include/linux/ftrace_regs.h
> index bbc1873ca6b8..15627ceea9bc 100644
> --- a/include/linux/ftrace_regs.h
> +++ b/include/linux/ftrace_regs.h
> @@ -35,4 +35,9 @@ struct ftrace_regs;
>
> #endif /* HAVE_ARCH_FTRACE_REGS */
>
> +/* This can be overridden by the architectures */
> +#ifndef FTRACE_REGS_MAX_ARGS
> +# define FTRACE_REGS_MAX_ARGS 6
> +#endif
> +
> #endif /* _LINUX_FTRACE_REGS_H */
> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> index d570b8b9c0a9..60412c1012ef 100644
> --- a/kernel/trace/Kconfig
> +++ b/kernel/trace/Kconfig
> @@ -263,6 +263,12 @@ config FUNCTION_GRAPH_RETADDR
> the function is called. This feature is off by default, and you can
> enable it via the trace option funcgraph-retaddr.
>
> +config FUNCTION_TRACE_ARGS
> + bool
> + depends on HAVE_FUNCTION_ARG_ACCESS_API
> + depends on DEBUG_INFO_BTF
> + default y
> +
> config DYNAMIC_FTRACE
> bool "enable/disable function tracing dynamically"
> depends on FUNCTION_TRACER
> diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
> index 03d56f711ad1..4b721cd4f21d 100644
> --- a/kernel/trace/trace_output.c
> +++ b/kernel/trace/trace_output.c
> @@ -12,8 +12,11 @@
> #include <linux/sched/clock.h>
> #include <linux/sched/mm.h>
> #include <linux/idr.h>
> +#include <linux/btf.h>
> +#include <linux/bpf.h>
>
> #include "trace_output.h"
> +#include "trace_btf.h"
>
> /* must be a power of 2 */
> #define EVENT_HASHSIZE 128
> @@ -684,6 +687,88 @@ int trace_print_lat_context(struct trace_iterator *iter)
> return !trace_seq_has_overflowed(s);
> }
>
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> +void print_function_args(struct trace_seq *s, unsigned long *args,
> + unsigned long func)
> +{
> + const struct btf_param *param;
> + const struct btf_type *t;
> + const char *param_name;
> + char name[KSYM_NAME_LEN];
> + unsigned long arg;
> + struct btf *btf;
> + s32 tid, nr = 0;
> + int a, p, x;
> +
> + trace_seq_printf(s, "(");
> +
> + if (!args)
> + goto out;
> + if (lookup_symbol_name(func, name))
> + goto out;
> +
> + /* TODO: Pass module name here too */
> + t = btf_find_func_proto(name, &btf);
> + if (IS_ERR_OR_NULL(t))
> + goto out;
> +
> + param = btf_get_func_param(t, &nr);
> + if (!param)
> + goto out_put;
> +
> + for (a = 0, p = 0; p < nr; a++, p++) {
> + if (p)
> + trace_seq_puts(s, ", ");
> +
> + /* This only prints what the arch allows (6 args by default) */
> + if (a == FTRACE_REGS_MAX_ARGS) {
> + trace_seq_puts(s, "...");
> + break;
> + }
> +
> + arg = args[a];
> +
> + param_name = btf_name_by_offset(btf, param[p].name_off);
> + if (param_name)
> + trace_seq_printf(s, "%s=", param_name);
> + t = btf_type_skip_modifiers(btf, param[p].type, &tid);
> +
> + switch (t ? BTF_INFO_KIND(t->info) : BTF_KIND_UNKN) {
> + case BTF_KIND_UNKN:
> + trace_seq_putc(s, '?');
> + /* Still print unknown type values */
> + fallthrough;
> + case BTF_KIND_PTR:
> + trace_seq_printf(s, "0x%lx", arg);
> + break;
> + case BTF_KIND_INT:
> + trace_seq_printf(s, "%ld", arg);
> + break;
> + case BTF_KIND_ENUM:
> + trace_seq_printf(s, "%ld", arg);
> + break;
> + default:
> + /* This does not handle complex arguments */
> + trace_seq_printf(s, "(%s)[0x%lx", btf_type_str(t), arg);
> + for (x = sizeof(long); x < t->size; x += sizeof(long)) {
> + trace_seq_putc(s, ':');
> + if (++a == FTRACE_REGS_MAX_ARGS) {
> + trace_seq_puts(s, "...]");
> + goto out_put;
> + }
> + trace_seq_printf(s, "0x%lx", args[a]);
> + }
> + trace_seq_putc(s, ']');
> + break;
> + }
> + }
> +out_put:
> + btf_put(btf);
> +out:
> + trace_seq_printf(s, ")");
> +}
> +#endif
> +
> /**
> * ftrace_find_event - find a registered event
> * @type: the type of event to look for
> diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
> index dca40f1f1da4..2e305364f2a9 100644
> --- a/kernel/trace/trace_output.h
> +++ b/kernel/trace/trace_output.h
> @@ -41,5 +41,14 @@ extern struct rw_semaphore trace_event_sem;
> #define SEQ_PUT_HEX_FIELD(s, x) \
> trace_seq_putmem_hex(s, &(x), sizeof(x))
>
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> +void print_function_args(struct trace_seq *s, unsigned long *args,
> + unsigned long func);
> +#else
> +static inline void print_function_args(struct trace_seq *s, unsigned long *args,
> + unsigned long func) {
> + trace_seq_puts(s, "()");
> +}
> +#endif
> #endif
>
> --
> 2.47.2
>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer
2025-02-25 22:26 ` [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer Steven Rostedt
@ 2025-02-26 14:48 ` Masami Hiramatsu
2025-02-26 16:11 ` Steven Rostedt
0 siblings, 1 reply; 8+ messages in thread
From: Masami Hiramatsu @ 2025-02-26 14:48 UTC (permalink / raw)
To: Steven Rostedt
Cc: linux-kernel, linux-trace-kernel, Masami Hiramatsu, Mark Rutland,
Mathieu Desnoyers, Andrew Morton, Sven Schnelle, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Guo Ren, Donglin Peng, Zheng Yejian,
bpf
On Tue, 25 Feb 2025 17:26:03 -0500
Steven Rostedt <rostedt@goodmis.org> wrote:
> From: Sven Schnelle <svens@linux.ibm.com>
>
> Wire up the code to print function arguments in the function graph
> tracer. This functionality can be enabled/disabled during runtime with
> options/funcgraph-args.
>
> Example usage:
>
> 6) | dummy_xmit [dummy](skb = 0x8887c100, dev = 0x872ca000) {
> 6) | consume_skb(skb = 0x8887c100) {
> 6) | skb_release_head_state(skb = 0x8887c100) {
> 6) 0.178 us | sock_wfree(skb = 0x8887c100)
> 6) 0.627 us | }
>
> Cc: Masami Hiramatsu <mhiramat@kernel.org>
> 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/20241223201542.067076254@goodmis.org
> Co-developed-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
> ---
> kernel/trace/Kconfig | 6 ++
> kernel/trace/trace.h | 1 +
> kernel/trace/trace_entries.h | 7 +-
> kernel/trace/trace_functions_graph.c | 143 +++++++++++++++++++++------
> 4 files changed, 122 insertions(+), 35 deletions(-)
>
> diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
> index 60412c1012ef..033fba0633cf 100644
> --- a/kernel/trace/Kconfig
> +++ b/kernel/trace/Kconfig
> @@ -268,6 +268,12 @@ config FUNCTION_TRACE_ARGS
> depends on HAVE_FUNCTION_ARG_ACCESS_API
> depends on DEBUG_INFO_BTF
> default y
> + help
> + If supported with function argument access API and BTF, then
> + the function tracer and function graph tracer will support printing
> + of function arguments. This feature is off by default, and can be
> + enabled via the trace option func-args (for the function tracer) and
> + funcgraph-args (for the function graph tracer)
>
> config DYNAMIC_FTRACE
> bool "enable/disable function tracing dynamically"
> diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
> index 9c21ba45b7af..6963cd83b6da 100644
> --- a/kernel/trace/trace.h
> +++ b/kernel/trace/trace.h
> @@ -897,6 +897,7 @@ static __always_inline bool ftrace_hash_empty(struct ftrace_hash *hash)
> #define TRACE_GRAPH_PRINT_RETVAL 0x800
> #define TRACE_GRAPH_PRINT_RETVAL_HEX 0x1000
> #define TRACE_GRAPH_PRINT_RETADDR 0x2000
> +#define TRACE_GRAPH_ARGS 0x4000
> #define TRACE_GRAPH_PRINT_FILL_SHIFT 28
> #define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)
>
> diff --git a/kernel/trace/trace_entries.h b/kernel/trace/trace_entries.h
> index fbfb396905a6..77a8ba3bc1e3 100644
> --- a/kernel/trace/trace_entries.h
> +++ b/kernel/trace/trace_entries.h
> @@ -72,17 +72,18 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
> );
>
> /* Function call entry */
> -FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry,
> +FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
>
> TRACE_GRAPH_ENT,
>
> F_STRUCT(
> __field_struct( struct ftrace_graph_ent, graph_ent )
> __field_packed( unsigned long, graph_ent, func )
> - __field_packed( int, graph_ent, depth )
> + __field_packed( unsigned long, graph_ent, depth )
> + __dynamic_array(unsigned long, args )
> ),
>
> - F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth)
> + F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth)
> );
>
> #ifdef CONFIG_FUNCTION_GRAPH_RETADDR
> diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
> index 136c750b0b4d..406b21472bde 100644
> --- a/kernel/trace/trace_functions_graph.c
> +++ b/kernel/trace/trace_functions_graph.c
> @@ -70,6 +70,10 @@ static struct tracer_opt trace_opts[] = {
> #ifdef CONFIG_FUNCTION_GRAPH_RETADDR
> /* Display function return address ? */
> { TRACER_OPT(funcgraph-retaddr, TRACE_GRAPH_PRINT_RETADDR) },
> +#endif
> +#ifdef CONFIG_FUNCTION_TRACE_ARGS
> + /* Display function arguments ? */
> + { TRACER_OPT(funcgraph-args, TRACE_GRAPH_ARGS) },
> #endif
> /* Include sleep time (scheduled out) between entry and return */
> { TRACER_OPT(sleep-time, TRACE_GRAPH_SLEEP_TIME) },
> @@ -110,25 +114,41 @@ static void
> print_graph_duration(struct trace_array *tr, unsigned long long duration,
> struct trace_seq *s, u32 flags);
>
> -int __trace_graph_entry(struct trace_array *tr,
> - struct ftrace_graph_ent *trace,
> - unsigned int trace_ctx)
> +static int __graph_entry(struct trace_array *tr, struct ftrace_graph_ent *trace,
> + unsigned int trace_ctx, struct ftrace_regs *fregs)
> {
> struct ring_buffer_event *event;
> struct trace_buffer *buffer = tr->array_buffer.buffer;
> struct ftrace_graph_ent_entry *entry;
> + int size;
>
> - event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
> - sizeof(*entry), trace_ctx);
> + /* If fregs is defined, add FTRACE_REGS_MAX_ARGS long size words */
> + size = sizeof(*entry) + (FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long));
Is `!!fregs` always 1 if fregs != NULL? (seems to depend on compiler)
Others looks good to me.
Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Thank you,
> +
> + event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT, size, trace_ctx);
> if (!event)
> return 0;
> - entry = ring_buffer_event_data(event);
> - entry->graph_ent = *trace;
> +
> + entry = ring_buffer_event_data(event);
> + entry->graph_ent = *trace;
> +
> + if (fregs) {
> + for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++)
> + entry->args[i] = ftrace_regs_get_argument(fregs, i);
> + }
> +
> trace_buffer_unlock_commit_nostack(buffer, event);
>
> return 1;
> }
>
> +int __trace_graph_entry(struct trace_array *tr,
> + struct ftrace_graph_ent *trace,
> + unsigned int trace_ctx)
> +{
> + return __graph_entry(tr, trace, trace_ctx, NULL);
> +}
> +
> #ifdef CONFIG_FUNCTION_GRAPH_RETADDR
> int __trace_graph_retaddr_entry(struct trace_array *tr,
> struct ftrace_graph_ent *trace,
> @@ -174,9 +194,9 @@ struct fgraph_times {
> unsigned long long sleeptime; /* may be optional! */
> };
>
> -int trace_graph_entry(struct ftrace_graph_ent *trace,
> - struct fgraph_ops *gops,
> - struct ftrace_regs *fregs)
> +static int graph_entry(struct ftrace_graph_ent *trace,
> + struct fgraph_ops *gops,
> + struct ftrace_regs *fregs)
> {
> unsigned long *task_var = fgraph_get_task_var(gops);
> struct trace_array *tr = gops->private;
> @@ -246,7 +266,7 @@ int trace_graph_entry(struct ftrace_graph_ent *trace,
> unsigned long retaddr = ftrace_graph_top_ret_addr(current);
> ret = __trace_graph_retaddr_entry(tr, trace, trace_ctx, retaddr);
> } else {
> - ret = __trace_graph_entry(tr, trace, trace_ctx);
> + ret = __graph_entry(tr, trace, trace_ctx, fregs);
> }
> }
> preempt_enable_notrace();
> @@ -254,6 +274,20 @@ int trace_graph_entry(struct ftrace_graph_ent *trace,
> return ret;
> }
>
> +int trace_graph_entry(struct ftrace_graph_ent *trace,
> + struct fgraph_ops *gops,
> + struct ftrace_regs *fregs)
> +{
> + return graph_entry(trace, gops, NULL);
> +}
> +
> +static int trace_graph_entry_args(struct ftrace_graph_ent *trace,
> + struct fgraph_ops *gops,
> + struct ftrace_regs *fregs)
> +{
> + return graph_entry(trace, gops, fregs);
> +}
> +
> static void
> __trace_graph_function(struct trace_array *tr,
> unsigned long ip, unsigned int trace_ctx)
> @@ -418,7 +452,10 @@ static int graph_trace_init(struct trace_array *tr)
> {
> int ret;
>
> - tr->gops->entryfunc = trace_graph_entry;
> + if (tracer_flags_is_set(TRACE_GRAPH_ARGS))
> + tr->gops->entryfunc = trace_graph_entry_args;
> + else
> + tr->gops->entryfunc = trace_graph_entry;
>
> if (tracing_thresh)
> tr->gops->retfunc = trace_graph_thresh_return;
> @@ -775,7 +812,7 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e
>
> static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entry *entry,
> struct ftrace_graph_ret *graph_ret, void *func,
> - u32 opt_flags, u32 trace_flags)
> + u32 opt_flags, u32 trace_flags, int args_size)
> {
> unsigned long err_code = 0;
> unsigned long retval = 0;
> @@ -809,7 +846,14 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr
> if (entry->ent.type != TRACE_GRAPH_RETADDR_ENT)
> print_retaddr = false;
>
> - trace_seq_printf(s, "%ps();", func);
> + trace_seq_printf(s, "%ps", func);
> +
> + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) {
> + print_function_args(s, entry->args, (unsigned long)func);
> + trace_seq_putc(s, ';');
> + } else
> + trace_seq_puts(s, "();");
> +
> if (print_retval || print_retaddr)
> trace_seq_puts(s, " /*");
> else
> @@ -836,7 +880,8 @@ static void print_graph_retval(struct trace_seq *s, struct ftrace_graph_ent_entr
>
> #else
>
> -#define print_graph_retval(_seq, _ent, _ret, _func, _opt_flags, _trace_flags) do {} while (0)
> +#define print_graph_retval(_seq, _ent, _ret, _func, _opt_flags, _trace_flags, args_size) \
> + do {} while (0)
>
> #endif
>
> @@ -852,10 +897,14 @@ print_graph_entry_leaf(struct trace_iterator *iter,
> struct ftrace_graph_ret *graph_ret;
> struct ftrace_graph_ent *call;
> unsigned long long duration;
> + unsigned long ret_func;
> unsigned long func;
> + int args_size;
> int cpu = iter->cpu;
> int i;
>
> + args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args);
> +
> graph_ret = &ret_entry->ret;
> call = &entry->graph_ent;
> duration = ret_entry->rettime - ret_entry->calltime;
> @@ -887,16 +936,25 @@ print_graph_entry_leaf(struct trace_iterator *iter,
> for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)
> trace_seq_putc(s, ' ');
>
> + ret_func = graph_ret->func + iter->tr->text_delta;
> +
> /*
> * Write out the function return value or return address
> */
> if (flags & (__TRACE_GRAPH_PRINT_RETVAL | __TRACE_GRAPH_PRINT_RETADDR)) {
> print_graph_retval(s, entry, graph_ret,
> (void *)graph_ret->func + iter->tr->text_delta,
> - flags, tr->trace_flags);
> + flags, tr->trace_flags, args_size);
> } else {
> - trace_seq_printf(s, "%ps();\n", (void *)func);
> + trace_seq_printf(s, "%ps", (void *)ret_func);
> +
> + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) {
> + print_function_args(s, entry->args, ret_func);
> + trace_seq_putc(s, ';');
> + } else
> + trace_seq_puts(s, "();");
> }
> + trace_seq_printf(s, "\n");
>
> print_graph_irq(iter, graph_ret->func, TRACE_GRAPH_RET,
> cpu, iter->ent->pid, flags);
> @@ -913,6 +971,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
> struct fgraph_data *data = iter->private;
> struct trace_array *tr = iter->tr;
> unsigned long func;
> + int args_size;
> int i;
>
> if (data) {
> @@ -937,7 +996,17 @@ print_graph_entry_nested(struct trace_iterator *iter,
>
> func = call->func + iter->tr->text_delta;
>
> - trace_seq_printf(s, "%ps() {", (void *)func);
> + trace_seq_printf(s, "%ps", (void *)func);
> +
> + args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args);
> +
> + if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long))
> + print_function_args(s, entry->args, func);
> + else
> + trace_seq_puts(s, "()");
> +
> + trace_seq_puts(s, " {");
> +
> if (flags & __TRACE_GRAPH_PRINT_RETADDR &&
> entry->ent.type == TRACE_GRAPH_RETADDR_ENT)
> print_graph_retaddr(s, (struct fgraph_retaddr_ent_entry *)entry,
> @@ -1107,21 +1176,38 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
> struct trace_iterator *iter, u32 flags)
> {
> struct fgraph_data *data = iter->private;
> - struct ftrace_graph_ent *call = &field->graph_ent;
> + struct ftrace_graph_ent *call;
> struct ftrace_graph_ret_entry *leaf_ret;
> static enum print_line_t ret;
> int cpu = iter->cpu;
> + /*
> + * print_graph_entry() may consume the current event,
> + * thus @field may become invalid, so we need to save it.
> + * sizeof(struct ftrace_graph_ent_entry) is very small,
> + * it can be safely saved at the stack.
> + */
> + struct ftrace_graph_ent_entry *entry;
> + u8 save_buf[sizeof(*entry) + FTRACE_REGS_MAX_ARGS * sizeof(long)];
> +
> + /* The ent_size is expected to be as big as the entry */
> + if (iter->ent_size > sizeof(save_buf))
> + iter->ent_size = sizeof(save_buf);
> +
> + entry = (void *)save_buf;
> + memcpy(entry, field, iter->ent_size);
> +
> + call = &entry->graph_ent;
>
> if (check_irq_entry(iter, flags, call->func, call->depth))
> return TRACE_TYPE_HANDLED;
>
> print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags);
>
> - leaf_ret = get_return_for_leaf(iter, field);
> + leaf_ret = get_return_for_leaf(iter, entry);
> if (leaf_ret)
> - ret = print_graph_entry_leaf(iter, field, leaf_ret, s, flags);
> + ret = print_graph_entry_leaf(iter, entry, leaf_ret, s, flags);
> else
> - ret = print_graph_entry_nested(iter, field, s, cpu, flags);
> + ret = print_graph_entry_nested(iter, entry, s, cpu, flags);
>
> if (data) {
> /*
> @@ -1195,7 +1281,8 @@ print_graph_return(struct ftrace_graph_ret_entry *retentry, struct trace_seq *s,
> * funcgraph-retval option is enabled.
> */
> if (flags & __TRACE_GRAPH_PRINT_RETVAL) {
> - print_graph_retval(s, NULL, trace, (void *)func, flags, tr->trace_flags);
> + print_graph_retval(s, NULL, trace, (void *)func, flags,
> + tr->trace_flags, 0);
> } else {
> /*
> * If the return function does not have a matching entry,
> @@ -1323,16 +1410,8 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
>
> switch (entry->type) {
> case TRACE_GRAPH_ENT: {
> - /*
> - * print_graph_entry() may consume the current event,
> - * thus @field may become invalid, so we need to save it.
> - * sizeof(struct ftrace_graph_ent_entry) is very small,
> - * it can be safely saved at the stack.
> - */
> - struct ftrace_graph_ent_entry saved;
> trace_assign_type(field, entry);
> - saved = *field;
> - return print_graph_entry(&saved, s, iter, flags);
> + return print_graph_entry(field, s, iter, flags);
> }
> #ifdef CONFIG_FUNCTION_GRAPH_RETADDR
> case TRACE_GRAPH_RETADDR_ENT: {
> --
> 2.47.2
>
>
--
Masami Hiramatsu (Google) <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer
2025-02-26 14:48 ` Masami Hiramatsu
@ 2025-02-26 16:11 ` Steven Rostedt
0 siblings, 0 replies; 8+ messages in thread
From: Steven Rostedt @ 2025-02-26 16:11 UTC (permalink / raw)
To: Masami Hiramatsu (Google)
Cc: linux-kernel, linux-trace-kernel, Mark Rutland, Mathieu Desnoyers,
Andrew Morton, Sven Schnelle, Paul Walmsley, Palmer Dabbelt,
Albert Ou, Guo Ren, Donglin Peng, Zheng Yejian, bpf
On Wed, 26 Feb 2025 23:48:52 +0900
Masami Hiramatsu (Google) <mhiramat@kernel.org> wrote:
> > - event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_ENT,
> > - sizeof(*entry), trace_ctx);
> > + /* If fregs is defined, add FTRACE_REGS_MAX_ARGS long size words */
> > + size = sizeof(*entry) + (FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long));
>
> Is `!!fregs` always 1 if fregs != NULL? (seems to depend on compiler)
Yes, C guarantees that ! is either 1 or zero. If you want to convert
something from non zero to 1, the C convention is "!!".
>
> Others looks good to me.
>
> Reviewed-by: Masami Hiramatsu (Google) <mhiramat@kernel.org>
Thanks!
-- Steve
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-02-26 16:11 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-25 22:26 [PATCH v3 0/4] ftrace: Add function arguments to function tracers Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 1/4] ftrace: Add print_function_args() Steven Rostedt
2025-02-26 14:48 ` Masami Hiramatsu
2025-02-25 22:26 ` [PATCH v3 2/4] ftrace: Add support for function argument to graph tracer Steven Rostedt
2025-02-26 14:48 ` Masami Hiramatsu
2025-02-26 16:11 ` Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 3/4] ftrace: Have funcgraph-args take affect during tracing Steven Rostedt
2025-02-25 22:26 ` [PATCH v3 4/4] ftrace: Add arguments to function tracer Steven Rostedt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).