tracing, perf: Implement BPF programs attached to uprobes
authorWang Nan <wangnan0@huawei.com>
Wed, 1 Jul 2015 02:13:50 +0000 (02:13 +0000)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 6 Aug 2015 18:29:14 +0000 (15:29 -0300)
By copying BPF related operation to uprobe processing path, this patch
allow users attach BPF programs to uprobes like what they are already
doing on kprobes.

After this patch, users are allowed to use PERF_EVENT_IOC_SET_BPF on a
uprobe perf event. Which make it possible to profile user space programs
and kernel events together using BPF.

Because of this patch, CONFIG_BPF_EVENTS should be selected by
CONFIG_UPROBE_EVENT to ensure trace_call_bpf() is compiled even if
KPROBE_EVENT is not set.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: David Ahern <dsahern@gmail.com>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kaixu Xia <xiakaixu@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1435716878-189507-3-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
include/linux/trace_events.h
kernel/events/core.c
kernel/trace/Kconfig
kernel/trace/trace_uprobe.c

index 180dbf8720f9d99054ee0e95beaea8a50a501391..ed27917cabc9d95ff3b30b115f1f661626edba17 100644 (file)
@@ -243,6 +243,7 @@ enum {
        TRACE_EVENT_FL_USE_CALL_FILTER_BIT,
        TRACE_EVENT_FL_TRACEPOINT_BIT,
        TRACE_EVENT_FL_KPROBE_BIT,
+       TRACE_EVENT_FL_UPROBE_BIT,
 };
 
 /*
@@ -257,6 +258,7 @@ enum {
  *  USE_CALL_FILTER - For trace internal events, don't use file filter
  *  TRACEPOINT    - Event is a tracepoint
  *  KPROBE        - Event is a kprobe
+ *  UPROBE        - Event is a uprobe
  */
 enum {
        TRACE_EVENT_FL_FILTERED         = (1 << TRACE_EVENT_FL_FILTERED_BIT),
@@ -267,8 +269,11 @@ enum {
        TRACE_EVENT_FL_USE_CALL_FILTER  = (1 << TRACE_EVENT_FL_USE_CALL_FILTER_BIT),
        TRACE_EVENT_FL_TRACEPOINT       = (1 << TRACE_EVENT_FL_TRACEPOINT_BIT),
        TRACE_EVENT_FL_KPROBE           = (1 << TRACE_EVENT_FL_KPROBE_BIT),
+       TRACE_EVENT_FL_UPROBE           = (1 << TRACE_EVENT_FL_UPROBE_BIT),
 };
 
+#define TRACE_EVENT_FL_UKPROBE (TRACE_EVENT_FL_KPROBE | TRACE_EVENT_FL_UPROBE)
+
 struct trace_event_call {
        struct list_head        list;
        struct trace_event_class *class;
index bdea12924b111faa2647038e93b051e365887c16..77f9e5d0e2d17d4b11ce0209311f4fe783a07db3 100644 (file)
@@ -6846,8 +6846,8 @@ static int perf_event_set_bpf_prog(struct perf_event *event, u32 prog_fd)
        if (event->tp_event->prog)
                return -EEXIST;
 
-       if (!(event->tp_event->flags & TRACE_EVENT_FL_KPROBE))
-               /* bpf programs can only be attached to kprobes */
+       if (!(event->tp_event->flags & TRACE_EVENT_FL_UKPROBE))
+               /* bpf programs can only be attached to u/kprobes */
                return -EINVAL;
 
        prog = bpf_prog_get(prog_fd);
index 3b9a48ae153ac85c5f601b03ef64c7e9d49f153c..1153c43428f3b51d43aba2e8df21950d9029ab04 100644 (file)
@@ -434,7 +434,7 @@ config UPROBE_EVENT
 
 config BPF_EVENTS
        depends on BPF_SYSCALL
-       depends on KPROBE_EVENT
+       depends on KPROBE_EVENT || UPROBE_EVENT
        bool
        default y
        help
index aa1ea7b36fa889877bb790831a01a8d14b472221..f97479f1ce3523783df853d4fd0f2c76ba4ae129 100644 (file)
@@ -1095,11 +1095,15 @@ static void __uprobe_perf_func(struct trace_uprobe *tu,
 {
        struct trace_event_call *call = &tu->tp.call;
        struct uprobe_trace_entry_head *entry;
+       struct bpf_prog *prog = call->prog;
        struct hlist_head *head;
        void *data;
        int size, esize;
        int rctx;
 
+       if (prog && !trace_call_bpf(prog, regs))
+               return;
+
        esize = SIZEOF_TRACE_ENTRY(is_ret_probe(tu));
 
        size = esize + tu->tp.size + dsize;
@@ -1289,6 +1293,7 @@ static int register_uprobe_event(struct trace_uprobe *tu)
                return -ENODEV;
        }
 
+       call->flags = TRACE_EVENT_FL_UPROBE;
        call->class->reg = trace_uprobe_register;
        call->data = tu;
        ret = trace_add_event_call(call);