[1/4] ftrace: pass fregs to arch_ftrace_set_direct_caller()

Message ID 20221024140846.3555435-2-mark.rutland@arm.com
State New
Headers
Series arm64/ftrace: move to DYNAMIC_FTRACE_WITH_ARGS |

Commit Message

Mark Rutland Oct. 24, 2022, 2:08 p.m. UTC
  In subsequent patches we'll arrange for architectures to have an
ftrace_regs which is entirely distinct from pt_regs. In preparation for
this, we need to minimize the use of pt_regs to where strictly
necessary in the core ftrace code.

This patch changes the prototype of arch_ftrace_set_direct_caller() to
take ftrace_regs rather than pt_regs, and moves the extraction of the
pt_regs into arch_ftrace_set_direct_caller().

For x86, we need to move arch_ftrace_set_direct_caller() after the
definition of struct ftrace_regs. As arch_ftrace_set_direct_caller() is
always called with a non-NULL pt_regs by call_direct_funcs() whose ops
have FTRACE_OPS_FL_SAVE_REGS, it's not necessary to add an additional
NULL check.

There should be no functional change as a result of this patch.

Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Florent Revest <revest@chromium.org>
Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Steven Rostedt <rostedt@goodmis.org>
---
 arch/s390/include/asm/ftrace.h |  3 ++-
 arch/x86/include/asm/ftrace.h  | 26 +++++++++++++-------------
 include/linux/ftrace.h         |  4 +++-
 kernel/trace/ftrace.c          |  3 +--
 4 files changed, 19 insertions(+), 17 deletions(-)
  

Comments

Steven Rostedt Oct. 24, 2022, 2:48 p.m. UTC | #1
On Mon, 24 Oct 2022 15:08:43 +0100
Mark Rutland <mark.rutland@arm.com> wrote:

> --- a/include/linux/ftrace.h
> +++ b/include/linux/ftrace.h
> @@ -429,6 +429,7 @@ static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
>  }
>  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
>  
> +#ifdef CONFIG_FUNCTION_TRACER

Instead of adding the above preprocessor check, the below chunk should be
moved into the CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS block above.

-- Steve


>  #ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
>  /*
>   * This must be implemented by the architecture.
> @@ -443,9 +444,10 @@ static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
>   * the return from the trampoline jump to the direct caller
>   * instead of going back to the function it just traced.
>   */
> -static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs,
> +static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
>  						 unsigned long addr) { }
>  #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
> +#endif /* CONFIG_FUNCTION_TRACER */
>  
>  #ifdef CONFIG_STACK_TRACER
>  
> diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
> index fbf2543111c0..234c5414deee 100644
  
Mark Rutland Oct. 24, 2022, 5:04 p.m. UTC | #2
On Mon, Oct 24, 2022 at 10:48:45AM -0400, Steven Rostedt wrote:
> On Mon, 24 Oct 2022 15:08:43 +0100
> Mark Rutland <mark.rutland@arm.com> wrote:
> 
> > --- a/include/linux/ftrace.h
> > +++ b/include/linux/ftrace.h
> > @@ -429,6 +429,7 @@ static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
> >  }
> >  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
> >  
> > +#ifdef CONFIG_FUNCTION_TRACER
> 
> Instead of adding the above preprocessor check, the below chunk should be
> moved into the CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS block above.

Sure; but note that doing that naively means 'struct ftrace_regs' won't always
be declared (e.g. if !CONFIG_FUNCTION_TRACER), and will result in warnings, e.g.

|   CC      arch/x86/kernel/asm-offsets.s
| In file included from ./include/linux/kvm_host.h:32,
|                  from arch/x86/kernel/../kvm/vmx/vmx.h:5,
|                  from arch/x86/kernel/asm-offsets.c:22:
| ./include/linux/ftrace.h:444:57: error: ‘struct ftrace_regs’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
|   444 | static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
|       |                                                         ^~~~~~~~~~~
| cc1: all warnings being treated as errors
| make[1]: *** [scripts/Makefile.build:118: arch/x86/kernel/asm-offsets.s] Error 1
| make: *** [Makefile:1270: prepare0] Error 2

... so I'll either need to add some ifdeffery, for CONFIG_FUNCTION_TRACER, or I
can hoist the declaration of 'struct ftrace_regs' to not depend on
CONFIG_FUNCTION_TRACER.

I guess the latter is preferable, e.g.

| diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
| index 2b34fec40a39..f201fcbfffb0 100644
| --- a/include/linux/ftrace.h
| +++ b/include/linux/ftrace.h
| @@ -37,9 +37,10 @@ extern void ftrace_boot_snapshot(void);
|  static inline void ftrace_boot_snapshot(void) { }
|  #endif
|  
| -#ifdef CONFIG_FUNCTION_TRACER
|  struct ftrace_ops;
|  struct ftrace_regs;
| +
| +#ifdef CONFIG_FUNCTION_TRACER
|  /*
|   * If the arch's mcount caller does not support all of ftrace's
|   * features, then it must call an indirect function that

... so I've done that locally for now.

Thanks,
Mark.
  
Florent Revest Oct. 25, 2022, 12:15 p.m. UTC | #3
On Mon, Oct 24, 2022 at 4:08 PM Mark Rutland <mark.rutland@arm.com> wrote:
> --- a/kernel/trace/ftrace.c
> +++ b/kernel/trace/ftrace.c
> @@ -2487,14 +2487,13 @@ ftrace_add_rec_direct(unsigned long ip, unsigned long addr,
>  static void call_direct_funcs(unsigned long ip, unsigned long pip,
>                               struct ftrace_ops *ops, struct ftrace_regs *fregs)
>  {
> -       struct pt_regs *regs = ftrace_get_regs(fregs);

Was this ftrace_get_regs() the only reason why we have
config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
    depends on DYNAMIC_FTRACE_WITH_REGS
?

If we no longer use it, maybe this should be:
    depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
?
  
Mark Rutland Oct. 28, 2022, 4:27 p.m. UTC | #4
On Mon, Oct 24, 2022 at 06:04:49PM +0100, Mark Rutland wrote:
> On Mon, Oct 24, 2022 at 10:48:45AM -0400, Steven Rostedt wrote:
> > On Mon, 24 Oct 2022 15:08:43 +0100
> > Mark Rutland <mark.rutland@arm.com> wrote:
> > 
> > > --- a/include/linux/ftrace.h
> > > +++ b/include/linux/ftrace.h
> > > @@ -429,6 +429,7 @@ static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
> > >  }
> > >  #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
> > >  
> > > +#ifdef CONFIG_FUNCTION_TRACER
> > 
> > Instead of adding the above preprocessor check, the below chunk should be
> > moved into the CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS block above.
> 
> Sure; but note that doing that naively means 'struct ftrace_regs' won't always
> be declared (e.g. if !CONFIG_FUNCTION_TRACER), and will result in warnings, e.g.
> 
> |   CC      arch/x86/kernel/asm-offsets.s
> | In file included from ./include/linux/kvm_host.h:32,
> |                  from arch/x86/kernel/../kvm/vmx/vmx.h:5,
> |                  from arch/x86/kernel/asm-offsets.c:22:
> | ./include/linux/ftrace.h:444:57: error: ‘struct ftrace_regs’ declared inside parameter list will not be visible outside of this definition or declaration [-Werror]
> |   444 | static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
> |       |                                                         ^~~~~~~~~~~
> | cc1: all warnings being treated as errors
> | make[1]: *** [scripts/Makefile.build:118: arch/x86/kernel/asm-offsets.s] Error 1
> | make: *** [Makefile:1270: prepare0] Error 2
> 
> ... so I'll either need to add some ifdeffery, for CONFIG_FUNCTION_TRACER, or I
> can hoist the declaration of 'struct ftrace_regs' to not depend on
> CONFIG_FUNCTION_TRACER.
> 
> I guess the latter is preferable, e.g.
> 
> | diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
> | index 2b34fec40a39..f201fcbfffb0 100644
> | --- a/include/linux/ftrace.h
> | +++ b/include/linux/ftrace.h
> | @@ -37,9 +37,10 @@ extern void ftrace_boot_snapshot(void);
> |  static inline void ftrace_boot_snapshot(void) { }
> |  #endif
> |  
> | -#ifdef CONFIG_FUNCTION_TRACER
> |  struct ftrace_ops;
> |  struct ftrace_regs;
> | +
> | +#ifdef CONFIG_FUNCTION_TRACER
> |  /*
> |   * If the arch's mcount caller does not support all of ftrace's
> |   * features, then it must call an indirect function that
> 
> ... so I've done that locally for now.

The kbuild robot complained that this led to x86 getting multiple definitions
of arch_ftrace_set_direct_caller(), so I've also added the below:

| diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
| index 788e7c1f6463c..6f9b9fee04132 100644
| --- a/arch/x86/include/asm/ftrace.h
| +++ b/arch/x86/include/asm/ftrace.h
| @@ -59,6 +59,7 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
|  #define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR
|  #endif
|  
| +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
|  /*
|   * When a ftrace registered caller is tracing a function that is
|   * also set by a register_ftrace_direct() call, it needs to be
| @@ -71,6 +72,7 @@ static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsi
|         /* Emulate a call */
|         fregs->regs.orig_ax = addr;
|  }
| +#endif
|  
|  #ifdef CONFIG_DYNAMIC_FTRACE

... AFAICT s390 doesn't need similar treatment.

Thanks,
Mark.
  

Patch

diff --git a/arch/s390/include/asm/ftrace.h b/arch/s390/include/asm/ftrace.h
index 6f80ec9c04be..53c4d1257549 100644
--- a/arch/s390/include/asm/ftrace.h
+++ b/arch/s390/include/asm/ftrace.h
@@ -67,8 +67,9 @@  static __always_inline void ftrace_instruction_pointer_set(struct ftrace_regs *f
  * place the direct caller in the ORIG_GPR2 part of pt_regs. This
  * tells the ftrace_caller that there's a direct caller.
  */
-static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
+static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
 {
+	struct pt_regs *regs = &fregs->regs;
 	regs->orig_gpr2 = addr;
 }
 
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index 908d99b127d3..788e7c1f6463 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -34,19 +34,6 @@  static inline unsigned long ftrace_call_adjust(unsigned long addr)
 	return addr;
 }
 
-/*
- * When a ftrace registered caller is tracing a function that is
- * also set by a register_ftrace_direct() call, it needs to be
- * differentiated in the ftrace_caller trampoline. To do this, we
- * place the direct caller in the ORIG_AX part of pt_regs. This
- * tells the ftrace_caller that there's a direct caller.
- */
-static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned long addr)
-{
-	/* Emulate a call */
-	regs->orig_ax = addr;
-}
-
 #ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
 struct ftrace_regs {
 	struct pt_regs		regs;
@@ -72,6 +59,19 @@  void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
 #define FTRACE_GRAPH_TRAMP_ADDR FTRACE_GRAPH_ADDR
 #endif
 
+/*
+ * When a ftrace registered caller is tracing a function that is
+ * also set by a register_ftrace_direct() call, it needs to be
+ * differentiated in the ftrace_caller trampoline. To do this, we
+ * place the direct caller in the ORIG_AX part of pt_regs. This
+ * tells the ftrace_caller that there's a direct caller.
+ */
+static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs, unsigned long addr)
+{
+	/* Emulate a call */
+	fregs->regs.orig_ax = addr;
+}
+
 #ifdef CONFIG_DYNAMIC_FTRACE
 
 struct dyn_arch_ftrace {
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 62557d4bffc2..5ca6c6680460 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -429,6 +429,7 @@  static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
 }
 #endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
 
+#ifdef CONFIG_FUNCTION_TRACER
 #ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
 /*
  * This must be implemented by the architecture.
@@ -443,9 +444,10 @@  static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsi
  * the return from the trampoline jump to the direct caller
  * instead of going back to the function it just traced.
  */
-static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs,
+static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
 						 unsigned long addr) { }
 #endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
+#endif /* CONFIG_FUNCTION_TRACER */
 
 #ifdef CONFIG_STACK_TRACER
 
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index fbf2543111c0..234c5414deee 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -2487,14 +2487,13 @@  ftrace_add_rec_direct(unsigned long ip, unsigned long addr,
 static void call_direct_funcs(unsigned long ip, unsigned long pip,
 			      struct ftrace_ops *ops, struct ftrace_regs *fregs)
 {
-	struct pt_regs *regs = ftrace_get_regs(fregs);
 	unsigned long addr;
 
 	addr = ftrace_find_rec_direct(ip);
 	if (!addr)
 		return;
 
-	arch_ftrace_set_direct_caller(regs, addr);
+	arch_ftrace_set_direct_caller(fregs, addr);
 }
 
 struct ftrace_ops direct_ops = {