ARM: 8678/1: ftrace: Adds support for CONFIG_DYNAMIC_FTRACE_WITH_REGS
The DYNAMIC_FTRACE_WITH_REGS configuration makes it possible for a ftrace operation to specify if registers need to saved/restored by the ftrace handler. This is needed by kgraft and possibly other ftrace-based tools, and the ARM architecture is currently lacking this feature. It would also be the first step to support the "Kprobes-on-ftrace" optimization on ARM. This patch introduces a new ftrace handler that stores the registers on the stack before calling the next stage. The registers are restored from the stack before going back to the instrumented function. A side-effect of this patch is to activate the support for ftrace_modify_call() as it defines ARCH_SUPPORTS_FTRACE_OPS for the ARM architecture. Signed-off-by: Abel Vesa <abelvesa@linux.com> Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
This commit is contained in:
@@ -141,6 +141,15 @@ int ftrace_update_ftrace_func(ftrace_func_t func)
|
||||
|
||||
ret = ftrace_modify_code(pc, 0, new, false);
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||
if (!ret) {
|
||||
pc = (unsigned long)&ftrace_regs_call;
|
||||
new = ftrace_call_replace(pc, (unsigned long)func);
|
||||
|
||||
ret = ftrace_modify_code(pc, 0, new, false);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_OLD_MCOUNT
|
||||
if (!ret) {
|
||||
pc = (unsigned long)&ftrace_call_old;
|
||||
@@ -159,11 +168,29 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr)
|
||||
unsigned long ip = rec->ip;
|
||||
|
||||
old = ftrace_nop_replace(rec);
|
||||
|
||||
new = ftrace_call_replace(ip, adjust_address(rec, addr));
|
||||
|
||||
return ftrace_modify_code(rec->ip, old, new, true);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||
|
||||
int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr,
|
||||
unsigned long addr)
|
||||
{
|
||||
unsigned long new, old;
|
||||
unsigned long ip = rec->ip;
|
||||
|
||||
old = ftrace_call_replace(ip, adjust_address(rec, old_addr));
|
||||
|
||||
new = ftrace_call_replace(ip, adjust_address(rec, addr));
|
||||
|
||||
return ftrace_modify_code(rec->ip, old, new, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ftrace_make_nop(struct module *mod,
|
||||
struct dyn_ftrace *rec, unsigned long addr)
|
||||
{
|
||||
@@ -231,6 +258,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
|
||||
extern unsigned long ftrace_graph_call;
|
||||
extern unsigned long ftrace_graph_call_old;
|
||||
extern void ftrace_graph_caller_old(void);
|
||||
extern unsigned long ftrace_graph_regs_call;
|
||||
extern void ftrace_graph_regs_caller(void);
|
||||
|
||||
static int __ftrace_modify_caller(unsigned long *callsite,
|
||||
void (*func) (void), bool enable)
|
||||
@@ -253,6 +282,14 @@ static int ftrace_modify_graph_caller(bool enable)
|
||||
ftrace_graph_caller,
|
||||
enable);
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS
|
||||
if (!ret)
|
||||
ret = __ftrace_modify_caller(&ftrace_graph_regs_call,
|
||||
ftrace_graph_regs_caller,
|
||||
enable);
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_OLD_MCOUNT
|
||||
if (!ret)
|
||||
ret = __ftrace_modify_caller(&ftrace_graph_call_old,
|
||||
|
Reference in New Issue
Block a user