On Thu, Dec 21, 2023 at 09:35:20AM +0100, Jiri Olsa wrote: > 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 Ack, will take a look. > > > + > > + 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) Good catch thanks. Been writing too much rust... Thanks, Daniel