module.patch From: Jason Wessel CC: rusty@rustcorp.com.au Subject: [PATCH] This allows for KGDB to better deal with autoloaded modules. With more information in the kernel, gdb can be modified in such a way as to automatically read the kernel module section information and allow for easy kernel module debugging. This patch can be found at: ftp://ftp..kernel.org/pub/linux/kernel/people/trini/patches/gdb/6.3/gdb-6.3-kgdb-module-notification.patch In gdb the solib-search-path must contain the location of any module to be debugged. When a module is loaded GDB acts like a shared library has been loaded and will collect the information about the memory location so the kernel module can be debugged or inspected. Even when not using kgdb+gdb, it is quite useful for a debugger+ICE/jtag to have the module section information. Signed-off-by: Milind Dumbare Signed-off-by: Tom Rini Signed-off-by: Jason Wessel --- include/linux/module.h | 16 +++++++++++++ kernel/module.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) Index: linux-2.6-kgdb/include/linux/module.h =================================================================== --- linux-2.6-kgdb.orig/include/linux/module.h +++ linux-2.6-kgdb/include/linux/module.h @@ -226,8 +226,17 @@ enum module_state MODULE_STATE_LIVE, MODULE_STATE_COMING, MODULE_STATE_GOING, + MODULE_STATE_GONE, }; +#ifdef CONFIG_KGDB +#define MAX_SECTNAME 31 +struct mod_section { + void *address; + char name[MAX_SECTNAME + 1]; +}; +#endif + /* Similar stuff for section attributes. */ struct module_sect_attr { @@ -255,6 +264,13 @@ struct module /* Unique handle for this module */ char name[MODULE_NAME_LEN]; +#ifdef CONFIG_KGDB + /* keep kgdb info at the begining so that gdb doesn't have a chance to + * miss out any fields */ + unsigned long num_sections; + struct mod_section *mod_sections; +#endif + /* Sysfs stuff. */ struct module_kobject mkobj; struct module_param_attrs *param_attrs; Index: linux-2.6-kgdb/kernel/module.c =================================================================== --- linux-2.6-kgdb.orig/kernel/module.c +++ linux-2.6-kgdb/kernel/module.c @@ -65,6 +65,7 @@ extern int module_sysfs_initialized; * (add/delete uses stop_machine). */ static DEFINE_MUTEX(module_mutex); static LIST_HEAD(modules); +static DECLARE_MUTEX(notify_mutex); static BLOCKING_NOTIFIER_HEAD(module_notify_list); @@ -710,6 +711,12 @@ sys_delete_module(const char __user *nam if (ret != 0) goto out; + down(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GOING, + mod); + up(¬ify_mutex); + + /* Never wait if forced. */ if (!forced && module_refcount(mod) != 0) wait_for_zero_refcount(mod); @@ -722,6 +729,11 @@ sys_delete_module(const char __user *nam } free_module(mod); + down(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, MODULE_STATE_GONE, + NULL); + up(¬ify_mutex); + out: mutex_unlock(&module_mutex); return ret; @@ -842,6 +854,9 @@ static ssize_t show_initstate(struct mod case MODULE_STATE_GOING: state = "going"; break; + case MODULE_STATE_GONE: + state = "gone"; + break; } return sprintf(buffer, "%s\n", state); } @@ -1206,6 +1221,11 @@ static void free_module(struct module *m /* Arch-specific cleanup. */ module_arch_cleanup(mod); +#ifdef CONFIG_KGDB + /* kgdb info */ + vfree(mod->mod_sections); +#endif + /* Module unload stuff */ module_unload_free(mod); @@ -1465,6 +1485,30 @@ static void setup_modinfo(struct module } } +#ifdef CONFIG_KGDB +int add_modsects(struct module *mod, Elf_Ehdr *hdr, Elf_Shdr *sechdrs, + const char *secstrings) +{ + int i; + + mod->num_sections = hdr->e_shnum - 1; + mod->mod_sections = vmalloc((hdr->e_shnum - 1) * + sizeof(struct mod_section)); + + if (mod->mod_sections == NULL) + return -ENOMEM; + + for (i = 1; i < hdr->e_shnum; i++) { + mod->mod_sections[i - 1].address = (void *)sechdrs[i].sh_addr; + strncpy(mod->mod_sections[i - 1].name, secstrings + + sechdrs[i].sh_name, MAX_SECTNAME); + mod->mod_sections[i - 1].name[MAX_SECTNAME] = '\0'; + } + + return 0; +} +#endif + #ifdef CONFIG_KALLSYMS static int is_exported(const char *name, const struct module *mod) { @@ -1880,6 +1924,12 @@ static struct module *load_module(void _ add_kallsyms(mod, sechdrs, symindex, strindex, secstrings); +#ifdef CONFIG_KGDB + err = add_modsects(mod, hdr, sechdrs, secstrings); + if (err < 0) + goto nomodsectinfo; +#endif + err = module_finalize(hdr, sechdrs, mod); if (err < 0) goto cleanup; @@ -1940,6 +1990,11 @@ static struct module *load_module(void _ arch_cleanup: module_arch_cleanup(mod); cleanup: + +#ifdef CONFIG_KGDB +nomodsectinfo: + vfree(mod->mod_sections); +#endif module_unload_free(mod); module_free(mod, mod->module_init); free_core: @@ -2011,6 +2066,11 @@ sys_init_module(void __user *umod, /* Init routine failed: abort. Try to protect us from buggy refcounters. */ mod->state = MODULE_STATE_GOING; + down(¬ify_mutex); + blocking_notifier_call_chain(&module_notify_list, + MODULE_STATE_GOING, + mod); + up(¬ify_mutex); synchronize_sched(); if (mod->unsafe) printk(KERN_ERR "%s: module is now stuck!\n",