aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib/bpf/libbpf.c
diff options
context:
space:
mode:
authorDaniel Borkmann <daniel@iogearbox.net>2019-04-09 17:20:14 -0400
committerAlexei Starovoitov <ast@kernel.org>2019-04-09 20:05:47 -0400
commit1713d68b3bf039d029afd74653c9325f5003ccbe (patch)
tree1a075e1e49244968145a450df10005fc73df0282 /tools/lib/bpf/libbpf.c
parentd859900c4c56dc4f0f8894c92a01dad86917453e (diff)
bpf, libbpf: add support for BTF Var and DataSec
This adds libbpf support for BTF Var and DataSec kinds. Main point here is that libbpf needs to do some preparatory work before the whole BTF object can be loaded into the kernel, that is, fixing up of DataSec size taken from the ELF section size and non-static variable offset which needs to be taken from the ELF's string section. Upstream LLVM doesn't fix these up since at time of BTF emission it is too early in the compilation process thus this information isn't available yet, hence loader needs to take care of it. Note, deduplication handling has not been in the scope of this work and needs to be addressed in a future commit. Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Link: https://reviews.llvm.org/D59441 Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'tools/lib/bpf/libbpf.c')
-rw-r--r--tools/lib/bpf/libbpf.c150
1 files changed, 131 insertions, 19 deletions
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index f7b245fbb960..e2a457e7c318 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -669,6 +669,112 @@ static bool bpf_map_type__is_map_in_map(enum bpf_map_type type)
669 return false; 669 return false;
670} 670}
671 671
672static int bpf_object_search_section_size(const struct bpf_object *obj,
673 const char *name, size_t *d_size)
674{
675 const GElf_Ehdr *ep = &obj->efile.ehdr;
676 Elf *elf = obj->efile.elf;
677 Elf_Scn *scn = NULL;
678 int idx = 0;
679
680 while ((scn = elf_nextscn(elf, scn)) != NULL) {
681 const char *sec_name;
682 Elf_Data *data;
683 GElf_Shdr sh;
684
685 idx++;
686 if (gelf_getshdr(scn, &sh) != &sh) {
687 pr_warning("failed to get section(%d) header from %s\n",
688 idx, obj->path);
689 return -EIO;
690 }
691
692 sec_name = elf_strptr(elf, ep->e_shstrndx, sh.sh_name);
693 if (!sec_name) {
694 pr_warning("failed to get section(%d) name from %s\n",
695 idx, obj->path);
696 return -EIO;
697 }
698
699 if (strcmp(name, sec_name))
700 continue;
701
702 data = elf_getdata(scn, 0);
703 if (!data) {
704 pr_warning("failed to get section(%d) data from %s(%s)\n",
705 idx, name, obj->path);
706 return -EIO;
707 }
708
709 *d_size = data->d_size;
710 return 0;
711 }
712
713 return -ENOENT;
714}
715
716int bpf_object__section_size(const struct bpf_object *obj, const char *name,
717 __u32 *size)
718{
719 int ret = -ENOENT;
720 size_t d_size;
721
722 *size = 0;
723 if (!name) {
724 return -EINVAL;
725 } else if (!strcmp(name, ".data")) {
726 if (obj->efile.data)
727 *size = obj->efile.data->d_size;
728 } else if (!strcmp(name, ".bss")) {
729 if (obj->efile.bss)
730 *size = obj->efile.bss->d_size;
731 } else if (!strcmp(name, ".rodata")) {
732 if (obj->efile.rodata)
733 *size = obj->efile.rodata->d_size;
734 } else {
735 ret = bpf_object_search_section_size(obj, name, &d_size);
736 if (!ret)
737 *size = d_size;
738 }
739
740 return *size ? 0 : ret;
741}
742
743int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
744 __u32 *off)
745{
746 Elf_Data *symbols = obj->efile.symbols;
747 const char *sname;
748 size_t si;
749
750 if (!name || !off)
751 return -EINVAL;
752
753 for (si = 0; si < symbols->d_size / sizeof(GElf_Sym); si++) {
754 GElf_Sym sym;
755
756 if (!gelf_getsym(symbols, si, &sym))
757 continue;
758 if (GELF_ST_BIND(sym.st_info) != STB_GLOBAL ||
759 GELF_ST_TYPE(sym.st_info) != STT_OBJECT)
760 continue;
761
762 sname = elf_strptr(obj->efile.elf, obj->efile.strtabidx,
763 sym.st_name);
764 if (!sname) {
765 pr_warning("failed to get sym name string for var %s\n",
766 name);
767 return -EIO;
768 }
769 if (strcmp(name, sname) == 0) {
770 *off = sym.st_value;
771 return 0;
772 }
773 }
774
775 return -ENOENT;
776}
777
672static bool bpf_object__has_maps(const struct bpf_object *obj) 778static bool bpf_object__has_maps(const struct bpf_object *obj)
673{ 779{
674 return obj->efile.maps_shndx >= 0 || 780 return obj->efile.maps_shndx >= 0 ||
@@ -911,6 +1017,7 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
911 Elf *elf = obj->efile.elf; 1017 Elf *elf = obj->efile.elf;
912 GElf_Ehdr *ep = &obj->efile.ehdr; 1018 GElf_Ehdr *ep = &obj->efile.ehdr;
913 Elf_Data *btf_ext_data = NULL; 1019 Elf_Data *btf_ext_data = NULL;
1020 Elf_Data *btf_data = NULL;
914 Elf_Scn *scn = NULL; 1021 Elf_Scn *scn = NULL;
915 int idx = 0, err = 0; 1022 int idx = 0, err = 0;
916 1023
@@ -954,32 +1061,18 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
954 (int)sh.sh_link, (unsigned long)sh.sh_flags, 1061 (int)sh.sh_link, (unsigned long)sh.sh_flags,
955 (int)sh.sh_type); 1062 (int)sh.sh_type);
956 1063
957 if (strcmp(name, "license") == 0) 1064 if (strcmp(name, "license") == 0) {
958 err = bpf_object__init_license(obj, 1065 err = bpf_object__init_license(obj,
959 data->d_buf, 1066 data->d_buf,
960 data->d_size); 1067 data->d_size);
961 else if (strcmp(name, "version") == 0) 1068 } else if (strcmp(name, "version") == 0) {
962 err = bpf_object__init_kversion(obj, 1069 err = bpf_object__init_kversion(obj,
963 data->d_buf, 1070 data->d_buf,
964 data->d_size); 1071 data->d_size);
965 else if (strcmp(name, "maps") == 0) 1072 } else if (strcmp(name, "maps") == 0) {
966 obj->efile.maps_shndx = idx; 1073 obj->efile.maps_shndx = idx;
967 else if (strcmp(name, BTF_ELF_SEC) == 0) { 1074 } else if (strcmp(name, BTF_ELF_SEC) == 0) {
968 obj->btf = btf__new(data->d_buf, data->d_size); 1075 btf_data = data;
969 if (IS_ERR(obj->btf)) {
970 pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
971 BTF_ELF_SEC, PTR_ERR(obj->btf));
972 obj->btf = NULL;
973 continue;
974 }
975 err = btf__load(obj->btf);
976 if (err) {
977 pr_warning("Error loading %s into kernel: %d. Ignored and continue.\n",
978 BTF_ELF_SEC, err);
979 btf__free(obj->btf);
980 obj->btf = NULL;
981 err = 0;
982 }
983 } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) { 1076 } else if (strcmp(name, BTF_EXT_ELF_SEC) == 0) {
984 btf_ext_data = data; 1077 btf_ext_data = data;
985 } else if (sh.sh_type == SHT_SYMTAB) { 1078 } else if (sh.sh_type == SHT_SYMTAB) {
@@ -1054,6 +1147,25 @@ static int bpf_object__elf_collect(struct bpf_object *obj, int flags)
1054 pr_warning("Corrupted ELF file: index of strtab invalid\n"); 1147 pr_warning("Corrupted ELF file: index of strtab invalid\n");
1055 return LIBBPF_ERRNO__FORMAT; 1148 return LIBBPF_ERRNO__FORMAT;
1056 } 1149 }
1150 if (btf_data) {
1151 obj->btf = btf__new(btf_data->d_buf, btf_data->d_size);
1152 if (IS_ERR(obj->btf)) {
1153 pr_warning("Error loading ELF section %s: %ld. Ignored and continue.\n",
1154 BTF_ELF_SEC, PTR_ERR(obj->btf));
1155 obj->btf = NULL;
1156 } else {
1157 err = btf__finalize_data(obj, obj->btf);
1158 if (!err)
1159 err = btf__load(obj->btf);
1160 if (err) {
1161 pr_warning("Error finalizing and loading %s into kernel: %d. Ignored and continue.\n",
1162 BTF_ELF_SEC, err);
1163 btf__free(obj->btf);
1164 obj->btf = NULL;
1165 err = 0;
1166 }
1167 }
1168 }
1057 if (btf_ext_data) { 1169 if (btf_ext_data) {
1058 if (!obj->btf) { 1170 if (!obj->btf) {
1059 pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n", 1171 pr_debug("Ignore ELF section %s because its depending ELF section %s is not found.\n",