aboutsummaryrefslogtreecommitdiffstats
path: root/tools/lib
diff options
context:
space:
mode:
Diffstat (limited to 'tools/lib')
-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;