perf bpf: Add support to run BEGIN/END code
Subsystems (3)
Jiri Olsa
reviewercover perf bpf: Add support to run BEGIN/END code
hi,
this is *RFC* and the following patchset is very rough and ugly 'prove of concept'-kind-of-toy code. I'm mostly interested in opinions about if this could be useful in your current eBPF usage.
Currently we can load eBPF code within the record command and attach it to event. We have 2 ways of communicating the data back to user: bpf-output event that goes to perf.data or 'trace_printk' output in tracefs buffer.
AFAICS we're not covering quite large usage base that runs code before and once the probe is finished to setup, collect and display the collected data.
This patchset is adding support to run BEGIN and END code snipets before and after eBPF probe is loaded.
This allow to write 'collecting' code in eBPF object, like in the attached example (it's also part of the patchset).
This patchset also adds 'bpf' command to ease up the loading of eBPF files with options for compilation and disassembly of eBPF objects:
$ perf bpf -c samples/syscall-counts.c
LLVM: dumping samples/syscall-counts.o $ perf bpf -d samples/syscall-counts.o | head
Disassembly of raw_syscalls:sys_enter:
0: (b7) r1 = 1
b7 01 00 00 01 00 00 00
1: (7b) *(u64 *)(r10 -8) = r1
7b 1a f8 ff 00 00 00 00
2: (bf) r6 = r10
... $ sudo perf bpf -e samples/syscall-counts.o -a
BEGIN
^CEND
comm value
firefox 182
Socket Thread 8
InotifyEventThr 26
xmonad-x86_64-l 405
...The patchset is also available in here:
https://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/bpf
So far I need following following lines in .perfconfig to run this:
[llvm]
kbuild-dir=/home/jolsa/kernel/linux-perf clang-opt=-I/home/jolsa/kernel/linux-perf/tools/perf/util
thoughts? ;-) thanks,
jirka
---
#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
Jiri Olsa
reviewerPATCH 1/13 lib bpf: Add bpf_program__insns function
Adding bpf_program__insns helper function to retrieve prog's instructions. It's used later in the patchset.
--- tools/lib/bpf/libbpf.c | 7 +++++++ tools/lib/bpf/libbpf.h | 3 +++ 2 files changed, 10 insertions(+)
tools/lib/bpf/libbpf.c +7 -0
@@ -261,6 +261,13 @@ struct bpf_object { };#define obj_elf_valid (o) ((o)->efile.elf) +struct bpf_insn * +bpf_program__insns (struct bpf_program *prog,int *insns_cnt) +{ + *insns_cnt = prog->insns_cnt; +return prog->insns; +} +static void bpf_program__unload (struct bpf_program *prog) {int i;
tools/lib/bpf/libbpf.h +3 -0
@@ -180,6 +180,9 @@ int bpf_program__set_prep(struct bpf_program *prog, int nr_instance,int bpf_program__nth_fd (struct bpf_program *prog,int n); +struct bpf_insn * +bpf_program__insns (struct bpf_program *prog,int *insns_cnt); +/* * Adjust type of bpf program. Default is kprobe. */
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 2/13 perf tools: Display ebpf compiling command in debug output
In reply to Jiri OlsaIn addition to template, display also the real compile command line with all the variables substituted.
llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS ... llvm compiling command : /usr/bin/clang -D__KERNEL__ -D__NR_CPUS__=24 -DLINUX_VERSION_CODE=0x41000 ...
--- tools/perf/util/llvm-utils.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
tools/perf/util/llvm-utils.c +14 -0
@@ -433,6 +433,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf,char serr[STRERR_BUFSIZE ];char *kbuild_dir =NULL , *kbuild_include_opts =NULL ;const char *template = llvm_param.clang_bpf_cmd_template; +char *command_echo, *command_out;if (path[0 ] !='-' &&realpath (path, abspath) ==NULL ) { err = errno;
@@ -487,6 +488,16 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, (path[0] == '-') ? path : abspath);pr_debug ("llvm compiling command template: %s\n" , template); + +if (asprintf (&command_echo,"echo -n \"%s\"" , template) <0 ) + goto errout; + + err =read_from_pipe (command_echo, (void **) &command_out,NULL ); +if (err) + goto errout; + +pr_debug ("llvm compiling command : %s\n" , command_out); + err =read_from_pipe (template, &obj_buf, &obj_buf_sz);if (err) {pr_err ("ERROR:\tunable to compile %s\n" , path);
@@ -497,6 +508,8 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, goto errout; } +free (command_echo); +free (command_out);free (kbuild_dir);free (kbuild_include_opts);
@@ -509,6 +522,7 @@ int llvm__compile_bpf(const char *path, void **p_obj_buf, *p_obj_buf_sz = obj_buf_sz;return 0 ; errout: +free (command_echo);free (kbuild_dir);free (kbuild_include_opts);free (obj_buf);
Signature · 1 line
2.13.6
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 02/13] perf tools: Display ebpf compiling command in debug output
Em Mon, Mar 12, 2018 at 10:43:02AM +0100, Jiri Olsa escreveu:
Quoted 5 lines
In addition to template, display also the real compile command line with all the variables substituted.
llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS ... llvm compiling command :
/usr/bin/clang-D__KERNEL__ -D__NR_CPUS__=24 -DLINUX_VERSION_CODE=0x41000 ...
Useful, applied.
- Arnaldo
tip-bot for Jiri Olsa
merge bot[tip:perf/core] perf llvm: Display eBPF compiling command in debug output
In reply to Jiri Olsaperf llvm: Display eBPF compiling command in debug output
Commit-ID: 5eab5a7ee032acaab3da8fc95a3614fec14687ac Gitweb: https://git.kernel.org/tip/5eab5a7ee032acaab3da8fc95a3614fec14687ac Author: Jiri Olsa <[email protected]> AuthorDate: Mon, 12 Mar 2018 10:43:02 +0100 Committer: Arnaldo Carvalho de Melo <[email protected]> CommitDate: Fri, 16 Mar 2018 13:56:12 -0300
perf llvm: Display eBPF compiling command in debug output
In addition to template, display also the real compile command line with all the variables substituted.
llvm compiling command template: $CLANG_EXEC -D__KERNEL__ -D__NR_CPUS__=$NR_CPUS ... llvm compiling command : /usr/bin/clang -D__KERNEL__ -D__NR_CPUS__=24 -DLINUX_VERSION_CODE=0x41000 ...
--- tools/perf/util/llvm-utils.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+)
tools/perf/util/llvm-utils.c +14 -0
@@ -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);
Jiri Olsa
reviewerPATCH 3/13 perf tools: Add bpf command
In reply to Jiri OlsaAdding perf bpf command to allow to provide some fucs over ebpf objects, like compile, disassembly and loading, which is comming in following patches.
--- tools/perf/Build | 1 + tools/perf/builtin-bpf.c | 199 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/builtin.h | 1 + tools/perf/command-list.txt | 1 + tools/perf/perf.c | 1 + 5 files changed, 203 insertions(+) create mode 100644 tools/perf/builtin-bpf.c
tools/perf/Build +1 -0
@@ -24,6 +24,7 @@ perf-y += builtin-mem.o perf-y += builtin-data.o perf-y += builtin-version.o perf-y += builtin-c2c.o +perf-y += builtin-bpf.o perf-$(CONFIG_TRACE) += builtin-trace.o perf-$(CONFIG_LIBELF) += builtin-probe.o
tools/perf/builtin-bpf.c new file +199 -0
199 lines not on this page · raw message
tools/perf/builtin.h +1 -0
@@ -39,6 +39,7 @@ int cmd_inject(int argc, const char **argv);int cmd_mem (int argc,const char **argv);int cmd_data (int argc,const char **argv);int cmd_ftrace (int argc,const char **argv); +int cmd_bpf (int argc,const char **argv);int find_scripts (char **scripts_array,char **scripts_path_array);#endif
tools/perf/command-list.txt +1 -0
@@ -30,3 +30,4 @@ perf-test mainporcelain common perf-timechart mainporcelain common perf-top mainporcelain common perf-trace mainporcelain audit +perf-bpf mainporcelain common
tools/perf/perf.c +1 -0
@@ -80,6 +80,7 @@ static struct cmd_struct commands[] = { { "mem", cmd_mem, 0 }, { "data", cmd_data, 0 }, { "ftrace", cmd_ftrace, 0 }, + { "bpf", cmd_bpf, 0 }, }; struct pager_config {
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 4/13 perf tools: Add bpf__compile function
In reply to Jiri OlsaAdding bpf__compile function to have interface for ebpf object compilation.
--- tools/perf/util/bpf-loader.c | 46 +++++++++++++++++++++++++++++++++----------- tools/perf/util/bpf-loader.h | 2 ++ 2 files changed, 37 insertions(+), 11 deletions(-)
tools/perf/util/bpf-loader.c +35 -11
@@ -74,6 +74,38 @@ bpf__prepare_load_buffer(void *obj_buf, size_t obj_buf_sz, const char *name)return obj; } +static int compile (const char *filename,void *obj_buf,size_t *obj_buf_sz) +{ +int err; + +perf_clang__init (); + err =perf_clang__compile_bpf (filename, obj_buf, obj_buf_sz); +perf_clang__cleanup (); +if (err) { +pr_debug ("bpf: builtin compilation failed: %d, try external compiler\n" , err); + err =llvm__compile_bpf (filename, obj_buf, obj_buf_sz); +if (err) +return -1 ; + }else { +pr_debug ("bpf: successfull builtin compilation\n" ); + } + +return 0 ; +} + +int bpf__compile (const char *filename) +{ +void *obj_buf; +size_t obj_buf_sz; + +if (compile (filename, &obj_buf, &obj_buf_sz)) +return -1 ; + +/* make llvm__dump_obj to return error value */ +llvm__dump_obj (filename, obj_buf, obj_buf_sz); +return 0 ; +} +struct bpf_object *bpf__prepare_load (const char *filename,bool source) {struct bpf_object *obj;
@@ -86,20 +118,12 @@ struct bpf_object *bpf__prepare_load(const char *filename, bool source) }if (source) { -int err;void *obj_buf;size_t obj_buf_sz; -perf_clang__init (); - err =perf_clang__compile_bpf (filename, &obj_buf, &obj_buf_sz); -perf_clang__cleanup (); -if (err) { -pr_debug ("bpf: builtin compilation failed: %d, try external compiler\n" , err); - err =llvm__compile_bpf (filename, &obj_buf, &obj_buf_sz); -if (err) -return ERR_PTR (-BPF_LOADER_ERRNO__COMPILE ); - }else -pr_debug ("bpf: successfull builtin compilation\n" ); +if (compile (filename, &obj_buf, &obj_buf_sz)) +return ERR_PTR (-BPF_LOADER_ERRNO__COMPILE ); + obj =bpf_object__open_buffer (obj_buf, obj_buf_sz, filename);if (!IS_ERR (obj) && llvm_param.dump_obj)
tools/perf/util/bpf-loader.h +2 -0
@@ -58,6 +58,8 @@ int bpf__strerror_prepare_load(const char *filename, bool source,struct bpf_object *bpf__prepare_load_buffer (void *obj_buf,size_t obj_buf_sz,const char *name); +int bpf__compile (const char *filename); +void bpf__clear (void );int bpf__probe (struct bpf_object *obj);
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 5/13 perf bpf: Add compile option
In reply to Jiri OlsaAdding -c/--compile option to provide compilation
for ebpf objects, like:
$ perf bpf -c samples/syscall-counts.c LLVM: dumping samples/syscall-counts.o
--- tools/perf/builtin-bpf.c | 7 +++++++ 1 file changed, 7 insertions(+)
tools/perf/builtin-bpf.c +7 -0
@@ -145,6 +145,7 @@ int cmd_bpf(int argc, const char **argv) "perf bpf [<options>] -- <command> [<options>]", NULL }; +const char *compile_src =NULL ;const struct option bpf_options[] = { OPT_CALLBACK('e', "event", &bpf.evlist, "event", "event selector. use 'perf list' to list available events",
@@ -159,6 +160,8 @@ int cmd_bpf(int argc, const char **argv) "record events on existing thread id"),OPT_INCR ('v' ,"verbose" , &verbose,"be more verbose" ), +OPT_STRING ('c' ,"compile" , &compile_src,"eBPF source" , +"compile eBPF object" ), OPT_END() };
@@ -170,6 +173,10 @@ int cmd_bpf(int argc, const char **argv) argc =parse_options (argc, argv, bpf_options, bpf_usage,PARSE_OPT_STOP_AT_NON_OPTION ); + +if (compile_src) +return bpf__compile (compile_src); +if (!argc &&target__none (&bpf.target))usage_with_options (bpf_usage, bpf_options);
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 6/13 perf bpf: Add disasm option
In reply to Jiri OlsaAdd -d/--disasm option to get the sbpf assembly
code dump, like:
$ perf bpf -d ./comm1.o | head
Disassembly of raw_syscalls:sys_enter:
0: (b7) r1 = 1
b7 01 00 00 01 00 00 00
1: (7b) *(u64 *)(r10 -8) = r1
7b 1a f8 ff 00 00 00 00
2: (bf) r6 = r10
bf a6 00 00 00 00 00 00
3: (07) r6 += -24
07 06 00 00 e8 ff ff ff
4: (bf) r1 = r6
...--- tools/perf/Build | 6 +++ tools/perf/Makefile.config | 1 + tools/perf/builtin-bpf.c | 107 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+)
tools/perf/Build +6 -0
@@ -25,6 +25,7 @@ perf-y += builtin-data.o perf-y += builtin-version.o perf-y += builtin-c2c.o perf-y += builtin-bpf.o +perf-y += bpf-disasm.o perf-$(CONFIG_TRACE) += builtin-trace.o perf-$(CONFIG_LIBELF) += builtin-probe.o
@@ -46,6 +47,7 @@ CFLAGS_perf.o += -DPERF_HTML_PATH="BUILD_STR($(htmldir_SQ))" \ CFLAGS_builtin-trace.o += -DSTRACE_GROUPS_DIR="BUILD_STR($(STRACE_GROUPS_DIR_SQ))" CFLAGS_builtin-report.o += -DTIPDIR="BUILD_STR($(tipdir_SQ))" CFLAGS_builtin-report.o += -DDOCDIR="BUILD_STR($(srcdir_SQ)/Documentation)" +CFLAGS_builtin-bpf.o += -I$(srctree)/kernel/bpf libperf-y += util/ libperf-y += arch/
@@ -54,3 +56,7 @@ libperf-y += scripts/ libperf-$(CONFIG_TRACE) += trace/beauty/ gtk-y += ui/gtk/ + +$(OUTPUT)bpf-disasm.o: ../../kernel/bpf/disasm.c FORCE + $(call rule_mkdir) + $(call if_changed_dep,cc_o_c)
tools/perf/Makefile.config +1 -0
@@ -999,3 +999,4 @@ $(call detected_var,LIBDIR) $(call detected_var,GTK_CFLAGS) $(call detected_var,PERL_EMBED_CCOPTS) $(call detected_var,PYTHON_EMBED_CCOPTS) +$(call detected_var,srctree)
tools/perf/builtin-bpf.c +107 -0
143 lines not on this page · raw message
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 7/13 libbpf: Make bpf_program__next skip .text section
In reply to Jiri OlsaSkip .text section in bpf_program__next, so it iterates only throught the probes code. We are about to add .text code support, so the .text section needs to get separated from probes.
--- tools/lib/bpf/libbpf.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
tools/lib/bpf/libbpf.c +15 -3
@@ -1705,22 +1705,34 @@ void *bpf_object__priv(struct bpf_object *obj)struct bpf_program *bpf_program__next (struct bpf_program *prev,struct bpf_object *obj) { +struct bpf_program *prog;size_t idx;if (!obj->programs)return NULL ; +/* First handler */ if (prev ==NULL ) -return &obj->programs[0 ]; + idx =0 ; +else + idx = (prev - obj->programs) +1 ; -if (prev->obj != obj) { +if (prev && (prev->obj != obj)) {pr_warning ("error: program handler doesn't match object\n" );return NULL ; } - idx = (prev - obj->programs) +1 ;if (idx >= obj->nr_programs)return NULL ; + + prog = &obj->programs[idx]; + +if (prog->idx == obj->efile.text_shndx) + idx++; + +if (idx >= obj->nr_programs) +return NULL ; +return &obj->programs[idx]; }
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 8/13 libbpf: Collect begin/end .text functions
In reply to Jiri OlsaCollect begin/end functions from .text section,
so they could be executed before/after probes.
--- tools/lib/bpf/libbpf.c | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+)
tools/lib/bpf/libbpf.c +70 -0
@@ -225,6 +225,10 @@ struct bpf_object {struct bpf_map *maps;size_t nr_maps; +struct bpf_program *text; +struct bpf_insn *insn_begin; +struct bpf_insn *insn_end; +bool loaded;/*
@@ -440,6 +444,68 @@ bpf_object__init_prog_names(struct bpf_object *obj)return 0 ; } +static int +bpf_object__init_text (struct bpf_object *obj) +{ +Elf_Data *symbols = obj->efile.symbols; +struct bpf_program *prog; +size_t pi, si; + +if (obj->efile.text_shndx ==-1 ) +return 0 ; + +for (pi =0 ; pi < obj->nr_programs; pi++) { + prog = &obj->programs[pi]; +if (prog->idx != obj->efile.text_shndx) +continue ; + + obj->text = prog; + +for (si =0 ; si < symbols->d_size /sizeof (GElf_Sym); si++) { +bool is_end = false, is_begin = false; +struct bpf_insn *insn; +const char *name =NULL ; +unsigned int insn_idx; +GElf_Sym sym; + +if (!gelf_getsym (symbols, si, &sym)) +continue ; +if (sym.st_shndx != prog->idx) +continue ; +if (GELF_ST_BIND (sym.st_info) !=STB_GLOBAL ) +continue ; + + name =elf_strptr (obj->efile.elf, + obj->efile.strtabidx, + sym.st_name); +if (!name) { +pr_warning ("failed to get sym name string for prog %s\n" , + prog->section_name); +return -LIBBPF_ERRNO__LIBELF ; + } + + is_begin = !strcmp (name,"BEGIN" ); + is_end = !strcmp (name,"END" ); + +if (!is_begin && !is_end) +continue ; + + insn_idx = sym.st_value /sizeof (struct bpf_insn ); + insn = &prog->insns[insn_idx]; + +pr_debug ("set %s to %p\n" , name, insn); + +if (is_begin) + obj->insn_begin = insn; +else + obj->insn_end = insn; + } + } + +return 0 ; +} + +static struct bpf_object *bpf_object__new (const char *path,void *obj_buf,size_t obj_buf_sz)
@@ -464,6 +530,7 @@ static struct bpf_object *bpf_object__new(const char *path, obj->efile.obj_buf = obj_buf; obj->efile.obj_buf_sz = obj_buf_sz; obj->efile.maps_shndx =-1 ; + obj->efile.text_shndx =-1 ; obj->loaded = false;
@@ -890,6 +957,9 @@ static int bpf_object__elf_collect(struct bpf_object *obj) goto out; } err =bpf_object__init_prog_names (obj); +if (err) + goto out; + err =bpf_object__init_text (obj); out:return err; }
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 9/13 libbpf: Add bpf_insn__interpret function
In reply to Jiri OlsaAdding bpf_insn__interpret function to run ebpf program in user space.
It's 'borrowed' from systemtap code, I still need to figure the proper credits, that will go to the file header in case this would ever go in.
--- tools/lib/bpf/Build | 2 +- tools/lib/bpf/interp.c | 245 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 246 insertions(+), 1 deletion(-) create mode 100644 tools/lib/bpf/interp.c
tools/lib/bpf/Build +1 -1
@@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o +libbpf-y := libbpf.o bpf.o nlattr.o interp.o
tools/lib/bpf/interp.c new file +245 -0
245 lines not on this page · raw message
Signature · 1 line
2.13.6
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 09/13] libbpf: Add bpf_insn__interpret function
Em Mon, Mar 12, 2018 at 10:43:09AM +0100, Jiri Olsa escreveu:
Quoted 6 lines
Adding
bpf_insn__interpretfunction to run ebpf program in user space.It's 'borrowed' from systemtap code, I still need to figure the proper credits, that will go to the file header in case this would ever go in.
What is the license? GPL?
Quoted 19 lines
Signed-off-by Jiri Olsa <[email protected]>+++ b/tools/lib/bpf/Build
tools/lib/bpf/Build +1
-1@@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o +libbpf-y := libbpf.o bpf.o nlattr.o interp.otools/lib/bpf/interp.c new file +6
-0@@ -0,0 +1,245 @@ +#include <uapi/linux/bpf.h> +#include <stdlib.h> +#include "interp.h" + +u64 bpf_interp__run (struct bpf_interp *interp) +{
<SNIP>
tools/lib/bpf/interp.c line 236
Quoted 6 lines
tools/lib/bpf/interp.c new file +6
-0+ +case BPF_JMP |BPF_EXIT : +return regs[0 ]; + +default : +abort ();
And this should be converted to returning some error that the users can tell the user using whatever UI (TUI, etc).
Quoted 11 lines
tools/lib/bpf/interp.c new file +9
-0+ } + + regs[i->dst_reg] = dr; + nowrite: + i++; + } + +return 0 ; +}Signature · 1 line
2.13.6
Re: [PATCH 09/13] libbpf: Add bpf_insn__interpret function
Quoted 9 lines · Arnaldo Carvalho de Melo
Em Mon, Mar 12, 2018 at 10:43:09AM +0100, Jiri Olsa escreveu:
Quoted 6 lines
Adding
bpf_insn__interpretfunction to run ebpf program in user space.It's 'borrowed' from systemtap code, I still need to figure the proper credits, that will go to the file header in case this would ever go in.
What is the license? GPL?
yes GPLv2
Quoted 21 lines
Quoted 20 lines
Signed-off-by Jiri Olsa <[email protected]>+++ b/tools/lib/bpf/Build
tools/lib/bpf/Build +1
-1@@ -1 +1 @@ -libbpf-y := libbpf.o bpf.o nlattr.o +libbpf-y := libbpf.o bpf.o nlattr.o interp.otools/lib/bpf/interp.c new file +6
-0@@ -0,0 +1,245 @@ +#include <uapi/linux/bpf.h> +#include <stdlib.h> +#include "interp.h" + +u64 bpf_interp__run (struct bpf_interp *interp) +{<SNIP>
Quoted 9 lines
tools/lib/bpf/interp.c line 236
Quoted 6 lines
tools/lib/bpf/interp.c new file +6
-0+ +case BPF_JMP |BPF_EXIT : +return regs[0 ]; + +default : +abort ();And this should be converted to returning some error that the users can tell the user using whatever UI (TUI, etc).
right, I want to get rid of all abort calls, I think there's one more
jirka
Jiri Olsa
reviewerPATCH 10/13 libbpf: Add bpf_object__run_(begin|end) functions
In reply to Jiri OlsaAdd bpf_object__run_(begin|end) functions to run
BEGIN/END code for specific object.
--- tools/lib/bpf/libbpf.c | 30 ++++++++++++++++++++++++++++++ tools/lib/bpf/libbpf.h | 4 ++++ 2 files changed, 34 insertions(+)
tools/lib/bpf/libbpf.c +30 -0
@@ -45,6 +45,7 @@#include "libbpf.h" #include "bpf.h" +#include "interp.h" #ifndef EM_BPF #define EM_BPF 247
@@ -2107,3 +2108,32 @@ int bpf_prog_load(const char *file, enum bpf_prog_type type, *prog_fd =bpf_program__fd (first_prog);return 0 ; } + +static u64 bpf_program__run (struct bpf_program *prog, +struct bpf_insn *insn, +struct bpf_interp *interp) +{ + interp->insns = prog->insns; + interp->insns_cnt = prog->insns_cnt; + interp->insns_start = insn - prog->insns; + +return bpf_interp__run (interp); +} + +u64 bpf_object__run_begin (struct bpf_object *obj,struct bpf_interp *interp) +{ +struct bpf_program *prog = obj->text; +struct bpf_insn *insn = obj->insn_begin; + +pr_debug ("running BEGIN(%p) for %s\n" , insn, prog->name); +return insn &&bpf_program__run (obj->text, insn, interp); +} + +u64 bpf_object__run_end (struct bpf_object *obj,struct bpf_interp *interp) +{ +struct bpf_program *prog = obj->text; +struct bpf_insn *insn = obj->insn_end; + +pr_debug ("running END(%p) for %s\n" , insn, prog->name); +return insn &&bpf_program__run (obj->text, insn, interp); +}
tools/lib/bpf/libbpf.h +4 -0
@@ -96,6 +96,10 @@ struct bpf_program;struct bpf_program *bpf_program__next (struct bpf_program *prog,struct bpf_object *obj); +struct bpf_interp ; +u64 bpf_object__run_begin (struct bpf_object *obj,struct bpf_interp *interp); +u64 bpf_object__run_end (struct bpf_object *obj,struct bpf_interp *interp); +#define bpf_object__for_each_program (pos, obj) \ for ((pos) = bpf_program__next(NULL, (obj)); \ (pos) != NULL; \
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 11/13 perf bpf: Add helper header files
In reply to Jiri OlsaAdding following header files with defines for kernel and user space ebpf calls:
bpf-helpers.h
bpf-userfuncs.h
bpf-userapi.h
--- tools/perf/util/bpf-helpers.h | 246 ++++++++++++++++++++++++++++++++++++++++ tools/perf/util/bpf-userapi.h | 11 ++ tools/perf/util/bpf-userfuncs.h | 19 ++++ 3 files changed, 276 insertions(+) create mode 100644 tools/perf/util/bpf-helpers.h create mode 100644 tools/perf/util/bpf-userapi.h create mode 100644 tools/perf/util/bpf-userfuncs.h
tools/perf/util/bpf-helpers.h new file +246 -0
@@ -0,0 +1,246 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __BPF_HELPERS_H +#define __BPF_HELPERS_H + +#include "bpf-userfuncs.h" + +/* +* helper macro to place programs, maps, license in +* different sections in elf_bpf file. Section names +* are interpreted by elf_bpf loader +*/ +#define SEC (NAME ) __attribute__((section(NAME), used)) + +/* helper functions called from eBPF programs written in C */ +static void *(*bpf_map_lookup_elem)(void *map,void *key) = + (void *) BPF_FUNC_map_lookup_elem; +static int (*bpf_map_update_elem)(void *map,void *key,void *value, +unsigned long long flags) = + (void *) BPF_FUNC_map_update_elem; +static int (*bpf_map_delete_elem)(void *map,void *key) = + (void *) BPF_FUNC_map_delete_elem; +static int (*bpf_probe_read)(void *dst,int size,void *unsafe_ptr) = + (void *) BPF_FUNC_probe_read; +static unsigned long long (*bpf_ktime_get_ns)(void ) = + (void *) BPF_FUNC_ktime_get_ns; +static int (*bpf_trace_printk)(const char *fmt,int fmt_size, ...) = + (void *) BPF_FUNC_trace_printk; +static void (*bpf_tail_call)(void *ctx,void *map,int index) = + (void *) BPF_FUNC_tail_call; +static unsigned long long (*bpf_get_smp_processor_id)(void ) = + (void *) BPF_FUNC_get_smp_processor_id; +static unsigned long long (*bpf_get_current_pid_tgid)(void ) = + (void *) BPF_FUNC_get_current_pid_tgid; +static unsigned long long (*bpf_get_current_uid_gid)(void ) = + (void *) BPF_FUNC_get_current_uid_gid; +static int (*bpf_get_current_comm)(void *buf,int buf_size) = + (void *) BPF_FUNC_get_current_comm; +static unsigned long long (*bpf_perf_event_read)(void *map, +unsigned long long flags) = + (void *) BPF_FUNC_perf_event_read; +static int (*bpf_clone_redirect)(void *ctx,int ifindex,int flags) = + (void *) BPF_FUNC_clone_redirect; +static int (*bpf_redirect)(int ifindex,int flags) = + (void *) BPF_FUNC_redirect; +static int (*bpf_redirect_map)(void *map,int key,int flags) = + (void *) BPF_FUNC_redirect_map; +static int (*bpf_perf_event_output)(void *ctx,void *map, +unsigned long long flags,void *data, +int size) = + (void *) BPF_FUNC_perf_event_output; +static int (*bpf_get_stackid)(void *ctx,void *map,int flags) = + (void *) BPF_FUNC_get_stackid; +static int (*bpf_probe_write_user)(void *dst,void *src,int size) = + (void *) BPF_FUNC_probe_write_user; +static int (*bpf_current_task_under_cgroup)(void *map,int index) = + (void *) BPF_FUNC_current_task_under_cgroup; +static int (*bpf_skb_get_tunnel_key)(void *ctx,void *key,int size,int flags) = + (void *) BPF_FUNC_skb_get_tunnel_key; +static int (*bpf_skb_set_tunnel_key)(void *ctx,void *key,int size,int flags) = + (void *) BPF_FUNC_skb_set_tunnel_key; +static int (*bpf_skb_get_tunnel_opt)(void *ctx,void *md,int size) = + (void *) BPF_FUNC_skb_get_tunnel_opt; +static int (*bpf_skb_set_tunnel_opt)(void *ctx,void *md,int size) = + (void *) BPF_FUNC_skb_set_tunnel_opt; +static unsigned long long (*bpf_get_prandom_u32)(void ) = + (void *) BPF_FUNC_get_prandom_u32; +static int (*bpf_xdp_adjust_head)(void *ctx,int offset) = + (void *) BPF_FUNC_xdp_adjust_head; +static int (*bpf_xdp_adjust_meta)(void *ctx,int offset) = + (void *) BPF_FUNC_xdp_adjust_meta; +static int (*bpf_setsockopt)(void *ctx,int level,int optname,void *optval, +int optlen) = + (void *) BPF_FUNC_setsockopt; +static int (*bpf_getsockopt)(void *ctx,int level,int optname,void *optval, +int optlen) = + (void *) BPF_FUNC_getsockopt; +static int (*bpf_sock_ops_cb_flags_set)(void *ctx,int flags) = + (void *) BPF_FUNC_sock_ops_cb_flags_set; +static int (*bpf_sk_redirect_map)(void *ctx,void *map,int key,int flags) = + (void *) BPF_FUNC_sk_redirect_map; +static int (*bpf_sock_map_update)(void *map,void *key,void *value, +unsigned long long flags) = + (void *) BPF_FUNC_sock_map_update; +static int (*bpf_perf_event_read_value)(void *map,unsigned long long flags, +void *buf,unsigned int buf_size) = + (void *) BPF_FUNC_perf_event_read_value; +static int (*bpf_perf_prog_read_value)(void *ctx,void *buf, +unsigned int buf_size) = + (void *) BPF_FUNC_perf_prog_read_value; +static int (*bpf_override_return)(void *ctx,unsigned long rc) = + (void *) BPF_FUNC_override_return; + +/* +* llvm builtin functions that eBPF C program may use to +* emit BPF_LD_ABS and BPF_LD_IND instructions +*/ +struct sk_buff ; +unsigned long long load_byte (void *skb, +unsigned long long off) asm("llvm.bpf.load.byte" ); +unsigned long long load_half (void *skb, +unsigned long long off) asm("llvm.bpf.load.half" ); +unsigned long long load_word (void *skb, +unsigned long long off) asm("llvm.bpf.load.word" ); + +/* +* a helper structure used by eBPF C program +* to describe map attributes to elf_bpf loader +*/ +struct bpf_map_def { +unsigned int type; +unsigned int key_size; +unsigned int value_size; +unsigned int max_entries; +unsigned int map_flags; +unsigned int inner_map_idx; +unsigned int numa_node; +}; + +static int (*bpf_skb_load_bytes)(void *ctx,int off,void *to,int len) = + (void *) BPF_FUNC_skb_load_bytes; +static int (*bpf_skb_store_bytes)(void *ctx,int off,void *from,int len,int flags) = + (void *) BPF_FUNC_skb_store_bytes; +static int (*bpf_l3_csum_replace)(void *ctx,int off,int from,int to,int flags) = + (void *) BPF_FUNC_l3_csum_replace; +static int (*bpf_l4_csum_replace)(void *ctx,int off,int from,int to,int flags) = + (void *) BPF_FUNC_l4_csum_replace; +static int (*bpf_skb_under_cgroup)(void *ctx,void *map,int index) = + (void *) BPF_FUNC_skb_under_cgroup; +static int (*bpf_skb_change_head)(void *,int len,int flags) = + (void *) BPF_FUNC_skb_change_head; + +/* Fall back to what the compiler says */ +#ifndef bpf_target_defined +#if defined(__x86_64__) +#define bpf_target_x86 +#elif defined(__s390x__) +#define bpf_target_s930x +#elif defined(__aarch64__) +#define bpf_target_arm64 +#elif defined(__mips__) +#define bpf_target_mips +#elif defined(__powerpc__) +#define bpf_target_powerpc +#elif defined(__sparc__) +#define bpf_target_sparc +#endif +#endif + +#if defined(bpf_target_x86) + +#define PT_REGS_PARM1 (x) ((x)->di) +#define PT_REGS_PARM2 (x) ((x)->si) +#define PT_REGS_PARM3 (x) ((x)->dx) +#define PT_REGS_PARM4 (x) ((x)->cx) +#define PT_REGS_PARM5 (x) ((x)->r8) +#define PT_REGS_RET (x) ((x)->sp) +#define PT_REGS_FP (x) ((x)->bp) +#define PT_REGS_RC (x) ((x)->ax) +#define PT_REGS_SP (x) ((x)->sp) +#define PT_REGS_IP (x) ((x)->ip) + +#elif defined(bpf_target_s390x) + +#define PT_REGS_PARM1 (x) ((x)->gprs[2]) +#define PT_REGS_PARM2 (x) ((x)->gprs[3]) +#define PT_REGS_PARM3 (x) ((x)->gprs[4]) +#define PT_REGS_PARM4 (x) ((x)->gprs[5]) +#define PT_REGS_PARM5 (x) ((x)->gprs[6]) +#define PT_REGS_RET (x) ((x)->gprs[14]) +#define PT_REGS_FP (x) ((x)->gprs[11])/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC (x) ((x)->gprs[2]) +#define PT_REGS_SP (x) ((x)->gprs[15]) +#define PT_REGS_IP (x) ((x)->psw.addr) + +#elif defined(bpf_target_arm64) + +#define PT_REGS_PARM1 (x) ((x)->regs[0]) +#define PT_REGS_PARM2 (x) ((x)->regs[1]) +#define PT_REGS_PARM3 (x) ((x)->regs[2]) +#define PT_REGS_PARM4 (x) ((x)->regs[3]) +#define PT_REGS_PARM5 (x) ((x)->regs[4]) +#define PT_REGS_RET (x) ((x)->regs[30]) +#define PT_REGS_FP (x) ((x)->regs[29])/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC (x) ((x)->regs[0]) +#define PT_REGS_SP (x) ((x)->sp) +#define PT_REGS_IP (x) ((x)->pc) + +#elif defined(bpf_target_mips) + +#define PT_REGS_PARM1 (x) ((x)->regs[4]) +#define PT_REGS_PARM2 (x) ((x)->regs[5]) +#define PT_REGS_PARM3 (x) ((x)->regs[6]) +#define PT_REGS_PARM4 (x) ((x)->regs[7]) +#define PT_REGS_PARM5 (x) ((x)->regs[8]) +#define PT_REGS_RET (x) ((x)->regs[31]) +#define PT_REGS_FP (x) ((x)->regs[30])/* Works only with CONFIG_FRAME_POINTER */ +#define PT_REGS_RC (x) ((x)->regs[1]) +#define PT_REGS_SP (x) ((x)->regs[29]) +#define PT_REGS_IP (x) ((x)->cp0_epc) + +#elif defined(bpf_target_powerpc) + +#define PT_REGS_PARM1 (x) ((x)->gpr[3]) +#define PT_REGS_PARM2 (x) ((x)->gpr[4]) +#define PT_REGS_PARM3 (x) ((x)->gpr[5]) +#define PT_REGS_PARM4 (x) ((x)->gpr[6]) +#define PT_REGS_PARM5 (x) ((x)->gpr[7]) +#define PT_REGS_RC (x) ((x)->gpr[3]) +#define PT_REGS_SP (x) ((x)->sp) +#define PT_REGS_IP (x) ((x)->nip) + +#elif defined(bpf_target_sparc) + +#define PT_REGS_PARM1 (x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_PARM2 (x) ((x)->u_regs[UREG_I1]) +#define PT_REGS_PARM3 (x) ((x)->u_regs[UREG_I2]) +#define PT_REGS_PARM4 (x) ((x)->u_regs[UREG_I3]) +#define PT_REGS_PARM5 (x) ((x)->u_regs[UREG_I4]) +#define PT_REGS_RET (x) ((x)->u_regs[UREG_I7]) +#define PT_REGS_RC (x) ((x)->u_regs[UREG_I0]) +#define PT_REGS_SP (x) ((x)->u_regs[UREG_FP]) + +/* Should this also be a bpf_target check for the sparc case? */ +#if defined(__arch64__) +#define PT_REGS_IP (x) ((x)->tpc) +#else +#define PT_REGS_IP (x) ((x)->pc) +#endif + +#endif + +#ifdef bpf_target_powerpc +#define BPF_KPROBE_READ_RET_IP (ip, ctx) ({ (ip) = (ctx)->link; }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#elif bpf_target_sparc +#define BPF_KPROBE_READ_RET_IP (ip, ctx) ({ (ip) = PT_REGS_RET(ctx); }) +#define BPF_KRETPROBE_READ_RET_IP BPF_KPROBE_READ_RET_IP +#else +#define BPF_KPROBE_READ_RET_IP (ip, ctx) ({ \ + bpf_probe_read(&(ip), sizeof(ip), (void *)PT_REGS_RET(ctx)); }) +#define BPF_KRETPROBE_READ_RET_IP (ip, ctx) ({ \ + bpf_probe_read(&(ip), sizeof(ip), \ + (void *)(PT_REGS_FP(ctx) + sizeof(ip))); }) +#endif + +#endif
tools/perf/util/bpf-userapi.h new file +11 -0
@@ -0,0 +1,11 @@ +#ifndef __BPF_USERAPI_H +#define __BPF_USERAPI_H + +enum { +BPF_FUNC_USER_START =10000 , + BPF_FUNC_USER_print =BPF_FUNC_USER_START , + BPF_FUNC_USER_bpf_map_get_next_key, + BPF_FUNC_USER_bpf_map_lookup_elem, +}; + +#endif /* __BPF_USERFUNCS_H */
tools/perf/util/bpf-userfuncs.h new file +19 -0
@@ -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 #endif /* __BPF_USERFUNCS_H */
Signature · 1 line
2.13.6
Re: [PATCH 11/13] perf bpf: Add helper header files
Quoted 30 lines · Jiri Olsa
tools/perf/util/bpf-userapi.h new file +11
-0@@ -0,0 +1,11 @@ +#ifndef __BPF_USERAPI_H +#define __BPF_USERAPI_H + +enum { +BPF_FUNC_USER_START =10000 , + BPF_FUNC_USER_print =BPF_FUNC_USER_START , + BPF_FUNC_USER_bpf_map_get_next_key, + BPF_FUNC_USER_bpf_map_lookup_elem, +}; + +#endif /* __BPF_USERFUNCS_H */ tools/perf/util/bpf-userfuncs.h new file +7
-0@@ -0,0 +1,19 @@ +#ifndef __BPF_USERFUNCS_H +#define __BPF_USERFUNCS_H + +#include <bpf-userapi.h> + +static int (*bpfu_print)(const char *fmt, ...) = + (void *) BPF_FUNC_USER_print;
tools/perf/util/bpf-userfuncs.h line 17
Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10
-0+static int (*bpfu_map_get_next_key)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_get_next_key; +static int (*bpfu_map_lookup_elem)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_lookup_elem; + +#define
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.
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 11/13] perf bpf: Add helper header files
Em Mon, Mar 12, 2018 at 11:44:57AM -0700, Alexei Starovoitov escreveu:
Quoted 44 lines · Jiri Olsa
Quoted 30 lines
tools/perf/util/bpf-userapi.h new file +11
-0@@ -0,0 +1,11 @@ +#ifndef __BPF_USERAPI_H +#define __BPF_USERAPI_H + +enum { +BPF_FUNC_USER_START =10000 , + BPF_FUNC_USER_print =BPF_FUNC_USER_START , + BPF_FUNC_USER_bpf_map_get_next_key, + BPF_FUNC_USER_bpf_map_lookup_elem, +}; + +#endif /* __BPF_USERFUNCS_H */ tools/perf/util/bpf-userfuncs.h new file +7
-0@@ -0,0 +1,19 @@ +#ifndef __BPF_USERFUNCS_H +#define __BPF_USERFUNCS_H + +#include <bpf-userapi.h> + +static int (*bpfu_print)(const char *fmt, ...) = + (void *) BPF_FUNC_USER_print;tools/perf/util/bpf-userfuncs.h line 17
Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10
-0+static int (*bpfu_map_get_next_key)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_get_next_key; +static int (*bpfu_map_lookup_elem)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_lookup_elem; + +#define since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call.
Quoted 8 lines
llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will seebpf_callinto normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and letcall_cbdo 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
Re: [PATCH 11/13] perf bpf: Add helper header files
In reply to Alexei StarovoitovQuoted 42 lines · Alexei Starovoitov
Quoted 30 lines · Jiri Olsa
tools/perf/util/bpf-userapi.h new file +11
-0@@ -0,0 +1,11 @@ +#ifndef __BPF_USERAPI_H +#define __BPF_USERAPI_H + +enum { +BPF_FUNC_USER_START =10000 , + BPF_FUNC_USER_print =BPF_FUNC_USER_START , + BPF_FUNC_USER_bpf_map_get_next_key, + BPF_FUNC_USER_bpf_map_lookup_elem, +}; + +#endif /* __BPF_USERFUNCS_H */ tools/perf/util/bpf-userfuncs.h new file +7
-0@@ -0,0 +1,19 @@ +#ifndef __BPF_USERFUNCS_H +#define __BPF_USERFUNCS_H + +#include <bpf-userapi.h> + +static int (*bpfu_print)(const char *fmt, ...) = + (void *) BPF_FUNC_USER_print;tools/perf/util/bpf-userfuncs.h line 17
Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10
-0+static int (*bpfu_map_get_next_key)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_get_next_key; +static int (*bpfu_map_lookup_elem)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_lookup_elem; + +#define
Quoted 8 lines
since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call. llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will seebpf_callinto normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and letcall_cbdo the call.
right, I kept this way, because it was already there for kernel, so it was fast to write ;-)
but it's true we could leave it symbol based and have some sort of dynamic loader behaviour.. but we'd need to sort out passing the arguments in some generic form.. I'll check on that
thanks,
jirka
Quoted 3 lines
I think this way begin/end will be much more powerful and useful. Potentially allowing some of the bcc scripts to be written this way.
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 11/13] perf bpf: Add helper header files
Em Mon, Mar 12, 2018 at 08:20:20PM +0100, Jiri Olsa escreveu:
Quoted 52 lines · Alexei Starovoitov
Quoted 42 lines · Jiri Olsa
Quoted 30 lines
tools/perf/util/bpf-userapi.h new file +11
-0@@ -0,0 +1,11 @@ +#ifndef __BPF_USERAPI_H +#define __BPF_USERAPI_H + +enum { +BPF_FUNC_USER_START =10000 , + BPF_FUNC_USER_print =BPF_FUNC_USER_START , + BPF_FUNC_USER_bpf_map_get_next_key, + BPF_FUNC_USER_bpf_map_lookup_elem, +}; + +#endif /* __BPF_USERFUNCS_H */ tools/perf/util/bpf-userfuncs.h new file +7
-0@@ -0,0 +1,19 @@ +#ifndef __BPF_USERFUNCS_H +#define __BPF_USERFUNCS_H + +#include <bpf-userapi.h> + +static int (*bpfu_print)(const char *fmt, ...) = + (void *) BPF_FUNC_USER_print;tools/perf/util/bpf-userfuncs.h line 17
Quoted 10 lines
tools/perf/util/bpf-userfuncs.h new file +10
-0+static int (*bpfu_map_get_next_key)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_get_next_key; +static int (*bpfu_map_lookup_elem)(void *map,void *key,void *value) = + (void *) BPF_FUNC_USER_bpf_map_lookup_elem; + +#define Quoted 8 lines
since there is no verifier for this user space bpf interpreter there is no need to restrict what BEGIN/END progs can do and can call. llvm will happily compile any C code into bpf instructions. With little bit of elf magic it's possible to let it call any libc function instead of only 3 above.
perf loader will seebpf_callinto normal printf, memcpy, memcmp, etc then during the loading need to associate symbol with actual address of these functions inside perf binary and letcall_cbdo the call.
Quoted 6 lines
right, I kept this way, because it was already there for kernel, so it was fast to write ;-)
but it's true we could leave it symbol based and have some sort of dynamic loader behaviour.. but we'd need to sort out passing the arguments in some generic form.. I'll check on that
Does this answer it or am I missing something?
Documentation/bpf/bpf_design_QA.txt
Q: Is BPF a generic virtual machine ?
A: NO.
BPF is generic instruction set _with_ C calling convention.
Q: Why C calling convention was chosen?
A: Because BPF programs are designed to run in the linux kernel
which is written in C, hence BPF defines instruction set compatible with two most used architectures x64 and arm64 (and takes into consideration important quirks of other architectures) and defines calling convention that is compatible with C calling convention of the linux kernel on those architectures.
- Arnaldo
Re: [PATCH 11/13] perf bpf: Add helper header files
On Mon, Mar 12, 2018 at 04:25:51PM -0300, Arnaldo Carvalho de Melo wrote:
SNIP
Quoted 17 lines
Quoted 7 lines
right, I kept this way, because it was already there for kernel, so it was fast to write ;-)
but it's true we could leave it symbol based and have some sort of dynamic loader behaviour.. but we'd need to sort out passing the arguments in some generic form.. I'll check on that
Does this answer it or am I missing something?
Documentation/bpf/bpf_design_QA.txtQ: Is BPF a generic virtual machine ?
A: NO.BPF is generic instruction set _with_ C calling convention.
Quoted 7 lines
Q: Why C calling convention was chosen?
A: Because BPF programs are designed to run in the linux kernel
which is written in C, hence BPF defines instruction set compatible with two most used architectures x64 and arm64 (and takes into consideration important quirks of other architectures) and defines calling convention that is compatible with C calling convention of the linux kernel on those architectures.
hm right, but still we interpret the calls.. so we have to call the function at the end
jirka
Arnaldo Carvalho de Melo
maintainerRe: [PATCH 11/13] perf bpf: Add helper header files
In reply to Jiri OlsaEm Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa escreveu:
tools/perf/util/bpf-helpers.h line 137
Quoted 2 lines
tools/perf/util/bpf-helpers.h new file +2
-0+#elif defined(__s390x__) +#define bpf_target_s930x
bpf_target_s390x
Quoted 10 lines
tools/perf/util/bpf-helpers.h new file +10
-0+#elif defined(__aarch64__) +#define bpf_target_arm64 +#elif defined(__mips__) +#define bpf_target_mips +#elif defined(__powerpc__) +#define bpf_target_powerpc +#elif defined(__sparc__) +#define bpf_target_sparc +#endif +#endif
Re: [PATCH 11/13] perf bpf: Add helper header files
Quoted 5 lines · Arnaldo Carvalho de Melo
Em Mon, Mar 12, 2018 at 10:43:11AM +0100, Jiri Olsa escreveu:
tools/perf/util/bpf-helpers.h line 137
Quoted 2 lines
tools/perf/util/bpf-helpers.h new file +2
-0+#elif defined(__s390x__) +#define bpf_target_s930xbpf_target_s390x
eagle eyes ;-) must be problem in samples/bpf where I stoled it from ;-)
thanks,
jirka
Quoted 11 lines
Quoted 11 lines
tools/perf/util/bpf-helpers.h new file +10
-0+#elif defined(__aarch64__) +#define bpf_target_arm64 +#elif defined(__mips__) +#define bpf_target_mips +#elif defined(__powerpc__) +#define bpf_target_powerpc +#elif defined(__sparc__) +#define bpf_target_sparc +#endif +#endif
Jiri Olsa
reviewerPATCH 12/13 perf bpf: Run begin/end programs
In reply to Jiri OlsaRunning begin and end programs for ebpf object.
--- tools/perf/builtin-bpf.c | 6 ++++ tools/perf/util/bpf-loader.c | 78 ++++++++++++++++++++++++++++++++++++++++++++ tools/perf/util/bpf-loader.h | 2 ++ 3 files changed, 86 insertions(+)
tools/perf/builtin-bpf.c +6 -0
@@ -94,6 +94,10 @@ static int __cmd_bpf(int argc , const char **argv) goto out_child; } + err =bpf__run_begin (stdout); +if (err) + goto out_child; +if (forks) {perf_evlist__start_workload (bpf.evlist);
@@ -115,6 +119,8 @@ static int __cmd_bpf(int argc , const char **argv) child_pid =-1 ; +bpf__run_end (stdout); + out_child:if (forks) {if (workload_exec_errno) {
tools/perf/util/bpf-loader.c +78 -0
96 lines not on this page · raw message
tools/perf/util/bpf-loader.h +2 -0
@@ -87,6 +87,8 @@ int bpf__setup_stdout(struct perf_evlist *evlist);int bpf__strerror_setup_stdout (struct perf_evlist *evlist,int err,char *buf,size_t size); +int bpf__run_begin (FILE *out); +int bpf__run_end (FILE *out);#else #include <errno.h>
Signature · 1 line
2.13.6
Jiri Olsa
reviewerPATCH 13/13 perf samples: Add syscall-count.c object
In reply to Jiri OlsaAdding syscall-count.c sample, that generates
syscall entry calls, like:
$ perf bpf -c samples/syscall-counts.c LLVM: dumping samples/syscall-counts.o
$ sudo perf bpf -e samples/syscall-counts.o -a
BEGIN
^CEND
comm value
firefox 182
Socket Thread 8
InotifyEventThr 26
xmonad-x86_64-l 405
perf 45122
VoiceProcessThr 12
JS Watchdog 14
Chrome_~dThread 657
Softwar~cThread 474
Gecko_IOThread 489
stalonetray 8
mutt 410
Xorg 956
xchat 37
nm-applet 14
xscreensaver 170
Timer 1205
NetworkManager 25
rtkit-daemon 4
webrtc_audio_mo 24
Web Content 6889
IPDL Background 474
JS Helper 221
gkrellm 434
xterm 528
InputThread 793--- tools/perf/samples/syscall-counts.c | 61 +++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 tools/perf/samples/syscall-counts.c
tools/perf/samples/syscall-counts.c new file +61 -0
@@ -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 ) +{ +"BEGIN\n" ); +return 0 ; +} + +void END (void ) +{ +struct key_t key = {}, next_key; +u64 value; +int i =0 ; + +"END\n" ); +"\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 ; + +"%18s %16lu\n" , next_key.comm, value); + key = next_key; + } +}
Signature · 1 line
2.13.6
adding Alexei and Wang to the loop
Quoted 172 lines · Jiri Olsa
hi,
this is *RFC* and the following patchset is very rough and ugly 'prove of concept'-kind-of-toy code. I'm mostly interested in opinions about if this could be useful in your current eBPF usage.Currently we can load eBPF code within the record command and attach it to event. We have 2 ways of communicating the data back to user: bpf-output event that goes to perf.data or '
trace_printk' output in tracefs buffer.AFAICS we're not covering quite large usage base that runs code before and once the probe is finished to setup, collect and display the collected data.
This patchset is adding support to run BEGIN and END code snipets before and after eBPF probe is loaded.
This allow to write 'collecting' code in eBPF object, like in the attached example (it's also part of the patchset).
This patchset also adds 'bpf' command to ease up the loading of eBPF files with options for compilation and disassembly of eBPF objects:
$ perf bpf -c samples/syscall-counts.c LLVM: dumping samples/syscall-counts.o$ perf bpf -d samples/syscall-counts.o | head Disassembly of raw_syscalls:sys_enter: 0: (b7) r1 = 1 b7 01 00 00 01 00 00 00 1: (7b) *(u64 *)(r10 -8) = r1 7b 1a f8 ff 00 00 00 00 2: (bf) r6 = r10 ...$ sudo perf bpf -e samples/syscall-counts.o -a BEGIN ^CEND comm value firefox 182 Socket Thread 8 InotifyEventThr 26 xmonad-x86_64-l 405 ...The patchset is also available in here:
https://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf.git
perf/bpfSo 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/utilthoughts? ;-) thanks,
jirkaCc Brendan Gregg <[email protected]>Cc Stanislav Kozina <[email protected]>Cc "Frank Ch. Eigler" <[email protected]>Cc Will Cohen <[email protected]>Cc Eugene Syromiatnikov <[email protected]>Cc Jerome Marchand <[email protected]>---
#include <uapi/linux/bpf.h>
#include <bpf-helpers.h>
#include <bpf-userfuncs.h>#define
TASK_COMM_LEN16char _license[]
SEC("license")= "GPL";
int_versionSEC("version")=LINUX_VERSION_CODE;struct key_t { char comm[TASK_COMM_LEN]; };struct
bpf_map_defSEC("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")
intfunc(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: Addbpf_program__insnsfunction
perf tools: Display ebpf compiling command in debug output perf tools: Add bpf command
perf tools: Addbpf__compilefunction
perf bpf: Add compile option
perf bpf: Add disasm option
libbpf: Makebpf_program__nextskip .text section
libbpf: Collect begin/end .text functions
libbpf: Addbpf_insn__interpretfunction
libbpf: Addbpf_object__run_(begin|end)functions perf bpf: Add helper header files
perf bpf: Run begin/end programs
perf samples: Addsyscall-count.cobjecttools/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
Arnaldo Carvalho de Melo
maintainerEm Mon, Mar 12, 2018 at 12:17:05PM +0100, Jiri Olsa escreveu:
Quoted 20 lines
adding Alexei and Wang to the loop
Quoted 17 lines · Jiri Olsa
hi,
this is *RFC* and the following patchset is very rough and ugly 'prove of concept'-kind-of-toy code. I'm mostly interested in opinions about if this could be useful in your current eBPF usage.Currently we can load eBPF code within the record command and attach it to event. We have 2 ways of communicating the data back to user: bpf-output event that goes to perf.data or '
trace_printk' output in tracefs buffer.AFAICS we're not covering quite large usage base that runs code before and once the probe is finished to setup, collect and display the collected data.
This patchset is adding support to run BEGIN and END code snipets before and after eBPF probe is loaded.
Right, with all the code that Wang contributed, and reusing that begin/end code from systemtap, it was easy to do it, not that much code added, so I don't see a reason for this not to be merged.
On top of this patchset, I think that the restricted C code that is used to write the eBPF utilities should be simplified, I've toyed with this from time to time, for instance:
[root@jouet bpf]# cat o_cloexec.c
#include "bpf.h"
#include "stdio.h"
#define O_CLOEXEC 0x80000
int syscall_enter(openat)
{
char filename[256];
int flags = syscall_field_int(flags, 32);
int len = syscall_field_str(filename, 24);
if (!(flags & O_CLOEXEC))
return 0;
perf_stdout(filename, len);
return 1;
}[root@jouet bpf]# perf trace -e openat,o_cloexec.c
0.573 ( ): __bpf_stdout__:/etc/ld.so.cache....)
0.576 ( ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de411563, flags: 0x00080000, mode: 0x00000000)
0.579 ( 0.013 ms): sh/17728 openat(dfd: CWD, filename: /etc/ld.so.cache, flags: CLOEXEC ) = 3
0.620 ( ): __bpf_stdout__:/lib64/libtinfo.so.6........)
0.622 ( ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de619ce0, flags: 0x00080000, mode: 0x00000000)
0.624 ( 0.013 ms): sh/17728 openat(dfd: CWD, filename: /lib64/libtinfo.so.6, flags: CLOEXEC ) = 3
0.705 ( ): __bpf_stdout__:/lib64/libdl.so.2...)
0.708 ( ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de5ef4c0, flags: 0x00080000, mode: 0x00000000)
0.710 ( 0.058 ms): sh/17728 openat(dfd: CWD, filename: /lib64/libdl.so.2, flags: CLOEXEC ) = 3
0.852 ( ): __bpf_stdout__:/lib64/libc.so.6....)
0.857 ( ): syscalls:sys_enter_openat:dfd: 0xffffffffffffff9c, filename: 0x7fc4de5ef9a0, flags: 0x00080000, mode: 0x00000000)
0.860 ( 0.021 ms): sh/17728 openat(dfd: CWD, filename: /lib64/libc.so.6, flags: CLOEXEC ) = 3^C
[root@jouet bpf]#
Hiding details such as:
[root@jouet bpf]# cat stdio.h
struct bpf_map_def SEC("maps") __bpf_stdout__ = {
.type = BPF_MAP_TYPE_PERF_EVENT_ARRAY,
.key_size = sizeof(int),
.value_size = sizeof(u32),
.max_entries = __NR_CPUS__,
};
#define perf_stdout(from, len) \ perf_event_output(ctx, &__bpf_stdout__, BPF_F_CURRENT_CPU, \ &from, len & (sizeof(from) - 1));
[root@jouet bpf]#
That 'perf trace' will setup "bpf_output" event, etc.
And the other macros:
#define SEC(NAME) __attribute__((section(NAME), used))
#define pid_map(name, value_type) \
struct bpf_map_def SEC("maps") name = { \
.type = BPF_MAP_TYPE_HASH, \
.key_size = sizeof(u64), \
.value_size = sizeof(value_type), \
.max_entries = 500, \
}#define syscall_enter(name) \
SEC("syscalls:sys_enter_" #name) syscall_enter_ ## name(void *ctx)
#define syscall_exit(name) \
SEC("syscalls:sys_exit_" #name) syscall_exit_ ## name(void *ctx)
#define syscall_field_str(field, offset) \
({ char *__ptr = *((char **)(ctx + offset)); \
bpf_probe_read_str(field, sizeof(field), __ptr); })#define syscall_field_int(field, offset) \
({ int *__ptr = (int *)(ctx + offset); \
bpf_probe_read(&field, sizeof(field), __ptr); field; }While this hides some of the details, it still hardcodes the offset, so should be used that way, I was trying to read about clang internals to do some preprocessing trick that would automagically make the tracepoint fields accessible as local variables, reading the tracepoint format files from the running system or from the description stored in the perf.data header, when running these things on perf.data files.
- Arnaldo