Commit ea88dc92 authored by Will Deacon's avatar Will Deacon

Merge branch 'for-next/ftrace' into for-next/core

* for-next/ftrace:
  arm64: ftrace: Simplify get_ftrace_plt
  arm64: ftrace: Add direct call support
  ftrace: selftest: remove broken trace_direct_tramp
  ftrace: Make DIRECT_CALLS work WITH_ARGS and !WITH_REGS
  ftrace: Store direct called addresses in their ops
  ftrace: Rename _ftrace_direct_multi APIs to _ftrace_direct APIs
  ftrace: Remove the legacy _ftrace_direct API
  ftrace: Replace uses of _ftrace_direct APIs with _ftrace_direct_multi
  ftrace: Let unregister_ftrace_direct_multi() call ftrace_free_filter()
parents 31eb87cf 0f59dca6
...@@ -185,6 +185,10 @@ config ARM64 ...@@ -185,6 +185,10 @@ config ARM64
select HAVE_DEBUG_KMEMLEAK select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_CONTIGUOUS select HAVE_DMA_CONTIGUOUS
select HAVE_DYNAMIC_FTRACE select HAVE_DYNAMIC_FTRACE
select HAVE_DYNAMIC_FTRACE_WITH_ARGS \
if $(cc-option,-fpatchable-function-entry=2)
select HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS \
if DYNAMIC_FTRACE_WITH_ARGS && DYNAMIC_FTRACE_WITH_CALL_OPS
select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \ select HAVE_DYNAMIC_FTRACE_WITH_CALL_OPS \
if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG && \ if (DYNAMIC_FTRACE_WITH_ARGS && !CFI_CLANG && \
!CC_OPTIMIZE_FOR_SIZE) !CC_OPTIMIZE_FOR_SIZE)
......
...@@ -70,10 +70,19 @@ struct ftrace_ops; ...@@ -70,10 +70,19 @@ struct ftrace_ops;
#define arch_ftrace_get_regs(regs) NULL #define arch_ftrace_get_regs(regs) NULL
/*
* Note: sizeof(struct ftrace_regs) must be a multiple of 16 to ensure correct
* stack alignment
*/
struct ftrace_regs { struct ftrace_regs {
/* x0 - x8 */ /* x0 - x8 */
unsigned long regs[9]; unsigned long regs[9];
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
unsigned long direct_tramp;
#else
unsigned long __unused; unsigned long __unused;
#endif
unsigned long fp; unsigned long fp;
unsigned long lr; unsigned long lr;
...@@ -136,6 +145,19 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec); ...@@ -136,6 +145,19 @@ int ftrace_init_nop(struct module *mod, struct dyn_ftrace *rec);
void ftrace_graph_func(unsigned long ip, unsigned long parent_ip, void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
struct ftrace_ops *op, struct ftrace_regs *fregs); struct ftrace_ops *op, struct ftrace_regs *fregs);
#define ftrace_graph_func ftrace_graph_func #define ftrace_graph_func ftrace_graph_func
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
static inline void arch_ftrace_set_direct_caller(struct ftrace_regs *fregs,
unsigned long addr)
{
/*
* The ftrace trampoline will return to this address instead of the
* instrumented function.
*/
fregs->direct_tramp = addr;
}
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
#endif #endif
#define ftrace_return_address(n) return_address(n) #define ftrace_return_address(n) return_address(n)
......
...@@ -93,6 +93,9 @@ int main(void) ...@@ -93,6 +93,9 @@ int main(void)
DEFINE(FREGS_LR, offsetof(struct ftrace_regs, lr)); DEFINE(FREGS_LR, offsetof(struct ftrace_regs, lr));
DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp)); DEFINE(FREGS_SP, offsetof(struct ftrace_regs, sp));
DEFINE(FREGS_PC, offsetof(struct ftrace_regs, pc)); DEFINE(FREGS_PC, offsetof(struct ftrace_regs, pc));
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
DEFINE(FREGS_DIRECT_TRAMP, offsetof(struct ftrace_regs, direct_tramp));
#endif
DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs)); DEFINE(FREGS_SIZE, sizeof(struct ftrace_regs));
BLANK(); BLANK();
#endif #endif
...@@ -197,6 +200,9 @@ int main(void) ...@@ -197,6 +200,9 @@ int main(void)
#endif #endif
#ifdef CONFIG_FUNCTION_TRACER #ifdef CONFIG_FUNCTION_TRACER
DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func)); DEFINE(FTRACE_OPS_FUNC, offsetof(struct ftrace_ops, func));
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
DEFINE(FTRACE_OPS_DIRECT_CALL, offsetof(struct ftrace_ops, direct_call));
#endif
#endif #endif
return 0; return 0;
} }
...@@ -36,6 +36,31 @@ ...@@ -36,6 +36,31 @@
SYM_CODE_START(ftrace_caller) SYM_CODE_START(ftrace_caller)
bti c bti c
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
/*
* The literal pointer to the ops is at an 8-byte aligned boundary
* which is either 12 or 16 bytes before the BL instruction in the call
* site. See ftrace_call_adjust() for details.
*
* Therefore here the LR points at `literal + 16` or `literal + 20`,
* and we can find the address of the literal in either case by
* aligning to an 8-byte boundary and subtracting 16. We do the
* alignment first as this allows us to fold the subtraction into the
* LDR.
*/
bic x11, x30, 0x7
ldr x11, [x11, #-(4 * AARCH64_INSN_SIZE)] // op
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
/*
* If the op has a direct call, handle it immediately without
* saving/restoring registers.
*/
ldr x17, [x11, #FTRACE_OPS_DIRECT_CALL] // op->direct_call
cbnz x17, ftrace_caller_direct
#endif
#endif
/* Save original SP */ /* Save original SP */
mov x10, sp mov x10, sp
...@@ -49,6 +74,10 @@ SYM_CODE_START(ftrace_caller) ...@@ -49,6 +74,10 @@ SYM_CODE_START(ftrace_caller)
stp x6, x7, [sp, #FREGS_X6] stp x6, x7, [sp, #FREGS_X6]
str x8, [sp, #FREGS_X8] str x8, [sp, #FREGS_X8]
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
str xzr, [sp, #FREGS_DIRECT_TRAMP]
#endif
/* Save the callsite's FP, LR, SP */ /* Save the callsite's FP, LR, SP */
str x29, [sp, #FREGS_FP] str x29, [sp, #FREGS_FP]
str x9, [sp, #FREGS_LR] str x9, [sp, #FREGS_LR]
...@@ -71,20 +100,7 @@ SYM_CODE_START(ftrace_caller) ...@@ -71,20 +100,7 @@ SYM_CODE_START(ftrace_caller)
mov x3, sp // regs mov x3, sp // regs
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS #ifdef CONFIG_DYNAMIC_FTRACE_WITH_CALL_OPS
/* mov x2, x11 // op
* The literal pointer to the ops is at an 8-byte aligned boundary
* which is either 12 or 16 bytes before the BL instruction in the call
* site. See ftrace_call_adjust() for details.
*
* Therefore here the LR points at `literal + 16` or `literal + 20`,
* and we can find the address of the literal in either case by
* aligning to an 8-byte boundary and subtracting 16. We do the
* alignment first as this allows us to fold the subtraction into the
* LDR.
*/
bic x2, x30, 0x7
ldr x2, [x2, #-16] // op
ldr x4, [x2, #FTRACE_OPS_FUNC] // op->func ldr x4, [x2, #FTRACE_OPS_FUNC] // op->func
blr x4 // op->func(ip, parent_ip, op, regs) blr x4 // op->func(ip, parent_ip, op, regs)
...@@ -107,8 +123,15 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) ...@@ -107,8 +123,15 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
ldp x6, x7, [sp, #FREGS_X6] ldp x6, x7, [sp, #FREGS_X6]
ldr x8, [sp, #FREGS_X8] ldr x8, [sp, #FREGS_X8]
/* Restore the callsite's FP, LR, PC */ /* Restore the callsite's FP */
ldr x29, [sp, #FREGS_FP] ldr x29, [sp, #FREGS_FP]
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
ldr x17, [sp, #FREGS_DIRECT_TRAMP]
cbnz x17, ftrace_caller_direct_late
#endif
/* Restore the callsite's LR and PC */
ldr x30, [sp, #FREGS_LR] ldr x30, [sp, #FREGS_LR]
ldr x9, [sp, #FREGS_PC] ldr x9, [sp, #FREGS_PC]
...@@ -116,8 +139,45 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL) ...@@ -116,8 +139,45 @@ SYM_INNER_LABEL(ftrace_call, SYM_L_GLOBAL)
add sp, sp, #FREGS_SIZE + 32 add sp, sp, #FREGS_SIZE + 32
ret x9 ret x9
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
SYM_INNER_LABEL(ftrace_caller_direct_late, SYM_L_LOCAL)
/*
* Head to a direct trampoline in x17 after having run other tracers.
* The ftrace_regs are live, and x0-x8 and FP have been restored. The
* LR, PC, and SP have not been restored.
*/
/*
* Restore the callsite's LR and PC matching the trampoline calling
* convention.
*/
ldr x9, [sp, #FREGS_LR]
ldr x30, [sp, #FREGS_PC]
/* Restore the callsite's SP */
add sp, sp, #FREGS_SIZE + 32
SYM_INNER_LABEL(ftrace_caller_direct, SYM_L_LOCAL)
/*
* Head to a direct trampoline in x17.
*
* We use `BR X17` as this can safely land on a `BTI C` or `PACIASP` in
* the trampoline, and will not unbalance any return stack.
*/
br x17
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
SYM_CODE_END(ftrace_caller) SYM_CODE_END(ftrace_caller)
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
SYM_CODE_START(ftrace_stub_direct_tramp)
bti c
mov x10, x30
mov x30, x9
ret x10
SYM_CODE_END(ftrace_stub_direct_tramp)
#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */
#else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */ #else /* CONFIG_DYNAMIC_FTRACE_WITH_ARGS */
/* /*
......
...@@ -195,15 +195,22 @@ int ftrace_update_ftrace_func(ftrace_func_t func) ...@@ -195,15 +195,22 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
return ftrace_modify_code(pc, 0, new, false); return ftrace_modify_code(pc, 0, new, false);
} }
static struct plt_entry *get_ftrace_plt(struct module *mod, unsigned long addr) static struct plt_entry *get_ftrace_plt(struct module *mod)
{ {
#ifdef CONFIG_ARM64_MODULE_PLTS #ifdef CONFIG_ARM64_MODULE_PLTS
struct plt_entry *plt = mod->arch.ftrace_trampolines; struct plt_entry *plt = mod->arch.ftrace_trampolines;
if (addr == FTRACE_ADDR)
return &plt[FTRACE_PLT_IDX]; return &plt[FTRACE_PLT_IDX];
#endif #else
return NULL; return NULL;
#endif
}
static bool reachable_by_bl(unsigned long addr, unsigned long pc)
{
long offset = (long)addr - (long)pc;
return offset >= -SZ_128M && offset < SZ_128M;
} }
/* /*
...@@ -220,14 +227,21 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec, ...@@ -220,14 +227,21 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
unsigned long *addr) unsigned long *addr)
{ {
unsigned long pc = rec->ip; unsigned long pc = rec->ip;
long offset = (long)*addr - (long)pc;
struct plt_entry *plt; struct plt_entry *plt;
/*
* If a custom trampoline is unreachable, rely on the ftrace_caller
* trampoline which knows how to indirectly reach that trampoline
* through ops->direct_call.
*/
if (*addr != FTRACE_ADDR && !reachable_by_bl(*addr, pc))
*addr = FTRACE_ADDR;
/* /*
* When the target is within range of the 'BL' instruction, use 'addr' * When the target is within range of the 'BL' instruction, use 'addr'
* as-is and branch to that directly. * as-is and branch to that directly.
*/ */
if (offset >= -SZ_128M && offset < SZ_128M) if (reachable_by_bl(*addr, pc))
return true; return true;
/* /*
...@@ -256,7 +270,7 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec, ...@@ -256,7 +270,7 @@ static bool ftrace_find_callable_addr(struct dyn_ftrace *rec,
if (WARN_ON(!mod)) if (WARN_ON(!mod))
return false; return false;
plt = get_ftrace_plt(mod, *addr); plt = get_ftrace_plt(mod);
if (!plt) { if (!plt) {
pr_err("ftrace: no module PLT for %ps\n", (void *)*addr); pr_err("ftrace: no module PLT for %ps\n", (void *)*addr);
return false; return false;
...@@ -330,12 +344,24 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) ...@@ -330,12 +344,24 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
unsigned long addr) unsigned long addr)
{ {
if (WARN_ON_ONCE(old_addr != (unsigned long)ftrace_caller)) unsigned long pc = rec->ip;
u32 old, new;
int ret;
ret = ftrace_rec_set_ops(rec, arm64_rec_get_ops(rec));
if (ret)
return ret;
if (!ftrace_find_callable_addr(rec, NULL, &old_addr))
return -EINVAL; return -EINVAL;
if (WARN_ON_ONCE(addr != (unsigned long)ftrace_caller)) if (!ftrace_find_callable_addr(rec, NULL, &addr))
return -EINVAL; return -EINVAL;
return ftrace_rec_update_ops(rec); old = aarch64_insn_gen_branch_imm(pc, old_addr,
AARCH64_INSN_BRANCH_LINK);
new = aarch64_insn_gen_branch_imm(pc, addr, AARCH64_INSN_BRANCH_LINK);
return ftrace_modify_code(pc, old, new, true);
} }
#endif #endif
......
...@@ -32,6 +32,11 @@ ENTRY(ftrace_stub) ...@@ -32,6 +32,11 @@ ENTRY(ftrace_stub)
BR_EX %r14 BR_EX %r14
ENDPROC(ftrace_stub) ENDPROC(ftrace_stub)
SYM_CODE_START(ftrace_stub_direct_tramp)
lgr %r1, %r0
BR_EX %r1
SYM_CODE_END(ftrace_stub_direct_tramp)
.macro ftrace_regs_entry, allregs=0 .macro ftrace_regs_entry, allregs=0
stg %r14,(__SF_GPRS+8*8)(%r15) # save traced function caller stg %r14,(__SF_GPRS+8*8)(%r15) # save traced function caller
......
...@@ -163,6 +163,11 @@ SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL) ...@@ -163,6 +163,11 @@ SYM_INNER_LABEL(ftrace_regs_call, SYM_L_GLOBAL)
jmp .Lftrace_ret jmp .Lftrace_ret
SYM_CODE_END(ftrace_regs_caller) SYM_CODE_END(ftrace_regs_caller)
SYM_FUNC_START(ftrace_stub_direct_tramp)
CALL_DEPTH_ACCOUNT
RET
SYM_FUNC_END(ftrace_stub_direct_tramp)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER #ifdef CONFIG_FUNCTION_GRAPH_TRACER
SYM_CODE_START(ftrace_graph_caller) SYM_CODE_START(ftrace_graph_caller)
pushl %eax pushl %eax
......
...@@ -309,6 +309,10 @@ SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL) ...@@ -309,6 +309,10 @@ SYM_INNER_LABEL(ftrace_regs_caller_end, SYM_L_GLOBAL)
SYM_FUNC_END(ftrace_regs_caller) SYM_FUNC_END(ftrace_regs_caller)
STACK_FRAME_NON_STANDARD_FP(ftrace_regs_caller) STACK_FRAME_NON_STANDARD_FP(ftrace_regs_caller)
SYM_FUNC_START(ftrace_stub_direct_tramp)
CALL_DEPTH_ACCOUNT
RET
SYM_FUNC_END(ftrace_stub_direct_tramp)
#else /* ! CONFIG_DYNAMIC_FTRACE */ #else /* ! CONFIG_DYNAMIC_FTRACE */
......
...@@ -241,6 +241,12 @@ enum { ...@@ -241,6 +241,12 @@ enum {
FTRACE_OPS_FL_DIRECT = BIT(17), FTRACE_OPS_FL_DIRECT = BIT(17),
}; };
#ifndef CONFIG_DYNAMIC_FTRACE_WITH_ARGS
#define FTRACE_OPS_FL_SAVE_ARGS FTRACE_OPS_FL_SAVE_REGS
#else
#define FTRACE_OPS_FL_SAVE_ARGS 0
#endif
/* /*
* FTRACE_OPS_CMD_* commands allow the ftrace core logic to request changes * FTRACE_OPS_CMD_* commands allow the ftrace core logic to request changes
* to a ftrace_ops. Note, the requests may fail. * to a ftrace_ops. Note, the requests may fail.
...@@ -321,6 +327,9 @@ struct ftrace_ops { ...@@ -321,6 +327,9 @@ struct ftrace_ops {
unsigned long trampoline_size; unsigned long trampoline_size;
struct list_head list; struct list_head list;
ftrace_ops_func_t ops_func; ftrace_ops_func_t ops_func;
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
unsigned long direct_call;
#endif
#endif #endif
}; };
...@@ -397,64 +406,36 @@ struct ftrace_func_entry { ...@@ -397,64 +406,36 @@ struct ftrace_func_entry {
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
extern int ftrace_direct_func_count; extern int ftrace_direct_func_count;
int register_ftrace_direct(unsigned long ip, unsigned long addr);
int unregister_ftrace_direct(unsigned long ip, unsigned long addr);
int modify_ftrace_direct(unsigned long ip, unsigned long old_addr, unsigned long new_addr);
struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr);
int ftrace_modify_direct_caller(struct ftrace_func_entry *entry,
struct dyn_ftrace *rec,
unsigned long old_addr,
unsigned long new_addr);
unsigned long ftrace_find_rec_direct(unsigned long ip); unsigned long ftrace_find_rec_direct(unsigned long ip);
int register_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr); int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr); int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr,
int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr); bool free_filters);
int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsigned long addr); int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr);
int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr);
void ftrace_stub_direct_tramp(void);
#else #else
struct ftrace_ops; struct ftrace_ops;
# define ftrace_direct_func_count 0 # define ftrace_direct_func_count 0
static inline int register_ftrace_direct(unsigned long ip, unsigned long addr)
{
return -ENOTSUPP;
}
static inline int unregister_ftrace_direct(unsigned long ip, unsigned long addr)
{
return -ENOTSUPP;
}
static inline int modify_ftrace_direct(unsigned long ip,
unsigned long old_addr, unsigned long new_addr)
{
return -ENOTSUPP;
}
static inline struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr)
{
return NULL;
}
static inline int ftrace_modify_direct_caller(struct ftrace_func_entry *entry,
struct dyn_ftrace *rec,
unsigned long old_addr,
unsigned long new_addr)
{
return -ENODEV;
}
static inline unsigned long ftrace_find_rec_direct(unsigned long ip) static inline unsigned long ftrace_find_rec_direct(unsigned long ip)
{ {
return 0; return 0;
} }
static inline int register_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr) static inline int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int unregister_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr) static inline int unregister_ftrace_direct(struct ftrace_ops *ops, unsigned long addr,
bool free_filters)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int modify_ftrace_direct_multi(struct ftrace_ops *ops, unsigned long addr) static inline int modify_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)
{ {
return -ENODEV; return -ENODEV;
} }
static inline int modify_ftrace_direct_multi_nolock(struct ftrace_ops *ops, unsigned long addr) static inline int modify_ftrace_direct_nolock(struct ftrace_ops *ops, unsigned long addr)
{ {
return -ENODEV; return -ENODEV;
} }
......
...@@ -45,8 +45,8 @@ static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, enum ftrace_ops_cmd ...@@ -45,8 +45,8 @@ static int bpf_tramp_ftrace_ops_func(struct ftrace_ops *ops, enum ftrace_ops_cmd
lockdep_assert_held_once(&tr->mutex); lockdep_assert_held_once(&tr->mutex);
/* Instead of updating the trampoline here, we propagate /* Instead of updating the trampoline here, we propagate
* -EAGAIN to register_ftrace_direct_multi(). Then we can * -EAGAIN to register_ftrace_direct(). Then we can
* retry register_ftrace_direct_multi() after updating the * retry register_ftrace_direct() after updating the
* trampoline. * trampoline.
*/ */
if ((tr->flags & BPF_TRAMP_F_CALL_ORIG) && if ((tr->flags & BPF_TRAMP_F_CALL_ORIG) &&
...@@ -198,7 +198,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr) ...@@ -198,7 +198,7 @@ static int unregister_fentry(struct bpf_trampoline *tr, void *old_addr)
int ret; int ret;
if (tr->func.ftrace_managed) if (tr->func.ftrace_managed)
ret = unregister_ftrace_direct_multi(tr->fops, (long)old_addr); ret = unregister_ftrace_direct(tr->fops, (long)old_addr, false);
else else
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL); ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, NULL);
...@@ -215,9 +215,9 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad ...@@ -215,9 +215,9 @@ static int modify_fentry(struct bpf_trampoline *tr, void *old_addr, void *new_ad
if (tr->func.ftrace_managed) { if (tr->func.ftrace_managed) {
if (lock_direct_mutex) if (lock_direct_mutex)
ret = modify_ftrace_direct_multi(tr->fops, (long)new_addr); ret = modify_ftrace_direct(tr->fops, (long)new_addr);
else else
ret = modify_ftrace_direct_multi_nolock(tr->fops, (long)new_addr); ret = modify_ftrace_direct_nolock(tr->fops, (long)new_addr);
} else { } else {
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, new_addr); ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, old_addr, new_addr);
} }
...@@ -243,7 +243,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr) ...@@ -243,7 +243,7 @@ static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
if (tr->func.ftrace_managed) { if (tr->func.ftrace_managed) {
ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1); ftrace_set_filter_ip(tr->fops, (unsigned long)ip, 0, 1);
ret = register_ftrace_direct_multi(tr->fops, (long)new_addr); ret = register_ftrace_direct(tr->fops, (long)new_addr);
} else { } else {
ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr); ret = bpf_arch_text_poke(ip, BPF_MOD_CALL, NULL, new_addr);
} }
......
...@@ -257,7 +257,7 @@ config DYNAMIC_FTRACE_WITH_REGS ...@@ -257,7 +257,7 @@ config DYNAMIC_FTRACE_WITH_REGS
config DYNAMIC_FTRACE_WITH_DIRECT_CALLS config DYNAMIC_FTRACE_WITH_DIRECT_CALLS
def_bool y def_bool y
depends on DYNAMIC_FTRACE_WITH_REGS depends on DYNAMIC_FTRACE_WITH_REGS || DYNAMIC_FTRACE_WITH_ARGS
depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS depends on HAVE_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
config DYNAMIC_FTRACE_WITH_CALL_OPS config DYNAMIC_FTRACE_WITH_CALL_OPS
......
This diff is collapsed.
...@@ -785,14 +785,7 @@ static struct fgraph_ops fgraph_ops __initdata = { ...@@ -785,14 +785,7 @@ static struct fgraph_ops fgraph_ops __initdata = {
}; };
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
#ifndef CALL_DEPTH_ACCOUNT static struct ftrace_ops direct;
#define CALL_DEPTH_ACCOUNT ""
#endif
noinline __noclone static void trace_direct_tramp(void)
{
asm(CALL_DEPTH_ACCOUNT);
}
#endif #endif
/* /*
...@@ -870,8 +863,9 @@ trace_selftest_startup_function_graph(struct tracer *trace, ...@@ -870,8 +863,9 @@ trace_selftest_startup_function_graph(struct tracer *trace,
* Register direct function together with graph tracer * Register direct function together with graph tracer
* and make sure we get graph trace. * and make sure we get graph trace.
*/ */
ret = register_ftrace_direct((unsigned long) DYN_FTRACE_TEST_NAME, ftrace_set_filter_ip(&direct, (unsigned long)DYN_FTRACE_TEST_NAME, 0, 0);
(unsigned long) trace_direct_tramp); ret = register_ftrace_direct(&direct,
(unsigned long)ftrace_stub_direct_tramp);
if (ret) if (ret)
goto out; goto out;
...@@ -891,8 +885,9 @@ trace_selftest_startup_function_graph(struct tracer *trace, ...@@ -891,8 +885,9 @@ trace_selftest_startup_function_graph(struct tracer *trace,
unregister_ftrace_graph(&fgraph_ops); unregister_ftrace_graph(&fgraph_ops);
ret = unregister_ftrace_direct((unsigned long) DYN_FTRACE_TEST_NAME, ret = unregister_ftrace_direct(&direct,
(unsigned long) trace_direct_tramp); (unsigned long)ftrace_stub_direct_tramp,
true);
if (ret) if (ret)
goto out; goto out;
......
...@@ -38,7 +38,7 @@ config SAMPLE_FTRACE_DIRECT ...@@ -38,7 +38,7 @@ config SAMPLE_FTRACE_DIRECT
that hooks to wake_up_process and prints the parameters. that hooks to wake_up_process and prints the parameters.
config SAMPLE_FTRACE_DIRECT_MULTI config SAMPLE_FTRACE_DIRECT_MULTI
tristate "Build register_ftrace_direct_multi() example" tristate "Build register_ftrace_direct() on multiple ips example"
depends on DYNAMIC_FTRACE_WITH_DIRECT_CALLS && m depends on DYNAMIC_FTRACE_WITH_DIRECT_CALLS && m
depends on HAVE_SAMPLE_FTRACE_DIRECT_MULTI depends on HAVE_SAMPLE_FTRACE_DIRECT_MULTI
help help
......
...@@ -96,6 +96,8 @@ asm ( ...@@ -96,6 +96,8 @@ asm (
#endif /* CONFIG_S390 */ #endif /* CONFIG_S390 */
static struct ftrace_ops direct;
static unsigned long my_tramp = (unsigned long)my_tramp1; static unsigned long my_tramp = (unsigned long)my_tramp1;
static unsigned long tramps[2] = { static unsigned long tramps[2] = {
(unsigned long)my_tramp1, (unsigned long)my_tramp1,
...@@ -114,7 +116,7 @@ static int simple_thread(void *arg) ...@@ -114,7 +116,7 @@ static int simple_thread(void *arg)
if (ret) if (ret)
continue; continue;
t ^= 1; t ^= 1;
ret = modify_ftrace_direct(my_ip, my_tramp, tramps[t]); ret = modify_ftrace_direct(&direct, tramps[t]);
if (!ret) if (!ret)
my_tramp = tramps[t]; my_tramp = tramps[t];
WARN_ON_ONCE(ret); WARN_ON_ONCE(ret);
...@@ -129,7 +131,9 @@ static int __init ftrace_direct_init(void) ...@@ -129,7 +131,9 @@ static int __init ftrace_direct_init(void)
{ {
int ret; int ret;
ret = register_ftrace_direct(my_ip, my_tramp); ftrace_set_filter_ip(&direct, (unsigned long) my_ip, 0, 0);
ret = register_ftrace_direct(&direct, my_tramp);
if (!ret) if (!ret)
simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn"); simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");
return ret; return ret;
...@@ -138,7 +142,7 @@ static int __init ftrace_direct_init(void) ...@@ -138,7 +142,7 @@ static int __init ftrace_direct_init(void)
static void __exit ftrace_direct_exit(void) static void __exit ftrace_direct_exit(void)
{ {
kthread_stop(simple_tsk); kthread_stop(simple_tsk);
unregister_ftrace_direct(my_ip, my_tramp); unregister_ftrace_direct(&direct, my_tramp, true);
} }
module_init(ftrace_direct_init); module_init(ftrace_direct_init);
......
...@@ -123,7 +123,7 @@ static int simple_thread(void *arg) ...@@ -123,7 +123,7 @@ static int simple_thread(void *arg)
if (ret) if (ret)
continue; continue;
t ^= 1; t ^= 1;
ret = modify_ftrace_direct_multi(&direct, tramps[t]); ret = modify_ftrace_direct(&direct, tramps[t]);
if (!ret) if (!ret)
my_tramp = tramps[t]; my_tramp = tramps[t];
WARN_ON_ONCE(ret); WARN_ON_ONCE(ret);
...@@ -141,7 +141,7 @@ static int __init ftrace_direct_multi_init(void) ...@@ -141,7 +141,7 @@ static int __init ftrace_direct_multi_init(void)
ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0); ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0); ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);
ret = register_ftrace_direct_multi(&direct, my_tramp); ret = register_ftrace_direct(&direct, my_tramp);
if (!ret) if (!ret)
simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn"); simple_tsk = kthread_run(simple_thread, NULL, "event-sample-fn");
...@@ -151,13 +151,12 @@ static int __init ftrace_direct_multi_init(void) ...@@ -151,13 +151,12 @@ static int __init ftrace_direct_multi_init(void)
static void __exit ftrace_direct_multi_exit(void) static void __exit ftrace_direct_multi_exit(void)
{ {
kthread_stop(simple_tsk); kthread_stop(simple_tsk);
unregister_ftrace_direct_multi(&direct, my_tramp); unregister_ftrace_direct(&direct, my_tramp, true);
ftrace_free_filter(&direct);
} }
module_init(ftrace_direct_multi_init); module_init(ftrace_direct_multi_init);
module_exit(ftrace_direct_multi_exit); module_exit(ftrace_direct_multi_exit);
MODULE_AUTHOR("Jiri Olsa"); MODULE_AUTHOR("Jiri Olsa");
MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct_multi()"); MODULE_DESCRIPTION("Example use case of using modify_ftrace_direct()");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -73,13 +73,12 @@ static int __init ftrace_direct_multi_init(void) ...@@ -73,13 +73,12 @@ static int __init ftrace_direct_multi_init(void)
ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0); ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0); ftrace_set_filter_ip(&direct, (unsigned long) schedule, 0, 0);
return register_ftrace_direct_multi(&direct, (unsigned long) my_tramp); return register_ftrace_direct(&direct, (unsigned long) my_tramp);
} }
static void __exit ftrace_direct_multi_exit(void) static void __exit ftrace_direct_multi_exit(void)
{ {
unregister_ftrace_direct_multi(&direct, (unsigned long) my_tramp); unregister_ftrace_direct(&direct, (unsigned long) my_tramp, true);
ftrace_free_filter(&direct);
} }
module_init(ftrace_direct_multi_init); module_init(ftrace_direct_multi_init);
......
...@@ -70,16 +70,18 @@ asm ( ...@@ -70,16 +70,18 @@ asm (
#endif /* CONFIG_S390 */ #endif /* CONFIG_S390 */
static struct ftrace_ops direct;
static int __init ftrace_direct_init(void) static int __init ftrace_direct_init(void)
{ {
return register_ftrace_direct((unsigned long)handle_mm_fault, ftrace_set_filter_ip(&direct, (unsigned long) handle_mm_fault, 0, 0);
(unsigned long)my_tramp);
return register_ftrace_direct(&direct, (unsigned long) my_tramp);
} }
static void __exit ftrace_direct_exit(void) static void __exit ftrace_direct_exit(void)
{ {
unregister_ftrace_direct((unsigned long)handle_mm_fault, unregister_ftrace_direct(&direct, (unsigned long)my_tramp, true);
(unsigned long)my_tramp);
} }
module_init(ftrace_direct_init); module_init(ftrace_direct_init);
......
...@@ -63,16 +63,18 @@ asm ( ...@@ -63,16 +63,18 @@ asm (
#endif /* CONFIG_S390 */ #endif /* CONFIG_S390 */
static struct ftrace_ops direct;
static int __init ftrace_direct_init(void) static int __init ftrace_direct_init(void)
{ {
return register_ftrace_direct((unsigned long)wake_up_process, ftrace_set_filter_ip(&direct, (unsigned long) wake_up_process, 0, 0);
(unsigned long)my_tramp);
return register_ftrace_direct(&direct, (unsigned long) my_tramp);
} }
static void __exit ftrace_direct_exit(void) static void __exit ftrace_direct_exit(void)
{ {
unregister_ftrace_direct((unsigned long)wake_up_process, unregister_ftrace_direct(&direct, (unsigned long)my_tramp, true);
(unsigned long)my_tramp);
} }
module_init(ftrace_direct_init); module_init(ftrace_direct_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment