This patch parses section name of each program, and creates
corresponding 'struct perf_probe_event' structure.

parse_perf_probe_command() is used to do the main parsing works.
Parsing result is stored into a global array. This is because
add_perf_probe_events() is non-reentrantable. In following patch,
add_perf_probe_events will be introduced to insert kprobes. It accepts
an array of 'struct perf_probe_event' and do all works in one call.

Define PERF_BPF_PROBE_GROUP as "perf_bpf_probe", which will be used
as group name of all eBPF probing points.

This patch utilizes bpf_program__set_private(), bind perf_probe_event
with bpf program by private field.

Signed-off-by: Wang Nan <wangn...@huawei.com>
---
 tools/perf/util/bpf-loader.c | 126 ++++++++++++++++++++++++++++++++++++++++++-
 tools/perf/util/bpf-loader.h |   2 +
 2 files changed, 126 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 61d3adf..e810d05 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -10,6 +10,8 @@
 #include "debug.h"
 #include "bpf-loader.h"
 #include "llvm-utils.h"
+#include "probe-event.h"
+#include "probe-finder.h"
 
 #define DEFINE_PRINT_FN(name, level) \
 static int libbpf_##name(const char *fmt, ...) \
@@ -29,9 +31,122 @@ DEFINE_PRINT_FN(debug, 1)
 
 static bool libbpf_initialized;
 
+static struct perf_probe_event probe_event_array[MAX_PROBES];
+static size_t nr_probe_events;
+
+static struct perf_probe_event *
+alloc_perf_probe_event(void)
+{
+       struct perf_probe_event *pev;
+       int n = nr_probe_events;
+
+       if (n >= MAX_PROBES) {
+               pr_err("bpf: too many events, increase MAX_PROBES\n");
+               return NULL;
+       }
+
+       nr_probe_events = n + 1;
+       pev = &probe_event_array[n];
+       bzero(pev, sizeof(*pev));
+       return pev;
+}
+
+struct bpf_prog_priv {
+       struct perf_probe_event *pev;
+};
+
+static void
+bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
+                         void *_priv)
+{
+       struct bpf_prog_priv *priv = _priv;
+
+       if (priv->pev)
+               clear_perf_probe_event(priv->pev);
+       free(priv);
+}
+
+static int
+config_bpf_program(struct bpf_program *prog)
+{
+       struct perf_probe_event *pev = alloc_perf_probe_event();
+       struct bpf_prog_priv *priv = NULL;
+       const char *config_str;
+       int err;
+
+       /* pr_err has been done by alloc_perf_probe_event */
+       if (!pev)
+               return -ENOMEM;
+
+       err = bpf_program__get_title(prog, &config_str, false);
+       if (err || !config_str) {
+               pr_err("bpf: unable to get title for program\n");
+               return -EINVAL;
+       }
+
+       pr_debug("bpf: config program '%s'\n", config_str);
+       err = parse_perf_probe_command(config_str, pev);
+       if (err < 0) {
+               pr_err("bpf: '%s' is not a valid config string\n",
+                      config_str);
+               /* parse failed, don't need clear pev. */
+               return -EINVAL;
+       }
+
+       if (pev->group && strcmp(pev->group, PERF_BPF_PROBE_GROUP)) {
+               pr_err("bpf: '%s': group for event is set and not '%s'.\n",
+                      config_str, PERF_BPF_PROBE_GROUP);
+               err = -EINVAL;
+               goto errout;
+       } else if (!pev->group)
+               pev->group = strdup(PERF_BPF_PROBE_GROUP);
+
+       if (!pev->group) {
+               pr_err("bpf: strdup failed\n");
+               err = -ENOMEM;
+               goto errout;
+       }
+
+       if (!pev->event) {
+               pr_err("bpf: '%s': event name is missing\n",
+                      config_str);
+               err = -EINVAL;
+               goto errout;
+       }
+
+       pr_debug("bpf: config '%s' is ok\n", config_str);
+
+       priv = calloc(1, sizeof(*priv));
+       if (!priv) {
+               pr_err("bpf: failed to alloc memory\n");
+               err = -ENOMEM;
+               goto errout;
+       }
+
+       priv->pev = pev;
+
+       err = bpf_program__set_private(prog, priv,
+                                      bpf_prog_priv__clear);
+       if (err) {
+               pr_err("bpf: set program private failed\n");
+               err = -ENOMEM;
+               goto errout;
+       }
+       return 0;
+
+errout:
+       if (pev)
+               clear_perf_probe_event(pev);
+       if (priv)
+               free(priv);
+       return err;
+}
+
 int bpf__prepare_load(const char *filename, bool source)
 {
        struct bpf_object *obj;
+       struct bpf_program *prog;
+       int err = 0;
 
        if (!libbpf_initialized)
                libbpf_set_print(libbpf_warning,
@@ -41,7 +156,6 @@ int bpf__prepare_load(const char *filename, bool source)
        if (source) {
                void *obj_buf;
                size_t obj_buf_sz;
-               int err;
 
                err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
                if (err)
@@ -56,12 +170,20 @@ int bpf__prepare_load(const char *filename, bool source)
                return -EINVAL;
        }
 
+       bpf_object__for_each_program(prog, obj) {
+               err = config_bpf_program(prog);
+               if (err)
+                       goto errout;
+       }
+
        /*
         * Throw object pointer away: it will be retrived using
         * bpf_objects iterater.
         */
-
        return 0;
+errout:
+       bpf_object__close(obj);
+       return err;
 }
 
 void bpf__clear(void)
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 5566be0..5a3c954 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -8,6 +8,8 @@
 #include <linux/compiler.h>
 #include "debug.h"
 
+#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
+
 #ifdef HAVE_LIBBPF_SUPPORT
 int bpf__prepare_load(const char *filename, bool source);
 
-- 
1.8.3.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to