Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+2014 -1
+5 -1
tools/build/feature/Makefile
··· 33 33 test-compile-32.bin \ 34 34 test-compile-x32.bin \ 35 35 test-zlib.bin \ 36 - test-lzma.bin 36 + test-lzma.bin \ 37 + test-bpf.bin 37 38 38 39 CC := $(CROSS_COMPILE)gcc -MD 39 40 PKG_CONFIG := $(CROSS_COMPILE)pkg-config ··· 156 155 157 156 test-lzma.bin: 158 157 $(BUILD) -llzma 158 + 159 + test-bpf.bin: 160 + $(BUILD) 159 161 160 162 -include *.d 161 163
+18
tools/build/feature/test-bpf.c
··· 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 + }
+2
tools/lib/bpf/.gitignore
··· 1 + libbpf_version.h 2 + FEATURE-DUMP
+1
tools/lib/bpf/Build
··· 1 + libbpf-y := libbpf.o bpf.o
+195
tools/lib/bpf/Makefile
··· 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)
+85
tools/lib/bpf/bpf.c
··· 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 + }
+23
tools/lib/bpf/bpf.h
··· 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
+1037
tools/lib/bpf/libbpf.c
··· 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 + }
+81
tools/lib/bpf/libbpf.h
··· 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
+1
tools/perf/MANIFEST
··· 18 18 tools/arch/x86/include/asm/rmwcc.h 19 19 tools/lib/traceevent 20 20 tools/lib/api 21 + tools/lib/bpf 21 22 tools/lib/hweight.c 22 23 tools/lib/rbtree.c 23 24 tools/lib/symbol/kallsyms.c
+1
tools/perf/tests/Build
··· 32 32 perf-y += parse-no-sample-id-all.o 33 33 perf-y += kmod-path.o 34 34 perf-y += thread-map.o 35 + perf-y += llvm.o 35 36 36 37 perf-$(CONFIG_X86) += perf-time-to-tsc.o 37 38
+4
tools/perf/tests/builtin-test.c
··· 175 175 .func = test__thread_map, 176 176 }, 177 177 { 178 + .desc = "Test LLVM searching and compiling", 179 + .func = test__llvm, 180 + }, 181 + { 178 182 .func = NULL, 179 183 }, 180 184 };
+98
tools/perf/tests/llvm.c
··· 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 + }
+1
tools/perf/tests/tests.h
··· 62 62 int test__fdarray__add(void); 63 63 int test__kmod_path__parse(void); 64 64 int test__thread_map(void); 65 + int test__llvm(void); 65 66 66 67 #if defined(__x86_64__) || defined(__i386__) || defined(__arm__) || defined(__aarch64__) 67 68 #ifdef HAVE_DWARF_UNWIND_SUPPORT
+1
tools/perf/util/Build
··· 14 14 libperf-y += help.o 15 15 libperf-y += kallsyms.o 16 16 libperf-y += levenshtein.o 17 + libperf-y += llvm-utils.o 17 18 libperf-y += parse-options.o 18 19 libperf-y += parse-events.o 19 20 libperf-y += path.o
+4
tools/perf/util/config.c
··· 12 12 #include "cache.h" 13 13 #include "exec_cmd.h" 14 14 #include "util/hist.h" /* perf_hist_config */ 15 + #include "util/llvm-utils.h" /* perf_llvm_config */ 15 16 16 17 #define MAXNAME (256) 17 18 ··· 408 407 409 408 if (!prefixcmp(var, "call-graph.")) 410 409 return perf_callchain_config(var, value); 410 + 411 + if (!prefixcmp(var, "llvm.")) 412 + return perf_llvm_config(var, value); 411 413 412 414 /* Add other config variables here. */ 413 415 return 0;
+408
tools/perf/util/llvm-utils.c
··· 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 + }
+49
tools/perf/util/llvm-utils.h
··· 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