diff options
Diffstat (limited to 'tools/lib/bpf/libbpf.c')
-rw-r--r-- | tools/lib/bpf/libbpf.c | 150 |
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 | ||
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", |