96 lines
3.2 KiB
Diff
96 lines
3.2 KiB
Diff
diff --git a/include/linux/module.h b/include/linux/module.h
|
|
--- a/include/linux/module.h
|
|
+++ b/include/linux/module.h
|
|
@@ -975,6 +975,10 @@ unsigned long module_kallsyms_lookup_name(const char *name);
|
|
|
|
unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name);
|
|
|
|
+void module_kallsyms_on_each_addr(struct module *mod,
|
|
+ void (*fn)(void *, unsigned long),
|
|
+ void *data);
|
|
+
|
|
#else /* CONFIG_MODULES && CONFIG_KALLSYMS */
|
|
|
|
static inline int module_kallsyms_on_each_symbol(const char *modname,
|
|
@@ -1018,6 +1022,12 @@ static inline unsigned long find_kallsyms_symbol_value(struct module *mod,
|
|
return 0;
|
|
}
|
|
|
|
+static inline void module_kallsyms_on_each_addr(struct module *mod,
|
|
+ void (*fn)(void *, unsigned long),
|
|
+ void *data)
|
|
+{
|
|
+}
|
|
+
|
|
#endif /* CONFIG_MODULES && CONFIG_KALLSYMS */
|
|
|
|
/* Define __free(module_put) macro for struct module *. */
|
|
diff --git a/kernel/module/kallsyms.c b/kernel/module/kallsyms.c
|
|
--- a/kernel/module/kallsyms.c
|
|
+++ b/kernel/module/kallsyms.c
|
|
@@ -246,6 +246,18 @@ static const char *kallsyms_symbol_name(struct mod_kallsyms *kallsyms, unsigned
|
|
return kallsyms->strtab + kallsyms->symtab[symnum].st_name;
|
|
}
|
|
|
|
+/*
|
|
+ * Whether find_kallsyms_symbol() may resolve an address to symbol @symnum.
|
|
+ * Unnamed symbols are ignored: they're uninformative and inserted at a whim.
|
|
+ */
|
|
+static bool is_lookup_symbol(struct mod_kallsyms *kallsyms, unsigned int symnum)
|
|
+{
|
|
+ const char *name = kallsyms_symbol_name(kallsyms, symnum);
|
|
+
|
|
+ return kallsyms->symtab[symnum].st_shndx != SHN_UNDEF &&
|
|
+ *name != '\0' && !is_mapping_symbol(name);
|
|
+}
|
|
+
|
|
/*
|
|
* Given a module and address, find the corresponding symbol and return its name
|
|
* while providing its size and offset if needed.
|
|
@@ -286,15 +298,7 @@ static const char *find_kallsyms_symbol(struct module *mod,
|
|
const Elf_Sym *sym = &kallsyms->symtab[i];
|
|
unsigned long thisval = kallsyms_symbol_value(sym);
|
|
|
|
- if (sym->st_shndx == SHN_UNDEF)
|
|
- continue;
|
|
-
|
|
- /*
|
|
- * We ignore unnamed symbols: they're uninformative
|
|
- * and inserted at a whim.
|
|
- */
|
|
- if (*kallsyms_symbol_name(kallsyms, i) == '\0' ||
|
|
- is_mapping_symbol(kallsyms_symbol_name(kallsyms, i)))
|
|
+ if (!is_lookup_symbol(kallsyms, i))
|
|
continue;
|
|
|
|
if (thisval <= addr && thisval > bestval) {
|
|
@@ -458,6 +462,28 @@ unsigned long find_kallsyms_symbol_value(struct module *mod, const char *name)
|
|
return __find_kallsyms_symbol_value(mod, name);
|
|
}
|
|
|
|
+/*
|
|
+ * Call @fn with the address of each symbol of @mod that find_kallsyms_symbol()
|
|
+ * may resolve an address to. Unlike module_kallsyms_on_each_symbol(), this
|
|
+ * also works while @mod is still being loaded.
|
|
+ */
|
|
+void module_kallsyms_on_each_addr(struct module *mod,
|
|
+ void (*fn)(void *, unsigned long),
|
|
+ void *data)
|
|
+{
|
|
+ struct mod_kallsyms *kallsyms;
|
|
+ unsigned int i;
|
|
+
|
|
+ guard(rcu)();
|
|
+ kallsyms = rcu_dereference(mod->kallsyms);
|
|
+
|
|
+ /* ELF starts real symbols at 1. */
|
|
+ for (i = 1; i < kallsyms->num_symtab; i++) {
|
|
+ if (is_lookup_symbol(kallsyms, i))
|
|
+ fn(data, kallsyms_symbol_value(&kallsyms->symtab[i]));
|
|
+ }
|
|
+}
|
|
+
|
|
int module_kallsyms_on_each_symbol(const char *modname,
|
|
int (*fn)(void *, const char *, unsigned long),
|
|
void *data)
|