All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC 00/13] perf bpf: Add support to run BEGIN/END code
@ 2018-03-12  9:43 Jiri Olsa
  2018-03-12  9:43 ` [PATCH 01/13] lib bpf: Add bpf_program__insns function Jiri Olsa
                   ` (13 more replies)
  0 siblings, 14 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Brendan Gregg, Stanislav Kozina, Frank Ch. Eigler, Will Cohen,
	Eugene Syromiatnikov, Jerome Marchand, lkml, Ingo Molnar,
	Namhyung Kim, David Ahern, Alexander Shishkin, Peter Zijlstra

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 <bgregg@netflix.com>
Cc: Stanislav Kozina <skozina@redhat.com>
Cc: "Frank Ch. Eigler" <fche@redhat.com>
Cc: Will Cohen <wcohen@redhat.com>
Cc: Eugene Syromiatnikov <esyromia@redhat.com>
Cc: Jerome Marchand <jmarchan@redhat.com>

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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [PATCH 01/13] lib bpf: Add bpf_program__insns function
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 02/13] perf tools: Display ebpf compiling command in debug output Jiri Olsa
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-xvpbbusx8gie33kj0et5wx6l@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/libbpf.c | 7 +++++++
 tools/lib/bpf/libbpf.h | 3 +++
 2 files changed, 10 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 5bbbf285af74..6b9df10470e8 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -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;
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index f85906533cdd..bfc4d0411ec5 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -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.
  */
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 02/13] perf tools: Display ebpf compiling command in debug output
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
  2018-03-12  9:43 ` [PATCH 01/13] lib bpf: Add bpf_program__insns function Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12 14:24   ` Arnaldo Carvalho de Melo
  2018-03-20  6:29   ` [tip:perf/core] perf llvm: Display eBPF " tip-bot for Jiri Olsa
  2018-03-12  9:43 ` [PATCH 03/13] perf tools: Add bpf command Jiri Olsa
                   ` (11 subsequent siblings)
  13 siblings, 2 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-mygjr5z3c77x9ephks7n06oc@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/llvm-utils.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 4952b429caa7..1cca0a2fa641 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -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);
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 03/13] perf tools: Add bpf command
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
  2018-03-12  9:43 ` [PATCH 01/13] lib bpf: Add bpf_program__insns function Jiri Olsa
  2018-03-12  9:43 ` [PATCH 02/13] perf tools: Display ebpf compiling command in debug output Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 04/13] perf tools: Add bpf__compile function Jiri Olsa
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-51vi69jgn3nfa00azjlikfck@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 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

diff --git a/tools/perf/Build b/tools/perf/Build
index e5232d567611..7f521ac16466 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -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
diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
new file mode 100644
index 000000000000..6f02352caf79
--- /dev/null
+++ b/tools/perf/builtin-bpf.c
@@ -0,0 +1,199 @@
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+#include <time.h>
+#include <linux/compiler.h>
+#include <subcmd/parse-options.h>
+#include "builtin.h"
+#include "perf.h"
+#include "target.h"
+#include "debug.h"
+#include "parse-events.h"
+#include "evlist.h"
+#include "evsel.h"
+#include "bpf-loader.h"
+
+struct perf_bpf {
+	struct target		 target;
+	struct perf_evlist	*evlist;
+};
+
+struct perf_bpf bpf = {
+	.target = { .uid = UINT_MAX, },
+};
+
+static volatile int done;
+static volatile int workload_exec_errno;
+
+static void sig_handler(int sig __maybe_unused)
+{
+	done = 1;
+}
+
+/*
+ * perf_evlist__prepare_workload will send a SIGUSR1
+ * if the fork fails, since we asked by setting its
+ * want_signal to true.
+ */
+static void workload_exec_failed_signal(int signo __maybe_unused, siginfo_t *info,
+					void *ucontext __maybe_unused)
+{
+	workload_exec_errno = info->si_value.sival_int;
+}
+
+static int create_perf_bpf_counter(struct perf_evsel *evsel)
+{
+	if (target__has_cpu(&bpf.target) && !target__has_per_thread(&bpf.target))
+		return perf_evsel__open_per_cpu(evsel, perf_evsel__cpus(evsel));
+
+	return perf_evsel__open_per_thread(evsel, bpf.evlist->threads);
+}
+
+static int __cmd_bpf(int argc , const char **argv)
+{
+	struct perf_evsel *evsel;
+	bool forks = argc > 0;
+	int err, status;
+	int child_pid = -1;
+	char msg[BUFSIZ];
+	struct timespec ts = { .tv_sec = 0, .tv_nsec = 500 };
+
+	if (forks) {
+		err = perf_evlist__prepare_workload(bpf.evlist, &bpf.target,
+						    argv, true,
+						    workload_exec_failed_signal);
+		if (err < 0) {
+			pr_err("Couldn't run the workload!\n");
+			status = err;
+			goto out;
+		}
+
+		child_pid = bpf.evlist->workload.pid;
+	}
+
+        evlist__for_each_entry(bpf.evlist, evsel) {
+                err =create_perf_bpf_counter(evsel);
+		if (err < 0) {
+                        perf_evsel__open_strerror(evsel, &bpf.target,
+                                                  errno, msg, sizeof(msg));
+                        pr_err("%s\n", msg);
+			goto out_child;
+                }
+	}
+
+	err = bpf__apply_obj_config();
+	if (err) {
+		char errbuf[BUFSIZ];
+
+		bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
+					       pr_err("ERROR: Apply config to BPF failed: %s\n",
+					       errbuf);
+		goto out_child;
+	}
+
+	if (forks) {
+		perf_evlist__start_workload(bpf.evlist);
+
+		if (!target__none(&bpf.target))
+			perf_evlist__enable(bpf.evlist);
+
+                waitpid(child_pid, &status, 0);
+        } else {
+		if (!target__none(&bpf.target))
+			perf_evlist__enable(bpf.evlist);
+
+                while (!done) {
+                        nanosleep(&ts, NULL);
+                }
+        }
+
+	if (!target__none(&bpf.target))
+		perf_evlist__disable(bpf.evlist);
+
+	child_pid = -1;
+
+out_child:
+	if (forks) {
+                if (workload_exec_errno) {
+                        const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg));
+                        pr_err("Workload failed: %s\n", emsg);
+                        return -1;
+                }
+
+		if (child_pid != -1) {
+			kill(child_pid, SIGTERM);
+			waitpid(child_pid, &status, 0);
+		}
+
+                if (WIFSIGNALED(status))
+                        psignal(WTERMSIG(status), argv[0]);
+	}
+
+out:
+	perf_evlist__close(bpf.evlist);
+
+	if (err)
+		status = err;
+	return WEXITSTATUS(status);
+}
+
+int cmd_bpf(int argc, const char **argv)
+{
+	int err = -1;
+	const char * const bpf_usage[] = {
+		"perf bpf [<options>] [<command>]",
+		"perf bpf [<options>] -- <command> [<options>]",
+		NULL
+	};
+	const struct option bpf_options[] = {
+		OPT_CALLBACK('e', "event", &bpf.evlist, "event",
+			     "event selector. use 'perf list' to list available events",
+			     parse_events_option),
+		OPT_STRING('C', "cpu", &bpf.target.cpu_list, "cpu",
+			   "list of cpus to monitor"),
+		OPT_BOOLEAN('a', "all-cpus", &bpf.target.system_wide,
+			    "system-wide collection from all CPUs"),
+		OPT_STRING('p', "pid", &bpf.target.pid, "pid",
+			   "record events on existing process id"),
+		OPT_STRING('t', "tid", &bpf.target.tid, "tid",
+			   "record events on existing thread id"),
+		OPT_INCR('v', "verbose", &verbose,
+			 "be more verbose"),
+		OPT_END()
+	};
+
+	signal(SIGINT, sig_handler);
+
+	bpf.evlist = perf_evlist__new();
+	if (bpf.evlist == NULL)
+		return -ENOMEM;
+
+	argc = parse_options(argc, argv, bpf_options, bpf_usage,
+			     PARSE_OPT_STOP_AT_NON_OPTION);
+	if (!argc && target__none(&bpf.target))
+		usage_with_options(bpf_usage, bpf_options);
+
+	if (bpf.evlist->nr_entries == 0) {
+		pr_err("failed: No event specified\n");
+		goto out;
+	}
+
+	if (perf_evlist__create_maps(bpf.evlist, &bpf.target) < 0) {
+		if (target__has_task(&bpf.target)) {
+			pr_err("Problems finding threads of monitor\n");
+			parse_options_usage(bpf_usage, bpf_options, "p", 1);
+			parse_options_usage(NULL, bpf_options, "t", 1);
+		} else if (target__has_cpu(&bpf.target)) {
+			perror("failed to parse CPUs map");
+			parse_options_usage(bpf_usage, bpf_options, "C", 1);
+			parse_options_usage(NULL, bpf_options, "a", 1);
+		}
+	}
+
+	target__validate(&bpf.target);
+
+	err = __cmd_bpf(argc, argv);
+out:
+	perf_evlist__delete(bpf.evlist);
+	return err;
+}
diff --git a/tools/perf/builtin.h b/tools/perf/builtin.h
index 05745f3ce912..1805c65f4d01 100644
--- a/tools/perf/builtin.h
+++ b/tools/perf/builtin.h
@@ -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
diff --git a/tools/perf/command-list.txt b/tools/perf/command-list.txt
index 2d0caf20ff3a..4e8e398d4f45 100644
--- a/tools/perf/command-list.txt
+++ b/tools/perf/command-list.txt
@@ -30,3 +30,4 @@ perf-test			mainporcelain common
 perf-timechart			mainporcelain common
 perf-top			mainporcelain common
 perf-trace			mainporcelain audit
+perf-bpf			mainporcelain common
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 1b3fc8ec0fa2..144cf71af0f7 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -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 {
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 04/13] perf tools: Add bpf__compile function
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (2 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 03/13] perf tools: Add bpf command Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 05/13] perf bpf: Add compile option Jiri Olsa
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

Adding bpf__compile function to have interface for
ebpf object compilation.

Link: http://lkml.kernel.org/n/tip-3kus9vjbiven8par9j1ju9u5@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/util/bpf-loader.c | 46 +++++++++++++++++++++++++++++++++-----------
 tools/perf/util/bpf-loader.h |  2 ++
 2 files changed, 37 insertions(+), 11 deletions(-)

diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index af7ad814b2c3..e59168153375 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -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)
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 5d3aefd6fae7..8c2a494cab53 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -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);
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 05/13] perf bpf: Add compile option
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (3 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 04/13] perf tools: Add bpf__compile function Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 06/13] perf bpf: Add disasm option Jiri Olsa
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

  $ perf bpf -c samples/syscall-counts.c
  LLVM: dumping samples/syscall-counts.o

Link: http://lkml.kernel.org/n/tip-w48lyepbrde7no35sxi2vtxh@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/builtin-bpf.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
index 6f02352caf79..1ae93fd01a97 100644
--- a/tools/perf/builtin-bpf.c
+++ b/tools/perf/builtin-bpf.c
@@ -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);
 
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 06/13] perf bpf: Add disasm option
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (4 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 05/13] perf bpf: Add compile option Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 07/13] libbpf: Make bpf_program__next skip .text section Jiri Olsa
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-djopq2e6ajsg9h90hb9iuat3@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/Build           |   6 +++
 tools/perf/Makefile.config |   1 +
 tools/perf/builtin-bpf.c   | 107 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 114 insertions(+)

diff --git a/tools/perf/Build b/tools/perf/Build
index 7f521ac16466..0585fd3715d0 100644
--- a/tools/perf/Build
+++ b/tools/perf/Build
@@ -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)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 98ff73648b51..575910cebb57 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -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)
diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
index 1ae93fd01a97..7065153a9577 100644
--- a/tools/perf/builtin-bpf.c
+++ b/tools/perf/builtin-bpf.c
@@ -4,6 +4,8 @@
 #include <time.h>
 #include <linux/compiler.h>
 #include <subcmd/parse-options.h>
+#include <bpf/bpf.h>
+#include <bpf/libbpf.h>
 #include "builtin.h"
 #include "perf.h"
 #include "target.h"
@@ -12,6 +14,7 @@
 #include "evlist.h"
 #include "evsel.h"
 #include "bpf-loader.h"
+#include "disasm.h"
 
 struct perf_bpf {
 	struct target		 target;
@@ -137,6 +140,104 @@ static int __cmd_bpf(int argc , const char **argv)
 	return WEXITSTATUS(status);
 }
 
+static void print_insn(struct bpf_verifier_env *env __maybe_unused, const char *fmt, ...)
+{
+	va_list args;
+
+	va_start(args, fmt);
+	vprintf(fmt, args);
+	va_end(args);
+}
+
+static const char *print_call(void *private_data __maybe_unused,
+			      const struct bpf_insn *insn __maybe_unused)
+{
+	return NULL;
+}
+
+static const char *print_imm(void *private_data __maybe_unused,
+			     const struct bpf_insn *insn __maybe_unused,
+			     __u64 full_imm __maybe_unused)
+{
+	return NULL;
+}
+
+static void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
+{
+	unsigned char *data = arg;
+	unsigned int i;
+
+	for (i = 0; i < n; i++) {
+		const char *pfx = "";
+
+		if (!i)
+			/* nothing */;
+		else if (!(i % 16))
+			fprintf(f, "\n");
+		else if (!(i % 8))
+			fprintf(f, "  ");
+		else
+			pfx = sep;
+
+		fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
+	}
+}
+
+static int disasm_fprintf(FILE *out, const char *filename, bool opcodes)
+{
+	const struct bpf_insn_cbs cbs = {
+		.cb_print       = print_insn,
+		.cb_call        = print_call,
+		.cb_imm         = print_imm,
+		.private_data   = NULL,
+	};
+	bool double_insn = false;
+	struct bpf_program *prog;
+	struct bpf_object *obj;
+	int i;
+
+	obj = bpf__prepare_load(filename, false);
+	if (IS_ERR(obj))
+		return -1;
+
+	bpf_object__for_each_program(prog, obj) {
+		struct bpf_insn *insn;
+		int insns_cnt;
+
+		fprintf(out, "Disassembly of %s:\n", bpf_program__title(prog, false));
+
+		insn = bpf_program__insns(prog, &insns_cnt);
+		if (!insn) {
+			pr_err("failed: NULL instructions\n");
+			return -1;
+		}
+
+		for (i = 0; i < (int) insns_cnt; i++) {
+			if (double_insn) {
+				double_insn = false;
+				continue;
+			}
+
+			double_insn = insn[i].code == (BPF_LD | BPF_IMM | BPF_DW);
+
+			printf("% 4d: ", i);
+			print_bpf_insn(&cbs, NULL, insn + i, true);
+
+			if (opcodes) {
+				printf("       ");
+				fprint_hex(stdout, insn + i, 8, " ");
+				if (double_insn && i < (int) (insns_cnt*sizeof(*insn)) - 1) {
+					printf(" ");
+					fprint_hex(stdout, insn + i + 1, 8, " ");
+				}
+				printf("\n");
+			}
+		}
+	}
+
+	return 0;
+}
+
 int cmd_bpf(int argc, const char **argv)
 {
 	int err = -1;
@@ -146,6 +247,7 @@ int cmd_bpf(int argc, const char **argv)
 		NULL
 	};
 	const char *compile_src = NULL;
+	const char *disasm_obj = NULL;
 	const struct option bpf_options[] = {
 		OPT_CALLBACK('e', "event", &bpf.evlist, "event",
 			     "event selector. use 'perf list' to list available events",
@@ -162,6 +264,8 @@ int cmd_bpf(int argc, const char **argv)
 			 "be more verbose"),
 		OPT_STRING('c', "compile", &compile_src, "eBPF source",
 			   "compile eBPF object"),
+		OPT_STRING('d', "disasm", &disasm_obj, "eBPF object",
+			   "disasm eBPF object"),
 		OPT_END()
 	};
 
@@ -177,6 +281,9 @@ int cmd_bpf(int argc, const char **argv)
 	if (compile_src)
 		return bpf__compile(compile_src);
 
+	if (disasm_obj)
+		return disasm_fprintf(stdout, disasm_obj, true);
+
 	if (!argc && target__none(&bpf.target))
 		usage_with_options(bpf_usage, bpf_options);
 
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 07/13] libbpf: Make bpf_program__next skip .text section
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (5 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 06/13] perf bpf: Add disasm option Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 08/13] libbpf: Collect begin/end .text functions Jiri Olsa
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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.

Link: http://lkml.kernel.org/n/tip-lcftc9k0fby5b5g2o0lhum8x@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/libbpf.c | 18 +++++++++++++++---
 1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 6b9df10470e8..07a6d8f5e5ab 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -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];
 }
 
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 08/13] libbpf: Collect begin/end .text functions
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (6 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 07/13] libbpf: Make bpf_program__next skip .text section Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 09/13] libbpf: Add bpf_insn__interpret function Jiri Olsa
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-hj1hwb7fshdwco706j22ela3@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/libbpf.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 07a6d8f5e5ab..26231e278bb8 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -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;
 }
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 09/13] libbpf: Add bpf_insn__interpret function
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (7 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 08/13] libbpf: Collect begin/end .text functions Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12 15:44   ` Arnaldo Carvalho de Melo
  2018-03-12  9:43 ` [PATCH 10/13] libbpf: Add bpf_object__run_(begin|end) functions Jiri Olsa
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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.

Link: http://lkml.kernel.org/n/tip-qqxsyw6imdisj3dydd6e21y7@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 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

diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build
index 64c679d67109..af99109f3d2d 100644
--- a/tools/lib/bpf/Build
+++ b/tools/lib/bpf/Build
@@ -1 +1 @@
-libbpf-y := libbpf.o bpf.o nlattr.o
+libbpf-y := libbpf.o bpf.o nlattr.o interp.o
diff --git a/tools/lib/bpf/interp.c b/tools/lib/bpf/interp.c
new file mode 100644
index 000000000000..2ceb6a0836c3
--- /dev/null
+++ b/tools/lib/bpf/interp.c
@@ -0,0 +1,245 @@
+#include <uapi/linux/bpf.h>
+#include <stdlib.h>
+#include "interp.h"
+
+u64 bpf_interp__run(struct bpf_interp *interp)
+{
+	const struct bpf_insn *i = interp->insns + interp->insns_start;
+	u64 stack[512 / 8];
+	u64 regs[MAX_BPF_REG];
+
+	regs[BPF_REG_10] = (uintptr_t)stack + sizeof(stack);
+
+	while ((size_t)(i - interp->insns) < interp->insns_cnt) {
+		u64 dr, sr, si, s1;
+
+		dr = regs[i->dst_reg];
+		sr = regs[i->src_reg];
+		si = i->imm;
+		s1 = i->code & BPF_X ? sr : si;
+
+		switch (i->code) {
+		case BPF_LDX | BPF_MEM | BPF_B:
+			dr = *(u8 *)((uintptr_t) sr + i->off);
+			break;
+		case BPF_LDX | BPF_MEM | BPF_H:
+			dr = *(u16 *)((uintptr_t) sr + i->off);
+			break;
+		case BPF_LDX | BPF_MEM | BPF_W:
+			dr = *(u32 *)((uintptr_t) sr + i->off);
+			break;
+		case BPF_LDX | BPF_MEM | BPF_DW:
+			dr = *(u64 *)((uintptr_t) sr + i->off);
+			break;
+		case BPF_ST | BPF_MEM | BPF_B:
+			sr = si;
+			/* Fallthrough */
+		case BPF_STX | BPF_MEM | BPF_B:
+			*(u8 *)((uintptr_t) dr + i->off) = sr;
+			goto nowrite;
+		case BPF_ST | BPF_MEM | BPF_H:
+			sr = si;
+			/* Fallthrough */
+		case BPF_STX | BPF_MEM | BPF_H:
+			*(u16 *)((uintptr_t) dr + i->off) = sr;
+			goto nowrite;
+		case BPF_ST | BPF_MEM | BPF_W:
+			sr = si;
+			/* Fallthrough */
+		case BPF_STX | BPF_MEM | BPF_W:
+			*(u32 *)((uintptr_t) dr + i->off) = sr;
+			goto nowrite;
+		case BPF_ST | BPF_MEM | BPF_DW:
+			sr = si;
+			/* Fallthrough */
+		case BPF_STX | BPF_MEM | BPF_DW:
+			*(u64 *)((uintptr_t) dr + i->off) = sr;
+			goto nowrite;
+
+		case BPF_ALU64 | BPF_ADD | BPF_X:
+		case BPF_ALU64 | BPF_ADD | BPF_K:
+			dr += s1;
+			break;
+		case BPF_ALU64 | BPF_SUB | BPF_X:
+		case BPF_ALU64 | BPF_SUB | BPF_K:
+			dr -= s1;
+			break;
+		case BPF_ALU64 | BPF_AND | BPF_X:
+		case BPF_ALU64 | BPF_AND | BPF_K:
+			dr &= s1;
+			break;
+		case BPF_ALU64 | BPF_OR  | BPF_X:
+		case BPF_ALU64 | BPF_OR  | BPF_K:
+			dr |= s1;
+			break;
+		case BPF_ALU64 | BPF_LSH | BPF_X:
+		case BPF_ALU64 | BPF_LSH | BPF_K:
+			dr <<= s1;
+			break;
+		case BPF_ALU64 | BPF_RSH | BPF_X:
+		case BPF_ALU64 | BPF_RSH | BPF_K:
+			dr >>= s1;
+			break;
+		case BPF_ALU64 | BPF_XOR | BPF_X:
+		case BPF_ALU64 | BPF_XOR | BPF_K:
+			dr ^= s1;
+			break;
+		case BPF_ALU64 | BPF_MUL | BPF_X:
+		case BPF_ALU64 | BPF_MUL | BPF_K:
+			dr *= s1;
+			break;
+		case BPF_ALU64 | BPF_MOV | BPF_X:
+		case BPF_ALU64 | BPF_MOV | BPF_K:
+			dr = s1;
+			break;
+		case BPF_ALU64 | BPF_ARSH | BPF_X:
+		case BPF_ALU64 | BPF_ARSH | BPF_K:
+			dr = (u64) dr >> s1;
+			break;
+		case BPF_ALU64 | BPF_NEG:
+			dr = -sr;
+			/* Fallthrough */
+		case BPF_ALU64 | BPF_DIV | BPF_X:
+		case BPF_ALU64 | BPF_DIV | BPF_K:
+			if (s1 == 0)
+				return 0;
+			dr /= s1;
+			break;
+		case BPF_ALU64 | BPF_MOD | BPF_X:
+		case BPF_ALU64 | BPF_MOD | BPF_K:
+			if (s1 == 0)
+				return 0;
+			dr %= s1;
+			break;
+
+		case BPF_ALU | BPF_ADD | BPF_X:
+		case BPF_ALU | BPF_ADD | BPF_K:
+			dr = (u32)(dr + s1);
+			break;
+		case BPF_ALU | BPF_SUB | BPF_X:
+		case BPF_ALU | BPF_SUB | BPF_K:
+			dr = (u32)(dr - s1);
+			break;
+		case BPF_ALU | BPF_AND | BPF_X:
+		case BPF_ALU | BPF_AND | BPF_K:
+			dr = (u32)(dr & s1);
+			break;
+		case BPF_ALU | BPF_OR  | BPF_X:
+		case BPF_ALU | BPF_OR  | BPF_K:
+			dr = (u32)(dr | s1);
+			break;
+		case BPF_ALU | BPF_LSH | BPF_X:
+		case BPF_ALU | BPF_LSH | BPF_K:
+			dr = (u32)dr << s1;
+			break;
+		case BPF_ALU | BPF_RSH | BPF_X:
+		case BPF_ALU | BPF_RSH | BPF_K:
+			dr = (u32)dr >> s1;
+			break;
+		case BPF_ALU | BPF_XOR | BPF_X:
+		case BPF_ALU | BPF_XOR | BPF_K:
+			dr = (u32)(dr ^ s1);
+			break;
+		case BPF_ALU | BPF_MUL | BPF_X:
+		case BPF_ALU | BPF_MUL | BPF_K:
+			dr = (u32)(dr * s1);
+			break;
+		case BPF_ALU | BPF_MOV | BPF_X:
+		case BPF_ALU | BPF_MOV | BPF_K:
+			dr = (u32)s1;
+			break;
+		case BPF_ALU | BPF_ARSH | BPF_X:
+		case BPF_ALU | BPF_ARSH | BPF_K:
+			dr = (u32)dr >> s1;
+			break;
+		case BPF_ALU | BPF_NEG:
+			dr = -(u32)sr;
+			/* Fallthrough */
+		case BPF_ALU | BPF_DIV | BPF_X:
+		case BPF_ALU | BPF_DIV | BPF_K:
+			if ((u32)s1 == 0)
+				return 0;
+			dr = (u32)dr / (u32)s1;
+			break;
+		case BPF_ALU | BPF_MOD | BPF_X:
+		case BPF_ALU | BPF_MOD | BPF_K:
+			if ((u32)s1 == 0)
+				return 0;
+			dr = (u32)dr % (u32)s1;
+			break;
+
+		case BPF_LD | BPF_IMM | BPF_DW:
+			switch (i->src_reg) {
+			case 0:
+				dr = (u32)si | ((u64 )i[1].imm << 32);
+				break;
+			case BPF_PSEUDO_MAP_FD:
+				dr = (u64) si;
+				break;
+			default:
+				abort();
+			}
+			regs[i->dst_reg] = dr;
+			i += 2;
+			continue;
+
+		case BPF_JMP | BPF_JEQ | BPF_X:
+		case BPF_JMP | BPF_JEQ | BPF_K:
+			if (dr == s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JNE | BPF_X:
+		case BPF_JMP | BPF_JNE | BPF_K:
+			if (dr != s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JGT | BPF_X:
+		case BPF_JMP | BPF_JGT | BPF_K:
+			if (dr > s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JGE | BPF_X:
+		case BPF_JMP | BPF_JGE | BPF_K:
+			if (dr >= s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JSGT | BPF_X:
+		case BPF_JMP | BPF_JSGT | BPF_K:
+			if ((u64) dr > (u64) s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JSGE | BPF_X:
+		case BPF_JMP | BPF_JSGE | BPF_K:
+			if ((u64) dr >= (u64) s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JSET | BPF_X:
+		case BPF_JMP | BPF_JSET | BPF_K:
+			if (dr & s1)
+				goto dojmp;
+			goto nowrite;
+		case BPF_JMP | BPF_JA:
+		dojmp:
+			i += 1 + i->off;
+			continue;
+
+		case BPF_JMP | BPF_CALL:
+			if (interp->call_cb(interp, si, regs))
+				return (u64) -1;
+
+			goto nowrite;
+
+		case BPF_JMP | BPF_EXIT:
+			return regs[0];
+
+		default:
+			abort();
+		}
+
+		regs[i->dst_reg] = dr;
+	nowrite:
+		i++;
+	}
+
+	return 0;
+}
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 10/13] libbpf: Add bpf_object__run_(begin|end) functions
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (8 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 09/13] libbpf: Add bpf_insn__interpret function Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 11/13] perf bpf: Add helper header files Jiri Olsa
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-hj1hwb7fshdwco706j22ela3@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/lib/bpf/libbpf.c | 30 ++++++++++++++++++++++++++++++
 tools/lib/bpf/libbpf.h |  4 ++++
 2 files changed, 34 insertions(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 26231e278bb8..f1f999d64d6a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -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);
+}
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index bfc4d0411ec5..8ac4d4efcc1b 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -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;				\
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (9 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 10/13] libbpf: Add bpf_object__run_(begin|end) functions Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12 18:44   ` Alexei Starovoitov
  2018-03-13  1:35   ` Arnaldo Carvalho de Melo
  2018-03-12  9:43 ` [PATCH 12/13] perf bpf: Run begin/end programs Jiri Olsa
                   ` (2 subsequent siblings)
  13 siblings, 2 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

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

Link: http://lkml.kernel.org/n/tip-sku9te4ouxg6svjtloh2nwdq@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 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

diff --git a/tools/perf/util/bpf-helpers.h b/tools/perf/util/bpf-helpers.h
new file mode 100644
index 000000000000..5ec52420e906
--- /dev/null
+++ b/tools/perf/util/bpf-helpers.h
@@ -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
diff --git a/tools/perf/util/bpf-userapi.h b/tools/perf/util/bpf-userapi.h
new file mode 100644
index 000000000000..63f2b4c13a5c
--- /dev/null
+++ b/tools/perf/util/bpf-userapi.h
@@ -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 */
diff --git a/tools/perf/util/bpf-userfuncs.h b/tools/perf/util/bpf-userfuncs.h
new file mode 100644
index 000000000000..e920420237ee
--- /dev/null
+++ b/tools/perf/util/bpf-userfuncs.h
@@ -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 */
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 12/13] perf bpf: Run begin/end programs
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (10 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 11/13] perf bpf: Add helper header files Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12  9:43 ` [PATCH 13/13] perf samples: Add syscall-count.c object Jiri Olsa
  2018-03-12 11:17 ` [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

Running begin and end programs for ebpf object.

Link: http://lkml.kernel.org/n/tip-ego7m00cr7sru8l5bjpjwwcm@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 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(+)

diff --git a/tools/perf/builtin-bpf.c b/tools/perf/builtin-bpf.c
index 7065153a9577..1111e240e259 100644
--- a/tools/perf/builtin-bpf.c
+++ b/tools/perf/builtin-bpf.c
@@ -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) {
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c
index e59168153375..d5f9c3cd5280 100644
--- a/tools/perf/util/bpf-loader.c
+++ b/tools/perf/util/bpf-loader.c
@@ -9,6 +9,7 @@
 #include <linux/bpf.h>
 #include <bpf/libbpf.h>
 #include <bpf/bpf.h>
+#include <bpf/interp.h>
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/string.h>
@@ -23,6 +24,7 @@
 #include "strfilter.h"
 #include "llvm-utils.h"
 #include "c++/clang-c.h"
+#include "bpf-userapi.h"
 
 #define DEFINE_PRINT_FN(name, level) \
 static int libbpf_##name(const char *fmt, ...)	\
@@ -1547,6 +1549,82 @@ int bpf__apply_obj_config(void)
 	return 0;
 }
 
+struct interp {
+	struct bpf_interp  in;
+	FILE		  *out;
+};
+
+static int bpf_interp_call_cb(struct bpf_interp *in,
+			      u64 imm, u64 *regs)
+{
+	struct interp *interp = container_of(in, struct interp, in);
+	u64 dr;
+
+	switch (imm) {
+	case BPF_FUNC_USER_bpf_map_lookup_elem:
+		dr = bpf_map_lookup_elem((int)    regs[1],
+					 (void *) regs[2],
+					 (void *) regs[3]);
+		break;
+	case BPF_FUNC_USER_bpf_map_get_next_key:
+		dr = bpf_map_get_next_key((int)    regs[1],
+					  (void *) regs[2],
+					  (void *) regs[3]);
+		break;
+	case BPF_FUNC_USER_print:
+		dr = fprintf(interp->out, (const char *) regs[1],
+			     regs[2], regs[3], regs[4], regs[5]);
+		fflush(interp->out);
+		break;
+	default:
+		return -1;
+		break;
+	};
+
+	regs[0] = dr;
+	regs[1] = 0xdeadbeef;
+	regs[2] = 0xdeadbeef;
+	regs[3] = 0xdeadbeef;
+	regs[4] = 0xdeadbeef;
+	return 0;
+}
+
+int bpf__run_begin(FILE *out)
+{
+	struct interp interp = {
+		.in.call_cb	= bpf_interp_call_cb,
+		.out		= out,
+	};
+	struct bpf_object *obj, *tmp;
+	int err;
+
+	bpf_object__for_each_safe(obj, tmp) {
+		err = bpf_object__run_begin(obj, &interp.in);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+int bpf__run_end(FILE *out)
+{
+	struct interp interp = {
+		.in.call_cb	= bpf_interp_call_cb,
+		.out		= out,
+	};
+	struct bpf_object *obj, *tmp;
+	int err;
+
+	bpf_object__for_each_safe(obj, tmp) {
+		err = bpf_object__run_end(obj, &interp.in);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
 #define bpf__for_each_map(pos, obj, objtmp)	\
 	bpf_object__for_each_safe(obj, objtmp)	\
 		bpf_map__for_each(pos, obj)
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h
index 8c2a494cab53..1ee4c3ca4927 100644
--- a/tools/perf/util/bpf-loader.h
+++ b/tools/perf/util/bpf-loader.h
@@ -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>
 
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* [PATCH 13/13] perf samples: Add syscall-count.c object
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (11 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 12/13] perf bpf: Run begin/end programs Jiri Olsa
@ 2018-03-12  9:43 ` Jiri Olsa
  2018-03-12 11:17 ` [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
  13 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12  9:43 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

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

Link: http://lkml.kernel.org/n/tip-9jsy0nnm8khn6e60fmwn4ei7@git.kernel.org
Signed-off-by: Jiri Olsa <jolsa@kernel.org>
---
 tools/perf/samples/syscall-counts.c | 61 +++++++++++++++++++++++++++++++++++++
 1 file changed, 61 insertions(+)
 create mode 100644 tools/perf/samples/syscall-counts.c

diff --git a/tools/perf/samples/syscall-counts.c b/tools/perf/samples/syscall-counts.c
new file mode 100644
index 000000000000..e6de6c9fdb85
--- /dev/null
+++ b/tools/perf/samples/syscall-counts.c
@@ -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;
+        }
+}
-- 
2.13.6

^ permalink raw reply related	[flat|nested] 27+ messages in thread

* Re: [RFC 00/13] perf bpf: Add support to run BEGIN/END code
  2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
                   ` (12 preceding siblings ...)
  2018-03-12  9:43 ` [PATCH 13/13] perf samples: Add syscall-count.c object Jiri Olsa
@ 2018-03-12 11:17 ` Jiri Olsa
  2018-03-12 13:56   ` Arnaldo Carvalho de Melo
  13 siblings, 1 reply; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12 11:17 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, Brendan Gregg, Stanislav Kozina,
	Frank Ch. Eigler, Will Cohen, Eugene Syromiatnikov,
	Jerome Marchand, lkml, Ingo Molnar, Namhyung Kim, David Ahern,
	Alexander Shishkin, Peter Zijlstra, Wang Nan, Alexei Starovoitov

adding Alexei and Wang to the loop

On Mon, Mar 12, 2018 at 10:43:00AM +0100, Jiri Olsa wrote:
> 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 <bgregg@netflix.com>
> Cc: Stanislav Kozina <skozina@redhat.com>
> Cc: "Frank Ch. Eigler" <fche@redhat.com>
> Cc: Will Cohen <wcohen@redhat.com>
> Cc: Eugene Syromiatnikov <esyromia@redhat.com>
> Cc: Jerome Marchand <jmarchan@redhat.com>
> 
> ---
> #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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [RFC 00/13] perf bpf: Add support to run BEGIN/END code
  2018-03-12 11:17 ` [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
@ 2018-03-12 13:56   ` Arnaldo Carvalho de Melo
  0 siblings, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-03-12 13:56 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Brendan Gregg, Stanislav Kozina, Frank Ch. Eigler, Will Cohen,
	Eugene Syromiatnikov, Jerome Marchand, lkml, Ingo Molnar,
	Namhyung Kim, David Ahern, Alexander Shishkin, Peter Zijlstra,
	Jiri Olsa, Wang Nan, Alexei Starovoitov

Em Mon, Mar 12, 2018 at 12:17:05PM +0100, Jiri Olsa escreveu:
> adding Alexei and Wang to the loop
> 
> On Mon, Mar 12, 2018 at 10:43:00AM +0100, Jiri Olsa wrote:
> > 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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 02/13] perf tools: Display ebpf compiling command in debug output
  2018-03-12  9:43 ` [PATCH 02/13] perf tools: Display ebpf compiling command in debug output Jiri Olsa
@ 2018-03-12 14:24   ` Arnaldo Carvalho de Melo
  2018-03-20  6:29   ` [tip:perf/core] perf llvm: Display eBPF " tip-bot for Jiri Olsa
  1 sibling, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-03-12 14:24 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

Em Mon, Mar 12, 2018 at 10:43:02AM +0100, Jiri Olsa escreveu:
> 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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 09/13] libbpf: Add bpf_insn__interpret function
  2018-03-12  9:43 ` [PATCH 09/13] libbpf: Add bpf_insn__interpret function Jiri Olsa
@ 2018-03-12 15:44   ` Arnaldo Carvalho de Melo
  2018-03-12 15:53     ` Jiri Olsa
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-03-12 15:44 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

Em Mon, Mar 12, 2018 at 10:43:09AM +0100, Jiri Olsa escreveu:
> 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?
 
> Link: http://lkml.kernel.org/n/tip-qqxsyw6imdisj3dydd6e21y7@git.kernel.org
> Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> 
> +++ b/tools/lib/bpf/Build
> @@ -1 +1 @@
> -libbpf-y := libbpf.o bpf.o nlattr.o
> +libbpf-y := libbpf.o bpf.o nlattr.o interp.o
> diff --git a/tools/lib/bpf/interp.c b/tools/lib/bpf/interp.c
> new file mode 100644
> index 000000000000..2ceb6a0836c3
> --- /dev/null
> +++ b/tools/lib/bpf/interp.c
> @@ -0,0 +1,245 @@
> +#include <uapi/linux/bpf.h>
> +#include <stdlib.h>
> +#include "interp.h"
> +
> +u64 bpf_interp__run(struct bpf_interp *interp)
> +{
<SNIP>
> +
> +		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).

> +		}
> +
> +		regs[i->dst_reg] = dr;
> +	nowrite:
> +		i++;
> +	}
> +
> +	return 0;
> +}
> -- 
> 2.13.6

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 09/13] libbpf: Add bpf_insn__interpret function
  2018-03-12 15:44   ` Arnaldo Carvalho de Melo
@ 2018-03-12 15:53     ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12 15:53 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, David Ahern,
	Alexander Shishkin, Peter Zijlstra

On Mon, Mar 12, 2018 at 12:44:03PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Mon, Mar 12, 2018 at 10:43:09AM +0100, Jiri Olsa escreveu:
> > 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

>  
> > Link: http://lkml.kernel.org/n/tip-qqxsyw6imdisj3dydd6e21y7@git.kernel.org
> > Signed-off-by: Jiri Olsa <jolsa@kernel.org>
> > 
> > +++ b/tools/lib/bpf/Build
> > @@ -1 +1 @@
> > -libbpf-y := libbpf.o bpf.o nlattr.o
> > +libbpf-y := libbpf.o bpf.o nlattr.o interp.o
> > diff --git a/tools/lib/bpf/interp.c b/tools/lib/bpf/interp.c
> > new file mode 100644
> > index 000000000000..2ceb6a0836c3
> > --- /dev/null
> > +++ b/tools/lib/bpf/interp.c
> > @@ -0,0 +1,245 @@
> > +#include <uapi/linux/bpf.h>
> > +#include <stdlib.h>
> > +#include "interp.h"
> > +
> > +u64 bpf_interp__run(struct bpf_interp *interp)
> > +{
> <SNIP>
> > +
> > +		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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12  9:43 ` [PATCH 11/13] perf bpf: Add helper header files Jiri Olsa
@ 2018-03-12 18:44   ` Alexei Starovoitov
  2018-03-12 19:06     ` Arnaldo Carvalho de Melo
  2018-03-12 19:20     ` Jiri Olsa
  2018-03-13  1:35   ` Arnaldo Carvalho de Melo
  1 sibling, 2 replies; 27+ messages in thread
From: Alexei Starovoitov @ 2018-03-12 18:44 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Arnaldo Carvalho de Melo, lkml, Ingo Molnar, Namhyung Kim,
	David Ahern, Alexander Shishkin, Peter Zijlstra, Daniel Borkmann,
	Wangnan

On Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa wrote:
> diff --git a/tools/perf/util/bpf-userapi.h b/tools/perf/util/bpf-userapi.h
> new file mode 100644
> index 000000000000..63f2b4c13a5c
> --- /dev/null
> +++ b/tools/perf/util/bpf-userapi.h
> @@ -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 */
> diff --git a/tools/perf/util/bpf-userfuncs.h b/tools/perf/util/bpf-userfuncs.h
> new file mode 100644
> index 000000000000..e920420237ee
> --- /dev/null
> +++ b/tools/perf/util/bpf-userfuncs.h
> @@ -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__);              \
> +})

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.

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12 18:44   ` Alexei Starovoitov
@ 2018-03-12 19:06     ` Arnaldo Carvalho de Melo
  2018-03-12 19:20     ` Jiri Olsa
  1 sibling, 0 replies; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-03-12 19:06 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, David Ahern,
	Alexander Shishkin, Peter Zijlstra, Daniel Borkmann, Wangnan

Em Mon, Mar 12, 2018 at 11:44:57AM -0700, Alexei Starovoitov escreveu:
> On Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa wrote:
> > diff --git a/tools/perf/util/bpf-userapi.h b/tools/perf/util/bpf-userapi.h
> > new file mode 100644
> > index 000000000000..63f2b4c13a5c
> > --- /dev/null
> > +++ b/tools/perf/util/bpf-userapi.h
> > @@ -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 */
> > diff --git a/tools/perf/util/bpf-userfuncs.h b/tools/perf/util/bpf-userfuncs.h
> > new file mode 100644
> > index 000000000000..e920420237ee
> > --- /dev/null
> > +++ b/tools/perf/util/bpf-userfuncs.h
> > @@ -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__);              \
> > +})
> 
> 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.

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

- Arnaldo

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12 18:44   ` Alexei Starovoitov
  2018-03-12 19:06     ` Arnaldo Carvalho de Melo
@ 2018-03-12 19:20     ` Jiri Olsa
  2018-03-12 19:25       ` Arnaldo Carvalho de Melo
  1 sibling, 1 reply; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12 19:20 UTC (permalink / raw)
  To: Alexei Starovoitov
  Cc: Jiri Olsa, Arnaldo Carvalho de Melo, lkml, Ingo Molnar,
	Namhyung Kim, David Ahern, Alexander Shishkin, Peter Zijlstra,
	Daniel Borkmann, Wangnan

On Mon, Mar 12, 2018 at 11:44:57AM -0700, Alexei Starovoitov wrote:
> On Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa wrote:
> > diff --git a/tools/perf/util/bpf-userapi.h b/tools/perf/util/bpf-userapi.h
> > new file mode 100644
> > index 000000000000..63f2b4c13a5c
> > --- /dev/null
> > +++ b/tools/perf/util/bpf-userapi.h
> > @@ -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 */
> > diff --git a/tools/perf/util/bpf-userfuncs.h b/tools/perf/util/bpf-userfuncs.h
> > new file mode 100644
> > index 000000000000..e920420237ee
> > --- /dev/null
> > +++ b/tools/perf/util/bpf-userfuncs.h
> > @@ -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__);              \
> > +})
> 
> 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

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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12 19:20     ` Jiri Olsa
@ 2018-03-12 19:25       ` Arnaldo Carvalho de Melo
  2018-03-12 22:32         ` Jiri Olsa
  0 siblings, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-03-12 19:25 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: Alexei Starovoitov, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	David Ahern, Alexander Shishkin, Peter Zijlstra, Daniel Borkmann,
	Wangnan

Em Mon, Mar 12, 2018 at 08:20:20PM +0100, Jiri Olsa escreveu:
> On Mon, Mar 12, 2018 at 11:44:57AM -0700, Alexei Starovoitov wrote:
> > On Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa wrote:
> > > diff --git a/tools/perf/util/bpf-userapi.h b/tools/perf/util/bpf-userapi.h
> > > new file mode 100644
> > > index 000000000000..63f2b4c13a5c
> > > --- /dev/null
> > > +++ b/tools/perf/util/bpf-userapi.h
> > > @@ -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 */
> > > diff --git a/tools/perf/util/bpf-userfuncs.h b/tools/perf/util/bpf-userfuncs.h
> > > new file mode 100644
> > > index 000000000000..e920420237ee
> > > --- /dev/null
> > > +++ b/tools/perf/util/bpf-userfuncs.h
> > > @@ -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__);              \
> > > +})
> > 
> > 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

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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12 19:25       ` Arnaldo Carvalho de Melo
@ 2018-03-12 22:32         ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-12 22:32 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Alexei Starovoitov, Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim,
	David Ahern, Alexander Shishkin, Peter Zijlstra, Daniel Borkmann,
	Wangnan

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

SNIP

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

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

jirka

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-12  9:43 ` [PATCH 11/13] perf bpf: Add helper header files Jiri Olsa
  2018-03-12 18:44   ` Alexei Starovoitov
@ 2018-03-13  1:35   ` Arnaldo Carvalho de Melo
  2018-03-13 14:18     ` Jiri Olsa
  1 sibling, 1 reply; 27+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-03-13  1:35 UTC (permalink / raw)
  To: Jiri Olsa
  Cc: lkml, Ingo Molnar, Namhyung Kim, David Ahern, Alexander Shishkin,
	Peter Zijlstra

Em Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa escreveu:
> +#elif defined(__s390x__)
> +	#define bpf_target_s930x

    bpf_target_s390x

> +#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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* Re: [PATCH 11/13] perf bpf: Add helper header files
  2018-03-13  1:35   ` Arnaldo Carvalho de Melo
@ 2018-03-13 14:18     ` Jiri Olsa
  0 siblings, 0 replies; 27+ messages in thread
From: Jiri Olsa @ 2018-03-13 14:18 UTC (permalink / raw)
  To: Arnaldo Carvalho de Melo
  Cc: Jiri Olsa, lkml, Ingo Molnar, Namhyung Kim, David Ahern,
	Alexander Shishkin, Peter Zijlstra

On Mon, Mar 12, 2018 at 10:35:29PM -0300, Arnaldo Carvalho de Melo wrote:
> Em Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa escreveu:
> > +#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

> 
> > +#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

^ permalink raw reply	[flat|nested] 27+ messages in thread

* [tip:perf/core] perf llvm: Display eBPF compiling command in debug output
  2018-03-12  9:43 ` [PATCH 02/13] perf tools: Display ebpf compiling command in debug output Jiri Olsa
  2018-03-12 14:24   ` Arnaldo Carvalho de Melo
@ 2018-03-20  6:29   ` tip-bot for Jiri Olsa
  1 sibling, 0 replies; 27+ messages in thread
From: tip-bot for Jiri Olsa @ 2018-03-20  6:29 UTC (permalink / raw)
  To: linux-tip-commits
  Cc: alexander.shishkin, tglx, jolsa, acme, hpa, mingo, peterz,
	dsahern, namhyung, linux-kernel

Commit-ID:  5eab5a7ee032acaab3da8fc95a3614fec14687ac
Gitweb:     https://git.kernel.org/tip/5eab5a7ee032acaab3da8fc95a3614fec14687ac
Author:     Jiri Olsa <jolsa@kernel.org>
AuthorDate: Mon, 12 Mar 2018 10:43:02 +0100
Committer:  Arnaldo Carvalho de Melo <acme@redhat.com>
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 ...

Signed-off-by: Jiri Olsa <jolsa@kernel.org>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20180312094313.18738-3-jolsa@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
---
 tools/perf/util/llvm-utils.c | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c
index 4952b429caa7..1cca0a2fa641 100644
--- a/tools/perf/util/llvm-utils.c
+++ b/tools/perf/util/llvm-utils.c
@@ -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);

^ permalink raw reply related	[flat|nested] 27+ messages in thread

end of thread, other threads:[~2018-03-20  6:30 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-03-12  9:43 [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
2018-03-12  9:43 ` [PATCH 01/13] lib bpf: Add bpf_program__insns function Jiri Olsa
2018-03-12  9:43 ` [PATCH 02/13] perf tools: Display ebpf compiling command in debug output Jiri Olsa
2018-03-12 14:24   ` Arnaldo Carvalho de Melo
2018-03-20  6:29   ` [tip:perf/core] perf llvm: Display eBPF " tip-bot for Jiri Olsa
2018-03-12  9:43 ` [PATCH 03/13] perf tools: Add bpf command Jiri Olsa
2018-03-12  9:43 ` [PATCH 04/13] perf tools: Add bpf__compile function Jiri Olsa
2018-03-12  9:43 ` [PATCH 05/13] perf bpf: Add compile option Jiri Olsa
2018-03-12  9:43 ` [PATCH 06/13] perf bpf: Add disasm option Jiri Olsa
2018-03-12  9:43 ` [PATCH 07/13] libbpf: Make bpf_program__next skip .text section Jiri Olsa
2018-03-12  9:43 ` [PATCH 08/13] libbpf: Collect begin/end .text functions Jiri Olsa
2018-03-12  9:43 ` [PATCH 09/13] libbpf: Add bpf_insn__interpret function Jiri Olsa
2018-03-12 15:44   ` Arnaldo Carvalho de Melo
2018-03-12 15:53     ` Jiri Olsa
2018-03-12  9:43 ` [PATCH 10/13] libbpf: Add bpf_object__run_(begin|end) functions Jiri Olsa
2018-03-12  9:43 ` [PATCH 11/13] perf bpf: Add helper header files Jiri Olsa
2018-03-12 18:44   ` Alexei Starovoitov
2018-03-12 19:06     ` Arnaldo Carvalho de Melo
2018-03-12 19:20     ` Jiri Olsa
2018-03-12 19:25       ` Arnaldo Carvalho de Melo
2018-03-12 22:32         ` Jiri Olsa
2018-03-13  1:35   ` Arnaldo Carvalho de Melo
2018-03-13 14:18     ` Jiri Olsa
2018-03-12  9:43 ` [PATCH 12/13] perf bpf: Run begin/end programs Jiri Olsa
2018-03-12  9:43 ` [PATCH 13/13] perf samples: Add syscall-count.c object Jiri Olsa
2018-03-12 11:17 ` [RFC 00/13] perf bpf: Add support to run BEGIN/END code Jiri Olsa
2018-03-12 13:56   ` Arnaldo Carvalho de Melo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.