diff options
Diffstat (limited to 'arch/powerpc/kernel/ftrace.c')
-rw-r--r-- | arch/powerpc/kernel/ftrace.c | 47 |
1 files changed, 41 insertions, 6 deletions
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c index c9b1547f65a5..7538b944fa52 100644 --- a/arch/powerpc/kernel/ftrace.c +++ b/arch/powerpc/kernel/ftrace.c @@ -43,7 +43,8 @@ static unsigned char *ftrace_nop_replace(void) return (char *)&ftrace_nop; } -static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) +static unsigned char * +ftrace_call_replace(unsigned long ip, unsigned long addr, int link) { static unsigned int op; @@ -55,8 +56,9 @@ static unsigned char *ftrace_call_replace(unsigned long ip, unsigned long addr) */ addr = GET_ADDR(addr); - /* Set to "bl addr" */ - op = 0x48000001 | (ftrace_calc_offset(ip, addr) & 0x03fffffc); + /* if (link) set op to 'bl' else 'b' */ + op = 0x48000000 | (link ? 1 : 0); + op |= (ftrace_calc_offset(ip, addr) & 0x03fffffc); /* * No locking needed, this must be called via kstop_machine @@ -344,7 +346,7 @@ int ftrace_make_nop(struct module *mod, */ if (test_24bit_addr(ip, addr)) { /* within range */ - old = ftrace_call_replace(ip, addr); + old = ftrace_call_replace(ip, addr, 1); new = ftrace_nop_replace(); return ftrace_modify_code(ip, old, new); } @@ -484,7 +486,7 @@ int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) if (test_24bit_addr(ip, addr)) { /* within range */ old = ftrace_nop_replace(); - new = ftrace_call_replace(ip, addr); + new = ftrace_call_replace(ip, addr, 1); return ftrace_modify_code(ip, old, new); } @@ -513,7 +515,7 @@ int ftrace_update_ftrace_func(ftrace_func_t func) int ret; memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); - new = ftrace_call_replace(ip, (unsigned long)func); + new = ftrace_call_replace(ip, (unsigned long)func, 1); ret = ftrace_modify_code(ip, old, new); return ret; @@ -532,6 +534,39 @@ int __init ftrace_dyn_arch_init(void *data) #ifdef CONFIG_FUNCTION_GRAPH_TRACER +#ifdef CONFIG_DYNAMIC_FTRACE +extern void ftrace_graph_call(void); +extern void ftrace_graph_stub(void); + +int ftrace_enable_ftrace_graph_caller(void) +{ + unsigned long ip = (unsigned long)(&ftrace_graph_call); + unsigned long addr = (unsigned long)(&ftrace_graph_caller); + unsigned long stub = (unsigned long)(&ftrace_graph_stub); + unsigned char old[MCOUNT_INSN_SIZE], *new; + + new = ftrace_call_replace(ip, stub, 0); + memcpy(old, new, MCOUNT_INSN_SIZE); + new = ftrace_call_replace(ip, addr, 0); + + return ftrace_modify_code(ip, old, new); +} + +int ftrace_disable_ftrace_graph_caller(void) +{ + unsigned long ip = (unsigned long)(&ftrace_graph_call); + unsigned long addr = (unsigned long)(&ftrace_graph_caller); + unsigned long stub = (unsigned long)(&ftrace_graph_stub); + unsigned char old[MCOUNT_INSN_SIZE], *new; + + new = ftrace_call_replace(ip, addr, 0); + memcpy(old, new, MCOUNT_INSN_SIZE); + new = ftrace_call_replace(ip, stub, 0); + + return ftrace_modify_code(ip, old, new); +} +#endif /* CONFIG_DYNAMIC_FTRACE */ + /* * Hook the return address and push it in the stack of return addrs * in current thread info. |