ftrace: Have global_ops store the functions that are to be traced
[linux-2.6.git] / kernel / trace / trace_syscalls.c
index d2c859c..ee7b5a0 100644 (file)
@@ -31,63 +31,66 @@ syscall_get_enter_fields(struct ftrace_event_call *call)
        return &entry->enter_fields;
 }
 
-static struct list_head *
-syscall_get_exit_fields(struct ftrace_event_call *call)
-{
-       struct syscall_metadata *entry = call->data;
-
-       return &entry->exit_fields;
-}
-
 struct trace_event_functions enter_syscall_print_funcs = {
-       .trace                  = print_syscall_enter,
+       .trace          = print_syscall_enter,
 };
 
 struct trace_event_functions exit_syscall_print_funcs = {
-       .trace                  = print_syscall_exit,
+       .trace          = print_syscall_exit,
 };
 
 struct ftrace_event_class event_class_syscall_enter = {
-       .system                 = "syscalls",
-       .reg                    = syscall_enter_register,
-       .define_fields          = syscall_enter_define_fields,
-       .get_fields             = syscall_get_enter_fields,
-       .raw_init               = init_syscall_trace,
+       .system         = "syscalls",
+       .reg            = syscall_enter_register,
+       .define_fields  = syscall_enter_define_fields,
+       .get_fields     = syscall_get_enter_fields,
+       .raw_init       = init_syscall_trace,
 };
 
 struct ftrace_event_class event_class_syscall_exit = {
-       .system                 = "syscalls",
-       .reg                    = syscall_exit_register,
-       .define_fields          = syscall_exit_define_fields,
-       .get_fields             = syscall_get_exit_fields,
-       .raw_init               = init_syscall_trace,
+       .system         = "syscalls",
+       .reg            = syscall_exit_register,
+       .define_fields  = syscall_exit_define_fields,
+       .fields         = LIST_HEAD_INIT(event_class_syscall_exit.fields),
+       .raw_init       = init_syscall_trace,
 };
 
-extern unsigned long __start_syscalls_metadata[];
-extern unsigned long __stop_syscalls_metadata[];
+extern struct syscall_metadata *__start_syscalls_metadata[];
+extern struct syscall_metadata *__stop_syscalls_metadata[];
 
 static struct syscall_metadata **syscalls_metadata;
 
-static struct syscall_metadata *find_syscall_meta(unsigned long syscall)
+#ifndef ARCH_HAS_SYSCALL_MATCH_SYM_NAME
+static inline bool arch_syscall_match_sym_name(const char *sym, const char *name)
 {
-       struct syscall_metadata *start;
-       struct syscall_metadata *stop;
+       /*
+        * Only compare after the "sys" prefix. Archs that use
+        * syscall wrappers may have syscalls symbols aliases prefixed
+        * with "SyS" instead of "sys", leading to an unwanted
+        * mismatch.
+        */
+       return !strcmp(sym + 3, name + 3);
+}
+#endif
+
+static __init struct syscall_metadata *
+find_syscall_meta(unsigned long syscall)
+{
+       struct syscall_metadata **start;
+       struct syscall_metadata **stop;
        char str[KSYM_SYMBOL_LEN];
 
 
-       start = (struct syscall_metadata *)__start_syscalls_metadata;
-       stop = (struct syscall_metadata *)__stop_syscalls_metadata;
+       start = __start_syscalls_metadata;
+       stop = __stop_syscalls_metadata;
        kallsyms_lookup(syscall, NULL, NULL, NULL, str);
 
+       if (arch_syscall_match_sym_name(str, "sys_ni_syscall"))
+               return NULL;
+
        for ( ; start < stop; start++) {
-               /*
-                * Only compare after the "sys" prefix. Archs that use
-                * syscall wrappers may have syscalls symbols aliases prefixed
-                * with "SyS" instead of "sys", leading to an unwanted
-                * mismatch.
-                */
-               if (start->name && !strcmp(start->name + 3, str + 3))
-                       return start;
+               if ((*start)->name && arch_syscall_match_sym_name(str, (*start)->name))
+                       return *start;
        }
        return NULL;
 }
@@ -366,7 +369,7 @@ int reg_event_syscall_enter(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_enter)
@@ -384,7 +387,7 @@ void unreg_event_syscall_enter(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return;
        mutex_lock(&syscall_trace_lock);
        sys_refcount_enter--;
@@ -400,7 +403,7 @@ int reg_event_syscall_exit(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return -ENOSYS;
        mutex_lock(&syscall_trace_lock);
        if (!sys_refcount_exit)
@@ -418,7 +421,7 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
        int num;
 
        num = ((struct syscall_metadata *)call->data)->syscall_nr;
-       if (num < 0 || num >= NR_syscalls)
+       if (WARN_ON_ONCE(num < 0 || num >= NR_syscalls))
                return;
        mutex_lock(&syscall_trace_lock);
        sys_refcount_exit--;
@@ -431,6 +434,14 @@ void unreg_event_syscall_exit(struct ftrace_event_call *call)
 int init_syscall_trace(struct ftrace_event_call *call)
 {
        int id;
+       int num;
+
+       num = ((struct syscall_metadata *)call->data)->syscall_nr;
+       if (num < 0 || num >= NR_syscalls) {
+               pr_debug("syscall %s metadata not mapped, disabling ftrace event\n",
+                               ((struct syscall_metadata *)call->data)->name);
+               return -ENOSYS;
+       }
 
        if (set_syscall_print_fmt(call) < 0)
                return -ENOMEM;
@@ -445,7 +456,7 @@ int init_syscall_trace(struct ftrace_event_call *call)
        return id;
 }
 
-unsigned long __init arch_syscall_addr(int nr)
+unsigned long __init __weak arch_syscall_addr(int nr)
 {
        return (unsigned long)sys_call_table[nr];
 }
@@ -519,7 +530,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
        syscall_get_arguments(current, regs, 0, sys_data->nb_args,
                               (unsigned long *)&rec->args);
 
-       head = per_cpu_ptr(sys_data->enter_event->perf_events, smp_processor_id());
+       head = this_cpu_ptr(sys_data->enter_event->perf_events);
        perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
 }
 
@@ -595,7 +606,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
        rec->nr = syscall_nr;
        rec->ret = syscall_get_return_value(current, regs);
 
-       head = per_cpu_ptr(sys_data->exit_event->perf_events, smp_processor_id());
+       head = this_cpu_ptr(sys_data->exit_event->perf_events);
        perf_trace_buf_submit(rec, size, rctx, 0, 1, regs, head);
 }