Messages in this thread Patch in this message |  | | | Date | Tue, 2 Feb 2010 16:21:51 -0500 | | From | Jason Baron <> | | Subject | [PATCH 4/6] tracing: add tracing support for compat syscalls |
| |
Add core support to event tracing for compat syscalls. The basic idea is that we check if we have a compat task via 'is_compat_task()'. If so, we lookup in the new compat_syscalls_metadata table, the corresponding struct syscall_metadata, to check syscall arguments and whether or not we are enabled.
Signed-off-by: Jason Baron <jbaron@redhat.com> --- include/linux/compat.h | 8 +++++ include/trace/syscall.h | 4 ++ kernel/trace/trace.h | 2 + kernel/trace/trace_syscalls.c | 63 +++++++++++++++++++++++++++++++++++----- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/include/linux/compat.h b/include/linux/compat.h index ef68119..ab2cda2 100644 --- a/include/linux/compat.h +++ b/include/linux/compat.h @@ -353,5 +353,13 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename, asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename, int flags, int mode); +#else /* CONFIG_COMPAT */ + +#define NR_syscalls_compat 0 +static inline int is_compat_task(void) +{ + return 0; +} + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff --git a/include/trace/syscall.h b/include/trace/syscall.h index 8f5ac38..1cc1d1e 100644 --- a/include/trace/syscall.h +++ b/include/trace/syscall.h @@ -22,6 +22,7 @@ struct syscall_metadata { const char *name; int syscall_nr; + int compat_syscall_nr; int nb_args; const char **types; const char **args; @@ -36,6 +37,9 @@ struct syscall_metadata { #ifdef CONFIG_FTRACE_SYSCALLS extern unsigned long arch_syscall_addr(int nr); +#ifdef CONFIG_COMPAT +extern unsigned long arch_compat_syscall_addr(int nr); +#endif extern int init_syscall_trace(struct ftrace_event_call *call); extern int syscall_enter_define_fields(struct ftrace_event_call *call); diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index ce077fb..0ed0d2e 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -94,12 +94,14 @@ extern struct tracer boot_tracer; struct syscall_trace_enter { struct trace_entry ent; int nr; + int compat; unsigned long args[]; }; struct syscall_trace_exit { struct trace_entry ent; int nr; + int compat; long ret; }; diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c index 8411d6c..6f721be 100644 --- a/kernel/trace/trace_syscalls.c +++ b/kernel/trace/trace_syscalls.c @@ -3,6 +3,7 @@ #include <linux/kernel.h> #include <linux/ftrace.h> #include <linux/perf_event.h> +#include <linux/compat.h> #include <asm/syscall.h> #include "trace_output.h" @@ -16,6 +17,7 @@ extern unsigned long __start_syscalls_metadata[]; extern unsigned long __stop_syscalls_metadata[]; static struct syscall_metadata **syscalls_metadata; +static struct syscall_metadata **compat_syscalls_metadata; static struct syscall_metadata *find_syscall_meta(unsigned long syscall) { @@ -41,8 +43,14 @@ static struct syscall_metadata *find_syscall_meta(unsigned long syscall) return NULL; } -static struct syscall_metadata *syscall_nr_to_meta(int nr) +static struct syscall_metadata *syscall_nr_to_meta(int nr, int compat) { + if (compat) { + if (!compat_syscalls_metadata || nr >= NR_syscalls_compat || + nr < 0) + return NULL; + return compat_syscalls_metadata[nr]; + } if (!syscalls_metadata || nr >= NR_syscalls || nr < 0) return NULL; @@ -60,7 +68,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags) trace = (typeof(trace))ent; syscall = trace->nr; - entry = syscall_nr_to_meta(syscall); + entry = syscall_nr_to_meta(syscall, trace->compat); if (!entry) goto end; @@ -113,7 +121,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags) trace = (typeof(trace))ent; syscall = trace->nr; - entry = syscall_nr_to_meta(syscall); + entry = syscall_nr_to_meta(syscall, trace->compat); if (!entry) { trace_seq_printf(s, "\n"); @@ -248,12 +256,16 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) struct ring_buffer *buffer; int size; int syscall_nr; + int compat = 0; syscall_nr = syscall_get_nr(current, regs); if (syscall_nr < 0) return; - sys_data = syscall_nr_to_meta(syscall_nr); + if (is_compat_task()) + compat = 1; + + sys_data = syscall_nr_to_meta(syscall_nr, compat); if (!sys_data) return; @@ -269,6 +281,7 @@ void ftrace_syscall_enter(struct pt_regs *regs, long id) entry = ring_buffer_event_data(event); entry->nr = syscall_nr; + entry->compat = compat; syscall_get_arguments(current, regs, 0, sys_data->nb_args, entry->args); if (!filter_current_check_discard(buffer, sys_data->enter_event, @@ -283,12 +296,16 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) struct ring_buffer_event *event; struct ring_buffer *buffer; int syscall_nr; + int compat = 0; syscall_nr = syscall_get_nr(current, regs); if (syscall_nr < 0) return; - sys_data = syscall_nr_to_meta(syscall_nr); + if (is_compat_task()) + compat = 1; + + sys_data = syscall_nr_to_meta(syscall_nr, compat); if (!sys_data) return; @@ -302,6 +319,7 @@ void ftrace_syscall_exit(struct pt_regs *regs, long ret) entry = ring_buffer_event_data(event); entry->nr = syscall_nr; + entry->compat = compat; entry->ret = syscall_get_return_value(current, regs); if (!filter_current_check_discard(buffer, sys_data->exit_event, @@ -416,7 +434,26 @@ int __init init_ftrace_syscalls(void) meta->syscall_nr = i; syscalls_metadata[i] = meta; } - +#ifdef CONFIG_COMPAT + if (NR_syscalls_compat) { + compat_syscalls_metadata = kzalloc(sizeof(*syscalls_metadata) * + NR_syscalls_compat, GFP_KERNEL); + if (!compat_syscalls_metadata) { + WARN_ON(1); + kfree(syscalls_metadata); + return -ENOMEM; + } + for (i = 0; i < NR_syscalls_compat; i++) { + addr = arch_compat_syscall_addr(i); + meta = find_syscall_meta(addr); + if (!meta) + continue; + + meta->compat_syscall_nr = i; + compat_syscalls_metadata[i] = meta; + } + } +#endif return 0; } core_initcall(init_ftrace_syscalls); @@ -434,9 +471,13 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) int syscall_nr; int rctx; int size; + int compat = 0; syscall_nr = syscall_get_nr(current, regs); - sys_data = syscall_nr_to_meta(syscall_nr); + if (is_compat_task()) + compat = 1; + + sys_data = syscall_nr_to_meta(syscall_nr, compat); if (!sys_data) return; @@ -458,6 +499,7 @@ static void prof_syscall_enter(struct pt_regs *regs, long id) return; rec->nr = syscall_nr; + rec->compat = compat; syscall_get_arguments(current, regs, 0, sys_data->nb_args, (unsigned long *)&rec->args); ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags); @@ -506,9 +548,13 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) int syscall_nr; int rctx; int size; + int compat = 0; syscall_nr = syscall_get_nr(current, regs); - sys_data = syscall_nr_to_meta(syscall_nr); + if (is_compat_task()) + compat = 1; + + sys_data = syscall_nr_to_meta(syscall_nr, compat); if (!sys_data) return; @@ -533,6 +579,7 @@ static void prof_syscall_exit(struct pt_regs *regs, long ret) return; rec->nr = syscall_nr; + rec->compat = compat; rec->ret = syscall_get_return_value(current, regs); ftrace_perf_buf_submit(rec, size, rctx, 0, 1, flags); -- 1.6.5.1
|  |