diff --git a/kpatch-build/create-diff-object.c b/kpatch-build/create-diff-object.c index 56ade7ef..77581fb1 100644 --- a/kpatch-build/create-diff-object.c +++ b/kpatch-build/create-diff-object.c @@ -80,7 +80,8 @@ struct special_section { char *name; enum architecture arch; int (*group_size)(struct kpatch_elf *kelf, int offset); - bool (*group_filter)(struct lookup_table *lookup, + bool (*group_filter)(struct kpatch_elf *kelf, + struct lookup_table *lookup, struct section *relasec, unsigned int offset, unsigned int size); }; @@ -2462,7 +2463,72 @@ static int fixup_group_size(struct kpatch_elf *kelf, int offset) return (int)(rela->addend - offset); } -static bool jump_table_group_filter(struct lookup_table *lookup, +/* + * Exclude function symbols absent from any rela sections (except + * .rela__bug_table) to eliminate undefined symbols modpost errors. + */ +static bool bug_table_group_filter(struct kpatch_elf *kelf, + struct lookup_table *lookup, + struct section *relasec, + unsigned int group_offset, + unsigned int group_size) +{ + unsigned int i = 0, count = 0; + unsigned int *symindex; + struct section *sec; + struct symbol *sym; + struct rela *rela; + bool found; + + list_for_each_entry(rela, &relasec->relas, list) { + if (rela->sym->type == STT_FUNC && rela->sym->sec && + !rela->sym->sec->include) + count++; + } + symindex = (unsigned int *)malloc(sizeof(unsigned int) * count); + if (!symindex) + ERROR("malloc"); + list_for_each_entry(rela, &relasec->relas, list) { + if (rela->sym->type == STT_FUNC && rela->sym->sec && + !rela->sym->sec->include) + symindex[i++] = rela->sym->index; + } + for (i = 0; i < count; i++) { + found = false; + list_for_each_entry(sec, &kelf->sections, list) { + if (!is_rela_section(sec) || + is_debug_section(sec)) + continue; + if (!strcmp(sec->name, relasec->name) || + !strcmp(sec->name, ".rela__mcount_loc") || + !sec->include) + continue; + list_for_each_entry(rela, &sec->relas, list) { + if (symindex[i] == rela->sym->index) { + found = true; + break; + } + } + } + if (!found) { + /* + * Function symbol is present in only __bug_table. + * i.e. function symbol was included earlier, but its + * associated section is not included and not + * referenced in any relas. Exclude the function symbol + * to eliminate UND symbols modpost errors. + */ + sym = find_symbol_by_index(&kelf->symbols, symindex[i]); + if (!sym) + ERROR("could not find function symbol\n"); + sym->include = 0; + } + } + return true; +} + +static bool jump_table_group_filter(struct kpatch_elf *kelf, + struct lookup_table *lookup, struct section *relasec, unsigned int group_offset, unsigned int group_size) @@ -2563,7 +2629,8 @@ static bool jump_table_group_filter(struct lookup_table *lookup, return true; } -static bool static_call_sites_group_filter(struct lookup_table *lookup, +static bool static_call_sites_group_filter(struct kpatch_elf *kelf, + struct lookup_table *lookup, struct section *relasec, unsigned int group_offset, unsigned int group_size) @@ -2630,6 +2697,7 @@ static struct special_section special_sections[] = { .name = "__bug_table", .arch = AARCH64 | X86_64 | PPC64 | S390 | LOONGARCH64, .group_size = bug_table_group_size, + .group_filter = bug_table_group_filter, }, { .name = ".fixup", @@ -2837,7 +2905,7 @@ static void kpatch_regenerate_special_section(struct kpatch_elf *kelf, continue; if (special->group_filter && - !special->group_filter(lookup, relasec, src_offset, group_size)) + !special->group_filter(kelf, lookup, relasec, src_offset, group_size)) continue; /*