Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > linux.kernel > #1179785 > unrolled thread

[PATCH v11 00/39] perf tools: filtering events using eBPF programs - part1

Started byWang Nan <wangnan0@huawei.com>
First post2015-07-08 15:20 +0200
Last post2015-07-08 16:10 +0200
Articles 17 on this page of 37 — 2 participants

Back to article view | Back to linux.kernel


Contents

  [PATCH v11 00/39] perf tools: filtering events using eBPF programs - part1 Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 03/39] bpf tools: Introduce 'bpf' library and add bpf feature check Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 35/39] perf tools: Add bpf_fd field to evsel and config it Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 28/39] perf tools: Make perf depend on libbpf Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 34/39] perf record: Load all eBPF object into kernel Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 13/39] bpf tools: Collect relocation sections from SHT_REL sections Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 22/39] bpf tools: Link all bpf objects onto a list Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 02/39] tracing, perf: Implement BPF programs attached to uprobes Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 07/39] bpf tools: Check endianness and make libbpf fail early Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 38/39] perf record: Add clang options for compiling BPF scripts Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 33/39] perf record: Probe at kprobe points Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 32/39] perf probe: Attach trace_probe_event with perf_probe_event Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 36/39] perf tools: Attach eBPF program to perf event Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 23/39] perf tools: Introduce llvm config options Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 11/39] bpf tools: Collect symbol table from SHT_SYMTAB section Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 10/39] bpf tools: Collect map definitions from 'maps' section Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:20 +0200
    [PATCH v11 19/39] bpf tools: Load eBPF programs in object files into kernel Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 18/39] bpf tools: Introduce bpf_load_program() to bpf.c Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 15/39] bpf tools: Add bpf.c/h for common bpf operations Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 29/39] perf record: Enable passing bpf object file to --event Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 05/39] bpf tools: Open eBPF object file and do basic validation Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 27/39] perf tests: Add LLVM test for eBPF on-the-fly compiling Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 09/39] bpf tools: Collect version and license from ELF sections Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 31/39] perf tools: Parse probe points of eBPF programs during preparation Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 17/39] bpf tools: Relocate eBPF programs Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 16/39] bpf tools: Create eBPF maps defined in an object file Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 14/39] bpf tools: Record map accessing instructions for each program Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 25/39] perf tools: Auto detecting kernel build directory Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 39/39] bpf tools: Load a program with different instance using preprocessor Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 04/39] bpf tools: Allow caller to set printing function Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 21/39] bpf tools: Introduce accessors for struct bpf_object Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 06/39] bpf tools: Read eBPF object from buffer Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 24/39] perf tools: Call clang to compile C source to object code Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 20/39] bpf tools: Introduce accessors for struct bpf_program Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 37/39] perf tools: Suppress probing messages when probing by BPF loading Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    [PATCH v11 26/39] perf tools: Auto detecting kernel include options Wang Nan <wangnan0@huawei.com> - 2015-07-08 15:30 +0200
    Re: [PATCH v11 00/39] perf tools: filtering events using eBPF  programs - part1 Arnaldo Carvalho de Melo <acme@kernel.org> - 2015-07-08 16:10 +0200

Page 2 of 2 — ← Prev page 1 [2]


#1179812 — [PATCH v11 05/39] bpf tools: Open eBPF object file and do basic validation

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 05/39] bpf tools: Open eBPF object file and do basic validation
Message-ID<pJXAe-3fG-19@gated-at.bofh.it>
In reply to#1179785
This patch defines basic interface of libbpf. 'struct bpf_object' will
be the handler of each object file. Its internal structure is hide to
user. eBPF object files are compiled by LLVM as ELF format. In this
patch, libelf is used to open those files, read EHDR and do basic
validation according to e_type and e_machine.

All elf related staffs are grouped together and reside in efile field of
'struct bpf_object'. bpf_object__elf_finish() is introduced to clear it.

After all eBPF programs in an object file are loaded, related ELF
information is useless. Close the object file and free those memory.

The zfree() and zclose() functions are introduced to ensure setting NULL
pointers and negative file descriptors after resources are released.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-6-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 158 +++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h |   8 +++
 2 files changed, 166 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 6f0c13a..9e44608 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -11,8 +11,12 @@
 #include <stdarg.h>
 #include <string.h>
 #include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
 #include <asm/unistd.h>
 #include <linux/bpf.h>
+#include <libelf.h>
+#include <gelf.h>
 
 #include "libbpf.h"
 
@@ -52,3 +56,157 @@ void libbpf_set_print(libbpf_print_fn_t warn,
 	__pr_info = info;
 	__pr_debug = debug;
 }
+
+/* Copied from tools/perf/util/util.h */
+#ifndef zfree
+# define zfree(ptr) ({ free(*ptr); *ptr = NULL; })
+#endif
+
+#ifndef zclose
+# define zclose(fd) ({			\
+	int ___err = 0;			\
+	if ((fd) >= 0)			\
+		___err = close((fd));	\
+	fd = -1;			\
+	___err; })
+#endif
+
+#ifdef HAVE_LIBELF_MMAP_SUPPORT
+# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP
+#else
+# define LIBBPF_ELF_C_READ_MMAP ELF_C_READ
+#endif
+
+struct bpf_object {
+	/*
+	 * Information when doing elf related work. Only valid if fd
+	 * is valid.
+	 */
+	struct {
+		int fd;
+		Elf *elf;
+		GElf_Ehdr ehdr;
+	} efile;
+	char path[];
+};
+#define obj_elf_valid(o)	((o)->efile.elf)
+
+static struct bpf_object *bpf_object__new(const char *path)
+{
+	struct bpf_object *obj;
+
+	obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1);
+	if (!obj) {
+		pr_warning("alloc memory failed for %s\n", path);
+		return NULL;
+	}
+
+	strcpy(obj->path, path);
+	obj->efile.fd = -1;
+	return obj;
+}
+
+static void bpf_object__elf_finish(struct bpf_object *obj)
+{
+	if (!obj_elf_valid(obj))
+		return;
+
+	if (obj->efile.elf) {
+		elf_end(obj->efile.elf);
+		obj->efile.elf = NULL;
+	}
+	zclose(obj->efile.fd);
+}
+
+static int bpf_object__elf_init(struct bpf_object *obj)
+{
+	int err = 0;
+	GElf_Ehdr *ep;
+
+	if (obj_elf_valid(obj)) {
+		pr_warning("elf init: internal error\n");
+		return -EEXIST;
+	}
+
+	obj->efile.fd = open(obj->path, O_RDONLY);
+	if (obj->efile.fd < 0) {
+		pr_warning("failed to open %s: %s\n", obj->path,
+				strerror(errno));
+		return -errno;
+	}
+
+	obj->efile.elf = elf_begin(obj->efile.fd,
+				 LIBBPF_ELF_C_READ_MMAP,
+				 NULL);
+	if (!obj->efile.elf) {
+		pr_warning("failed to open %s as ELF file\n",
+				obj->path);
+		err = -EINVAL;
+		goto errout;
+	}
+
+	if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) {
+		pr_warning("failed to get EHDR from %s\n",
+				obj->path);
+		err = -EINVAL;
+		goto errout;
+	}
+	ep = &obj->efile.ehdr;
+
+	if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) {
+		pr_warning("%s is not an eBPF object file\n",
+			obj->path);
+		err = -EINVAL;
+		goto errout;
+	}
+
+	return 0;
+errout:
+	bpf_object__elf_finish(obj);
+	return err;
+}
+
+static struct bpf_object *
+__bpf_object__open(const char *path)
+{
+	struct bpf_object *obj;
+
+	if (elf_version(EV_CURRENT) == EV_NONE) {
+		pr_warning("failed to init libelf for %s\n", path);
+		return NULL;
+	}
+
+	obj = bpf_object__new(path);
+	if (!obj)
+		return NULL;
+
+	if (bpf_object__elf_init(obj))
+		goto out;
+
+	bpf_object__elf_finish(obj);
+	return obj;
+out:
+	bpf_object__close(obj);
+	return NULL;
+}
+
+struct bpf_object *bpf_object__open(const char *path)
+{
+	/* param validation */
+	if (!path)
+		return NULL;
+
+	pr_debug("loading %s\n", path);
+
+	return __bpf_object__open(path);
+}
+
+void bpf_object__close(struct bpf_object *obj)
+{
+	if (!obj)
+		return;
+
+	bpf_object__elf_finish(obj);
+
+	free(obj);
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 8d1eeba..ec3301c 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -8,6 +8,8 @@
 #ifndef __BPF_LIBBPF_H
 #define __BPF_LIBBPF_H
 
+#include <stdio.h>
+
 /*
  * In include/linux/compiler-gcc.h, __printf is defined. However
  * it should be better if libbpf.h doesn't depend on Linux header file.
@@ -20,4 +22,10 @@ void libbpf_set_print(libbpf_print_fn_t warn,
 		      libbpf_print_fn_t info,
 		      libbpf_print_fn_t debug);
 
+/* Hide internal to user */
+struct bpf_object;
+
+struct bpf_object *bpf_object__open(const char *path);
+void bpf_object__close(struct bpf_object *object);
+
 #endif
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179813 — [PATCH v11 27/39] perf tests: Add LLVM test for eBPF on-the-fly compiling

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 27/39] perf tests: Add LLVM test for eBPF on-the-fly compiling
Message-ID<pJXAe-3fG-21@gated-at.bofh.it>
In reply to#1179785
Previous patches introduce llvm__compile_bpf() to compile source file to
eBPF object. This patch adds testcase to test it. It also test libbpf
by opening generated object.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 tools/perf/tests/Build          |  1 +
 tools/perf/tests/builtin-test.c |  4 ++
 tools/perf/tests/llvm.c         | 85 +++++++++++++++++++++++++++++++++++++++++
 tools/perf/tests/tests.h        |  1 +
 4 files changed, 91 insertions(+)
 create mode 100644 tools/perf/tests/llvm.c

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index d20d6e6..c1518bd 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,6 +32,7 @@ perf-y += sample-parsing.o
 perf-y += parse-no-sample-id-all.o
 perf-y += kmod-path.o
 perf-y += thread-map.o
+perf-y += llvm.o
 
 perf-$(CONFIG_X86) += perf-time-to-tsc.o
 
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index c1dde73..6a3fb54 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -174,6 +174,10 @@ static struct test {
 		.desc = "Test thread map",
 		.func = test__thread_map,
 	},
+ 	{
+		.desc = "Test LLVM searching and compiling",
+		.func = test__llvm,
+	},
 	{
 		.func = NULL,
 	},
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
new file mode 100644
index 0000000..9984631
--- /dev/null
+++ b/tools/perf/tests/llvm.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <bpf/libbpf.h>
+#include <util/llvm-utils.h>
+#include <util/cache.h>
+#include "tests.h"
+#include "debug.h"
+
+static int perf_config_cb(const char *var, const char *val,
+			  void *arg __maybe_unused)
+{
+	return perf_default_config(var, val, arg);
+}
+
+/*
+ * Randomly give it a "version" section since we don't really load it
+ * into kernel
+ */
+static const char test_bpf_prog[] =
+	"__attribute__((section(\"do_fork\"), used)) "
+	"int fork(void *ctx) {return 0;} "
+	"char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";"
+	"int _version __attribute__((section(\"version\"), used)) = 0x40100;";
+
+#ifdef HAVE_LIBBPF_SUPPORT
+static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
+{
+	struct bpf_object *obj;
+
+	obj = bpf_object__open_buffer(obj_buf, obj_buf_sz);
+	if (!obj)
+		return -1;
+	bpf_object__close(obj);
+	return 0;
+}
+#else
+static int test__bpf_parsing(void *obj_buf __maybe_unused,
+			     size_t obj_buf_sz __maybe_unused)
+{
+	fprintf(stderr, " (skip bpf parsing)");
+	return 0;
+}
+#endif
+
+#define new_string(n, fmt, ...) \
+do {					\
+	n##_sz = snprintf(NULL, 0, fmt, __VA_ARGS__);\
+	if (n##_sz == 0)			\
+		return -1;		\
+	n##_new = malloc(n##_sz + 1);	\
+	if (!n##_new)			\
+		return -1;		\
+	snprintf(n##_new, n##_sz + 1, fmt, __VA_ARGS__);\
+	n##_new[n##_sz] = '\0';		\
+} while (0)
+
+int test__llvm(void)
+{
+	char *tmpl_new, *clang_opt_new;
+	size_t tmpl_sz, clang_opt_sz;
+	void *obj_buf;
+	size_t obj_buf_sz;
+	int err;
+
+	perf_config(perf_config_cb, NULL);
+
+	if (!llvm_param.clang_bpf_cmd_template)
+		return -1;
+
+	if (!llvm_param.clang_opt)
+		llvm_param.clang_opt = strdup("");
+
+	new_string(tmpl, "echo '%s' | %s", test_bpf_prog,
+		   llvm_param.clang_bpf_cmd_template);
+	new_string(clang_opt, "-xc %s", llvm_param.clang_opt);
+
+	llvm_param.clang_bpf_cmd_template = tmpl_new;
+	llvm_param.clang_opt = clang_opt_new;
+	err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz);
+	if (err)
+		return -1;
+
+	err = test__bpf_parsing(obj_buf, obj_buf_sz);
+	free(obj_buf);
+	return err;
+}
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index ebb47d9..bf113a2 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -62,6 +62,7 @@ int test__fdarray__filter(void);
 int test__fdarray__add(void);
 int test__kmod_path__parse(void);
 int test__thread_map(void);
+int test__llvm(void);
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179814 — [PATCH v11 09/39] bpf tools: Collect version and license from ELF sections

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 09/39] bpf tools: Collect version and license from ELF sections
Message-ID<pJXAe-3fG-23@gated-at.bofh.it>
In reply to#1179785
Expand bpf_obj_elf_collect() to collect license and kernel version
information in eBPF object file. eBPF object file should have a section
named 'license', which contains a string. It should also have a section
named 'version', contains a u32 LINUX_VERSION_CODE.

bpf_obj_validate() is introduced to validate object file after loaded.
Currently it only check existence of 'version' section.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-10-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index d8d6eb5..95c8d8e 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -14,6 +14,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <asm/unistd.h>
+#include <linux/kernel.h>
 #include <linux/bpf.h>
 #include <libelf.h>
 #include <gelf.h>
@@ -78,6 +79,8 @@ void libbpf_set_print(libbpf_print_fn_t warn,
 #endif
 
 struct bpf_object {
+	char license[64];
+	u32 kern_version;
 	/*
 	 * Information when doing elf related work. Only valid if fd
 	 * is valid.
@@ -220,6 +223,33 @@ mismatch:
 	return -EINVAL;
 }
 
+static int
+bpf_object__init_license(struct bpf_object *obj,
+			 void *data, size_t size)
+{
+	memcpy(obj->license, data,
+	       min(size, sizeof(obj->license) - 1));
+	pr_debug("license of %s is %s\n", obj->path, obj->license);
+	return 0;
+}
+
+static int
+bpf_object__init_kversion(struct bpf_object *obj,
+			  void *data, size_t size)
+{
+	u32 kver;
+
+	if (size != sizeof(kver)) {
+		pr_warning("invalid kver section in %s\n", obj->path);
+		return -EINVAL;
+	}
+	memcpy(&kver, data, sizeof(kver));
+	obj->kern_version = kver;
+	pr_debug("kernel version of %s is %x\n", obj->path,
+		 obj->kern_version);
+	return 0;
+}
+
 static int bpf_object__elf_collect(struct bpf_object *obj)
 {
 	Elf *elf = obj->efile.elf;
@@ -266,11 +296,32 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 			 name, (unsigned long)data->d_size,
 			 (int)sh.sh_link, (unsigned long)sh.sh_flags,
 			 (int)sh.sh_type);
+
+		if (strcmp(name, "license") == 0)
+			err = bpf_object__init_license(obj,
+						       data->d_buf,
+						       data->d_size);
+		else if (strcmp(name, "version") == 0)
+			err = bpf_object__init_kversion(obj,
+							data->d_buf,
+							data->d_size);
+		if (err)
+			goto out;
 	}
 out:
 	return err;
 }
 
+static int bpf_object__validate(struct bpf_object *obj)
+{
+	if (obj->kern_version == 0) {
+		pr_warning("%s doesn't provide kernel version\n",
+			   obj->path);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static struct bpf_object *
 __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
 {
@@ -291,6 +342,8 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
 		goto out;
 	if (bpf_object__elf_collect(obj))
 		goto out;
+	if (bpf_object__validate(obj))
+		goto out;
 
 	bpf_object__elf_finish(obj);
 	return obj;
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179815 — [PATCH v11 31/39] perf tools: Parse probe points of eBPF programs during preparation

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 31/39] perf tools: Parse probe points of eBPF programs during preparation
Message-ID<pJXAe-3fG-25@gated-at.bofh.it>
In reply to#1179785
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 <wangnan0@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 majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [next] | [standalone]


#1179817 — [PATCH v11 17/39] bpf tools: Relocate eBPF programs

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 17/39] bpf tools: Relocate eBPF programs
Message-ID<pJXAe-3fG-29@gated-at.bofh.it>
In reply to#1179785
If an eBPF program accesses a map, LLVM generates a load instruction
which loads an absolute address into a register, like this:

  ld_64   r1, <MCOperand Expr:(mymap)>
  ...
  call    2

That ld_64 instruction will be recorded in relocation section.
To enable the usage of that map, relocation must be done by replacing
the immediate value by real map file descriptor so it can be found by
eBPF map functions.

This patch to the relocation work based on information collected by
patches:

'bpf tools: Collect symbol table from SHT_SYMTAB section',
'bpf tools: Collect relocation sections from SHT_REL sections'
and
'bpf tools: Record map accessing instructions for each program'.

For each instruction which needs relocation, it inject corresponding
file descriptor to imm field. As a part of protocol, src_reg is set to
BPF_PSEUDO_MAP_FD to notify kernel this is a map loading instruction.

This is the final part of map relocation patch. The principle of map
relocation is described in commit message of 'bpf tools: Collect symbol
table from SHT_SYMTAB section'.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-18-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index c214e1c..cd40ae0 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -633,6 +633,56 @@ bpf_object__create_maps(struct bpf_object *obj)
 	return 0;
 }
 
+static int
+bpf_program__relocate(struct bpf_program *prog, int *map_fds)
+{
+	int i;
+
+	if (!prog || !prog->reloc_desc)
+		return 0;
+
+	for (i = 0; i < prog->nr_reloc; i++) {
+		int insn_idx, map_idx;
+		struct bpf_insn *insns = prog->insns;
+
+		insn_idx = prog->reloc_desc[i].insn_idx;
+		map_idx = prog->reloc_desc[i].map_idx;
+
+		if (insn_idx >= (int)prog->insns_cnt) {
+			pr_warning("relocation out of range: '%s'\n",
+				   prog->section_name);
+			return -ERANGE;
+		}
+		insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD;
+		insns[insn_idx].imm = map_fds[map_idx];
+	}
+
+	zfree(&prog->reloc_desc);
+	prog->nr_reloc = 0;
+	return 0;
+}
+
+
+static int
+bpf_object__relocate(struct bpf_object *obj)
+{
+	struct bpf_program *prog;
+	size_t i;
+	int err;
+
+	for (i = 0; i < obj->nr_programs; i++) {
+		prog = &obj->programs[i];
+
+		err = bpf_program__relocate(prog, obj->map_fds);
+		if (err) {
+			pr_warning("failed to relocate '%s'\n",
+				   prog->section_name);
+			return err;
+		}
+	}
+	return 0;
+}
+
 static int bpf_object__collect_reloc(struct bpf_object *obj)
 {
 	int i, err;
@@ -764,6 +814,8 @@ int bpf_object__load(struct bpf_object *obj)
 	obj->loaded = true;
 	if (bpf_object__create_maps(obj))
 		goto out;
+	if (bpf_object__relocate(obj))
+		goto out;
 
 	return 0;
 out:
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179818 — [PATCH v11 16/39] bpf tools: Create eBPF maps defined in an object file

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 16/39] bpf tools: Create eBPF maps defined in an object file
Message-ID<pJXAe-3fG-31@gated-at.bofh.it>
In reply to#1179785
This patch creates maps based on 'map' section in object file using
bpf_create_map(), and stores the fds into an array in 'struct
bpf_object'.

Previous patches parse ELF object file and collects required data, but
doesn't play with the kernel. They belong to the 'opening' phase. This
patch is the first patch in 'loading' phase. The 'loaded' field is
introduced in 'struct bpf_object' to avoid loading an object twice,
because the loading phase clears resources collected during the opening
which becomes useless after loading. In this patch, maps_buf is cleared.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-17-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 102 +++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h |   4 ++
 2 files changed, 106 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4f13772..c214e1c 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -21,6 +21,7 @@
 #include <gelf.h>
 
 #include "libbpf.h"
+#include "bpf.h"
 
 #define __printf(a, b)	__attribute__((format(printf, a, b)))
 
@@ -105,6 +106,13 @@ struct bpf_object {
 
 	struct bpf_program *programs;
 	size_t nr_programs;
+	int *map_fds;
+	/*
+	 * This field is required because maps_buf will be freed and
+	 * maps_buf_sz will be set to 0 after loaded.
+	 */
+	size_t nr_map_fds;
+	bool loaded;
 
 	/*
 	 * Information when doing elf related work. Only valid if fd
@@ -232,6 +240,7 @@ static struct bpf_object *bpf_object__new(const char *path,
 	obj->efile.obj_buf = obj_buf;
 	obj->efile.obj_buf_sz = obj_buf_sz;
 
+	obj->loaded = false;
 	return obj;
 }
 
@@ -568,6 +577,62 @@ bpf_program__collect_reloc(struct bpf_program *prog,
 	return 0;
 }
 
+static int
+bpf_object__create_maps(struct bpf_object *obj)
+{
+	unsigned int i;
+	size_t nr_maps;
+	int *pfd;
+
+	nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def);
+	if (!obj->maps_buf || !nr_maps) {
+		pr_debug("don't need create maps for %s\n",
+			 obj->path);
+		return 0;
+	}
+
+	obj->map_fds = malloc(sizeof(int) * nr_maps);
+	if (!obj->map_fds) {
+		pr_warning("realloc perf_bpf_map_fds failed\n");
+		return -ENOMEM;
+	}
+	obj->nr_map_fds = nr_maps;
+
+	/* fill all fd with -1 */
+	memset(obj->map_fds, 0xff, sizeof(int) * nr_maps);
+
+	pfd = obj->map_fds;
+	for (i = 0; i < nr_maps; i++) {
+		struct bpf_map_def def;
+
+		def = *(struct bpf_map_def *)(obj->maps_buf +
+				i * sizeof(struct bpf_map_def));
+
+		*pfd = bpf_create_map(def.type,
+				      def.key_size,
+				      def.value_size,
+				      def.max_entries);
+		if (*pfd < 0) {
+			size_t j;
+			int err = *pfd;
+
+			pr_warning("failed to create map: %s\n",
+				   strerror(errno));
+			for (j = 0; j < i; j++)
+				zclose(obj->map_fds[j]);
+			obj->nr_map_fds = 0;
+			zfree(&obj->map_fds);
+			return err;
+		}
+		pr_debug("create map: fd=%d\n", *pfd);
+		pfd++;
+	}
+
+	zfree(&obj->maps_buf);
+	obj->maps_buf_sz = 0;
+	return 0;
+}
+
 static int bpf_object__collect_reloc(struct bpf_object *obj)
 {
 	int i, err;
@@ -671,6 +736,42 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,
 	return __bpf_object__open("[buffer]", obj_buf, obj_buf_sz);
 }
 
+int bpf_object__unload(struct bpf_object *obj)
+{
+	size_t i;
+
+	if (!obj)
+		return -EINVAL;
+
+	for (i = 0; i < obj->nr_map_fds; i++)
+		zclose(obj->map_fds[i]);
+	zfree(&obj->map_fds);
+	obj->nr_map_fds = 0;
+
+	return 0;
+}
+
+int bpf_object__load(struct bpf_object *obj)
+{
+	if (!obj)
+		return -EINVAL;
+
+	if (obj->loaded) {
+		pr_warning("object should not be loaded twice\n");
+		return -EINVAL;
+	}
+
+	obj->loaded = true;
+	if (bpf_object__create_maps(obj))
+		goto out;
+
+	return 0;
+out:
+	bpf_object__unload(obj);
+	pr_warning("failed to load object '%s'\n", obj->path);
+	return -EINVAL;
+}
+
 void bpf_object__close(struct bpf_object *obj)
 {
 	size_t i;
@@ -679,6 +780,7 @@ void bpf_object__close(struct bpf_object *obj)
 		return;
 
 	bpf_object__elf_finish(obj);
+	bpf_object__unload(obj);
 
 	zfree(&obj->maps_buf);
 
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 6e75acd..3e69600 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -30,6 +30,10 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,
 					   size_t obj_buf_sz);
 void bpf_object__close(struct bpf_object *object);
 
+/* Load/unload object into/from kernel */
+int bpf_object__load(struct bpf_object *obj);
+int bpf_object__unload(struct bpf_object *obj);
+
 /*
  * We don't need __attribute__((packed)) now since it is
  * unnecessary for 'bpf_map_def' because they are all aligned.
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179819 — [PATCH v11 14/39] bpf tools: Record map accessing instructions for each program

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 14/39] bpf tools: Record map accessing instructions for each program
Message-ID<pJXAf-3fG-33@gated-at.bofh.it>
In reply to#1179785
This patch records the indices of instructions which are needed to be
relocated. That information is saved in the 'reloc_desc' field in
'struct bpf_program'. In the loading phase (this patch takes effect in
the opening phase), the collected instructions will be replaced by map
loading instructions.

Since we are going to close the ELF file and clear all data at the end
of the 'opening' phase, the ELF information will no longer be valid in
the 'loading' phase. We have to locate the instructions before maps are
loaded, instead of directly modifying the instruction.

'struct bpf_map_def' is introduced in this patch to let us know how many
maps are defined in the object.

This is the third part of map relocation. The principle of map relocation
is described in commit message of 'bpf tools: Collect symbol table from
SHT_SYMTAB section'.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-15-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 124 +++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h |  13 ++++++
 2 files changed, 137 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 5f12fa6..4f13772 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -9,6 +9,7 @@
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdarg.h>
+#include <inttypes.h>
 #include <string.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -88,6 +89,12 @@ struct bpf_program {
 	char *section_name;
 	struct bpf_insn *insns;
 	size_t insns_cnt;
+
+	struct {
+		int insn_idx;
+		int map_idx;
+	} *reloc_desc;
+	int nr_reloc;
 };
 
 struct bpf_object {
@@ -127,6 +134,9 @@ static void bpf_program__clear(struct bpf_program *prog)
 
 	zfree(&prog->section_name);
 	zfree(&prog->insns);
+	zfree(&prog->reloc_desc);
+
+	prog->nr_reloc = 0;
 	prog->insns_cnt = 0;
 	prog->idx = -1;
 }
@@ -484,6 +494,118 @@ out:
 	return err;
 }
 
+static struct bpf_program *
+bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx)
+{
+	struct bpf_program *prog;
+	size_t i;
+
+	for (i = 0; i < obj->nr_programs; i++) {
+		prog = &obj->programs[i];
+		if (prog->idx == idx)
+			return prog;
+	}
+	return NULL;
+}
+
+static int
+bpf_program__collect_reloc(struct bpf_program *prog,
+			   size_t nr_maps, GElf_Shdr *shdr,
+			   Elf_Data *data, Elf_Data *symbols)
+{
+	int i, nrels;
+
+	pr_debug("collecting relocating info for: '%s'\n",
+		 prog->section_name);
+	nrels = shdr->sh_size / shdr->sh_entsize;
+
+	prog->reloc_desc = malloc(sizeof(*prog->reloc_desc) * nrels);
+	if (!prog->reloc_desc) {
+		pr_warning("failed to alloc memory in relocation\n");
+		return -ENOMEM;
+	}
+	prog->nr_reloc = nrels;
+
+	for (i = 0; i < nrels; i++) {
+		GElf_Sym sym;
+		GElf_Rel rel;
+		unsigned int insn_idx;
+		struct bpf_insn *insns = prog->insns;
+		size_t map_idx;
+
+		if (!gelf_getrel(data, i, &rel)) {
+			pr_warning("relocation: failed to get %d reloc\n", i);
+			return -EINVAL;
+		}
+
+		insn_idx = rel.r_offset / sizeof(struct bpf_insn);
+		pr_debug("relocation: insn_idx=%u\n", insn_idx);
+
+		if (!gelf_getsym(symbols,
+				 GELF_R_SYM(rel.r_info),
+				 &sym)) {
+			pr_warning("relocation: symbol %"PRIx64" not found\n",
+				   GELF_R_SYM(rel.r_info));
+			return -EINVAL;
+		}
+
+		if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) {
+			pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n",
+				   insn_idx, insns[insn_idx].code);
+			return -EINVAL;
+		}
+
+		map_idx = sym.st_value / sizeof(struct bpf_map_def);
+		if (map_idx >= nr_maps) {
+			pr_warning("bpf relocation: map_idx %d large than %d\n",
+				   (int)map_idx, (int)nr_maps - 1);
+			return -EINVAL;
+		}
+
+		prog->reloc_desc[i].insn_idx = insn_idx;
+		prog->reloc_desc[i].map_idx = map_idx;
+	}
+	return 0;
+}
+
+static int bpf_object__collect_reloc(struct bpf_object *obj)
+{
+	int i, err;
+
+	if (!obj_elf_valid(obj)) {
+		pr_warning("Internal error: elf object is closed\n");
+		return -EINVAL;
+	}
+
+	for (i = 0; i < obj->efile.nr_reloc; i++) {
+		GElf_Shdr *shdr = &obj->efile.reloc[i].shdr;
+		Elf_Data *data = obj->efile.reloc[i].data;
+		int idx = shdr->sh_info;
+		struct bpf_program *prog;
+		size_t nr_maps = obj->maps_buf_sz /
+				 sizeof(struct bpf_map_def);
+
+		if (shdr->sh_type != SHT_REL) {
+			pr_warning("internal error at %d\n", __LINE__);
+			return -EINVAL;
+		}
+
+		prog = bpf_object__find_prog_by_idx(obj, idx);
+		if (!prog) {
+			pr_warning("relocation failed: no %d section\n",
+				   idx);
+			return -ENOENT;
+		}
+
+		err = bpf_program__collect_reloc(prog, nr_maps,
+						 shdr, data,
+						 obj->efile.symbols);
+		if (err)
+			return -EINVAL;
+	}
+	return 0;
+}
+
 static int bpf_object__validate(struct bpf_object *obj)
 {
 	if (obj->kern_version == 0) {
@@ -514,6 +636,8 @@ __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
 		goto out;
 	if (bpf_object__elf_collect(obj))
 		goto out;
+	if (bpf_object__collect_reloc(obj))
+		goto out;
 	if (bpf_object__validate(obj))
 		goto out;
 
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index dc966dd..6e75acd 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -30,4 +30,17 @@ struct bpf_object *bpf_object__open_buffer(void *obj_buf,
 					   size_t obj_buf_sz);
 void bpf_object__close(struct bpf_object *object);
 
+/*
+ * We don't need __attribute__((packed)) now since it is
+ * unnecessary for 'bpf_map_def' because they are all aligned.
+ * In addition, using it will trigger -Wpacked warning message,
+ * and will be treated as an error due to -Werror.
+ */
+struct bpf_map_def {
+	unsigned int type;
+	unsigned int key_size;
+	unsigned int value_size;
+	unsigned int max_entries;
+};
+
 #endif
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179820 — [PATCH v11 25/39] perf tools: Auto detecting kernel build directory

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 25/39] perf tools: Auto detecting kernel build directory
Message-ID<pJXAf-3fG-35@gated-at.bofh.it>
In reply to#1179785
This patch detects kernel build directory using a embedded shell
script 'kbuild_detector', which does this by checking existence of
include/generated/autoconf.h.

clang working directory is changed to kbuild directory if it is found,
to help user use relative include path. Following patch will detect
kernel include directory, which contains relative include patch so this
workdir changing is needed.

Users are allowed to set 'kbuild-dir = ""' manually to disable this
checking.

Signed-off-by: Wang Nan <wangnan0@hauwei.com>
---
 tools/perf/util/llvm-utils.c | 56 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 55 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index dca16e7..2ca2bd6 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -204,6 +204,51 @@ version_notice(void)
 );
 }
 
+static const char *kbuild_detector =
+"#!/usr/bin/env sh\n"
+"DEFAULT_KBUILD_DIR=/lib/modules/`uname -r`/build\n"
+"if test -z \"$KBUILD_DIR\"\n"
+"then\n"
+"    KBUILD_DIR=$DEFAULT_KBUILD_DIR\n"
+"fi\n"
+"if test -f $KBUILD_DIR/include/generated/autoconf.h\n"
+"then\n"
+"	echo -n $KBUILD_DIR\n"
+"	exit 0\n"
+"fi\n"
+"exit -1\n";
+
+static inline void
+get_kbuild_opts(char **kbuild_dir)
+{
+	int err;
+
+	if (!kbuild_dir)
+		return;
+
+	*kbuild_dir = NULL;
+
+	if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
+		pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
+		pr_debug("Skip kbuild options detection.\n");
+		return;
+	}
+
+	force_set_env("KBUILD_DIR", llvm_param.kbuild_dir);
+	force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts);
+	err = read_from_pipe(kbuild_detector,
+			     ((void **)kbuild_dir),
+			     NULL);
+	if (err) {
+		pr_warning(
+"WARNING:\tunable to get correct kernel building directory.\n"
+"Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n"
+"     \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n"
+"     \tdetection.\n\n");
+		return;
+	}
+}
+
 int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		      size_t *p_obj_buf_sz)
 {
@@ -211,6 +256,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	char clang_path[PATH_MAX];
 	const char *clang_opt = llvm_param.clang_opt;
 	const char *template = llvm_param.clang_bpf_cmd_template;
+	char *kbuild_dir = NULL;
 	void *obj_buf = NULL;
 	size_t obj_buf_sz;
 
@@ -228,10 +274,16 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		return -ENOENT;
 	}
 
+	/*
+	 * This is an optional work. Even it fail we can continue our
+	 * work. Needn't to check error return.
+	 */
+	get_kbuild_opts(&kbuild_dir);
+
 	force_set_env("CLANG_EXEC", clang_path);
 	force_set_env("CLANG_OPTIONS", clang_opt);
 	force_set_env("KERNEL_INC_OPTIONS", NULL);
-	force_set_env("WORKING_DIR", ".");
+	force_set_env("WORKING_DIR", kbuild_dir ? : ".");
 
 	/*
 	 * Since we may reset clang's working dir, path of source file
@@ -252,6 +304,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		goto errout;
 	}
 
+	free(kbuild_dir);
 	if (!p_obj_buf)
 		free(obj_buf);
 	else
@@ -261,6 +314,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		*p_obj_buf_sz = obj_buf_sz;
 	return 0;
 errout:
+	free(kbuild_dir);
 	free(obj_buf);
 	if (p_obj_buf)
 		*p_obj_buf = NULL;
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179823 — [PATCH v11 39/39] bpf tools: Load a program with different instance using preprocessor

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 39/39] bpf tools: Load a program with different instance using preprocessor
Message-ID<pJXAf-3fG-47@gated-at.bofh.it>
In reply to#1179785
In this patch, caller of libbpf is able to control the loaded programs
by installing a preprocessor callback for a BPF program. With
preprocessor, different instances can be created from one BPF program.

This patch will be used by perf to generate different prologue for
different 'struct probe_trace_event' instances matched by one
'struct perf_probe_event'.

bpf_program__set_prep() is added to support this function. Caller
should pass libbpf the number of instance should be created and a
preprocessor function which will be called when doing real loading.
The callback should return instructions arrays for each instances.

nr_instance and instance_fds are appended into bpf_programs to support
multiple instances. bpf_program__get_nth_fd() is introduced for
read fd of instances. Old interface bpf_program__get_fd() won't work
for program which has preprocessor hooked.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@huawei.com>
---
 tools/lib/bpf/libbpf.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++--
 tools/lib/bpf/libbpf.h |  22 ++++++++
 2 files changed, 152 insertions(+), 5 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 83a3b06..d467fcb 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -100,6 +100,10 @@ struct bpf_program {
 
 	int fd;
 
+	int nr_instance;
+	int *instance_fds;
+	bpf_program_prep_t preprocessor;
+
 	struct bpf_object *obj;
 	void *priv;
 	bpf_program_clear_priv_t clear_priv;
@@ -156,6 +160,19 @@ static void bpf_program__unload(struct bpf_program *prog)
 		return;
 
 	zclose(prog->fd);
+
+	if (prog->preprocessor) {
+		int i;
+
+		if (prog->nr_instance <= 0)
+			pr_warning("Internal error when unloading: instance is %d\n",
+				   prog->nr_instance);
+		else
+			for (i = 0; i < prog->nr_instance; i++)
+				zclose(prog->instance_fds[i]);
+		prog->nr_instance = -1;
+		zfree(&prog->instance_fds);
+	}
 }
 
 static void bpf_program__clear(struct bpf_program *prog)
@@ -207,6 +224,8 @@ __bpf_program__new(void *data, size_t size, char *name, int idx,
 	       prog->insns_cnt * sizeof(struct bpf_insn));
 	prog->idx = idx;
 	prog->fd = -1;
+	prog->nr_instance = -1;
+	prog->instance_fds = NULL;
 
 	return 0;
 errout:
@@ -798,13 +817,57 @@ static int
 bpf_program__load(struct bpf_program *prog,
 		  char *license, u32 kern_version)
 {
-	int err, fd;
+	int err = 0, fd, i;
+
+	if (!prog->preprocessor) {
+		err = load_program(prog->insns, prog->insns_cnt,
+				license, kern_version, &fd);
+		if (!err)
+			prog->fd = fd;
+		goto out;
+	}
 
-	err = load_program(prog->insns, prog->insns_cnt,
-			   license, kern_version, &fd);
-	if (!err)
-		prog->fd = fd;
+	if (prog->nr_instance <= 0 || !prog->instance_fds) {
+		pr_warning("Internal error when loading '%s'\n",
+				prog->section_name);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < prog->nr_instance; i++) {
+		struct bpf_prog_prep_result result;
+		bpf_program_prep_t preprocessor = prog->preprocessor;
+
+		bzero(&result, sizeof(result));
+		err = preprocessor(prog, i, prog->insns,
+				   prog->insns_cnt, &result);
+		if (err) {
+			pr_warning("Preprocessing %dth instance of program '%s' failed\n",
+					i, prog->section_name);
+			goto out;
+		}
+
+		if (!result.new_insn_ptr || !result.new_insn_cnt) {
+			pr_debug("Skip loading %dth instance of program '%s'\n",
+					i, prog->section_name);
+			prog->instance_fds[i] = -1;
+			continue;
+		}
 
+		err = load_program(result.new_insn_ptr,
+				   result.new_insn_cnt,
+				   license, kern_version, &fd);
+
+		if (err) {
+			pr_warning("Loading %dth instance of program '%s' failed\n",
+					i, prog->section_name);
+			goto out;
+		}
+
+		if (result.pfd)
+			*result.pfd = fd;
+		prog->instance_fds[i] = fd;
+	}
+out:
 	if (err)
 		pr_warning("failed to load program '%s'\n",
 			   prog->section_name);
@@ -1054,6 +1117,68 @@ int bpf_program__get_fd(struct bpf_program *prog, int *pfd)
 	if (!pfd)
 		return -EINVAL;
 
+	if (prog->preprocessor) {
+		pr_warning("Invalid using bpf_program__get_fd() on program %s\n",
+			   prog->section_name);
+		return -EINVAL;
+	}
+
 	*pfd = prog->fd;
 	return 0;
 }
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
+			  bpf_program_prep_t prep)
+{
+	int *instance_fds;
+
+	if (nr_instance <= 0 || !prep)
+		return -EINVAL;
+
+	instance_fds = malloc(sizeof(int) * nr_instance);
+	if (!instance_fds) {
+		pr_warning("alloc memory failed for instance of fds\n");
+		return -ENOMEM;
+	}
+
+	/* fill all fd with -1 */
+	memset(instance_fds, 0xff, sizeof(int) * nr_instance);
+
+	prog->nr_instance = nr_instance;
+	prog->instance_fds = instance_fds;
+	prog->preprocessor = prep;
+	return 0;
+}
+
+int bpf_program__get_nth_fd(struct bpf_program *prog, int n, int *pfd)
+{
+	int fd;
+
+	if (!pfd)
+		return -EINVAL;
+
+	if (!prog->preprocessor ||
+		prog->nr_instance <= 0 ||
+		!prog->instance_fds) {
+
+		pr_warning("Invalid using bpf_program__get_nth_fd() on program %s\n",
+			   prog->section_name);
+		return -EINVAL;
+	}
+
+	if (n >= prog->nr_instance || n < 0) {
+		pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
+			   n, prog->section_name, prog->nr_instance);
+		return -EINVAL;
+	}
+
+	fd = prog->instance_fds[n];
+	if (fd < 0) {
+		pr_warning("%dth instance of program '%s' is invalid\n",
+			   n, prog->section_name);
+		return -EEXIST;
+	}
+
+	*pfd = fd;
+	return 0;
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 1643b57..8c2dc74 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -69,6 +69,28 @@ int bpf_program__get_title(struct bpf_program *prog,
 
 int bpf_program__get_fd(struct bpf_program *prog, int *pfd);
 
+struct bpf_insn;
+struct bpf_prog_prep_result {
+	/*
+	 * If not NULL, load new instruction array.
+	 * If set to NULL, don't load this instance.
+	 */
+	struct bpf_insn *new_insn_ptr;
+	int new_insn_cnt;
+
+	/* If not NULL, result fd is set to it */
+	int *pfd;
+};
+
+typedef int (*bpf_program_prep_t)(struct bpf_program *, int n,
+				  struct bpf_insn *, int insn_cnt,
+				  struct bpf_prog_prep_result *res);
+
+int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
+			  bpf_program_prep_t prep);
+
+int bpf_program__get_nth_fd(struct bpf_program *prog, int n, int *pfd);
+
 /*
  * We don't need __attribute__((packed)) now since it is
  * unnecessary for 'bpf_map_def' because they are all aligned.
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179826 — [PATCH v11 04/39] bpf tools: Allow caller to set printing function

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 04/39] bpf tools: Allow caller to set printing function
Message-ID<pJXAf-3fG-53@gated-at.bofh.it>
In reply to#1179785
By libbpf_set_print(), users of libbpf are allowed to register he/she
own debug, info and warning printing functions. Libbpf will use those
functions to print messages. If not provided, default info and warning
printing functions are fprintf(stderr, ...); default debug printing
is NULL.

This API is designed to be used by perf, enables it to register its own
logging functions to make all logs uniform, instead of separated
logging level control.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-5-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 40 ++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h | 12 ++++++++++++
 2 files changed, 52 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index c08d6bc..6f0c13a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -7,8 +7,48 @@
  */
 
 #include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
 #include <unistd.h>
 #include <asm/unistd.h>
 #include <linux/bpf.h>
 
 #include "libbpf.h"
+
+#define __printf(a, b)	__attribute__((format(printf, a, b)))
+
+__printf(1, 2)
+static int __base_pr(const char *format, ...)
+{
+	va_list args;
+	int err;
+
+	va_start(args, format);
+	err = vfprintf(stderr, format, args);
+	va_end(args);
+	return err;
+}
+
+static __printf(1, 2) libbpf_print_fn_t __pr_warning = __base_pr;
+static __printf(1, 2) libbpf_print_fn_t __pr_info = __base_pr;
+static __printf(1, 2) libbpf_print_fn_t __pr_debug;
+
+#define __pr(func, fmt, ...)	\
+do {				\
+	if ((func))		\
+		(func)("libbpf: " fmt, ##__VA_ARGS__); \
+} while (0)
+
+#define pr_warning(fmt, ...)	__pr(__pr_warning, fmt, ##__VA_ARGS__)
+#define pr_info(fmt, ...)	__pr(__pr_info, fmt, ##__VA_ARGS__)
+#define pr_debug(fmt, ...)	__pr(__pr_debug, fmt, ##__VA_ARGS__)
+
+void libbpf_set_print(libbpf_print_fn_t warn,
+		      libbpf_print_fn_t info,
+		      libbpf_print_fn_t debug)
+{
+	__pr_warning = warn;
+	__pr_info = info;
+	__pr_debug = debug;
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index a6f46d9..8d1eeba 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -8,4 +8,16 @@
 #ifndef __BPF_LIBBPF_H
 #define __BPF_LIBBPF_H
 
+/*
+ * In include/linux/compiler-gcc.h, __printf is defined. However
+ * it should be better if libbpf.h doesn't depend on Linux header file.
+ * So instead of __printf, here we use gcc attribute directly.
+ */
+typedef int (*libbpf_print_fn_t)(const char *, ...)
+	__attribute__((format(printf, 1, 2)));
+
+void libbpf_set_print(libbpf_print_fn_t warn,
+		      libbpf_print_fn_t info,
+		      libbpf_print_fn_t debug);
+
 #endif
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179827 — [PATCH v11 21/39] bpf tools: Introduce accessors for struct bpf_object

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 21/39] bpf tools: Introduce accessors for struct bpf_object
Message-ID<pJXAf-3fG-55@gated-at.bofh.it>
In reply to#1179785
This patch add an accessor which allows caller to get count of programs
in an object file.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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
Link: http://lkml.kernel.org/r/1435716878-189507-22-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 9 +++++++++
 tools/lib/bpf/libbpf.h | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b1575c4..b58b13b 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -946,6 +946,15 @@ void bpf_object__close(struct bpf_object *obj)
 	free(obj);
 }
 
+int bpf_object__get_prog_cnt(struct bpf_object *obj, size_t *pcnt)
+{
+	if (!obj || !pcnt)
+		return -EINVAL;
+
+	*pcnt = obj->nr_programs;
+	return 0;
+}
+
 struct bpf_program *
 bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
 {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 9e0e102..a20ae2e 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -35,6 +35,9 @@ void bpf_object__close(struct bpf_object *object);
 int bpf_object__load(struct bpf_object *obj);
 int bpf_object__unload(struct bpf_object *obj);
 
+/* Accessors of bpf_object */
+int bpf_object__get_prog_cnt(struct bpf_object *obj, size_t *pcnt);
+
 /* Accessors of bpf_program. */
 struct bpf_program;
 struct bpf_program *bpf_program__next(struct bpf_program *prog,
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179828 — [PATCH v11 06/39] bpf tools: Read eBPF object from buffer

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 06/39] bpf tools: Read eBPF object from buffer
Message-ID<pJXAf-3fG-57@gated-at.bofh.it>
In reply to#1179785
To support dynamic compiling, this patch allows caller to pass a
in-memory buffer to libbpf by bpf_object__open_buffer(). libbpf calls
elf_memory() to open it as ELF object file.

Because __bpf_object__open() collects all required data and won't need
that buffer anymore, libbpf uses that buffer directly instead of clone a
new buffer. Caller of libbpf can free that buffer or use it do other
things after bpf_object__open_buffer() return.

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
Link: http://lkml.kernel.org/r/1435716878-189507-7-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 62 ++++++++++++++++++++++++++++++++++++++++----------
 tools/lib/bpf/libbpf.h |  2 ++
 2 files changed, 52 insertions(+), 12 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 9e44608..36dfbc1 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -84,6 +84,8 @@ struct bpf_object {
 	 */
 	struct {
 		int fd;
+		void *obj_buf;
+		size_t obj_buf_sz;
 		Elf *elf;
 		GElf_Ehdr ehdr;
 	} efile;
@@ -91,7 +93,9 @@ struct bpf_object {
 };
 #define obj_elf_valid(o)	((o)->efile.elf)
 
-static struct bpf_object *bpf_object__new(const char *path)
+static struct bpf_object *bpf_object__new(const char *path,
+					  void *obj_buf,
+					  size_t obj_buf_sz)
 {
 	struct bpf_object *obj;
 
@@ -103,6 +107,16 @@ static struct bpf_object *bpf_object__new(const char *path)
 
 	strcpy(obj->path, path);
 	obj->efile.fd = -1;
+
+	/*
+	 * Caller of this function should also calls
+	 * bpf_object__elf_finish() after data collection to return
+	 * obj_buf to user. If not, we should duplicate the buffer to
+	 * avoid user freeing them before elf finish.
+	 */
+	obj->efile.obj_buf = obj_buf;
+	obj->efile.obj_buf_sz = obj_buf_sz;
+
 	return obj;
 }
 
@@ -116,6 +130,8 @@ static void bpf_object__elf_finish(struct bpf_object *obj)
 		obj->efile.elf = NULL;
 	}
 	zclose(obj->efile.fd);
+	obj->efile.obj_buf = NULL;
+	obj->efile.obj_buf_sz = 0;
 }
 
 static int bpf_object__elf_init(struct bpf_object *obj)
@@ -128,16 +144,26 @@ static int bpf_object__elf_init(struct bpf_object *obj)
 		return -EEXIST;
 	}
 
-	obj->efile.fd = open(obj->path, O_RDONLY);
-	if (obj->efile.fd < 0) {
-		pr_warning("failed to open %s: %s\n", obj->path,
-				strerror(errno));
-		return -errno;
+	if (obj->efile.obj_buf_sz > 0) {
+		/*
+		 * obj_buf should have been validated by
+		 * bpf_object__open_buffer().
+		 */
+		obj->efile.elf = elf_memory(obj->efile.obj_buf,
+					    obj->efile.obj_buf_sz);
+	} else {
+		obj->efile.fd = open(obj->path, O_RDONLY);
+		if (obj->efile.fd < 0) {
+			pr_warning("failed to open %s: %s\n", obj->path,
+					strerror(errno));
+			return -errno;
+		}
+
+		obj->efile.elf = elf_begin(obj->efile.fd,
+				LIBBPF_ELF_C_READ_MMAP,
+				NULL);
 	}
 
-	obj->efile.elf = elf_begin(obj->efile.fd,
-				 LIBBPF_ELF_C_READ_MMAP,
-				 NULL);
 	if (!obj->efile.elf) {
 		pr_warning("failed to open %s as ELF file\n",
 				obj->path);
@@ -167,7 +193,7 @@ errout:
 }
 
 static struct bpf_object *
-__bpf_object__open(const char *path)
+__bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz)
 {
 	struct bpf_object *obj;
 
@@ -176,7 +202,7 @@ __bpf_object__open(const char *path)
 		return NULL;
 	}
 
-	obj = bpf_object__new(path);
+	obj = bpf_object__new(path, obj_buf, obj_buf_sz);
 	if (!obj)
 		return NULL;
 
@@ -198,7 +224,19 @@ struct bpf_object *bpf_object__open(const char *path)
 
 	pr_debug("loading %s\n", path);
 
-	return __bpf_object__open(path);
+	return __bpf_object__open(path, NULL, 0);
+}
+
+struct bpf_object *bpf_object__open_buffer(void *obj_buf,
+					   size_t obj_buf_sz)
+{
+	/* param validation */
+	if (!obj_buf || obj_buf_sz <= 0)
+		return NULL;
+
+	pr_debug("loading object from buffer\n");
+
+	return __bpf_object__open("[buffer]", obj_buf, obj_buf_sz);
 }
 
 void bpf_object__close(struct bpf_object *obj)
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index ec3301c..dc966dd 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -26,6 +26,8 @@ void libbpf_set_print(libbpf_print_fn_t warn,
 struct bpf_object;
 
 struct bpf_object *bpf_object__open(const char *path);
+struct bpf_object *bpf_object__open_buffer(void *obj_buf,
+					   size_t obj_buf_sz);
 void bpf_object__close(struct bpf_object *object);
 
 #endif
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179829 — [PATCH v11 24/39] perf tools: Call clang to compile C source to object code

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 24/39] perf tools: Call clang to compile C source to object code
Message-ID<pJXAg-3fG-59@gated-at.bofh.it>
In reply to#1179785
This is the core patch for supporting eBPF on-the-fly compiling, does
the following work:

 1. Search clang compiler using search_program().

 2. Run command template defined in llvm-bpf-cmd-template option in
    [llvm] config section using read_from_pipe(). Patch of clang and
    source code path is injected into shell command using environment
    variable using force_set_env().

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 tools/perf/util/llvm-utils.c | 225 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/llvm-utils.h |   3 +
 2 files changed, 228 insertions(+)

diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index fd5b1bc..dca16e7 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -43,3 +43,228 @@ int perf_llvm_config(const char *var, const char *value)
 		return -1;
 	return 0;
 }
+
+static int
+search_program(const char *def, const char *name,
+	       char *output)
+{
+	char *env, *path, *tmp;
+	char buf[PATH_MAX];
+	int ret;
+
+	output[0] = '\0';
+	if (def && def[0] != '\0') {
+		if (def[0] == '/') {
+			if (access(def, F_OK) == 0) {
+				strlcpy(output, def, PATH_MAX);
+				return 0;
+			}
+		} else if (def[0] != '\0')
+			name = def;
+	}
+
+	env = getenv("PATH");
+	if (!env)
+		return -1;
+	env = strdup(env);
+	if (!env)
+		return -1;
+
+	ret = -ENOENT;
+	path = strtok_r(env, ":",  &tmp);
+	while (path) {
+		scnprintf(buf, sizeof(buf), "%s/%s", path, name);
+		if (access(buf, F_OK) == 0) {
+			strlcpy(output, buf, PATH_MAX);
+			ret = 0;
+			break;
+		}
+		path = strtok_r(NULL, ":", &tmp);
+	}
+
+	free(env);
+	return ret;
+}
+
+#define READ_SIZE	4096
+static int
+read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz)
+{
+	int err = 0;
+	void *buf = NULL;
+	FILE *file = NULL;
+	size_t read_sz = 0, buf_sz = 0;
+
+	file = popen(cmd, "r");
+	if (!file) {
+		pr_err("ERROR: unable to popen cmd: %s\n",
+		       strerror(errno));
+		return -EINVAL;
+	}
+
+	while (!feof(file) && !ferror(file)) {
+		/*
+		 * Make buf_sz always have obe byte extra space so we
+		 * can put '\0' there.
+		 */
+		if (buf_sz - read_sz < READ_SIZE + 1) {
+			void *new_buf;
+
+			buf_sz = read_sz + READ_SIZE + 1;
+			new_buf = realloc(buf, buf_sz);
+
+			if (!new_buf) {
+				pr_err("ERROR: failed to realloc memory\n");
+				err = -ENOMEM;
+				goto errout;
+			}
+
+			buf = new_buf;
+		}
+		read_sz += fread(buf + read_sz, 1, READ_SIZE, file);
+	}
+
+	if (buf_sz - read_sz < 1) {
+		pr_err("ERROR: internal error\n");
+		err = -EINVAL;
+		goto errout;
+	}
+
+	if (ferror(file)) {
+		pr_err("ERROR: error occurred when reading from pipe: %s\n",
+		       strerror(errno));
+		err = -EIO;
+		goto errout;
+	}
+
+	err = WEXITSTATUS(pclose(file));
+	file = NULL;
+	if (err) {
+		err = -EINVAL;
+		goto errout;
+	}
+
+	/*
+	 * If buf is string, give it terminal '\0' to make our life
+	 * easier. If buf is not string, that '\0' is out of space
+	 * indicated by read_sz so caller won't even notice it.
+	 */
+	((char *)buf)[read_sz] = '\0';
+
+	if (!p_buf)
+		free(buf);
+	else
+		*p_buf = buf;
+
+	if (p_read_sz)
+		*p_read_sz = read_sz;
+	return 0;
+
+errout:
+	if (file)
+		pclose(file);
+	free(buf);
+	if (p_buf)
+		*p_buf = NULL;
+	if (p_read_sz)
+		*p_read_sz = 0;
+	return err;
+}
+
+static inline void
+force_set_env(const char *var, const char *value)
+{
+	if (value) {
+		setenv(var, value, 1);
+		pr_debug("set env: %s=%s\n", var, value);
+	} else {
+		unsetenv(var);
+		pr_debug("unset env: %s\n", var);
+	}
+}
+
+static void
+version_notice(void)
+{
+	pr_err(
+"     \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n"
+"     \tYou may want to try git trunk:\n"
+"     \t\tgit clone http://llvm.org/git/llvm.git\n"
+"     \t\t     and\n"
+"     \t\tgit clone http://llvm.org/git/clang.git\n\n"
+"     \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n"
+"     \tdebian/ubuntu:\n"
+"     \t\thttp://llvm.org/apt\n\n"
+"     \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n"
+"     \toption in [llvm] section of ~/.perfconfig to:\n\n"
+"     \t  \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS \\\n"
+"     \t     -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n"
+"     \t     -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n"
+"     \t(Replace /path/to/llc with path to your llc)\n\n"
+);
+}
+
+int llvm__compile_bpf(const char *path, void **p_obj_buf,
+		      size_t *p_obj_buf_sz)
+{
+	int err;
+	char clang_path[PATH_MAX];
+	const char *clang_opt = llvm_param.clang_opt;
+	const char *template = llvm_param.clang_bpf_cmd_template;
+	void *obj_buf = NULL;
+	size_t obj_buf_sz;
+
+	if (!template)
+		template = CLANG_BPF_CMD_DEFAULT_TEMPLATE;
+
+	err = search_program(llvm_param.clang_path,
+			     "clang", clang_path);
+	if (err) {
+		pr_err(
+"ERROR:\tunable to find clang.\n"
+"Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n"
+"     \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n");
+		version_notice();
+		return -ENOENT;
+	}
+
+	force_set_env("CLANG_EXEC", clang_path);
+	force_set_env("CLANG_OPTIONS", clang_opt);
+	force_set_env("KERNEL_INC_OPTIONS", NULL);
+	force_set_env("WORKING_DIR", ".");
+
+	/*
+	 * Since we may reset clang's working dir, path of source file
+	 * should be transferred into absolute path, except we want
+	 * stdin to be source file (testing).
+	 */
+	force_set_env("CLANG_SOURCE",
+		      (path[0] == '-') ? path :
+		      make_nonrelative_path(path));
+
+	pr_debug("llvm compiling command template: %s\n", template);
+	err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
+	if (err) {
+		pr_err("ERROR:\tunable to compile %s\n", path);
+		pr_err("Hint:\tCheck error message shown above.\n");
+		version_notice();
+		pr_err("Hint:\tYou can also pre-compile it into .o\n");
+		goto errout;
+	}
+
+	if (!p_obj_buf)
+		free(obj_buf);
+	else
+		*p_obj_buf = obj_buf;
+
+	if (p_obj_buf_sz)
+		*p_obj_buf_sz = obj_buf_sz;
+	return 0;
+errout:
+	free(obj_buf);
+	if (p_obj_buf)
+		*p_obj_buf = NULL;
+	if (p_obj_buf_sz)
+		*p_obj_buf_sz = 0;
+	return err;
+}
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h
index 504b799..d23adbc 100644
--- a/tools/perf/util/llvm-utils.h
+++ b/tools/perf/util/llvm-utils.h
@@ -33,4 +33,7 @@ struct llvm_param {
 
 extern struct llvm_param llvm_param;
 extern int perf_llvm_config(const char *var, const char *value);
+
+extern int llvm__compile_bpf(const char *path, void **p_obj_buf,
+			     size_t *p_obj_buf_sz);
 #endif
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179830 — [PATCH v11 20/39] bpf tools: Introduce accessors for struct bpf_program

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 20/39] bpf tools: Introduce accessors for struct bpf_program
Message-ID<pJXAg-3fG-61@gated-at.bofh.it>
In reply to#1179785
This patch introduces accessors for user of libbpf to retrieve section
name and fd of a opened/loaded eBPF program. 'struct bpf_prog_handler'
is used for that purpose. Accessors of programs section name and file
descriptor are provided. Set/get private data are also impelmented.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: 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: acme@kernel.org
Link: http://lkml.kernel.org/r/1435716878-189507-21-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/lib/bpf/libbpf.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h | 25 +++++++++++++++
 2 files changed, 107 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index d826d5b..b1575c4 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -98,6 +98,10 @@ struct bpf_program {
 	int nr_reloc;
 
 	int fd;
+
+	struct bpf_object *obj;
+	void *priv;
+	bpf_program_clear_priv_t clear_priv;
 };
 
 struct bpf_object {
@@ -150,6 +154,12 @@ static void bpf_program__clear(struct bpf_program *prog)
 	if (!prog)
 		return;
 
+	if (prog->clear_priv)
+		prog->clear_priv(prog, prog->priv);
+
+	prog->priv = NULL;
+	prog->clear_priv = NULL;
+
 	bpf_program__unload(prog);
 	zfree(&prog->section_name);
 	zfree(&prog->insns);
@@ -224,6 +234,7 @@ bpf_program__new(struct bpf_object *obj, void *data, size_t size,
 
 	obj->programs = progs;
 	obj->nr_programs = nr_progs + 1;
+	prog.obj = obj;
 	progs[nr_progs] = prog;
 	return &progs[nr_progs];
 }
@@ -934,3 +945,74 @@ void bpf_object__close(struct bpf_object *obj)
 
 	free(obj);
 }
+
+struct bpf_program *
+bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
+{
+	size_t idx;
+
+	if (!obj->programs)
+		return NULL;
+	/* First handler */
+	if (prev == NULL)
+		return &obj->programs[0];
+
+	if (prev->obj != obj) {
+		pr_warning("error: program handler doesn't match object\n");
+		return NULL;
+	}
+
+	idx = (prev - obj->programs) + 1;
+	if (idx >= obj->nr_programs)
+		return NULL;
+	return &obj->programs[idx];
+}
+
+int bpf_program__set_private(struct bpf_program *prog,
+			     void *priv,
+			     bpf_program_clear_priv_t clear_priv)
+{
+	if (prog->priv && prog->clear_priv)
+		prog->clear_priv(prog, prog->priv);
+
+	prog->priv = priv;
+	prog->clear_priv = clear_priv;
+	return 0;
+}
+
+int bpf_program__get_private(struct bpf_program *prog, void **ppriv)
+{
+	*ppriv = prog->priv;
+	return 0;
+}
+
+int bpf_program__get_title(struct bpf_program *prog,
+			   const char **ptitle, bool dup)
+{
+	const char *title;
+
+	if (!ptitle)
+		return -EINVAL;
+
+	title = prog->section_name;
+	if (dup) {
+		title = strdup(title);
+		if (!title) {
+			pr_warning("failed to strdup program title\n");
+			*ptitle = NULL;
+			return -ENOMEM;
+		}
+	}
+
+	*ptitle = title;
+	return 0;
+}
+
+int bpf_program__get_fd(struct bpf_program *prog, int *pfd)
+{
+	if (!pfd)
+		return -EINVAL;
+
+	*pfd = prog->fd;
+	return 0;
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 3e69600..9e0e102 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -9,6 +9,7 @@
 #define __BPF_LIBBPF_H
 
 #include <stdio.h>
+#include <stdbool.h>
 
 /*
  * In include/linux/compiler-gcc.h, __printf is defined. However
@@ -34,6 +35,30 @@ void bpf_object__close(struct bpf_object *object);
 int bpf_object__load(struct bpf_object *obj);
 int bpf_object__unload(struct bpf_object *obj);
 
+/* Accessors of bpf_program. */
+struct bpf_program;
+struct bpf_program *bpf_program__next(struct bpf_program *prog,
+				      struct bpf_object *obj);
+
+#define bpf_object__for_each_program(pos, obj)		\
+	for ((pos) = bpf_program__next(NULL, (obj));	\
+	     (pos) != NULL;				\
+	     (pos) = bpf_program__next((pos), (obj)))
+
+typedef void (*bpf_program_clear_priv_t)(struct bpf_program *,
+					 void *);
+
+int bpf_program__set_private(struct bpf_program *prog, void *priv,
+			     bpf_program_clear_priv_t clear_priv);
+
+int bpf_program__get_private(struct bpf_program *prog,
+			     void **ppriv);
+
+int bpf_program__get_title(struct bpf_program *prog,
+			   const char **ptitle, bool dup);
+
+int bpf_program__get_fd(struct bpf_program *prog, int *pfd);
+
 /*
  * We don't need __attribute__((packed)) now since it is
  * unnecessary for 'bpf_map_def' because they are all aligned.
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179831 — [PATCH v11 37/39] perf tools: Suppress probing messages when probing by BPF loading

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 37/39] perf tools: Suppress probing messages when probing by BPF loading
Message-ID<pJXAg-3fG-63@gated-at.bofh.it>
In reply to#1179785
This patch suppress message output by add_perf_probe_events() and
del_perf_probe_events() if they are triggered by BPF loading. Before
this patch, when using 'perf record' with BPF object/source as event
selector, following message will be output:

     Added new event:
           perf_bpf_probe:lock_page_ret (on __lock_page%return)
        You can now use it in all perf tools, such as:
	            perf record -e perf_bpf_probe:lock_page_ret -aR sleep 1
     ...
     Removed event: perf_bpf_probe:lock_page_ret

Which is misleading, especially 'use it in all perf tools' because they
will be removed after 'pref record' exit.

In this patch, a 'silent' field is appended into probe_conf to control
output. bpf__{,un}probe() set it to true when calling
{add,del}_perf_probe_events().

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 tools/perf/util/bpf-loader.c  |  6 ++++++
 tools/perf/util/probe-event.c | 22 ++++++++++++++++------
 tools/perf/util/probe-event.h |  1 +
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 63077b9..4aa372b 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -199,6 +199,7 @@ static bool is_probing;
 int bpf__unprobe(void)
 {
 	struct strfilter *delfilter;
+	bool old_silent = probe_conf.silent;
 	int ret;
 
 	if (!is_probing)
@@ -210,7 +211,9 @@ int bpf__unprobe(void)
 		return -ENOMEM;
 	}
 
+	probe_conf.silent = true;
 	ret = del_perf_probe_events(delfilter);
+	probe_conf.silent = old_silent;
 	strfilter__delete(delfilter);
 	if (ret < 0 && is_probing)
 		pr_err("Error: failed to delete events: %s\n",
@@ -223,15 +226,18 @@ int bpf__unprobe(void)
 int bpf__probe(void)
 {
 	int err;
+	bool old_silent = probe_conf.silent;
 
 	if (nr_probe_events <= 0)
 		return 0;
 
+	probe_conf.silent = true;
 	probe_conf.max_probes = MAX_PROBES;
 	/* Let add_perf_probe_events keeps probe_trace_event */
 	err = add_perf_probe_events(probe_event_array,
 				    nr_probe_events,
 				    false);
+	probe_conf.silent = old_silent;
 
 	/* add_perf_probe_events return negative when fail */
 	if (err < 0)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 083e8b4..b9573c5 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -51,7 +51,9 @@
 #define PERFPROBE_GROUP "probe"
 
 bool probe_event_dry_run;	/* Dry run flag */
-struct probe_conf probe_conf;
+struct probe_conf probe_conf = {
+	.silent = false,
+};
 
 #define semantic_error(msg ...) pr_err("Semantic error :" msg)
 
@@ -2250,10 +2252,12 @@ static int show_perf_probe_event(const char *group, const char *event,
 
 	ret = perf_probe_event__sprintf(group, event, pev, module, &buf);
 	if (ret >= 0) {
-		if (use_stdout)
+		if (use_stdout && !probe_conf.silent)
 			printf("%s\n", buf.buf);
-		else
+		else if (!probe_conf.silent)
 			pr_info("%s\n", buf.buf);
+		else
+			pr_debug("%s\n", buf.buf);
 	}
 	strbuf_release(&buf);
 
@@ -2512,7 +2516,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 
 	safename = (pev->point.function && !strisglob(pev->point.function));
 	ret = 0;
-	pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
+	if (!probe_conf.silent)
+		pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
+	else
+		pr_debug("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
 	for (i = 0; i < ntevs; i++) {
 		tev = &tevs[i];
 		/* Skip if the symbol is out of .text or blacklisted */
@@ -2569,7 +2576,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 		warn_uprobe_event_compat(tev);
 
 	/* Note that it is possible to skip all events because of blacklist */
-	if (ret >= 0 && event) {
+	if (ret >= 0 && event && !probe_conf.silent) {
 		/* Show how to use the event. */
 		pr_info("\nYou can now use it in all perf tools, such as:\n\n");
 		pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", group, event);
@@ -2865,7 +2872,10 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
 		goto error;
 	}
 
-	pr_info("Removed event: %s\n", ent->s);
+	if (!probe_conf.silent)
+		pr_info("Removed event: %s\n", ent->s);
+	else
+		pr_debug("Removed event: %s\n", ent->s);
 	return 0;
 error:
 	pr_warning("Failed to delete event: %s\n",
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 4b7a951..116b0aa 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -13,6 +13,7 @@ struct probe_conf {
 	bool	force_add;
 	bool	no_inlines;
 	int	max_probes;
+	bool	silent;
 };
 extern struct probe_conf probe_conf;
 extern bool probe_event_dry_run;
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179833 — [PATCH v11 26/39] perf tools: Auto detecting kernel include options

FromWang Nan <wangnan0@huawei.com>
Date2015-07-08 15:30 +0200
Subject[PATCH v11 26/39] perf tools: Auto detecting kernel include options
Message-ID<pJXAg-3fG-83@gated-at.bofh.it>
In reply to#1179785
To help user find correct kernel include options, this patch extracts
them from kbuild system by an embedded script kinc_fetch_script, which
creates a temporary directory, generates Makefile and an empty dummy.o
then use the Makefile to fetch $(NOSTDINC_FLAGS), $(LINUXINCLUDE) and
$(EXTRA_CFLAGS) options. The result is passed to compiler script using
'KERNEL_INC_OPTIONS' environment variable.

Because options from kbuild contains relative path like
'Iinclude/generated/uapi', the work directory must be changed. This is
done by previous patch.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 tools/perf/util/llvm-utils.c | 59 ++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 54 insertions(+), 5 deletions(-)

diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 2ca2bd6..b658896 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -218,15 +218,42 @@ static const char *kbuild_detector =
 "fi\n"
 "exit -1\n";
 
+static const char *kinc_fetch_script =
+"#!/usr/bin/env sh\n"
+"if ! test -d \"$KBUILD_DIR\"\n"
+"then\n"
+"	exit -1\n"
+"fi\n"
+"if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n"
+"then\n"
+"	exit -1\n"
+"fi\n"
+"TMPDIR=`mktemp -d`\n"
+"if test -z \"$TMPDIR\"\n"
+"then\n"
+"    exit -1\n"
+"fi\n"
+"cat << EOF > $TMPDIR/Makefile\n"
+"obj-y := dummy.o\n"
+"\\$(obj)/%.o: \\$(src)/%.c\n"
+"\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n"
+"EOF\n"
+"touch $TMPDIR/dummy.c\n"
+"make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n"
+"RET=$?\n"
+"rm -rf $TMPDIR\n"
+"exit $RET\n";
+
 static inline void
-get_kbuild_opts(char **kbuild_dir)
+get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts)
 {
 	int err;
 
-	if (!kbuild_dir)
+	if (!kbuild_dir || !kbuild_include_opts)
 		return;
 
 	*kbuild_dir = NULL;
+	*kbuild_include_opts = NULL;
 
 	if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) {
 		pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n");
@@ -247,6 +274,26 @@ get_kbuild_opts(char **kbuild_dir)
 "     \tdetection.\n\n");
 		return;
 	}
+
+	pr_debug("Kernel build dir is set to %s\n", *kbuild_dir);
+	force_set_env("KBUILD_DIR", *kbuild_dir);
+	err = read_from_pipe(kinc_fetch_script,
+			     (void **)kbuild_include_opts,
+			     NULL);
+	if (err) {
+		pr_warning(
+"WARNING:\tunable to get kernel include directories from '%s'\n"
+"Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n"
+"     \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n"
+"     \toption in [llvm] to \"\" to suppress this detection.\n\n",
+			*kbuild_dir);
+
+		free(*kbuild_dir);
+		*kbuild_dir = NULL;
+		return;
+	}
+
+	pr_debug("include option is set to %s\n", *kbuild_include_opts);
 }
 
 int llvm__compile_bpf(const char *path, void **p_obj_buf,
@@ -256,7 +303,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	char clang_path[PATH_MAX];
 	const char *clang_opt = llvm_param.clang_opt;
 	const char *template = llvm_param.clang_bpf_cmd_template;
-	char *kbuild_dir = NULL;
+	char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
 	void *obj_buf = NULL;
 	size_t obj_buf_sz;
 
@@ -278,11 +325,11 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	 * This is an optional work. Even it fail we can continue our
 	 * work. Needn't to check error return.
 	 */
-	get_kbuild_opts(&kbuild_dir);
+	get_kbuild_opts(&kbuild_dir, &kbuild_include_opts);
 
 	force_set_env("CLANG_EXEC", clang_path);
 	force_set_env("CLANG_OPTIONS", clang_opt);
-	force_set_env("KERNEL_INC_OPTIONS", NULL);
+	force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts);
 	force_set_env("WORKING_DIR", kbuild_dir ? : ".");
 
 	/*
@@ -305,6 +352,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	}
 
 	free(kbuild_dir);
+	free(kbuild_include_opts);
 	if (!p_obj_buf)
 		free(obj_buf);
 	else
@@ -315,6 +363,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	return 0;
 errout:
 	free(kbuild_dir);
+	free(kbuild_include_opts);
 	free(obj_buf);
 	if (p_obj_buf)
 		*p_obj_buf = NULL;
-- 
1.8.3.4

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

[toc] | [prev] | [next] | [standalone]


#1179863 — Re: [PATCH v11 00/39] perf tools: filtering events using eBPF programs - part1

FromArnaldo Carvalho de Melo <acme@kernel.org>
Date2015-07-08 16:10 +0200
SubjectRe: [PATCH v11 00/39] perf tools: filtering events using eBPF programs - part1
Message-ID<pJYcW-3IU-19@gated-at.bofh.it>
In reply to#1179785
Em Wed, Jul 08, 2015 at 01:13:49PM +0000, Wang Nan escreveu:
> Hi Arnaldo Carvalho de Melo,

Hi Wang (hope this shorter form is ok on your country, calling me just
"Arnaldo" is fine in mine :-))
 
>    I rearranged the first 39 patches of this patchset according to
> your comments. After applying all of them you can use a hello world
> BPF program for testing. They are based on your 'tmp.perf/ebpf', commit
> 60cd37eb100c4880b28078a47f3062fac7572095.
 
>   I hope I can manage a public avaliable git repository for you
> tomorrow (tomorrow means 24 hours later). What about a repository on
> github? However I have to do this out of my office because of company's
> IT policy.

Why not ask the kernel.org admins for a:

git://git.kernel.org/pub/scm/linux/kernel/git/wangnan0/linux.git

Area?
 
>  In this v11 you can see following improvements:
> 
>  Commit messages improvements:
>  'bpf tools: Collect symbol table from SHT_SYMTAB section'
>  'bpf tools: Collect relocation sections from SHT_REL sections'
>  'bpf tools: Record map accessing instructions for each program'
>  'bpf tools: Relocate eBPF programs'
>  'bpf tools: Link all bpf objects onto a list'
> 
>  Decoupling:
>  'bpf tools: Collect eBPF programs from their own sections'
>  'bpf tools: Introduce accessors for struct bpf_program'
> 
>  Renaming: bpf_object__for_each -> bpf_object__for_each_safe
>  'bpf tools: Link all bpf objects onto a list'
> 
>  Patch ordering:
>  'perf tools: Make perf depend on libbpf'
> 
>  Error message improvement (refer to http://llvm.org/apt):
>  'perf tools: Call clang to compile C source to object code'
> 
> In this v11 part 1 patch set, I haven't follow your comment in
> 'bpf tools: Introduce accessors for struct bpf_object' that let me
> update accessors API from returning error code to returning actual
> value and indicate error using invalid values. I prefer current API
> because I saw and fixed many bugs related to error code in perf's
> code (like commit ed30775).

> Reason of those bugs are misusing of error code: some part of code
> return negative on error, some part of code return non-zero on error,
> and developer forgot them. I don't want libbpf to introduce more bugs
> like them. But if you insist on it, I'll change it.

If you don't follow the chosen convention, bugs appear.

And the convention of returning < 0 for errors and >= 0 for success is
common, just see the libc wrappers for syscalls, see the open, read,
write man pages, etc, that is an ooooold convention :-)

And those wrappers struck me as exaggerated, see one of them:

int bpf_program__get_fd(struct bpf_program *prog, int *pfd)
{            
	if (!pfd)
		return -EINVAL;
     
	*pfd = prog->fd;
	return 0;
}

What can go wrong with accessing a struct member? The only think I
thought about was: hey, the struct pointer needs to be checked against
NULL, but no, in this case what you thought could go wrong was for the
library user to pass a NULL pointer as the return place (pfd).

So, yes, I still think this is way exaggerated, if you insist that the
struct must be opaque and thus we need accessors, I think that having:

int bpf_program__fd(struct bpf_program *prog)
{
	return prog->fd;
}

Is way more sane, yes, I would trow away those extra four characters
(get_).

Heck, in this case there is not even a possible problem where we would
want to return something negative instead of doing what was requested.

If you find any other part in tools/perf/ (or anywhere else) that
doesn't follows the convention it states it conforms to, please file a
bug or submit a patch, like you did in the case you mentioned (ed30775),
it would be a bug and has to be fixed.

- Arnaldo
 
> Wang Nan (39):
>   bpf: Use correct #ifdef controller for trace_call_bpf()
>   tracing, perf: Implement BPF programs attached to uprobes
>   bpf tools: Introduce 'bpf' library and add bpf feature check
>   bpf tools: Allow caller to set printing function
>   bpf tools: Open eBPF object file and do basic validation
>   bpf tools: Read eBPF object from buffer
>   bpf tools: Check endianness and make libbpf fail early
>   bpf tools: Iterate over ELF sections to collect information
>   bpf tools: Collect version and license from ELF sections
>   bpf tools: Collect map definitions from 'maps' section
>   bpf tools: Collect symbol table from SHT_SYMTAB section
>   bpf tools: Collect eBPF programs from their own sections
>   bpf tools: Collect relocation sections from SHT_REL sections
>   bpf tools: Record map accessing instructions for each program
>   bpf tools: Add bpf.c/h for common bpf operations
>   bpf tools: Create eBPF maps defined in an object file
>   bpf tools: Relocate eBPF programs
>   bpf tools: Introduce bpf_load_program() to bpf.c
>   bpf tools: Load eBPF programs in object files into kernel
>   bpf tools: Introduce accessors for struct bpf_program
>   bpf tools: Introduce accessors for struct bpf_object
>   bpf tools: Link all bpf objects onto a list
>   perf tools: Introduce llvm config options
>   perf tools: Call clang to compile C source to object code
>   perf tools: Auto detecting kernel build directory
>   perf tools: Auto detecting kernel include options
>   perf tests: Add LLVM test for eBPF on-the-fly compiling
>   perf tools: Make perf depend on libbpf
>   perf record: Enable passing bpf object file to --event
>   perf record: Compile scriptlets if pass '.c' to --event
>   perf tools: Parse probe points of eBPF programs during preparation
>   perf probe: Attach trace_probe_event with perf_probe_event
>   perf record: Probe at kprobe points
>   perf record: Load all eBPF object into kernel
>   perf tools: Add bpf_fd field to evsel and config it
>   perf tools: Attach eBPF program to perf event
>   perf tools: Suppress probing messages when probing by BPF loading
>   perf record: Add clang options for compiling BPF scripts
>   bpf tools: Load a program with different instance using preprocessor
> 
>  include/linux/trace_events.h    |    7 +-
>  kernel/events/core.c            |    4 +-
>  kernel/trace/Kconfig            |    2 +-
>  kernel/trace/trace_uprobe.c     |    5 +
>  tools/build/Makefile.feature    |    6 +-
>  tools/build/feature/Makefile    |    6 +-
>  tools/build/feature/test-bpf.c  |   18 +
>  tools/lib/bpf/.gitignore        |    2 +
>  tools/lib/bpf/Build             |    1 +
>  tools/lib/bpf/Makefile          |  195 +++++++
>  tools/lib/bpf/bpf.c             |   85 +++
>  tools/lib/bpf/bpf.h             |   23 +
>  tools/lib/bpf/libbpf.c          | 1184 +++++++++++++++++++++++++++++++++++++++
>  tools/lib/bpf/libbpf.h          |  107 ++++
>  tools/perf/MANIFEST             |    3 +
>  tools/perf/Makefile.perf        |   19 +-
>  tools/perf/builtin-probe.c      |    4 +-
>  tools/perf/builtin-record.c     |   43 +-
>  tools/perf/config/Makefile      |   19 +-
>  tools/perf/tests/Build          |    1 +
>  tools/perf/tests/builtin-test.c |    4 +
>  tools/perf/tests/llvm.c         |   85 +++
>  tools/perf/tests/make           |    4 +-
>  tools/perf/tests/tests.h        |    1 +
>  tools/perf/util/Build           |    2 +
>  tools/perf/util/bpf-loader.c    |  310 ++++++++++
>  tools/perf/util/bpf-loader.h    |   46 ++
>  tools/perf/util/config.c        |    4 +
>  tools/perf/util/debug.c         |    5 +
>  tools/perf/util/debug.h         |    1 +
>  tools/perf/util/evlist.c        |   41 ++
>  tools/perf/util/evlist.h        |    1 +
>  tools/perf/util/evsel.c         |   17 +
>  tools/perf/util/evsel.h         |    1 +
>  tools/perf/util/llvm-utils.c    |  373 ++++++++++++
>  tools/perf/util/llvm-utils.h    |   39 ++
>  tools/perf/util/parse-events.c  |   16 +
>  tools/perf/util/parse-events.h  |    2 +
>  tools/perf/util/parse-events.l  |    6 +
>  tools/perf/util/parse-events.y  |   29 +-
>  tools/perf/util/probe-event.c   |   82 +--
>  tools/perf/util/probe-event.h   |    7 +-
>  42 files changed, 2759 insertions(+), 51 deletions(-)
>  create mode 100644 tools/build/feature/test-bpf.c
>  create mode 100644 tools/lib/bpf/.gitignore
>  create mode 100644 tools/lib/bpf/Build
>  create mode 100644 tools/lib/bpf/Makefile
>  create mode 100644 tools/lib/bpf/bpf.c
>  create mode 100644 tools/lib/bpf/bpf.h
>  create mode 100644 tools/lib/bpf/libbpf.c
>  create mode 100644 tools/lib/bpf/libbpf.h
>  create mode 100644 tools/perf/tests/llvm.c
>  create mode 100644 tools/perf/util/bpf-loader.c
>  create mode 100644 tools/perf/util/bpf-loader.h
>  create mode 100644 tools/perf/util/llvm-utils.c
>  create mode 100644 tools/perf/util/llvm-utils.h
> 
> -- 
> 1.8.3.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[toc] | [prev] | [standalone]


Page 2 of 2 — ← Prev page 1 [2]

Back to top | Article view | linux.kernel


csiph-web