All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wang Nan <wangnan0@huawei.com>
To: <ast@plumgrid.com>, <davem@davemloft.net>, <acme@kernel.org>,
	<mingo@redhat.com>, <a.p.zijlstra@chello.nl>,
	<masami.hiramatsu.pt@hitachi.com>, <jolsa@kernel.org>
Cc: <lizefan@kernel.org>, <linux-kernel@vger.kernel.org>,
	<pi3orama@163.com>, <hekuang@huawei.com>
Subject: [RFC PATCH 14/22] perf bpf: config eBPF programs based on their names.
Date: Thu, 30 Apr 2015 10:52:37 +0000	[thread overview]
Message-ID: <1430391165-30267-15-git-send-email-wangnan0@huawei.com> (raw)
In-Reply-To: <1430391165-30267-1-git-send-email-wangnan0@huawei.com>

This patch partially implements bpf_obj_config(), which is used for
define k(ret)probe positions which will be attached eBPF programs.

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

This patch deals programs with 'kprobe/myprobe' like name only by
generating perf probe command string then calling
parse_perf_probe_command().

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

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 66fbca2..b2871fc 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -22,6 +22,38 @@
 
 static LIST_HEAD(bpf_obj_list);
 
+#define MAX_CMDLEN 256
+#define PERF_BPF_PROBE_GROUP "perf_bpf_probe"
+/*
+ * perf probe is no non-reentrantable, so we must group all events
+ * together and call add_perf_probe_events only once.
+ */
+
+struct params {
+	struct perf_probe_event event_array[MAX_PROBES];
+	size_t nr_events;
+};
+static struct params params = {
+	.nr_events = 0,
+};
+
+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 struct bpf_obj *__bpf_obj_alloc(const char *path)
 {
 	struct bpf_obj *obj;
@@ -279,6 +311,10 @@ bpf_perf_prog_free(struct bpf_perf_prog *prog)
 		free(prog->name);
 	if (prog->insns)
 		free(prog->insns);
+	if (prog->pev) {
+		clear_perf_probe_event(prog->pev);
+		bzero(prog->pev, sizeof(*prog->pev));
+	}
 	free(prog);
 }
 
@@ -448,6 +484,169 @@ static int bpf_obj_validate(struct bpf_obj *obj)
 	return 0;
 }
 
+static struct bpf_perf_prog *
+bpf_find_prog_by_name(struct bpf_obj *obj, const char *name)
+{
+	struct bpf_perf_prog *prog;
+
+	list_for_each_entry(prog, &obj->progs_list, list)
+		if (strcmp(name, prog->name) == 0)
+			return prog;
+	return NULL;
+}
+
+/*
+ * Use config_str to config program. If prog is NULL, find a
+ * prog based on config_str. config_str should not be NULL.
+ */
+static int __bpf_perf_prog_config(struct bpf_obj *obj,
+				  struct bpf_perf_prog *prog,
+				  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;
+	}
+
+	if (!prog)
+		prog = bpf_find_prog_by_name(obj, pev->event);
+	if (!prog) {
+		pr_err("bpf config: section %s not found for"
+		       " config '%s'\n", pev->event, config_str);
+		err = -ENOENT;
+		goto errout;
+	}
+
+	if (prog->pev) {
+		pr_err("bpf config: duplicate config for section %s\n",
+			prog->name);
+		err = -EEXIST;
+		goto errout;
+	}
+
+	prog->pev = pev;
+	pr_debug("bpf config: config %s ok\n", prog->name);
+	return 0;
+errout:
+	if (pev)
+		clear_perf_probe_event(pev);
+	return err;
+}
+
+/*
+ * Config specific prog using config_str. Both prog and config_str
+ * can be set to NULL, but not both. If prog is NULL, search prog
+ * based on config_str. If config_str is NULL, try to generate a
+ * config_str using prog->name.
+ */
+static int bpf_perf_prog_config(struct bpf_obj *obj,
+				struct bpf_perf_prog *prog,
+				char *config_str)
+{
+	char __config_str[MAX_CMDLEN];
+	char *func_str;
+	char *name = NULL;
+
+	if (!prog && !config_str) {
+		pr_err("bpf config: internal error\n");
+		return -EINVAL;
+	}
+
+	if (prog)
+		name = prog->name;
+
+	if (name && (func_str = strchr(name, '/'))) {
+		const char *ret_str;
+		int err = 0;
+
+		/* try to config prog based on its name */
+		if (config_str) {
+			pr_err("bpf config: bad config %s for %s\n",
+			       config_str, name);
+			return -EINVAL;
+		}
+		config_str = __config_str;
+
+		if (memcmp(name, "kprobe/", 7) == 0)
+			ret_str = "";
+		else if (memcmp(name, "kretprobe/", 10) == 0)
+			ret_str = "%return";
+		else {
+			pr_err("bpf: bad section name: '%s'\n", name);
+			return -EINVAL;
+		}
+
+		/* skip '/' */
+		func_str += 1;
+		err = snprintf(config_str, MAX_CMDLEN, "%s=%s%s",
+			       func_str, func_str, ret_str);
+		if (err >= MAX_CMDLEN) {
+			pr_err("bpf: function name %s too long\n", func_str);
+			return -EINVAL;
+		}
+
+		err = __bpf_perf_prog_config(obj, prog, config_str);
+		if (err)
+			return err;
+		return 0;
+	}
+
+	if (config_str)
+		/* prog should be NULL in this case. */
+		return __bpf_perf_prog_config(obj, prog, config_str);
+
+	/*
+	 * prog->name is a symbol and config_str is NULL.
+	 * Return normally. It will be config again with config_str.
+	 */
+	return 0;
+}
+
+static int bpf_obj_config(struct bpf_obj *obj)
+{
+	struct bpf_perf_prog *prog;
+	int err;
+
+	/* try to config progs based on their names */
+	list_for_each_entry(prog, &obj->progs_list, list) {
+		err = bpf_perf_prog_config(obj, prog, NULL);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 int bpf__load(const char *path)
 {
 	struct bpf_obj *obj;
@@ -474,6 +673,8 @@ int bpf__load(const char *path)
 		goto out;
 	if ((err = bpf_obj_validate(obj)))
 		goto out;
+	if ((err = bpf_obj_config(obj)))
+		goto out;
 
 	list_add(&obj->list, &bpf_obj_list);
 	return 0;
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 1417c0d..09f77a5 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -27,6 +27,8 @@ struct bpf_perf_prog {
 	char *name;
 	struct bpf_insn *insns;
 	size_t insns_cnt;
+
+	struct perf_probe_event *pev;
 };
 
 struct bpf_obj {
-- 
1.8.3.4


  parent reply	other threads:[~2015-04-30 11:00 UTC|newest]

Thread overview: 46+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-04-30 10:52 [RFC PATCH 00/22] perf tools: introduce 'perf bpf' command to load eBPF programs Wang Nan
2015-04-30 10:52 ` [RFC PATCH 01/22] perf: probe: avoid segfault if passed with '' Wang Nan
2015-05-05 14:09   ` Masami Hiramatsu
2015-05-05 15:26     ` Arnaldo Carvalho de Melo
2015-05-05 16:33       ` Masami Hiramatsu
2015-04-30 10:52 ` [RFC PATCH 02/22] perf: bpf: prepare: add __aligned_u64 to types.h Wang Nan
2015-04-30 10:52 ` [RFC PATCH 03/22] perf: add bpf common operations Wang Nan
2015-04-30 10:52 ` [RFC PATCH 04/22] perf tools: Add new 'perf bpf' command Wang Nan
2015-05-11  6:28   ` Namhyung Kim
2015-04-30 10:52 ` [RFC PATCH 05/22] perf bpf: open eBPF object file and do basic validation Wang Nan
2015-04-30 10:52 ` [RFC PATCH 06/22] perf bpf: check swap according to EHDR Wang Nan
2015-04-30 10:52 ` [RFC PATCH 07/22] perf bpf: iterater over elf sections to collect information Wang Nan
2015-04-30 10:52 ` [RFC PATCH 08/22] perf bpf: collect version and license from ELF Wang Nan
2015-04-30 10:52 ` [RFC PATCH 09/22] perf bpf: collect map definitions Wang Nan
2015-05-11  6:32   ` Namhyung Kim
2015-04-30 10:52 ` [RFC PATCH 10/22] perf bpf: collect config section in object Wang Nan
2015-04-30 10:52 ` [RFC PATCH 11/22] perf bpf: collect symbol table in object files Wang Nan
2015-04-30 10:52 ` [RFC PATCH 12/22] perf bpf: collect bpf programs from " Wang Nan
2015-04-30 10:52 ` [RFC PATCH 13/22] perf bpf: collects relocation sections from object file Wang Nan
2015-04-30 10:52 ` Wang Nan [this message]
2015-04-30 10:52 ` [RFC PATCH 15/22] perf bpf: config eBPF programs using config section Wang Nan
2015-04-30 10:52 ` [RFC PATCH 16/22] perf bpf: create maps needed by object file Wang Nan
2015-04-30 10:52 ` [RFC PATCH 17/22] perf bpf: relocation programs Wang Nan
2015-04-30 10:52 ` [RFC PATCH 18/22] perf bpf: load eBPF programs into kernel Wang Nan
2015-04-30 10:52 ` [RFC PATCH 19/22] perf bpf: dump eBPF program before loading Wang Nan
2015-04-30 10:52 ` [RFC PATCH 20/22] perf bpf: clean elf memory after loading Wang Nan
2015-04-30 10:52 ` [RFC PATCH 21/22] perf bpf: probe at kprobe points Wang Nan
2015-05-05 16:34   ` Masami Hiramatsu
2015-05-06  2:36     ` Wang Nan
2015-04-30 10:52 ` [RFC PATCH 22/22] perf bpf: attaches eBPF program to perf fd Wang Nan
2015-05-01  4:37 ` [RFC PATCH 00/22] perf tools: introduce 'perf bpf' command to load eBPF programs Alexei Starovoitov
2015-05-01 11:06   ` Peter Zijlstra
2015-05-01 11:49     ` Ingo Molnar
2015-05-01 16:56       ` Alexei Starovoitov
2015-05-01 17:06         ` Ingo Molnar
2015-05-05 15:39         ` Arnaldo Carvalho de Melo
2015-05-02  7:19   ` Wang Nan
2015-05-05  3:02     ` Alexei Starovoitov
2015-05-05  4:41       ` Wang Nan
2015-05-05  5:49         ` Alexei Starovoitov
2015-05-05  6:14           ` Wang Nan
2015-05-06  4:46             ` Wang Nan
2015-05-06  4:56               ` Alexei Starovoitov
2015-05-06  5:00                 ` Wang Nan
2015-05-01  7:16 ` Ingo Molnar
2015-05-05 21:52 ` Brendan Gregg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1430391165-30267-15-git-send-email-wangnan0@huawei.com \
    --to=wangnan0@huawei.com \
    --cc=a.p.zijlstra@chello.nl \
    --cc=acme@kernel.org \
    --cc=ast@plumgrid.com \
    --cc=davem@davemloft.net \
    --cc=hekuang@huawei.com \
    --cc=jolsa@kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lizefan@kernel.org \
    --cc=masami.hiramatsu.pt@hitachi.com \
    --cc=mingo@redhat.com \
    --cc=pi3orama@163.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.