Skip to contentSkip to conversation

perf bpf: Add support to run BEGIN/END code

RFC In review Jiri Olsa 5 participants 27 messages Mar 12, 2018 – Mar 20, 2018

Subsystems (3)
lore
Share & tools
lore

Jiri Olsa

author reviewer
#0 lore raw

cover perf bpf: Add support to run BEGIN/END code

hi,
this is *RFC* and the following patchset is very rough and ugly 'prove of concept'-kind-of-toy code. I'm mostly interested in opinions about if this could be useful in your current eBPF usage.

Currently we can load eBPF code within the record command and attach it to event. We have 2 ways of communicating the data back to user: bpf-output event that goes to perf.data or 'trace_printk' output in tracefs buffer.

AFAICS we're not covering quite large usage base that runs code before and once the probe is finished to setup, collect and display the collected data.

This patchset is adding support to run BEGIN and END code snipets before and after eBPF probe is loaded.

This allow to write 'collecting' code in eBPF object, like in the attached example (it's also part of the patchset).

This patchset also adds 'bpf' command to ease up the loading of eBPF files with options for compilation and disassembly of eBPF objects:

      $ perf bpf -c samples/syscall-counts.c
      LLVM: dumping samples/syscall-counts.o
      $ perf bpf -d samples/syscall-counts.o | head
      Disassembly of raw_syscalls:sys_enter:
         0: (b7) r1 = 1
             b7 01 00 00 01 00 00 00
         1: (7b) *(u64 *)(r10 -8) = r1
             7b 1a f8 ff 00 00 00 00
         2: (bf) r6 = r10
      ...
      $ sudo perf bpf -e samples/syscall-counts.o -a
      BEGIN
      ^CEND
                    comm            value
                 firefox              182
           Socket Thread                8
         InotifyEventThr               26
         xmonad-x86_64-l              405
      ...

The patchset is also available in here:
https://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/bpf

So far I need following following lines in .perfconfig to run this:
[llvm]
kbuild-dir=/home/jolsa/kernel/linux-perf clang-opt=-I/home/jolsa/kernel/linux-perf/tools/perf/util

thoughts? ;-) thanks,
jirka

Cc Brendan Gregg <[email protected]>
Cc Stanislav Kozina <[email protected]>
Cc "Frank Ch. Eigler" <[email protected]>
Cc Will Cohen <[email protected]>
Cc Eugene Syromiatnikov <[email protected]>
Cc Jerome Marchand <[email protected]>

---
#include <uapi/linux/bpf.h>
#include <bpf-helpers.h>
#include <bpf-userfuncs.h>

#define TASK_COMM_LEN 16

char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;

struct key_t {
        char comm[TASK_COMM_LEN];
};

struct bpf_map_def SEC("maps") counts_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct key_t),
.value_size = sizeof(u64),
.max_entries = 100,
};

SEC("raw_syscalls:sys_enter")
int func(void *ctx)

{
        u64 *val, one = 1;
        struct key_t key;
        char comm[TASK_COMM_LEN];

        bpf_get_current_comm(&key.comm, sizeof(comm));

        val = bpf_map_lookup_elem(&counts_map, &key);
        if (val)
                (*val)++;
        else
                bpf_map_update_elem(&counts_map, &key, &one, BPF_NOEXIST);

        return 0;
}

int BEGIN(void)

{
        print("BEGIN\n");
        return 0;
}

void END(void)

{
        struct key_t key = {}, next_key;
        u64 value;
        int i = 0;

        print("END\n");
        print("\n              comm            value\n");

        while (bpfu_map_get_next_key(&counts_map, &key, &next_key) == 0) {
                if (bpfu_map_lookup_elem(&counts_map, &next_key, &value))
                        continue;

                print("%18s %16lu\n", next_key.comm, value);
                key = next_key;
        }
}

---
Jiri Olsa (13):
lib bpf: Add bpf_program__insns function
perf tools: Display ebpf compiling command in debug output perf tools: Add bpf command
perf tools: Add bpf__compile function
perf bpf: Add compile option
perf bpf: Add disasm option
libbpf: Make bpf_program__next skip .text section
libbpf: Collect begin/end .text functions
libbpf: Add bpf_insn__interpret function
libbpf: Add bpf_object__run_(begin|end) functions perf bpf: Add helper header files
perf bpf: Run begin/end programs
perf samples: Add syscall-count.c object

 tools/lib/bpf/Build                 |   2 +-
 tools/lib/bpf/interp.c              | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.c              | 125 +++++++++++++++++++++++++++++++++++++++++++++++--
 tools/lib/bpf/libbpf.h              |   7 +++
 tools/perf/Build                    |   7 +++
 tools/perf/Makefile.config          |   1 +
 tools/perf/builtin-bpf.c            | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/builtin.h                |   1 +
 tools/perf/command-list.txt         |   1 +
 tools/perf/perf.c                   |   1 +
 tools/perf/samples/syscall-counts.c |  61 ++++++++++++++++++++++++
 tools/perf/util/bpf-helpers.h       | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.c        | 124 ++++++++++++++++++++++++++++++++++++++++++++-----
 tools/perf/util/bpf-loader.h        |   4 ++
 tools/perf/util/bpf-userapi.h       |  11 +++++
 tools/perf/util/bpf-userfuncs.h     |  19 ++++++++
 tools/perf/util/llvm-utils.c        |  14 ++++++
 17 files changed, 1173 insertions(+), 15 deletions(-)
 create mode 100644 tools/lib/bpf/interp.c
 create mode 100644 tools/perf/builtin-bpf.c
 create mode 100644 tools/perf/samples/syscall-counts.c
 create mode 100644 tools/perf/util/bpf-helpers.h
 create mode 100644 tools/perf/util/bpf-userapi.h
 create mode 100644 tools/perf/util/bpf-userfuncs.h
author reviewer
#1 lore raw

PATCH 1/13 lib bpf: Add bpf_program__insns function

Adding bpf_program__insns helper function to retrieve prog's instructions. It's used later in the patchset.

---
 tools/lib/bpf/libbpf.c | 7 +++++++
 tools/lib/bpf/libbpf.h | 3 +++
 2 files changed, 10 insertions(+)
tools/lib/bpf/libbpf.c +7 -0
index 5bbbf285af74..6b9df10470e8 100644
@@ -261,6 +261,13 @@ struct bpf_object {
 };
 #define obj_elf_valid(o)	((o)->efile.elf)
 
+struct bpf_insn*
+bpf_program__insns(struct bpf_program *prog, int *insns_cnt)
+{
+	*insns_cnt = prog->insns_cnt;
+	return prog->insns;
+}
+
 static void bpf_program__unload(struct bpf_program *prog)
 {
 	int i;
tools/lib/bpf/libbpf.h +3 -0
index f85906533cdd..bfc4d0411ec5 100644
@@ -180,6 +180,9 @@ int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,
 
 int bpf_program__nth_fd(struct bpf_program *prog, int n);
 
+struct bpf_insn*
+bpf_program__insns(struct bpf_program *prog, int *insns_cnt);
+
 /*
  * Adjust type of bpf program. Default is kprobe.
  */
Signature · 1 line
2.13.6
author reviewer
#2 lore raw

PATCH 2/13 perf tools: Display ebpf compiling command in debug output

In reply to Jiri Olsa

In addition to template, display also the real compile command line with all the variables substituted.

llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS ... llvm compiling command : /usr/bin/clang -D__KERNEL__ -D__NR_CPUS__=24 -DLINUX_VERSION_CODE=0x41000 ...

---
 tools/perf/util/llvm-utils.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
tools/perf/util/llvm-utils.c +14 -0
index 4952b429caa7..1cca0a2fa641 100644
@@ -433,6 +433,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	char serr[STRERR_BUFSIZE];
 	char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
 	const char *template = llvm_param.clang_bpf_cmd_template;
+	char *command_echo, *command_out;
 
 	if (path[0] != '-' && realpath(path, abspath) == NULL) {
 		err = errno;
@@ -487,6 +488,16 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		      (path[0] == '-') ? path : abspath);
 
 	pr_debug("llvm compiling command template: %s\n", template);
+
+	if (asprintf(&command_echo, "echo -n \"%s\"", template) < 0)
+		goto errout;
+
+	err = read_from_pipe(command_echo, (void **) &command_out, NULL);
+	if (err)
+		goto errout;
+
+	pr_debug("llvm compiling command : %s\n", command_out);
+
 	err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
 	if (err) {
 		pr_err("ERROR:\tunable to compile %s\n", path);
@@ -497,6 +508,8 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		goto errout;
 	}
 
+	free(command_echo);
+	free(command_out);
 	free(kbuild_dir);
 	free(kbuild_include_opts);
 
@@ -509,6 +522,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		*p_obj_buf_sz = obj_buf_sz;
 	return 0;
 errout:
+	free(command_echo);
 	free(kbuild_dir);
 	free(kbuild_include_opts);
 	free(obj_buf);
Signature · 1 line
2.13.6
#3 lore raw

Re: [PATCH 02/13] perf tools: Display ebpf compiling command in debug output

Em Mon, Mar 12, 2018 at 10:43:02AM +0100, Jiri Olsa escreveu:

Quoted 5 lines

In addition to template, display also the real compile command line with all the variables substituted.

llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS ... llvm compiling command : /usr/bin/clang -D__KERNEL__ -D__NR_CPUS__=24 -DLINUX_VERSION_CODE=0x41000 ...

Useful, applied.

- Arnaldo

#4 lore raw

[tip:perf/core] perf llvm: Display eBPF compiling command in debug output

In reply to Jiri Olsa
perf llvm: Display eBPF compiling command in debug output
Commit-ID:  5eab5a7ee032acaab3da8fc95a3614fec14687ac
Gitweb:     https://git.kernel.org/tip/5eab5a7ee032acaab3da8fc95a3614fec14687ac
Author:     Jiri Olsa <[email protected]>
AuthorDate: Mon, 12 Mar 2018 10:43:02 +0100
Committer:  Arnaldo Carvalho de Melo <[email protected]>
CommitDate: Fri, 16 Mar 2018 13:56:12 -0300

perf llvm: Display eBPF compiling command in debug output

In addition to template, display also the real compile command line with all the variables substituted.

llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS ... llvm compiling command : /usr/bin/clang -D__KERNEL__ -D__NR_CPUS__=24 -DLINUX_VERSION_CODE=0x41000 ...

---
 tools/perf/util/llvm-utils.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)
tools/perf/util/llvm-utils.c +14 -0
index 4952b429caa7..1cca0a2fa641 100644
@@ -433,6 +433,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 	char serr[STRERR_BUFSIZE];
 	char *kbuild_dir = NULL, *kbuild_include_opts = NULL;
 	const char *template = llvm_param.clang_bpf_cmd_template;
+	char *command_echo, *command_out;
 
 	if (path[0] != '-' && realpath(path, abspath) == NULL) {
 		err = errno;
@@ -487,6 +488,16 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		      (path[0] == '-') ? path : abspath);
 
 	pr_debug("llvm compiling command template: %s\n", template);
+
+	if (asprintf(&command_echo, "echo -n \"%s\"", template) < 0)
+		goto errout;
+
+	err = read_from_pipe(command_echo, (void **) &command_out, NULL);
+	if (err)
+		goto errout;
+
+	pr_debug("llvm compiling command : %s\n", command_out);
+
 	err = read_from_pipe(template, &obj_buf, &obj_buf_sz);
 	if (err) {
 		pr_err("ERROR:\tunable to compile %s\n", path);
@@ -497,6 +508,8 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		goto errout;
 	}
 
+	free(command_echo);
+	free(command_out);
 	free(kbuild_dir);
 	free(kbuild_include_opts);
 
@@ -509,6 +522,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,
 		*p_obj_buf_sz = obj_buf_sz;
 	return 0;
 errout:
+	free(command_echo);
 	free(kbuild_dir);
 	free(kbuild_include_opts);
 	free(obj_buf);
author reviewer
#5 lore raw

PATCH 3/13 perf tools: Add bpf command

In reply to Jiri Olsa

Adding perf bpf command to allow to provide some fucs over ebpf objects, like compile, disassembly and loading, which is comming in following patches.

---
 tools/perf/Build            |   1 +
 tools/perf/builtin-bpf.c    | 199 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/builtin.h        |   1 +
 tools/perf/command-list.txt |   1 +
 tools/perf/perf.c           |   1 +
 5 files changed, 203 insertions(+)
 create mode 100644 tools/perf/builtin-bpf.c
tools/perf/Build +1 -0
index e5232d567611..7f521ac16466 100644
@@ -24,6 +24,7 @@ perf-y += builtin-mem.o
 perf-y += builtin-data.o
 perf-y += builtin-version.o
 perf-y += builtin-c2c.o
+perf-y += builtin-bpf.o
 
 perf-$(CONFIG_TRACE) += builtin-trace.o
 perf-$(CONFIG_LIBELF) += builtin-probe.o
tools/perf/builtin-bpf.c new file +199 -0

199 lines not on this page · raw message

tools/perf/builtin.h +1 -0
index 05745f3ce912..1805c65f4d01 100644
@@ -39,6 +39,7 @@ int cmd_inject(int argc, const char **argv);
 int cmd_mem(int argc, const char **argv);
 int cmd_data(int argc, const char **argv);
 int cmd_ftrace(int argc, const char **argv);
+int cmd_bpf(int argc, const char **argv);
 
 int find_scripts(char **scripts_array, char **scripts_path_array);
 #endif
tools/perf/command-list.txt +1 -0
index 2d0caf20ff3a..4e8e398d4f45 100644
@@ -30,3 +30,4 @@ perf-test			mainporcelain common
 perf-timechart			mainporcelain common
 perf-top			mainporcelain common
 perf-trace			mainporcelain audit
+perf-bpf			mainporcelain common
tools/perf/perf.c +1 -0
index 1b3fc8ec0fa2..144cf71af0f7 100644
@@ -80,6 +80,7 @@ static struct cmd_struct commands[] = {
 	{ "mem",	cmd_mem,	0 },
 	{ "data",	cmd_data,	0 },
 	{ "ftrace",	cmd_ftrace,	0 },
+	{ "bpf",	cmd_bpf,	0 },
 };
 
 struct pager_config {
Signature · 1 line
2.13.6
author reviewer
#6 lore raw

PATCH 4/13 perf tools: Add bpf__compile function

In reply to Jiri Olsa

Adding bpf__compile function to have interface for ebpf object compilation.

---
 tools/perf/util/bpf-loader.c | 46 +++++++++++++++++++++++++++++++++-----------
 tools/perf/util/bpf-loader.h |  2 ++
 2 files changed, 37 insertions(+), 11 deletions(-)
tools/perf/util/bpf-loader.c +35 -11
index af7ad814b2c3..e59168153375 100644
@@ -74,6 +74,38 @@ bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)
 	return obj;
 }
 
+static int compile(const char *filename, void *obj_buf, size_t *obj_buf_sz)
+{
+	int err;
+
+	perf_clang__init();
+	err = perf_clang__compile_bpf(filename, obj_buf, obj_buf_sz);
+	perf_clang__cleanup();
+	if (err) {
+		pr_debug("bpf: builtin compilation failed: %d, try external compiler\n", err);
+		err = llvm__compile_bpf(filename, obj_buf, obj_buf_sz);
+		if (err)
+			return -1;
+	} else {
+		pr_debug("bpf: successfull builtin compilation\n");
+	}
+
+	return 0;
+}
+
+int bpf__compile(const char *filename)
+{
+	void *obj_buf;
+	size_t obj_buf_sz;
+
+	if (compile(filename, &obj_buf, &obj_buf_sz))
+		return -1;
+
+	/* make llvm__dump_obj to return error value */
+	llvm__dump_obj(filename, obj_buf, obj_buf_sz);
+	return 0;
+}
+
 struct bpf_object *bpf__prepare_load(const char *filename, bool source)
 {
 	struct bpf_object *obj;
@@ -86,20 +118,12 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source)
 	}
 
 	if (source) {
-		int err;
 		void *obj_buf;
 		size_t obj_buf_sz;
 
-		perf_clang__init();
-		err = perf_clang__compile_bpf(filename, &obj_buf, &obj_buf_sz);
-		perf_clang__cleanup();
-		if (err) {
-			pr_debug("bpf: builtin compilation failed: %d, try external compiler\n", err);
-			err = llvm__compile_bpf(filename, &obj_buf, &obj_buf_sz);
-			if (err)
-				return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
-		} else
-			pr_debug("bpf: successfull builtin compilation\n");
+		if (compile(filename, &obj_buf, &obj_buf_sz))
+			return ERR_PTR(-BPF_LOADER_ERRNO__COMPILE);
+
 		obj = bpf_object__open_buffer(obj_buf, obj_buf_sz, filename);
 
 		if (!IS_ERR(obj) && llvm_param.dump_obj)
tools/perf/util/bpf-loader.h +2 -0
index 5d3aefd6fae7..8c2a494cab53 100644
@@ -58,6 +58,8 @@ int bpf__strerror_prepare_load(const char *filename, bool source,
 struct bpf_object *bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz,
 					    const char *name);
 
+int bpf__compile(const char *filename);
+
 void bpf__clear(void);
 
 int bpf__probe(struct bpf_object *obj);
Signature · 1 line
2.13.6
author reviewer
#7 lore raw

PATCH 5/13 perf bpf: Add compile option

In reply to Jiri Olsa

Adding -c/--compile option to provide compilation
for ebpf objects, like:

  $ perf bpf -c samples/syscall-counts.c
  LLVM: dumping samples/syscall-counts.o
---
 tools/perf/builtin-bpf.c | 7 +++++++
 1 file changed, 7 insertions(+)
tools/perf/builtin-bpf.c +7 -0
index 6f02352caf79..1ae93fd01a97 100644
@@ -145,6 +145,7 @@ int cmd_bpf(int argc, const char **argv)
 		"perf bpf [<options>] -- <command> [<options>]",
 		NULL
 	};
+	const char *compile_src = NULL;
 	const struct option bpf_options[] = {
 		OPT_CALLBACK('e', "event", &bpf.evlist, "event",
 			     "event selector. use 'perf list' to list available events",
@@ -159,6 +160,8 @@ int cmd_bpf(int argc, const char **argv)
 			   "record events on existing thread id"),
 		OPT_INCR('v', "verbose", &verbose,
 			 "be more verbose"),
+		OPT_STRING('c', "compile", &compile_src, "eBPF source",
+			   "compile eBPF object"),
 		OPT_END()
 	};
 
@@ -170,6 +173,10 @@ int cmd_bpf(int argc, const char **argv)
 
 	argc = parse_options(argc, argv, bpf_options, bpf_usage,
 			     PARSE_OPT_STOP_AT_NON_OPTION);
+
+	if (compile_src)
+		return bpf__compile(compile_src);
+
 	if (!argc && target__none(&bpf.target))
 		usage_with_options(bpf_usage, bpf_options);
 
Signature · 1 line
2.13.6
author reviewer
#8 lore raw

PATCH 6/13 perf bpf: Add disasm option

In reply to Jiri Olsa

Add -d/--disasm option to get the sbpf assembly
code dump, like:

  $ perf bpf -d ./comm1.o | head
  Disassembly of raw_syscalls:sys_enter:
     0: (b7) r1 = 1
         b7 01 00 00 01 00 00 00
     1: (7b) *(u64 *)(r10 -8) = r1
         7b 1a f8 ff 00 00 00 00
     2: (bf) r6 = r10
         bf a6 00 00 00 00 00 00
     3: (07) r6 += -24
         07 06 00 00 e8 ff ff ff
     4: (bf) r1 = r6
     ...
---
 tools/perf/Build           |   6 +++
 tools/perf/Makefile.config |   1 +
 tools/perf/builtin-bpf.c   | 107 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)
tools/perf/Build +6 -0
index 7f521ac16466..0585fd3715d0 100644
@@ -25,6 +25,7 @@ perf-y += builtin-data.o
 perf-y += builtin-version.o
 perf-y += builtin-c2c.o
 perf-y += builtin-bpf.o
+perf-y += bpf-disasm.o
 
 perf-$(CONFIG_TRACE) += builtin-trace.o
 perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -46,6 +47,7 @@ CFLAGS_perf.o              += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))"	\
 CFLAGS_builtin-trace.o	   += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))"
 CFLAGS_builtin-report.o	   += -DTIPDIR="BUILD_STR($(tipdir_SQ))"
 CFLAGS_builtin-report.o	   += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)"
+CFLAGS_builtin-bpf.o	   += -I$(srctree)/kernel/bpf
 
 libperf-y += util/
 libperf-y += arch/
@@ -54,3 +56,7 @@ libperf-y += scripts/
 libperf-$(CONFIG_TRACE) += trace/beauty/
 
 gtk-y += ui/gtk/
+
+$(OUTPUT)bpf-disasm.o: ../../kernel/bpf/disasm.c FORCE
+	$(call rule_mkdir)
+	$(call if_changed_dep,cc_o_c)
tools/perf/Makefile.config +1 -0
index 98ff73648b51..575910cebb57 100644
@@ -999,3 +999,4 @@ $(call detected_var,LIBDIR)
 $(call detected_var,GTK_CFLAGS)
 $(call detected_var,PERL_EMBED_CCOPTS)
 $(call detected_var,PYTHON_EMBED_CCOPTS)
+$(call detected_var,srctree)
tools/perf/builtin-bpf.c +107 -0

143 lines not on this page · raw message

Signature · 1 line
2.13.6
author reviewer
#9 lore raw

PATCH 7/13 libbpf: Make bpf_program__next skip .text section

In reply to Jiri Olsa

Skip .text section in bpf_program__next, so it iterates only throught the probes code. We are about to add .text code support, so the .text section needs to get separated from probes.

---
 tools/lib/bpf/libbpf.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)
tools/lib/bpf/libbpf.c +15 -3
index 6b9df10470e8..07a6d8f5e5ab 100644
@@ -1705,22 +1705,34 @@ void *bpf_object__priv(struct bpf_object *obj)
 struct bpf_program *
 bpf_program__next(struct bpf_program *prev, struct bpf_object *obj)
 {
+	struct bpf_program *prog;
 	size_t idx;
 
 	if (!obj->programs)
 		return NULL;
+
 	/* First handler */
 	if (prev == NULL)
-		return &obj->programs[0];
+		idx = 0;
+	else
+		idx = (prev - obj->programs) + 1;
 
-	if (prev->obj != obj) {
+	if (prev && (prev->obj != obj)) {
 		pr_warning("error: program handler doesn't match object\n");
 		return NULL;
 	}
 
-	idx = (prev - obj->programs) + 1;
 	if (idx >= obj->nr_programs)
 		return NULL;
+
+	prog = &obj->programs[idx];
+
+	if (prog->idx == obj->efile.text_shndx)
+		idx++;
+
+	if (idx >= obj->nr_programs)
+		return NULL;
+
 	return &obj->programs[idx];
 }
 
Signature · 1 line
2.13.6
author reviewer
#10 lore raw

PATCH 8/13 libbpf: Collect begin/end .text functions

In reply to Jiri Olsa

Collect begin/end functions from .text section,
so they could be executed before/after probes.

---
 tools/lib/bpf/libbpf.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)
tools/lib/bpf/libbpf.c +70 -0
index 07a6d8f5e5ab..26231e278bb8 100644
@@ -225,6 +225,10 @@ struct bpf_object {
 	struct bpf_map *maps;
 	size_t nr_maps;
 
+	struct bpf_program *text;
+	struct bpf_insn *insn_begin;
+	struct bpf_insn *insn_end;
+
 	bool loaded;
 
 	/*
@@ -440,6 +444,68 @@ bpf_object__init_prog_names(struct bpf_object *obj)
 	return 0;
 }
 
+static int
+bpf_object__init_text(struct bpf_object *obj)
+{
+	Elf_Data *symbols = obj->efile.symbols;
+	struct bpf_program *prog;
+	size_t pi, si;
+
+	if (obj->efile.text_shndx == -1)
+		return 0;
+
+	for (pi = 0; pi < obj->nr_programs; pi++) {
+		prog = &obj->programs[pi];
+		if (prog->idx != obj->efile.text_shndx)
+			continue;
+
+		obj->text = prog;
+
+		for (si = 0; si < symbols->d_size / sizeof(GElf_Sym); si++) {
+			bool is_end = false, is_begin = false;
+			struct bpf_insn *insn;
+			const char *name = NULL;
+			unsigned int insn_idx;
+			GElf_Sym sym;
+
+			if (!gelf_getsym(symbols, si, &sym))
+				continue;
+			if (sym.st_shndx != prog->idx)
+				continue;
+			if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL)
+				continue;
+
+			name = elf_strptr(obj->efile.elf,
+					  obj->efile.strtabidx,
+					  sym.st_name);
+			if (!name) {
+				pr_warning("failed to get sym name string for prog %s\n",
+					   prog->section_name);
+				return -LIBBPF_ERRNO__LIBELF;
+			}
+
+			is_begin = !strcmp(name, "BEGIN");
+			is_end   = !strcmp(name, "END");
+
+			if (!is_begin && !is_end)
+				continue;
+
+			insn_idx = sym.st_value / sizeof(struct bpf_insn);
+			insn = &prog->insns[insn_idx];
+
+			pr_debug("set %s to %p\n", name, insn);
+
+			if (is_begin)
+				obj->insn_begin = insn;
+			else
+				obj->insn_end   = insn;
+		}
+	}
+
+	return 0;
+}
+
+
 static struct bpf_object *bpf_object__new(const char *path,
 					  void *obj_buf,
 					  size_t obj_buf_sz)
@@ -464,6 +530,7 @@ static struct bpf_object *bpf_object__new(const char *path,
 	obj->efile.obj_buf = obj_buf;
 	obj->efile.obj_buf_sz = obj_buf_sz;
 	obj->efile.maps_shndx = -1;
+	obj->efile.text_shndx = -1;
 
 	obj->loaded = false;
 
@@ -890,6 +957,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 			goto out;
 	}
 	err = bpf_object__init_prog_names(obj);
+	if (err)
+		goto out;
+	err = bpf_object__init_text(obj);
 out:
 	return err;
 }
Signature · 1 line
2.13.6
author reviewer
#11 lore raw

PATCH 9/13 libbpf: Add bpf_insn__interpret function

In reply to Jiri Olsa

Adding bpf_insn__interpret function to run ebpf program in user space.

It's 'borrowed' from systemtap code, I still need to figure the proper credits, that will go to the file header in case this would ever go in.

---
 tools/lib/bpf/Build    |   2 +-
 tools/lib/bpf/interp.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 246 insertions(+), 1 deletion(-)
 create mode 100644 tools/lib/bpf/interp.c
tools/lib/bpf/Build +1 -1
index 64c679d67109..af99109f3d2d 100644
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o nlattr.o
+libbpf-y := libbpf.o bpf.o nlattr.o interp.o
tools/lib/bpf/interp.c new file +245 -0

245 lines not on this page · raw message

Signature · 1 line
2.13.6
#12 lore raw

Re: [PATCH 09/13] libbpf: Add bpf_insn__interpret function

Em Mon, Mar 12, 2018 at 10:43:09AM +0100, Jiri Olsa escreveu:

Quoted 6 lines

Adding bpf_insn__interpret function to run ebpf program in user space.

It's 'borrowed' from systemtap code, I still need to figure the proper credits, that will go to the file header in case this would ever go in.

What is the license? GPL?

Quoted 19 lines

+++ b/tools/lib/bpf/Build

tools/lib/bpf/Build +1 -1
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o nlattr.o
+libbpf-y := libbpf.o bpf.o nlattr.o interp.o
tools/lib/bpf/interp.c new file +6 -0
new file mode 100644
index 000000000000..2ceb6a0836c3
@@ -0,0 +1,245 @@
+#include <uapi/linux/bpf.h>
+#include <stdlib.h>
+#include "interp.h"
+
+u64 bpf_interp__run(struct bpf_interp *interp)
+{

<SNIP>

tools/lib/bpf/interp.c line 236

Quoted 6 lines
tools/lib/bpf/interp.c new file +6 -0
+
+		case BPF_JMP | BPF_EXIT:
+			return regs[0];
+
+		default:
+			abort();

And this should be converted to returning some error that the users can tell the user using whatever UI (TUI, etc).

Quoted 11 lines
tools/lib/bpf/interp.c new file +9 -0
+		}
+
+		regs[i->dst_reg] = dr;
+	nowrite:
+		i++;
+	}
+
+	return 0;
+}
Signature · 1 line
2.13.6
#13 lore raw

Re: [PATCH 09/13] libbpf: Add bpf_insn__interpret function

Quoted 9 lines · Arnaldo Carvalho de Melo

Em Mon, Mar 12, 2018 at 10:43:09AM +0100, Jiri Olsa escreveu:

Quoted 6 lines

Adding bpf_insn__interpret function to run ebpf program in user space.

It's 'borrowed' from systemtap code, I still need to figure the proper credits, that will go to the file header in case this would ever go in.

What is the license? GPL?

yes GPLv2

Quoted 21 lines
Quoted 20 lines

+++ b/tools/lib/bpf/Build

tools/lib/bpf/Build +1 -1
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o nlattr.o
+libbpf-y := libbpf.o bpf.o nlattr.o interp.o
tools/lib/bpf/interp.c new file +6 -0
new file mode 100644
index 000000000000..2ceb6a0836c3
@@ -0,0 +1,245 @@
+#include <uapi/linux/bpf.h>
+#include <stdlib.h>
+#include "interp.h"
+
+u64 bpf_interp__run(struct bpf_interp *interp)
+{

<SNIP>

Quoted 9 lines

tools/lib/bpf/interp.c line 236

Quoted 6 lines
tools/lib/bpf/interp.c new file +6 -0
+
+		case BPF_JMP | BPF_EXIT:
+			return regs[0];
+
+		default:
+			abort();

And this should be converted to returning some error that the users can tell the user using whatever UI (TUI, etc).

right, I want to get rid of all abort calls, I think there's one more

jirka

author reviewer
#14 lore raw

PATCH 10/13 libbpf: Add bpf_object__run_(begin|end) functions

In reply to Jiri Olsa

Add bpf_object__run_(begin|end) functions to run
BEGIN/END code for specific object.

---
 tools/lib/bpf/libbpf.c | 30 ++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h |  4 ++++
 2 files changed, 34 insertions(+)
tools/lib/bpf/libbpf.c +30 -0
index 26231e278bb8..f1f999d64d6a 100644
@@ -45,6 +45,7 @@
 
 #include "libbpf.h"
 #include "bpf.h"
+#include "interp.h"
 
 #ifndef EM_BPF
 #define EM_BPF 247
@@ -2107,3 +2108,32 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type,
 	*prog_fd = bpf_program__fd(first_prog);
 	return 0;
 }
+
+static u64 bpf_program__run(struct bpf_program *prog,
+			    struct bpf_insn *insn,
+			    struct bpf_interp *interp)
+{
+	interp->insns       = prog->insns;
+	interp->insns_cnt   = prog->insns_cnt;
+	interp->insns_start = insn - prog->insns;
+
+	return bpf_interp__run(interp);
+}
+
+u64 bpf_object__run_begin(struct bpf_object *obj, struct bpf_interp *interp)
+{
+	struct bpf_program *prog = obj->text;
+	struct bpf_insn *insn = obj->insn_begin;
+
+	pr_debug("running BEGIN(%p) for %s\n", insn, prog->name);
+	return insn && bpf_program__run(obj->text, insn, interp);
+}
+
+u64 bpf_object__run_end(struct bpf_object *obj, struct bpf_interp *interp)
+{
+	struct bpf_program *prog = obj->text;
+	struct bpf_insn *insn = obj->insn_end;
+
+	pr_debug("running END(%p) for %s\n", insn, prog->name);
+	return insn && bpf_program__run(obj->text, insn, interp);
+}
tools/lib/bpf/libbpf.h +4 -0
index bfc4d0411ec5..8ac4d4efcc1b 100644
@@ -96,6 +96,10 @@ struct bpf_program;
 struct bpf_program *bpf_program__next(struct bpf_program *prog,
 				      struct bpf_object *obj);
 
+struct bpf_interp;
+u64 bpf_object__run_begin(struct bpf_object *obj, struct bpf_interp *interp);
+u64 bpf_object__run_end(struct bpf_object *obj, struct bpf_interp *interp);
+
 #define bpf_object__for_each_program(pos, obj)		\
 	for ((pos) = bpf_program__next(NULL, (obj));	\
 	     (pos) != NULL;				\
Signature · 1 line
2.13.6
author reviewer
#15 lore raw

PATCH 11/13 perf bpf: Add helper header files

In reply to Jiri Olsa

Adding following header files with defines for kernel and user space ebpf calls:

bpf-helpers.h
bpf-userfuncs.h
bpf-userapi.h

---
 tools/perf/util/bpf-helpers.h   | 246 ++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-userapi.h   |  11 ++
 tools/perf/util/bpf-userfuncs.h |  19 ++++
 3 files changed, 276 insertions(+)
 create mode 100644 tools/perf/util/bpf-helpers.h
 create mode 100644 tools/perf/util/bpf-userapi.h
 create mode 100644 tools/perf/util/bpf-userfuncs.h
tools/perf/util/bpf-helpers.h new file +246 -0
new file mode 100644
index 000000000000..5ec52420e906
@@ -0,0 +1,246 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __BPF_HELPERS_H
+#define __BPF_HELPERS_H
+
+#include "bpf-userfuncs.h"
+
+/*
+ * helper macro to place programs, maps, license in
+ * different sections in elf_bpf file. Section names
+ * are interpreted by elf_bpf loader
+ */
+#define SEC(NAME) __attribute__((section(NAME), used))
+
+/* helper functions called from eBPF programs written in C */
+static void *(*bpf_map_lookup_elem)(void *map, void *key) =
+	(void *) BPF_FUNC_map_lookup_elem;
+static int (*bpf_map_update_elem)(void *map, void *key, void *value,
+				  unsigned long long flags) =
+	(void *) BPF_FUNC_map_update_elem;
+static int (*bpf_map_delete_elem)(void *map, void *key) =
+	(void *) BPF_FUNC_map_delete_elem;
+static int (*bpf_probe_read)(void *dst, int size, void *unsafe_ptr) =
+	(void *) BPF_FUNC_probe_read;
+static unsigned long long (*bpf_ktime_get_ns)(void) =
+	(void *) BPF_FUNC_ktime_get_ns;
+static int (*bpf_trace_printk)(const char *fmt, int fmt_size, ...) =
+	(void *) BPF_FUNC_trace_printk;
+static void (*bpf_tail_call)(void *ctx, void *map, int index) =
+	(void *) BPF_FUNC_tail_call;
+static unsigned long long (*bpf_get_smp_processor_id)(void) =
+	(void *) BPF_FUNC_get_smp_processor_id;
+static unsigned long long (*bpf_get_current_pid_tgid)(void) =
+	(void *) BPF_FUNC_get_current_pid_tgid;
+static unsigned long long (*bpf_get_current_uid_gid)(void) =
+	(void *) BPF_FUNC_get_current_uid_gid;
+static int (*bpf_get_current_comm)(void *buf, int buf_size) =
+	(void *) BPF_FUNC_get_current_comm;
+static unsigned long long (*bpf_perf_event_read)(void *map,
+						 unsigned long long flags) =
+	(void *) BPF_FUNC_perf_event_read;
+static int (*bpf_clone_redirect)(void *ctx, int ifindex, int flags) =
+	(void *) BPF_FUNC_clone_redirect;
+static int (*bpf_redirect)(int ifindex, int flags) =
+	(void *) BPF_FUNC_redirect;
+static int (*bpf_redirect_map)(void *map, int key, int flags) =
+	(void *) BPF_FUNC_redirect_map;
+static int (*bpf_perf_event_output)(void *ctx, void *map,
+				    unsigned long long flags, void *data,
+				    int size) =
+	(void *) BPF_FUNC_perf_event_output;
+static int (*bpf_get_stackid)(void *ctx, void *map, int flags) =
+	(void *) BPF_FUNC_get_stackid;
+static int (*bpf_probe_write_user)(void *dst, void *src, int size) =
+	(void *) BPF_FUNC_probe_write_user;
+static int (*bpf_current_task_under_cgroup)(void *map, int index) =
+	(void *) BPF_FUNC_current_task_under_cgroup;
+static int (*bpf_skb_get_tunnel_key)(void *ctx, void *key, int size, int flags) =
+	(void *) BPF_FUNC_skb_get_tunnel_key;
+static int (*bpf_skb_set_tunnel_key)(void *ctx, void *key, int size, int flags) =
+	(void *) BPF_FUNC_skb_set_tunnel_key;
+static int (*bpf_skb_get_tunnel_opt)(void *ctx, void *md, int size) =
+	(void *) BPF_FUNC_skb_get_tunnel_opt;
+static int (*bpf_skb_set_tunnel_opt)(void *ctx, void *md, int size) =
+	(void *) BPF_FUNC_skb_set_tunnel_opt;
+static unsigned long long (*bpf_get_prandom_u32)(void) =
+	(void *) BPF_FUNC_get_prandom_u32;
+static int (*bpf_xdp_adjust_head)(void *ctx, int offset) =
+	(void *) BPF_FUNC_xdp_adjust_head;
+static int (*bpf_xdp_adjust_meta)(void *ctx, int offset) =
+	(void *) BPF_FUNC_xdp_adjust_meta;
+static int (*bpf_setsockopt)(void *ctx, int level, int optname, void *optval,
+			     int optlen) =
+	(void *) BPF_FUNC_setsockopt;
+static int (*bpf_getsockopt)(void *ctx, int level, int optname, void *optval,
+			     int optlen) =
+	(void *) BPF_FUNC_getsockopt;
+static int (*bpf_sock_ops_cb_flags_set)(void *ctx, int flags) =
+	(void *) BPF_FUNC_sock_ops_cb_flags_set;
+static int (*bpf_sk_redirect_map)(void *ctx, void *map, int key, int flags) =
+	(void *) BPF_FUNC_sk_redirect_map;
+static int (*bpf_sock_map_update)(void *map, void *key, void *value,
+				  unsigned long long flags) =
+	(void *) BPF_FUNC_sock_map_update;
+static int (*bpf_perf_event_read_value)(void *map, unsigned long long flags,
+					void *buf, unsigned int buf_size) =
+	(void *) BPF_FUNC_perf_event_read_value;
+static int (*bpf_perf_prog_read_value)(void *ctx, void *buf,
+				       unsigned int buf_size) =
+	(void *) BPF_FUNC_perf_prog_read_value;
+static int (*bpf_override_return)(void *ctx, unsigned long rc) =
+	(void *) BPF_FUNC_override_return;
+
+/*
+ * llvm builtin functions that eBPF C program may use to
+ * emit BPF_LD_ABS and BPF_LD_IND instructions
+ */
+struct sk_buff;
+unsigned long long load_byte(void *skb,
+			     unsigned long long off) asm("llvm.bpf.load.byte");
+unsigned long long load_half(void *skb,
+			     unsigned long long off) asm("llvm.bpf.load.half");
+unsigned long long load_word(void *skb,
+			     unsigned long long off) asm("llvm.bpf.load.word");
+
+/*
+ * a helper structure used by eBPF C program
+ * to describe map attributes to elf_bpf loader
+ */
+struct bpf_map_def {
+	unsigned int type;
+	unsigned int key_size;
+	unsigned int value_size;
+	unsigned int max_entries;
+	unsigned int map_flags;
+	unsigned int inner_map_idx;
+	unsigned int numa_node;
+};
+
+static int (*bpf_skb_load_bytes)(void *ctx, int off, void *to, int len) =
+	(void *) BPF_FUNC_skb_load_bytes;
+static int (*bpf_skb_store_bytes)(void *ctx, int off, void *from, int len, int flags) =
+	(void *) BPF_FUNC_skb_store_bytes;
+static int (*bpf_l3_csum_replace)(void *ctx, int off, int from, int to, int flags) =
+	(void *) BPF_FUNC_l3_csum_replace;
+static int (*bpf_l4_csum_replace)(void *ctx, int off, int from, int to, int flags) =
+	(void *) BPF_FUNC_l4_csum_replace;
+static int (*bpf_skb_under_cgroup)(void *ctx, void *map, int index) =
+	(void *) BPF_FUNC_skb_under_cgroup;
+static int (*bpf_skb_change_head)(void *, int len, int flags) =
+	(void *) BPF_FUNC_skb_change_head;
+
+/* Fall back to what the compiler says */
+#ifndef bpf_target_defined
+#if defined(__x86_64__)
+	#define bpf_target_x86
+#elif defined(__s390x__)
+	#define bpf_target_s930x
+#elif defined(__aarch64__)
+	#define bpf_target_arm64
+#elif defined(__mips__)
+	#define bpf_target_mips
+#elif defined(__powerpc__)
+	#define bpf_target_powerpc
+#elif defined(__sparc__)
+	#define bpf_target_sparc
+#endif
+#endif
+
+#if defined(bpf_target_x86)
+
+#define PT_REGS_PARM1(x) ((x)->di)
+#define PT_REGS_PARM2(x) ((x)->si)
+#define PT_REGS_PARM3(x) ((x)->dx)
+#define PT_REGS_PARM4(x) ((x)->cx)
+#define PT_REGS_PARM5(x) ((x)->r8)
+#define PT_REGS_RET(x) ((x)->sp)
+#define PT_REGS_FP(x) ((x)->bp)
+#define PT_REGS_RC(x) ((x)->ax)
+#define PT_REGS_SP(x) ((x)->sp)
+#define PT_REGS_IP(x) ((x)->ip)
+
+#elif defined(bpf_target_s390x)
+
+#define PT_REGS_PARM1(x) ((x)->gprs[2])
+#define PT_REGS_PARM2(x) ((x)->gprs[3])
+#define PT_REGS_PARM3(x) ((x)->gprs[4])
+#define PT_REGS_PARM4(x) ((x)->gprs[5])
+#define PT_REGS_PARM5(x) ((x)->gprs[6])
+#define PT_REGS_RET(x) ((x)->gprs[14])
+#define PT_REGS_FP(x) ((x)->gprs[11]) /* Works only with CONFIG_FRAME_POINTER */
+#define PT_REGS_RC(x) ((x)->gprs[2])
+#define PT_REGS_SP(x) ((x)->gprs[15])
+#define PT_REGS_IP(x) ((x)->psw.addr)
+
+#elif defined(bpf_target_arm64)
+
+#define PT_REGS_PARM1(x) ((x)->regs[0])
+#define PT_REGS_PARM2(x) ((x)->regs[1])
+#define PT_REGS_PARM3(x) ((x)->regs[2])
+#define PT_REGS_PARM4(x) ((x)->regs[3])
+#define PT_REGS_PARM5(x) ((x)->regs[4])
+#define PT_REGS_RET(x) ((x)->regs[30])
+#define PT_REGS_FP(x) ((x)->regs[29]) /* Works only with CONFIG_FRAME_POINTER */
+#define PT_REGS_RC(x) ((x)->regs[0])
+#define PT_REGS_SP(x) ((x)->sp)
+#define PT_REGS_IP(x) ((x)->pc)
+
+#elif defined(bpf_target_mips)
+
+#define PT_REGS_PARM1(x) ((x)->regs[4])
+#define PT_REGS_PARM2(x) ((x)->regs[5])
+#define PT_REGS_PARM3(x) ((x)->regs[6])
+#define PT_REGS_PARM4(x) ((x)->regs[7])
+#define PT_REGS_PARM5(x) ((x)->regs[8])
+#define PT_REGS_RET(x) ((x)->regs[31])
+#define PT_REGS_FP(x) ((x)->regs[30]) /* Works only with CONFIG_FRAME_POINTER */
+#define PT_REGS_RC(x) ((x)->regs[1])
+#define PT_REGS_SP(x) ((x)->regs[29])
+#define PT_REGS_IP(x) ((x)->cp0_epc)
+
+#elif defined(bpf_target_powerpc)
+
+#define PT_REGS_PARM1(x) ((x)->gpr[3])
+#define PT_REGS_PARM2(x) ((x)->gpr[4])
+#define PT_REGS_PARM3(x) ((x)->gpr[5])
+#define PT_REGS_PARM4(x) ((x)->gpr[6])
+#define PT_REGS_PARM5(x) ((x)->gpr[7])
+#define PT_REGS_RC(x) ((x)->gpr[3])
+#define PT_REGS_SP(x) ((x)->sp)
+#define PT_REGS_IP(x) ((x)->nip)
+
+#elif defined(bpf_target_sparc)
+
+#define PT_REGS_PARM1(x) ((x)->u_regs[UREG_I0])
+#define PT_REGS_PARM2(x) ((x)->u_regs[UREG_I1])
+#define PT_REGS_PARM3(x) ((x)->u_regs[UREG_I2])
+#define PT_REGS_PARM4(x) ((x)->u_regs[UREG_I3])
+#define PT_REGS_PARM5(x) ((x)->u_regs[UREG_I4])
+#define PT_REGS_RET(x) ((x)->u_regs[UREG_I7])
+#define PT_REGS_RC(x) ((x)->u_regs[UREG_I0])
+#define PT_REGS_SP(x) ((x)->u_regs[UREG_FP])
+
+/* Should this also be a bpf_target check for the sparc case? */
+#if defined(__arch64__)
+#define PT_REGS_IP(x) ((x)->tpc)
+#else
+#define PT_REGS_IP(x) ((x)->pc)
+#endif
+
+#endif
+
+#ifdef bpf_target_powerpc
+#define BPF_KPROBE_READ_RET_IP(ip, ctx)		({ (ip) = (ctx)->link; })
+#define BPF_KRETPROBE_READ_RET_IP		BPF_KPROBE_READ_RET_IP
+#elif bpf_target_sparc
+#define BPF_KPROBE_READ_RET_IP(ip, ctx)		({ (ip) = PT_REGS_RET(ctx); })
+#define BPF_KRETPROBE_READ_RET_IP		BPF_KPROBE_READ_RET_IP
+#else
+#define BPF_KPROBE_READ_RET_IP(ip, ctx)		({				\
+		bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); })
+#define BPF_KRETPROBE_READ_RET_IP(ip, ctx)	({				\
+		bpf_probe_read(&(ip), sizeof(ip),				\
+				(void *)(PT_REGS_FP(ctx) + sizeof(ip))); })
+#endif
+
+#endif
tools/perf/util/bpf-userapi.h new file +11 -0
new file mode 100644
index 000000000000..63f2b4c13a5c
@@ -0,0 +1,11 @@
+#ifndef __BPF_USERAPI_H
+#define __BPF_USERAPI_H
+
+enum {
+	BPF_FUNC_USER_START			= 10000,
+	BPF_FUNC_USER_print			= BPF_FUNC_USER_START,
+	BPF_FUNC_USER_bpf_map_get_next_key,
+	BPF_FUNC_USER_bpf_map_lookup_elem,
+};
+
+#endif /* __BPF_USERFUNCS_H */
tools/perf/util/bpf-userfuncs.h new file +19 -0
new file mode 100644
index 000000000000..e920420237ee
@@ -0,0 +1,19 @@
+#ifndef __BPF_USERFUNCS_H
+#define __BPF_USERFUNCS_H
+
+#include <bpf-userapi.h>
+
+static int (*bpfu_print)(const char *fmt, ...) =
+	(void *) BPF_FUNC_USER_print;
+static int (*bpfu_map_get_next_key)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_get_next_key;
+static int (*bpfu_map_lookup_elem)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_lookup_elem;
+
+#define print(fmt, ...)                                  \
+({                                                       \
+	char ____fmt[] = fmt;                            \
+	bpfu_print(____fmt, ##__VA_ARGS__);              \
+})
+
+#endif /* __BPF_USERFUNCS_H */
Signature · 1 line
2.13.6
#16 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

Quoted 30 lines · Jiri Olsa
tools/perf/util/bpf-userapi.h new file +11 -0
new file mode 100644
index 000000000000..63f2b4c13a5c
@@ -0,0 +1,11 @@
+#ifndef __BPF_USERAPI_H
+#define __BPF_USERAPI_H
+
+enum {
+	BPF_FUNC_USER_START			= 10000,
+	BPF_FUNC_USER_print			= BPF_FUNC_USER_START,
+	BPF_FUNC_USER_bpf_map_get_next_key,
+	BPF_FUNC_USER_bpf_map_lookup_elem,
+};
+
+#endif /* __BPF_USERFUNCS_H */
tools/perf/util/bpf-userfuncs.h new file +7 -0
new file mode 100644
index 000000000000..e920420237ee
@@ -0,0 +1,19 @@
+#ifndef __BPF_USERFUNCS_H
+#define __BPF_USERFUNCS_H
+
+#include <bpf-userapi.h>
+
+static int (*bpfu_print)(const char *fmt, ...) =
+	(void *) BPF_FUNC_USER_print;

tools/perf/util/bpf-userfuncs.h line 17

Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10 -0
+static int (*bpfu_map_get_next_key)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_get_next_key;
+static int (*bpfu_map_lookup_elem)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_lookup_elem;
+
+#define print(fmt, ...)                                  \
+({                                                       \
+	char ____fmt[] = fmt;                            \
+	bpfu_print(____fmt, ##__VA_ARGS__);              \
+})

since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call. llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will see bpf_call into normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and let call_cb do the call. I think this way begin/end will be much more powerful and useful. Potentially allowing some of the bcc scripts to be written this way.

#17 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

Em Mon, Mar 12, 2018 at 11:44:57AM -0700, Alexei Starovoitov escreveu:

Quoted 44 lines · Jiri Olsa
Quoted 30 lines
tools/perf/util/bpf-userapi.h new file +11 -0
new file mode 100644
index 000000000000..63f2b4c13a5c
@@ -0,0 +1,11 @@
+#ifndef __BPF_USERAPI_H
+#define __BPF_USERAPI_H
+
+enum {
+	BPF_FUNC_USER_START			= 10000,
+	BPF_FUNC_USER_print			= BPF_FUNC_USER_START,
+	BPF_FUNC_USER_bpf_map_get_next_key,
+	BPF_FUNC_USER_bpf_map_lookup_elem,
+};
+
+#endif /* __BPF_USERFUNCS_H */
tools/perf/util/bpf-userfuncs.h new file +7 -0
new file mode 100644
index 000000000000..e920420237ee
@@ -0,0 +1,19 @@
+#ifndef __BPF_USERFUNCS_H
+#define __BPF_USERFUNCS_H
+
+#include <bpf-userapi.h>
+
+static int (*bpfu_print)(const char *fmt, ...) =
+	(void *) BPF_FUNC_USER_print;

tools/perf/util/bpf-userfuncs.h line 17

Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10 -0
+static int (*bpfu_map_get_next_key)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_get_next_key;
+static int (*bpfu_map_lookup_elem)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_lookup_elem;
+
+#define print(fmt, ...)                                  \
+({                                                       \
+	char ____fmt[] = fmt;                            \
+	bpfu_print(____fmt, ##__VA_ARGS__);              \
+})

since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call.

Quoted 8 lines

llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will see bpf_call into normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and let call_cb do the call. I think this way begin/end will be much more powerful and useful. Potentially allowing some of the bcc scripts to be written this way.

Yeah, what is in perf right now, i.e. symbol resolution, rbtree, etc provides a really nice lib for use in these scripts.

- Arnaldo

#18 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

In reply to Alexei Starovoitov
Quoted 42 lines · Alexei Starovoitov
Quoted 30 lines · Jiri Olsa
tools/perf/util/bpf-userapi.h new file +11 -0
new file mode 100644
index 000000000000..63f2b4c13a5c
@@ -0,0 +1,11 @@
+#ifndef __BPF_USERAPI_H
+#define __BPF_USERAPI_H
+
+enum {
+	BPF_FUNC_USER_START			= 10000,
+	BPF_FUNC_USER_print			= BPF_FUNC_USER_START,
+	BPF_FUNC_USER_bpf_map_get_next_key,
+	BPF_FUNC_USER_bpf_map_lookup_elem,
+};
+
+#endif /* __BPF_USERFUNCS_H */
tools/perf/util/bpf-userfuncs.h new file +7 -0
new file mode 100644
index 000000000000..e920420237ee
@@ -0,0 +1,19 @@
+#ifndef __BPF_USERFUNCS_H
+#define __BPF_USERFUNCS_H
+
+#include <bpf-userapi.h>
+
+static int (*bpfu_print)(const char *fmt, ...) =
+	(void *) BPF_FUNC_USER_print;

tools/perf/util/bpf-userfuncs.h line 17

Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10 -0
+static int (*bpfu_map_get_next_key)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_get_next_key;
+static int (*bpfu_map_lookup_elem)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_lookup_elem;
+
+#define print(fmt, ...)                                  \
+({                                                       \
+	char ____fmt[] = fmt;                            \
+	bpfu_print(____fmt, ##__VA_ARGS__);              \
+})
Quoted 8 lines

since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call. llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will see bpf_call into normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and let call_cb do the call.

right, I kept this way, because it was already there for kernel, so it was fast to write ;-)

but it's true we could leave it symbol based and have some sort of dynamic loader behaviour.. but we'd need to sort out passing the arguments in some generic form.. I'll check on that

thanks,
jirka

Quoted 3 lines

I think this way begin/end will be much more powerful and useful. Potentially allowing some of the bcc scripts to be written this way.

#19 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

Em Mon, Mar 12, 2018 at 08:20:20PM +0100, Jiri Olsa escreveu:

Quoted 52 lines · Alexei Starovoitov
Quoted 42 lines · Jiri Olsa
Quoted 30 lines
tools/perf/util/bpf-userapi.h new file +11 -0
new file mode 100644
index 000000000000..63f2b4c13a5c
@@ -0,0 +1,11 @@
+#ifndef __BPF_USERAPI_H
+#define __BPF_USERAPI_H
+
+enum {
+	BPF_FUNC_USER_START			= 10000,
+	BPF_FUNC_USER_print			= BPF_FUNC_USER_START,
+	BPF_FUNC_USER_bpf_map_get_next_key,
+	BPF_FUNC_USER_bpf_map_lookup_elem,
+};
+
+#endif /* __BPF_USERFUNCS_H */
tools/perf/util/bpf-userfuncs.h new file +7 -0
new file mode 100644
index 000000000000..e920420237ee
@@ -0,0 +1,19 @@
+#ifndef __BPF_USERFUNCS_H
+#define __BPF_USERFUNCS_H
+
+#include <bpf-userapi.h>
+
+static int (*bpfu_print)(const char *fmt, ...) =
+	(void *) BPF_FUNC_USER_print;

tools/perf/util/bpf-userfuncs.h line 17

Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10 -0
+static int (*bpfu_map_get_next_key)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_get_next_key;
+static int (*bpfu_map_lookup_elem)(void *map, void *key, void *value) =
+	(void *) BPF_FUNC_USER_bpf_map_lookup_elem;
+
+#define print(fmt, ...)                                  \
+({                                                       \
+	char ____fmt[] = fmt;                            \
+	bpfu_print(____fmt, ##__VA_ARGS__);              \
+})
Quoted 8 lines

since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call. llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will see bpf_call into normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and let call_cb do the call.

Quoted 6 lines

right, I kept this way, because it was already there for kernel, so it was fast to write ;-)

but it's true we could leave it symbol based and have some sort of dynamic loader behaviour.. but we'd need to sort out passing the arguments in some generic form.. I'll check on that

Does this answer it or am I missing something?

Documentation/bpf/bpf_design_QA.txt

Q: Is BPF a generic virtual machine ?
A: NO.

BPF is generic instruction set _with_ C calling convention.

Q: Why C calling convention was chosen?
A: Because BPF programs are designed to run in the linux kernel
which is written in C, hence BPF defines instruction set compatible with two most used architectures x64 and arm64 (and takes into consideration important quirks of other architectures) and defines calling convention that is compatible with C calling convention of the linux kernel on those architectures.

- Arnaldo

#20 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

On Mon, Mar 12, 2018 at 04:25:51PM -0300, Arnaldo Carvalho de Melo wrote:

SNIP

Quoted 17 lines
Quoted 7 lines

right, I kept this way, because it was already there for kernel, so it was fast to write ;-)

but it's true we could leave it symbol based and have some sort of dynamic loader behaviour.. but we'd need to sort out passing the arguments in some generic form.. I'll check on that

Does this answer it or am I missing something?

Documentation/bpf/bpf_design_QA.txt

Q: Is BPF a generic virtual machine ?
A: NO.

BPF is generic instruction set _with_ C calling convention.

Quoted 7 lines

Q: Why C calling convention was chosen?
A: Because BPF programs are designed to run in the linux kernel
which is written in C, hence BPF defines instruction set compatible with two most used architectures x64 and arm64 (and takes into consideration important quirks of other architectures) and defines calling convention that is compatible with C calling convention of the linux kernel on those architectures.

hm right, but still we interpret the calls.. so we have to call the function at the end

jirka

#21 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

In reply to Jiri Olsa

Em Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa escreveu:

tools/perf/util/bpf-helpers.h line 137

Quoted 2 lines
tools/perf/util/bpf-helpers.h new file +2 -0
+#elif defined(__s390x__)
+	#define bpf_target_s930x
    bpf_target_s390x
Quoted 10 lines
tools/perf/util/bpf-helpers.h new file +10 -0
+#elif defined(__aarch64__)
+	#define bpf_target_arm64
+#elif defined(__mips__)
+	#define bpf_target_mips
+#elif defined(__powerpc__)
+	#define bpf_target_powerpc
+#elif defined(__sparc__)
+	#define bpf_target_sparc
+#endif
+#endif
#22 lore raw

Re: [PATCH 11/13] perf bpf: Add helper header files

Quoted 5 lines · Arnaldo Carvalho de Melo

Em Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa escreveu:

tools/perf/util/bpf-helpers.h line 137

Quoted 2 lines
tools/perf/util/bpf-helpers.h new file +2 -0
+#elif defined(__s390x__)
+	#define bpf_target_s930x
    bpf_target_s390x

eagle eyes ;-) must be problem in samples/bpf where I stoled it from ;-)

thanks,
jirka

Quoted 11 lines
Quoted 11 lines
tools/perf/util/bpf-helpers.h new file +10 -0
+#elif defined(__aarch64__)
+	#define bpf_target_arm64
+#elif defined(__mips__)
+	#define bpf_target_mips
+#elif defined(__powerpc__)
+	#define bpf_target_powerpc
+#elif defined(__sparc__)
+	#define bpf_target_sparc
+#endif
+#endif
author reviewer
#23 lore raw

PATCH 12/13 perf bpf: Run begin/end programs

In reply to Jiri Olsa

Running begin and end programs for ebpf object.

---
 tools/perf/builtin-bpf.c     |  6 ++++
 tools/perf/util/bpf-loader.c | 78 ++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.h |  2 ++
 3 files changed, 86 insertions(+)
tools/perf/builtin-bpf.c +6 -0
index 7065153a9577..1111e240e259 100644
@@ -94,6 +94,10 @@ static int __cmd_bpf(int argc , const char **argv)
 		goto out_child;
 	}
 
+	err = bpf__run_begin(stdout);
+	if (err)
+		goto out_child;
+
 	if (forks) {
 		perf_evlist__start_workload(bpf.evlist);
 
@@ -115,6 +119,8 @@ static int __cmd_bpf(int argc , const char **argv)
 
 	child_pid = -1;
 
+	bpf__run_end(stdout);
+
 out_child:
 	if (forks) {
                 if (workload_exec_errno) {
tools/perf/util/bpf-loader.c +78 -0

96 lines not on this page · raw message

tools/perf/util/bpf-loader.h +2 -0
index 8c2a494cab53..1ee4c3ca4927 100644
@@ -87,6 +87,8 @@ int bpf__setup_stdout(struct perf_evlist *evlist);
 int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err,
 			       char *buf, size_t size);
 
+int bpf__run_begin(FILE *out);
+int bpf__run_end(FILE *out);
 #else
 #include <errno.h>
 
Signature · 1 line
2.13.6
author reviewer
#24 lore raw

PATCH 13/13 perf samples: Add syscall-count.c object

In reply to Jiri Olsa

Adding syscall-count.c sample, that generates
syscall entry calls, like:

  $ perf bpf -c samples/syscall-counts.c
  LLVM: dumping samples/syscall-counts.o
  $ sudo perf bpf -e samples/syscall-counts.o -a
  BEGIN
  ^CEND
                comm            value
             firefox              182
       Socket Thread                8
     InotifyEventThr               26
     xmonad-x86_64-l              405
                perf            45122
     VoiceProcessThr               12
         JS Watchdog               14
     Chrome_~dThread              657
     Softwar~cThread              474
      Gecko_IOThread              489
         stalonetray                8
                mutt              410
                Xorg              956
               xchat               37
           nm-applet               14
        xscreensaver              170
               Timer             1205
      NetworkManager               25
        rtkit-daemon                4
     webrtc_audio_mo               24
         Web Content             6889
     IPDL Background              474
           JS Helper              221
             gkrellm              434
               xterm              528
         InputThread              793
---
 tools/perf/samples/syscall-counts.c | 61 +++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 tools/perf/samples/syscall-counts.c
tools/perf/samples/syscall-counts.c new file +61 -0
new file mode 100644
index 000000000000..e6de6c9fdb85
@@ -0,0 +1,61 @@
+#include <uapi/linux/bpf.h>
+#include <bpf-helpers.h>
+#include <bpf-userfuncs.h>
+
+#define TASK_COMM_LEN 16
+
+char _license[] SEC("license") = "GPL";
+int _version SEC("version") = LINUX_VERSION_CODE;
+
+struct key_t {
+	char comm[TASK_COMM_LEN];
+};
+
+struct bpf_map_def SEC("maps") counts_map = {
+	.type = BPF_MAP_TYPE_HASH,
+	.key_size = sizeof(struct key_t),
+	.value_size = sizeof(u64),
+	.max_entries = 100,
+};
+
+SEC("raw_syscalls:sys_enter")
+int func(void *ctx)
+{
+	u64 *val, one = 1;
+	struct key_t key;
+	char comm[TASK_COMM_LEN];
+
+	bpf_get_current_comm(&key.comm, sizeof(comm));
+
+	val = bpf_map_lookup_elem(&counts_map, &key);
+	if (val)
+		(*val)++;
+	else
+		bpf_map_update_elem(&counts_map, &key, &one, BPF_NOEXIST);
+
+	return 0;
+}
+
+int BEGIN(void)
+{
+	print("BEGIN\n");
+	return 0;
+}
+
+void END(void)
+{
+	struct key_t key = {}, next_key;
+	u64 value;
+	int i = 0;
+
+	print("END\n");
+	print("\n              comm            value\n");
+
+	while (bpfu_map_get_next_key(&counts_map, &key, &next_key) == 0) {
+                if (bpfu_map_lookup_elem(&counts_map, &next_key, &value))
+			continue;
+
+		print("%18s %16lu\n", next_key.comm, value);
+                key = next_key;
+        }
+}
Signature · 1 line
2.13.6
#25 lore raw
In reply to Jiri Olsa

adding Alexei and Wang to the loop

Quoted 172 lines · Jiri Olsa

hi,
this is *RFC* and the following patchset is very rough and ugly 'prove of concept'-kind-of-toy code. I'm mostly interested in opinions about if this could be useful in your current eBPF usage.

Currently we can load eBPF code within the record command and attach it to event. We have 2 ways of communicating the data back to user: bpf-output event that goes to perf.data or 'trace_printk' output in tracefs buffer.

AFAICS we're not covering quite large usage base that runs code before and once the probe is finished to setup, collect and display the collected data.

This patchset is adding support to run BEGIN and END code snipets before and after eBPF probe is loaded.

This allow to write 'collecting' code in eBPF object, like in the attached example (it's also part of the patchset).

This patchset also adds 'bpf' command to ease up the loading of eBPF files with options for compilation and disassembly of eBPF objects:

      $ perf bpf -c samples/syscall-counts.c
      LLVM: dumping samples/syscall-counts.o
      $ perf bpf -d samples/syscall-counts.o | head
      Disassembly of raw_syscalls:sys_enter:
         0: (b7) r1 = 1
             b7 01 00 00 01 00 00 00
         1: (7b) *(u64 *)(r10 -8) = r1
             7b 1a f8 ff 00 00 00 00
         2: (bf) r6 = r10
      ...
      $ sudo perf bpf -e samples/syscall-counts.o -a
      BEGIN
      ^CEND
                    comm            value
                 firefox              182
           Socket Thread                8
         InotifyEventThr               26
         xmonad-x86_64-l              405
      ...

The patchset is also available in here:
https://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/bpf

So far I need following following lines in .perfconfig to run this:
[llvm]
kbuild-dir=/home/jolsa/kernel/linux-perf clang-opt=-I/home/jolsa/kernel/linux-perf/tools/perf/util

thoughts? ;-) thanks,
jirka

Cc Brendan Gregg <[email protected]>
Cc Stanislav Kozina <[email protected]>
Cc "Frank Ch. Eigler" <[email protected]>
Cc Will Cohen <[email protected]>
Cc Eugene Syromiatnikov <[email protected]>
Cc Jerome Marchand <[email protected]>

---
#include <uapi/linux/bpf.h>
#include <bpf-helpers.h>
#include <bpf-userfuncs.h>

#define TASK_COMM_LEN 16

char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;

struct key_t {
        char comm[TASK_COMM_LEN];
};

struct bpf_map_def SEC("maps") counts_map = {
.type = BPF_MAP_TYPE_HASH,
.key_size = sizeof(struct key_t),
.value_size = sizeof(u64),
.max_entries = 100,
};

SEC("raw_syscalls:sys_enter")
int func(void *ctx)

{
        u64 *val, one = 1;
        struct key_t key;
        char comm[TASK_COMM_LEN];

        bpf_get_current_comm(&key.comm, sizeof(comm));

        val = bpf_map_lookup_elem(&counts_map, &key);
        if (val)
                (*val)++;
        else
                bpf_map_update_elem(&counts_map, &key, &one, BPF_NOEXIST);

        return 0;
}

int BEGIN(void)

{
        print("BEGIN\n");
        return 0;
}

void END(void)

{
        struct key_t key = {}, next_key;
        u64 value;
        int i = 0;

        print("END\n");
        print("\n              comm            value\n");

        while (bpfu_map_get_next_key(&counts_map, &key, &next_key) == 0) {
                if (bpfu_map_lookup_elem(&counts_map, &next_key, &value))
                        continue;

                print("%18s %16lu\n", next_key.comm, value);
                key = next_key;
        }
}

---
Jiri Olsa (13):
lib bpf: Add bpf_program__insns function
perf tools: Display ebpf compiling command in debug output perf tools: Add bpf command
perf tools: Add bpf__compile function
perf bpf: Add compile option
perf bpf: Add disasm option
libbpf: Make bpf_program__next skip .text section
libbpf: Collect begin/end .text functions
libbpf: Add bpf_insn__interpret function
libbpf: Add bpf_object__run_(begin|end) functions perf bpf: Add helper header files
perf bpf: Run begin/end programs
perf samples: Add syscall-count.c object

 tools/lib/bpf/Build                 |   2 +-
 tools/lib/bpf/interp.c              | 245 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.c              | 125 +++++++++++++++++++++++++++++++++++++++++++++++--
 tools/lib/bpf/libbpf.h              |   7 +++
 tools/perf/Build                    |   7 +++
 tools/perf/Makefile.config          |   1 +
 tools/perf/builtin-bpf.c            | 319 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/builtin.h                |   1 +
 tools/perf/command-list.txt         |   1 +
 tools/perf/perf.c                   |   1 +
 tools/perf/samples/syscall-counts.c |  61 ++++++++++++++++++++++++
 tools/perf/util/bpf-helpers.h       | 246 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 tools/perf/util/bpf-loader.c        | 124 ++++++++++++++++++++++++++++++++++++++++++++-----
 tools/perf/util/bpf-loader.h        |   4 ++
 tools/perf/util/bpf-userapi.h       |  11 +++++
 tools/perf/util/bpf-userfuncs.h     |  19 ++++++++
 tools/perf/util/llvm-utils.c        |  14 ++++++
 17 files changed, 1173 insertions(+), 15 deletions(-)
 create mode 100644 tools/lib/bpf/interp.c
 create mode 100644 tools/perf/builtin-bpf.c
 create mode 100644 tools/perf/samples/syscall-counts.c
 create mode 100644 tools/perf/util/bpf-helpers.h
 create mode 100644 tools/perf/util/bpf-userapi.h
 create mode 100644 tools/perf/util/bpf-userfuncs.h
#26 lore raw

Em Mon, Mar 12, 2018 at 12:17:05PM +0100, Jiri Olsa escreveu:

Quoted 20 lines

adding Alexei and Wang to the loop

Quoted 17 lines · Jiri Olsa

hi,
this is *RFC* and the following patchset is very rough and ugly 'prove of concept'-kind-of-toy code. I'm mostly interested in opinions about if this could be useful in your current eBPF usage.

Currently we can load eBPF code within the record command and attach it to event. We have 2 ways of communicating the data back to user: bpf-output event that goes to perf.data or 'trace_printk' output in tracefs buffer.

AFAICS we're not covering quite large usage base that runs code before and once the probe is finished to setup, collect and display the collected data.

This patchset is adding support to run BEGIN and END code snipets before and after eBPF probe is loaded.

Right, with all the code that Wang contributed, and reusing that begin/end code from systemtap, it was easy to do it, not that much code added, so I don't see a reason for this not to be merged.

On top of this patchset, I think that the restricted C code that is used to write the eBPF utilities should be simplified, I've toyed with this from time to time, for instance:

[root@jouet bpf]# cat o_cloexec.c
#include "bpf.h"
#include "stdio.h"

#define O_CLOEXEC 0x80000

int syscall_enter(openat)

{
	char filename[256];
	int flags = syscall_field_int(flags, 32);
	int len = syscall_field_str(filename, 24);

	if (!(flags & O_CLOEXEC))
		return 0;

	perf_stdout(filename, len);
	return 1;
}

[root@jouet bpf]# perf trace -e openat,o_cloexec.c

     0.573 (         ): __bpf_stdout__:/etc/ld.so.cache....)
     0.576 (         ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de411563, flags: 0x00080000, mode: 0x00000000)
     0.579 ( 0.013 ms): sh/17728 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC           ) = 3
     0.620 (         ): __bpf_stdout__:/lib64/libtinfo.so.6........)
     0.622 (         ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de619ce0, flags: 0x00080000, mode: 0x00000000)
     0.624 ( 0.013 ms): sh/17728 openat(dfd: CWD, filename: /lib64/libtinfo.so.6, flags: CLOEXEC       ) = 3
     0.705 (         ): __bpf_stdout__:/lib64/libdl.so.2...)
     0.708 (         ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de5ef4c0, flags: 0x00080000, mode: 0x00000000)
     0.710 ( 0.058 ms): sh/17728 openat(dfd: CWD, filename: /lib64/libdl.so.2, flags: CLOEXEC          ) = 3
     0.852 (         ): __bpf_stdout__:/lib64/libc.so.6....)
     0.857 (         ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de5ef9a0, flags: 0x00080000, mode: 0x00000000)
     0.860 ( 0.021 ms): sh/17728 openat(dfd: CWD, filename: /lib64/libc.so.6, flags: CLOEXEC           ) = 3

^C
[root@jouet bpf]#

Hiding details such as:

[root@jouet bpf]# cat stdio.h
struct bpf_map_def SEC("maps") __bpf_stdout__ = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = __NR_CPUS__,
};

#define perf_stdout(from, len) \
	perf_event_output(ctx, &__bpf_stdout__, BPF_F_CURRENT_CPU, \
			  &from, len & (sizeof(from) - 1));

[root@jouet bpf]#

That 'perf trace' will setup "bpf_output" event, etc.

And the other macros:

#define SEC(NAME) __attribute__((section(NAME), used))

#define pid_map(name, value_type) \

struct bpf_map_def SEC("maps") name = { \
        .type        = BPF_MAP_TYPE_HASH, \
        .key_size    = sizeof(u64), \
        .value_size  = sizeof(value_type), \
        .max_entries = 500, \
}

#define syscall_enter(name) \
SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name(void *ctx)

#define syscall_exit(name) \
SEC("syscalls:sys_exit_" #name) syscall_exit_ ## name(void *ctx)

#define syscall_field_str(field, offset) \
        ({ char *__ptr = *((char **)(ctx + offset)); \
           bpf_probe_read_str(field, sizeof(field), __ptr); })
#define syscall_field_int(field, offset) \
        ({ int *__ptr = (int *)(ctx + offset); \
           bpf_probe_read(&field, sizeof(field), __ptr); field; }

While this hides some of the details, it still hardcodes the offset, so should be used that way, I was trying to read about clang internals to do some preprocessing trick that would automagically make the tracepoint fields accessible as local variables, reading the tracepoint format files from the running system or from the description stored in the perf.data header, when running these things on perf.data files.

- Arnaldo