[PATCH] module: make symbol_put_addr() work for all exported symbols

Previous thread: KLOGD loops continuously calling 'syslog' system call when prink is disabled by Madhu R on Thursday, June 19, 2008 - 9:09 am. (2 messages)

Next thread: [PATCH]ACPI: Fix CMOS time error after waking up by /proc/acpi/alarm by Chen, Huacai on Thursday, June 19, 2008 - 9:52 am. (2 messages)
To: Rusty Russell <rusty@...>, Andrew Morton <akpm@...>
Cc: <linux-kernel@...>, <llipavsky@...>
Date: Thursday, June 19, 2008 - 9:11 am

symbol_put_addr() works only for exported function names (symbols present
in text section). This for example means that

symbol_put_addr(__symbol_get("any_exported_variable_name"))

triggers a BUG, which really seems wrong.

This patch introduces generic lookup_symbol_address(), which performs
lookup on symbol tables of all modules according to the address, and makes
symbol_put_addr() use this interface to find the module owner instead.

Signed-off-by: Jiri Kosina <jkosina@suse.cz>

diff --git a/kernel/module.c b/kernel/module.c
index 5f80478..77ff23e 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -302,6 +302,64 @@ static unsigned long find_symbol(const char *name,
return -ENOENT;
}

+/* Lookup module symbol by address */
+const static struct kernel_symbol *lookup_symbol_address(unsigned long addr,
+ struct module **owner)
+{
+ struct module *mod;
+ const struct kernel_symbol *s;
+ unsigned int i;
+
+ /* Core kernel first */
+ struct {
+ const struct kernel_symbol *s_start;
+ const struct kernel_symbol *s_end;
+ } kern_syms[] = {
+ { __start___ksymtab, __stop___ksymtab },
+ { __start___ksymtab_gpl, __stop___ksymtab_gpl },
+ { __start___ksymtab_gpl_future, __stop___ksymtab_gpl_future },
+ { __start___ksymtab_unused, __stop___ksymtab_unused },
+ { __start___ksymtab_unused_gpl, __stop___ksymtab_unused_gpl },
+ };
+
+ for (i = 0; i < ARRAY_SIZE(kern_syms); i++) {
+ for (s = kern_syms[i].s_start; s < kern_syms[i].s_end; s++) {
+ if (s->value == addr) {
+ if (owner)
+ *owner = NULL;
+ return s;
+ }
+ }
+ }
+
+ /* Now try modules */
+ list_for_each_entry(mod, &modules, list) {
+ struct {
+ const struct kernel_symbol *sym;
+ unsigned int num;
+ } arr[] = {
+ { mod->syms, mod->num_syms },
+ { mod->gpl_syms, mod->num_gpl_syms },
+ { mod->gpl_future_syms, mod->num_gpl_future_syms },
+ { mod->unused_syms, mod->num_unused_syms },
+ { mod->unused_gpl_syms, mo...

To: Jiri Kosina <jkosina@...>
Cc: Andrew Morton <akpm@...>, <linux-kernel@...>, <llipavsky@...>
Date: Sunday, June 22, 2008 - 11:48 pm

Hi Jiri,

It might be better to centralize all these iterators, and create a proper
iterator function. Any chance you could rewrite it on top of this patch?
(Lightly tested)

Thanks!
Rusty.

module: generic each_symbol iterator function

Introduce an each_symbol() iterator to avoid duplicating the knowledge
about the 5 different sections containing symbols. Currently only
used by find_symbol(), but will be used by symbol_put_addr() too.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

diff -r 909eac180d25 kernel/module.c
--- a/kernel/module.c Fri Jun 20 15:56:43 2008 +1000
+++ b/kernel/module.c Mon Jun 23 13:40:43 2008 +1000
@@ -152,6 +152,167 @@ extern const unsigned long __start___kcr
#define symversion(base, idx) ((base != NULL) ? ((base) + (idx)) : NULL)
#endif

+struct symsearch {
+ const struct kernel_symbol *start, *stop;
+ const unsigned long *crcs;
+ enum {
+ NOT_GPL_ONLY,
+ GPL_ONLY,
+ WILL_BE_GPL_ONLY,
+ } licence;
+ bool unused;
+};
+
+static bool each_symbol_in_section(const struct symsearch *arr,
+ unsigned int arrsize,
+ struct module *owner,
+ bool (*fn)(const struct symsearch *syms,
+ struct module *owner,
+ unsigned int symnum, void *data),
+ void *data)
+{
+ unsigned int i, j;
+
+ for (j = 0; j < arrsize; j++) {
+ for (i = 0; i < arr[j].stop - arr[j].start; i++)
+ if (fn(&arr[j], owner, i, data))
+ return true;
+ }
+
+ return false;
+}
+
+/* Returns true as soon as fn returns true, otherwise false. */
+static bool each_symbol(bool (*fn)(const struct symsearch *arr,
+ struct module *owner,
+ unsigned int symnum, void *data),
+ void *data)
+{
+ struct module *mod;
+ const struct symsearch arr[] = {
+ { __start___ksymtab, __stop___ksymtab, __start___kcrctab,
+ NOT_GPL_ONLY, false },
+ { __start___ksymtab_gpl, __stop___ksymtab_gpl,
+ __start___kcrctab_gpl,
+ GPL_ONLY, false },
+ { __start___ksymtab_gpl_future, __stop__...

To: Rusty Russell <rusty@...>
Cc: Andrew Morton <akpm@...>, <linux-kernel@...>, <llipavsky@...>
Date: Wednesday, June 25, 2008 - 4:37 am

Hi Rusty,

I see two options how to do this -- either I can make 'value' input
parameter too, so that find_symbol_in_section() could perform lookup
either according to address or according to name (whatever is specified in
the passed struct find_symbol_arg), or I can do a completely new lookup
function for address-wise lookups. What would you prefer? I don't have any
strong preference either way.

Thanks,

--
Jiri Kosina
SUSE Labs
--

To: Jiri Kosina <jkosina@...>
Cc: Andrew Morton <akpm@...>, <linux-kernel@...>, <llipavsky@...>
Date: Wednesday, June 25, 2008 - 11:37 am

A new lookup function (and hence a new structure) I think. It'll be clearer.

Cheers,
Rusty.
--

Previous thread: KLOGD loops continuously calling 'syslog' system call when prink is disabled by Madhu R on Thursday, June 19, 2008 - 9:09 am. (2 messages)

Next thread: [PATCH]ACPI: Fix CMOS time error after waking up by /proc/acpi/alarm by Chen, Huacai on Thursday, June 19, 2008 - 9:52 am. (2 messages)