Skip to content

Commit 88cefd9

Browse files
committed
ftrace: Show subops in enabled_functions
The function graph infrastructure uses subops of the function tracer. These are not shown in enabled_functions. Add a "subops:" section to the enabled_functions line to show what functions are attached via subops. If the subops is from the function_graph infrastructure, then show the entry and return callbacks that are attached. Here's an example of the output: schedule_on_each_cpu (1) tramp: 0xffffffffc03ef000 (ftrace_graph_func+0x0/0x60) ->ftrace_graph_func+0x0/0x60 subops: {ent:trace_graph_entry+0x0/0x20 ret:trace_graph_return+0x0/0x150} Cc: Masami Hiramatsu <mhiramat@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Link: https://lore.kernel.org/20250410153830.5d97f108@gandalf.local.home Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
1 parent 54c53df commit 88cefd9

3 files changed

Lines changed: 42 additions & 0 deletions

File tree

include/linux/ftrace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
328328
* DIRECT - Used by the direct ftrace_ops helper for direct functions
329329
* (internal ftrace only, should not be used by others)
330330
* SUBOP - Is controlled by another op in field managed.
331+
* GRAPH - Is a component of the fgraph_ops structure
331332
*/
332333
enum {
333334
FTRACE_OPS_FL_ENABLED = BIT(0),
@@ -349,6 +350,7 @@ enum {
349350
FTRACE_OPS_FL_PERMANENT = BIT(16),
350351
FTRACE_OPS_FL_DIRECT = BIT(17),
351352
FTRACE_OPS_FL_SUBOP = BIT(18),
353+
FTRACE_OPS_FL_GRAPH = BIT(19),
352354
};
353355

354356
#ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS

kernel/trace/fgraph.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1382,6 +1382,8 @@ int register_ftrace_graph(struct fgraph_ops *gops)
13821382
/* Always save the function, and reset at unregistering */
13831383
gops->saved_func = gops->entryfunc;
13841384

1385+
gops->ops.flags |= FTRACE_OPS_FL_GRAPH;
1386+
13851387
ret = ftrace_startup_subops(&graph_ops, &gops->ops, command);
13861388
if (!ret)
13871389
fgraph_array[i] = gops;

kernel/trace/ftrace.c

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4373,6 +4373,42 @@ static inline int print_rec(struct seq_file *m, unsigned long ip)
43734373
}
43744374
#endif
43754375

4376+
static void print_subops(struct seq_file *m, struct ftrace_ops *ops, struct dyn_ftrace *rec)
4377+
{
4378+
struct ftrace_ops *subops;
4379+
bool first = true;
4380+
4381+
list_for_each_entry(subops, &ops->subop_list, list) {
4382+
if (!((subops->flags & FTRACE_OPS_FL_ENABLED) &&
4383+
hash_contains_ip(rec->ip, subops->func_hash)))
4384+
continue;
4385+
if (first) {
4386+
seq_printf(m, "\tsubops:");
4387+
first = false;
4388+
}
4389+
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
4390+
if (subops->flags & FTRACE_OPS_FL_GRAPH) {
4391+
struct fgraph_ops *gops;
4392+
4393+
gops = container_of(subops, struct fgraph_ops, ops);
4394+
seq_printf(m, " {ent:%pS ret:%pS}",
4395+
(void *)gops->entryfunc,
4396+
(void *)gops->retfunc);
4397+
continue;
4398+
}
4399+
#endif
4400+
if (subops->trampoline) {
4401+
seq_printf(m, " {%pS (%pS)}",
4402+
(void *)subops->trampoline,
4403+
(void *)subops->func);
4404+
add_trampoline_func(m, subops, rec);
4405+
} else {
4406+
seq_printf(m, " {%pS}",
4407+
(void *)subops->func);
4408+
}
4409+
}
4410+
}
4411+
43764412
static int t_show(struct seq_file *m, void *v)
43774413
{
43784414
struct ftrace_iterator *iter = m->private;
@@ -4425,6 +4461,7 @@ static int t_show(struct seq_file *m, void *v)
44254461
(void *)ops->trampoline,
44264462
(void *)ops->func);
44274463
add_trampoline_func(m, ops, rec);
4464+
print_subops(m, ops, rec);
44284465
ops = ftrace_find_tramp_ops_next(rec, ops);
44294466
} while (ops);
44304467
} else
@@ -4437,6 +4474,7 @@ static int t_show(struct seq_file *m, void *v)
44374474
if (ops) {
44384475
seq_printf(m, "\tops: %pS (%pS)",
44394476
ops, ops->func);
4477+
print_subops(m, ops, rec);
44404478
} else {
44414479
seq_puts(m, "\tops: ERROR!");
44424480
}

0 commit comments

Comments
 (0)