Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[safe/jmp/linux-2.6] / kernel / trace / trace_kprobe.c
index 465b36b..505c922 100644 (file)
@@ -91,11 +91,6 @@ static __kprobes unsigned long fetch_memory(struct pt_regs *regs, void *addr)
        return retval;
 }
 
-static __kprobes unsigned long fetch_argument(struct pt_regs *regs, void *num)
-{
-       return regs_get_argument_nth(regs, (unsigned int)((unsigned long)num));
-}
-
 static __kprobes unsigned long fetch_retvalue(struct pt_regs *regs,
                                              void *dummy)
 {
@@ -231,9 +226,7 @@ static int probe_arg_string(char *buf, size_t n, struct fetch_func *ff)
 {
        int ret = -EINVAL;
 
-       if (ff->func == fetch_argument)
-               ret = snprintf(buf, n, "$arg%lu", (unsigned long)ff->data);
-       else if (ff->func == fetch_register) {
+       if (ff->func == fetch_register) {
                const char *name;
                name = regs_query_register_name((unsigned int)((long)ff->data));
                ret = snprintf(buf, n, "%%%s", name);
@@ -489,14 +482,6 @@ static int parse_probe_vars(char *arg, struct fetch_func *ff, int is_return)
                        }
                } else
                        ret = -EINVAL;
-       } else if (strncmp(arg, "arg", 3) == 0 && isdigit(arg[3])) {
-               ret = strict_strtoul(arg + 3, 10, &param);
-               if (ret || param > PARAM_MAX_ARGS)
-                       ret = -EINVAL;
-               else {
-                       ff->func = fetch_argument;
-                       ff->data = (void *)param;
-               }
        } else
                ret = -EINVAL;
        return ret;
@@ -611,7 +596,6 @@ static int create_trace_probe(int argc, char **argv)
         *  - Add kprobe: p[:[GRP/]EVENT] KSYM[+OFFS]|KADDR [FETCHARGS]
         *  - Add kretprobe: r[:[GRP/]EVENT] KSYM[+0] [FETCHARGS]
         * Fetch args:
-        *  $argN       : fetch Nth of function argument. (N:0-)
         *  $retval     : fetch return value
         *  $stack      : fetch stack address
         *  $stackN     : fetch Nth of stack (N:0-)
@@ -958,7 +942,7 @@ static const struct file_operations kprobe_profile_ops = {
 };
 
 /* Kprobe handler */
-static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
+static __kprobes void kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
 {
        struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
        struct kprobe_trace_entry *entry;
@@ -978,7 +962,7 @@ static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
        event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
                                                  irq_flags, pc);
        if (!event)
-               return 0;
+               return;
 
        entry = ring_buffer_event_data(event);
        entry->nargs = tp->nr_args;
@@ -988,11 +972,10 @@ static __kprobes int kprobe_trace_func(struct kprobe *kp, struct pt_regs *regs)
 
        if (!filter_current_check_discard(buffer, call, entry, event))
                trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
-       return 0;
 }
 
 /* Kretprobe handler */
-static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri,
+static __kprobes void kretprobe_trace_func(struct kretprobe_instance *ri,
                                          struct pt_regs *regs)
 {
        struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
@@ -1011,7 +994,7 @@ static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri,
        event = trace_current_buffer_lock_reserve(&buffer, call->id, size,
                                                  irq_flags, pc);
        if (!event)
-               return 0;
+               return;
 
        entry = ring_buffer_event_data(event);
        entry->nargs = tp->nr_args;
@@ -1022,8 +1005,6 @@ static __kprobes int kretprobe_trace_func(struct kretprobe_instance *ri,
 
        if (!filter_current_check_discard(buffer, call, entry, event))
                trace_nowake_buffer_unlock_commit(buffer, event, irq_flags, pc);
-
-       return 0;
 }
 
 /* Event entry printers */
@@ -1230,137 +1211,67 @@ static int set_print_fmt(struct trace_probe *tp)
        return 0;
 }
 
-#ifdef CONFIG_EVENT_PROFILE
+#ifdef CONFIG_PERF_EVENTS
 
 /* Kprobe profile handler */
-static __kprobes int kprobe_profile_func(struct kprobe *kp,
+static __kprobes void kprobe_profile_func(struct kprobe *kp,
                                         struct pt_regs *regs)
 {
        struct trace_probe *tp = container_of(kp, struct trace_probe, rp.kp);
        struct ftrace_event_call *call = &tp->call;
        struct kprobe_trace_entry *entry;
-       struct trace_entry *ent;
-       int size, __size, i, pc, __cpu;
+       int size, __size, i;
        unsigned long irq_flags;
-       char *trace_buf;
-       char *raw_data;
        int rctx;
 
-       pc = preempt_count();
        __size = SIZEOF_KPROBE_TRACE_ENTRY(tp->nr_args);
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
        if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
                     "profile buffer not large enough"))
-               return 0;
-
-       /*
-        * Protect the non nmi buffer
-        * This also protects the rcu read side
-        */
-       local_irq_save(irq_flags);
+               return;
 
-       rctx = perf_swevent_get_recursion_context();
-       if (rctx < 0)
-               goto end_recursion;
-
-       __cpu = smp_processor_id();
-
-       if (in_nmi())
-               trace_buf = rcu_dereference(perf_trace_buf_nmi);
-       else
-               trace_buf = rcu_dereference(perf_trace_buf);
-
-       if (!trace_buf)
-               goto end;
-
-       raw_data = per_cpu_ptr(trace_buf, __cpu);
-
-       /* Zero dead bytes from alignment to avoid buffer leak to userspace */
-       *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
-       entry = (struct kprobe_trace_entry *)raw_data;
-       ent = &entry->ent;
+       entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags);
+       if (!entry)
+               return;
 
-       tracing_generic_entry_update(ent, irq_flags, pc);
-       ent->type = call->id;
        entry->nargs = tp->nr_args;
        entry->ip = (unsigned long)kp->addr;
        for (i = 0; i < tp->nr_args; i++)
                entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
-       perf_tp_event(call->id, entry->ip, 1, entry, size);
 
-end:
-       perf_swevent_put_recursion_context(rctx);
-end_recursion:
-       local_irq_restore(irq_flags);
-
-       return 0;
+       ftrace_perf_buf_submit(entry, size, rctx, entry->ip, 1, irq_flags);
 }
 
 /* Kretprobe profile handler */
-static __kprobes int kretprobe_profile_func(struct kretprobe_instance *ri,
+static __kprobes void kretprobe_profile_func(struct kretprobe_instance *ri,
                                            struct pt_regs *regs)
 {
        struct trace_probe *tp = container_of(ri->rp, struct trace_probe, rp);
        struct ftrace_event_call *call = &tp->call;
        struct kretprobe_trace_entry *entry;
-       struct trace_entry *ent;
-       int size, __size, i, pc, __cpu;
+       int size, __size, i;
        unsigned long irq_flags;
-       char *trace_buf;
-       char *raw_data;
        int rctx;
 
-       pc = preempt_count();
        __size = SIZEOF_KRETPROBE_TRACE_ENTRY(tp->nr_args);
        size = ALIGN(__size + sizeof(u32), sizeof(u64));
        size -= sizeof(u32);
        if (WARN_ONCE(size > FTRACE_MAX_PROFILE_SIZE,
                     "profile buffer not large enough"))
-               return 0;
-
-       /*
-        * Protect the non nmi buffer
-        * This also protects the rcu read side
-        */
-       local_irq_save(irq_flags);
-
-       rctx = perf_swevent_get_recursion_context();
-       if (rctx < 0)
-               goto end_recursion;
-
-       __cpu = smp_processor_id();
-
-       if (in_nmi())
-               trace_buf = rcu_dereference(perf_trace_buf_nmi);
-       else
-               trace_buf = rcu_dereference(perf_trace_buf);
-
-       if (!trace_buf)
-               goto end;
-
-       raw_data = per_cpu_ptr(trace_buf, __cpu);
+               return;
 
-       /* Zero dead bytes from alignment to avoid buffer leak to userspace */
-       *(u64 *)(&raw_data[size - sizeof(u64)]) = 0ULL;
-       entry = (struct kretprobe_trace_entry *)raw_data;
-       ent = &entry->ent;
+       entry = ftrace_perf_buf_prepare(size, call->id, &rctx, &irq_flags);
+       if (!entry)
+               return;
 
-       tracing_generic_entry_update(ent, irq_flags, pc);
-       ent->type = call->id;
        entry->nargs = tp->nr_args;
        entry->func = (unsigned long)tp->rp.kp.addr;
        entry->ret_ip = (unsigned long)ri->ret_addr;
        for (i = 0; i < tp->nr_args; i++)
                entry->args[i] = call_fetch(&tp->args[i].fetch, regs);
-       perf_tp_event(call->id, entry->ret_ip, 1, entry, size);
-
-end:
-       perf_swevent_put_recursion_context(rctx);
-end_recursion:
-       local_irq_restore(irq_flags);
 
-       return 0;
+       ftrace_perf_buf_submit(entry, size, rctx, entry->ret_ip, 1, irq_flags);
 }
 
 static int probe_profile_enable(struct ftrace_event_call *call)
@@ -1388,7 +1299,7 @@ static void probe_profile_disable(struct ftrace_event_call *call)
                        disable_kprobe(&tp->rp.kp);
        }
 }
-#endif /* CONFIG_EVENT_PROFILE */
+#endif /* CONFIG_PERF_EVENTS */
 
 
 static __kprobes
@@ -1398,10 +1309,10 @@ int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
 
        if (tp->flags & TP_FLAG_TRACE)
                kprobe_trace_func(kp, regs);
-#ifdef CONFIG_EVENT_PROFILE
+#ifdef CONFIG_PERF_EVENTS
        if (tp->flags & TP_FLAG_PROFILE)
                kprobe_profile_func(kp, regs);
-#endif /* CONFIG_EVENT_PROFILE */
+#endif
        return 0;       /* We don't tweek kernel, so just return 0 */
 }
 
@@ -1412,10 +1323,10 @@ int kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
 
        if (tp->flags & TP_FLAG_TRACE)
                kretprobe_trace_func(ri, regs);
-#ifdef CONFIG_EVENT_PROFILE
+#ifdef CONFIG_PERF_EVENTS
        if (tp->flags & TP_FLAG_PROFILE)
                kretprobe_profile_func(ri, regs);
-#endif /* CONFIG_EVENT_PROFILE */
+#endif
        return 0;       /* We don't tweek kernel, so just return 0 */
 }
 
@@ -1446,7 +1357,7 @@ static int register_probe_event(struct trace_probe *tp)
        call->regfunc = probe_event_enable;
        call->unregfunc = probe_event_disable;
 
-#ifdef CONFIG_EVENT_PROFILE
+#ifdef CONFIG_PERF_EVENTS
        call->profile_enable = probe_profile_enable;
        call->profile_disable = probe_profile_disable;
 #endif
@@ -1507,28 +1418,67 @@ static int kprobe_trace_selftest_target(int a1, int a2, int a3,
 
 static __init int kprobe_trace_self_tests_init(void)
 {
-       int ret;
+       int ret, warn = 0;
        int (*target)(int, int, int, int, int, int);
+       struct trace_probe *tp;
 
        target = kprobe_trace_selftest_target;
 
        pr_info("Testing kprobe tracing: ");
 
        ret = command_trace_probe("p:testprobe kprobe_trace_selftest_target "
-                                 "$arg1 $arg2 $arg3 $arg4 $stack $stack0");
-       if (WARN_ON_ONCE(ret))
-               pr_warning("error enabling function entry\n");
+                                 "$stack $stack0 +0($stack)");
+       if (WARN_ON_ONCE(ret)) {
+               pr_warning("error on probing function entry.\n");
+               warn++;
+       } else {
+               /* Enable trace point */
+               tp = find_probe_event("testprobe", KPROBE_EVENT_SYSTEM);
+               if (WARN_ON_ONCE(tp == NULL)) {
+                       pr_warning("error on getting new probe.\n");
+                       warn++;
+               } else
+                       probe_event_enable(&tp->call);
+       }
 
        ret = command_trace_probe("r:testprobe2 kprobe_trace_selftest_target "
                                  "$retval");
-       if (WARN_ON_ONCE(ret))
-               pr_warning("error enabling function return\n");
+       if (WARN_ON_ONCE(ret)) {
+               pr_warning("error on probing function return.\n");
+               warn++;
+       } else {
+               /* Enable trace point */
+               tp = find_probe_event("testprobe2", KPROBE_EVENT_SYSTEM);
+               if (WARN_ON_ONCE(tp == NULL)) {
+                       pr_warning("error on getting new probe.\n");
+                       warn++;
+               } else
+                       probe_event_enable(&tp->call);
+       }
+
+       if (warn)
+               goto end;
 
        ret = target(1, 2, 3, 4, 5, 6);
 
-       cleanup_all_probes();
+       ret = command_trace_probe("-:testprobe");
+       if (WARN_ON_ONCE(ret)) {
+               pr_warning("error on deleting a probe.\n");
+               warn++;
+       }
+
+       ret = command_trace_probe("-:testprobe2");
+       if (WARN_ON_ONCE(ret)) {
+               pr_warning("error on deleting a probe.\n");
+               warn++;
+       }
 
-       pr_cont("OK\n");
+end:
+       cleanup_all_probes();
+       if (warn)
+               pr_cont("NG: Some tests are failed. Please check them.\n");
+       else
+               pr_cont("OK\n");
        return 0;
 }