summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWang Nan <wangnan0@huawei.com>2016-01-25 04:55:48 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2016-01-26 10:10:55 -0500
commit7b6982ce4b38ecc3f63be46beb7bd079aa290fd7 (patch)
treed94c748f4b190b9e38eefd2063530ef8463dc15d
parentab414dcda8fa307388c40a540b35e3c98a9da5ae (diff)
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: Wang Nan <wangnan0@huawei.com> Tested-by: Arnaldo 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: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r--tools/perf/Makefile.perf2
-rw-r--r--tools/perf/tests/.gitignore1
-rw-r--r--tools/perf/tests/Build9
-rw-r--r--tools/perf/tests/bpf-script-test-relocation.c50
-rw-r--r--tools/perf/tests/bpf.c26
-rw-r--r--tools/perf/tests/llvm.c17
-rw-r--r--tools/perf/tests/llvm.h5
7 files changed, 98 insertions, 12 deletions
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 5d34815c7ccb..97ce8695199e 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -618,7 +618,7 @@ clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean
618 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32 618 $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
619 $(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* \ 619 $(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* \
620 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \ 620 $(OUTPUT)util/intel-pt-decoder/inat-tables.c $(OUTPUT)fixdep \
621 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue}.c 621 $(OUTPUT)tests/llvm-src-{base,kbuild,prologue,relocation}.c
622 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean 622 $(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
623 $(python-clean) 623 $(python-clean)
624 624
diff --git a/tools/perf/tests/.gitignore b/tools/perf/tests/.gitignore
index bf016c439fbd..8cc30e731c73 100644
--- a/tools/perf/tests/.gitignore
+++ b/tools/perf/tests/.gitignore
@@ -1,3 +1,4 @@
1llvm-src-base.c 1llvm-src-base.c
2llvm-src-kbuild.c 2llvm-src-kbuild.c
3llvm-src-prologue.c 3llvm-src-prologue.c
4llvm-src-relocation.c
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build
index 614899b88b37..1ba628ed049a 100644
--- a/tools/perf/tests/Build
+++ b/tools/perf/tests/Build
@@ -31,7 +31,7 @@ perf-y += sample-parsing.o
31perf-y += parse-no-sample-id-all.o 31perf-y += parse-no-sample-id-all.o
32perf-y += kmod-path.o 32perf-y += kmod-path.o
33perf-y += thread-map.o 33perf-y += thread-map.o
34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o 34perf-y += llvm.o llvm-src-base.o llvm-src-kbuild.o llvm-src-prologue.o llvm-src-relocation.o
35perf-y += bpf.o 35perf-y += bpf.o
36perf-y += topology.o 36perf-y += topology.o
37perf-y += cpumap.o 37perf-y += cpumap.o
@@ -59,6 +59,13 @@ $(OUTPUT)tests/llvm-src-prologue.c: tests/bpf-script-test-prologue.c tests/Build
59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@ 59 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
60 $(Q)echo ';' >> $@ 60 $(Q)echo ';' >> $@
61 61
62$(OUTPUT)tests/llvm-src-relocation.c: tests/bpf-script-test-relocation.c tests/Build
63 $(call rule_mkdir)
64 $(Q)echo '#include <tests/llvm.h>' > $@
65 $(Q)echo 'const char test_llvm__bpf_test_relocation[] =' >> $@
66 $(Q)sed -e 's/"/\\"/g' -e 's/\(.*\)/"\1\\n"/g' $< >> $@
67 $(Q)echo ';' >> $@
68
62ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64)) 69ifeq ($(ARCH),$(filter $(ARCH),x86 arm arm64))
63perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o 70perf-$(CONFIG_DWARF_UNWIND) += dwarf-unwind.o
64endif 71endif
diff --git a/tools/perf/tests/bpf-script-test-relocation.c b/tools/perf/tests/bpf-script-test-relocation.c
new file mode 100644
index 000000000000..93af77421816
--- /dev/null
+++ b/tools/perf/tests/bpf-script-test-relocation.c
@@ -0,0 +1,50 @@
1/*
2 * bpf-script-test-relocation.c
3 * Test BPF loader checking relocation
4 */
5#ifndef LINUX_VERSION_CODE
6# error Need LINUX_VERSION_CODE
7# error Example: for 4.2 kernel, put 'clang-opt="-DLINUX_VERSION_CODE=0x40200" into llvm section of ~/.perfconfig'
8#endif
9#define BPF_ANY 0
10#define BPF_MAP_TYPE_ARRAY 2
11#define BPF_FUNC_map_lookup_elem 1
12#define BPF_FUNC_map_update_elem 2
13
14static void *(*bpf_map_lookup_elem)(void *map, void *key) =
15 (void *) BPF_FUNC_map_lookup_elem;
16static void *(*bpf_map_update_elem)(void *map, void *key, void *value, int flags) =
17 (void *) BPF_FUNC_map_update_elem;
18
19struct bpf_map_def {
20 unsigned int type;
21 unsigned int key_size;
22 unsigned int value_size;
23 unsigned int max_entries;
24};
25
26#define SEC(NAME) __attribute__((section(NAME), used))
27struct bpf_map_def SEC("maps") my_table = {
28 .type = BPF_MAP_TYPE_ARRAY,
29 .key_size = sizeof(int),
30 .value_size = sizeof(int),
31 .max_entries = 1,
32};
33
34int this_is_a_global_val;
35
36SEC("func=sys_write")
37int bpf_func__sys_write(void *ctx)
38{
39 int key = 0;
40 int value = 0;
41
42 /*
43 * Incorrect relocation. Should not allow this program be
44 * loaded into kernel.
45 */
46 bpf_map_update_elem(&this_is_a_global_val, &key, &value, 0);
47 return 0;
48}
49char _license[] SEC("license") = "GPL";
50int _version SEC("version") = LINUX_VERSION_CODE;
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c
index 33689a0cf821..952ca99aba6b 100644
--- a/tools/perf/tests/bpf.c
+++ b/tools/perf/tests/bpf.c
@@ -71,6 +71,15 @@ static struct {
71 (NR_ITERS + 1) / 4, 71 (NR_ITERS + 1) / 4,
72 }, 72 },
73#endif 73#endif
74 {
75 LLVM_TESTCASE_BPF_RELOCATION,
76 "Test BPF relocation checker",
77 "[bpf_relocation_test]",
78 "fix 'perf test LLVM' first",
79 "libbpf error when dealing with relocation",
80 NULL,
81 0,
82 },
74}; 83};
75 84
76static int do_test(struct bpf_object *obj, int (*func)(void), 85static int do_test(struct bpf_object *obj, int (*func)(void),
@@ -190,7 +199,7 @@ static int __test__bpf(int idx)
190 199
191 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 200 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
192 bpf_testcase_table[idx].prog_id, 201 bpf_testcase_table[idx].prog_id,
193 true); 202 true, NULL);
194 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) { 203 if (ret != TEST_OK || !obj_buf || !obj_buf_sz) {
195 pr_debug("Unable to get BPF object, %s\n", 204 pr_debug("Unable to get BPF object, %s\n",
196 bpf_testcase_table[idx].msg_compile_fail); 205 bpf_testcase_table[idx].msg_compile_fail);
@@ -202,14 +211,21 @@ static int __test__bpf(int idx)
202 211
203 obj = prepare_bpf(obj_buf, obj_buf_sz, 212 obj = prepare_bpf(obj_buf, obj_buf_sz,
204 bpf_testcase_table[idx].name); 213 bpf_testcase_table[idx].name);
205 if (!obj) { 214 if ((!!bpf_testcase_table[idx].target_func) != (!!obj)) {
215 if (!obj)
216 pr_debug("Fail to load BPF object: %s\n",
217 bpf_testcase_table[idx].msg_load_fail);
218 else
219 pr_debug("Success unexpectedly: %s\n",
220 bpf_testcase_table[idx].msg_load_fail);
206 ret = TEST_FAIL; 221 ret = TEST_FAIL;
207 goto out; 222 goto out;
208 } 223 }
209 224
210 ret = do_test(obj, 225 if (obj)
211 bpf_testcase_table[idx].target_func, 226 ret = do_test(obj,
212 bpf_testcase_table[idx].expect_result); 227 bpf_testcase_table[idx].target_func,
228 bpf_testcase_table[idx].expect_result);
213out: 229out:
214 bpf__clear(); 230 bpf__clear();
215 return ret; 231 return ret;
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 06f45c1d4256..70edcdfa5672 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -35,6 +35,7 @@ static int test__bpf_parsing(void *obj_buf __maybe_unused,
35static struct { 35static struct {
36 const char *source; 36 const char *source;
37 const char *desc; 37 const char *desc;
38 bool should_load_fail;
38} bpf_source_table[__LLVM_TESTCASE_MAX] = { 39} bpf_source_table[__LLVM_TESTCASE_MAX] = {
39 [LLVM_TESTCASE_BASE] = { 40 [LLVM_TESTCASE_BASE] = {
40 .source = test_llvm__bpf_base_prog, 41 .source = test_llvm__bpf_base_prog,
@@ -48,14 +49,19 @@ static struct {
48 .source = test_llvm__bpf_test_prologue_prog, 49 .source = test_llvm__bpf_test_prologue_prog,
49 .desc = "Compile source for BPF prologue generation test", 50 .desc = "Compile source for BPF prologue generation test",
50 }, 51 },
52 [LLVM_TESTCASE_BPF_RELOCATION] = {
53 .source = test_llvm__bpf_test_relocation,
54 .desc = "Compile source for BPF relocation test",
55 .should_load_fail = true,
56 },
51}; 57};
52 58
53
54int 59int
55test_llvm__fetch_bpf_obj(void **p_obj_buf, 60test_llvm__fetch_bpf_obj(void **p_obj_buf,
56 size_t *p_obj_buf_sz, 61 size_t *p_obj_buf_sz,
57 enum test_llvm__testcase idx, 62 enum test_llvm__testcase idx,
58 bool force) 63 bool force,
64 bool *should_load_fail)
59{ 65{
60 const char *source; 66 const char *source;
61 const char *desc; 67 const char *desc;
@@ -68,6 +74,8 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,
68 74
69 source = bpf_source_table[idx].source; 75 source = bpf_source_table[idx].source;
70 desc = bpf_source_table[idx].desc; 76 desc = bpf_source_table[idx].desc;
77 if (should_load_fail)
78 *should_load_fail = bpf_source_table[idx].should_load_fail;
71 79
72 perf_config(perf_config_cb, NULL); 80 perf_config(perf_config_cb, NULL);
73 81
@@ -136,14 +144,15 @@ int test__llvm(int subtest)
136 int ret; 144 int ret;
137 void *obj_buf = NULL; 145 void *obj_buf = NULL;
138 size_t obj_buf_sz = 0; 146 size_t obj_buf_sz = 0;
147 bool should_load_fail = false;
139 148
140 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX)) 149 if ((subtest < 0) || (subtest >= __LLVM_TESTCASE_MAX))
141 return TEST_FAIL; 150 return TEST_FAIL;
142 151
143 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz, 152 ret = test_llvm__fetch_bpf_obj(&obj_buf, &obj_buf_sz,
144 subtest, false); 153 subtest, false, &should_load_fail);
145 154
146 if (ret == TEST_OK) { 155 if (ret == TEST_OK && !should_load_fail) {
147 ret = test__bpf_parsing(obj_buf, obj_buf_sz); 156 ret = test__bpf_parsing(obj_buf, obj_buf_sz);
148 if (ret != TEST_OK) { 157 if (ret != TEST_OK) {
149 pr_debug("Failed to parse test case '%s'\n", 158 pr_debug("Failed to parse test case '%s'\n",
diff --git a/tools/perf/tests/llvm.h b/tools/perf/tests/llvm.h
index 5150b4d6ef50..0eaa604be99d 100644
--- a/tools/perf/tests/llvm.h
+++ b/tools/perf/tests/llvm.h
@@ -7,14 +7,17 @@
7extern const char test_llvm__bpf_base_prog[]; 7extern const char test_llvm__bpf_base_prog[];
8extern const char test_llvm__bpf_test_kbuild_prog[]; 8extern const char test_llvm__bpf_test_kbuild_prog[];
9extern const char test_llvm__bpf_test_prologue_prog[]; 9extern const char test_llvm__bpf_test_prologue_prog[];
10extern const char test_llvm__bpf_test_relocation[];
10 11
11enum test_llvm__testcase { 12enum test_llvm__testcase {
12 LLVM_TESTCASE_BASE, 13 LLVM_TESTCASE_BASE,
13 LLVM_TESTCASE_KBUILD, 14 LLVM_TESTCASE_KBUILD,
14 LLVM_TESTCASE_BPF_PROLOGUE, 15 LLVM_TESTCASE_BPF_PROLOGUE,
16 LLVM_TESTCASE_BPF_RELOCATION,
15 __LLVM_TESTCASE_MAX, 17 __LLVM_TESTCASE_MAX,
16}; 18};
17 19
18int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz, 20int test_llvm__fetch_bpf_obj(void **p_obj_buf, size_t *p_obj_buf_sz,
19 enum test_llvm__testcase index, bool force); 21 enum test_llvm__testcase index, bool force,
22 bool *should_load_fail);
20#endif 23#endif