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


Groups > linux.kernel > #1211076 > unrolled thread

[GIT PULL 00/29] perf tools: filtering events using eBPF programs

Started byWang Nan <wangnan0@huawei.com>
First post2015-08-21 12:20 +0200
Last post2015-08-21 12:30 +0200
Articles 20 on this page of 30 — 3 participants

Back to article view | Back to linux.kernel


Contents

  [GIT PULL 00/29] perf tools: filtering events using eBPF programs Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 25/29] perf record: Support custom vmlinux path Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 14/29] perf tests: Enforce LLVM test for BPF test Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 18/29] perf probe: Reset args and nargs for probe_trace_event when failure Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 11/29] perf tools: Suppress probing messages when probing by BPF loading Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 13/29] perf tools: Infrastructure for compiling scriptlets when passing '.c' to --event Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 19/29] perf tools: Move linux/filter.h to tools/include Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 05/29] perf probe: Attach trace_probe_event with perf_probe_event Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 21/29] perf tools: Introduce arch_get_reg_info() for x86 Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 03/29] perf ebpf: Add the libbpf glue Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 10/29] perf tools: Attach eBPF program to perf event Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 01/29] perf probe: Try to use symbol table if searching debug info failed Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
      Re: [PATCH 01/29] perf probe: Try to use symbol table if searching  debug info failed Arnaldo Carvalho de Melo <acme@redhat.com> - 2015-08-21 16:20 +0200
      [tip:perf/core] perf probe:   Try to use symbol table if searching debug info failed tip-bot for Wang Nan <tipbot@zytor.com> - 2015-08-22 09:00 +0200
    [PATCH 16/29] bpf tools: Load a program with different instances using preprocessor Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 07/29] perf bpf: Collect 'struct perf_probe_event' for bpf_program Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 04/29] perf tools: Enable passing bpf object file to --event Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 20/29] perf tools: Add BPF_PROLOGUE config options for further patches Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 24/29] perf tools: Use same BPF program if arguments are identical Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 23/29] perf tools: Generate prologue for BPF programs Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 02/29] perf tools: Make perf depend on libbpf Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 29/29] bpf: Introduce function for outputing data to perf event Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 12/29] perf record: Add clang options for compiling BPF scripts Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 06/29] perf record, bpf: Parse and probe eBPF programs probe points Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 27/29] perf tools: Support attach BPF program on uprobe events Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 17/29] perf tools: Fix probe-event.h include Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 28/29] tools lib traceevent: Support function __get_dynamic_array_len Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
      Re: [PATCH 28/29] tools lib traceevent: Support function  __get_dynamic_array_len Arnaldo Carvalho de Melo <acme@redhat.com> - 2015-08-21 18:10 +0200
    [PATCH 15/29] perf test: Add 'perf test BPF' Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:20 +0200
    [PATCH 08/29] perf record: Load all eBPF object into kernel Wang Nan <wangnan0@huawei.com> - 2015-08-21 12:30 +0200

Page 1 of 2  [1] 2  Next page →


#1211076 — [GIT PULL 00/29] perf tools: filtering events using eBPF programs

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[GIT PULL 00/29] perf tools: filtering events using eBPF programs
Message-ID<pZRAt-DT-3@gated-at.bofh.it>
Hi Arnaldo,

This is the first time I use my new kernel.org account to generate pull
request for you. I hope it work.

The following changes since commit acc60583a43fe93ff42d707a39d478c7dbe24028:

  perf tools: Fix Intel PT timestamp handling (2015-08-20 16:45:01 -0300)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/pi3orama/linux tags/perf-ebpf-for-acme-20150821

for you to fetch changes up to 15756861299809103c00d9342352eb22bb84f20f:

  perf tools: Support attach BPF program on uprobe events (2015-08-21 03:57:12 +0000)

----------------------------------------------------------------
perf bpf improvements:

 - Improve 'perf test BPF'

   Don't use the hacking way in previous series that make perf act test
   target and run 'perf record' using system().

   In this series, perf test BPF open the evlist and evsel, attach then
   record, analysis result in its own context.

 - Improve error reporting

   Use strerror style error reporting. Only output debug information
   in bpf-loader.c.

Signed-off-by: Wang Nan <wangnan0@huawei.com>

----------------------------------------------------------------
He Kuang (3):
      perf tools: Move linux/filter.h to tools/include
      perf tools: Introduce arch_get_reg_info() for x86
      perf record: Support custom vmlinux path

Wang Nan (24):
      perf probe: Try to use symbol table if searching debug info failed
      perf tools: Make perf depend on libbpf
      perf ebpf: Add the libbpf glue
      perf tools: Enable passing bpf object file to --event
      perf probe: Attach trace_probe_event with perf_probe_event
      perf record, bpf: Parse and probe eBPF programs probe points
      perf bpf: Collect 'struct perf_probe_event' for bpf_program
      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
      perf tools: Infrastructure for compiling scriptlets when passing '.c' to --event
      perf tests: Enforce LLVM test for BPF test
      perf test: Add 'perf test BPF'
      bpf tools: Load a program with different instances using preprocessor
      perf tools: Fix probe-event.h include
      perf probe: Reset args and nargs for probe_trace_event when failure
      perf tools: Add BPF_PROLOGUE config options for further patches
      perf tools: Add prologue for BPF programs for fetching arguments
      perf tools: Generate prologue for BPF programs
      perf tools: Use same BPF program if arguments are identical
      perf probe: Init symbol as kprobe
      perf tools: Support attach BPF program on uprobe events

 tools/build/Makefile.feature          |   6 +-
 tools/include/linux/filter.h          | 237 +++++++++++
 tools/lib/bpf/libbpf.c                | 143 ++++++-
 tools/lib/bpf/libbpf.h                |  22 ++
 tools/perf/MANIFEST                   |   4 +
 tools/perf/Makefile.perf              |  19 +-
 tools/perf/arch/x86/Makefile          |   1 +
 tools/perf/arch/x86/util/Build        |   2 +
 tools/perf/arch/x86/util/dwarf-regs.c | 104 +++--
 tools/perf/builtin-probe.c            |   4 +-
 tools/perf/builtin-record.c           |  52 ++-
 tools/perf/config/Makefile            |  31 +-
 tools/perf/tests/Build                |  10 +-
 tools/perf/tests/bpf-script-example.c |  44 +++
 tools/perf/tests/bpf.c                | 170 ++++++++
 tools/perf/tests/builtin-test.c       |  12 +
 tools/perf/tests/llvm.c               | 123 +++++-
 tools/perf/tests/llvm.h               |  15 +
 tools/perf/tests/make                 |   4 +-
 tools/perf/tests/tests.h              |   3 +
 tools/perf/util/Build                 |   2 +
 tools/perf/util/bpf-loader.c          | 723 ++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h          |  92 +++++
 tools/perf/util/bpf-prologue.c        | 442 +++++++++++++++++++++
 tools/perf/util/bpf-prologue.h        |  34 ++
 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/include/dwarf-regs.h  |   7 +
 tools/perf/util/parse-events.c        |  26 ++
 tools/perf/util/parse-events.h        |   4 +
 tools/perf/util/parse-events.l        |   6 +
 tools/perf/util/parse-events.y        |  29 +-
 tools/perf/util/probe-event.c         |  86 ++--
 tools/perf/util/probe-event.h         |   8 +-
 tools/perf/util/probe-file.c          |   5 +-
 tools/perf/util/probe-finder.c        |   4 +
 38 files changed, 2432 insertions(+), 102 deletions(-)
 create mode 100644 tools/include/linux/filter.h
 create mode 100644 tools/perf/tests/bpf-script-example.c
 create mode 100644 tools/perf/tests/bpf.c
 create mode 100644 tools/perf/tests/llvm.h
 create mode 100644 tools/perf/util/bpf-loader.c
 create mode 100644 tools/perf/util/bpf-loader.h
 create mode 100644 tools/perf/util/bpf-prologue.c
 create mode 100644 tools/perf/util/bpf-prologue.h
--
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] | [next] | [standalone]


#1211077 — [PATCH 25/29] perf record: Support custom vmlinux path

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 25/29] perf record: Support custom vmlinux path
Message-ID<pZRAu-DT-17@gated-at.bofh.it>
In reply to#1211076
From: He Kuang <hekuang@huawei.com>

Make perf-record command support --vmlinux option if BPF_PROLOGUE is on.

'perf record' needs vmlinux as the source of DWARF info to generate
prologue for BPF programs, so path of vmlinux should be specified.

Short name 'k' has been taken by 'clockid'. This patch skips the short
option name and use '--vmlinux' for vmlinux path.

Signed-off-by: He Kuang <hekuang@huawei.com>
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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-38-git-send-email-wangnan0@huawei.com
---
 tools/perf/builtin-record.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index c7353ba..c5e1080 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -1100,6 +1100,10 @@ struct option __record_options[] = {
 		   "clang binary to use for compiling BPF scriptlets"),
 	OPT_STRING(0, "clang-opt", &llvm_param.clang_opt, "clang options",
 		   "options passed to clang when compiling BPF scriptlets"),
+#ifdef HAVE_BPF_PROLOGUE
+	OPT_STRING(0, "vmlinux", &symbol_conf.vmlinux_name,
+		   "file", "vmlinux pathname"),
+#endif
 #endif
 	OPT_END()
 };
-- 
2.1.0

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


#1211078 — [PATCH 14/29] perf tests: Enforce LLVM test for BPF test

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 14/29] perf tests: Enforce LLVM test for BPF test
Message-ID<pZRAu-DT-21@gated-at.bofh.it>
In reply to#1211076
This patch replaces the original toy BPF program with previous introduced
bpf-script-example.c. Dynamically embedded it into 'llvm-src.c'.

The newly introduced BPF program attaches a BPF program at
'sys_epoll_pwait()', and collect half samples from it. perf itself never
use that syscall, so further test can verify their result with it.

Since BPF program require LINUX_VERSION_CODE of runtime kernel, this
patch computes that code from uname.

Since the resuling BPF object is useful for further testcases, this patch
introduces 'prepare' and 'cleanup' method to tests, and makes test__llvm()
create a MAP_SHARED memory array to hold the resulting object.

Signed-off-by: He Kuang <hekuang@huawei.com>
Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.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: 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: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
---
 tools/perf/tests/Build          |   9 +++-
 tools/perf/tests/builtin-test.c |   8 ++++
 tools/perf/tests/llvm.c         | 104 +++++++++++++++++++++++++++++++++++-----
 tools/perf/tests/llvm.h         |  14 ++++++
 tools/perf/tests/tests.h        |   2 +
 5 files changed, 123 insertions(+), 14 deletions(-)
 create mode 100644 tools/perf/tests/llvm.h

diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index c1518bd..8c98409 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -32,7 +32,14 @@ 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-y += llvm.o llvm-src.o
+
+$(OUTPUT)tests/llvm-src.c: tests/bpf-script-example.c
+	$(Q)echo '#include <tests/llvm.h>' > $@
+	$(Q)echo 'const char test_llvm__bpf_prog[] =' >> $@
+	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
+	$(Q)echo ';' >> $@
+
 
 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 136cd93..1a349e8 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -17,6 +17,8 @@
 static struct test {
 	const char *desc;
 	int (*func)(void);
+	void (*prepare)(void);
+	void (*cleanup)(void);
 } tests[] = {
 	{
 		.desc = "vmlinux symtab matches kallsyms",
@@ -177,6 +179,8 @@ static struct test {
 	{
 		.desc = "Test LLVM searching and compiling",
 		.func = test__llvm,
+		.prepare = test__llvm_prepare,
+		.cleanup = test__llvm_cleanup,
 	},
 	{
 		.func = NULL,
@@ -265,7 +269,11 @@ static int __cmd_test(int argc, const char *argv[], struct intlist *skiplist)
 		}
 
 		pr_debug("\n--- start ---\n");
+		if (tests[curr].prepare)
+			tests[curr].prepare();
 		err = run_test(&tests[curr]);
+		if (tests[curr].cleanup)
+			tests[curr].cleanup();
 		pr_debug("---- end ----\n%s:", tests[curr].desc);
 
 		switch (err) {
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index a337356..e48eb64 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -1,9 +1,13 @@
 #include <stdio.h>
+#include <sys/utsname.h>
 #include <bpf/libbpf.h>
 #include <util/llvm-utils.h>
 #include <util/cache.h>
+#include <util/util.h>
+#include <sys/mman.h>
 #include "tests.h"
 #include "debug.h"
+#include "llvm.h"
 
 static int perf_config_cb(const char *var, const char *val,
 			  void *arg __maybe_unused)
@@ -11,16 +15,6 @@ static int perf_config_cb(const char *var, const char *val,
 	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)
 {
@@ -41,12 +35,44 @@ static int test__bpf_parsing(void *obj_buf __maybe_unused,
 }
 #endif
 
+static char *
+compose_source(void)
+{
+	struct utsname utsname;
+	int version, patchlevel, sublevel, err;
+	unsigned long version_code;
+	char *code;
+
+	if (uname(&utsname))
+		return NULL;
+
+	err = sscanf(utsname.release, "%d.%d.%d",
+		     &version, &patchlevel, &sublevel);
+	if (err != 3) {
+		fprintf(stderr, " (Can't get kernel version from uname '%s')",
+			utsname.release);
+		return NULL;
+	}
+
+	version_code = (version << 16) + (patchlevel << 8) + sublevel;
+	err = asprintf(&code, "#define LINUX_VERSION_CODE 0x%08lx;\n%s",
+		       version_code, test_llvm__bpf_prog);
+	if (err < 0)
+		return NULL;
+
+	return code;
+}
+
+#define SHARED_BUF_INIT_SIZE	(1 << 20)
+struct test_llvm__bpf_result *p_test_llvm__bpf_result;
+
 int test__llvm(void)
 {
 	char *tmpl_new, *clang_opt_new;
 	void *obj_buf;
 	size_t obj_buf_sz;
 	int err, old_verbose;
+	char *source;
 
 	perf_config(perf_config_cb, NULL);
 
@@ -73,10 +99,22 @@ int test__llvm(void)
 	if (!llvm_param.clang_opt)
 		llvm_param.clang_opt = strdup("");
 
-	err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog,
-		       llvm_param.clang_bpf_cmd_template);
-	if (err < 0)
+	source = compose_source();
+	if (!source) {
+		pr_err("Failed to compose source code\n");
+		return -1;
+	}
+
+	/* Quote __EOF__ so strings in source won't be expanded by shell */
+	err = asprintf(&tmpl_new, "cat << '__EOF__' | %s\n%s\n__EOF__\n",
+		       llvm_param.clang_bpf_cmd_template, source);
+	free(source);
+	source = NULL;
+	if (err < 0) {
+		pr_err("Failed to alloc new template\n");
 		return -1;
+	}
+
 	err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt);
 	if (err < 0)
 		return -1;
@@ -93,6 +131,46 @@ int test__llvm(void)
 	}
 
 	err = test__bpf_parsing(obj_buf, obj_buf_sz);
+	if (!err && p_test_llvm__bpf_result) {
+		if (obj_buf_sz > SHARED_BUF_INIT_SIZE) {
+			pr_err("Resulting object too large\n");
+		} else {
+			p_test_llvm__bpf_result->size = obj_buf_sz;
+			memcpy(p_test_llvm__bpf_result->object,
+			       obj_buf, obj_buf_sz);
+		}
+	}
 	free(obj_buf);
 	return err;
 }
+
+void test__llvm_prepare(void)
+{
+	p_test_llvm__bpf_result = mmap(NULL, SHARED_BUF_INIT_SIZE,
+				       PROT_READ | PROT_WRITE,
+				       MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+	if (!p_test_llvm__bpf_result)
+		return;
+	memset((void *)p_test_llvm__bpf_result, '\0', SHARED_BUF_INIT_SIZE);
+}
+
+void test__llvm_cleanup(void)
+{
+	unsigned long boundary, buf_end;
+
+	if (!p_test_llvm__bpf_result)
+		return;
+	if (p_test_llvm__bpf_result->size == 0) {
+		munmap((void *)p_test_llvm__bpf_result, SHARED_BUF_INIT_SIZE);
+		p_test_llvm__bpf_result = NULL;
+		return;
+	}
+
+	buf_end = (unsigned long)p_test_llvm__bpf_result + SHARED_BUF_INIT_SIZE;
+
+	boundary = (unsigned long)(p_test_llvm__bpf_result);
+	boundary += p_test_llvm__bpf_result->size;
+	boundary = (boundary + (page_size - 1)) &
+			(~((unsigned long)page_size - 1));
+	munmap((void *)boundary, buf_end - boundary);
+}
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
new file mode 100644
index 0000000..1e89e46
--- /dev/null
+++ b/tools/perf/tests/llvm.h
@@ -0,0 +1,14 @@
+#ifndef PERF_TEST_LLVM_H
+#define PERF_TEST_LLVM_H
+
+#include <stddef.h> /* for size_t */
+
+struct test_llvm__bpf_result {
+	size_t size;
+	char object[];
+};
+
+extern struct test_llvm__bpf_result *p_test_llvm__bpf_result;
+extern const char test_llvm__bpf_prog[];
+
+#endif
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h
index bf113a2..0d79f04 100644
--- a/tools/perf/tests/tests.h
+++ b/tools/perf/tests/tests.h
@@ -63,6 +63,8 @@ int test__fdarray__add(void);
 int test__kmod_path__parse(void);
 int test__thread_map(void);
 int test__llvm(void);
+void test__llvm_prepare(void);
+void test__llvm_cleanup(void);
 
 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__)
 #ifdef HAVE_DWARF_UNWIND_SUPPORT
-- 
2.1.0

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


#1211079 — [PATCH 18/29] perf probe: Reset args and nargs for probe_trace_event when failure

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 18/29] perf probe: Reset args and nargs for probe_trace_event when failure
Message-ID<pZRAu-DT-25@gated-at.bofh.it>
In reply to#1211076
When failure occures in add_probe_trace_event(), args in
probe_trace_event is incomplete. Since information in it may be used
in further, this patch frees the allocated memory and set it to NULL
to avoid dangling pointer.

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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-31-git-send-email-wangnan0@huawei.com
---
 tools/perf/util/probe-finder.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 7b80f8c..4b1e074 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1243,6 +1243,10 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
 
 end:
 	free(args);
+	if (ret) {
+		tev->nargs = 0;
+		zfree(&tev->args);
+	}
 	return ret;
 }
 
-- 
2.1.0

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


#1211080 — [PATCH 11/29] perf tools: Suppress probing messages when probing by BPF loading

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 11/29] perf tools: Suppress probing messages when probing by BPF loading
Message-ID<pZRAu-DT-27@gated-at.bofh.it>
In reply to#1211076
This patch suppresses 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 | 17 ++++++++++++-----
 tools/perf/util/probe-event.h |  1 +
 tools/perf/util/probe-file.c  |  5 ++++-
 4 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 126aa71..8e91ad1 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -188,6 +188,7 @@ static bool is_probed;
 int bpf__unprobe(void)
 {
 	struct strfilter *delfilter;
+	bool old_silent = probe_conf.silent;
 	int ret;
 
 	if (!is_probed)
@@ -199,7 +200,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_probed)
 		pr_debug("Error: failed to delete events: %s\n",
@@ -215,6 +218,7 @@ int bpf__probe(void)
 	struct bpf_object *obj, *tmp;
 	struct bpf_program *prog;
 	struct perf_probe_event *pevs;
+	bool old_silent = probe_conf.silent;
 
 	pevs = calloc(MAX_PROBES, sizeof(pevs[0]));
 	if (!pevs)
@@ -235,9 +239,11 @@ int bpf__probe(void)
 		}
 	}
 
+	probe_conf.silent = true;
 	probe_conf.max_probes = MAX_PROBES;
 	/* Let add_perf_probe_events generates probe_trace_event (tevs) */
 	err = add_perf_probe_events(pevs, nr_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 d5368ac..ffc0113 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -52,7 +52,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)
 
@@ -2133,10 +2135,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);
 
@@ -2357,7 +2361,10 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
 	}
 
 	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 */
@@ -2393,7 +2400,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);
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 5db0f20..ba981c5 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;
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c
index bbb2437..db7bd4c 100644
--- a/tools/perf/util/probe-file.c
+++ b/tools/perf/util/probe-file.c
@@ -267,7 +267,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",
-- 
2.1.0

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


#1211081 — [PATCH 13/29] perf tools: Infrastructure for compiling scriptlets when passing '.c' to --event

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 13/29] perf tools: Infrastructure for compiling scriptlets when passing '.c' to --event
Message-ID<pZRAu-DT-19@gated-at.bofh.it>
In reply to#1211076
This patch provides infrastructure for passing source files to --event
directly using:

 # perf record --event bpf-file.c command

This patch does following works:

 1) Allow passing '.c' file to '--event'. parse_events_load_bpf() is
    expanded to allow caller tell it whether the passed file is source
    file or object.

 2) llvm__compile_bpf() is called to compile the '.c' file, the result
    is saved into memory. Use bpf_object__open_buffer() to load the
    in-memory object.

Introduces a bpf-script-example.c so we can manually test it:

 # perf record --clang-opt "-DLINUX_VERSION_CODE=0x40200" --event ./bpf-script-example.c sleep 1

Note that '--clang-opt' must put before '--event'.

Futher patches will merge it into a testcase so can be tested automatically.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@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: 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: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/n/1436445342-1402-20-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/tests/bpf-script-example.c | 44 +++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.c          | 25 +++++++++++++++-----
 tools/perf/util/bpf-loader.h          | 10 ++++----
 tools/perf/util/parse-events.c        |  6 ++---
 tools/perf/util/parse-events.h        |  3 ++-
 tools/perf/util/parse-events.l        |  3 +++
 tools/perf/util/parse-events.y        | 15 ++++++++++--
 7 files changed, 90 insertions(+), 16 deletions(-)
 create mode 100644 tools/perf/tests/bpf-script-example.c

diff --git a/tools/perf/tests/bpf-script-example.c b/tools/perf/tests/bpf-script-example.c
new file mode 100644
index 0000000..410a70b
--- /dev/null
+++ b/tools/perf/tests/bpf-script-example.c
@@ -0,0 +1,44 @@
+#ifndef LINUX_VERSION_CODE
+# error Need LINUX_VERSION_CODE
+# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
+#endif
+#define BPF_ANY 0
+#define BPF_MAP_TYPE_ARRAY 2
+#define BPF_FUNC_map_lookup_elem 1
+#define BPF_FUNC_map_update_elem 2
+
+static void *(*bpf_map_lookup_elem)(void *map, void *key) =
+	(void *) BPF_FUNC_map_lookup_elem;
+static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
+	(void *) BPF_FUNC_map_update_elem;
+
+struct bpf_map_def {
+	unsigned int type;
+	unsigned int key_size;
+	unsigned int value_size;
+	unsigned int max_entries;
+};
+
+#define SEC(NAME) __attribute__((section(NAME), used))
+struct bpf_map_def SEC("maps") flip_table = {
+	.type = BPF_MAP_TYPE_ARRAY,
+	.key_size = sizeof(int),
+	.value_size = sizeof(int),
+	.max_entries = 1,
+};
+
+SEC("func=sys_epoll_pwait")
+int bpf_func__sys_epoll_pwait(void *ctx)
+{
+	int ind =0;
+	int *flag = bpf_map_lookup_elem(&flip_table, &ind);
+	int new_flag;
+	if (!flag)
+		return 0;
+	/* flip flag and store back */
+	new_flag = !*flag;
+	bpf_map_update_elem(&flip_table, &ind, &new_flag, BPF_ANY);
+	return new_flag;
+}
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 8e91ad1..5a203ae 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -11,6 +11,7 @@
 #include "bpf-loader.h"
 #include "probe-event.h"
 #include "probe-finder.h"
+#include "llvm-utils.h"
 
 #define DEFINE_PRINT_FN(name, level) \
 static int libbpf_##name(const char *fmt, ...)	\
@@ -152,16 +153,28 @@ sync_bpf_program_pev(struct bpf_program *prog)
 	return 0;
 }
 
-int bpf__prepare_load(const char *filename)
+int bpf__prepare_load(const char *filename, bool source)
 {
 	struct bpf_object *obj;
+	int err;
 
 	if (!libbpf_initialized)
 		libbpf_set_print(libbpf_warning,
 				 libbpf_info,
 				 libbpf_debug);
 
-	obj = bpf_object__open(filename);
+	if (source) {
+		void *obj_buf;
+		size_t obj_buf_sz;
+
+		err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
+		if (err)
+			return err;
+		obj = bpf_object__open_buffer(obj_buf, obj_buf_sz);
+		free(obj_buf);
+	} else
+		obj = bpf_object__open(filename);
+
 	if (!obj) {
 		pr_debug("bpf: failed to load %s\n", filename);
 		return -EINVAL;
@@ -355,12 +368,12 @@ int bpf__foreach_tev(bpf_prog_iter_callback_t func, void *arg)
 	}\
 	buf[size - 1] = '\0';
 
-int bpf__strerror_prepare_load(const char *filename, int err,
-			       char *buf, size_t size)
+int bpf__strerror_prepare_load(const char *filename, bool source,
+			       int err, char *buf, size_t size)
 {
 	bpf__strerror_head(err, buf, size);
-	bpf__strerror_entry(EINVAL, "%s: BPF object file '%s' is invalid",
-			    emsg, filename)
+	bpf__strerror_entry(EINVAL, "%s: BPF %s file '%s' is invalid",
+			    emsg, source ? "source" : "object", filename);
 	bpf__strerror_end(buf, size);
 	return 0;
 }
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 34656f8..c55ffde 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -16,9 +16,9 @@ typedef int (*bpf_prog_iter_callback_t)(struct probe_trace_event *tev,
 					int fd, void *arg);
 
 #ifdef HAVE_LIBBPF_SUPPORT
-int bpf__prepare_load(const char *filename);
-int bpf__strerror_prepare_load(const char *filename, int err,
-			       char *buf, size_t size);
+int bpf__prepare_load(const char *filename, bool source);
+int bpf__strerror_prepare_load(const char *filename, bool source,
+			       int err, char *buf, size_t size);
 int bpf__probe(void);
 int bpf__unprobe(void);
 int bpf__strerror_probe(int err, char *buf, size_t size);
@@ -30,7 +30,8 @@ void bpf__clear(void);
 
 int bpf__foreach_tev(bpf_prog_iter_callback_t func, void *arg);
 #else
-static inline int bpf__prepare_load(const char *filename __maybe_unused)
+static inline int bpf__prepare_load(const char *filename __maybe_unused,
+				    bool source __maybe_unused)
 {
 	pr_debug("ERROR: eBPF object loading is disabled during compiling.\n");
 	return -1;
@@ -62,6 +63,7 @@ __bpf_strerror(char *buf, size_t size)
 
 static inline int
 bpf__strerror_prepare_load(const char *filename __maybe_unused,
+			   bool source __maybe_unused,
 			   int err __maybe_unused,
 			   char *buf, size_t size)
 {
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 9eaceb2..cce3e43 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -484,7 +484,7 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 
 int parse_events_load_bpf(struct parse_events_evlist *data,
 			  struct list_head *list __maybe_unused,
-			  char *bpf_file_name)
+			  char *bpf_file_name, bool source)
 {
 	int err;
 	char errbuf[BUFSIZ];
@@ -497,9 +497,9 @@ int parse_events_load_bpf(struct parse_events_evlist *data,
 	 * problem. After that probe events file by file is possible.
 	 * However, probing cost is still need to be considered.
 	 */
-	err = bpf__prepare_load(bpf_file_name);
+	err = bpf__prepare_load(bpf_file_name, source);
 	if (err) {
-		bpf__strerror_prepare_load(bpf_file_name, err,
+		bpf__strerror_prepare_load(bpf_file_name, source, err,
 					   errbuf, sizeof(errbuf));
 		data->error->str = strdup(errbuf);
 		data->error->help = strdup("(add -v to see detail)");
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index 3652387..728a424 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -121,7 +121,8 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 				char *sys, char *event);
 int parse_events_load_bpf(struct parse_events_evlist *data,
 			  struct list_head *list,
-			  char *bpf_file_name);
+			  char *bpf_file_name,
+			  bool source);
 int parse_events_add_numeric(struct parse_events_evlist *data,
 			     struct list_head *list,
 			     u32 type, u64 config,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 22e8f93..8033890 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -116,6 +116,7 @@ group		[^,{}/]*[{][^}]*[}][^,{}/]*
 event_pmu	[^,{}/]+[/][^/]*[/][^,{}/]*
 event		[^,{}/]+
 bpf_object	.*\.(o|bpf)
+bpf_source	.*\.c
 
 num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
@@ -161,6 +162,7 @@ modifier_bp	[rwx]{1,3}
 
 {event_pmu}	|
 {bpf_object}	|
+{bpf_source}	|
 {event}		{
 			BEGIN(INITIAL);
 			REWIND(1);
@@ -267,6 +269,7 @@ r{num_raw_hex}		{ return raw(yyscanner); }
 
 {modifier_event}	{ return str(yyscanner, PE_MODIFIER_EVENT); }
 {bpf_object}		{ return str(yyscanner, PE_BPF_OBJECT); }
+{bpf_source}		{ return str(yyscanner, PE_BPF_SOURCE); }
 {name}			{ return pmu_str_check(yyscanner); }
 "/"			{ BEGIN(config); return '/'; }
 -			{ return '-'; }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 3ee3a32..90d2458 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -42,7 +42,7 @@ static inc_group_count(struct list_head *list,
 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
 %token PE_EVENT_NAME
 %token PE_NAME
-%token PE_BPF_OBJECT
+%token PE_BPF_OBJECT PE_BPF_SOURCE
 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
 %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
@@ -55,6 +55,7 @@ static inc_group_count(struct list_head *list,
 %type <num> PE_TERM
 %type <str> PE_NAME
 %type <str> PE_BPF_OBJECT
+%type <str> PE_BPF_SOURCE
 %type <str> PE_NAME_CACHE_TYPE
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
@@ -431,7 +432,17 @@ PE_BPF_OBJECT
 	struct list_head *list;
 
 	ALLOC_LIST(list);
-	ABORT_ON(parse_events_load_bpf(data, list, $1));
+	ABORT_ON(parse_events_load_bpf(data, list, $1, false));
+	$$ = list;
+}
+|
+PE_BPF_SOURCE
+{
+	struct parse_events_evlist *data = _data;
+	struct list_head *list;
+
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_load_bpf(data, list, $1, true));
 	$$ = list;
 }
 
-- 
2.1.0

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


#1211082 — [PATCH 19/29] perf tools: Move linux/filter.h to tools/include

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 19/29] perf tools: Move linux/filter.h to tools/include
Message-ID<pZRAv-DT-29@gated-at.bofh.it>
In reply to#1211076
From: He Kuang <hekuang@huawei.com>

This patch moves filter.h from include/linux/kernel.h to
tools/include/linux/filter.h to enable other libraries use macros in
it, like libbpf which will be introduced by further patches. Currenty,
the moved filter.h only contains the useful macros needed by libbpf
for not introducing too much dependence.

MANIFEST is also updated for 'make perf-*-src-pkg'.

One change:
  imm field of BPF_EMIT_CALL becomes ((FUNC) - BPF_FUNC_unspec) to
  suit user space code generator.

Signed-off-by: He Kuang <hekuang@huawei.com>
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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-32-git-send-email-wangnan0@huawei.com
---
 tools/include/linux/filter.h | 237 +++++++++++++++++++++++++++++++++++++++++++
 tools/perf/MANIFEST          |   1 +
 2 files changed, 238 insertions(+)
 create mode 100644 tools/include/linux/filter.h

diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h
new file mode 100644
index 0000000..11d2b1c
--- /dev/null
+++ b/tools/include/linux/filter.h
@@ -0,0 +1,237 @@
+/*
+ * Linux Socket Filter Data Structures
+ */
+#ifndef __TOOLS_LINUX_FILTER_H
+#define __TOOLS_LINUX_FILTER_H
+
+#include <linux/bpf.h>
+
+/* ArgX, context and stack frame pointer register positions. Note,
+ * Arg1, Arg2, Arg3, etc are used as argument mappings of function
+ * calls in BPF_CALL instruction.
+ */
+#define BPF_REG_ARG1	BPF_REG_1
+#define BPF_REG_ARG2	BPF_REG_2
+#define BPF_REG_ARG3	BPF_REG_3
+#define BPF_REG_ARG4	BPF_REG_4
+#define BPF_REG_ARG5	BPF_REG_5
+#define BPF_REG_CTX	BPF_REG_6
+#define BPF_REG_FP	BPF_REG_10
+
+/* Additional register mappings for converted user programs. */
+#define BPF_REG_A	BPF_REG_0
+#define BPF_REG_X	BPF_REG_7
+#define BPF_REG_TMP	BPF_REG_8
+
+/* BPF program can access up to 512 bytes of stack space. */
+#define MAX_BPF_STACK	512
+
+/* Helper macros for filter block array initializers. */
+
+/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
+
+#define BPF_ALU64_REG(OP, DST, SRC)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_X,	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#define BPF_ALU32_REG(OP, DST, SRC)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_OP(OP) | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+/* ALU ops on immediates, bpf_add|sub|...: dst_reg += imm32 */
+
+#define BPF_ALU64_IMM(OP, DST, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_K,	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_ALU32_IMM(OP, DST, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_OP(OP) | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Endianness conversion, cpu_to_{l,b}e(), {l,b}e_to_cpu() */
+
+#define BPF_ENDIAN(TYPE, DST, LEN)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_END | BPF_SRC(TYPE),	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = LEN })
+
+/* Short form of mov, dst_reg = src_reg */
+
+#define BPF_MOV64_REG(DST, SRC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#define BPF_MOV32_REG(DST, SRC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_MOV | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+/* Short form of mov, dst_reg = imm32 */
+
+#define BPF_MOV64_IMM(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_MOV32_IMM(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_MOV | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Short form of mov based on type,
+ * BPF_X: dst_reg = src_reg, BPF_K: dst_reg = imm32
+ */
+
+#define BPF_MOV64_RAW(TYPE, DST, SRC, IMM)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_SRC(TYPE),	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_MOV32_RAW(TYPE, DST, SRC, IMM)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU | BPF_MOV | BPF_SRC(TYPE),	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */
+
+#define BPF_LD_ABS(SIZE, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS,	\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Indirect packet access, R0 = *(uint *) (skb->data + src_reg + imm32) */
+
+#define BPF_LD_IND(SIZE, SRC, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_SIZE(SIZE) | BPF_IND,	\
+		.dst_reg = 0,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+/* Memory load, dst_reg = *(uint *) (src_reg + off16) */
+
+#define BPF_LDX_MEM(SIZE, DST, SRC, OFF)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_LDX | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = src_reg */
+
+#define BPF_STX_MEM(SIZE, DST, SRC, OFF)			\
+	((struct bpf_insn) {					\
+		.code  = BPF_STX | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = 0 })
+
+/* Memory store, *(uint *) (dst_reg + off16) = imm32 */
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+/* Conditional jumps against registers,
+ * if (dst_reg 'op' src_reg) goto pc + off16
+ */
+
+#define BPF_JMP_REG(OP, DST, SRC, OFF)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_OP(OP) | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = 0 })
+
+/* Conditional jumps against immediates,
+ * if (dst_reg 'op' imm32) goto pc + off16
+ */
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_OP(OP) | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+/* Function call */
+
+#define BPF_EMIT_CALL(FUNC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_CALL,			\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = ((FUNC) - BPF_FUNC_unspec) })
+
+/* Raw code statement block */
+
+#define BPF_RAW_INSN(CODE, DST, SRC, OFF, IMM)			\
+	((struct bpf_insn) {					\
+		.code  = CODE,					\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+/* Program exit */
+
+#define BPF_EXIT_INSN()						\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_EXIT,			\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#endif /* __TOOLS_LINUX_FILTER_H */
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST
index 3db15cf..21a5237 100644
--- a/tools/perf/MANIFEST
+++ b/tools/perf/MANIFEST
@@ -45,6 +45,7 @@ tools/include/linux/compiler.h
 tools/include/linux/export.h
 tools/include/linux/hash.h
 tools/include/linux/kernel.h
+tools/include/linux/filter.h
 tools/include/linux/list.h
 tools/include/linux/log2.h
 tools/include/linux/poison.h
-- 
2.1.0

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


#1211083 — [PATCH 05/29] perf probe: Attach trace_probe_event with perf_probe_event

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 05/29] perf probe: Attach trace_probe_event with perf_probe_event
Message-ID<pZRAu-DT-23@gated-at.bofh.it>
In reply to#1211076
This patch drops struct __event_package structure. Instead, it adds
trace_probe_event into 'struct perf_probe_event'.

trace_probe_event information gives further patches a chance to access
actual probe points and actual arguments. Using them, bpf_loader will
be able to attach one bpf program to different probing points of a
inline functions (which has multiple probing points) and glob
functions. Moreover, by reading arguments information, bpf code for
reading those arguments can be generated.

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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-22-git-send-email-wangnan0@huawei.com
---
 tools/perf/builtin-probe.c    |  4 ++-
 tools/perf/util/probe-event.c | 60 +++++++++++++++++++++----------------------
 tools/perf/util/probe-event.h |  6 ++++-
 3 files changed, 38 insertions(+), 32 deletions(-)

diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index b81cec3..826d452 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -496,7 +496,9 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 			usage_with_options(probe_usage, options);
 		}
 
-		ret = add_perf_probe_events(params.events, params.nevents);
+		ret = add_perf_probe_events(params.events,
+					    params.nevents,
+					    true);
 		if (ret < 0) {
 			pr_err_with_code("  Error: Failed to add events.", ret);
 			return ret;
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index f07374b..d5368ac 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1926,6 +1926,9 @@ void clear_perf_probe_event(struct perf_probe_event *pev)
 	struct perf_probe_arg_field *field, *next;
 	int i;
 
+	if (pev->ntevs)
+		cleanup_perf_probe_event(pev);
+
 	free(pev->event);
 	free(pev->group);
 	free(pev->target);
@@ -2602,61 +2605,58 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev,
 	return find_probe_trace_events_from_map(pev, tevs);
 }
 
-struct __event_package {
-	struct perf_probe_event		*pev;
-	struct probe_trace_event	*tevs;
-	int				ntevs;
-};
-
-int add_perf_probe_events(struct perf_probe_event *pevs, int npevs)
+int cleanup_perf_probe_event(struct perf_probe_event *pev)
 {
-	int i, j, ret;
-	struct __event_package *pkgs;
+	int i;
 
-	ret = 0;
-	pkgs = zalloc(sizeof(struct __event_package) * npevs);
+	if (!pev || !pev->ntevs)
+		return 0;
 
-	if (pkgs == NULL)
-		return -ENOMEM;
+	for (i = 0; i < pev->ntevs; i++)
+		clear_probe_trace_event(&pev->tevs[i]);
+
+	zfree(&pev->tevs);
+	pev->ntevs = 0;
+	return 0;
+}
+
+int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
+			  bool cleanup)
+{
+	int i, ret;
 
 	ret = init_symbol_maps(pevs->uprobes);
-	if (ret < 0) {
-		free(pkgs);
+	if (ret < 0)
 		return ret;
-	}
 
 	/* Loop 1: convert all events */
 	for (i = 0; i < npevs; i++) {
-		pkgs[i].pev = &pevs[i];
 		/* Init kprobe blacklist if needed */
-		if (!pkgs[i].pev->uprobes)
+		if (pevs[i].uprobes)
 			kprobe_blacklist__init();
 		/* Convert with or without debuginfo */
-		ret  = convert_to_probe_trace_events(pkgs[i].pev,
-						     &pkgs[i].tevs);
-		if (ret < 0)
+		ret  = convert_to_probe_trace_events(&pevs[i], &pevs[i].tevs);
+		if (ret < 0) {
+			cleanup = true;
 			goto end;
-		pkgs[i].ntevs = ret;
+		}
+		pevs[i].ntevs = ret;
 	}
 	/* This just release blacklist only if allocated */
 	kprobe_blacklist__release();
 
 	/* Loop 2: add all events */
 	for (i = 0; i < npevs; i++) {
-		ret = __add_probe_trace_events(pkgs[i].pev, pkgs[i].tevs,
-					       pkgs[i].ntevs,
+		ret = __add_probe_trace_events(&pevs[i], pevs[i].tevs,
+					       pevs[i].ntevs,
 					       probe_conf.force_add);
 		if (ret < 0)
 			break;
 	}
 end:
 	/* Loop 3: cleanup and free trace events  */
-	for (i = 0; i < npevs; i++) {
-		for (j = 0; j < pkgs[i].ntevs; j++)
-			clear_probe_trace_event(&pkgs[i].tevs[j]);
-		zfree(&pkgs[i].tevs);
-	}
-	free(pkgs);
+	for (i = 0; cleanup && (i < npevs); i++)
+		cleanup_perf_probe_event(&pevs[i]);
 	exit_symbol_maps();
 
 	return ret;
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h
index 83ee95e..5db0f20 100644
--- a/tools/perf/util/probe-event.h
+++ b/tools/perf/util/probe-event.h
@@ -86,6 +86,8 @@ struct perf_probe_event {
 	bool			uprobes;	/* Uprobe event flag */
 	char			*target;	/* Target binary */
 	struct perf_probe_arg	*args;	/* Arguments */
+	struct probe_trace_event *tevs;
+	int			ntevs;
 };
 
 /* Line range */
@@ -136,8 +138,10 @@ extern void line_range__clear(struct line_range *lr);
 /* Initialize line range */
 extern int line_range__init(struct line_range *lr);
 
-extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs);
+extern int add_perf_probe_events(struct perf_probe_event *pevs, int npevs,
+				 bool cleanup);
 extern int del_perf_probe_events(struct strfilter *filter);
+extern int cleanup_perf_probe_event(struct perf_probe_event *pev);
 extern int show_perf_probe_events(struct strfilter *filter);
 extern int show_line_range(struct line_range *lr, const char *module,
 			   bool user);
-- 
2.1.0

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


#1211084 — [PATCH 21/29] perf tools: Introduce arch_get_reg_info() for x86

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 21/29] perf tools: Introduce arch_get_reg_info() for x86
Message-ID<pZRAv-DT-37@gated-at.bofh.it>
In reply to#1211076
From: He Kuang <hekuang@huawei.com>

arch_get_reg_info() is a helper function which converts register name
like "%rax" to offset of a register in 'struct pt_regs', which is
required by BPF prologue generator.

This patch replaces original string table by a 'struct reg_info' table,
which records offset of registers according to its name.

For x86, since there are two sub-archs (x86_32 and x86_64) but we can
only get pt_regs for the arch we are currently on, this patch fills
offset with '-1' for another sub-arch. This introduces a limitation to
perf prologue that, we are unable to generate prologue on a x86_32
compiled perf for BPF programs targeted on x86_64 kernel. This
limitation is acceptable, because this is a very rare usecase.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-34-git-send-email-wangnan0@huawei.com
---
 tools/perf/arch/x86/Makefile          |   1 +
 tools/perf/arch/x86/util/Build        |   2 +
 tools/perf/arch/x86/util/dwarf-regs.c | 104 ++++++++++++++++++++++++----------
 3 files changed, 78 insertions(+), 29 deletions(-)

diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile
index 21322e0..a84a6f6f 100644
--- a/tools/perf/arch/x86/Makefile
+++ b/tools/perf/arch/x86/Makefile
@@ -2,3 +2,4 @@ ifndef NO_DWARF
 PERF_HAVE_DWARF_REGS := 1
 endif
 HAVE_KVM_STAT_SUPPORT := 1
+PERF_HAVE_ARCH_GET_REG_INFO := 1
diff --git a/tools/perf/arch/x86/util/Build b/tools/perf/arch/x86/util/Build
index a8be9f9..a3837f5 100644
--- a/tools/perf/arch/x86/util/Build
+++ b/tools/perf/arch/x86/util/Build
@@ -3,6 +3,8 @@ libperf-y += tsc.o
 libperf-y += pmu.o
 libperf-y += kvm-stat.o
 
+# BPF_PROLOGUE also need dwarf-regs.o. However, if CONFIG_BPF_PROLOGUE
+# is true, CONFIG_DWARF must true.
 libperf-$(CONFIG_DWARF) += dwarf-regs.o
 
 libperf-$(CONFIG_LIBUNWIND)          += unwind-libunwind.o
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c
index be22dd4..9928caf 100644
--- a/tools/perf/arch/x86/util/dwarf-regs.c
+++ b/tools/perf/arch/x86/util/dwarf-regs.c
@@ -22,44 +22,67 @@
 
 #include <stddef.h>
 #include <dwarf-regs.h>
+#include <string.h>
+#include <linux/ptrace.h>
+#include <linux/kernel.h> /* for offsetof */
+#include <util/bpf-loader.h>
+
+struct reg_info {
+	const char	*name;		/* Reg string in debuginfo      */
+	int		offset;		/* Reg offset in struct pt_regs */
+};
 
 /*
  * Generic dwarf analysis helpers
  */
-
+/*
+ * x86_64 compiling can't access pt_regs for x86_32, so fill offset
+ * with -1.
+ */
+#ifdef __x86_64__
+# define REG_INFO(n, f) { .name = n, .offset = -1, }
+#else
+# define REG_INFO(n, f) { .name = n, .offset = offsetof(struct pt_regs, f), }
+#endif
 #define X86_32_MAX_REGS 8
-const char *x86_32_regs_table[X86_32_MAX_REGS] = {
-	"%ax",
-	"%cx",
-	"%dx",
-	"%bx",
-	"$stack",	/* Stack address instead of %sp */
-	"%bp",
-	"%si",
-	"%di",
+
+struct reg_info x86_32_regs_table[X86_32_MAX_REGS] = {
+	REG_INFO("%ax", eax),
+	REG_INFO("%cx", ecx),
+	REG_INFO("%dx", edx),
+	REG_INFO("%bx", ebx),
+	REG_INFO("$stack", esp),	/* Stack address instead of %sp */
+	REG_INFO("%bp", ebp),
+	REG_INFO("%si", esi),
+	REG_INFO("%di", edi),
 };
 
+#undef REG_INFO
+#ifdef __x86_64__
+# define REG_INFO(n, f) { .name = n, .offset = offsetof(struct pt_regs, f), }
+#else
+# define REG_INFO(n, f) { .name = n, .offset = -1, }
+#endif
 #define X86_64_MAX_REGS 16
-const char *x86_64_regs_table[X86_64_MAX_REGS] = {
-	"%ax",
-	"%dx",
-	"%cx",
-	"%bx",
-	"%si",
-	"%di",
-	"%bp",
-	"%sp",
-	"%r8",
-	"%r9",
-	"%r10",
-	"%r11",
-	"%r12",
-	"%r13",
-	"%r14",
-	"%r15",
+struct reg_info x86_64_regs_table[X86_64_MAX_REGS] = {
+	REG_INFO("%ax",		rax),
+	REG_INFO("%dx",		rdx),
+	REG_INFO("%cx",		rcx),
+	REG_INFO("%bx",		rbx),
+	REG_INFO("%si",		rsi),
+	REG_INFO("%di",		rdi),
+	REG_INFO("%bp",		rbp),
+	REG_INFO("%sp",		rsp),
+	REG_INFO("%r8",		r8),
+	REG_INFO("%r9",		r9),
+	REG_INFO("%r10",	r10),
+	REG_INFO("%r11",	r11),
+	REG_INFO("%r12",	r12),
+	REG_INFO("%r13",	r13),
+	REG_INFO("%r14",	r14),
+	REG_INFO("%r15",	r15),
 };
 
-/* TODO: switching by dwarf address size */
 #ifdef __x86_64__
 #define ARCH_MAX_REGS X86_64_MAX_REGS
 #define arch_regs_table x86_64_regs_table
@@ -71,5 +94,28 @@ const char *x86_64_regs_table[X86_64_MAX_REGS] = {
 /* Return architecture dependent register string (for kprobe-tracer) */
 const char *get_arch_regstr(unsigned int n)
 {
-	return (n <= ARCH_MAX_REGS) ? arch_regs_table[n] : NULL;
+	return (n <= ARCH_MAX_REGS) ? arch_regs_table[n].name : NULL;
 }
+
+#ifdef HAVE_BPF_PROLOGUE
+int arch_get_reg_info(const char *name, int *offset)
+{
+	int i;
+	struct reg_info *info;
+
+	if (!name || !offset)
+		return -1;
+
+	for (i = 0; i < ARCH_MAX_REGS; i++) {
+		info = &arch_regs_table[i];
+		if (strcmp(info->name, name) == 0) {
+			if (info->offset < 0)
+				return -1;
+			*offset = info->offset;
+			return 0;
+		}
+	}
+
+	return -1;
+}
+#endif
-- 
2.1.0

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


#1211085 — [PATCH 03/29] perf ebpf: Add the libbpf glue

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 03/29] perf ebpf: Add the libbpf glue
Message-ID<pZRAv-DT-39@gated-at.bofh.it>
In reply to#1211076
The 'bpf-loader.[ch]' files are introduced in this patch. Which will be
the interface between perf and libbpf. bpf__prepare_load() resides in
bpf-loader.c. Dummy functions should be used because bpf-loader.c is
available only when CONFIG_LIBBPF is on.

Functions in bpf-loader.c should not report error explicitly. Instead,
strerror style error reporting should be used.

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: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/n/1436445342-1402-19-git-send-email-wangnan0@huawei.com
[ split from a larger patch ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/bpf-loader.c | 92 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h | 47 ++++++++++++++++++++++
 2 files changed, 139 insertions(+)
 create mode 100644 tools/perf/util/bpf-loader.c
 create mode 100644 tools/perf/util/bpf-loader.h

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
new file mode 100644
index 0000000..88531ea
--- /dev/null
+++ b/tools/perf/util/bpf-loader.c
@@ -0,0 +1,92 @@
+/*
+ * bpf-loader.c
+ *
+ * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015 Huawei Inc.
+ */
+
+#include <bpf/libbpf.h>
+#include "perf.h"
+#include "debug.h"
+#include "bpf-loader.h"
+
+#define DEFINE_PRINT_FN(name, level) \
+static int libbpf_##name(const char *fmt, ...)	\
+{						\
+	va_list args;				\
+	int ret;				\
+						\
+	va_start(args, fmt);			\
+	ret = veprintf(level, verbose, pr_fmt(fmt), args);\
+	va_end(args);				\
+	return ret;				\
+}
+
+DEFINE_PRINT_FN(warning, 0)
+DEFINE_PRINT_FN(info, 0)
+DEFINE_PRINT_FN(debug, 1)
+
+static bool libbpf_initialized;
+
+int bpf__prepare_load(const char *filename)
+{
+	struct bpf_object *obj;
+
+	if (!libbpf_initialized)
+		libbpf_set_print(libbpf_warning,
+				 libbpf_info,
+				 libbpf_debug);
+
+	obj = bpf_object__open(filename);
+	if (!obj) {
+		pr_debug("bpf: failed to load %s\n", filename);
+		return -EINVAL;
+	}
+
+	/*
+	 * Throw object pointer away: it will be retrived using
+	 * bpf_objects iterater.
+	 */
+
+	return 0;
+}
+
+void bpf__clear(void)
+{
+	struct bpf_object *obj, *tmp;
+
+	bpf_object__for_each_safe(obj, tmp)
+		bpf_object__close(obj);
+}
+
+#define bpf__strerror_head(err, buf, size) \
+	char sbuf[STRERR_BUFSIZE], *emsg;\
+	if (!size)\
+		return 0;\
+	if (err < 0)\
+		err = -err;\
+	emsg = strerror_r(err, sbuf, sizeof(sbuf));\
+	switch (err) {\
+	default:\
+		scnprintf(buf, size, "%s", emsg);\
+		break;
+
+#define bpf__strerror_entry(val, fmt...)\
+	case val: {\
+		scnprintf(buf, size, fmt);\
+		break;\
+	}
+
+#define bpf__strerror_end(buf, size)\
+	}\
+	buf[size - 1] = '\0';
+
+int bpf__strerror_prepare_load(const char *filename, int err,
+			       char *buf, size_t size)
+{
+	bpf__strerror_head(err, buf, size);
+	bpf__strerror_entry(EINVAL, "%s: BPF object file '%s' is invalid",
+			    emsg, filename)
+	bpf__strerror_end(buf, size);
+	return 0;
+}
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
new file mode 100644
index 0000000..12be630
--- /dev/null
+++ b/tools/perf/util/bpf-loader.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com>
+ * Copyright (C) 2015, Huawei Inc.
+ */
+#ifndef __BPF_LOADER_H
+#define __BPF_LOADER_H
+
+#include <linux/compiler.h>
+#include <string.h>
+#include "debug.h"
+
+#ifdef HAVE_LIBBPF_SUPPORT
+int bpf__prepare_load(const char *filename);
+int bpf__strerror_prepare_load(const char *filename, int err,
+			       char *buf, size_t size);
+
+void bpf__clear(void);
+#else
+static inline int bpf__prepare_load(const char *filename __maybe_unused)
+{
+	pr_debug("ERROR: eBPF object loading is disabled during compiling.\n");
+	return -1;
+}
+
+static inline void bpf__clear(void) { }
+
+static inline int
+__bpf_strerror(char *buf, size_t size)
+{
+	if (!size)
+		return 0;
+	strncpy(buf,
+		"ERROR: eBPF object loading is disabled during compiling.\n",
+		size);
+	buf[size - 1] = '\0';
+	return 0;
+}
+
+static inline int
+bpf__strerror_prepare_load(const char *filename __maybe_unused,
+			   int err __maybe_unused,
+			   char *buf, size_t size)
+{
+	return __bpf_strerror(buf, size);
+}
+#endif
+#endif
-- 
2.1.0

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


#1211086 — [PATCH 10/29] perf tools: Attach eBPF program to perf event

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 10/29] perf tools: Attach eBPF program to perf event
Message-ID<pZRAw-DT-55@gated-at.bofh.it>
In reply to#1211076
This is the final patch which makes basic BPF filter work. After
applying this patch, users are allowed to use BPF filter like:

 # perf record --event ./hello_world.c ls

In this patch PERF_EVENT_IOC_SET_BPF ioctl is used to attach eBPF
program to a newly created perf event. The file descriptor of the
eBPF program is passed to perf record using previous patches, and
stored into evsel->bpf_fd.

It is possible that different perf event are created for one kprobe
events for different CPUs. In this case, when trying to call the
ioctl, EEXIST will be return. This patch doesn't treat it as an error.

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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-26-git-send-email-wangnan0@huawei.com
---
 tools/perf/util/evsel.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index ae9ad2d..40b2722 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -1331,6 +1331,22 @@ retry_open:
 					  err);
 				goto try_fallback;
 			}
+
+			if (evsel->bpf_fd >= 0) {
+				int evt_fd = FD(evsel, cpu, thread);
+				int bpf_fd = evsel->bpf_fd;
+
+				err = ioctl(evt_fd,
+					    PERF_EVENT_IOC_SET_BPF,
+					    bpf_fd);
+				if (err && errno != EEXIST) {
+					pr_err("failed to attach bpf fd %d: %s\n",
+					       bpf_fd, strerror(errno));
+					err = -EINVAL;
+					goto out_close;
+				}
+			}
+
 			set_rlimit = NO_CHANGE;
 
 			/*
-- 
2.1.0

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


#1211087 — [PATCH 01/29] perf probe: Try to use symbol table if searching debug info failed

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 01/29] perf probe: Try to use symbol table if searching debug info failed
Message-ID<pZRAv-DT-49@gated-at.bofh.it>
In reply to#1211076
A problem can occure in statically linked perf when vmlinux can be found:

 # perf probe --add sys_epoll_pwait
 probe-definition(0): sys_epoll_pwait
 symbol:sys_epoll_pwait file:(null) line:0 offset:0 return:0 lazy:(null)
 0 arguments
 Looking at the vmlinux_path (7 entries long)
 Using /lib/modules/4.2.0-rc1+/build/vmlinux for symbols
 Open Debuginfo file: /lib/modules/4.2.0-rc1+/build/vmlinux
 Try to find probe point from debuginfo.
 Symbol sys_epoll_pwait address found : ffffffff8122bd40
 Matched function: SyS_epoll_pwait
 Failed to get call frame on 0xffffffff8122bd40
 An error occurred in debuginfo analysis (-2).
   Error: Failed to add events. Reason: No such file or directory (Code: -2)

The reason is caused by libdw that, if libdw is statically linked, it can't
load libebl_{arch}.so reliable.

In this case it is still possible to get the address from /proc/kalksyms.
However, perf tries that only when libdw returns -EBADF.

This patch gives it another chance to utilize symbol table, even if libdw
return error code other than -EBADF.

After applying this patch:

 # perf probe -nv --add sys_epoll_pwait
 probe-definition(0): sys_epoll_pwait
 symbol:sys_epoll_pwait file:(null) line:0 offset:0 return:0 lazy:(null)
 0 arguments
 Looking at the vmlinux_path (7 entries long)
 Using /lib/modules/4.2.0-rc1+/build/vmlinux for symbols
 Open Debuginfo file: /lib/modules/4.2.0-rc1+/build/vmlinux
 Try to find probe point from debuginfo.
 Symbol sys_epoll_pwait address found : ffffffff8122bd40
 Matched function: SyS_epoll_pwait
 Failed to get call frame on 0xffffffff8122bd40
 An error occurred in debuginfo analysis (-2).
 Trying to use symbols.
 Opening /sys/kernel/debug/tracing/kprobe_events write=1
 Added new event:
 Writing event: p:probe/sys_epoll_pwait _text+2276672
   probe:sys_epoll_pwait (on sys_epoll_pwait)

 You can now use it in all perf tools, such as:

 	perf record -e probe:sys_epoll_pwait -aR sleep 1

Although libdw returns an error (Failed to get call frame),
perf tries symbol table and finally gets correct address.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
---
 tools/perf/util/probe-event.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fe4941a..f07374b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -705,9 +705,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 	}
 	/* Error path : ntevs < 0 */
 	pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
-	if (ntevs == -EBADF) {
-		pr_warning("Warning: No dwarf info found in the vmlinux - "
-			"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
+	if (ntevs < 0) {
+		if (ntevs == -EBADF)
+			pr_warning("Warning: No dwarf info found in the vmlinux - "
+				"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
 		if (!need_dwarf) {
 			pr_debug("Trying to use symbols.\n");
 			return 0;
-- 
2.1.0

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


#1211195 — Re: [PATCH 01/29] perf probe: Try to use symbol table if searching debug info failed

FromArnaldo Carvalho de Melo <acme@redhat.com>
Date2015-08-21 16:20 +0200
SubjectRe: [PATCH 01/29] perf probe: Try to use symbol table if searching debug info failed
Message-ID<pZVkK-63n-33@gated-at.bofh.it>
In reply to#1211087
Em Fri, Aug 21, 2015 at 10:09:02AM +0000, Wang Nan escreveu:
> Although libdw returns an error (Failed to get call frame),
> perf tries symbol table and finally gets correct address.

So, what my script does when processing from the e-mail messages is to
add a Cc: line for each of the e-mail addresses found, that way, in the
git history, we will know who got notifications about the patch.

There is also the Link tag, that it forms using the Message-ID, i.e.:

Link: http://lkml.kernel.org/r/<MESSAGE-ID>

Which I put right before my own "Signed-off-by: Arnaldo" line.

So:

Reported-by: Name <foo@bar.baz>
Signed-off-by: Original Author <e@mail.bla>
Reviewed-by: Name <foo@bar.baz>
Acked-by: Name <foo@bar.baz>
Tested-by: Bla <foo@bar.baz>
Link: http://lkml.kernel.org/r/<MESSAGE-ID>
Signed-off-by: You <you@your.company>

I've been avoiding having the same person in multiple tags, i.e. if
someone reviewed, tested, acked, then no need to have it on the Cc:
list, if someone tested and acked, the Tested-by: is enough, implies an
Acked-by.

My script has a database of e-mail addresses and expands it to have the
names and addresses, i.e.: "Arnaldo Carvalho de Melo <acme@redhat.com>"
instead of just acme@redhat.com, etc.

If someone reacts to your patch and acks it, you should try to add the
relevant tag to your patch, possibly doing a 'rebase -i
patch-just-before, reword it, etc" before I process it, doing so will
reduce the work I have to do to process your patches.

Now ideally this would all happen before you put it somewhere public so
that we don't disrupt git trees cloned from ours, but I'm leaving that
to my upstreamers (Ingo and Linus), which I should refrain from as I go
on pulling from other people more often, which I really want, its all
just a matter of us all agreeing to some common ground on how to format
those patches that doesn't requires me being the one doing the patch
editing, etc, which adds up as a burden, preventing me from doing more
interesting work :)

This set of rules evolved over time as I went by pushing patches to
Ingo, it would be good if you followed it so that I could straight away
pull from your tree.

Anyway, thanks for trying to be taking the steps in that direction, I
will now go back to processing the Intel PT patches so that I can get
back to eBPF.

- Arnaldo
 
> Signed-off-by: Wang Nan <wangnan0@huawei.com>
> ---
>  tools/perf/util/probe-event.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
> index fe4941a..f07374b 100644
> --- a/tools/perf/util/probe-event.c
> +++ b/tools/perf/util/probe-event.c
> @@ -705,9 +705,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
>  	}
>  	/* Error path : ntevs < 0 */
>  	pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
> -	if (ntevs == -EBADF) {
> -		pr_warning("Warning: No dwarf info found in the vmlinux - "
> -			"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
> +	if (ntevs < 0) {
> +		if (ntevs == -EBADF)
> +			pr_warning("Warning: No dwarf info found in the vmlinux - "
> +				"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
>  		if (!need_dwarf) {
>  			pr_debug("Trying to use symbols.\n");
>  			return 0;
> -- 
> 2.1.0
--
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]


#1211404 — [tip:perf/core] perf probe: Try to use symbol table if searching debug info failed

Fromtip-bot for Wang Nan <tipbot@zytor.com>
Date2015-08-22 09:00 +0200
Subject[tip:perf/core] perf probe: Try to use symbol table if searching debug info failed
Message-ID<q0aWt-2Y7-3@gated-at.bofh.it>
In reply to#1211087
Commit-ID:  1c0bd0e891aaed0219010bfe79b32e1b0b82d662
Gitweb:     http://git.kernel.org/tip/1c0bd0e891aaed0219010bfe79b32e1b0b82d662
Author:     Wang Nan <wangnan0@huawei.com>
AuthorDate: Fri, 21 Aug 2015 10:09:02 +0000
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
CommitDate: Fri, 21 Aug 2015 12:57:20 -0300

perf probe: Try to use symbol table if searching debug info failed

A problem can occur in a statically linked perf when vmlinux can be found:

 # perf probe --add sys_epoll_pwait
 probe-definition(0): sys_epoll_pwait
 symbol:sys_epoll_pwait file:(null) line:0 offset:0 return:0 lazy:(null)
 0 arguments
 Looking at the vmlinux_path (7 entries long)
 Using /lib/modules/4.2.0-rc1+/build/vmlinux for symbols
 Open Debuginfo file: /lib/modules/4.2.0-rc1+/build/vmlinux
 Try to find probe point from debuginfo.
 Symbol sys_epoll_pwait address found : ffffffff8122bd40
 Matched function: SyS_epoll_pwait
 Failed to get call frame on 0xffffffff8122bd40
 An error occurred in debuginfo analysis (-2).
   Error: Failed to add events. Reason: No such file or directory (Code: -2)

The reason is caused by libdw that, if libdw is statically linked, it
can't load libebl_{arch}.so reliable.

In this case it is still possible to get the address from
/proc/kalksyms.  However, perf tries that only when libdw returns
-EBADF.

This patch gives it another chance to utilize symbol table, even if
libdw returns an error code other than -EBADF.

After applying this patch:

 # perf probe -nv --add sys_epoll_pwait
 probe-definition(0): sys_epoll_pwait
 symbol:sys_epoll_pwait file:(null) line:0 offset:0 return:0 lazy:(null)
 0 arguments
 Looking at the vmlinux_path (7 entries long)
 Using /lib/modules/4.2.0-rc1+/build/vmlinux for symbols
 Open Debuginfo file: /lib/modules/4.2.0-rc1+/build/vmlinux
 Try to find probe point from debuginfo.
 Symbol sys_epoll_pwait address found : ffffffff8122bd40
 Matched function: SyS_epoll_pwait
 Failed to get call frame on 0xffffffff8122bd40
 An error occurred in debuginfo analysis (-2).
 Trying to use symbols.
 Opening /sys/kernel/debug/tracing/kprobe_events write=1
 Added new event:
 Writing event: p:probe/sys_epoll_pwait _text+2276672
   probe:sys_epoll_pwait (on sys_epoll_pwait)

 You can now use it in all perf tools, such as:

 	perf record -e probe:sys_epoll_pwait -aR sleep 1

Although libdw returns an error (Failed to get call frame), perf tries
symbol table and finally gets correct address.

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: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1440151770-129878-2-git-send-email-wangnan0@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/probe-event.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index fe4941a..f07374b 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -705,9 +705,10 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
 	}
 	/* Error path : ntevs < 0 */
 	pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs);
-	if (ntevs == -EBADF) {
-		pr_warning("Warning: No dwarf info found in the vmlinux - "
-			"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
+	if (ntevs < 0) {
+		if (ntevs == -EBADF)
+			pr_warning("Warning: No dwarf info found in the vmlinux - "
+				"please rebuild kernel with CONFIG_DEBUG_INFO=y.\n");
 		if (!need_dwarf) {
 			pr_debug("Trying to use symbols.\n");
 			return 0;
--
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]


#1211088 — [PATCH 16/29] bpf tools: Load a program with different instances using preprocessor

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 16/29] bpf tools: Load a program with different instances using preprocessor
Message-ID<pZRAv-DT-51@gated-at.bofh.it>
In reply to#1211076
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 feature. Caller
should pass libbpf the number of instances should be created and a
preprocessor function which will be called when doing real loading.
The callback should return instructions arrays for each instances.

fd field in bpf_programs is replaced by instance, which has an nr field
and fds array. bpf_program__nth_fd() is introduced for read fd of
instances. Old interface bpf_program__fd() is reimplemented by
returning the first fd.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Signed-off-by: He Kuang <hekuang@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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-29-git-send-email-wangnan0@huawei.com
[wangnan: Add missing '!',
          allows bpf_program__unload() when prog->instance.nr == -1
]
---
 tools/lib/bpf/libbpf.c | 143 +++++++++++++++++++++++++++++++++++++++++++++----
 tools/lib/bpf/libbpf.h |  22 ++++++++
 2 files changed, 156 insertions(+), 9 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 4fa4bc4..1ff6a19 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -98,7 +98,11 @@ struct bpf_program {
 	} *reloc_desc;
 	int nr_reloc;
 
-	int fd;
+	struct {
+		int nr;
+		int *fds;
+	} instance;
+	bpf_program_prep_t preprocessor;
 
 	struct bpf_object *obj;
 	void *priv;
@@ -152,10 +156,24 @@ struct bpf_object {
 
 static void bpf_program__unload(struct bpf_program *prog)
 {
+	int i;
+
 	if (!prog)
 		return;
 
-	zclose(prog->fd);
+	/*
+	 * If the object is opened but the program is never loaded,
+	 * it is possible that prog->instance.nr == -1.
+	 */
+	if (prog->instance.nr > 0) {
+		for (i = 0; i < prog->instance.nr; i++)
+			zclose(prog->instance.fds[i]);
+	} else if (prog->instance.nr != -1)
+		pr_warning("Internal error: instance.nr is %d\n",
+			   prog->instance.nr);
+
+	prog->instance.nr = -1;
+	zfree(&prog->instance.fds);
 }
 
 static void bpf_program__exit(struct bpf_program *prog)
@@ -206,7 +224,8 @@ bpf_program__init(void *data, size_t size, char *name, int idx,
 	memcpy(prog->insns, data,
 	       prog->insns_cnt * sizeof(struct bpf_insn));
 	prog->idx = idx;
-	prog->fd = -1;
+	prog->instance.fds = NULL;
+	prog->instance.nr = -1;
 
 	return 0;
 errout:
@@ -795,13 +814,71 @@ static int
 bpf_program__load(struct bpf_program *prog,
 		  char *license, u32 kern_version)
 {
-	int err, fd;
+	int err = 0, fd, i;
+
+	if (prog->instance.nr < 0 || !prog->instance.fds) {
+		if (prog->preprocessor) {
+			pr_warning("Internal error: can't load program '%s'\n",
+				   prog->section_name);
+			return -EINVAL;
+		}
+
+		prog->instance.fds = malloc(sizeof(int));
+		if (!prog->instance.fds) {
+			pr_warning("No enough memory for fds\n");
+			return -ENOMEM;
+		}
+		prog->instance.nr = 1;
+		prog->instance.fds[0] = -1;
+	}
+
+	if (!prog->preprocessor) {
+		if (prog->instance.nr != 1)
+			pr_warning("Program '%s' inconsistent: nr(%d) not 1\n",
+				   prog->section_name, prog->instance.nr);
 
-	err = load_program(prog->insns, prog->insns_cnt,
-			   license, kern_version, &fd);
-	if (!err)
-		prog->fd = fd;
+		err = load_program(prog->insns, prog->insns_cnt,
+				   license, kern_version, &fd);
+		if (!err)
+			prog->instance.fds[0] = fd;
+		goto out;
+	}
+
+	for (i = 0; i < prog->instance.nr; 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);
@@ -1033,5 +1110,53 @@ const char *bpf_program__title(struct bpf_program *prog, bool dup)
 
 int bpf_program__fd(struct bpf_program *prog)
 {
-	return prog->fd;
+	return bpf_program__nth_fd(prog, 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;
+
+	if (prog->instance.nr > 0 || prog->instance.fds) {
+		pr_warning("Can't set pre-processor after loading\n");
+		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->instance.nr = nr_instance;
+	prog->instance.fds = instance_fds;
+	prog->preprocessor = prep;
+	return 0;
+}
+
+int bpf_program__nth_fd(struct bpf_program *prog, int n)
+{
+	int fd;
+
+	if (n >= prog->instance.nr || n < 0) {
+		pr_warning("Can't get the %dth fd from program %s: only %d instances\n",
+			   n, prog->section_name, prog->instance.nr);
+		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 -ENOENT;
+	}
+
+	return fd;
 }
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index ea8adc2..9fa7b09 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -65,6 +65,28 @@ const char *bpf_program__title(struct bpf_program *prog, bool dup);
 
 int bpf_program__fd(struct bpf_program *prog);
 
+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__nth_fd(struct bpf_program *prog, int n);
+
 /*
  * We don't need __attribute__((packed)) now since it is
  * unnecessary for 'bpf_map_def' because they are all aligned.
-- 
2.1.0

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


#1211089 — [PATCH 07/29] perf bpf: Collect 'struct perf_probe_event' for bpf_program

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 07/29] perf bpf: Collect 'struct perf_probe_event' for bpf_program
Message-ID<pZRAv-DT-43@gated-at.bofh.it>
In reply to#1211076
This patch utilizes bpf_program__set_private(), binding perf_probe_event
with bpf program by private field.

Saving those information so 'perf record' knows which kprobe point a program
should be attached.

Since data in 'struct perf_probe_event' is build by 2 stages, tev_ready
is used to mark whether the information (especially tevs) in 'struct
perf_probe_event' is valid or not. It is false at first, and set to true
by sync_bpf_program_pev(), which copy all pointers in original pev into
a program specific memory region. sync_bpf_program_pev() is called after
add_perf_probe_events() to make sure ready of data.

Remove code which clean 'struct perf_probe_event' after bpf__probe()
because pointers in pevs are copied to program's private field, calling
clear_perf_probe_event() becomes unsafe.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.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/n/1436445342-1402-21-git-send-email-wangnan0@huawei.com
[Splitted from a larger patch]
---
 tools/perf/util/bpf-loader.c | 90 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 435f52e..ae23f6f 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -30,9 +30,35 @@ DEFINE_PRINT_FN(debug, 1)
 
 static bool libbpf_initialized;
 
+struct bpf_prog_priv {
+	/*
+	 * If pev_ready is false, ppev pointes to a local memory which
+	 * is only valid inside bpf__probe().
+	 * pev is valid only when pev_ready.
+	 */
+	bool pev_ready;
+	union {
+		struct perf_probe_event *ppev;
+		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;
+
+	/* check if pev is initialized */
+	if (priv && priv->pev_ready)
+		clear_perf_probe_event(&priv->pev);
+	free(priv);
+}
+
 static int
 config_bpf_program(struct bpf_program *prog, struct perf_probe_event *pev)
 {
+	struct bpf_prog_priv *priv = NULL;
 	const char *config_str;
 	int err;
 
@@ -74,14 +100,58 @@ config_bpf_program(struct bpf_program *prog, struct perf_probe_event *pev)
 
 	pr_debug("bpf: config '%s' is ok\n", config_str);
 
+	priv = calloc(1, sizeof(*priv));
+	if (!priv) {
+		pr_debug("bpf: failed to alloc memory\n");
+		err = -ENOMEM;
+		goto errout;
+	}
+
+	/*
+	 * At this very early stage, tevs inside pev are not ready.
+	 * It becomes usable after add_perf_probe_events() is called.
+	 * set pev_ready to false so further access read priv->ppev
+	 * only.
+	 */
+	priv->pev_ready = false;
+	priv->ppev = pev;
+
+	err = bpf_program__set_private(prog, priv,
+				       bpf_prog_priv__clear);
+	if (err) {
+		pr_debug("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;
 }
 
+static int
+sync_bpf_program_pev(struct bpf_program *prog)
+{
+	int err;
+	struct bpf_prog_priv *priv;
+	struct perf_probe_event *ppev;
+
+	err = bpf_program__get_private(prog, (void **)&priv);
+	if (err || !priv || priv->pev_ready) {
+		pr_debug("Internal error: sync_bpf_program_pev\n");
+		return -EINVAL;
+	}
+
+	ppev = priv->ppev;
+	memcpy(&priv->pev, ppev, sizeof(*ppev));
+	priv->pev_ready = true;
+	return 0;
+}
+
 int bpf__prepare_load(const char *filename)
 {
 	struct bpf_object *obj;
@@ -172,11 +242,27 @@ int bpf__probe(void)
 	/* add_perf_probe_events return negative when fail */
 	if (err < 0) {
 		pr_debug("bpf probe: failed to probe events\n");
+		goto out;
 	} else
 		is_probed = true;
+
+	/*
+	 * After add_perf_probe_events, 'struct perf_probe_event' is ready.
+	 * Until now copying program's priv->pev field and freeing
+	 * the big array allocated before become safe.
+	 */
+	bpf_object__for_each_safe(obj, tmp) {
+		bpf_object__for_each_program(prog, obj) {
+			err = sync_bpf_program_pev(prog);
+			if (err)
+				goto out;
+		}
+	}
 out:
-	while (nr_events > 0)
-		clear_perf_probe_event(&pevs[--nr_events]);
+	/*
+	 * Don't call clear_perf_probe_event() for entries of pevs:
+	 * they are used by prog's private field.
+	 */
 	free(pevs);
 	return err < 0 ? err : 0;
 }
-- 
2.1.0

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


#1211090 — [PATCH 04/29] perf tools: Enable passing bpf object file to --event

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 04/29] perf tools: Enable passing bpf object file to --event
Message-ID<pZRAv-DT-53@gated-at.bofh.it>
In reply to#1211076
By introducing new rules in tools/perf/util/parse-events.[ly], this
patch enables 'perf record --event bpf_file.o' to select events by an
eBPF object file. It calls parse_events_load_bpf() to load that file,
which uses bpf__prepare_load() and finally calls bpf_object__open() for
the object files.

Instead of introducing evsel to evlist during parsing, events selected
by eBPF object files are appended separately. The reason is:

 1. During parsing, the probing points have not been initialized.

 2. Currently we are unable to call add_perf_probe_events() twice,
    therefore we have to wait until all such events are collected,
    then probe all points by one call.

The real probing and selecting is reside in following patches.

Commiter note:

Testing if the event parsing changes indeed call the BPF loading
routines:

  [root@felicio ~]# ls -la foo.o
  ls: cannot access foo.o: No such file or directory
  [root@felicio ~]# perf record --event foo.o sleep
  libbpf: failed to open foo.o: No such file or directory
  bpf: failed to load foo.o
  invalid or unsupported event: 'foo.o'
  Run 'perf list' for a list of valid events

   usage: perf record [<options>] [<command>]
      or: perf record [<options>] -- <command> [<options>]

      -e, --event <event>   event selector. use 'perf list' to list available events
  [root@felicio ~]#

Yes, it does this time around.

Signed-off-by: Wang Nan <wangnan0@huawei.com>
Acked-by: Alexei Starovoitov <ast@plumgrid.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.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: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Zefan Li <lizefan@huawei.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/n/1436445342-1402-19-git-send-email-wangnan0@huawei.com
[ The veprintf() and bpf loader parts were split from this one ]
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/Build          |  1 +
 tools/perf/util/parse-events.c | 26 ++++++++++++++++++++++++++
 tools/perf/util/parse-events.h |  3 +++
 tools/perf/util/parse-events.l |  3 +++
 tools/perf/util/parse-events.y | 18 +++++++++++++++++-
 5 files changed, 50 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index c20473d..4d944d4 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -82,6 +82,7 @@ libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
 libperf-$(CONFIG_AUXTRACE) += intel-pt.o
 libperf-y += parse-branch-options.o
 
+libperf-$(CONFIG_LIBBPF) += bpf-loader.o
 libperf-$(CONFIG_LIBELF) += symbol-elf.o
 libperf-$(CONFIG_LIBELF) += probe-file.o
 libperf-$(CONFIG_LIBELF) += probe-event.o
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index d826e6f..9eaceb2 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -19,6 +19,7 @@
 #include "thread_map.h"
 #include "cpumap.h"
 #include "asm/bug.h"
+#include "bpf-loader.h"
 
 #define MAX_NAME_LEN 100
 
@@ -481,6 +482,31 @@ int parse_events_add_tracepoint(struct list_head *list, int *idx,
 		return add_tracepoint_event(list, idx, sys, event);
 }
 
+int parse_events_load_bpf(struct parse_events_evlist *data,
+			  struct list_head *list __maybe_unused,
+			  char *bpf_file_name)
+{
+	int err;
+	char errbuf[BUFSIZ];
+
+	/*
+	 * Currently don't link any event to list. BPF object files
+	 * should be saved to a seprated list and processed together.
+	 *
+	 * Things could be changed if we solve perf probe reentering
+	 * problem. After that probe events file by file is possible.
+	 * However, probing cost is still need to be considered.
+	 */
+	err = bpf__prepare_load(bpf_file_name);
+	if (err) {
+		bpf__strerror_prepare_load(bpf_file_name, err,
+					   errbuf, sizeof(errbuf));
+		data->error->str = strdup(errbuf);
+		data->error->help = strdup("(add -v to see detail)");
+	}
+	return err;
+}
+
 static int
 parse_breakpoint_type(const char *type, struct perf_event_attr *attr)
 {
diff --git a/tools/perf/util/parse-events.h b/tools/perf/util/parse-events.h
index a09b0e2..3652387 100644
--- a/tools/perf/util/parse-events.h
+++ b/tools/perf/util/parse-events.h
@@ -119,6 +119,9 @@ int parse_events__modifier_group(struct list_head *list, char *event_mod);
 int parse_events_name(struct list_head *list, char *name);
 int parse_events_add_tracepoint(struct list_head *list, int *idx,
 				char *sys, char *event);
+int parse_events_load_bpf(struct parse_events_evlist *data,
+			  struct list_head *list,
+			  char *bpf_file_name);
 int parse_events_add_numeric(struct parse_events_evlist *data,
 			     struct list_head *list,
 			     u32 type, u64 config,
diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l
index 936d566..22e8f93 100644
--- a/tools/perf/util/parse-events.l
+++ b/tools/perf/util/parse-events.l
@@ -115,6 +115,7 @@ do {							\
 group		[^,{}/]*[{][^}]*[}][^,{}/]*
 event_pmu	[^,{}/]+[/][^/]*[/][^,{}/]*
 event		[^,{}/]+
+bpf_object	.*\.(o|bpf)
 
 num_dec		[0-9]+
 num_hex		0x[a-fA-F0-9]+
@@ -159,6 +160,7 @@ modifier_bp	[rwx]{1,3}
 		}
 
 {event_pmu}	|
+{bpf_object}	|
 {event}		{
 			BEGIN(INITIAL);
 			REWIND(1);
@@ -264,6 +266,7 @@ r{num_raw_hex}		{ return raw(yyscanner); }
 {num_hex}		{ return value(yyscanner, 16); }
 
 {modifier_event}	{ return str(yyscanner, PE_MODIFIER_EVENT); }
+{bpf_object}		{ return str(yyscanner, PE_BPF_OBJECT); }
 {name}			{ return pmu_str_check(yyscanner); }
 "/"			{ BEGIN(config); return '/'; }
 -			{ return '-'; }
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index 591905a..3ee3a32 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -42,6 +42,7 @@ static inc_group_count(struct list_head *list,
 %token PE_VALUE PE_VALUE_SYM_HW PE_VALUE_SYM_SW PE_RAW PE_TERM
 %token PE_EVENT_NAME
 %token PE_NAME
+%token PE_BPF_OBJECT
 %token PE_MODIFIER_EVENT PE_MODIFIER_BP
 %token PE_NAME_CACHE_TYPE PE_NAME_CACHE_OP_RESULT
 %token PE_PREFIX_MEM PE_PREFIX_RAW PE_PREFIX_GROUP
@@ -53,6 +54,7 @@ static inc_group_count(struct list_head *list,
 %type <num> PE_RAW
 %type <num> PE_TERM
 %type <str> PE_NAME
+%type <str> PE_BPF_OBJECT
 %type <str> PE_NAME_CACHE_TYPE
 %type <str> PE_NAME_CACHE_OP_RESULT
 %type <str> PE_MODIFIER_EVENT
@@ -69,6 +71,7 @@ static inc_group_count(struct list_head *list,
 %type <head> event_legacy_tracepoint
 %type <head> event_legacy_numeric
 %type <head> event_legacy_raw
+%type <head> event_bpf_file
 %type <head> event_def
 %type <head> event_mod
 %type <head> event_name
@@ -198,7 +201,8 @@ event_def: event_pmu |
 	   event_legacy_mem |
 	   event_legacy_tracepoint sep_dc |
 	   event_legacy_numeric sep_dc |
-	   event_legacy_raw sep_dc
+	   event_legacy_raw sep_dc |
+	   event_bpf_file
 
 event_pmu:
 PE_NAME '/' event_config '/'
@@ -420,6 +424,18 @@ PE_RAW
 	$$ = list;
 }
 
+event_bpf_file:
+PE_BPF_OBJECT
+{
+	struct parse_events_evlist *data = _data;
+	struct list_head *list;
+
+	ALLOC_LIST(list);
+	ABORT_ON(parse_events_load_bpf(data, list, $1));
+	$$ = list;
+}
+
+
 start_terms: event_config
 {
 	struct parse_events_terms *data = _data;
-- 
2.1.0

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


#1211091 — [PATCH 20/29] perf tools: Add BPF_PROLOGUE config options for further patches

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 20/29] perf tools: Add BPF_PROLOGUE config options for further patches
Message-ID<pZRAw-DT-57@gated-at.bofh.it>
In reply to#1211076
If both LIBBPF and DWARF are detected, it is possible to create prologue
for eBPF programs to help them accessing kernel data. HAVE_BPF_PROLOGUE
and CONFIG_BPF_PROLOGUE is added as flags for this feature.

PERF_HAVE_ARCH_GET_REG_OFFSET indicates an architecture supports
converting name of a register to its offset in 'struct pt_regs'.
Without this support, BPF_PROLOGUE should be turned off.

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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-33-git-send-email-wangnan0@huawei.com
---
 tools/perf/config/Makefile           | 12 ++++++++++++
 tools/perf/util/include/dwarf-regs.h |  7 +++++++
 2 files changed, 19 insertions(+)

diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 38a4144..d46765b7 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -314,6 +314,18 @@ ifndef NO_LIBELF
       CFLAGS += -DHAVE_LIBBPF_SUPPORT
       $(call detected,CONFIG_LIBBPF)
     endif
+
+    ifndef NO_DWARF
+      ifneq ($(origin PERF_HAVE_ARCH_GET_REG_INFO), undefined)
+        CFLAGS += -DHAVE_BPF_PROLOGUE
+        $(call detected,CONFIG_BPF_PROLOGUE)
+      else
+        msg := $(warning BPF prologue is not supported by architecture $(ARCH));
+      endif
+    else
+      msg := $(warning DWARF support is off, BPF prologue is disabled);
+    endif
+
   endif # NO_LIBBPF
 endif # NO_LIBELF
 
diff --git a/tools/perf/util/include/dwarf-regs.h b/tools/perf/util/include/dwarf-regs.h
index 8f14965..3dda083 100644
--- a/tools/perf/util/include/dwarf-regs.h
+++ b/tools/perf/util/include/dwarf-regs.h
@@ -5,4 +5,11 @@
 const char *get_arch_regstr(unsigned int n);
 #endif
 
+#ifdef HAVE_BPF_PROLOGUE
+/*
+ * Arch should support fetching the offset of a register in pt_regs
+ * by its name.
+ */
+int arch_get_reg_info(const char *name, int *offset);
+#endif
 #endif
-- 
2.1.0

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


#1211092 — [PATCH 24/29] perf tools: Use same BPF program if arguments are identical

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 24/29] perf tools: Use same BPF program if arguments are identical
Message-ID<pZRAw-DT-59@gated-at.bofh.it>
In reply to#1211076
This patch allows creating only one BPF program for different
'probe_trace_event'(tev) generated by one 'perf_probe_event'(pev), if
their prologues are identical.

This is done by comparing argument list of different tev, and maps type
of prologue and tev using a mapping array. This patch utilizes qsort to
sort tevs. After sorting, tevs with identical argument list will group
together.

Signed-off-by: Wang Nan <wangnan0@hauwei.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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-37-git-send-email-wangnan0@huawei.com
---
 tools/perf/util/bpf-loader.c | 133 ++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 126 insertions(+), 7 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index 10fbd33..68c059b 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -47,6 +47,8 @@ struct bpf_prog_priv {
 	};
 	bool need_prologue;
 	struct bpf_insn *insns_buf;
+	int nr_types;
+	int *type_mapping;
 };
 
 static void
@@ -59,6 +61,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
 	if (priv && priv->pev_ready)
 		clear_perf_probe_event(&priv->pev);
 	zfree(&priv->insns_buf);
+	zfree(&priv->type_mapping);
 	free(priv);
 }
 
@@ -254,7 +257,7 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
 	struct bpf_prog_priv *priv;
 	struct bpf_insn *buf;
 	size_t prologue_cnt = 0;
-	int err;
+	int i, err;
 
 	err = bpf_program__get_private(prog, (void **)&priv);
 	if (err || !priv || !priv->pev_ready)
@@ -262,10 +265,20 @@ preproc_gen_prologue(struct bpf_program *prog, int n,
 
 	pev = &priv->pev;
 
-	if (n < 0 || n >= pev->ntevs)
+	if (n < 0 || n >= priv->nr_types)
 		goto errout;
 
-	tev = &pev->tevs[n];
+	/* Find a tev belongs to that type */
+	for (i = 0; i < pev->ntevs; i++)
+		if (priv->type_mapping[i] == n)
+			break;
+
+	if (i >= pev->ntevs) {
+		pr_debug("Internal error: prologue type %d not found\n", n);
+		return -ENOENT;
+	}
+
+	tev = &pev->tevs[i];
 
 	buf = priv->insns_buf;
 	err = bpf__gen_prologue(tev->args, tev->nargs,
@@ -296,6 +309,98 @@ errout:
 	return -EINVAL;
 }
 
+/*
+ * compare_tev_args is reflexive, transitive and antisymmetric.
+ * I can show that but this margin is too narrow to contain.
+ */
+static int compare_tev_args(const void *ptev1, const void *ptev2)
+{
+	int i, ret;
+	const struct probe_trace_event *tev1 =
+		*(const struct probe_trace_event **)ptev1;
+	const struct probe_trace_event *tev2 =
+		*(const struct probe_trace_event **)ptev2;
+
+	ret = tev2->nargs - tev1->nargs;
+	if (ret)
+		return ret;
+
+	for (i = 0; i < tev1->nargs; i++) {
+		struct probe_trace_arg *arg1, *arg2;
+		struct probe_trace_arg_ref *ref1, *ref2;
+
+		arg1 = &tev1->args[i];
+		arg2 = &tev2->args[i];
+
+		ret = strcmp(arg1->value, arg2->value);
+		if (ret)
+			return ret;
+
+		ref1 = arg1->ref;
+		ref2 = arg2->ref;
+
+		while (ref1 && ref2) {
+			ret = ref2->offset - ref1->offset;
+			if (ret)
+				return ret;
+
+			ref1 = ref1->next;
+			ref2 = ref2->next;
+		}
+
+		if (ref1 || ref2)
+			return ref2 ? 1 : -1;
+	}
+
+	return 0;
+}
+
+static int map_prologue(struct perf_probe_event *pev, int *mapping,
+			int *nr_types)
+{
+	int i, type = 0;
+	struct {
+		struct probe_trace_event *tev;
+		int idx;
+	} *stevs;
+	size_t array_sz = sizeof(*stevs) * pev->ntevs;
+
+	stevs = malloc(array_sz);
+	if (!stevs) {
+		pr_debug("No ehough memory: alloc stevs failed\n");
+		return -ENOMEM;
+	}
+
+	pr_debug("In map_prologue, ntevs=%d\n", pev->ntevs);
+	for (i = 0; i < pev->ntevs; i++) {
+		stevs[i].tev = &pev->tevs[i];
+		stevs[i].idx = i;
+	}
+	qsort(stevs, pev->ntevs, sizeof(*stevs),
+	      compare_tev_args);
+
+	for (i = 0; i < pev->ntevs; i++) {
+		if (i == 0) {
+			mapping[stevs[i].idx] = type;
+			pr_debug("mapping[%d]=%d\n", stevs[i].idx,
+				 type);
+			continue;
+		}
+
+		if (compare_tev_args(stevs + i, stevs + i - 1) == 0)
+			mapping[stevs[i].idx] = type;
+		else
+			mapping[stevs[i].idx] = ++type;
+
+		pr_debug("mapping[%d]=%d\n", stevs[i].idx,
+			 mapping[stevs[i].idx]);
+	}
+	free(stevs);
+	*nr_types = type + 1;
+
+	return 0;
+}
+
 static int hook_load_preprocessor(struct bpf_program *prog)
 {
 	struct perf_probe_event *pev;
@@ -336,7 +441,19 @@ static int hook_load_preprocessor(struct bpf_program *prog)
 		return -ENOMEM;
 	}
 
-	err = bpf_program__set_prep(prog, pev->ntevs,
+	priv->type_mapping = malloc(sizeof(int) * pev->ntevs);
+	if (!priv->type_mapping) {
+		pr_debug("No enough memory: alloc type_mapping failed\n");
+		return -ENOMEM;
+	}
+	memset(priv->type_mapping, 0xff,
+	       sizeof(int) * pev->ntevs);
+
+	err = map_prologue(pev, priv->type_mapping, &priv->nr_types);
+	if (err)
+		return err;
+
+	err = bpf_program__set_prep(prog, priv->nr_types,
 				    preproc_gen_prologue);
 	return err;
 }
@@ -456,9 +573,11 @@ int bpf__foreach_tev(bpf_prog_iter_callback_t func, void *arg)
 			for (i = 0; i < pev->ntevs; i++) {
 				tev = &pev->tevs[i];
 
-				if (priv->need_prologue)
-					fd = bpf_program__nth_fd(prog, i);
-				else
+				if (priv->need_prologue) {
+					int type = priv->type_mapping[i];
+
+					fd = bpf_program__nth_fd(prog, type);
+				} else
 					fd = bpf_program__fd(prog);
 
 				if (fd < 0) {
-- 
2.1.0

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


#1211095 — [PATCH 23/29] perf tools: Generate prologue for BPF programs

FromWang Nan <wangnan0@huawei.com>
Date2015-08-21 12:20 +0200
Subject[PATCH 23/29] perf tools: Generate prologue for BPF programs
Message-ID<pZRAw-DT-67@gated-at.bofh.it>
In reply to#1211076
This patch generates prologue for each 'struct probe_trace_event' for
fetching arguments for BPF programs.

After bpf__probe(), iterate over each programs to check whether
prologue is required. If none of 'struct perf_probe_event' a program
will attach to has at least one argument, simply skip preprocessor
hooking. For those who prologue is required, calls bpf__gen_prologue()
and paste original instruction after prologue.

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
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Link: http://lkml.kernel.org/n/1436445342-1402-36-git-send-email-wangnan0@huawei.com
---
 tools/perf/util/bpf-loader.c | 120 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 119 insertions(+), 1 deletion(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index f4693b6..10fbd33 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -5,10 +5,13 @@
  * Copyright (C) 2015 Huawei Inc.
  */
 
+#include <linux/bpf.h>
 #include <bpf/libbpf.h>
 #include "perf.h"
 #include "debug.h"
 #include "bpf-loader.h"
+#include "bpf-prologue.h"
+#include "llvm-utils.h"
 #include "probe-event.h"
 #include "probe-finder.h"
 #include "llvm-utils.h"
@@ -42,6 +45,8 @@ struct bpf_prog_priv {
 		struct perf_probe_event *ppev;
 		struct perf_probe_event pev;
 	};
+	bool need_prologue;
+	struct bpf_insn *insns_buf;
 };
 
 static void
@@ -53,6 +58,7 @@ bpf_prog_priv__clear(struct bpf_program *prog __maybe_unused,
 	/* check if pev is initialized */
 	if (priv && priv->pev_ready)
 		clear_perf_probe_event(&priv->pev);
+	zfree(&priv->insns_buf);
 	free(priv);
 }
 
@@ -238,6 +244,103 @@ int bpf__unprobe(void)
 	return ret < 0 ? ret : 0;
 }
 
+static int
+preproc_gen_prologue(struct bpf_program *prog, int n,
+		     struct bpf_insn *orig_insns, int orig_insns_cnt,
+		     struct bpf_prog_prep_result *res)
+{
+	struct probe_trace_event *tev;
+	struct perf_probe_event *pev;
+	struct bpf_prog_priv *priv;
+	struct bpf_insn *buf;
+	size_t prologue_cnt = 0;
+	int err;
+
+	err = bpf_program__get_private(prog, (void **)&priv);
+	if (err || !priv || !priv->pev_ready)
+		goto errout;
+
+	pev = &priv->pev;
+
+	if (n < 0 || n >= pev->ntevs)
+		goto errout;
+
+	tev = &pev->tevs[n];
+
+	buf = priv->insns_buf;
+	err = bpf__gen_prologue(tev->args, tev->nargs,
+				buf, &prologue_cnt,
+				BPF_MAXINSNS - orig_insns_cnt);
+	if (err) {
+		const char *title;
+
+		title = bpf_program__title(prog, false);
+		if (!title)
+			title = "??";
+
+		pr_debug("Failed to generate prologue for program %s\n",
+			 title);
+		return err;
+	}
+
+	memcpy(&buf[prologue_cnt], orig_insns,
+	       sizeof(struct bpf_insn) * orig_insns_cnt);
+
+	res->new_insn_ptr = buf;
+	res->new_insn_cnt = prologue_cnt + orig_insns_cnt;
+	res->pfd = NULL;
+	return 0;
+
+errout:
+	pr_debug("Internal error in preproc_gen_prologue\n");
+	return -EINVAL;
+}
+
+static int hook_load_preprocessor(struct bpf_program *prog)
+{
+	struct perf_probe_event *pev;
+	struct bpf_prog_priv *priv;
+	bool need_prologue = false;
+	int err, i;
+
+	err = bpf_program__get_private(prog, (void **)&priv);
+	if (err || !priv) {
+		pr_debug("Internal error when hook preprocessor\n");
+		return -EINVAL;
+	}
+
+	pev = &priv->pev;
+	for (i = 0; i < pev->ntevs; i++) {
+		struct probe_trace_event *tev = &pev->tevs[i];
+
+		if (tev->nargs > 0) {
+			need_prologue = true;
+			break;
+		}
+	}
+
+	/*
+	 * Since all tev doesn't have argument, we don't need generate
+	 * prologue.
+	 */
+	if (!need_prologue) {
+		priv->need_prologue = false;
+		return 0;
+	}
+
+	priv->need_prologue = true;
+	priv->insns_buf = malloc(sizeof(struct bpf_insn) *
+					BPF_MAXINSNS);
+	if (!priv->insns_buf) {
+		pr_debug("No enough memory: alloc insns_buf failed\n");
+		return -ENOMEM;
+	}
+
+	err = bpf_program__set_prep(prog, pev->ntevs,
+				    preproc_gen_prologue);
+	return err;
+}
+
 int bpf__probe(void)
 {
 	int err, nr_events = 0;
@@ -288,6 +391,17 @@ int bpf__probe(void)
 			err = sync_bpf_program_pev(prog);
 			if (err)
 				goto out;
+			/*
+			 * After probing, let's consider prologue, which
+			 * adds program fetcher to BPF programs.
+			 *
+			 * hook_load_preprocessorr() hooks pre-processor
+			 * to bpf_program, let it generate prologue
+			 * dynamically during loading.
+			 */
+			err = hook_load_preprocessor(prog);
+			if (err)
+				goto out;
 		}
 	}
 out:
@@ -342,7 +456,11 @@ int bpf__foreach_tev(bpf_prog_iter_callback_t func, void *arg)
 			for (i = 0; i < pev->ntevs; i++) {
 				tev = &pev->tevs[i];
 
-				fd = bpf_program__fd(prog);
+				if (priv->need_prologue)
+					fd = bpf_program__nth_fd(prog, i);
+				else
+					fd = bpf_program__fd(prog);
+
 				if (fd < 0) {
 					pr_debug("bpf: failed to get file descriptor\n");
 					return fd;
-- 
2.1.0

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


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | linux.kernel


csiph-web