When a weak type function is overridden, its symbol will be removed from the symbol table, but its code will not been removed. It will cause find_kallsyms_symbol() to compute a larger function size than it actually is, just because symbol of its following weak function is removed. To fix this issue, check that given address is within the size of the function found. Signed-off-by: Zheng Yejian <zhengyejian@xxxxxxxxxxxxxxx> --- include/linux/module.h | 7 +++++++ kernel/module/kallsyms.c | 19 +++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index 4213d8993cd8..0299d79433ae 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -599,6 +599,13 @@ static inline unsigned long kallsyms_symbol_value(const Elf_Sym *sym) } #endif +#ifndef HAVE_ARCH_KALLSYMS_SYMBOL_TYPE +static inline unsigned int kallsyms_symbol_type(const Elf_Sym *sym) +{ + return ELF_ST_TYPE(sym->st_info); +} +#endif + /* FIXME: It'd be nice to isolate modules during init, too, so they aren't used before they (may) fail. But presently too much code (IDE & SCSI) require entry into the module during init.*/ diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c index bf65e0c3c86f..cce4f81b9933 100644 --- a/kernel/module/kallsyms.c +++ b/kernel/module/kallsyms.c @@ -262,6 +262,7 @@ static const char *find_kallsyms_symbol(struct module *mod, unsigned long nextval, bestval; struct mod_kallsyms *kallsyms = rcu_dereference_sched(mod->kallsyms); struct module_memory *mod_mem; + const Elf_Sym *sym; /* At worse, next value is at end of module */ if (within_module_init(addr, mod)) @@ -278,9 +279,10 @@ static const char *find_kallsyms_symbol(struct module *mod, * starts real symbols at 1). */ for (i = 1; i < kallsyms->num_symtab; i++) { - const Elf_Sym *sym = &kallsyms->symtab[i]; - unsigned long thisval = kallsyms_symbol_value(sym); + unsigned long thisval; + sym = &kallsyms->symtab[i]; + thisval = kallsyms_symbol_value(sym); if (sym->st_shndx == SHN_UNDEF) continue; @@ -292,6 +294,13 @@ static const char *find_kallsyms_symbol(struct module *mod, is_mapping_symbol(kallsyms_symbol_name(kallsyms, i))) continue; + if (kallsyms_symbol_type(sym) == STT_FUNC && + addr >= thisval && addr < thisval + sym->st_size) { + best = i; + bestval = thisval; + nextval = thisval + sym->st_size; + goto found; + } if (thisval <= addr && thisval > bestval) { best = i; bestval = thisval; @@ -303,6 +312,12 @@ static const char *find_kallsyms_symbol(struct module *mod, if (!best) return NULL; + sym = &kallsyms->symtab[best]; + if (kallsyms_symbol_type(sym) == STT_FUNC && sym->st_size && + addr >= kallsyms_symbol_value(sym) + sym->st_size) + return NULL; + +found: if (size) *size = nextval - bestval; if (offset) -- 2.25.1