summaryrefslogtreecommitdiff
path: root/arch/powerpc/kernel/ftrace.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel/ftrace.c')
-rw-r--r--arch/powerpc/kernel/ftrace.c47
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.