[RFC PATCH v3 32/37] perf bpf: Parse probe points of eBPF programs during preparation

Wang Nan
2015-05-17T11:00:22Z

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 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.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
tools/perf/util/bpf-loader.c | 74 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 74 insertions(+)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 67bfb62..3dc9b61 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -29,6 +29,7 @@ DEFINE_PRINT_FN(debug, 1)
static bool libbpf_inited = false;

#define MAX_OBJECTS 128
+#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"

struct {
struct bpf_object *objects[MAX_OBJECTS];
@@ -36,10 +37,78 @@ struct {

struct {
struct bpf_prog_handler *prog;
+ struct perf_probe_event *pevent;
} progs[MAX_PROBES];
size_t nr_progs;
+
+ struct perf_probe_event event_array[MAX_PROBES];
+ size_t nr_events;
} params;

+static struct perf_probe_event *
+alloc_perf_probe_event(void)
+{
+ struct perf_probe_event *pev;
+ int n = params.nr_events;
+
+ if (n >= MAX_PROBES) {
+ pr_err("bpf: too many events, increase MAX_PROBES\n");
+ return NULL;
+ }
+
+ params.nr_events = n + 1;
+ pev = &params.event_array[n];
+ bzero(pev, sizeof(*pev));
+ return pev;
+}
+
+static int
+bpf_do_config(size_t prog_idx, const char *config_str)
+{
+ struct perf_probe_event *pev = alloc_perf_probe_event();
+ int err = 0;
+
+ if (!pev)
+ return -ENOMEM;
+
+ if ((err = parse_perf_probe_command(config_str, pev)) < 0) {
+ pr_err("bpf config: %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 config: '%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 config: strdup failed\n");
+ err = -ENOMEM;
+ goto errout;
+ }
+
+ if (!pev->event) {
+ pr_err("bpf config: '%s': event name is missing\n",
+ config_str);
+ err = -EINVAL;
+ goto errout;
+ }
+
+ pr_debug("bpf config: config '%s' ok\n", config_str);
+ params.progs[prog_idx].pevent = pev;
+ return 0;
+errout:
+ if (pev)
+ clear_perf_probe_event(pev);
+ return err;
+}
+
int bpf_prepare_load(const char *filename)
{
struct bpf_object *obj;
@@ -81,6 +150,8 @@ int bpf_prepare_load(const char *filename)
return -EINVAL;
}
pr_debug("bpf: add program '%s'\n", title);
+
+ bpf_do_config(params.nr_progs - 1, title);
}
return 0;
}
@@ -89,6 +160,9 @@ void bpf_clear(void)
{
size_t i;

+ for (i = 0; i < params.nr_events; i++)
+ clear_perf_probe_event(&params.event_array[i]);
+
for (i = 0; i < params.nr_objects; i++)
bpf_close_object(params.objects[i]);
}
--
1.8.3.4