Skip to content

Commit

Permalink
ftrace/x86: Allow for arguments to be passed in to ftrace_regs by def…
Browse files Browse the repository at this point in the history
…ault

Currently, the only way to get access to the registers of a function via a
ftrace callback is to set the "FL_SAVE_REGS" bit in the ftrace_ops. But as this
saves all regs as if a breakpoint were to trigger (for use with kprobes), it
is expensive.

The regs are already saved on the stack for the default ftrace callbacks, as
that is required otherwise a function being traced will get the wrong
arguments and possibly crash. And on x86, the arguments are already stored
where they would be on a pt_regs structure to use that code for both the
regs version of a callback, it makes sense to pass that information always
to all functions.

If an architecture does this (as x86_64 now does), it is to set
HAVE_DYNAMIC_FTRACE_WITH_ARGS, and this will let the generic code that it
could have access to arguments without having to set the flags.

This also includes having the stack pointer being saved, which could be used
for accessing arguments on the stack, as well as having the function graph
tracer not require its own trampoline!

Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt (VMware) committed Nov 13, 2020
1 parent d19ad07 commit 02a474c
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 3 deletions.
1 change: 1 addition & 0 deletions arch/x86/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ config X86
select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_REGS
select HAVE_DYNAMIC_FTRACE_WITH_ARGS if X86_64
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
select HAVE_EBPF_JIT
select HAVE_EFFICIENT_UNALIGNED_ACCESS
Expand Down
15 changes: 15 additions & 0 deletions arch/x86/include/asm/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ static inline void arch_ftrace_set_direct_caller(struct pt_regs *regs, unsigned
regs->orig_ax = addr;
}

#ifdef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS
struct ftrace_regs {
struct pt_regs regs;
};

static __always_inline struct pt_regs *
arch_ftrace_get_regs(struct ftrace_regs *fregs)
{
/* Only when FL_SAVE_REGS is set, cs will be non zero */
if (!fregs->regs.cs)
return NULL;
return &fregs->regs;
}
#endif

#ifdef CONFIG_DYNAMIC_FTRACE

struct dyn_arch_ftrace {
Expand Down
11 changes: 9 additions & 2 deletions arch/x86/kernel/ftrace_64.S
Original file line number Diff line number Diff line change
Expand Up @@ -140,12 +140,19 @@ SYM_FUNC_START(ftrace_caller)
/* save_mcount_regs fills in first two parameters */
save_mcount_regs

/* Stack - skipping return address of ftrace_caller */
leaq MCOUNT_REG_SIZE+8(%rsp), %rcx
movq %rcx, RSP(%rsp)

SYM_INNER_LABEL(ftrace_caller_op_ptr, SYM_L_GLOBAL)
/* Load the ftrace_ops into the 3rd parameter */
movq function_trace_op(%rip), %rdx

/* regs go into 4th parameter (but make it NULL) */
movq $0, %rcx
/* regs go into 4th parameter */
leaq (%rsp), %rcx

/* Only ops with REGS flag set should have CS register set */
movq $0, CS(%rsp)

SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
call ftrace_stub
Expand Down
7 changes: 6 additions & 1 deletion include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,21 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,

struct ftrace_ops;

#ifndef CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS

struct ftrace_regs {
struct pt_regs regs;
};
#define arch_ftrace_get_regs(fregs) (&(fregs)->regs)

#endif /* CONFIG_HAVE_DYNAMIC_FTRACE_WITH_ARGS */

static __always_inline struct pt_regs *ftrace_get_regs(struct ftrace_regs *fregs)
{
if (!fregs)
return NULL;

return &fregs->regs;
return arch_ftrace_get_regs(fregs);
}

typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip,
Expand Down
9 changes: 9 additions & 0 deletions kernel/trace/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,15 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS
config HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
bool

config HAVE_DYNAMIC_FTRACE_WITH_ARGS
bool
help
If this is set, then arguments and stack can be found from
the pt_regs passed into the function callback regs parameter
by default, even without setting the REGS flag in the ftrace_ops.
This allows for use of regs_get_kernel_argument() and
kernel_stack_pointer().

config HAVE_FTRACE_MCOUNT_RECORD
bool
help
Expand Down

0 comments on commit 02a474c

Please sign in to comment.