Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7b6982ce authored by Wang Nan's avatar Wang Nan Committed by Arnaldo Carvalho de Melo
Browse files

perf test: Add libbpf relocation checker

There's a bug in LLVM that it can generate unneeded relocation
information. See [1] and [2]. Libbpf should check the target section of
a relocation symbol.

This patch adds a testcase which references a global variable (BPF
doesn't support global variables). Before fixing libbpf, the new test
case can be loaded into kernel, the global variable acts like the first
map. It is incorrect.

Result:

  # ~/perf test BPF
  37: Test BPF filter                                          :
  37.1: Test basic BPF filtering                               : Ok
  37.2: Test BPF prologue generation                           : Ok
  37.3: Test BPF relocation checker                            : FAILED!

  # ~/perf test -v BPF
  ...
  libbpf: loading object '[bpf_relocation_test]' from buffer
  libbpf: section .strtab, size 126, link 0, flags 0, type=3
  libbpf: section .text, size 0, link 0, flags 6, type=1
  libbpf: section .data, size 0, link 0, flags 3, type=1
  libbpf: section .bss, size 0, link 0, flags 3, type=8
  libbpf: section func=sys_write, size 104, link 0, flags 6, type=1
  libbpf: found program func=sys_write
  libbpf: section .relfunc=sys_write, size 16, link 10, flags 0, type=9
  libbpf: section maps, size 16, link 0, flags 3, type=1
  libbpf: maps in [bpf_relocation_test]: 16 bytes
  libbpf: section license, size 4, link 0, flags 3, type=1
  libbpf: license of [bpf_relocation_test] is GPL
  libbpf: section version, size 4, link 0, flags 3, type=1
  libbpf: kernel version of [bpf_relocation_test] is 40400
  libbpf: section .symtab, size 144, link 1, flags 0, type=2
  libbpf: map 0 is "my_table"
  libbpf: collecting relocating info for: 'func=sys_write'
  libbpf: relocation: insn_idx=7
  Success unexpectedly: libbpf error when dealing with relocation
  test child finished with -1
  ---- end ----
  Test BPF filter subtest 2: FAILED!

[1] https://llvm.org/bugs/show_bug.cgi?id=26243
[2] https://patchwork.ozlabs.org/patch/571385/



Signed-off-by: default avatarWang Nan <wangnan0@huawei.com>
Tested-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: He Kuang <hekuang@huawei.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1453715801-7732-2-git-send-email-wangnan0@huawei.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent ab414dcd
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -618,7 +618,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean
	$(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
	$(call QUIET_CLEAN, core-gen)   $(RM)  *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)FEATURE-DUMP $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex* \
		$(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
		$(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c
		$(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c
	$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
	$(python-clean)

+1 −0
Original line number Diff line number Diff line
llvm-src-base.c
llvm-src-kbuild.c
llvm-src-prologue.c
llvm-src-relocation.c
+8 −1
Original line number Diff line number Diff line
@@ -31,7 +31,7 @@ perf-y += sample-parsing.o
perf-y += parse-no-sample-id-all.o
perf-y += kmod-path.o
perf-y += thread-map.o
perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o
perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o llvm-src-relocation.o
perf-y += bpf.o
perf-y += topology.o
perf-y += cpumap.o
@@ -59,6 +59,13 @@ $(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
	$(Q)echo ';' >> $@

$(OUTPUT)tests/llvm-src-relocation.c: tests/bpf-script-test-relocation.c tests/Build
	$(call rule_mkdir)
	$(Q)echo '#include <tests/llvm.h>' > $@
	$(Q)echo 'const char test_llvm__bpf_test_relocation[] =' >> $@
	$(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
	$(Q)echo ';' >> $@

ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
endif
+50 −0
Original line number Diff line number Diff line
/*
 * bpf-script-test-relocation.c
 * Test BPF loader checking relocation
 */
#ifndef LINUX_VERSION_CODE
# error Need LINUX_VERSION_CODE
# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
#endif
#define BPF_ANY 0
#define BPF_MAP_TYPE_ARRAY 2
#define BPF_FUNC_map_lookup_elem 1
#define BPF_FUNC_map_update_elem 2

static void *(*bpf_map_lookup_elem)(void *map, void *key) =
	(void *) BPF_FUNC_map_lookup_elem;
static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
	(void *) BPF_FUNC_map_update_elem;

struct bpf_map_def {
	unsigned int type;
	unsigned int key_size;
	unsigned int value_size;
	unsigned int max_entries;
};

#define SEC(NAME) __attribute__((section(NAME), used))
struct bpf_map_def SEC("maps") my_table = {
	.type = BPF_MAP_TYPE_ARRAY,
	.key_size = sizeof(int),
	.value_size = sizeof(int),
	.max_entries = 1,
};

int this_is_a_global_val;

SEC("func=sys_write")
int bpf_func__sys_write(void *ctx)
{
	int key = 0;
	int value = 0;

	/*
	 * Incorrect relocation. Should not allow this program be
	 * loaded into kernel.
	 */
	bpf_map_update_elem(&this_is_a_global_val, &key, &value, 0);
	return 0;
}
char _license[] SEC("license") = "GPL";
int _version SEC("version") = LINUX_VERSION_CODE;
+21 −5
Original line number Diff line number Diff line
@@ -71,6 +71,15 @@ static struct {
		(NR_ITERS + 1) / 4,
	},
#endif
	{
		LLVM_TESTCASE_BPF_RELOCATION,
		"Test BPF relocation checker",
		"[bpf_relocation_test]",
		"fix 'perf test LLVM' first",
		"libbpf error when dealing with relocation",
		NULL,
		0,
	},
};

static int do_test(struct bpf_object *obj, int (*func)(void),
@@ -190,7 +199,7 @@ static int __test__bpf(int idx)

	ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
				       bpf_testcase_table[idx].prog_id,
				       true);
				       true, NULL);
	if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
		pr_debug("Unable to get BPF object, %s\n",
			 bpf_testcase_table[idx].msg_compile_fail);
@@ -202,11 +211,18 @@ static int __test__bpf(int idx)

	obj = prepare_bpf(obj_buf, obj_buf_sz,
			  bpf_testcase_table[idx].name);
	if (!obj) {
	if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
		if (!obj)
			pr_debug("Fail to load BPF object: %s\n",
				 bpf_testcase_table[idx].msg_load_fail);
		else
			pr_debug("Success unexpectedly: %s\n",
				 bpf_testcase_table[idx].msg_load_fail);
		ret = TEST_FAIL;
		goto out;
	}

	if (obj)
		ret = do_test(obj,
			      bpf_testcase_table[idx].target_func,
			      bpf_testcase_table[idx].expect_result);
Loading