@@ -254,6 +254,46 @@ int bpf__load(struct bpf_object *obj)
return 0;
}
+int bpf__foreach_tev(struct bpf_object *obj,
+ bpf_prog_iter_callback_t func,
+ void *arg)
+{
+ struct bpf_program *prog;
+ int err;
+
+ bpf_object__for_each_program(prog, obj) {
+ struct probe_trace_event *tev;
+ struct perf_probe_event *pev;
+ struct bpf_prog_priv *priv;
+ int i, fd;
+
+ err = bpf_program__get_private(prog,
+ (void **)&priv);
+ if (err || !priv) {
+ pr_debug("bpf: failed to get private field\n");
+ return -EINVAL;
+ }
+
+ pev = &priv->pev;
+ for (i = 0; i < pev->ntevs; i++) {
+ tev = &pev->tevs[i];
+
+ fd = bpf_program__fd(prog);
+ if (fd < 0) {
+ pr_debug("bpf: failed to get file descriptor\n");
+ return fd;
+ }
+
+ err = (*func)(tev, fd, arg);
+ if (err) {
+ pr_debug("bpf: call back failed, stop iterate\n");
+ return err;
+ }
+ }
+ }
+ return 0;
+}
+
#define bpf__strerror_head(err, buf, size) \
char sbuf[STRERR_BUFSIZE], *emsg;\
if (!size)\
@@ -8,11 +8,15 @@
#include <linux/compiler.h>
#include <linux/err.h>
#include <string.h>
+#include "probe-event.h"
#include "debug.h"
struct bpf_object;
#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
+typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
+ int fd, void *arg);
+
#ifdef HAVE_LIBBPF_SUPPORT
struct bpf_object *bpf__prepare_load(const char *filename);
@@ -26,6 +30,9 @@ int bpf__strerror_probe(struct bpf_object *obj, int err,
int bpf__load(struct bpf_object *obj);
int bpf__strerror_load(struct bpf_object *obj, int err,
char *buf, size_t size);
+
+int bpf__foreach_tev(struct bpf_object *obj,
+ bpf_prog_iter_callback_t func, void *arg);
#else
static inline struct bpf_object *
bpf__prepare_load(const char *filename __maybe_unused)
@@ -41,6 +48,14 @@ static inline int bpf__unprobe(struct bpf_object *obj __maybe_unused) { return 0
static inline int bpf__load(struct bpf_object *obj __maybe_unused) { return 0; }
static inline int
+bpf__foreach_tev(struct bpf_object *obj __maybe_unused,
+ bpf_prog_iter_callback_t func __maybe_unused,
+ void *arg __maybe_unused)
+{
+ return 0;
+}
+
+static inline int
__bpf_strerror(char *buf, size_t size)
{
if (!size)
@@ -516,6 +516,39 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
return add_tracepoint_event(list, idx, sys, event, error);
}
+struct __add_bpf_event_param {
+ struct parse_events_evlist *data;
+ struct list_head *list;
+};
+
+static int add_bpf_event(struct probe_trace_event *tev, int fd,
+ void *_param)
+{
+ struct __add_bpf_event_param *param = _param;
+ struct parse_events_evlist *evlist = param->data;
+ struct list_head *list = param->list;
+ int err;
+
+ pr_debug("add bpf event %s:%s and attach bpf program %d\n",
+ tev->group, tev->event, fd);
+
+ err = parse_events_add_tracepoint(list, &evlist->idx, tev->group,
+ tev->event, evlist->error);
+ if (err) {
+ struct perf_evsel *evsel, *tmp;
+
+ pr_debug("Failed to add BPF event %s:%s\n",
+ tev->group, tev->event);
+ list_for_each_entry_safe(evsel, tmp, list, node) {
+ list_del(&evsel->node);
+ perf_evsel__delete(evsel);
+ }
+ return err;
+ }
+ pr_debug("adding %s:%s\n", tev->group, tev->event);
+ return 0;
+}
+
int parse_events_load_bpf_obj(struct parse_events_evlist *data,
struct list_head *list,
struct bpf_object *obj)
@@ -523,6 +556,7 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
int err;
char errbuf[BUFSIZ];
static bool registered_unprobe_atexit = false;
+ struct __add_bpf_event_param param = {data, list};
if (IS_ERR(obj) || !obj) {
snprintf(errbuf, sizeof(errbuf),
@@ -548,12 +582,14 @@ int parse_events_load_bpf_obj(struct parse_events_evlist *data,
goto errout;
}
- /*
- * Temporary add a dummy event here so we can check whether
- * basic bpf loader works. Will be removed in following patch.
- */
- return parse_events_add_numeric(data, list, PERF_TYPE_SOFTWARE,
- PERF_COUNT_SW_DUMMY, NULL);
+ err = bpf__foreach_tev(obj, add_bpf_event, ¶m);
+ if (err) {
+ snprintf(errbuf, sizeof(errbuf),
+ "Attach events in BPF object failed");
+ goto errout;
+ }
+
+ return 0;
errout:
data->error->help = strdup("(add -v to see detail)");
data->error->str = strdup(errbuf);
This patch collects 'struct perf_evsel' for every probing points in BPF object file(s) and fill 'struct evlist'. The previous introduced dummy event now removed. After this patch, following command: # perf record --event filter.o ls Can trace on each probing points defined in filter.o. The core of this patch is bpf__foreach_tev(), which calls a callback function for each 'struct probe_trace_event' events for a bpf program with their file descriptors. Callback function add_bpf_event() creates evsels by calling parse_events_add_tracepoint(). Since bpf-loader.c will not be built if libbpf is turned off, an empty bpf__foreach_tev() is defined in bpf-loader.h to avoid compiling error. Signed-off-by: Wang Nan <wangnan0@huawei.com> Cc: 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: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Zefan Li <lizefan@huawei.com> Cc: pi3orama@163.com Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Link: http://lkml.kernel.org/n/ebpf-6yw9eg0ej3l4jnqhinngkw86@git.kernel.org --- tools/perf/util/bpf-loader.c | 40 +++++++++++++++++++++++++++++++++++ tools/perf/util/bpf-loader.h | 15 +++++++++++++ tools/perf/util/parse-events.c | 48 ++++++++++++++++++++++++++++++++++++------ 3 files changed, 97 insertions(+), 6 deletions(-)