Skip to content

Commit 31eb415

Browse files
committed
Merge tag 'ftrace-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace
Pull ftrace updates from Steven Rostedt: - Record function parameters for function and function graph tracers An option has been added to function tracer (func-args) and the function graph tracer (funcgraph-args) that when set, the tracers will record the registers that hold the arguments into each function event. On reading of the trace, it will use BTF to print those arguments. Most archs support up to 6 arguments (depending on the complexity of the arguments) and those are printed. If a function has more arguments then what was recorded, the output will end with " ... )". Example of function graph tracer: 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 | } - The rest of the changes are minor clean ups and fixes * tag 'ftrace-v6.15' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace: tracing: Use hashtable.h for event_hash tracing: Fix use-after-free in print_graph_function_flags during tracer switching function_graph: Remove the unused variable func ftrace: Add arguments to function tracer ftrace: Have funcgraph-args take affect during tracing ftrace: Add support for function argument to graph tracer ftrace: Add print_function_args() ftrace: Have ftrace_free_filter() WARN and exit if ops is active fgraph: Correct typo in ftrace_return_to_handler comment
2 parents dd161f7 + 391dda1 commit 31eb415

File tree

13 files changed

+351
-74
lines changed

13 files changed

+351
-74
lines changed

include/linux/ftrace_regs.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,9 @@ struct ftrace_regs;
3535

3636
#endif /* HAVE_ARCH_FTRACE_REGS */
3737

38+
/* This can be overridden by the architectures */
39+
#ifndef FTRACE_REGS_MAX_ARGS
40+
# define FTRACE_REGS_MAX_ARGS 6
41+
#endif
42+
3843
#endif /* _LINUX_FTRACE_REGS_H */

kernel/trace/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,18 @@ config FUNCTION_GRAPH_RETADDR
263263
the function is called. This feature is off by default, and you can
264264
enable it via the trace option funcgraph-retaddr.
265265

266+
config FUNCTION_TRACE_ARGS
267+
bool
268+
depends on HAVE_FUNCTION_ARG_ACCESS_API
269+
depends on DEBUG_INFO_BTF
270+
default y
271+
help
272+
If supported with function argument access API and BTF, then
273+
the function tracer and function graph tracer will support printing
274+
of function arguments. This feature is off by default, and can be
275+
enabled via the trace option func-args (for the function tracer) and
276+
funcgraph-args (for the function graph tracer)
277+
266278
config DYNAMIC_FTRACE
267279
bool "enable/disable function tracing dynamically"
268280
depends on FUNCTION_TRACER

kernel/trace/fgraph.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -865,7 +865,7 @@ __ftrace_return_to_handler(struct ftrace_regs *fregs, unsigned long frame_pointe
865865
}
866866

867867
/*
868-
* After all architecures have selected HAVE_FUNCTION_GRAPH_FREGS, we can
868+
* After all architectures have selected HAVE_FUNCTION_GRAPH_FREGS, we can
869869
* leave only ftrace_return_to_handler(fregs).
870870
*/
871871
#ifdef CONFIG_HAVE_FUNCTION_GRAPH_FREGS

kernel/trace/ftrace.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1293,6 +1293,8 @@ static void free_ftrace_hash_rcu(struct ftrace_hash *hash)
12931293
void ftrace_free_filter(struct ftrace_ops *ops)
12941294
{
12951295
ftrace_ops_init(ops);
1296+
if (WARN_ON(ops->flags & FTRACE_OPS_FL_ENABLED))
1297+
return;
12961298
free_ftrace_hash(ops->func_hash->filter_hash);
12971299
free_ftrace_hash(ops->func_hash->notrace_hash);
12981300
}

kernel/trace/trace.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2878,20 +2878,30 @@ trace_buffer_unlock_commit_nostack(struct trace_buffer *buffer,
28782878

28792879
void
28802880
trace_function(struct trace_array *tr, unsigned long ip, unsigned long
2881-
parent_ip, unsigned int trace_ctx)
2881+
parent_ip, unsigned int trace_ctx, struct ftrace_regs *fregs)
28822882
{
28832883
struct trace_buffer *buffer = tr->array_buffer.buffer;
28842884
struct ring_buffer_event *event;
28852885
struct ftrace_entry *entry;
2886+
int size = sizeof(*entry);
28862887

2887-
event = __trace_buffer_lock_reserve(buffer, TRACE_FN, sizeof(*entry),
2888+
size += FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long);
2889+
2890+
event = __trace_buffer_lock_reserve(buffer, TRACE_FN, size,
28882891
trace_ctx);
28892892
if (!event)
28902893
return;
28912894
entry = ring_buffer_event_data(event);
28922895
entry->ip = ip;
28932896
entry->parent_ip = parent_ip;
28942897

2898+
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
2899+
if (fregs) {
2900+
for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++)
2901+
entry->args[i] = ftrace_regs_get_argument(fregs, i);
2902+
}
2903+
#endif
2904+
28952905
if (static_branch_unlikely(&trace_function_exports_enabled))
28962906
ftrace_exports(event, TRACE_EXPORT_FUNCTION);
28972907
__buffer_unlock_commit(buffer, event);

kernel/trace/trace.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/workqueue.h>
2222
#include <linux/ctype.h>
2323
#include <linux/once_lite.h>
24+
#include <linux/ftrace_regs.h>
2425

2526
#include "pid_list.h"
2627

@@ -697,7 +698,8 @@ unsigned long trace_total_entries(struct trace_array *tr);
697698
void trace_function(struct trace_array *tr,
698699
unsigned long ip,
699700
unsigned long parent_ip,
700-
unsigned int trace_ctx);
701+
unsigned int trace_ctx,
702+
struct ftrace_regs *regs);
701703
void trace_graph_function(struct trace_array *tr,
702704
unsigned long ip,
703705
unsigned long parent_ip,
@@ -897,6 +899,7 @@ static __always_inline bool ftrace_hash_empty(struct ftrace_hash *hash)
897899
#define TRACE_GRAPH_PRINT_RETVAL 0x800
898900
#define TRACE_GRAPH_PRINT_RETVAL_HEX 0x1000
899901
#define TRACE_GRAPH_PRINT_RETADDR 0x2000
902+
#define TRACE_GRAPH_ARGS 0x4000
900903
#define TRACE_GRAPH_PRINT_FILL_SHIFT 28
901904
#define TRACE_GRAPH_PRINT_FILL_MASK (0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)
902905

kernel/trace/trace_entries.h

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
6161
TRACE_FN,
6262

6363
F_STRUCT(
64-
__field_fn( unsigned long, ip )
65-
__field_fn( unsigned long, parent_ip )
64+
__field_fn( unsigned long, ip )
65+
__field_fn( unsigned long, parent_ip )
66+
__dynamic_array( unsigned long, args )
6667
),
6768

6869
F_printk(" %ps <-- %ps",
@@ -72,17 +73,18 @@ FTRACE_ENTRY_REG(function, ftrace_entry,
7273
);
7374

7475
/* Function call entry */
75-
FTRACE_ENTRY_PACKED(funcgraph_entry, ftrace_graph_ent_entry,
76+
FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
7677

7778
TRACE_GRAPH_ENT,
7879

7980
F_STRUCT(
8081
__field_struct( struct ftrace_graph_ent, graph_ent )
8182
__field_packed( unsigned long, graph_ent, func )
82-
__field_packed( int, graph_ent, depth )
83+
__field_packed( unsigned long, graph_ent, depth )
84+
__dynamic_array(unsigned long, args )
8385
),
8486

85-
F_printk("--> %ps (%d)", (void *)__entry->func, __entry->depth)
87+
F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth)
8688
);
8789

8890
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR

kernel/trace/trace_functions.c

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ static void
2525
function_trace_call(unsigned long ip, unsigned long parent_ip,
2626
struct ftrace_ops *op, struct ftrace_regs *fregs);
2727
static void
28+
function_args_trace_call(unsigned long ip, unsigned long parent_ip,
29+
struct ftrace_ops *op, struct ftrace_regs *fregs);
30+
static void
2831
function_stack_trace_call(unsigned long ip, unsigned long parent_ip,
2932
struct ftrace_ops *op, struct ftrace_regs *fregs);
3033
static void
@@ -42,9 +45,10 @@ enum {
4245
TRACE_FUNC_NO_OPTS = 0x0, /* No flags set. */
4346
TRACE_FUNC_OPT_STACK = 0x1,
4447
TRACE_FUNC_OPT_NO_REPEATS = 0x2,
48+
TRACE_FUNC_OPT_ARGS = 0x4,
4549

4650
/* Update this to next highest bit. */
47-
TRACE_FUNC_OPT_HIGHEST_BIT = 0x4
51+
TRACE_FUNC_OPT_HIGHEST_BIT = 0x8
4852
};
4953

5054
#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)
114118
switch (flags_val & TRACE_FUNC_OPT_MASK) {
115119
case TRACE_FUNC_NO_OPTS:
116120
return function_trace_call;
121+
case TRACE_FUNC_OPT_ARGS:
122+
return function_args_trace_call;
117123
case TRACE_FUNC_OPT_STACK:
118124
return function_stack_trace_call;
119125
case TRACE_FUNC_OPT_NO_REPEATS:
@@ -220,7 +226,34 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,
220226

221227
data = this_cpu_ptr(tr->array_buffer.data);
222228
if (!atomic_read(&data->disabled))
223-
trace_function(tr, ip, parent_ip, trace_ctx);
229+
trace_function(tr, ip, parent_ip, trace_ctx, NULL);
230+
231+
ftrace_test_recursion_unlock(bit);
232+
}
233+
234+
static void
235+
function_args_trace_call(unsigned long ip, unsigned long parent_ip,
236+
struct ftrace_ops *op, struct ftrace_regs *fregs)
237+
{
238+
struct trace_array *tr = op->private;
239+
struct trace_array_cpu *data;
240+
unsigned int trace_ctx;
241+
int bit;
242+
int cpu;
243+
244+
if (unlikely(!tr->function_enabled))
245+
return;
246+
247+
bit = ftrace_test_recursion_trylock(ip, parent_ip);
248+
if (bit < 0)
249+
return;
250+
251+
trace_ctx = tracing_gen_ctx();
252+
253+
cpu = smp_processor_id();
254+
data = per_cpu_ptr(tr->array_buffer.data, cpu);
255+
if (!atomic_read(&data->disabled))
256+
trace_function(tr, ip, parent_ip, trace_ctx, fregs);
224257

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

271304
if (likely(disabled == 1)) {
272305
trace_ctx = tracing_gen_ctx_flags(flags);
273-
trace_function(tr, ip, parent_ip, trace_ctx);
306+
trace_function(tr, ip, parent_ip, trace_ctx, NULL);
274307
#ifdef CONFIG_UNWINDER_FRAME_POINTER
275308
if (ftrace_pids_enabled(op))
276309
skip++;
@@ -349,7 +382,7 @@ function_no_repeats_trace_call(unsigned long ip, unsigned long parent_ip,
349382
trace_ctx = tracing_gen_ctx_dec();
350383
process_repeats(tr, ip, parent_ip, last_info, trace_ctx);
351384

352-
trace_function(tr, ip, parent_ip, trace_ctx);
385+
trace_function(tr, ip, parent_ip, trace_ctx, NULL);
353386

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

392-
trace_function(tr, ip, parent_ip, trace_ctx);
425+
trace_function(tr, ip, parent_ip, trace_ctx, NULL);
393426
__trace_stack(tr, trace_ctx, STACK_SKIP);
394427
}
395428

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

0 commit comments

Comments
 (0)