diff options
| author | Anders Kaseorg <andersk@mit.edu> | 2008-12-05 19:03:58 -0500 | 
|---|---|---|
| committer | Rusty Russell <rusty@rustcorp.com.au> | 2009-03-31 13:05:32 +1030 | 
| commit | 75a66614db21007bcc8c37f9c5d5b922981387b9 (patch) | |
| tree | d02c905a3aee02ec25ce38700f47d0fa57d2cbf7 | |
| parent | a6e6abd575fcbe6572ebc7a70ad616406d206fa8 (diff) | |
Ksplice: Add functions for walking kallsyms symbols
Impact: New API
kallsyms_lookup_name only returns the first match that it finds.  Ksplice
needs information about all symbols with a given name in order to correctly
resolve local symbols.
kallsyms_on_each_symbol provides a generic mechanism for iterating over the
kallsyms table.
Cc: Jeff Arnold <jbarnold@mit.edu>
Cc: Tim Abbott <tabbott@mit.edu>
Signed-off-by: Anders Kaseorg <andersk@mit.edu>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
| -rw-r--r-- | include/linux/kallsyms.h | 15 | ||||
| -rw-r--r-- | include/linux/module.h | 12 | ||||
| -rw-r--r-- | kernel/kallsyms.c | 19 | ||||
| -rw-r--r-- | kernel/module.c | 19 | 
4 files changed, 65 insertions, 0 deletions
| diff --git a/include/linux/kallsyms.h b/include/linux/kallsyms.h index f3fe34391d8e..792274269f2b 100644 --- a/include/linux/kallsyms.h +++ b/include/linux/kallsyms.h @@ -13,10 +13,17 @@  #define KSYM_SYMBOL_LEN (sizeof("%s+%#lx/%#lx [%s]") + (KSYM_NAME_LEN - 1) + \  			 2*(BITS_PER_LONG*3/10) + (MODULE_NAME_LEN - 1) + 1) +struct module; +  #ifdef CONFIG_KALLSYMS  /* Lookup the address for a symbol. Returns 0 if not found. */  unsigned long kallsyms_lookup_name(const char *name); +/* Call a function on each kallsyms symbol in the core kernel */ +int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, +				      unsigned long), +			    void *data); +  extern int kallsyms_lookup_size_offset(unsigned long addr,  				  unsigned long *symbolsize,  				  unsigned long *offset); @@ -43,6 +50,14 @@ static inline unsigned long kallsyms_lookup_name(const char *name)  	return 0;  } +static inline int kallsyms_on_each_symbol(int (*fn)(void *, const char *, +						    struct module *, +						    unsigned long), +					  void *data) +{ +	return 0; +} +  static inline int kallsyms_lookup_size_offset(unsigned long addr,  					      unsigned long *symbolsize,  					      unsigned long *offset) diff --git a/include/linux/module.h b/include/linux/module.h index 69761ce0dbf0..c3d3fc4ffb18 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -387,6 +387,10 @@ int module_get_kallsym(unsigned int symnum, unsigned long *value, char *type,  /* Look for this name: can be of form module:name. */  unsigned long module_kallsyms_lookup_name(const char *name); +int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +					     struct module *, unsigned long), +				   void *data); +  extern void __module_put_and_exit(struct module *mod, long code)  	__attribute__((noreturn));  #define module_put_and_exit(code) __module_put_and_exit(THIS_MODULE, code); @@ -566,6 +570,14 @@ static inline unsigned long module_kallsyms_lookup_name(const char *name)  	return 0;  } +static inline int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +							   struct module *, +							   unsigned long), +						 void *data) +{ +	return 0; +} +  static inline int register_module_notifier(struct notifier_block * nb)  {  	/* no events will happen anyway, so this can always succeed */ diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index 7b8b0f21a5b1..374faf9bfdc7 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -161,6 +161,25 @@ unsigned long kallsyms_lookup_name(const char *name)  	return module_kallsyms_lookup_name(name);  } +int kallsyms_on_each_symbol(int (*fn)(void *, const char *, struct module *, +				      unsigned long), +			    void *data) +{ +	char namebuf[KSYM_NAME_LEN]; +	unsigned long i; +	unsigned int off; +	int ret; + +	for (i = 0, off = 0; i < kallsyms_num_syms; i++) { +		off = kallsyms_expand_symbol(off, namebuf); +		ret = fn(data, namebuf, NULL, kallsyms_addresses[i]); +		if (ret != 0) +			return ret; +	} +	return module_kallsyms_on_each_symbol(fn, data); +} +EXPORT_SYMBOL_GPL(kallsyms_on_each_symbol); +  static unsigned long get_symbol_pos(unsigned long addr,  				    unsigned long *symbolsize,  				    unsigned long *offset) diff --git a/kernel/module.c b/kernel/module.c index 8ddca629e079..dd4389be9152 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -2612,6 +2612,25 @@ unsigned long module_kallsyms_lookup_name(const char *name)  	preempt_enable();  	return ret;  } + +int module_kallsyms_on_each_symbol(int (*fn)(void *, const char *, +					     struct module *, unsigned long), +				   void *data) +{ +	struct module *mod; +	unsigned int i; +	int ret; + +	list_for_each_entry(mod, &modules, list) { +		for (i = 0; i < mod->num_symtab; i++) { +			ret = fn(data, mod->strtab + mod->symtab[i].st_name, +				 mod, mod->symtab[i].st_value); +			if (ret != 0) +				return ret; +		} +	} +	return 0; +}  #endif /* CONFIG_KALLSYMS */  static char *module_flags(struct module *mod, char *buf) | 
