Skip to content

Commit 41705c4

Browse files
mhiramatrostedt
authored andcommitted
fgraph: Pass ftrace_regs to entryfunc
Pass ftrace_regs to the fgraph_ops::entryfunc(). If ftrace_regs is not available, it passes a NULL instead. User callback function can access some registers (including return address) via this ftrace_regs. Note that the ftrace_regs can be NULL when the arch does NOT define: HAVE_DYNAMIC_FTRACE_WITH_ARGS or HAVE_DYNAMIC_FTRACE_WITH_REGS. More specifically, if HAVE_DYNAMIC_FTRACE_WITH_REGS is defined but not the HAVE_DYNAMIC_FTRACE_WITH_ARGS, and the ftrace ops used to register the function callback does not set FTRACE_OPS_FL_SAVE_REGS. In this case, ftrace_regs can be NULL in user callback. Signed-off-by: Masami Hiramatsu (Google) <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Florent Revest <[email protected]> Cc: Martin KaFai Lau <[email protected]> Cc: bpf <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Alan Maguire <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Will Deacon <[email protected]> Cc: Huacai Chen <[email protected]> Cc: WANG Xuerui <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Nicholas Piggin <[email protected]> Cc: Christophe Leroy <[email protected]> Cc: Naveen N Rao <[email protected]> Cc: Madhavan Srinivasan <[email protected]> Cc: Paul Walmsley <[email protected]> Cc: Palmer Dabbelt <[email protected]> Cc: Albert Ou <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Dave Hansen <[email protected]> Cc: [email protected] Cc: "H. Peter Anvin" <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Link: https://lore.kernel.org/173518990044.391279.17406984900626078579.stgit@devnote2 Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent d576aec commit 41705c4

File tree

14 files changed

+114
-42
lines changed

14 files changed

+114
-42
lines changed

arch/arm64/kernel/ftrace.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,20 @@ void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
481481
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
482482
struct ftrace_ops *op, struct ftrace_regs *fregs)
483483
{
484-
prepare_ftrace_return(ip, &arch_ftrace_regs(fregs)->lr, arch_ftrace_regs(fregs)->fp);
484+
unsigned long return_hooker = (unsigned long)&return_to_handler;
485+
unsigned long frame_pointer = arch_ftrace_regs(fregs)->fp;
486+
unsigned long *parent = &arch_ftrace_regs(fregs)->lr;
487+
unsigned long old;
488+
489+
if (unlikely(atomic_read(&current->tracing_graph_pause)))
490+
return;
491+
492+
old = *parent;
493+
494+
if (!function_graph_enter_regs(old, ip, frame_pointer,
495+
(void *)frame_pointer, fregs)) {
496+
*parent = return_hooker;
497+
}
485498
}
486499
#else
487500
/*

arch/loongarch/kernel/ftrace_dyn.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,8 +243,16 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
243243
{
244244
struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs;
245245
unsigned long *parent = (unsigned long *)&regs->regs[1];
246+
unsigned long return_hooker = (unsigned long)&return_to_handler;
247+
unsigned long old;
248+
249+
if (unlikely(atomic_read(&current->tracing_graph_pause)))
250+
return;
251+
252+
old = *parent;
246253

247-
prepare_ftrace_return(ip, (unsigned long *)parent);
254+
if (!function_graph_enter_regs(old, ip, 0, parent, fregs))
255+
*parent = return_hooker;
248256
}
249257
#else
250258
static int ftrace_modify_graph_caller(bool enable)

arch/powerpc/kernel/trace/ftrace.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,7 +665,7 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
665665
if (unlikely(atomic_read(&current->tracing_graph_pause)))
666666
goto out;
667667

668-
if (!function_graph_enter(parent_ip, ip, 0, (unsigned long *)sp))
668+
if (!function_graph_enter_regs(parent_ip, ip, 0, (unsigned long *)sp, fregs))
669669
parent_ip = ppc_function_entry(return_to_handler);
670670

671671
out:

arch/powerpc/kernel/trace/ftrace_64_pg.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -787,7 +787,8 @@ int ftrace_disable_ftrace_graph_caller(void)
787787
* in current thread info. Return the address we want to divert to.
788788
*/
789789
static unsigned long
790-
__prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp)
790+
__prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp,
791+
struct ftrace_regs *fregs)
791792
{
792793
unsigned long return_hooker;
793794

@@ -799,7 +800,7 @@ __prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp
799800

800801
return_hooker = ppc_function_entry(return_to_handler);
801802

802-
if (!function_graph_enter(parent, ip, 0, (unsigned long *)sp))
803+
if (!function_graph_enter_regs(parent, ip, 0, (unsigned long *)sp, fregs))
803804
parent = return_hooker;
804805

805806
out:
@@ -810,13 +811,14 @@ __prepare_ftrace_return(unsigned long parent, unsigned long ip, unsigned long sp
810811
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
811812
struct ftrace_ops *op, struct ftrace_regs *fregs)
812813
{
813-
arch_ftrace_regs(fregs)->regs.link = __prepare_ftrace_return(parent_ip, ip, arch_ftrace_regs(fregs)->regs.gpr[1]);
814+
arch_ftrace_regs(fregs)->regs.link = __prepare_ftrace_return(parent_ip, ip,
815+
arch_ftrace_regs(fregs)->regs.gpr[1], fregs);
814816
}
815817
#else
816818
unsigned long prepare_ftrace_return(unsigned long parent, unsigned long ip,
817819
unsigned long sp)
818820
{
819-
return __prepare_ftrace_return(parent, ip, sp);
821+
return __prepare_ftrace_return(parent, ip, sp, NULL);
820822
}
821823
#endif
822824
#endif /* CONFIG_FUNCTION_GRAPH_TRACER */

arch/riscv/kernel/ftrace.c

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,22 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
214214
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
215215
struct ftrace_ops *op, struct ftrace_regs *fregs)
216216
{
217-
prepare_ftrace_return(&arch_ftrace_regs(fregs)->ra, ip, arch_ftrace_regs(fregs)->s0);
217+
unsigned long return_hooker = (unsigned long)&return_to_handler;
218+
unsigned long frame_pointer = arch_ftrace_regs(fregs)->s0;
219+
unsigned long *parent = &arch_ftrace_regs(fregs)->ra;
220+
unsigned long old;
221+
222+
if (unlikely(atomic_read(&current->tracing_graph_pause)))
223+
return;
224+
225+
/*
226+
* We don't suffer access faults, so no extra fault-recovery assembly
227+
* is needed here.
228+
*/
229+
old = *parent;
230+
231+
if (!function_graph_enter_regs(old, ip, frame_pointer, parent, fregs))
232+
*parent = return_hooker;
218233
}
219234
#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
220235
extern void ftrace_graph_call(void);

arch/x86/kernel/ftrace.c

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -607,15 +607,8 @@ int ftrace_disable_ftrace_graph_caller(void)
607607
}
608608
#endif /* CONFIG_DYNAMIC_FTRACE && !CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */
609609

610-
/*
611-
* Hook the return address and push it in the stack of return addrs
612-
* in current thread info.
613-
*/
614-
void prepare_ftrace_return(unsigned long ip, unsigned long *parent,
615-
unsigned long frame_pointer)
610+
static inline bool skip_ftrace_return(void)
616611
{
617-
unsigned long return_hooker = (unsigned long)&return_to_handler;
618-
619612
/*
620613
* When resuming from suspend-to-ram, this function can be indirectly
621614
* called from early CPU startup code while the CPU is in real mode,
@@ -625,13 +618,27 @@ void prepare_ftrace_return(unsigned long ip, unsigned long *parent,
625618
* This check isn't as accurate as virt_addr_valid(), but it should be
626619
* good enough for this purpose, and it's fast.
627620
*/
628-
if (unlikely((long)__builtin_frame_address(0) >= 0))
629-
return;
621+
if ((long)__builtin_frame_address(0) >= 0)
622+
return true;
630623

631-
if (unlikely(ftrace_graph_is_dead()))
632-
return;
624+
if (ftrace_graph_is_dead())
625+
return true;
626+
627+
if (atomic_read(&current->tracing_graph_pause))
628+
return true;
629+
return false;
630+
}
631+
632+
/*
633+
* Hook the return address and push it in the stack of return addrs
634+
* in current thread info.
635+
*/
636+
void prepare_ftrace_return(unsigned long ip, unsigned long *parent,
637+
unsigned long frame_pointer)
638+
{
639+
unsigned long return_hooker = (unsigned long)&return_to_handler;
633640

634-
if (unlikely(atomic_read(&current->tracing_graph_pause)))
641+
if (unlikely(skip_ftrace_return()))
635642
return;
636643

637644
if (!function_graph_enter(*parent, ip, frame_pointer, parent))
@@ -644,8 +651,15 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
644651
{
645652
struct pt_regs *regs = &arch_ftrace_regs(fregs)->regs;
646653
unsigned long *stack = (unsigned long *)kernel_stack_pointer(regs);
654+
unsigned long return_hooker = (unsigned long)&return_to_handler;
655+
unsigned long *parent = (unsigned long *)stack;
656+
657+
if (unlikely(skip_ftrace_return()))
658+
return;
659+
647660

648-
prepare_ftrace_return(ip, (unsigned long *)stack, 0);
661+
if (!function_graph_enter_regs(*parent, ip, 0, parent, fregs))
662+
*parent = return_hooker;
649663
}
650664
#endif
651665

include/linux/ftrace.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,10 +1071,12 @@ struct fgraph_ops;
10711071
typedef void (*trace_func_graph_ret_t)(struct ftrace_graph_ret *,
10721072
struct fgraph_ops *); /* return */
10731073
typedef int (*trace_func_graph_ent_t)(struct ftrace_graph_ent *,
1074-
struct fgraph_ops *); /* entry */
1074+
struct fgraph_ops *,
1075+
struct ftrace_regs *); /* entry */
10751076

10761077
extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace,
1077-
struct fgraph_ops *gops);
1078+
struct fgraph_ops *gops,
1079+
struct ftrace_regs *fregs);
10781080
bool ftrace_pids_enabled(struct ftrace_ops *ops);
10791081

10801082
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -1114,8 +1116,15 @@ struct ftrace_ret_stack {
11141116
extern void return_to_handler(void);
11151117

11161118
extern int
1117-
function_graph_enter(unsigned long ret, unsigned long func,
1118-
unsigned long frame_pointer, unsigned long *retp);
1119+
function_graph_enter_regs(unsigned long ret, unsigned long func,
1120+
unsigned long frame_pointer, unsigned long *retp,
1121+
struct ftrace_regs *fregs);
1122+
1123+
static inline int function_graph_enter(unsigned long ret, unsigned long func,
1124+
unsigned long fp, unsigned long *retp)
1125+
{
1126+
return function_graph_enter_regs(ret, func, fp, retp, NULL);
1127+
}
11191128

11201129
struct ftrace_ret_stack *
11211130
ftrace_graph_get_ret_stack(struct task_struct *task, int skip);

kernel/trace/fgraph.c

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,8 @@ static inline unsigned long make_data_type_val(int idx, int size, int offset)
292292
}
293293

294294
/* ftrace_graph_entry set to this to tell some archs to run function graph */
295-
static int entry_run(struct ftrace_graph_ent *trace, struct fgraph_ops *ops)
295+
static int entry_run(struct ftrace_graph_ent *trace, struct fgraph_ops *ops,
296+
struct ftrace_regs *fregs)
296297
{
297298
return 0;
298299
}
@@ -520,7 +521,8 @@ int __weak ftrace_disable_ftrace_graph_caller(void)
520521
#endif
521522

522523
int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace,
523-
struct fgraph_ops *gops)
524+
struct fgraph_ops *gops,
525+
struct ftrace_regs *fregs)
524526
{
525527
return 0;
526528
}
@@ -644,8 +646,9 @@ ftrace_push_return_trace(unsigned long ret, unsigned long func,
644646
#endif
645647

646648
/* If the caller does not use ftrace, call this function. */
647-
int function_graph_enter(unsigned long ret, unsigned long func,
648-
unsigned long frame_pointer, unsigned long *retp)
649+
int function_graph_enter_regs(unsigned long ret, unsigned long func,
650+
unsigned long frame_pointer, unsigned long *retp,
651+
struct ftrace_regs *fregs)
649652
{
650653
struct ftrace_graph_ent trace;
651654
unsigned long bitmap = 0;
@@ -668,7 +671,7 @@ int function_graph_enter(unsigned long ret, unsigned long func,
668671
if (static_branch_likely(&fgraph_do_direct)) {
669672
int save_curr_ret_stack = current->curr_ret_stack;
670673

671-
if (static_call(fgraph_func)(&trace, fgraph_direct_gops))
674+
if (static_call(fgraph_func)(&trace, fgraph_direct_gops, fregs))
672675
bitmap |= BIT(fgraph_direct_gops->idx);
673676
else
674677
/* Clear out any saved storage */
@@ -686,7 +689,7 @@ int function_graph_enter(unsigned long ret, unsigned long func,
686689

687690
save_curr_ret_stack = current->curr_ret_stack;
688691
if (ftrace_ops_test(&gops->ops, func, NULL) &&
689-
gops->entryfunc(&trace, gops))
692+
gops->entryfunc(&trace, gops, fregs))
690693
bitmap |= BIT(i);
691694
else
692695
/* Clear out any saved storage */
@@ -1180,7 +1183,8 @@ void ftrace_graph_exit_task(struct task_struct *t)
11801183

11811184
#ifdef CONFIG_DYNAMIC_FTRACE
11821185
static int fgraph_pid_func(struct ftrace_graph_ent *trace,
1183-
struct fgraph_ops *gops)
1186+
struct fgraph_ops *gops,
1187+
struct ftrace_regs *fregs)
11841188
{
11851189
struct trace_array *tr = gops->ops.private;
11861190
int pid;
@@ -1194,7 +1198,7 @@ static int fgraph_pid_func(struct ftrace_graph_ent *trace,
11941198
return 0;
11951199
}
11961200

1197-
return gops->saved_func(trace, gops);
1201+
return gops->saved_func(trace, gops, fregs);
11981202
}
11991203

12001204
void fgraph_update_pid_func(void)

kernel/trace/ftrace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -819,7 +819,8 @@ struct profile_fgraph_data {
819819
};
820820

821821
static int profile_graph_entry(struct ftrace_graph_ent *trace,
822-
struct fgraph_ops *gops)
822+
struct fgraph_ops *gops,
823+
struct ftrace_regs *fregs)
823824
{
824825
struct profile_fgraph_data *profile_data;
825826

kernel/trace/trace.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -694,7 +694,8 @@ void trace_default_header(struct seq_file *m);
694694
void print_trace_header(struct seq_file *m, struct trace_iterator *iter);
695695

696696
void trace_graph_return(struct ftrace_graph_ret *trace, struct fgraph_ops *gops);
697-
int trace_graph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops);
697+
int trace_graph_entry(struct ftrace_graph_ent *trace, struct fgraph_ops *gops,
698+
struct ftrace_regs *fregs);
698699

699700
void tracing_start_cmdline_record(void);
700701
void tracing_stop_cmdline_record(void);

kernel/trace/trace_functions_graph.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,8 @@ struct fgraph_times {
175175
};
176176

177177
int trace_graph_entry(struct ftrace_graph_ent *trace,
178-
struct fgraph_ops *gops)
178+
struct fgraph_ops *gops,
179+
struct ftrace_regs *fregs)
179180
{
180181
unsigned long *task_var = fgraph_get_task_var(gops);
181182
struct trace_array *tr = gops->private;

kernel/trace/trace_irqsoff.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,8 @@ static int irqsoff_display_graph(struct trace_array *tr, int set)
176176
}
177177

178178
static int irqsoff_graph_entry(struct ftrace_graph_ent *trace,
179-
struct fgraph_ops *gops)
179+
struct fgraph_ops *gops,
180+
struct ftrace_regs *fregs)
180181
{
181182
struct trace_array *tr = irqsoff_trace;
182183
struct trace_array_cpu *data;

kernel/trace/trace_sched_wakeup.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ static int wakeup_display_graph(struct trace_array *tr, int set)
113113
}
114114

115115
static int wakeup_graph_entry(struct ftrace_graph_ent *trace,
116-
struct fgraph_ops *gops)
116+
struct fgraph_ops *gops,
117+
struct ftrace_regs *fregs)
117118
{
118119
struct trace_array *tr = wakeup_trace;
119120
struct trace_array_cpu *data;

kernel/trace/trace_selftest.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -774,7 +774,8 @@ struct fgraph_fixture {
774774
};
775775

776776
static __init int store_entry(struct ftrace_graph_ent *trace,
777-
struct fgraph_ops *gops)
777+
struct fgraph_ops *gops,
778+
struct ftrace_regs *fregs)
778779
{
779780
struct fgraph_fixture *fixture = container_of(gops, struct fgraph_fixture, gops);
780781
const char *type = fixture->store_type_name;
@@ -1025,7 +1026,8 @@ static unsigned int graph_hang_thresh;
10251026

10261027
/* Wrap the real function entry probe to avoid possible hanging */
10271028
static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace,
1028-
struct fgraph_ops *gops)
1029+
struct fgraph_ops *gops,
1030+
struct ftrace_regs *fregs)
10291031
{
10301032
/* This is harmlessly racy, we want to approximately detect a hang */
10311033
if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
@@ -1039,7 +1041,7 @@ static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace,
10391041
return 0;
10401042
}
10411043

1042-
return trace_graph_entry(trace, gops);
1044+
return trace_graph_entry(trace, gops, fregs);
10431045
}
10441046

10451047
static struct fgraph_ops fgraph_ops __initdata = {

0 commit comments

Comments
 (0)