From: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx> Add __module_build_id() to find module by build_id. This also makes module::build_id available with CONFIG_MODULE_BUILD_ID kconfig. Signed-off-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx> --- include/linux/module.h | 8 +++++++- kernel/module/Kconfig | 3 +++ kernel/module/kallsyms.c | 4 ++-- kernel/module/main.c | 29 +++++++++++++++++++++++++++++ lib/Kconfig.debug | 1 + 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/include/linux/module.h b/include/linux/module.h index b3a643435357..e181056d6af6 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -416,7 +416,7 @@ struct module { /* Unique handle for this module */ char name[MODULE_NAME_LEN]; -#ifdef CONFIG_STACKTRACE_BUILD_ID +#ifdef CONFIG_MODULE_BUILD_ID /* Module build ID */ unsigned char build_id[BUILD_ID_SIZE_MAX]; #endif @@ -622,6 +622,7 @@ static inline bool module_is_coming(struct module *mod) struct module *__module_text_address(unsigned long addr); struct module *__module_address(unsigned long addr); +struct module *__module_build_id(unsigned char *build_id, int size); bool is_module_address(unsigned long addr); bool __is_module_percpu_address(unsigned long addr, unsigned long *can_addr); bool is_module_percpu_address(unsigned long addr); @@ -791,6 +792,11 @@ static inline struct module *__module_text_address(unsigned long addr) return NULL; } +static inline struct module *__module_build_id(unsigned char *build_id, int size) +{ + return NULL; +} + static inline bool is_module_address(unsigned long addr) { return false; diff --git a/kernel/module/Kconfig b/kernel/module/Kconfig index 7b329057997a..5e81dea1afea 100644 --- a/kernel/module/Kconfig +++ b/kernel/module/Kconfig @@ -26,6 +26,9 @@ if MODULES config MODULE_DEBUGFS bool +config MODULE_BUILD_ID + bool + config MODULE_DEBUG bool "Module debugging" depends on DEBUG_FS diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c index bf65e0c3c86f..98f2661c1da8 100644 --- a/kernel/module/kallsyms.c +++ b/kernel/module/kallsyms.c @@ -224,7 +224,7 @@ void add_kallsyms(struct module *mod, const struct load_info *info) mod->core_kallsyms.num_symtab = ndst; } -#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +#if IS_ENABLED(CONFIG_MODULE_BUILD_ID) void init_build_id(struct module *mod, const struct load_info *info) { const Elf_Shdr *sechdr; @@ -338,7 +338,7 @@ int module_address_lookup(unsigned long addr, if (modname) *modname = mod->name; if (modbuildid) { -#if IS_ENABLED(CONFIG_STACKTRACE_BUILD_ID) +#if IS_ENABLED(CONFIG_MODULE_BUILD_ID) *modbuildid = mod->build_id; #else *modbuildid = NULL; diff --git a/kernel/module/main.c b/kernel/module/main.c index 5399c182b3cb..fca9b6a692e3 100644 --- a/kernel/module/main.c +++ b/kernel/module/main.c @@ -3746,6 +3746,35 @@ struct module *__module_text_address(unsigned long addr) return mod; } +/** + * __module_build_id() - get the module whose build_id start with an array. + * @build_id: the first part of the build_id. + * @size: the size of @build_id. + * + * Must be called with preempt disabled or module mutex held so that + * module doesn't get freed during this. + */ +struct module *__module_build_id(unsigned char *build_id, int size) +{ +#ifdef CONFIG_MODULE_BUILD_ID + struct module *mod; + + if (size < 0) + return NULL; + + if (size > BUILD_ID_SIZE_MAX) + size = BUILD_ID_SIZE_MAX; + + list_for_each_entry_rcu(mod, &modules, list) { + if (mod->state == MODULE_STATE_UNFORMED) + continue; + if (!memcmp(mod->build_id, build_id, size)) + return mod; + } +#endif + return NULL; +} + /* Don't grab lock, we're oopsing. */ void print_modules(void) { diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug index cf2a41dc7682..2d3a2f656a86 100644 --- a/lib/Kconfig.debug +++ b/lib/Kconfig.debug @@ -38,6 +38,7 @@ config PRINTK_CALLER config STACKTRACE_BUILD_ID bool "Show build ID information in stacktraces" depends on PRINTK + select MODULE_BUILD_ID if MODULES help Selecting this option adds build ID information for symbols in stacktraces printed with the printk format '%p[SR]b'.