From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753498AbbGIMg4 (ORCPT ); Thu, 9 Jul 2015 08:36:56 -0400 Received: from szxga01-in.huawei.com ([58.251.152.64]:31487 "EHLO szxga01-in.huawei.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753463AbbGIMgk (ORCPT ); Thu, 9 Jul 2015 08:36:40 -0400 From: Wang Nan To: , CC: , , , , Subject: [PATCH 20/39] perf tools: Parse probe points of eBPF programs during preparation Date: Thu, 9 Jul 2015 12:35:23 +0000 Message-ID: <1436445342-1402-21-git-send-email-wangnan0@huawei.com> X-Mailer: git-send-email 1.8.3.4 In-Reply-To: <1436445342-1402-1-git-send-email-wangnan0@huawei.com> References: <1436445342-1402-1-git-send-email-wangnan0@huawei.com> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.107.197.200] X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- 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..e33995d 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; + + config_str = bpf_program__title(prog, false); + if (!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 #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