diff options
Diffstat (limited to 'arch/parisc/kernel/ftrace.c')
-rw-r--r-- | arch/parisc/kernel/ftrace.c | 78 |
1 files changed, 78 insertions, 0 deletions
diff --git a/arch/parisc/kernel/ftrace.c b/arch/parisc/kernel/ftrace.c new file mode 100644 index 000000000..e46a4157a --- /dev/null +++ b/arch/parisc/kernel/ftrace.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Code for tracing calls in Linux kernel. + * Copyright (C) 2009-2016 Helge Deller <deller@gmx.de> + * + * based on code for x86 which is: + * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com> + * + * future possible enhancements: + * - add CONFIG_DYNAMIC_FTRACE + * - add CONFIG_STACK_TRACER + */ + +#include <linux/init.h> +#include <linux/ftrace.h> + +#include <asm/assembly.h> +#include <asm/sections.h> +#include <asm/ftrace.h> + + +#define __hot __attribute__ ((__section__ (".text.hot"))) + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER +/* + * Hook the return address and push it in the stack of return addrs + * in current thread info. + */ +static void __hot prepare_ftrace_return(unsigned long *parent, + unsigned long self_addr) +{ + unsigned long old; + extern int parisc_return_to_handler; + + if (unlikely(ftrace_graph_is_dead())) + return; + + if (unlikely(atomic_read(¤t->tracing_graph_pause))) + return; + + old = *parent; + + if (!function_graph_enter(old, self_addr, 0, NULL)) + /* activate parisc_return_to_handler() as return point */ + *parent = (unsigned long) &parisc_return_to_handler; +} +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ + +void notrace __hot ftrace_function_trampoline(unsigned long parent, + unsigned long self_addr, + unsigned long org_sp_gr3) +{ + extern ftrace_func_t ftrace_trace_function; /* depends on CONFIG_DYNAMIC_FTRACE */ + extern int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace); + + if (ftrace_trace_function != ftrace_stub) { + /* struct ftrace_ops *op, struct pt_regs *regs); */ + ftrace_trace_function(parent, self_addr, NULL, NULL); + return; + } + +#ifdef CONFIG_FUNCTION_GRAPH_TRACER + if (ftrace_graph_return != (trace_func_graph_ret_t) ftrace_stub || + ftrace_graph_entry != ftrace_graph_entry_stub) { + unsigned long *parent_rp; + + /* calculate pointer to %rp in stack */ + parent_rp = (unsigned long *) (org_sp_gr3 - RP_OFFSET); + /* sanity check: parent_rp should hold parent */ + if (*parent_rp != parent) + return; + + prepare_ftrace_return(parent_rp, self_addr); + return; + } +#endif +} + |