On Wed, Dec 20, 2023 at 03:19:52PM -0700, Daniel Xu wrote: > This commit teaches pahole to parse symbols in .BTF_ids section in > vmlinux and discover exported kfuncs. Pahole then takes the list of > kfuncs and injects a BTF_KIND_DECL_TAG for each kfunc. > > This enables downstream users and tools to dynamically discover which > kfuncs are available on a system by parsing vmlinux or module BTF, both > available in /sys/kernel/btf. > > Example of encoding: > > $ bpftool btf dump file .tmp_vmlinux.btf | rg DECL_TAG | wc -l > 388 > > $ bpftool btf dump file .tmp_vmlinux.btf | rg 68940 > [68940] FUNC 'bpf_xdp_get_xfrm_state' type_id=68939 linkage=static > [128124] DECL_TAG 'kfunc' type_id=68940 component_idx=-1 > > Signed-off-by: Daniel Xu <dxu@xxxxxxxxx> SNIP > + > +static int btf_encoder__tag_kfunc(struct btf_encoder *encoder, const char *kfunc) > +{ > + int nr_types, type_id, err = -1; > + struct btf *btf = encoder->btf; could we store the kuncs in sorted array (by name) and iterate all IDs just once while doing the bsearch for the name over the kfuncs array > + > + nr_types = btf__type_cnt(btf); > + for (type_id = 1; type_id < nr_types; type_id++) { > + const struct btf_type *type; > + const char *name; > + > + type = btf__type_by_id(btf, type_id); > + if (!type) { > + fprintf(stderr, "%s: malformed BTF, can't resolve type for ID %d\n", > + __func__, type_id); > + goto out; > + } > + > + if (!btf_is_func(type)) > + continue; > + > + name = btf__name_by_offset(btf, type->name_off); > + if (!name) { > + fprintf(stderr, "%s: malformed BTF, can't resolve name for ID %d\n", > + __func__, type_id); > + goto out; > + } > + > + if (strcmp(name, kfunc)) > + continue; > + > + err = btf__add_decl_tag(btf, BTF_KFUNC_TYPE_TAG, type_id, -1); > + if (err < 0) { > + fprintf(stderr, "%s: failed to insert kfunc decl tag for '%s': %d\n", > + __func__, kfunc, err); > + goto out; > + } > + > + err = 0; > + break; > + } > + > +out: > + return err; > +} > + > +static int btf_encoder__tag_kfuncs(struct btf_encoder *encoder) > +{ > + const char *filename = encoder->filename; > + GElf_Shdr shdr_mem, *shdr; > + int symbols_shndx = -1; > + int idlist_shndx = -1; > + Elf_Scn *scn = NULL; > + Elf_Data *symbols; > + int fd, err = -1; > + size_t strtabidx; > + Elf *elf = NULL; > + size_t strndx; > + char *secname; > + int nr_syms; > + int i = 0; > + > + fd = open(filename, O_RDONLY); > + if (fd < 0) { > + fprintf(stderr, "Cannot open %s\n", filename); > + goto out; > + } > + > + if (elf_version(EV_CURRENT) == EV_NONE) { > + elf_error("Cannot set libelf version"); > + goto out; > + } > + > + elf = elf_begin(fd, ELF_C_READ, NULL); > + if (elf == NULL) { > + elf_error("Cannot update ELF file"); > + goto out; > + } SNIP > + } > + free(kfunc); > + } > + > + err = 0; > +out: leaking fd and elf object (elf_end) jirka > + return err; > +} > + > int btf_encoder__encode(struct btf_encoder *encoder) > { > int err; > @@ -1366,6 +1563,11 @@ int btf_encoder__encode(struct btf_encoder *encoder) > if (btf__type_cnt(encoder->btf) == 1) > return 0; > > + if (btf_encoder__tag_kfuncs(encoder)) { > + fprintf(stderr, "%s: failed to tag kfuncs!\n", __func__); > + return -1; > + } > + > if (btf__dedup(encoder->btf, NULL)) { > fprintf(stderr, "%s: btf__dedup failed!\n", __func__); > return -1; > -- > 2.42.1 >