mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/
synced 2025-04-19 20:58:31 +09:00
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: 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>
This commit is contained in:
parent
c7a60a733c
commit
76fe0337c2
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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 */
|
||||
};
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user