aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2018-02-08 18:26:18 -0500
committerDaniel Borkmann <daniel@iogearbox.net>2018-02-08 18:26:28 -0500
commitd977ae593b2d3f9ef0df795eda93f4e6bc92b323 (patch)
tree0e3c09034cb8bc79fea586681d4de51689a23325
parent69fe98edee48b4c3c7d90cb7eea1f1662202137d (diff)
parente3d91b0ca523d53158f435a3e13df7f0cb360ea2 (diff)
Merge branch 'bpf-libbpf-relo-fix-and-tests'
Jesper Dangaard Brouer says: ==================== While playing with using libbpf for the Suricata project, we had issues LLVM >= 4.0.1 generating ELF files that could not be loaded with libbpf (tools/lib/bpf/). During the troubleshooting phase, I wrote a test program and improved the debugging output in libbpf. I turned this into a selftests program, and it also serves as a code example for libbpf in itself. I discovered that there are at least three ELF load issues with libbpf. I left them as TODO comments in (tools/testing/selftests/bpf) test_libbpf.sh. I've only fixed the load issue with eh_frames, and other types of relo-section that does not have exec flags. We can work on the other issues later. ==================== Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
-rw-r--r--tools/include/uapi/linux/bpf_common.h7
-rw-r--r--tools/lib/bpf/libbpf.c51
-rw-r--r--tools/testing/selftests/bpf/Makefile12
-rwxr-xr-xtools/testing/selftests/bpf/test_libbpf.sh49
-rw-r--r--tools/testing/selftests/bpf/test_libbpf_open.c150
5 files changed, 253 insertions, 16 deletions
diff --git a/tools/include/uapi/linux/bpf_common.h b/tools/include/uapi/linux/bpf_common.h
index 18be90725ab0..ee97668bdadb 100644
--- a/tools/include/uapi/linux/bpf_common.h
+++ b/tools/include/uapi/linux/bpf_common.h
@@ -15,9 +15,10 @@
15 15
16/* ld/ldx fields */ 16/* ld/ldx fields */
17#define BPF_SIZE(code) ((code) & 0x18) 17#define BPF_SIZE(code) ((code) & 0x18)
18#define BPF_W 0x00 18#define BPF_W 0x00 /* 32-bit */
19#define BPF_H 0x08 19#define BPF_H 0x08 /* 16-bit */
20#define BPF_B 0x10 20#define BPF_B 0x10 /* 8-bit */
21/* eBPF BPF_DW 0x18 64-bit */
21#define BPF_MODE(code) ((code) & 0xe0) 22#define BPF_MODE(code) ((code) & 0xe0)
22#define BPF_IMM 0x00 23#define BPF_IMM 0x00
23#define BPF_ABS 0x20 24#define BPF_ABS 0x20
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index c64840365433..97073d649c1a 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -319,8 +319,8 @@ bpf_program__init(void *data, size_t size, char *section_name, int idx,
319 319
320 prog->section_name = strdup(section_name); 320 prog->section_name = strdup(section_name);
321 if (!prog->section_name) { 321 if (!prog->section_name) {
322 pr_warning("failed to alloc name for prog under section %s\n", 322 pr_warning("failed to alloc name for prog under section(%d) %s\n",
323 section_name); 323 idx, section_name);
324 goto errout; 324 goto errout;
325 } 325 }
326 326
@@ -742,6 +742,24 @@ bpf_object__init_maps(struct bpf_object *obj)
742 return 0; 742 return 0;
743} 743}
744 744
745static bool section_have_execinstr(struct bpf_object *obj, int idx)
746{
747 Elf_Scn *scn;
748 GElf_Shdr sh;
749
750 scn = elf_getscn(obj->efile.elf, idx);
751 if (!scn)
752 return false;
753
754 if (gelf_getshdr(scn, &sh) != &sh)
755 return false;
756
757 if (sh.sh_flags & SHF_EXECINSTR)
758 return true;
759
760 return false;
761}
762
745static int bpf_object__elf_collect(struct bpf_object *obj) 763static int bpf_object__elf_collect(struct bpf_object *obj)
746{ 764{
747 Elf *elf = obj->efile.elf; 765 Elf *elf = obj->efile.elf;
@@ -763,29 +781,29 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
763 781
764 idx++; 782 idx++;
765 if (gelf_getshdr(scn, &sh) != &sh) { 783 if (gelf_getshdr(scn, &sh) != &sh) {
766 pr_warning("failed to get section header from %s\n", 784 pr_warning("failed to get section(%d) header from %s\n",
767 obj->path); 785 idx, obj->path);
768 err = -LIBBPF_ERRNO__FORMAT; 786 err = -LIBBPF_ERRNO__FORMAT;
769 goto out; 787 goto out;
770 } 788 }
771 789
772 name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name); 790 name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name);
773 if (!name) { 791 if (!name) {
774 pr_warning("failed to get section name from %s\n", 792 pr_warning("failed to get section(%d) name from %s\n",
775 obj->path); 793 idx, obj->path);
776 err = -LIBBPF_ERRNO__FORMAT; 794 err = -LIBBPF_ERRNO__FORMAT;
777 goto out; 795 goto out;
778 } 796 }
779 797
780 data = elf_getdata(scn, 0); 798 data = elf_getdata(scn, 0);
781 if (!data) { 799 if (!data) {
782 pr_warning("failed to get section data from %s(%s)\n", 800 pr_warning("failed to get section(%d) data from %s(%s)\n",
783 name, obj->path); 801 idx, name, obj->path);
784 err = -LIBBPF_ERRNO__FORMAT; 802 err = -LIBBPF_ERRNO__FORMAT;
785 goto out; 803 goto out;
786 } 804 }
787 pr_debug("section %s, size %ld, link %d, flags %lx, type=%d\n", 805 pr_debug("section(%d) %s, size %ld, link %d, flags %lx, type=%d\n",
788 name, (unsigned long)data->d_size, 806 idx, name, (unsigned long)data->d_size,
789 (int)sh.sh_link, (unsigned long)sh.sh_flags, 807 (int)sh.sh_link, (unsigned long)sh.sh_flags,
790 (int)sh.sh_type); 808 (int)sh.sh_type);
791 809
@@ -825,6 +843,14 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
825 } else if (sh.sh_type == SHT_REL) { 843 } else if (sh.sh_type == SHT_REL) {
826 void *reloc = obj->efile.reloc; 844 void *reloc = obj->efile.reloc;
827 int nr_reloc = obj->efile.nr_reloc + 1; 845 int nr_reloc = obj->efile.nr_reloc + 1;
846 int sec = sh.sh_info; /* points to other section */
847
848 /* Only do relo for section with exec instructions */
849 if (!section_have_execinstr(obj, sec)) {
850 pr_debug("skip relo %s(%d) for section(%d)\n",
851 name, idx, sec);
852 continue;
853 }
828 854
829 reloc = realloc(reloc, 855 reloc = realloc(reloc,
830 sizeof(*obj->efile.reloc) * nr_reloc); 856 sizeof(*obj->efile.reloc) * nr_reloc);
@@ -840,6 +866,8 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
840 obj->efile.reloc[n].shdr = sh; 866 obj->efile.reloc[n].shdr = sh;
841 obj->efile.reloc[n].data = data; 867 obj->efile.reloc[n].data = data;
842 } 868 }
869 } else {
870 pr_debug("skip section(%d) %s\n", idx, name);
843 } 871 }
844 if (err) 872 if (err)
845 goto out; 873 goto out;
@@ -1119,8 +1147,7 @@ static int bpf_object__collect_reloc(struct bpf_object *obj)
1119 1147
1120 prog = bpf_object__find_prog_by_idx(obj, idx); 1148 prog = bpf_object__find_prog_by_idx(obj, idx);
1121 if (!prog) { 1149 if (!prog) {
1122 pr_warning("relocation failed: no %d section\n", 1150 pr_warning("relocation failed: no section(%d)\n", idx);
1123 idx);
1124 return -LIBBPF_ERRNO__RELOC; 1151 return -LIBBPF_ERRNO__RELOC;
1125 } 1152 }
1126 1153
diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile
index 566d6adc172a..5c43c187f27c 100644
--- a/tools/testing/selftests/bpf/Makefile
+++ b/tools/testing/selftests/bpf/Makefile
@@ -13,6 +13,7 @@ endif
13CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include 13CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include
14LDLIBS += -lcap -lelf -lrt -lpthread 14LDLIBS += -lcap -lelf -lrt -lpthread
15 15
16# Order correspond to 'make run_tests' order
16TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ 17TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \
17 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user 18 test_align test_verifier_log test_dev_cgroup test_tcpbpf_user
18 19
@@ -22,15 +23,24 @@ TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test
22 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ 23 test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \
23 sample_map_ret0.o test_tcpbpf_kern.o 24 sample_map_ret0.o test_tcpbpf_kern.o
24 25
25TEST_PROGS := test_kmod.sh test_xdp_redirect.sh test_xdp_meta.sh \ 26# Order correspond to 'make run_tests' order
27TEST_PROGS := test_kmod.sh \
28 test_libbpf.sh \
29 test_xdp_redirect.sh \
30 test_xdp_meta.sh \
26 test_offload.py 31 test_offload.py
27 32
33# Compile but not part of 'make run_tests'
34TEST_GEN_PROGS_EXTENDED = test_libbpf_open
35
28include ../lib.mk 36include ../lib.mk
29 37
30BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c 38BPFOBJ := $(OUTPUT)/libbpf.a cgroup_helpers.c
31 39
32$(TEST_GEN_PROGS): $(BPFOBJ) 40$(TEST_GEN_PROGS): $(BPFOBJ)
33 41
42$(TEST_GEN_PROGS_EXTENDED): $(OUTPUT)/libbpf.a
43
34.PHONY: force 44.PHONY: force
35 45
36# force a rebuild of BPFOBJ when its dependencies are updated 46# force a rebuild of BPFOBJ when its dependencies are updated
diff --git a/tools/testing/selftests/bpf/test_libbpf.sh b/tools/testing/selftests/bpf/test_libbpf.sh
new file mode 100755
index 000000000000..d97dc914cd49
--- /dev/null
+++ b/tools/testing/selftests/bpf/test_libbpf.sh
@@ -0,0 +1,49 @@
1#!/bin/sh