Messages in this thread Patch in this message | | | From | Masami Hiramatsu <> | Subject | [PATCH -tip v2 1/9] ftrace: Add pt_regs acceptable trace callback | Date | Tue, 05 Jun 2012 19:27:50 +0900 |
| |
Add a new callback interface regs_func to ftrace_ops which is an anonymous union to share the pointer with func member. So, current ftrace user doesn't need to change their callbacks. This callback must be used with FTRACE_OPS_FL_SAVE_REGS.
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: Steven Rostedt <rostedt@goodmis.org> ---
include/linux/ftrace.h | 21 ++++++++++++++++++++- kernel/trace/ftrace.c | 44 +++++++++++++++++++++++++++++++------------- 2 files changed, 51 insertions(+), 14 deletions(-)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 55e6d63..11abe4e 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -10,6 +10,8 @@ #include <linux/kallsyms.h> #include <linux/linkage.h> #include <linux/bitops.h> +#include <linux/module.h> +#include <linux/ptrace.h> #include <linux/ktime.h> #include <linux/sched.h> #include <linux/types.h> @@ -18,6 +20,14 @@ #include <asm/ftrace.h> +/* + * If the arch supports saving the regs to the ftrace_ops + * then it should set this to 1. + */ +#ifndef ARCH_SUPPORTS_FTRACE_SAVE_REGS +#define ARCH_SUPPORTS_FTRACE_SAVE_REGS 0 +#endif + struct module; struct ftrace_hash; @@ -30,6 +40,8 @@ ftrace_enable_sysctl(struct ctl_table *table, int write, loff_t *ppos); typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); +typedef void (*ftrace_regs_func_t)(unsigned long ip, unsigned long parent_ip, + struct pt_regs *regs); /* * FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are @@ -45,16 +57,22 @@ typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip); * could be controled by following calls: * ftrace_function_local_enable * ftrace_function_local_disable + * SAVE_REGS - set manualy by ftrace_ops user to denote the ftrace_ops + * requests to pass pt_regs to callback. */ enum { FTRACE_OPS_FL_ENABLED = 1 << 0, FTRACE_OPS_FL_GLOBAL = 1 << 1, FTRACE_OPS_FL_DYNAMIC = 1 << 2, FTRACE_OPS_FL_CONTROL = 1 << 3, + FTRACE_OPS_FL_SAVE_REGS = 1 << 4, }; struct ftrace_ops { - ftrace_func_t func; + union { + ftrace_func_t func; + ftrace_regs_func_t regs_func; + }; struct ftrace_ops *next; unsigned long flags; int __percpu *disabled; @@ -164,6 +182,7 @@ static inline int ftrace_function_local_disabled(struct ftrace_ops *ops) } extern void ftrace_stub(unsigned long a0, unsigned long a1); +#define ftrace_regs_stub (ftrace_regs_func_t)(ftrace_stub) #else /* !CONFIG_FUNCTION_TRACER */ /* diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index a008663..357b15b 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -101,7 +101,9 @@ static struct ftrace_ops global_ops; static struct ftrace_ops control_ops; static void -ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip); +ftrace_ops_list_regs_func(unsigned long ip, unsigned long parent_ip, + struct pt_regs *regs); +#define ftrace_ops_list_func (ftrace_func_t)(ftrace_ops_list_regs_func) /* * Traverse the ftrace_global_list, invoking all entries. The reason that we @@ -112,8 +114,9 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip); * * Silly Alpha and silly pointer-speculation compiler optimizations! */ -static void ftrace_global_list_func(unsigned long ip, - unsigned long parent_ip) +static void +ftrace_global_list_regs_func(unsigned long ip, unsigned long parent_ip, + struct pt_regs *regs) { struct ftrace_ops *op; @@ -123,19 +126,24 @@ static void ftrace_global_list_func(unsigned long ip, trace_recursion_set(TRACE_GLOBAL_BIT); op = rcu_dereference_raw(ftrace_global_list); /*see above*/ while (op != &ftrace_list_end) { - op->func(ip, parent_ip); + op->regs_func(ip, parent_ip, regs); op = rcu_dereference_raw(op->next); /*see above*/ }; trace_recursion_clear(TRACE_GLOBAL_BIT); } +#define ftrace_global_list_func (ftrace_func_t)(ftrace_global_list_regs_func) -static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip) +static void ftrace_pid_regs_func(unsigned long ip, unsigned long parent_ip, + struct pt_regs *regs) { + ftrace_regs_func_t func = (ftrace_regs_func_t)ftrace_pid_function; + if (!test_tsk_trace_trace(current)) return; - ftrace_pid_function(ip, parent_ip); + func(ip, parent_ip, regs); } +#define ftrace_pid_func (ftrace_func_t)(ftrace_pid_regs_func) static void set_ftrace_pid_function(ftrace_func_t func) { @@ -328,6 +336,10 @@ static int __register_ftrace_function(struct ftrace_ops *ops) if (!core_kernel_data((unsigned long)ops)) ops->flags |= FTRACE_OPS_FL_DYNAMIC; + if ((ops->flags & FTRACE_OPS_FL_SAVE_REGS) && + !ARCH_SUPPORTS_FTRACE_SAVE_REGS) + return -ENOSYS; + if (ops->flags & FTRACE_OPS_FL_GLOBAL) { add_ftrace_list_ops(&ftrace_global_list, &global_ops, ops); ops->flags |= FTRACE_OPS_FL_ENABLED; @@ -1042,9 +1054,10 @@ static const struct ftrace_hash empty_hash = { #define EMPTY_HASH ((struct ftrace_hash *)&empty_hash) static struct ftrace_ops global_ops = { - .func = ftrace_stub, + .regs_func = ftrace_regs_stub, .notrace_hash = EMPTY_HASH, .filter_hash = EMPTY_HASH, + .flags = FTRACE_OPS_FL_SAVE_REGS, }; static DEFINE_MUTEX(ftrace_regex_lock); @@ -3911,7 +3924,8 @@ void __init ftrace_init(void) #else static struct ftrace_ops global_ops = { - .func = ftrace_stub, + .regs_func = ftrace_regs_stub, + .flags = FTRACE_OPS_FL_SAVE_REGS, }; static int __init ftrace_nodyn_init(void) @@ -3942,7 +3956,8 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip) #endif /* CONFIG_DYNAMIC_FTRACE */ static void -ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip) +ftrace_ops_control_regs_func(unsigned long ip, unsigned long parent_ip, + struct pt_regs *regs) { struct ftrace_ops *op; @@ -3959,7 +3974,7 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip) while (op != &ftrace_list_end) { if (!ftrace_function_local_disabled(op) && ftrace_ops_test(op, ip)) - op->func(ip, parent_ip); + op->regs_func(ip, parent_ip, regs); op = rcu_dereference_raw(op->next); }; @@ -3968,11 +3983,13 @@ ftrace_ops_control_func(unsigned long ip, unsigned long parent_ip) } static struct ftrace_ops control_ops = { - .func = ftrace_ops_control_func, + .regs_func = ftrace_ops_control_regs_func, + .flags = FTRACE_OPS_FL_SAVE_REGS, }; static void -ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) +ftrace_ops_list_regs_func(unsigned long ip, unsigned long parent_ip, + struct pt_regs *regs) { struct ftrace_ops *op; @@ -3988,7 +4005,8 @@ ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip) op = rcu_dereference_raw(ftrace_ops_list); while (op != &ftrace_list_end) { if (ftrace_ops_test(op, ip)) - op->func(ip, parent_ip); + /* regs will be ignored if op->func is set */ + op->regs_func(ip, parent_ip, regs); op = rcu_dereference_raw(op->next); }; preempt_enable_notrace();
| |