mirror of
https://github.com/torvalds/linux.git
synced 2026-04-18 06:44:00 -04:00
objtool/klp: Match symbols based on demangled_name for global variables
correlate_symbols() will always try to match full name first. If there is no match, try match only demangled_name. In very rare cases, it is possible to have multiple foo.llvm.<hash> in the same kernel. Whenever there is ambiguity like this, fail the klp diff. Signed-off-by: Song Liu <song@kernel.org> Link: https://patch.msgid.link/20260305231531.3847295-7-song@kernel.org Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
@@ -323,6 +323,19 @@ struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *nam
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void iterate_global_symbol_by_demangled_name(const struct elf *elf,
|
||||
const char *demangled_name,
|
||||
void (*process)(struct symbol *sym, void *data),
|
||||
void *data)
|
||||
{
|
||||
struct symbol *sym;
|
||||
|
||||
elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(demangled_name)) {
|
||||
if (!strcmp(sym->demangled_name, demangled_name) && !is_local_sym(sym))
|
||||
process(sym, data);
|
||||
}
|
||||
}
|
||||
|
||||
struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct section *sec,
|
||||
unsigned long offset, unsigned int len)
|
||||
{
|
||||
|
||||
@@ -186,6 +186,9 @@ struct symbol *find_func_by_offset(struct section *sec, unsigned long offset);
|
||||
struct symbol *find_symbol_by_offset(struct section *sec, unsigned long offset);
|
||||
struct symbol *find_symbol_by_name(const struct elf *elf, const char *name);
|
||||
struct symbol *find_global_symbol_by_name(const struct elf *elf, const char *name);
|
||||
void iterate_global_symbol_by_demangled_name(const struct elf *elf, const char *demangled_name,
|
||||
void (*process)(struct symbol *sym, void *data),
|
||||
void *data);
|
||||
struct symbol *find_symbol_containing(const struct section *sec, unsigned long offset);
|
||||
int find_symbol_hole_containing(const struct section *sec, unsigned long offset);
|
||||
struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *sec, unsigned long offset);
|
||||
|
||||
@@ -355,6 +355,46 @@ static bool dont_correlate(struct symbol *sym)
|
||||
strstarts(sym->name, "__initcall__");
|
||||
}
|
||||
|
||||
struct process_demangled_name_data {
|
||||
struct symbol *ret;
|
||||
int count;
|
||||
};
|
||||
|
||||
static void process_demangled_name(struct symbol *sym, void *d)
|
||||
{
|
||||
struct process_demangled_name_data *data = d;
|
||||
|
||||
if (sym->twin)
|
||||
return;
|
||||
|
||||
data->count++;
|
||||
data->ret = sym;
|
||||
}
|
||||
|
||||
/*
|
||||
* When there is no full name match, try match demangled_name. This would
|
||||
* match original foo.llvm.123 to patched foo.llvm.456.
|
||||
*
|
||||
* Note that, in very rare cases, it is possible to have multiple
|
||||
* foo.llvm.<hash> in the same kernel. When this happens, report error and
|
||||
* fail the diff.
|
||||
*/
|
||||
static int find_global_symbol_by_demangled_name(struct elf *elf, struct symbol *sym,
|
||||
struct symbol **out_sym)
|
||||
{
|
||||
struct process_demangled_name_data data = {};
|
||||
|
||||
iterate_global_symbol_by_demangled_name(elf, sym->demangled_name,
|
||||
process_demangled_name,
|
||||
&data);
|
||||
if (data.count > 1) {
|
||||
ERROR("Multiple (%d) correlation candidates for %s", data.count, sym->name);
|
||||
return -1;
|
||||
}
|
||||
*out_sym = data.ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* For each symbol in the original kernel, find its corresponding "twin" in the
|
||||
* patched kernel.
|
||||
@@ -453,6 +493,23 @@ static int correlate_symbols(struct elfs *e)
|
||||
continue;
|
||||
|
||||
sym2 = find_global_symbol_by_name(e->patched, sym1->name);
|
||||
if (sym2 && !sym2->twin) {
|
||||
sym1->twin = sym2;
|
||||
sym2->twin = sym1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Correlate globals with demangled_name.
|
||||
* A separate loop is needed because we want to finish all the
|
||||
* full name correlations first.
|
||||
*/
|
||||
for_each_sym(e->orig, sym1) {
|
||||
if (sym1->bind == STB_LOCAL || sym1->twin)
|
||||
continue;
|
||||
|
||||
if (find_global_symbol_by_demangled_name(e->patched, sym1, &sym2))
|
||||
return -1;
|
||||
|
||||
if (sym2 && !sym2->twin) {
|
||||
sym1->twin = sym2;
|
||||
|
||||
Reference in New Issue
Block a user