diff options
author | Ingo Molnar <mingo@kernel.org> | 2015-08-08 04:05:17 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2015-08-08 04:05:17 -0400 |
commit | f1d800bf615b84ca253af372d2dac8cdef743a20 (patch) | |
tree | 0ba71f573541cf42609230d8d96bc5e4c295536c | |
parent | 1354ac6ad84395660f551d0614a6ca39e5bfe8e3 (diff) | |
parent | 9bc898c7019383b6aa2ae6cb2928c4ca926449f0 (diff) |
Merge tag 'perf-ebpf-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/ebpf library + llvm/clang infrastructure changes from Arnaldo Carvalho de Melo:
Infrastructure changes:
- Add library for interfacing with the kernel eBPF infrastructure, with
tools/perf/ targeted as a first user. (Wang Nan)
- Add llvm/clang infrastructure for building BPF object files from C source
code. (Wang Nan)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/build/feature/Makefile | 6 | ||||
-rw-r--r-- | tools/build/feature/test-bpf.c | 18 | ||||
-rw-r--r-- | tools/lib/bpf/.gitignore | 2 | ||||
-rw-r--r-- | tools/lib/bpf/Build | 1 | ||||
-rw-r--r-- | tools/lib/bpf/Makefile | 195 | ||||
-rw-r--r-- | tools/lib/bpf/bpf.c | 85 | ||||
-rw-r--r-- | tools/lib/bpf/bpf.h | 23 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.c | 1037 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 81 | ||||
-rw-r--r-- | tools/perf/MANIFEST | 1 | ||||
-rw-r--r-- | tools/perf/tests/Build | 1 | ||||
-rw-r--r-- | tools/perf/tests/builtin-test.c | 4 | ||||
-rw-r--r-- | tools/perf/tests/llvm.c | 98 | ||||
-rw-r--r-- | tools/perf/tests/tests.h | 1 | ||||
-rw-r--r-- | tools/perf/util/Build | 1 | ||||
-rw-r--r-- | tools/perf/util/config.c | 4 | ||||
-rw-r--r-- | tools/perf/util/llvm-utils.c | 408 | ||||
-rw-r--r-- | tools/perf/util/llvm-utils.h | 49 |
18 files changed, 2014 insertions, 1 deletions
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index 463ed8f2a267..1c0d69f44552 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile | |||
@@ -33,7 +33,8 @@ FILES= \ | |||
33 | test-compile-32.bin \ | 33 | test-compile-32.bin \ |
34 | test-compile-x32.bin \ | 34 | test-compile-x32.bin \ |
35 | test-zlib.bin \ | 35 | test-zlib.bin \ |
36 | test-lzma.bin | 36 | test-lzma.bin \ |
37 | test-bpf.bin | ||
37 | 38 | ||
38 | CC := $(CROSS_COMPILE)gcc -MD | 39 | CC := $(CROSS_COMPILE)gcc -MD |
39 | PKG_CONFIG := $(CROSS_COMPILE)pkg-config | 40 | PKG_CONFIG := $(CROSS_COMPILE)pkg-config |
@@ -156,6 +157,9 @@ test-zlib.bin: | |||
156 | test-lzma.bin: | 157 | test-lzma.bin: |
157 | $(BUILD) -llzma | 158 | $(BUILD) -llzma |
158 | 159 | ||
160 | test-bpf.bin: | ||
161 | $(BUILD) | ||
162 | |||
159 | -include *.d | 163 | -include *.d |
160 | 164 | ||
161 | ############################### | 165 | ############################### |
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c new file mode 100644 index 000000000000..062bac811af9 --- /dev/null +++ b/tools/build/feature/test-bpf.c | |||
@@ -0,0 +1,18 @@ | |||
1 | #include <linux/bpf.h> | ||
2 | |||
3 | int main(void) | ||
4 | { | ||
5 | union bpf_attr attr; | ||
6 | |||
7 | attr.prog_type = BPF_PROG_TYPE_KPROBE; | ||
8 | attr.insn_cnt = 0; | ||
9 | attr.insns = 0; | ||
10 | attr.license = 0; | ||
11 | attr.log_buf = 0; | ||
12 | attr.log_size = 0; | ||
13 | attr.log_level = 0; | ||
14 | attr.kern_version = 0; | ||
15 | |||
16 | attr = attr; | ||
17 | return 0; | ||
18 | } | ||
diff --git a/tools/lib/bpf/.gitignore b/tools/lib/bpf/.gitignore new file mode 100644 index 000000000000..812aeedaea38 --- /dev/null +++ b/tools/lib/bpf/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | libbpf_version.h | ||
2 | FEATURE-DUMP | ||
diff --git a/tools/lib/bpf/Build b/tools/lib/bpf/Build new file mode 100644 index 000000000000..d8749756352d --- /dev/null +++ b/tools/lib/bpf/Build | |||
@@ -0,0 +1 @@ | |||
libbpf-y := libbpf.o bpf.o | |||
diff --git a/tools/lib/bpf/Makefile b/tools/lib/bpf/Makefile new file mode 100644 index 000000000000..f68d23a0b487 --- /dev/null +++ b/tools/lib/bpf/Makefile | |||
@@ -0,0 +1,195 @@ | |||
1 | # Most of this file is copied from tools/lib/traceevent/Makefile | ||
2 | |||
3 | BPF_VERSION = 0 | ||
4 | BPF_PATCHLEVEL = 0 | ||
5 | BPF_EXTRAVERSION = 1 | ||
6 | |||
7 | MAKEFLAGS += --no-print-directory | ||
8 | |||
9 | |||
10 | # Makefiles suck: This macro sets a default value of $(2) for the | ||
11 | # variable named by $(1), unless the variable has been set by | ||
12 | # environment or command line. This is necessary for CC and AR | ||
13 | # because make sets default values, so the simpler ?= approach | ||
14 | # won't work as expected. | ||
15 | define allow-override | ||
16 | $(if $(or $(findstring environment,$(origin $(1))),\ | ||
17 | $(findstring command line,$(origin $(1)))),,\ | ||
18 | $(eval $(1) = $(2))) | ||
19 | endef | ||
20 | |||
21 | # Allow setting CC and AR, or setting CROSS_COMPILE as a prefix. | ||
22 | $(call allow-override,CC,$(CROSS_COMPILE)gcc) | ||
23 | $(call allow-override,AR,$(CROSS_COMPILE)ar) | ||
24 | |||
25 | INSTALL = install | ||
26 | |||
27 | # Use DESTDIR for installing into a different root directory. | ||
28 | # This is useful for building a package. The program will be | ||
29 | # installed in this directory as if it was the root directory. | ||
30 | # Then the build tool can move it later. | ||
31 | DESTDIR ?= | ||
32 | DESTDIR_SQ = '$(subst ','\'',$(DESTDIR))' | ||
33 | |||
34 | LP64 := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1) | ||
35 | ifeq ($(LP64), 1) | ||
36 | libdir_relative = lib64 | ||
37 | else | ||
38 | libdir_relative = lib | ||
39 | endif | ||
40 | |||
41 | prefix ?= /usr/local | ||
42 | libdir = $(prefix)/$(libdir_relative) | ||
43 | man_dir = $(prefix)/share/man | ||
44 | man_dir_SQ = '$(subst ','\'',$(man_dir))' | ||
45 | |||
46 | export man_dir man_dir_SQ INSTALL | ||
47 | export DESTDIR DESTDIR_SQ | ||
48 | |||
49 | include ../../scripts/Makefile.include | ||
50 | |||
51 | # copy a bit from Linux kbuild | ||
52 | |||
53 | ifeq ("$(origin V)", "command line") | ||
54 | VERBOSE = $(V) | ||
55 | endif | ||
56 | ifndef VERBOSE | ||
57 | VERBOSE = 0 | ||
58 | endif | ||
59 | |||
60 | ifeq ($(srctree),) | ||
61 | srctree := $(patsubst %/,%,$(dir $(shell pwd))) | ||
62 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
63 | srctree := $(patsubst %/,%,$(dir $(srctree))) | ||
64 | #$(info Determined 'srctree' to be $(srctree)) | ||
65 | endif | ||
66 | |||
67 | FEATURE_DISPLAY = libelf libelf-getphdrnum libelf-mmap bpf | ||
68 | FEATURE_TESTS = libelf bpf | ||
69 | |||
70 | INCLUDES = -I. -I$(srctree)/tools/include -I$(srctree)/arch/$(ARCH)/include/uapi -I$(srctree)/include/uapi | ||
71 | FEATURE_CHECK_CFLAGS-bpf = $(INCLUDES) | ||
72 | |||
73 | include $(srctree)/tools/build/Makefile.feature | ||
74 | |||
75 | export prefix libdir src obj | ||
76 | |||
77 | # Shell quotes | ||
78 | libdir_SQ = $(subst ','\'',$(libdir)) | ||
79 | libdir_relative_SQ = $(subst ','\'',$(libdir_relative)) | ||
80 | plugin_dir_SQ = $(subst ','\'',$(plugin_dir)) | ||
81 | |||
82 | LIB_FILE = libbpf.a libbpf.so | ||
83 | |||
84 | VERSION = $(BPF_VERSION) | ||
85 | PATCHLEVEL = $(BPF_PATCHLEVEL) | ||
86 | EXTRAVERSION = $(BPF_EXTRAVERSION) | ||
87 | |||
88 | OBJ = $@ | ||
89 | N = | ||
90 | |||
91 | LIBBPF_VERSION = $(BPF_VERSION).$(BPF_PATCHLEVEL).$(BPF_EXTRAVERSION) | ||
92 | |||
93 | # Set compile option CFLAGS | ||
94 | ifdef EXTRA_CFLAGS | ||
95 | CFLAGS := $(EXTRA_CFLAGS) | ||
96 | else | ||
97 | CFLAGS := -g -Wall | ||
98 | endif | ||
99 | |||
100 | ifeq ($(feature-libelf-mmap), 1) | ||
101 | override CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT | ||
102 | endif | ||
103 | |||
104 | ifeq ($(feature-libelf-getphdrnum), 1) | ||
105 | override CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT | ||
106 | endif | ||
107 | |||
108 | # Append required CFLAGS | ||
109 | override CFLAGS += $(EXTRA_WARNINGS) | ||
110 | override CFLAGS += -Werror -Wall | ||
111 | override CFLAGS += -fPIC | ||
112 | override CFLAGS += $(INCLUDES) | ||
113 | |||
114 | ifeq ($(VERBOSE),1) | ||
115 | Q = | ||
116 | else | ||
117 | Q = @ | ||
118 | endif | ||
119 | |||
120 | # Disable command line variables (CFLAGS) overide from top | ||
121 | # level Makefile (perf), otherwise build Makefile will get | ||
122 | # the same command line setup. | ||
123 | MAKEOVERRIDES= | ||
124 | |||
125 | export srctree OUTPUT CC LD CFLAGS V | ||
126 | build := -f $(srctree)/tools/build/Makefile.build dir=. obj | ||
127 | |||
128 | BPF_IN := $(OUTPUT)libbpf-in.o | ||
129 | LIB_FILE := $(addprefix $(OUTPUT),$(LIB_FILE)) | ||
130 | |||
131 | CMD_TARGETS = $(LIB_FILE) | ||
132 | |||
133 | TARGETS = $(CMD_TARGETS) | ||
134 | |||
135 | all: $(VERSION_FILES) all_cmd | ||
136 | |||
137 | all_cmd: $(CMD_TARGETS) | ||
138 | |||
139 | $(BPF_IN): force elfdep bpfdep | ||
140 | $(Q)$(MAKE) $(build)=libbpf | ||
141 | |||
142 | $(OUTPUT)libbpf.so: $(BPF_IN) | ||
143 | $(QUIET_LINK)$(CC) --shared $^ -o $@ | ||
144 | |||
145 | $(OUTPUT)libbpf.a: $(BPF_IN) | ||
146 | $(QUIET_LINK)$(RM) $@; $(AR) rcs $@ $^ | ||
147 | |||
148 | define update_dir | ||
149 | (echo $1 > $@.tmp; \ | ||
150 | if [ -r $@ ] && cmp -s $@ $@.tmp; then \ | ||
151 | rm -f $@.tmp; \ | ||
152 | else \ | ||
153 | echo ' UPDATE $@'; \ | ||
154 | mv -f $@.tmp $@; \ | ||
155 | fi); | ||
156 | endef | ||
157 | |||
158 | define do_install | ||
159 | if [ ! -d '$(DESTDIR_SQ)$2' ]; then \ | ||
160 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$2'; \ | ||
161 | fi; \ | ||
162 | $(INSTALL) $1 '$(DESTDIR_SQ)$2' | ||
163 | endef | ||
164 | |||
165 | install_lib: all_cmd | ||
166 | $(call QUIET_INSTALL, $(LIB_FILE)) \ | ||
167 | $(call do_install,$(LIB_FILE),$(libdir_SQ)) | ||
168 | |||
169 | install: install_lib | ||
170 | |||
171 | ### Cleaning rules | ||
172 | |||
173 | config-clean: | ||
174 | $(call QUIET_CLEAN, config) | ||
175 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ clean >/dev/null | ||
176 | |||
177 | clean: | ||
178 | $(call QUIET_CLEAN, libbpf) $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d \ | ||
179 | $(RM) LIBBPF-CFLAGS | ||
180 | $(call QUIET_CLEAN, core-gen) $(RM) $(OUTPUT)FEATURE-DUMP | ||
181 | |||
182 | |||
183 | |||
184 | PHONY += force elfdep bpfdep | ||
185 | force: | ||
186 | |||
187 | elfdep: | ||
188 | @if [ "$(feature-libelf)" != "1" ]; then echo "No libelf found"; exit -1 ; fi | ||
189 | |||
190 | bpfdep: | ||
191 | @if [ "$(feature-bpf)" != "1" ]; then echo "BPF API too old"; exit -1 ; fi | ||
192 | |||
193 | # Declare the contents of the .PHONY variable as phony. We keep that | ||
194 | # information in a variable so we can use it in if_changed and friends. | ||
195 | .PHONY: $(PHONY) | ||
diff --git a/tools/lib/bpf/bpf.c b/tools/lib/bpf/bpf.c new file mode 100644 index 000000000000..a6331050ab79 --- /dev/null +++ b/tools/lib/bpf/bpf.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * common eBPF ELF operations. | ||
3 | * | ||
4 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> | ||
5 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | ||
6 | * Copyright (C) 2015 Huawei Inc. | ||
7 | */ | ||
8 | |||
9 | #include <stdlib.h> | ||
10 | #include <memory.h> | ||
11 | #include <unistd.h> | ||
12 | #include <asm/unistd.h> | ||
13 | #include <linux/bpf.h> | ||
14 | #include "bpf.h" | ||
15 | |||
16 | /* | ||
17 | * When building perf, unistd.h is override. Define __NR_bpf is | ||
18 | * required to be defined. | ||
19 | */ | ||
20 | #ifndef __NR_bpf | ||
21 | # if defined(__i386__) | ||
22 | # define __NR_bpf 357 | ||
23 | # elif defined(__x86_64__) | ||
24 | # define __NR_bpf 321 | ||
25 | # elif defined(__aarch64__) | ||
26 | # define __NR_bpf 280 | ||
27 | # else | ||
28 | # error __NR_bpf not defined. libbpf does not support your arch. | ||
29 | # endif | ||
30 | #endif | ||
31 | |||
32 | static __u64 ptr_to_u64(void *ptr) | ||
33 | { | ||
34 | return (__u64) (unsigned long) ptr; | ||
35 | } | ||
36 | |||
37 | static int sys_bpf(enum bpf_cmd cmd, union bpf_attr *attr, | ||
38 | unsigned int size) | ||
39 | { | ||
40 | return syscall(__NR_bpf, cmd, attr, size); | ||
41 | } | ||
42 | |||
43 | int bpf_create_map(enum bpf_map_type map_type, int key_size, | ||
44 | int value_size, int max_entries) | ||
45 | { | ||
46 | union bpf_attr attr; | ||
47 | |||
48 | memset(&attr, '\0', sizeof(attr)); | ||
49 | |||
50 | attr.map_type = map_type; | ||
51 | attr.key_size = key_size; | ||
52 | attr.value_size = value_size; | ||
53 | attr.max_entries = max_entries; | ||
54 | |||
55 | return sys_bpf(BPF_MAP_CREATE, &attr, sizeof(attr)); | ||
56 | } | ||
57 | |||
58 | int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, | ||
59 | size_t insns_cnt, char *license, | ||
60 | u32 kern_version, char *log_buf, size_t log_buf_sz) | ||
61 | { | ||
62 | int fd; | ||
63 | union bpf_attr attr; | ||
64 | |||
65 | bzero(&attr, sizeof(attr)); | ||
66 | attr.prog_type = type; | ||
67 | attr.insn_cnt = (__u32)insns_cnt; | ||
68 | attr.insns = ptr_to_u64(insns); | ||
69 | attr.license = ptr_to_u64(license); | ||
70 | attr.log_buf = ptr_to_u64(NULL); | ||
71 | attr.log_size = 0; | ||
72 | attr.log_level = 0; | ||
73 | attr.kern_version = kern_version; | ||
74 | |||
75 | fd = sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
76 | if (fd >= 0 || !log_buf || !log_buf_sz) | ||
77 | return fd; | ||
78 | |||
79 | /* Try again with log */ | ||
80 | attr.log_buf = ptr_to_u64(log_buf); | ||
81 | attr.log_size = log_buf_sz; | ||
82 | attr.log_level = 1; | ||
83 | log_buf[0] = 0; | ||
84 | return sys_bpf(BPF_PROG_LOAD, &attr, sizeof(attr)); | ||
85 | } | ||
diff --git a/tools/lib/bpf/bpf.h b/tools/lib/bpf/bpf.h new file mode 100644 index 000000000000..854b7361b784 --- /dev/null +++ b/tools/lib/bpf/bpf.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* | ||
2 | * common eBPF ELF operations. | ||
3 | * | ||
4 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> | ||
5 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | ||
6 | * Copyright (C) 2015 Huawei Inc. | ||
7 | */ | ||
8 | #ifndef __BPF_BPF_H | ||
9 | #define __BPF_BPF_H | ||
10 | |||
11 | #include <linux/bpf.h> | ||
12 | |||
13 | int bpf_create_map(enum bpf_map_type map_type, int key_size, int value_size, | ||
14 | int max_entries); | ||
15 | |||
16 | /* Recommend log buffer size */ | ||
17 | #define BPF_LOG_BUF_SIZE 65536 | ||
18 | int bpf_load_program(enum bpf_prog_type type, struct bpf_insn *insns, | ||
19 | size_t insns_cnt, char *license, | ||
20 | u32 kern_version, char *log_buf, | ||
21 | size_t log_buf_sz); | ||
22 | |||
23 | #endif | ||
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c new file mode 100644 index 000000000000..4fa4bc4505f5 --- /dev/null +++ b/tools/lib/bpf/libbpf.c | |||
@@ -0,0 +1,1037 @@ | |||
1 | /* | ||
2 | * Common eBPF ELF object loading operations. | ||
3 | * | ||
4 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> | ||
5 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | ||
6 | * Copyright (C) 2015 Huawei Inc. | ||
7 | */ | ||
8 | |||
9 | #include <stdlib.h> | ||
10 | #include <stdio.h> | ||
11 | #include <stdarg.h> | ||
12 | #include <inttypes.h> | ||
13 | #include <string.h> | ||
14 | #include <unistd.h> | ||
15 | #include <fcntl.h> | ||
16 | #include <errno.h> | ||
17 | #include <asm/unistd.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/bpf.h> | ||
20 | #include <linux/list.h> | ||
21 | #include <libelf.h> | ||
22 | #include <gelf.h> | ||
23 | |||
24 | #include "libbpf.h" | ||
25 | #include "bpf.h" | ||
26 | |||
27 | #define __printf(a, b) __attribute__((format(printf, a, b))) | ||
28 | |||
29 | __printf(1, 2) | ||
30 | static int __base_pr(const char *format, ...) | ||
31 | { | ||
32 | va_list args; | ||
33 | int err; | ||
34 | |||
35 | va_start(args, format); | ||
36 | err = vfprintf(stderr, format, args); | ||
37 | va_end(args); | ||
38 | return err; | ||
39 | } | ||
40 | |||
41 | static __printf(1, 2) libbpf_print_fn_t __pr_warning = __base_pr; | ||
42 | static __printf(1, 2) libbpf_print_fn_t __pr_info = __base_pr; | ||
43 | static __printf(1, 2) libbpf_print_fn_t __pr_debug; | ||
44 | |||
45 | #define __pr(func, fmt, ...) \ | ||
46 | do { \ | ||
47 | if ((func)) \ | ||
48 | (func)("libbpf: " fmt, ##__VA_ARGS__); \ | ||
49 | } while (0) | ||
50 | |||
51 | #define pr_warning(fmt, ...) __pr(__pr_warning, fmt, ##__VA_ARGS__) | ||
52 | #define pr_info(fmt, ...) __pr(__pr_info, fmt, ##__VA_ARGS__) | ||
53 | #define pr_debug(fmt, ...) __pr(__pr_debug, fmt, ##__VA_ARGS__) | ||
54 | |||
55 | void libbpf_set_print(libbpf_print_fn_t warn, | ||
56 | libbpf_print_fn_t info, | ||
57 | libbpf_print_fn_t debug) | ||
58 | { | ||
59 | __pr_warning = warn; | ||
60 | __pr_info = info; | ||
61 | __pr_debug = debug; | ||
62 | } | ||
63 | |||
64 | /* Copied from tools/perf/util/util.h */ | ||
65 | #ifndef zfree | ||
66 | # define zfree(ptr) ({ free(*ptr); *ptr = NULL; }) | ||
67 | #endif | ||
68 | |||
69 | #ifndef zclose | ||
70 | # define zclose(fd) ({ \ | ||
71 | int ___err = 0; \ | ||
72 | if ((fd) >= 0) \ | ||
73 | ___err = close((fd)); \ | ||
74 | fd = -1; \ | ||
75 | ___err; }) | ||
76 | #endif | ||
77 | |||
78 | #ifdef HAVE_LIBELF_MMAP_SUPPORT | ||
79 | # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ_MMAP | ||
80 | #else | ||
81 | # define LIBBPF_ELF_C_READ_MMAP ELF_C_READ | ||
82 | #endif | ||
83 | |||
84 | /* | ||
85 | * bpf_prog should be a better name but it has been used in | ||
86 | * linux/filter.h. | ||
87 | */ | ||
88 | struct bpf_program { | ||
89 | /* Index in elf obj file, for relocation use. */ | ||
90 | int idx; | ||
91 | char *section_name; | ||
92 | struct bpf_insn *insns; | ||
93 | size_t insns_cnt; | ||
94 | |||
95 | struct { | ||
96 | int insn_idx; | ||
97 | int map_idx; | ||
98 | } *reloc_desc; | ||
99 | int nr_reloc; | ||
100 | |||
101 | int fd; | ||
102 | |||
103 | struct bpf_object *obj; | ||
104 | void *priv; | ||
105 | bpf_program_clear_priv_t clear_priv; | ||
106 | }; | ||
107 | |||
108 | static LIST_HEAD(bpf_objects_list); | ||
109 | |||
110 | struct bpf_object { | ||
111 | char license[64]; | ||
112 | u32 kern_version; | ||
113 | void *maps_buf; | ||
114 | size_t maps_buf_sz; | ||
115 | |||
116 | struct bpf_program *programs; | ||
117 | size_t nr_programs; | ||
118 | int *map_fds; | ||
119 | /* | ||
120 | * This field is required because maps_buf will be freed and | ||
121 | * maps_buf_sz will be set to 0 after loaded. | ||
122 | */ | ||
123 | size_t nr_map_fds; | ||
124 | bool loaded; | ||
125 | |||
126 | /* | ||
127 | * Information when doing elf related work. Only valid if fd | ||
128 | * is valid. | ||
129 | */ | ||
130 | struct { | ||
131 | int fd; | ||
132 | void *obj_buf; | ||
133 | size_t obj_buf_sz; | ||
134 | Elf *elf; | ||
135 | GElf_Ehdr ehdr; | ||
136 | Elf_Data *symbols; | ||
137 | struct { | ||
138 | GElf_Shdr shdr; | ||
139 | Elf_Data *data; | ||
140 | } *reloc; | ||
141 | int nr_reloc; | ||
142 | } efile; | ||
143 | /* | ||
144 | * All loaded bpf_object is linked in a list, which is | ||
145 | * hidden to caller. bpf_objects__<func> handlers deal with | ||
146 | * all objects. | ||
147 | */ | ||
148 | struct list_head list; | ||
149 | char path[]; | ||
150 | }; | ||
151 | #define obj_elf_valid(o) ((o)->efile.elf) | ||
152 | |||
153 | static void bpf_program__unload(struct bpf_program *prog) | ||
154 | { | ||
155 | if (!prog) | ||
156 | return; | ||
157 | |||
158 | zclose(prog->fd); | ||
159 | } | ||
160 | |||
161 | static void bpf_program__exit(struct bpf_program *prog) | ||
162 | { | ||
163 | if (!prog) | ||
164 | return; | ||
165 | |||
166 | if (prog->clear_priv) | ||
167 | prog->clear_priv(prog, prog->priv); | ||
168 | |||
169 | prog->priv = NULL; | ||
170 | prog->clear_priv = NULL; | ||
171 | |||
172 | bpf_program__unload(prog); | ||
173 | zfree(&prog->section_name); | ||
174 | zfree(&prog->insns); | ||
175 | zfree(&prog->reloc_desc); | ||
176 | |||
177 | prog->nr_reloc = 0; | ||
178 | prog->insns_cnt = 0; | ||
179 | prog->idx = -1; | ||
180 | } | ||
181 | |||
182 | static int | ||
183 | bpf_program__init(void *data, size_t size, char *name, int idx, | ||
184 | struct bpf_program *prog) | ||
185 | { | ||
186 | if (size < sizeof(struct bpf_insn)) { | ||
187 | pr_warning("corrupted section '%s'\n", name); | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | |||
191 | bzero(prog, sizeof(*prog)); | ||
192 | |||
193 | prog->section_name = strdup(name); | ||
194 | if (!prog->section_name) { | ||
195 | pr_warning("failed to alloc name for prog %s\n", | ||
196 | name); | ||
197 | goto errout; | ||
198 | } | ||
199 | |||
200 | prog->insns = malloc(size); | ||
201 | if (!prog->insns) { | ||
202 | pr_warning("failed to alloc insns for %s\n", name); | ||
203 | goto errout; | ||
204 | } | ||
205 | prog->insns_cnt = size / sizeof(struct bpf_insn); | ||
206 | memcpy(prog->insns, data, | ||
207 | prog->insns_cnt * sizeof(struct bpf_insn)); | ||
208 | prog->idx = idx; | ||
209 | prog->fd = -1; | ||
210 | |||
211 | return 0; | ||
212 | errout: | ||
213 | bpf_program__exit(prog); | ||
214 | return -ENOMEM; | ||
215 | } | ||
216 | |||
217 | static int | ||
218 | bpf_object__add_program(struct bpf_object *obj, void *data, size_t size, | ||
219 | char *name, int idx) | ||
220 | { | ||
221 | struct bpf_program prog, *progs; | ||
222 | int nr_progs, err; | ||
223 | |||
224 | err = bpf_program__init(data, size, name, idx, &prog); | ||
225 | if (err) | ||
226 | return err; | ||
227 | |||
228 | progs = obj->programs; | ||
229 | nr_progs = obj->nr_programs; | ||
230 | |||
231 | progs = realloc(progs, sizeof(progs[0]) * (nr_progs + 1)); | ||
232 | if (!progs) { | ||
233 | /* | ||
234 | * In this case the original obj->programs | ||
235 | * is still valid, so don't need special treat for | ||
236 | * bpf_close_object(). | ||
237 | */ | ||
238 | pr_warning("failed to alloc a new program '%s'\n", | ||
239 | name); | ||
240 | bpf_program__exit(&prog); | ||
241 | return -ENOMEM; | ||
242 | } | ||
243 | |||
244 | pr_debug("found program %s\n", prog.section_name); | ||
245 | obj->programs = progs; | ||
246 | obj->nr_programs = nr_progs + 1; | ||
247 | prog.obj = obj; | ||
248 | progs[nr_progs] = prog; | ||
249 | return 0; | ||
250 | } | ||
251 | |||
252 | static struct bpf_object *bpf_object__new(const char *path, | ||
253 | void *obj_buf, | ||
254 | size_t obj_buf_sz) | ||
255 | { | ||
256 | struct bpf_object *obj; | ||
257 | |||
258 | obj = calloc(1, sizeof(struct bpf_object) + strlen(path) + 1); | ||
259 | if (!obj) { | ||
260 | pr_warning("alloc memory failed for %s\n", path); | ||
261 | return NULL; | ||
262 | } | ||
263 | |||
264 | strcpy(obj->path, path); | ||
265 | obj->efile.fd = -1; | ||
266 | |||
267 | /* | ||
268 | * Caller of this function should also calls | ||
269 | * bpf_object__elf_finish() after data collection to return | ||
270 | * obj_buf to user. If not, we should duplicate the buffer to | ||
271 | * avoid user freeing them before elf finish. | ||
272 | */ | ||
273 | obj->efile.obj_buf = obj_buf; | ||
274 | obj->efile.obj_buf_sz = obj_buf_sz; | ||
275 | |||
276 | obj->loaded = false; | ||
277 | |||
278 | INIT_LIST_HEAD(&obj->list); | ||
279 | list_add(&obj->list, &bpf_objects_list); | ||
280 | return obj; | ||
281 | } | ||
282 | |||
283 | static void bpf_object__elf_finish(struct bpf_object *obj) | ||
284 | { | ||
285 | if (!obj_elf_valid(obj)) | ||
286 | return; | ||
287 | |||
288 | if (obj->efile.elf) { | ||
289 | elf_end(obj->efile.elf); | ||
290 | obj->efile.elf = NULL; | ||
291 | } | ||
292 | obj->efile.symbols = NULL; | ||
293 | |||
294 | zfree(&obj->efile.reloc); | ||
295 | obj->efile.nr_reloc = 0; | ||
296 | zclose(obj->efile.fd); | ||
297 | obj->efile.obj_buf = NULL; | ||
298 | obj->efile.obj_buf_sz = 0; | ||
299 | } | ||
300 | |||
301 | static int bpf_object__elf_init(struct bpf_object *obj) | ||
302 | { | ||
303 | int err = 0; | ||
304 | GElf_Ehdr *ep; | ||
305 | |||
306 | if (obj_elf_valid(obj)) { | ||
307 | pr_warning("elf init: internal error\n"); | ||
308 | return -EEXIST; | ||
309 | } | ||
310 | |||
311 | if (obj->efile.obj_buf_sz > 0) { | ||
312 | /* | ||
313 | * obj_buf should have been validated by | ||
314 | * bpf_object__open_buffer(). | ||
315 | */ | ||
316 | obj->efile.elf = elf_memory(obj->efile.obj_buf, | ||
317 | obj->efile.obj_buf_sz); | ||
318 | } else { | ||
319 | obj->efile.fd = open(obj->path, O_RDONLY); | ||
320 | if (obj->efile.fd < 0) { | ||
321 | pr_warning("failed to open %s: %s\n", obj->path, | ||
322 | strerror(errno)); | ||
323 | return -errno; | ||
324 | } | ||
325 | |||
326 | obj->efile.elf = elf_begin(obj->efile.fd, | ||
327 | LIBBPF_ELF_C_READ_MMAP, | ||
328 | NULL); | ||
329 | } | ||
330 | |||
331 | if (!obj->efile.elf) { | ||
332 | pr_warning("failed to open %s as ELF file\n", | ||
333 | obj->path); | ||
334 | err = -EINVAL; | ||
335 | goto errout; | ||
336 | } | ||
337 | |||
338 | if (!gelf_getehdr(obj->efile.elf, &obj->efile.ehdr)) { | ||
339 | pr_warning("failed to get EHDR from %s\n", | ||
340 | obj->path); | ||
341 | err = -EINVAL; | ||
342 | goto errout; | ||
343 | } | ||
344 | ep = &obj->efile.ehdr; | ||
345 | |||
346 | if ((ep->e_type != ET_REL) || (ep->e_machine != 0)) { | ||
347 | pr_warning("%s is not an eBPF object file\n", | ||
348 | obj->path); | ||
349 | err = -EINVAL; | ||
350 | goto errout; | ||
351 | } | ||
352 | |||
353 | return 0; | ||
354 | errout: | ||
355 | bpf_object__elf_finish(obj); | ||
356 | return err; | ||
357 | } | ||
358 | |||
359 | static int | ||
360 | bpf_object__check_endianness(struct bpf_object *obj) | ||
361 | { | ||
362 | static unsigned int const endian = 1; | ||
363 | |||
364 | switch (obj->efile.ehdr.e_ident[EI_DATA]) { | ||
365 | case ELFDATA2LSB: | ||
366 | /* We are big endian, BPF obj is little endian. */ | ||
367 | if (*(unsigned char const *)&endian != 1) | ||
368 | goto mismatch; | ||
369 | break; | ||
370 | |||
371 | case ELFDATA2MSB: | ||
372 | /* We are little endian, BPF obj is big endian. */ | ||
373 | if (*(unsigned char const *)&endian != 0) | ||
374 | goto mismatch; | ||
375 | break; | ||
376 | default: | ||
377 | return -EINVAL; | ||
378 | } | ||
379 | |||
380 | return 0; | ||
381 | |||
382 | mismatch: | ||
383 | pr_warning("Error: endianness mismatch.\n"); | ||
384 | return -EINVAL; | ||
385 | } | ||
386 | |||
387 | static int | ||
388 | bpf_object__init_license(struct bpf_object *obj, | ||
389 | void *data, size_t size) | ||
390 | { | ||
391 | memcpy(obj->license, data, | ||
392 | min(size, sizeof(obj->license) - 1)); | ||
393 | pr_debug("license of %s is %s\n", obj->path, obj->license); | ||
394 | return 0; | ||
395 | } | ||
396 | |||
397 | static int | ||
398 | bpf_object__init_kversion(struct bpf_object *obj, | ||
399 | void *data, size_t size) | ||
400 | { | ||
401 | u32 kver; | ||
402 | |||
403 | if (size != sizeof(kver)) { | ||
404 | pr_warning("invalid kver section in %s\n", obj->path); | ||
405 | return -EINVAL; | ||
406 | } | ||
407 | memcpy(&kver, data, sizeof(kver)); | ||
408 | obj->kern_version = kver; | ||
409 | pr_debug("kernel version of %s is %x\n", obj->path, | ||
410 | obj->kern_version); | ||
411 | return 0; | ||
412 | } | ||
413 | |||
414 | static int | ||
415 | bpf_object__init_maps(struct bpf_object *obj, void *data, | ||
416 | size_t size) | ||
417 | { | ||
418 | if (size == 0) { | ||
419 | pr_debug("%s doesn't need map definition\n", | ||
420 | obj->path); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | obj->maps_buf = malloc(size); | ||
425 | if (!obj->maps_buf) { | ||
426 | pr_warning("malloc maps failed: %s\n", obj->path); | ||
427 | return -ENOMEM; | ||
428 | } | ||
429 | |||
430 | obj->maps_buf_sz = size; | ||
431 | memcpy(obj->maps_buf, data, size); | ||
432 | pr_debug("maps in %s: %ld bytes\n", obj->path, (long)size); | ||
433 | return 0; | ||
434 | } | ||
435 | |||
436 | static int bpf_object__elf_collect(struct bpf_object *obj) | ||
437 | { | ||
438 | Elf *elf = obj->efile.elf; | ||
439 | GElf_Ehdr *ep = &obj->efile.ehdr; | ||
440 | Elf_Scn *scn = NULL; | ||
441 | int idx = 0, err = 0; | ||
442 | |||
443 | /* Elf is corrupted/truncated, avoid calling elf_strptr. */ | ||
444 | if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL)) { | ||
445 | pr_warning("failed to get e_shstrndx from %s\n", | ||
446 | obj->path); | ||
447 | return -EINVAL; | ||
448 | } | ||
449 | |||
450 | while ((scn = elf_nextscn(elf, scn)) != NULL) { | ||
451 | char *name; | ||
452 | GElf_Shdr sh; | ||
453 | Elf_Data *data; | ||
454 | |||
455 | idx++; | ||
456 | if (gelf_getshdr(scn, &sh) != &sh) { | ||
457 | pr_warning("failed to get section header from %s\n", | ||
458 | obj->path); | ||
459 | err = -EINVAL; | ||
460 | goto out; | ||
461 | } | ||
462 | |||
463 | name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name); | ||
464 | if (!name) { | ||
465 | pr_warning("failed to get section name from %s\n", | ||
466 | obj->path); | ||
467 | err = -EINVAL; | ||
468 | goto out; | ||
469 | } | ||
470 | |||
471 | data = elf_getdata(scn, 0); | ||
472 | if (!data) { | ||
473 | pr_warning("failed to get section data from %s(%s)\n", | ||
474 | name, obj->path); | ||
475 | err = -EINVAL; | ||
476 | goto out; | ||
477 | } | ||
478 | pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n", | ||
479 | name, (unsigned long)data->d_size, | ||
480 | (int)sh.sh_link, (unsigned long)sh.sh_flags, | ||
481 | (int)sh.sh_type); | ||
482 | |||
483 | if (strcmp(name, "license") == 0) | ||
484 | err = bpf_object__init_license(obj, | ||
485 | data->d_buf, | ||
486 | data->d_size); | ||
487 | else if (strcmp(name, "version") == 0) | ||
488 | err = bpf_object__init_kversion(obj, | ||
489 | data->d_buf, | ||
490 | data->d_size); | ||
491 | else if (strcmp(name, "maps") == 0) | ||
492 | err = bpf_object__init_maps(obj, data->d_buf, | ||
493 | data->d_size); | ||
494 | else if (sh.sh_type == SHT_SYMTAB) { | ||
495 | if (obj->efile.symbols) { | ||
496 | pr_warning("bpf: multiple SYMTAB in %s\n", | ||
497 | obj->path); | ||
498 | err = -EEXIST; | ||
499 | } else | ||
500 | obj->efile.symbols = data; | ||
501 | } else if ((sh.sh_type == SHT_PROGBITS) && | ||
502 | (sh.sh_flags & SHF_EXECINSTR) && | ||
503 | (data->d_size > 0)) { | ||
504 | err = bpf_object__add_program(obj, data->d_buf, | ||
505 | data->d_size, name, idx); | ||
506 | if (err) { | ||
507 | char errmsg[128]; | ||
508 | strerror_r(-err, errmsg, sizeof(errmsg)); | ||
509 | pr_warning("failed to alloc program %s (%s): %s", | ||
510 | name, obj->path, errmsg); | ||
511 | } | ||
512 | } else if (sh.sh_type == SHT_REL) { | ||
513 | void *reloc = obj->efile.reloc; | ||
514 | int nr_reloc = obj->efile.nr_reloc + 1; | ||
515 | |||
516 | reloc = realloc(reloc, | ||
517 | sizeof(*obj->efile.reloc) * nr_reloc); | ||
518 | if (!reloc) { | ||
519 | pr_warning("realloc failed\n"); | ||
520 | err = -ENOMEM; | ||
521 | } else { | ||
522 | int n = nr_reloc - 1; | ||
523 | |||
524 | obj->efile.reloc = reloc; | ||
525 | obj->efile.nr_reloc = nr_reloc; | ||
526 | |||
527 | obj->efile.reloc[n].shdr = sh; | ||
528 | obj->efile.reloc[n].data = data; | ||
529 | } | ||
530 | } | ||
531 | if (err) | ||
532 | goto out; | ||
533 | } | ||
534 | out: | ||
535 | return err; | ||
536 | } | ||
537 | |||
538 | static struct bpf_program * | ||
539 | bpf_object__find_prog_by_idx(struct bpf_object *obj, int idx) | ||
540 | { | ||
541 | struct bpf_program *prog; | ||
542 | size_t i; | ||
543 | |||
544 | for (i = 0; i < obj->nr_programs; i++) { | ||
545 | prog = &obj->programs[i]; | ||
546 | if (prog->idx == idx) | ||
547 | return prog; | ||
548 | } | ||
549 | return NULL; | ||
550 | } | ||
551 | |||
552 | static int | ||
553 | bpf_program__collect_reloc(struct bpf_program *prog, | ||
554 | size_t nr_maps, GElf_Shdr *shdr, | ||
555 | Elf_Data *data, Elf_Data *symbols) | ||
556 | { | ||
557 | int i, nrels; | ||
558 | |||
559 | pr_debug("collecting relocating info for: '%s'\n", | ||
560 | prog->section_name); | ||
561 | nrels = shdr->sh_size / shdr->sh_entsize; | ||
562 | |||
563 | prog->reloc_desc = malloc(sizeof(*prog->reloc_desc) * nrels); | ||
564 | if (!prog->reloc_desc) { | ||
565 | pr_warning("failed to alloc memory in relocation\n"); | ||
566 | return -ENOMEM; | ||
567 | } | ||
568 | prog->nr_reloc = nrels; | ||
569 | |||
570 | for (i = 0; i < nrels; i++) { | ||
571 | GElf_Sym sym; | ||
572 | GElf_Rel rel; | ||
573 | unsigned int insn_idx; | ||
574 | struct bpf_insn *insns = prog->insns; | ||
575 | size_t map_idx; | ||
576 | |||
577 | if (!gelf_getrel(data, i, &rel)) { | ||
578 | pr_warning("relocation: failed to get %d reloc\n", i); | ||
579 | return -EINVAL; | ||
580 | } | ||
581 | |||
582 | insn_idx = rel.r_offset / sizeof(struct bpf_insn); | ||
583 | pr_debug("relocation: insn_idx=%u\n", insn_idx); | ||
584 | |||
585 | if (!gelf_getsym(symbols, | ||
586 | GELF_R_SYM(rel.r_info), | ||
587 | &sym)) { | ||
588 | pr_warning("relocation: symbol %"PRIx64" not found\n", | ||
589 | GELF_R_SYM(rel.r_info)); | ||
590 | return -EINVAL; | ||
591 | } | ||
592 | |||
593 | if (insns[insn_idx].code != (BPF_LD | BPF_IMM | BPF_DW)) { | ||
594 | pr_warning("bpf: relocation: invalid relo for insns[%d].code 0x%x\n", | ||
595 | insn_idx, insns[insn_idx].code); | ||
596 | return -EINVAL; | ||
597 | } | ||
598 | |||
599 | map_idx = sym.st_value / sizeof(struct bpf_map_def); | ||
600 | if (map_idx >= nr_maps) { | ||
601 | pr_warning("bpf relocation: map_idx %d large than %d\n", | ||
602 | (int)map_idx, (int)nr_maps - 1); | ||
603 | return -EINVAL; | ||
604 | } | ||
605 | |||
606 | prog->reloc_desc[i].insn_idx = insn_idx; | ||
607 | prog->reloc_desc[i].map_idx = map_idx; | ||
608 | } | ||
609 | return 0; | ||
610 | } | ||
611 | |||
612 | static int | ||
613 | bpf_object__create_maps(struct bpf_object *obj) | ||
614 | { | ||
615 | unsigned int i; | ||
616 | size_t nr_maps; | ||
617 | int *pfd; | ||
618 | |||
619 | nr_maps = obj->maps_buf_sz / sizeof(struct bpf_map_def); | ||
620 | if (!obj->maps_buf || !nr_maps) { | ||
621 | pr_debug("don't need create maps for %s\n", | ||
622 | obj->path); | ||
623 | return 0; | ||
624 | } | ||
625 | |||
626 | obj->map_fds = malloc(sizeof(int) * nr_maps); | ||
627 | if (!obj->map_fds) { | ||
628 | pr_warning("realloc perf_bpf_map_fds failed\n"); | ||
629 | return -ENOMEM; | ||
630 | } | ||
631 | obj->nr_map_fds = nr_maps; | ||
632 | |||
633 | /* fill all fd with -1 */ | ||
634 | memset(obj->map_fds, -1, sizeof(int) * nr_maps); | ||
635 | |||
636 | pfd = obj->map_fds; | ||
637 | for (i = 0; i < nr_maps; i++) { | ||
638 | struct bpf_map_def def; | ||
639 | |||
640 | def = *(struct bpf_map_def *)(obj->maps_buf + | ||
641 | i * sizeof(struct bpf_map_def)); | ||
642 | |||
643 | *pfd = bpf_create_map(def.type, | ||
644 | def.key_size, | ||
645 | def.value_size, | ||
646 | def.max_entries); | ||
647 | if (*pfd < 0) { | ||
648 | size_t j; | ||
649 | int err = *pfd; | ||
650 | |||
651 | pr_warning("failed to create map: %s\n", | ||
652 | strerror(errno)); | ||
653 | for (j = 0; j < i; j++) | ||
654 | zclose(obj->map_fds[j]); | ||
655 | obj->nr_map_fds = 0; | ||
656 | zfree(&obj->map_fds); | ||
657 | return err; | ||
658 | } | ||
659 | pr_debug("create map: fd=%d\n", *pfd); | ||
660 | pfd++; | ||
661 | } | ||
662 | |||
663 | zfree(&obj->maps_buf); | ||
664 | obj->maps_buf_sz = 0; | ||
665 | return 0; | ||
666 | } | ||
667 | |||
668 | static int | ||
669 | bpf_program__relocate(struct bpf_program *prog, int *map_fds) | ||
670 | { | ||
671 | int i; | ||
672 | |||
673 | if (!prog || !prog->reloc_desc) | ||
674 | return 0; | ||
675 | |||
676 | for (i = 0; i < prog->nr_reloc; i++) { | ||
677 | int insn_idx, map_idx; | ||
678 | struct bpf_insn *insns = prog->insns; | ||
679 | |||
680 | insn_idx = prog->reloc_desc[i].insn_idx; | ||
681 | map_idx = prog->reloc_desc[i].map_idx; | ||
682 | |||
683 | if (insn_idx >= (int)prog->insns_cnt) { | ||
684 | pr_warning("relocation out of range: '%s'\n", | ||
685 | prog->section_name); | ||
686 | return -ERANGE; | ||
687 | } | ||
688 | insns[insn_idx].src_reg = BPF_PSEUDO_MAP_FD; | ||
689 | insns[insn_idx].imm = map_fds[map_idx]; | ||
690 | } | ||
691 | |||
692 | zfree(&prog->reloc_desc); | ||
693 | prog->nr_reloc = 0; | ||
694 | return 0; | ||
695 | } | ||
696 | |||
697 | |||
698 | static int | ||
699 | bpf_object__relocate(struct bpf_object *obj) | ||
700 | { | ||
701 | struct bpf_program *prog; | ||
702 | size_t i; | ||
703 | int err; | ||
704 | |||
705 | for (i = 0; i < obj->nr_programs; i++) { | ||
706 | prog = &obj->programs[i]; | ||
707 | |||
708 | err = bpf_program__relocate(prog, obj->map_fds); | ||
709 | if (err) { | ||
710 | pr_warning("failed to relocate '%s'\n", | ||
711 | prog->section_name); | ||
712 | return err; | ||
713 | } | ||
714 | } | ||
715 | return 0; | ||
716 | } | ||
717 | |||
718 | static int bpf_object__collect_reloc(struct bpf_object *obj) | ||
719 | { | ||
720 | int i, err; | ||
721 | |||
722 | if (!obj_elf_valid(obj)) { | ||
723 | pr_warning("Internal error: elf object is closed\n"); | ||
724 | return -EINVAL; | ||
725 | } | ||
726 | |||
727 | for (i = 0; i < obj->efile.nr_reloc; i++) { | ||
728 | GElf_Shdr *shdr = &obj->efile.reloc[i].shdr; | ||
729 | Elf_Data *data = obj->efile.reloc[i].data; | ||
730 | int idx = shdr->sh_info; | ||
731 | struct bpf_program *prog; | ||
732 | size_t nr_maps = obj->maps_buf_sz / | ||
733 | sizeof(struct bpf_map_def); | ||
734 | |||
735 | if (shdr->sh_type != SHT_REL) { | ||
736 | pr_warning("internal error at %d\n", __LINE__); | ||
737 | return -EINVAL; | ||
738 | } | ||
739 | |||
740 | prog = bpf_object__find_prog_by_idx(obj, idx); | ||
741 | if (!prog) { | ||
742 | pr_warning("relocation failed: no %d section\n", | ||
743 | idx); | ||
744 | return -ENOENT; | ||
745 | } | ||
746 | |||
747 | err = bpf_program__collect_reloc(prog, nr_maps, | ||
748 | shdr, data, | ||
749 | obj->efile.symbols); | ||
750 | if (err) | ||
751 | return -EINVAL; | ||
752 | } | ||
753 | return 0; | ||
754 | } | ||
755 | |||
756 | static int | ||
757 | load_program(struct bpf_insn *insns, int insns_cnt, | ||
758 | char *license, u32 kern_version, int *pfd) | ||
759 | { | ||
760 | int ret; | ||
761 | char *log_buf; | ||
762 | |||
763 | if (!insns || !insns_cnt) | ||
764 | return -EINVAL; | ||
765 | |||
766 | log_buf = malloc(BPF_LOG_BUF_SIZE); | ||
767 | if (!log_buf) | ||
768 | pr_warning("Alloc log buffer for bpf loader error, continue without log\n"); | ||
769 | |||
770 | ret = bpf_load_program(BPF_PROG_TYPE_KPROBE, insns, | ||
771 | insns_cnt, license, kern_version, | ||
772 | log_buf, BPF_LOG_BUF_SIZE); | ||
773 | |||
774 | if (ret >= 0) { | ||
775 | *pfd = ret; | ||
776 | ret = 0; | ||
777 | goto out; | ||
778 | } | ||
779 | |||
780 | ret = -EINVAL; | ||
781 | pr_warning("load bpf program failed: %s\n", strerror(errno)); | ||
782 | |||
783 | if (log_buf) { | ||
784 | pr_warning("-- BEGIN DUMP LOG ---\n"); | ||
785 | pr_warning("\n%s\n", log_buf); | ||
786 | pr_warning("-- END LOG --\n"); | ||
787 | } | ||
788 | |||
789 | out: | ||
790 | free(log_buf); | ||
791 | return ret; | ||
792 | } | ||
793 | |||
794 | static int | ||
795 | bpf_program__load(struct bpf_program *prog, | ||
796 | char *license, u32 kern_version) | ||
797 | { | ||
798 | int err, fd; | ||
799 | |||
800 | err = load_program(prog->insns, prog->insns_cnt, | ||
801 | license, kern_version, &fd); | ||
802 | if (!err) | ||
803 | prog->fd = fd; | ||
804 | |||
805 | if (err) | ||
806 | pr_warning("failed to load program '%s'\n", | ||
807 | prog->section_name); | ||
808 | zfree(&prog->insns); | ||
809 | prog->insns_cnt = 0; | ||
810 | return err; | ||
811 | } | ||
812 | |||
813 | static int | ||
814 | bpf_object__load_progs(struct bpf_object *obj) | ||
815 | { | ||
816 | size_t i; | ||
817 | int err; | ||
818 | |||
819 | for (i = 0; i < obj->nr_programs; i++) { | ||
820 | err = bpf_program__load(&obj->programs[i], | ||
821 | obj->license, | ||
822 | obj->kern_version); | ||
823 | if (err) | ||
824 | return err; | ||
825 | } | ||
826 | return 0; | ||
827 | } | ||
828 | |||
829 | static int bpf_object__validate(struct bpf_object *obj) | ||
830 | { | ||
831 | if (obj->kern_version == 0) { | ||
832 | pr_warning("%s doesn't provide kernel version\n", | ||
833 | obj->path); | ||
834 | return -EINVAL; | ||
835 | } | ||
836 | return 0; | ||
837 | } | ||
838 | |||
839 | static struct bpf_object * | ||
840 | __bpf_object__open(const char *path, void *obj_buf, size_t obj_buf_sz) | ||
841 | { | ||
842 | struct bpf_object *obj; | ||
843 | |||
844 | if (elf_version(EV_CURRENT) == EV_NONE) { | ||
845 | pr_warning("failed to init libelf for %s\n", path); | ||
846 | return NULL; | ||
847 | } | ||
848 | |||
849 | obj = bpf_object__new(path, obj_buf, obj_buf_sz); | ||
850 | if (!obj) | ||
851 | return NULL; | ||
852 | |||
853 | if (bpf_object__elf_init(obj)) | ||
854 | goto out; | ||
855 | if (bpf_object__check_endianness(obj)) | ||
856 | goto out; | ||
857 | if (bpf_object__elf_collect(obj)) | ||
858 | goto out; | ||
859 | if (bpf_object__collect_reloc(obj)) | ||
860 | goto out; | ||
861 | if (bpf_object__validate(obj)) | ||
862 | goto out; | ||
863 | |||
864 | bpf_object__elf_finish(obj); | ||
865 | return obj; | ||
866 | out: | ||
867 | bpf_object__close(obj); | ||
868 | return NULL; | ||
869 | } | ||
870 | |||
871 | struct bpf_object *bpf_object__open(const char *path) | ||
872 | { | ||
873 | /* param validation */ | ||
874 | if (!path) | ||
875 | return NULL; | ||
876 | |||
877 | pr_debug("loading %s\n", path); | ||
878 | |||
879 | return __bpf_object__open(path, NULL, 0); | ||
880 | } | ||
881 | |||
882 | struct bpf_object *bpf_object__open_buffer(void *obj_buf, | ||
883 | size_t obj_buf_sz) | ||
884 | { | ||
885 | /* param validation */ | ||
886 | if (!obj_buf || obj_buf_sz <= 0) | ||
887 | return NULL; | ||
888 | |||
889 | pr_debug("loading object from buffer\n"); | ||
890 | |||
891 | return __bpf_object__open("[buffer]", obj_buf, obj_buf_sz); | ||
892 | } | ||
893 | |||
894 | int bpf_object__unload(struct bpf_object *obj) | ||
895 | { | ||
896 | size_t i; | ||
897 | |||
898 | if (!obj) | ||
899 | return -EINVAL; | ||
900 | |||
901 | for (i = 0; i < obj->nr_map_fds; i++) | ||
902 | zclose(obj->map_fds[i]); | ||
903 | zfree(&obj->map_fds); | ||
904 | obj->nr_map_fds = 0; | ||
905 | |||
906 | for (i = 0; i < obj->nr_programs; i++) | ||
907 | bpf_program__unload(&obj->programs[i]); | ||
908 | |||
909 | return 0; | ||
910 | } | ||
911 | |||
912 | int bpf_object__load(struct bpf_object *obj) | ||
913 | { | ||
914 | if (!obj) | ||
915 | return -EINVAL; | ||
916 | |||
917 | if (obj->loaded) { | ||
918 | pr_warning("object should not be loaded twice\n"); | ||
919 | return -EINVAL; | ||
920 | } | ||
921 | |||
922 | obj->loaded = true; | ||
923 | if (bpf_object__create_maps(obj)) | ||
924 | goto out; | ||
925 | if (bpf_object__relocate(obj)) | ||
926 | goto out; | ||
927 | if (bpf_object__load_progs(obj)) | ||
928 | goto out; | ||
929 | |||
930 | return 0; | ||
931 | out: | ||
932 | bpf_object__unload(obj); | ||
933 | pr_warning("failed to load object '%s'\n", obj->path); | ||
934 | return -EINVAL; | ||
935 | } | ||
936 | |||
937 | void bpf_object__close(struct bpf_object *obj) | ||
938 | { | ||
939 | size_t i; | ||
940 | |||
941 | if (!obj) | ||
942 | return; | ||
943 | |||
944 | bpf_object__elf_finish(obj); | ||
945 | bpf_object__unload(obj); | ||
946 | |||
947 | zfree(&obj->maps_buf); | ||
948 | |||
949 | if (obj->programs && obj->nr_programs) { | ||
950 | for (i = 0; i < obj->nr_programs; i++) | ||
951 | bpf_program__exit(&obj->programs[i]); | ||
952 | } | ||
953 | zfree(&obj->programs); | ||
954 | |||
955 | list_del(&obj->list); | ||
956 | free(obj); | ||
957 | } | ||
958 | |||
959 | struct bpf_object * | ||
960 | bpf_object__next(struct bpf_object *prev) | ||
961 | { | ||
962 | struct bpf_object *next; | ||
963 | |||
964 | if (!prev) | ||
965 | next = list_first_entry(&bpf_objects_list, | ||
966 | struct bpf_object, | ||
967 | list); | ||
968 | else | ||
969 | next = list_next_entry(prev, list); | ||
970 | |||
971 | /* Empty list is noticed here so don't need checking on entry. */ | ||
972 | if (&next->list == &bpf_objects_list) | ||
973 | return NULL; | ||
974 | |||
975 | return next; | ||
976 | } | ||
977 | |||
978 | struct bpf_program * | ||
979 | bpf_program__next(struct bpf_program *prev, struct bpf_object *obj) | ||
980 | { | ||
981 | size_t idx; | ||
982 | |||
983 | if (!obj->programs) | ||
984 | return NULL; | ||
985 | /* First handler */ | ||
986 | if (prev == NULL) | ||
987 | return &obj->programs[0]; | ||
988 | |||
989 | if (prev->obj != obj) { | ||
990 | pr_warning("error: program handler doesn't match object\n"); | ||
991 | return NULL; | ||
992 | } | ||
993 | |||
994 | idx = (prev - obj->programs) + 1; | ||
995 | if (idx >= obj->nr_programs) | ||
996 | return NULL; | ||
997 | return &obj->programs[idx]; | ||
998 | } | ||
999 | |||
1000 | int bpf_program__set_private(struct bpf_program *prog, | ||
1001 | void *priv, | ||
1002 | bpf_program_clear_priv_t clear_priv) | ||
1003 | { | ||
1004 | if (prog->priv && prog->clear_priv) | ||
1005 | prog->clear_priv(prog, prog->priv); | ||
1006 | |||
1007 | prog->priv = priv; | ||
1008 | prog->clear_priv = clear_priv; | ||
1009 | return 0; | ||
1010 | } | ||
1011 | |||
1012 | int bpf_program__get_private(struct bpf_program *prog, void **ppriv) | ||
1013 | { | ||
1014 | *ppriv = prog->priv; | ||
1015 | return 0; | ||
1016 | } | ||
1017 | |||
1018 | const char *bpf_program__title(struct bpf_program *prog, bool dup) | ||
1019 | { | ||
1020 | const char *title; | ||
1021 | |||
1022 | title = prog->section_name; | ||
1023 | if (dup) { | ||
1024 | title = strdup(title); | ||
1025 | if (!title) { | ||
1026 | pr_warning("failed to strdup program title\n"); | ||
1027 | return NULL; | ||
1028 | } | ||
1029 | } | ||
1030 | |||
1031 | return title; | ||
1032 | } | ||
1033 | |||
1034 | int bpf_program__fd(struct bpf_program *prog) | ||
1035 | { | ||
1036 | return prog->fd; | ||
1037 | } | ||
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h new file mode 100644 index 000000000000..ea8adc206b62 --- /dev/null +++ b/tools/lib/bpf/libbpf.h | |||
@@ -0,0 +1,81 @@ | |||
1 | /* | ||
2 | * Common eBPF ELF object loading operations. | ||
3 | * | ||
4 | * Copyright (C) 2013-2015 Alexei Starovoitov <ast@kernel.org> | ||
5 | * Copyright (C) 2015 Wang Nan <wangnan0@huawei.com> | ||
6 | * Copyright (C) 2015 Huawei Inc. | ||
7 | */ | ||
8 | #ifndef __BPF_LIBBPF_H | ||
9 | #define __BPF_LIBBPF_H | ||
10 | |||
11 | #include <stdio.h> | ||
12 | #include <stdbool.h> | ||
13 | |||
14 | /* | ||
15 | * In include/linux/compiler-gcc.h, __printf is defined. However | ||
16 | * it should be better if libbpf.h doesn't depend on Linux header file. | ||
17 | * So instead of __printf, here we use gcc attribute directly. | ||
18 | */ | ||
19 | typedef int (*libbpf_print_fn_t)(const char *, ...) | ||
20 | __attribute__((format(printf, 1, 2))); | ||
21 | |||
22 | void libbpf_set_print(libbpf_print_fn_t warn, | ||
23 | libbpf_print_fn_t info, | ||
24 | libbpf_print_fn_t debug); | ||
25 | |||
26 | /* Hide internal to user */ | ||
27 | struct bpf_object; | ||
28 | |||
29 | struct bpf_object *bpf_object__open(const char *path); | ||
30 | struct bpf_object *bpf_object__open_buffer(void *obj_buf, | ||
31 | size_t obj_buf_sz); | ||
32 | void bpf_object__close(struct bpf_object *object); | ||
33 | |||
34 | /* Load/unload object into/from kernel */ | ||
35 | int bpf_object__load(struct bpf_object *obj); | ||
36 | int bpf_object__unload(struct bpf_object *obj); | ||
37 | |||
38 | struct bpf_object *bpf_object__next(struct bpf_object *prev); | ||
39 | #define bpf_object__for_each_safe(pos, tmp) \ | ||
40 | for ((pos) = bpf_object__next(NULL), \ | ||
41 | (tmp) = bpf_object__next(pos); \ | ||
42 | (pos) != NULL; \ | ||
43 | (pos) = (tmp), (tmp) = bpf_object__next(tmp)) | ||
44 | |||
45 | /* Accessors of bpf_program. */ | ||
46 | struct bpf_program; | ||
47 | struct bpf_program *bpf_program__next(struct bpf_program *prog, | ||
48 | struct bpf_object *obj); | ||
49 | |||
50 | #define bpf_object__for_each_program(pos, obj) \ | ||
51 | for ((pos) = bpf_program__next(NULL, (obj)); \ | ||
52 | (pos) != NULL; \ | ||
53 | (pos) = bpf_program__next((pos), (obj))) | ||
54 | |||
55 | typedef void (*bpf_program_clear_priv_t)(struct bpf_program *, | ||
56 | void *); | ||
57 | |||
58 | int bpf_program__set_private(struct bpf_program *prog, void *priv, | ||
59 | bpf_program_clear_priv_t clear_priv); | ||
60 | |||
61 | int bpf_program__get_private(struct bpf_program *prog, | ||
62 | void **ppriv); | ||
63 | |||
64 | const char *bpf_program__title(struct bpf_program *prog, bool dup); | ||
65 | |||
66 | int bpf_program__fd(struct bpf_program *prog); | ||
67 | |||
68 | /* | ||
69 | * We don't need __attribute__((packed)) now since it is | ||
70 | * unnecessary for 'bpf_map_def' because they are all aligned. | ||
71 | * In addition, using it will trigger -Wpacked warning message, | ||
72 | * and will be treated as an error due to -Werror. | ||
73 | */ | ||
74 | struct bpf_map_def { | ||
75 | unsigned int type; | ||
76 | unsigned int key_size; | ||
77 | unsigned int value_size; | ||
78 | unsigned int max_entries; | ||
79 | }; | ||
80 | |||
81 | #endif | ||
diff --git a/tools/perf/MANIFEST b/tools/perf/MANIFEST index d01a0aad5a01..f31f15a5f873 100644 --- a/tools/perf/MANIFEST +++ b/tools/perf/MANIFEST | |||
@@ -18,6 +18,7 @@ tools/arch/x86/include/asm/atomic.h | |||
18 | tools/arch/x86/include/asm/rmwcc.h | 18 | tools/arch/x86/include/asm/rmwcc.h |
19 | tools/lib/traceevent | 19 | tools/lib/traceevent |
20 | tools/lib/api | 20 | tools/lib/api |
21 | tools/lib/bpf | ||
21 | tools/lib/hweight.c | 22 | tools/lib/hweight.c |
22 | tools/lib/rbtree.c | 23 | tools/lib/rbtree.c |
23 | tools/lib/symbol/kallsyms.c | 24 | tools/lib/symbol/kallsyms.c |
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index d20d6e6ab65b..c1518bdd0f1b 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
@@ -32,6 +32,7 @@ perf-y += sample-parsing.o | |||
32 | perf-y += parse-no-sample-id-all.o | 32 | perf-y += parse-no-sample-id-all.o |
33 | perf-y += kmod-path.o | 33 | perf-y += kmod-path.o |
34 | perf-y += thread-map.o | 34 | perf-y += thread-map.o |
35 | perf-y += llvm.o | ||
35 | 36 | ||
36 | perf-$(CONFIG_X86) += perf-time-to-tsc.o | 37 | perf-$(CONFIG_X86) += perf-time-to-tsc.o |
37 | 38 | ||
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index c1dde733c3a6..136cd934be66 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -175,6 +175,10 @@ static struct test { | |||
175 | .func = test__thread_map, | 175 | .func = test__thread_map, |
176 | }, | 176 | }, |
177 | { | 177 | { |
178 | .desc = "Test LLVM searching and compiling", | ||
179 | .func = test__llvm, | ||
180 | }, | ||
181 | { | ||
178 | .func = NULL, | 182 | .func = NULL, |
179 | }, | 183 | }, |
180 | }; | 184 | }; |
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c new file mode 100644 index 000000000000..a337356fd979 --- /dev/null +++ b/tools/perf/tests/llvm.c | |||
@@ -0,0 +1,98 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <bpf/libbpf.h> | ||
3 | #include <util/llvm-utils.h> | ||
4 | #include <util/cache.h> | ||
5 | #include "tests.h" | ||
6 | #include "debug.h" | ||
7 | |||
8 | static int perf_config_cb(const char *var, const char *val, | ||
9 | void *arg __maybe_unused) | ||
10 | { | ||
11 | return perf_default_config(var, val, arg); | ||
12 | } | ||
13 | |||
14 | /* | ||
15 | * Randomly give it a "version" section since we don't really load it | ||
16 | * into kernel | ||
17 | */ | ||
18 | static const char test_bpf_prog[] = | ||
19 | "__attribute__((section(\"do_fork\"), used)) " | ||
20 | "int fork(void *ctx) {return 0;} " | ||
21 | "char _license[] __attribute__((section(\"license\"), used)) = \"GPL\";" | ||
22 | "int _version __attribute__((section(\"version\"), used)) = 0x40100;"; | ||
23 | |||
24 | #ifdef HAVE_LIBBPF_SUPPORT | ||
25 | static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz) | ||
26 | { | ||
27 | struct bpf_object *obj; | ||
28 | |||
29 | obj = bpf_object__open_buffer(obj_buf, obj_buf_sz); | ||
30 | if (!obj) | ||
31 | return -1; | ||
32 | bpf_object__close(obj); | ||
33 | return 0; | ||
34 | } | ||
35 | #else | ||
36 | static int test__bpf_parsing(void *obj_buf __maybe_unused, | ||
37 | size_t obj_buf_sz __maybe_unused) | ||
38 | { | ||
39 | fprintf(stderr, " (skip bpf parsing)"); | ||
40 | return 0; | ||
41 | } | ||
42 | #endif | ||
43 | |||
44 | int test__llvm(void) | ||
45 | { | ||
46 | char *tmpl_new, *clang_opt_new; | ||
47 | void *obj_buf; | ||
48 | size_t obj_buf_sz; | ||
49 | int err, old_verbose; | ||
50 | |||
51 | perf_config(perf_config_cb, NULL); | ||
52 | |||
53 | /* | ||
54 | * Skip this test if user's .perfconfig doesn't set [llvm] section | ||
55 | * and clang is not found in $PATH, and this is not perf test -v | ||
56 | */ | ||
57 | if (verbose == 0 && !llvm_param.user_set_param && llvm__search_clang()) { | ||
58 | fprintf(stderr, " (no clang, try 'perf test -v LLVM')"); | ||
59 | return TEST_SKIP; | ||
60 | } | ||
61 | |||
62 | old_verbose = verbose; | ||
63 | /* | ||
64 | * llvm is verbosity when error. Suppress all error output if | ||
65 | * not 'perf test -v'. | ||
66 | */ | ||
67 | if (verbose == 0) | ||
68 | verbose = -1; | ||
69 | |||
70 | if (!llvm_param.clang_bpf_cmd_template) | ||
71 | return -1; | ||
72 | |||
73 | if (!llvm_param.clang_opt) | ||
74 | llvm_param.clang_opt = strdup(""); | ||
75 | |||
76 | err = asprintf(&tmpl_new, "echo '%s' | %s", test_bpf_prog, | ||
77 | llvm_param.clang_bpf_cmd_template); | ||
78 | if (err < 0) | ||
79 | return -1; | ||
80 | err = asprintf(&clang_opt_new, "-xc %s", llvm_param.clang_opt); | ||
81 | if (err < 0) | ||
82 | return -1; | ||
83 | |||
84 | llvm_param.clang_bpf_cmd_template = tmpl_new; | ||
85 | llvm_param.clang_opt = clang_opt_new; | ||
86 | err = llvm__compile_bpf("-", &obj_buf, &obj_buf_sz); | ||
87 | |||
88 | verbose = old_verbose; | ||
89 | if (err) { | ||
90 | if (!verbose) | ||
91 | fprintf(stderr, " (use -v to see error message)"); | ||
92 | return -1; | ||
93 | } | ||
94 | |||
95 | err = test__bpf_parsing(obj_buf, obj_buf_sz); | ||
96 | free(obj_buf); | ||
97 | return err; | ||
98 | } | ||
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index ebb47d96bc0b..bf113a247987 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -62,6 +62,7 @@ int test__fdarray__filter(void); | |||
62 | int test__fdarray__add(void); | 62 | int test__fdarray__add(void); |
63 | int test__kmod_path__parse(void); | 63 | int test__kmod_path__parse(void); |
64 | int test__thread_map(void); | 64 | int test__thread_map(void); |
65 | int test__llvm(void); | ||
65 | 66 | ||
66 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) | 67 | #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) |
67 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 68 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index a1e5168dc1fb..2ee81d74cf45 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -14,6 +14,7 @@ libperf-y += find_next_bit.o | |||
14 | libperf-y += help.o | 14 | libperf-y += help.o |
15 | libperf-y += kallsyms.o | 15 | libperf-y += kallsyms.o |
16 | libperf-y += levenshtein.o | 16 | libperf-y += levenshtein.o |
17 | libperf-y += llvm-utils.o | ||
17 | libperf-y += parse-options.o | 18 | libperf-y += parse-options.o |
18 | libperf-y += parse-events.o | 19 | libperf-y += parse-events.o |
19 | libperf-y += path.o | 20 | libperf-y += path.o |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index e18f653cd7db..2e452ac1353d 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include "cache.h" | 12 | #include "cache.h" |
13 | #include "exec_cmd.h" | 13 | #include "exec_cmd.h" |
14 | #include "util/hist.h" /* perf_hist_config */ | 14 | #include "util/hist.h" /* perf_hist_config */ |
15 | #include "util/llvm-utils.h" /* perf_llvm_config */ | ||
15 | 16 | ||
16 | #define MAXNAME (256) | 17 | #define MAXNAME (256) |
17 | 18 | ||
@@ -408,6 +409,9 @@ int perf_default_config(const char *var, const char *value, | |||
408 | if (!prefixcmp(var, "call-graph.")) | 409 | if (!prefixcmp(var, "call-graph.")) |
409 | return perf_callchain_config(var, value); | 410 | return perf_callchain_config(var, value); |
410 | 411 | ||
412 | if (!prefixcmp(var, "llvm.")) | ||
413 | return perf_llvm_config(var, value); | ||
414 | |||
411 | /* Add other config variables here. */ | 415 | /* Add other config variables here. */ |
412 | return 0; | 416 | return 0; |
413 | } | 417 | } |
diff --git a/tools/perf/util/llvm-utils.c b/tools/perf/util/llvm-utils.c new file mode 100644 index 000000000000..4f6a4780bd5f --- /dev/null +++ b/tools/perf/util/llvm-utils.c | |||
@@ -0,0 +1,408 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com> | ||
3 | * Copyright (C) 2015, Huawei Inc. | ||
4 | */ | ||
5 | |||
6 | #include <stdio.h> | ||
7 | #include <sys/utsname.h> | ||
8 | #include "util.h" | ||
9 | #include "debug.h" | ||
10 | #include "llvm-utils.h" | ||
11 | #include "cache.h" | ||
12 | |||
13 | #define CLANG_BPF_CMD_DEFAULT_TEMPLATE \ | ||
14 | "$CLANG_EXEC -D__KERNEL__ $CLANG_OPTIONS " \ | ||
15 | "$KERNEL_INC_OPTIONS -Wno-unused-value " \ | ||
16 | "-Wno-pointer-sign -working-directory " \ | ||
17 | "$WORKING_DIR -c \"$CLANG_SOURCE\" -target bpf -O2 -o -" | ||
18 | |||
19 | struct llvm_param llvm_param = { | ||
20 | .clang_path = "clang", | ||
21 | .clang_bpf_cmd_template = CLANG_BPF_CMD_DEFAULT_TEMPLATE, | ||
22 | .clang_opt = NULL, | ||
23 | .kbuild_dir = NULL, | ||
24 | .kbuild_opts = NULL, | ||
25 | .user_set_param = false, | ||
26 | }; | ||
27 | |||
28 | int perf_llvm_config(const char *var, const char *value) | ||
29 | { | ||
30 | if (prefixcmp(var, "llvm.")) | ||
31 | return 0; | ||
32 | var += sizeof("llvm.") - 1; | ||
33 | |||
34 | if (!strcmp(var, "clang-path")) | ||
35 | llvm_param.clang_path = strdup(value); | ||
36 | else if (!strcmp(var, "clang-bpf-cmd-template")) | ||
37 | llvm_param.clang_bpf_cmd_template = strdup(value); | ||
38 | else if (!strcmp(var, "clang-opt")) | ||
39 | llvm_param.clang_opt = strdup(value); | ||
40 | else if (!strcmp(var, "kbuild-dir")) | ||
41 | llvm_param.kbuild_dir = strdup(value); | ||
42 | else if (!strcmp(var, "kbuild-opts")) | ||
43 | llvm_param.kbuild_opts = strdup(value); | ||
44 | else | ||
45 | return -1; | ||
46 | llvm_param.user_set_param = true; | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | static int | ||
51 | search_program(const char *def, const char *name, | ||
52 | char *output) | ||
53 | { | ||
54 | char *env, *path, *tmp = NULL; | ||
55 | char buf[PATH_MAX]; | ||
56 | int ret; | ||
57 | |||
58 | output[0] = '\0'; | ||
59 | if (def && def[0] != '\0') { | ||
60 | if (def[0] == '/') { | ||
61 | if (access(def, F_OK) == 0) { | ||
62 | strlcpy(output, def, PATH_MAX); | ||
63 | return 0; | ||
64 | } | ||
65 | } else if (def[0] != '\0') | ||
66 | name = def; | ||
67 | } | ||
68 | |||
69 | env = getenv("PATH"); | ||
70 | if (!env) | ||
71 | return -1; | ||
72 | env = strdup(env); | ||
73 | if (!env) | ||
74 | return -1; | ||
75 | |||
76 | ret = -ENOENT; | ||
77 | path = strtok_r(env, ":", &tmp); | ||
78 | while (path) { | ||
79 | scnprintf(buf, sizeof(buf), "%s/%s", path, name); | ||
80 | if (access(buf, F_OK) == 0) { | ||
81 | strlcpy(output, buf, PATH_MAX); | ||
82 | ret = 0; | ||
83 | break; | ||
84 | } | ||
85 | path = strtok_r(NULL, ":", &tmp); | ||
86 | } | ||
87 | |||
88 | free(env); | ||
89 | return ret; | ||
90 | } | ||
91 | |||
92 | #define READ_SIZE 4096 | ||
93 | static int | ||
94 | read_from_pipe(const char *cmd, void **p_buf, size_t *p_read_sz) | ||
95 | { | ||
96 | int err = 0; | ||
97 | void *buf = NULL; | ||
98 | FILE *file = NULL; | ||
99 | size_t read_sz = 0, buf_sz = 0; | ||
100 | |||
101 | file = popen(cmd, "r"); | ||
102 | if (!file) { | ||
103 | pr_err("ERROR: unable to popen cmd: %s\n", | ||
104 | strerror(errno)); | ||
105 | return -EINVAL; | ||
106 | } | ||
107 | |||
108 | while (!feof(file) && !ferror(file)) { | ||
109 | /* | ||
110 | * Make buf_sz always have obe byte extra space so we | ||
111 | * can put '\0' there. | ||
112 | */ | ||
113 | if (buf_sz - read_sz < READ_SIZE + 1) { | ||
114 | void *new_buf; | ||
115 | |||
116 | buf_sz = read_sz + READ_SIZE + 1; | ||
117 | new_buf = realloc(buf, buf_sz); | ||
118 | |||
119 | if (!new_buf) { | ||
120 | pr_err("ERROR: failed to realloc memory\n"); | ||
121 | err = -ENOMEM; | ||
122 | goto errout; | ||
123 | } | ||
124 | |||
125 | buf = new_buf; | ||
126 | } | ||
127 | read_sz += fread(buf + read_sz, 1, READ_SIZE, file); | ||
128 | } | ||
129 | |||
130 | if (buf_sz - read_sz < 1) { | ||
131 | pr_err("ERROR: internal error\n"); | ||
132 | err = -EINVAL; | ||
133 | goto errout; | ||
134 | } | ||
135 | |||
136 | if (ferror(file)) { | ||
137 | pr_err("ERROR: error occurred when reading from pipe: %s\n", | ||
138 | strerror(errno)); | ||
139 | err = -EIO; | ||
140 | goto errout; | ||
141 | } | ||
142 | |||
143 | err = WEXITSTATUS(pclose(file)); | ||
144 | file = NULL; | ||
145 | if (err) { | ||
146 | err = -EINVAL; | ||
147 | goto errout; | ||
148 | } | ||
149 | |||
150 | /* | ||
151 | * If buf is string, give it terminal '\0' to make our life | ||
152 | * easier. If buf is not string, that '\0' is out of space | ||
153 | * indicated by read_sz so caller won't even notice it. | ||
154 | */ | ||
155 | ((char *)buf)[read_sz] = '\0'; | ||
156 | |||
157 | if (!p_buf) | ||
158 | free(buf); | ||
159 | else | ||
160 | *p_buf = buf; | ||
161 | |||
162 | if (p_read_sz) | ||
163 | *p_read_sz = read_sz; | ||
164 | return 0; | ||
165 | |||
166 | errout: | ||
167 | if (file) | ||
168 | pclose(file); | ||
169 | free(buf); | ||
170 | if (p_buf) | ||
171 | *p_buf = NULL; | ||
172 | if (p_read_sz) | ||
173 | *p_read_sz = 0; | ||
174 | return err; | ||
175 | } | ||
176 | |||
177 | static inline void | ||
178 | force_set_env(const char *var, const char *value) | ||
179 | { | ||
180 | if (value) { | ||
181 | setenv(var, value, 1); | ||
182 | pr_debug("set env: %s=%s\n", var, value); | ||
183 | } else { | ||
184 | unsetenv(var); | ||
185 | pr_debug("unset env: %s\n", var); | ||
186 | } | ||
187 | } | ||
188 | |||
189 | static void | ||
190 | version_notice(void) | ||
191 | { | ||
192 | pr_err( | ||
193 | " \tLLVM 3.7 or newer is required. Which can be found from http://llvm.org\n" | ||
194 | " \tYou may want to try git trunk:\n" | ||
195 | " \t\tgit clone http://llvm.org/git/llvm.git\n" | ||
196 | " \t\t and\n" | ||
197 | " \t\tgit clone http://llvm.org/git/clang.git\n\n" | ||
198 | " \tOr fetch the latest clang/llvm 3.7 from pre-built llvm packages for\n" | ||
199 | " \tdebian/ubuntu:\n" | ||
200 | " \t\thttp://llvm.org/apt\n\n" | ||
201 | " \tIf you are using old version of clang, change 'clang-bpf-cmd-template'\n" | ||
202 | " \toption in [llvm] section of ~/.perfconfig to:\n\n" | ||
203 | " \t \"$CLANG_EXEC $CLANG_OPTIONS $KERNEL_INC_OPTIONS \\\n" | ||
204 | " \t -working-directory $WORKING_DIR -c $CLANG_SOURCE \\\n" | ||
205 | " \t -emit-llvm -o - | /path/to/llc -march=bpf -filetype=obj -o -\"\n" | ||
206 | " \t(Replace /path/to/llc with path to your llc)\n\n" | ||
207 | ); | ||
208 | } | ||
209 | |||
210 | static int detect_kbuild_dir(char **kbuild_dir) | ||
211 | { | ||
212 | const char *test_dir = llvm_param.kbuild_dir; | ||
213 | const char *prefix_dir = ""; | ||
214 | const char *suffix_dir = ""; | ||
215 | |||
216 | char *autoconf_path; | ||
217 | struct utsname utsname; | ||
218 | |||
219 | int err; | ||
220 | |||
221 | if (!test_dir) { | ||
222 | err = uname(&utsname); | ||
223 | if (err) { | ||
224 | pr_warning("uname failed: %s\n", strerror(errno)); | ||
225 | return -EINVAL; | ||
226 | } | ||
227 | |||
228 | test_dir = utsname.release; | ||
229 | prefix_dir = "/lib/modules/"; | ||
230 | suffix_dir = "/build"; | ||
231 | } | ||
232 | |||
233 | err = asprintf(&autoconf_path, "%s%s%s/include/generated/autoconf.h", | ||
234 | prefix_dir, test_dir, suffix_dir); | ||
235 | if (err < 0) | ||
236 | return -ENOMEM; | ||
237 | |||
238 | if (access(autoconf_path, R_OK) == 0) { | ||
239 | free(autoconf_path); | ||
240 | |||
241 | err = asprintf(kbuild_dir, "%s%s%s", prefix_dir, test_dir, | ||
242 | suffix_dir); | ||
243 | if (err < 0) | ||
244 | return -ENOMEM; | ||
245 | return 0; | ||
246 | } | ||
247 | free(autoconf_path); | ||
248 | return -ENOENT; | ||
249 | } | ||
250 | |||
251 | static const char *kinc_fetch_script = | ||
252 | "#!/usr/bin/env sh\n" | ||
253 | "if ! test -d \"$KBUILD_DIR\"\n" | ||
254 | "then\n" | ||
255 | " exit -1\n" | ||
256 | "fi\n" | ||
257 | "if ! test -f \"$KBUILD_DIR/include/generated/autoconf.h\"\n" | ||
258 | "then\n" | ||
259 | " exit -1\n" | ||
260 | "fi\n" | ||
261 | "TMPDIR=`mktemp -d`\n" | ||
262 | "if test -z \"$TMPDIR\"\n" | ||
263 | "then\n" | ||
264 | " exit -1\n" | ||
265 | "fi\n" | ||
266 | "cat << EOF > $TMPDIR/Makefile\n" | ||
267 | "obj-y := dummy.o\n" | ||
268 | "\\$(obj)/%.o: \\$(src)/%.c\n" | ||
269 | "\t@echo -n \"\\$(NOSTDINC_FLAGS) \\$(LINUXINCLUDE) \\$(EXTRA_CFLAGS)\"\n" | ||
270 | "EOF\n" | ||
271 | "touch $TMPDIR/dummy.c\n" | ||
272 | "make -s -C $KBUILD_DIR M=$TMPDIR $KBUILD_OPTS dummy.o 2>/dev/null\n" | ||
273 | "RET=$?\n" | ||
274 | "rm -rf $TMPDIR\n" | ||
275 | "exit $RET\n"; | ||
276 | |||
277 | static inline void | ||
278 | get_kbuild_opts(char **kbuild_dir, char **kbuild_include_opts) | ||
279 | { | ||
280 | int err; | ||
281 | |||
282 | if (!kbuild_dir || !kbuild_include_opts) | ||
283 | return; | ||
284 | |||
285 | *kbuild_dir = NULL; | ||
286 | *kbuild_include_opts = NULL; | ||
287 | |||
288 | if (llvm_param.kbuild_dir && !llvm_param.kbuild_dir[0]) { | ||
289 | pr_debug("[llvm.kbuild-dir] is set to \"\" deliberately.\n"); | ||
290 | pr_debug("Skip kbuild options detection.\n"); | ||
291 | return; | ||
292 | } | ||
293 | |||
294 | err = detect_kbuild_dir(kbuild_dir); | ||
295 | if (err) { | ||
296 | pr_warning( | ||
297 | "WARNING:\tunable to get correct kernel building directory.\n" | ||
298 | "Hint:\tSet correct kbuild directory using 'kbuild-dir' option in [llvm]\n" | ||
299 | " \tsection of ~/.perfconfig or set it to \"\" to suppress kbuild\n" | ||
300 | " \tdetection.\n\n"); | ||
301 | return; | ||
302 | } | ||
303 | |||
304 | pr_debug("Kernel build dir is set to %s\n", *kbuild_dir); | ||
305 | force_set_env("KBUILD_DIR", *kbuild_dir); | ||
306 | force_set_env("KBUILD_OPTS", llvm_param.kbuild_opts); | ||
307 | err = read_from_pipe(kinc_fetch_script, | ||
308 | (void **)kbuild_include_opts, | ||
309 | NULL); | ||
310 | if (err) { | ||
311 | pr_warning( | ||
312 | "WARNING:\tunable to get kernel include directories from '%s'\n" | ||
313 | "Hint:\tTry set clang include options using 'clang-bpf-cmd-template'\n" | ||
314 | " \toption in [llvm] section of ~/.perfconfig and set 'kbuild-dir'\n" | ||
315 | " \toption in [llvm] to \"\" to suppress this detection.\n\n", | ||
316 | *kbuild_dir); | ||
317 | |||
318 | free(*kbuild_dir); | ||
319 | *kbuild_dir = NULL; | ||
320 | return; | ||
321 | } | ||
322 | |||
323 | pr_debug("include option is set to %s\n", *kbuild_include_opts); | ||
324 | } | ||
325 | |||
326 | int llvm__compile_bpf(const char *path, void **p_obj_buf, | ||
327 | size_t *p_obj_buf_sz) | ||
328 | { | ||
329 | int err; | ||
330 | char clang_path[PATH_MAX]; | ||
331 | const char *clang_opt = llvm_param.clang_opt; | ||
332 | const char *template = llvm_param.clang_bpf_cmd_template; | ||
333 | char *kbuild_dir = NULL, *kbuild_include_opts = NULL; | ||
334 | void *obj_buf = NULL; | ||
335 | size_t obj_buf_sz; | ||
336 | |||
337 | if (!template) | ||
338 | template = CLANG_BPF_CMD_DEFAULT_TEMPLATE; | ||
339 | |||
340 | err = search_program(llvm_param.clang_path, | ||
341 | "clang", clang_path); | ||
342 | if (err) { | ||
343 | pr_err( | ||
344 | "ERROR:\tunable to find clang.\n" | ||
345 | "Hint:\tTry to install latest clang/llvm to support BPF. Check your $PATH\n" | ||
346 | " \tand 'clang-path' option in [llvm] section of ~/.perfconfig.\n"); | ||
347 | version_notice(); | ||
348 | return -ENOENT; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * This is an optional work. Even it fail we can continue our | ||
353 | * work. Needn't to check error return. | ||
354 | */ | ||
355 | get_kbuild_opts(&kbuild_dir, &kbuild_include_opts); | ||
356 | |||
357 | force_set_env("CLANG_EXEC", clang_path); | ||
358 | force_set_env("CLANG_OPTIONS", clang_opt); | ||
359 | force_set_env("KERNEL_INC_OPTIONS", kbuild_include_opts); | ||
360 | force_set_env("WORKING_DIR", kbuild_dir ? : "."); | ||
361 | |||
362 | /* | ||
363 | * Since we may reset clang's working dir, path of source file | ||
364 | * should be transferred into absolute path, except we want | ||
365 | * stdin to be source file (testing). | ||
366 | */ | ||
367 | force_set_env("CLANG_SOURCE", | ||
368 | (path[0] == '-') ? path : | ||
369 | make_nonrelative_path(path)); | ||
370 | |||
371 | pr_debug("llvm compiling command template: %s\n", template); | ||
372 | err = read_from_pipe(template, &obj_buf, &obj_buf_sz); | ||
373 | if (err) { | ||
374 | pr_err("ERROR:\tunable to compile %s\n", path); | ||
375 | pr_err("Hint:\tCheck error message shown above.\n"); | ||
376 | pr_err("Hint:\tYou can also pre-compile it into .o using:\n"); | ||
377 | pr_err(" \t\tclang -target bpf -O2 -c %s\n", path); | ||
378 | pr_err(" \twith proper -I and -D options.\n"); | ||
379 | goto errout; | ||
380 | } | ||
381 | |||
382 | free(kbuild_dir); | ||
383 | free(kbuild_include_opts); | ||
384 | if (!p_obj_buf) | ||
385 | free(obj_buf); | ||
386 | else | ||
387 | *p_obj_buf = obj_buf; | ||
388 | |||
389 | if (p_obj_buf_sz) | ||
390 | *p_obj_buf_sz = obj_buf_sz; | ||
391 | return 0; | ||
392 | errout: | ||
393 | free(kbuild_dir); | ||
394 | free(kbuild_include_opts); | ||
395 | free(obj_buf); | ||
396 | if (p_obj_buf) | ||
397 | *p_obj_buf = NULL; | ||
398 | if (p_obj_buf_sz) | ||
399 | *p_obj_buf_sz = 0; | ||
400 | return err; | ||
401 | } | ||
402 | |||
403 | int llvm__search_clang(void) | ||
404 | { | ||
405 | char clang_path[PATH_MAX]; | ||
406 | |||
407 | return search_program(llvm_param.clang_path, "clang", clang_path); | ||
408 | } | ||
diff --git a/tools/perf/util/llvm-utils.h b/tools/perf/util/llvm-utils.h new file mode 100644 index 000000000000..5b3cf1c229e2 --- /dev/null +++ b/tools/perf/util/llvm-utils.h | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2015, Wang Nan <wangnan0@huawei.com> | ||
3 | * Copyright (C) 2015, Huawei Inc. | ||
4 | */ | ||
5 | #ifndef __LLVM_UTILS_H | ||
6 | #define __LLVM_UTILS_H | ||
7 | |||
8 | #include "debug.h" | ||
9 | |||
10 | struct llvm_param { | ||
11 | /* Path of clang executable */ | ||
12 | const char *clang_path; | ||
13 | /* | ||
14 | * Template of clang bpf compiling. 5 env variables | ||
15 | * can be used: | ||
16 | * $CLANG_EXEC: Path to clang. | ||
17 | * $CLANG_OPTIONS: Extra options to clang. | ||
18 | * $KERNEL_INC_OPTIONS: Kernel include directories. | ||
19 | * $WORKING_DIR: Kernel source directory. | ||
20 | * $CLANG_SOURCE: Source file to be compiled. | ||
21 | */ | ||
22 | const char *clang_bpf_cmd_template; | ||
23 | /* Will be filled in $CLANG_OPTIONS */ | ||
24 | const char *clang_opt; | ||
25 | /* Where to find kbuild system */ | ||
26 | const char *kbuild_dir; | ||
27 | /* | ||
28 | * Arguments passed to make, like 'ARCH=arm' if doing cross | ||
29 | * compiling. Should not be used for dynamic compiling. | ||
30 | */ | ||
31 | const char *kbuild_opts; | ||
32 | /* | ||
33 | * Default is false. If one of the above fields is set by user | ||
34 | * explicitly then user_set_llvm is set to true. This is used | ||
35 | * for perf test. If user doesn't set anything in .perfconfig | ||
36 | * and clang is not found, don't trigger llvm test. | ||
37 | */ | ||
38 | bool user_set_param; | ||
39 | }; | ||
40 | |||
41 | extern struct llvm_param llvm_param; | ||
42 | extern int perf_llvm_config(const char *var, const char *value); | ||
43 | |||
44 | extern int llvm__compile_bpf(const char *path, void **p_obj_buf, | ||
45 | size_t *p_obj_buf_sz); | ||
46 | |||
47 | /* This function is for test__llvm() use only */ | ||
48 | extern int llvm__search_clang(void); | ||
49 | #endif | ||