aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--tools/lib/bpf/btf.c97
-rw-r--r--tools/lib/bpf/btf.h3
-rw-r--r--tools/lib/bpf/libbpf.c150
-rw-r--r--tools/lib/bpf/libbpf.h4
-rw-r--r--tools/lib/bpf/libbpf.map1
5 files changed, 235 insertions, 20 deletions
diff --git a/tools/lib/bpf/btf.c b/tools/lib/bpf/btf.c
index 87e3020ac1bc..0f9079b9539e 100644
--- a/tools/lib/bpf/btf.c
+++ b/tools/lib/bpf/btf.c
@@ -24,6 +24,8 @@
24 ((k) == BTF_KIND_CONST) || \ 24 ((k) == BTF_KIND_CONST) || \
25 ((k) == BTF_KIND_RESTRICT)) 25 ((k) == BTF_KIND_RESTRICT))
26 26
27#define IS_VAR(k) ((k) == BTF_KIND_VAR)
28
27static struct btf_type btf_void; 29static struct btf_type btf_void;
28 30
29struct btf { 31struct btf {
@@ -212,6 +214,10 @@ static int btf_type_size(struct btf_type *t)
212 return base_size + vlen * sizeof(struct btf_member); 214 return base_size + vlen * sizeof(struct btf_member);
213 case BTF_KIND_FUNC_PROTO: 215 case BTF_KIND_FUNC_PROTO:
214 return base_size + vlen * sizeof(struct btf_param); 216 return base_size + vlen * sizeof(struct btf_param);
217 case BTF_KIND_VAR:
218 return base_size + sizeof(struct btf_var);
219 case BTF_KIND_DATASEC:
220 return base_size + vlen * sizeof(struct btf_var_secinfo);
215 default: 221 default:
216 pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info)); 222 pr_debug("Unsupported BTF_KIND:%u\n", BTF_INFO_KIND(t->info));
217 return -EINVAL; 223 return -EINVAL;
@@ -283,6 +289,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
283 case BTF_KIND_STRUCT: 289 case BTF_KIND_STRUCT:
284 case BTF_KIND_UNION: 290 case BTF_KIND_UNION:
285 case BTF_KIND_ENUM: 291 case BTF_KIND_ENUM:
292 case BTF_KIND_DATASEC:
286 size = t->size; 293 size = t->size;
287 goto done; 294 goto done;
288 case BTF_KIND_PTR: 295 case BTF_KIND_PTR:
@@ -292,6 +299,7 @@ __s64 btf__resolve_size(const struct btf *btf, __u32 type_id)
292 case BTF_KIND_VOLATILE: 299 case BTF_KIND_VOLATILE:
293 case BTF_KIND_CONST: 300 case BTF_KIND_CONST:
294 case BTF_KIND_RESTRICT: 301 case BTF_KIND_RESTRICT:
302 case BTF_KIND_VAR:
295 type_id = t->type; 303 type_id = t->type;
296 break; 304 break;
297 case BTF_KIND_ARRAY: 305 case BTF_KIND_ARRAY:
@@ -326,7 +334,8 @@ int btf__resolve_type(const struct btf *btf, __u32 type_id)
326 t = btf__type_by_id(btf, type_id); 334 t = btf__type_by_id(btf, type_id);
327 while (depth < MAX_RESOLVE_DEPTH && 335 while (depth < MAX_RESOLVE_DEPTH &&
328 !btf_type_is_void_or_null(t) && 336 !btf_type_is_void_or_null(t) &&
329 IS_MODIFIER(BTF_INFO_KIND(t->info))) { 337 (IS_MODIFIER(BTF_INFO_KIND(t->info)) ||
338 IS_VAR(BTF_INFO_KIND(t->info)))) {
330 type_id = t->type; 339 type_id = t->type;
331 t = btf__type_by_id(btf, type_id); 340 t = btf__type_by_id(btf, type_id);
332 depth++; 341 depth++;
@@ -408,6 +417,92 @@ done:
408 return btf; 417 return btf;
409} 418}
410 419
420static int compare_vsi_off(const void *_a, const void *_b)
421{
422 const struct btf_var_secinfo *a = _a;
423 const struct btf_var_secinfo *b = _b;
424
425 return a->offset - b->offset;
426}
427
428static int btf_fixup_datasec(struct bpf_object *obj, struct btf *btf,
429 struct btf_type *t)
430{
431 __u32 size = 0, off = 0, i, vars = BTF_INFO_VLEN(t->info);
432 const char *name = btf__name_by_offset(btf, t->name_off);
433 const struct btf_type *t_var;
434 struct btf_var_secinfo *vsi;
435 struct btf_var *var;
436 int ret;
437
438 if (!name) {
439 pr_debug("No name found in string section for DATASEC kind.\n");
440 return -ENOENT;
441 }
442
443 ret = bpf_object__section_size(obj, name, &size);
444 if (ret || !size || (t->size && t->size != size)) {
445 pr_debug("Invalid size for section %s: %u bytes\n", name, size);
446 return -ENOENT;
447 }
448
449 t->size = size;
450
451 for (i = 0, vsi = (struct btf_var_secinfo *)(t + 1);
452 i < vars; i++, vsi++) {
453 t_var = btf__type_by_id(btf, vsi->type);
454 var = (struct btf_var *)(t_var + 1);
455
456 if (BTF_INFO_KIND(t_var->info) != BTF_KIND_VAR) {
457 pr_debug("Non-VAR type seen in section %s\n", name);
458 return -EINVAL;
459 }
460
461 if (var->linkage == BTF_VAR_STATIC)
462 continue;
463
464 name = btf__name_by_offset(btf, t_var->name_off);
465 if (!name) {
466 pr_debug("No name found in string section for VAR kind\n");
467 return -ENOENT;
468 }
469
470 ret = bpf_object__variable_offset(obj, name, &off);
471 if (ret) {
472 pr_debug("No offset found in symbol table for VAR %s\n", name);
473 return -ENOENT;
474 }
475
476 vsi->offset = off;
477 }
478
479 qsort(t + 1, vars, sizeof(*vsi), compare_vsi_off);
480 return 0;
481}
482
483int btf__finalize_data(struct bpf_object *obj, struct btf *btf)
484{
485 int err = 0;
486 __u32 i;
487
488 for (i = 1; i <= btf->nr_types; i++) {
489 struct btf_type *t = btf->types[i];
490
491 /* Loader needs to fix up some of the things compiler
492 * couldn't get its hands on while emitting BTF. This
493 * is section size and global variable offset. We use
494 * the info from the ELF itself for this purpose.
495 */
496 if (BTF_INFO_KIND(t->info) == BTF_KIND_DATASEC) {
497 err = btf_fixup_datasec(obj, btf, t);
498 if (err)
499 break;
500 }
501 }
502
503 return err;
504}
505
411int btf__load(struct btf *btf) 506int btf__load(struct btf *btf)
412{ 507{
413 __u32 log_buf_size = BPF_LOG_BUF_SIZE; 508 __u32 log_buf_size = BPF_LOG_BUF_SIZE;
diff --git a/tools/lib/bpf/btf.h b/tools/lib/bpf/btf.h
index 28a1e1e59861..c7b399e81fce 100644
--- a/tools/lib/bpf/btf.h
+++ b/tools/lib/bpf/btf.h
@@ -21,6 +21,8 @@ struct btf;
21struct btf_ext; 21struct btf_ext;
22struct btf_type; 22struct btf_type;
23 23
24struct bpf_object;
25
24/* 26/*
25 * The .BTF.ext ELF section layout defined as 27 * The .BTF.ext ELF section layout defined as
26 * struct btf_ext_header 28 * struct btf_ext_header
@@ -57,6 +59,7 @@ struct btf_ext_header {
57 59
58LIBBPF_API void btf__free(struct btf *btf); 60LIBBPF_API void btf__free(struct btf *btf);
59LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size); 61LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size);
62LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf);
60LIBBPF_API int btf__load(struct btf *btf); 63LIBBPF_API int btf__load(struct btf *btf);
61LIBBPF_API __s32 btf__find_by_name(const struct btf *btf, 64LIBBPF_API __s32 btf__find_by_name(const struct btf *btf,
62 const char *type_name); 65 const char *type_name);
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",
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index 12db2822c8e7..c5ff00515ce7 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -75,6 +75,10 @@ struct bpf_object *__bpf_object__open_xattr(struct bpf_object_open_attr *attr,
75LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, 75LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf,
76 size_t obj_buf_sz, 76 size_t obj_buf_sz,
77 const char *name); 77 const char *name);
78int bpf_object__section_size(const struct bpf_object *obj, const char *name,
79 __u32 *size);
80int bpf_object__variable_offset(const struct bpf_object *obj, const char *name,
81 __u32 *off);
78LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path); 82LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path);
79LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj, 83LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj,
80 const char *path); 84 const char *path);
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index be42bdffc8de..673001787cba 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -162,4 +162,5 @@ LIBBPF_0.0.3 {
162 global: 162 global:
163 bpf_map__is_internal; 163 bpf_map__is_internal;
164 bpf_map_freeze; 164 bpf_map_freeze;
165 btf__finalize_data;
165} LIBBPF_0.0.2; 166} LIBBPF_0.0.2;