diff options
Diffstat (limited to 'tools/lib')
-rw-r--r-- | tools/lib/bpf/btf.c | 97 | ||||
-rw-r--r-- | tools/lib/bpf/btf.h | 3 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.c | 150 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.h | 4 | ||||
-rw-r--r-- | tools/lib/bpf/libbpf.map | 1 |
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 | |||
27 | static struct btf_type btf_void; | 29 | static struct btf_type btf_void; |
28 | 30 | ||
29 | struct btf { | 31 | struct 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 | ||
420 | static 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 | |||
428 | static 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 | |||
483 | int 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 | |||
411 | int btf__load(struct btf *btf) | 506 | int 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; | |||
21 | struct btf_ext; | 21 | struct btf_ext; |
22 | struct btf_type; | 22 | struct btf_type; |
23 | 23 | ||
24 | struct 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 | ||
58 | LIBBPF_API void btf__free(struct btf *btf); | 60 | LIBBPF_API void btf__free(struct btf *btf); |
59 | LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size); | 61 | LIBBPF_API struct btf *btf__new(__u8 *data, __u32 size); |
62 | LIBBPF_API int btf__finalize_data(struct bpf_object *obj, struct btf *btf); | ||
60 | LIBBPF_API int btf__load(struct btf *btf); | 63 | LIBBPF_API int btf__load(struct btf *btf); |
61 | LIBBPF_API __s32 btf__find_by_name(const struct btf *btf, | 64 | LIBBPF_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 | ||
672 | static 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 | |||
716 | int 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 | |||
743 | int 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 | |||
672 | static bool bpf_object__has_maps(const struct bpf_object *obj) | 778 | static 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, | |||
75 | LIBBPF_API struct bpf_object *bpf_object__open_buffer(void *obj_buf, | 75 | LIBBPF_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); |
78 | int bpf_object__section_size(const struct bpf_object *obj, const char *name, | ||
79 | __u32 *size); | ||
80 | int bpf_object__variable_offset(const struct bpf_object *obj, const char *name, | ||
81 | __u32 *off); | ||
78 | LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path); | 82 | LIBBPF_API int bpf_object__pin_maps(struct bpf_object *obj, const char *path); |
79 | LIBBPF_API int bpf_object__unpin_maps(struct bpf_object *obj, | 83 | LIBBPF_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; |