@@ -102,6 +102,8 @@ struct elf_secinfo {
};
struct elf_functions {
+ struct list_head node; /* for elf_functions_list */
+ Elf *elf; /* source ELF */
struct elf_symtab *symtab;
struct elf_function *entries;
int cnt;
@@ -134,7 +136,11 @@ struct btf_encoder {
size_t seccnt;
int encode_vars;
struct list_head func_states;
- struct elf_functions functions;
+ /* This is a list of elf_functions tables, one per ELF.
+ * Multiple ELF modules can be processed in one pahole run,
+ * so we have to store elf_functions tables per ELF.
+ */
+ struct list_head elf_functions_list;
};
struct btf_func {
@@ -148,6 +154,72 @@ struct btf_kfunc_set_range {
uint64_t end;
};
+static inline void elf_functions__delete(struct elf_functions *funcs)
+{
+ for (int i = 0; i < funcs->cnt; i++)
+ free(funcs->entries[i].alias);
+ free(funcs->entries);
+ elf_symtab__delete(funcs->symtab);
+ list_del(&funcs->node);
+ free(funcs);
+}
+
+static int elf_functions__collect(struct elf_functions *functions);
+
+struct elf_functions *elf_functions__new(Elf *elf)
+{
+ struct elf_functions *funcs;
+ int err;
+
+ funcs = calloc(1, sizeof(*funcs));
+ if (!funcs) {
+ err = -ENOMEM;
+ goto out_delete;
+ }
+
+ funcs->symtab = elf_symtab__new(NULL, elf);
+ if (!funcs->symtab) {
+ err = -1;
+ goto out_delete;
+ }
+
+ funcs->elf = elf;
+ err = elf_functions__collect(funcs);
+ if (err < 0)
+ goto out_delete;
+
+ return funcs;
+
+out_delete:
+ elf_functions__delete(funcs);
+ return NULL;
+}
+
+static inline void elf_functions_list__clear(struct list_head *elf_functions_list)
+{
+ struct elf_functions *funcs;
+ struct list_head *pos, *tmp;
+
+ list_for_each_safe(pos, tmp, elf_functions_list) {
+ funcs = list_entry(pos, struct elf_functions, node);
+ elf_functions__delete(funcs);
+ }
+}
+
+static struct elf_functions *elf_functions__find(const Elf *elf, const struct list_head *elf_functions_list)
+{
+ struct elf_functions *funcs;
+ struct list_head *pos;
+
+ list_for_each(pos, elf_functions_list) {
+ funcs = list_entry(pos, struct elf_functions, node);
+ if (funcs->elf == elf)
+ return funcs;
+ }
+ return NULL;
+}
+
+
static LIST_HEAD(encoders);
static pthread_mutex_t encoders__lock = PTHREAD_MUTEX_INITIALIZER;
@@ -1253,9 +1325,6 @@ static void btf_encoder__delete_saved_funcs(struct btf_encoder *encoder)
free(pos->annots);
free(pos);
}
-
- for (int i = 0; i < encoder->functions.cnt; i++)
- free(encoder->functions.entries[i].alias);
}
int btf_encoder__add_saved_funcs(struct btf_encoder *encoder)
@@ -1341,12 +1410,30 @@ static void elf_functions__collect_function(struct elf_functions *functions, GEl
functions->cnt++;
}
+static struct elf_functions *btf_encoder__elf_functions(struct btf_encoder *encoder)
+{
+ struct elf_functions *funcs = NULL;
+
+ if (!encoder->cu || !encoder->cu->elf)
+ return NULL;
+
+ funcs = elf_functions__find(encoder->cu->elf, &encoder->elf_functions_list);
+ if (!funcs) {
+ funcs = elf_functions__new(encoder->cu->elf);
+ if (funcs)
+ list_add(&funcs->node, &encoder->elf_functions_list);
+ }
+
+ return funcs;
+}
+
static struct elf_function *btf_encoder__find_function(const struct btf_encoder *encoder,
const char *name, size_t prefixlen)
{
+ struct elf_functions *funcs = elf_functions__find(encoder->cu->elf, &encoder->elf_functions_list);
struct elf_function key = { .name = name, .prefixlen = prefixlen };
- return bsearch(&key, encoder->functions.entries, encoder->functions.cnt, sizeof(key), functions_cmp);
+ return bsearch(&key, funcs->entries, funcs->cnt, sizeof(key), functions_cmp);
}
static bool btf_name_char_ok(char c, bool first)
@@ -2100,6 +2187,8 @@ int btf_encoder__encode(struct btf_encoder *encoder)
#endif
err = btf_encoder__write_elf(encoder, encoder->btf, BTF_ELF_SEC);
}
+
+ elf_functions_list__clear(&encoder->elf_functions_list);
return err;
}
@@ -2358,8 +2447,10 @@ out:
struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filename, struct btf *base_btf, bool verbose, struct conf_load *conf_load)
{
struct btf_encoder *encoder = zalloc(sizeof(*encoder));
+ struct elf_functions *funcs = NULL;
if (encoder) {
+ encoder->cu = cu;
encoder->raw_output = detached_filename != NULL;
encoder->source_filename = strdup(cu->filename);
encoder->filename = strdup(encoder->raw_output ? detached_filename : cu->filename);
@@ -2387,6 +2478,13 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
if (conf_load->encode_btf_global_vars)
encoder->encode_vars |= BTF_VAR_GLOBAL;
+ INIT_LIST_HEAD(&encoder->elf_functions_list);
+ funcs = btf_encoder__elf_functions(encoder);
+ if (!funcs)
+ goto out_delete;
+
+ encoder->symtab = funcs->symtab;
+
GElf_Ehdr ehdr;
if (gelf_getehdr(cu->elf, &ehdr) == NULL) {
@@ -2407,14 +2505,6 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
goto out_delete;
}
- encoder->symtab = elf_symtab__new(NULL, cu->elf);
- if (!encoder->symtab) {
- if (encoder->verbose)
- printf("%s: '%s' doesn't have symtab.\n", __func__, cu->filename);
- goto out;
- }
- encoder->functions.symtab = encoder->symtab;
-
/* index the ELF sections for later lookup */
GElf_Shdr shdr;
@@ -2452,14 +2542,11 @@ struct btf_encoder *btf_encoder__new(struct cu *cu, const char *detached_filenam
if (!found_percpu && encoder->verbose)
printf("%s: '%s' doesn't have '%s' section\n", __func__, cu->filename, PERCPU_SECTION);
- if (elf_functions__collect(&encoder->functions))
- goto out_delete;
-
if (encoder->verbose)
printf("File %s:\n", cu->filename);
btf_encoders__add(encoder);
}
-out:
+
return encoder;
out_delete:
@@ -2482,11 +2569,8 @@ void btf_encoder__delete(struct btf_encoder *encoder)
zfree(&encoder->source_filename);
btf__free(encoder->btf);
encoder->btf = NULL;
- elf_symtab__delete(encoder->symtab);
- encoder->functions.cnt = 0;
- free(encoder->functions.entries);
- encoder->functions.entries = NULL;
+ elf_functions_list__clear(&encoder->elf_functions_list);
btf_encoder__delete_saved_funcs(encoder);
@@ -2497,12 +2581,20 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
{
struct llvm_annotation *annot;
int btf_type_id, tag_type_id, skipped_types = 0;
+ struct elf_functions *funcs;
uint32_t core_id;
struct function *fn;
struct tag *pos;
int err = 0;
encoder->cu = cu;
+ funcs = btf_encoder__elf_functions(encoder);
+ if (!funcs) {
+ err = -1;
+ goto out;
+ }
+ encoder->symtab = funcs->symtab;
+
encoder->type_id_off = btf__type_cnt(encoder->btf) - 1;
if (!encoder->has_index_type) {
@@ -2586,7 +2678,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
continue;
if (!ftype__has_arg_names(&fn->proto))
continue;
- if (encoder->functions.cnt) {
+ if (funcs->cnt) {
const char *name;
name = function__name(fn);
@@ -2595,7 +2687,7 @@ int btf_encoder__encode_cu(struct btf_encoder *encoder, struct cu *cu, struct co
/* prefer exact function name match... */
func = btf_encoder__find_function(encoder, name, 0);
- if (!func && encoder->functions.suffix_cnt &&
+ if (!func && funcs->suffix_cnt &&
conf_load->btf_gen_optimized) {
/* falling back to name.isra.0 match if no exact
* match is found; only bother if we found any
In case of processing of multiple DWARF modules, multiple ELFs are read. This requires maintaining and elf_functions table per ELF. Replace btf_encoder.functions with btf_encoder.elf_functions_list, that contains all necessary elf_functions tables. The list is initialized when btf_encoder is created. When a new CU is assigned to the encoder in btf_encoder__encode_cu, an elf_functions table will be created if the CU is coming from an unknown Elf. This patch is a variant of [1], following a discussion at [2]. [1] https://lore.kernel.org/bpf/20241213223641.564002-7-ihor.solodrai@pm.me/ [2] https://lore.kernel.org/bpf/C82bYTvJaV4bfT15o25EsBiUvFsj5eTlm17933Hvva76CXjIcu3gvpaOCWPgeZ8g3cZ-RMa8Vp0y1o_QMR2LhPB-LEUYfZCGuCfR_HvkIP8=@pm.me/ Signed-off-by: Ihor Solodrai <ihor.solodrai@pm.me> --- btf_encoder.c | 138 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 115 insertions(+), 23 deletions(-)