Skip to content

Commit f83ac75

Browse files
pengdonglinrostedt
authored andcommitted
function_graph: Enable funcgraph-args and funcgraph-retaddr to work simultaneously
Currently, the funcgraph-args and funcgraph-retaddr features are mutually exclusive. This patch resolves this limitation by allowing funcgraph-retaddr to have an args array. To verify the change, use perf to trace vfs_write with both options enabled: Before: # perf ftrace -G vfs_write --graph-opts args,retaddr ...... down_read() { /* <-n_tty_write+0xa3/0x540 */ __cond_resched(); /* <-down_read+0x12/0x160 */ preempt_count_add(); /* <-down_read+0x3b/0x160 */ preempt_count_sub(); /* <-down_read+0x8b/0x160 */ } After: # perf ftrace -G vfs_write --graph-opts args,retaddr ...... down_read(sem=0xffff8880100bea78) { /* <-n_tty_write+0xa3/0x540 */ __cond_resched(); /* <-down_read+0x12/0x160 */ preempt_count_add(val=1); /* <-down_read+0x3b/0x160 */ preempt_count_sub(val=1); /* <-down_read+0x8b/0x160 */ } Cc: Steven Rostedt (Google) <rostedt@goodmis.org> Cc: Sven Schnelle <svens@linux.ibm.com> Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Xiaoqin Zhang <zhangxiaoqin@xiaomi.com> Link: https://patch.msgid.link/20251125093425.2563849-1-dolinux.peng@gmail.com Signed-off-by: pengdonglin <pengdonglin@xiaomi.com> Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 20e7168 commit f83ac75

4 files changed

Lines changed: 80 additions & 37 deletions

File tree

include/linux/ftrace.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,17 +1126,14 @@ static inline void ftrace_init(void) { }
11261126
*/
11271127
struct ftrace_graph_ent {
11281128
unsigned long func; /* Current function */
1129-
int depth;
1129+
unsigned long depth;
11301130
} __packed;
11311131

11321132
/*
11331133
* Structure that defines an entry function trace with retaddr.
1134-
* It's already packed but the attribute "packed" is needed
1135-
* to remove extra padding at the end.
11361134
*/
11371135
struct fgraph_retaddr_ent {
1138-
unsigned long func; /* Current function */
1139-
int depth;
1136+
struct ftrace_graph_ent ent;
11401137
unsigned long retaddr; /* Return address */
11411138
} __packed;
11421139

kernel/trace/trace.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,8 @@ extern int __trace_graph_entry(struct trace_array *tr,
964964
extern int __trace_graph_retaddr_entry(struct trace_array *tr,
965965
struct ftrace_graph_ent *trace,
966966
unsigned int trace_ctx,
967-
unsigned long retaddr);
967+
unsigned long retaddr,
968+
struct ftrace_regs *fregs);
968969
extern void __trace_graph_return(struct trace_array *tr,
969970
struct ftrace_graph_ret *trace,
970971
unsigned int trace_ctx,
@@ -2276,4 +2277,25 @@ static inline int rv_init_interface(void)
22762277
*/
22772278
#define FTRACE_TRAMPOLINE_MARKER ((unsigned long) INT_MAX)
22782279

2280+
/*
2281+
* This is used to get the address of the args array based on
2282+
* the type of the entry.
2283+
*/
2284+
#define FGRAPH_ENTRY_ARGS(e) \
2285+
({ \
2286+
unsigned long *_args; \
2287+
struct ftrace_graph_ent_entry *_e = e; \
2288+
\
2289+
if (IS_ENABLED(CONFIG_FUNCTION_GRAPH_RETADDR) && \
2290+
e->ent.type == TRACE_GRAPH_RETADDR_ENT) { \
2291+
struct fgraph_retaddr_ent_entry *_re; \
2292+
\
2293+
_re = (typeof(_re))_e; \
2294+
_args = _re->args; \
2295+
} else { \
2296+
_args = _e->args; \
2297+
} \
2298+
_args; \
2299+
})
2300+
22792301
#endif /* _LINUX_KERNEL_TRACE_H */

kernel/trace/trace_entries.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ FTRACE_ENTRY(funcgraph_entry, ftrace_graph_ent_entry,
8080
F_STRUCT(
8181
__field_struct( struct ftrace_graph_ent, graph_ent )
8282
__field_packed( unsigned long, graph_ent, func )
83-
__field_packed( unsigned int, graph_ent, depth )
83+
__field_packed( unsigned long, graph_ent, depth )
8484
__dynamic_array(unsigned long, args )
8585
),
8686

87-
F_printk("--> %ps (%u)", (void *)__entry->func, __entry->depth)
87+
F_printk("--> %ps (%lu)", (void *)__entry->func, __entry->depth)
8888
);
8989

9090
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
@@ -95,13 +95,14 @@ FTRACE_ENTRY_PACKED(fgraph_retaddr_entry, fgraph_retaddr_ent_entry,
9595
TRACE_GRAPH_RETADDR_ENT,
9696

9797
F_STRUCT(
98-
__field_struct( struct fgraph_retaddr_ent, graph_ent )
99-
__field_packed( unsigned long, graph_ent, func )
100-
__field_packed( unsigned int, graph_ent, depth )
101-
__field_packed( unsigned long, graph_ent, retaddr )
98+
__field_struct( struct fgraph_retaddr_ent, graph_rent )
99+
__field_packed( unsigned long, graph_rent.ent, func )
100+
__field_packed( unsigned long, graph_rent.ent, depth )
101+
__field_packed( unsigned long, graph_rent, retaddr )
102+
__dynamic_array(unsigned long, args )
102103
),
103104

104-
F_printk("--> %ps (%u) <- %ps", (void *)__entry->func, __entry->depth,
105+
F_printk("--> %ps (%lu) <- %ps", (void *)__entry->func, __entry->depth,
105106
(void *)__entry->retaddr)
106107
);
107108

kernel/trace/trace_functions_graph.c

Lines changed: 47 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,19 @@ struct fgraph_ent_args {
3636
unsigned long args[FTRACE_REGS_MAX_ARGS];
3737
};
3838

39+
struct fgraph_retaddr_ent_args {
40+
struct fgraph_retaddr_ent_entry ent;
41+
/* Force the sizeof of args[] to have FTRACE_REGS_MAX_ARGS entries */
42+
unsigned long args[FTRACE_REGS_MAX_ARGS];
43+
};
44+
3945
struct fgraph_data {
4046
struct fgraph_cpu_data __percpu *cpu_data;
4147

4248
/* Place to preserve last processed entry. */
4349
union {
4450
struct fgraph_ent_args ent;
45-
/* TODO allow retaddr to have args */
46-
struct fgraph_retaddr_ent_entry rent;
51+
struct fgraph_retaddr_ent_args rent;
4752
};
4853
struct ftrace_graph_ret_entry ret;
4954
int failed;
@@ -160,20 +165,32 @@ int __trace_graph_entry(struct trace_array *tr,
160165
int __trace_graph_retaddr_entry(struct trace_array *tr,
161166
struct ftrace_graph_ent *trace,
162167
unsigned int trace_ctx,
163-
unsigned long retaddr)
168+
unsigned long retaddr,
169+
struct ftrace_regs *fregs)
164170
{
165171
struct ring_buffer_event *event;
166172
struct trace_buffer *buffer = tr->array_buffer.buffer;
167173
struct fgraph_retaddr_ent_entry *entry;
174+
int size;
175+
176+
/* If fregs is defined, add FTRACE_REGS_MAX_ARGS long size words */
177+
size = sizeof(*entry) + (FTRACE_REGS_MAX_ARGS * !!fregs * sizeof(long));
168178

169179
event = trace_buffer_lock_reserve(buffer, TRACE_GRAPH_RETADDR_ENT,
170-
sizeof(*entry), trace_ctx);
180+
size, trace_ctx);
171181
if (!event)
172182
return 0;
173183
entry = ring_buffer_event_data(event);
174-
entry->graph_ent.func = trace->func;
175-
entry->graph_ent.depth = trace->depth;
176-
entry->graph_ent.retaddr = retaddr;
184+
entry->graph_rent.ent = *trace;
185+
entry->graph_rent.retaddr = retaddr;
186+
187+
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API
188+
if (fregs) {
189+
for (int i = 0; i < FTRACE_REGS_MAX_ARGS; i++)
190+
entry->args[i] = ftrace_regs_get_argument(fregs, i);
191+
}
192+
#endif
193+
177194
trace_buffer_unlock_commit_nostack(buffer, event);
178195

179196
return 1;
@@ -182,7 +199,8 @@ int __trace_graph_retaddr_entry(struct trace_array *tr,
182199
int __trace_graph_retaddr_entry(struct trace_array *tr,
183200
struct ftrace_graph_ent *trace,
184201
unsigned int trace_ctx,
185-
unsigned long retaddr)
202+
unsigned long retaddr,
203+
struct ftrace_regs *fregs)
186204
{
187205
return 1;
188206
}
@@ -267,7 +285,8 @@ static int graph_entry(struct ftrace_graph_ent *trace,
267285
if (IS_ENABLED(CONFIG_FUNCTION_GRAPH_RETADDR) &&
268286
tracer_flags_is_set(tr, TRACE_GRAPH_PRINT_RETADDR)) {
269287
unsigned long retaddr = ftrace_graph_top_ret_addr(current);
270-
ret = __trace_graph_retaddr_entry(tr, trace, trace_ctx, retaddr);
288+
ret = __trace_graph_retaddr_entry(tr, trace, trace_ctx,
289+
retaddr, fregs);
271290
} else {
272291
ret = __graph_entry(tr, trace, trace_ctx, fregs);
273292
}
@@ -654,13 +673,9 @@ get_return_for_leaf(struct trace_iterator *iter,
654673
* Save current and next entries for later reference
655674
* if the output fails.
656675
*/
657-
if (unlikely(curr->ent.type == TRACE_GRAPH_RETADDR_ENT)) {
658-
data->rent = *(struct fgraph_retaddr_ent_entry *)curr;
659-
} else {
660-
int size = min((int)sizeof(data->ent), (int)iter->ent_size);
676+
int size = min_t(int, sizeof(data->rent), iter->ent_size);
661677

662-
memcpy(&data->ent, curr, size);
663-
}
678+
memcpy(&data->rent, curr, size);
664679
/*
665680
* If the next event is not a return type, then
666681
* we only care about what type it is. Otherwise we can
@@ -838,7 +853,7 @@ static void print_graph_retaddr(struct trace_seq *s, struct fgraph_retaddr_ent_e
838853
trace_seq_puts(s, " /*");
839854

840855
trace_seq_puts(s, " <-");
841-
seq_print_ip_sym_offset(s, entry->graph_ent.retaddr, trace_flags);
856+
seq_print_ip_sym_offset(s, entry->graph_rent.retaddr, trace_flags);
842857

843858
if (comment)
844859
trace_seq_puts(s, " */");
@@ -984,7 +999,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
984999
trace_seq_printf(s, "%ps", (void *)ret_func);
9851000

9861001
if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long)) {
987-
print_function_args(s, entry->args, ret_func);
1002+
print_function_args(s, FGRAPH_ENTRY_ARGS(entry), ret_func);
9881003
trace_seq_putc(s, ';');
9891004
} else
9901005
trace_seq_puts(s, "();");
@@ -1036,7 +1051,7 @@ print_graph_entry_nested(struct trace_iterator *iter,
10361051
args_size = iter->ent_size - offsetof(struct ftrace_graph_ent_entry, args);
10371052

10381053
if (args_size >= FTRACE_REGS_MAX_ARGS * sizeof(long))
1039-
print_function_args(s, entry->args, func);
1054+
print_function_args(s, FGRAPH_ENTRY_ARGS(entry), func);
10401055
else
10411056
trace_seq_puts(s, "()");
10421057

@@ -1218,11 +1233,14 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
12181233
/*
12191234
* print_graph_entry() may consume the current event,
12201235
* thus @field may become invalid, so we need to save it.
1221-
* sizeof(struct ftrace_graph_ent_entry) is very small,
1222-
* it can be safely saved at the stack.
1236+
* This function is shared by ftrace_graph_ent_entry and
1237+
* fgraph_retaddr_ent_entry, the size of the latter one
1238+
* is larger, but it is very small and can be safely saved
1239+
* at the stack.
12231240
*/
12241241
struct ftrace_graph_ent_entry *entry;
1225-
u8 save_buf[sizeof(*entry) + FTRACE_REGS_MAX_ARGS * sizeof(long)];
1242+
struct fgraph_retaddr_ent_entry *rentry;
1243+
u8 save_buf[sizeof(*rentry) + FTRACE_REGS_MAX_ARGS * sizeof(long)];
12261244

12271245
/* The ent_size is expected to be as big as the entry */
12281246
if (iter->ent_size > sizeof(save_buf))
@@ -1451,12 +1469,17 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags)
14511469
}
14521470
#ifdef CONFIG_FUNCTION_GRAPH_RETADDR
14531471
case TRACE_GRAPH_RETADDR_ENT: {
1454-
struct fgraph_retaddr_ent_entry saved;
1472+
/*
1473+
* ftrace_graph_ent_entry and fgraph_retaddr_ent_entry have
1474+
* similar functions and memory layouts. The only difference
1475+
* is that the latter one has an extra retaddr member, so
1476+
* they can share most of the logic.
1477+
*/
14551478
struct fgraph_retaddr_ent_entry *rfield;
14561479

14571480
trace_assign_type(rfield, entry);
1458-
saved = *rfield;
1459-
return print_graph_entry((struct ftrace_graph_ent_entry *)&saved, s, iter, flags);
1481+
return print_graph_entry((struct ftrace_graph_ent_entry *)rfield,
1482+
s, iter, flags);
14601483
}
14611484
#endif
14621485
case TRACE_GRAPH_RET: {

0 commit comments

Comments
 (0)