aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--modutils/Config.in11
-rw-r--r--modutils/insmod.c176
2 files changed, 185 insertions, 2 deletions
diff --git a/modutils/Config.in b/modutils/Config.in
index 9af0ad6dc..98aef0032 100644
--- a/modutils/Config.in
+++ b/modutils/Config.in
@@ -40,6 +40,17 @@ config CONFIG_FEATURE_INSMOD_VERSION_CHECKING
help
Please submit a patch to add help text for this item.
+config CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+ bool " Add module symbols to kernel symbol table"
+ default n
+ depends on CONFIG_INSMOD
+ help
+ By adding module symbols to the kernel symbol table, Oops messages
+ occuring within kernel modules can be properly debugged. By enabling
+ this feature, module symbols will always be added to the kernel symbol
+ table for properly debugging support. If you are not interested in
+ Oops messages from kernel modules, say N.
+
config CONFIG_FEATURE_INSMOD_LOADINKMEM
bool " In kernel memory optimization (uClinux only)"
default n
diff --git a/modutils/insmod.c b/modutils/insmod.c
index eda4e1a48..db9e1997e 100644
--- a/modutils/insmod.c
+++ b/modutils/insmod.c
@@ -234,7 +234,7 @@
#ifndef MODUTILS_MODULE_H
static const int MODUTILS_MODULE_H = 1;
-#ident "$Id: insmod.c,v 1.92 2002/11/28 11:27:27 aaronl Exp $"
+#ident "$Id: insmod.c,v 1.93 2003/01/23 04:48:34 andersen Exp $"
/* This file contains the structures used by the 2.0 and 2.1 kernels.
We do not use the kernel headers directly because we do not wish
@@ -455,7 +455,7 @@ int delete_module(const char *);
#ifndef MODUTILS_OBJ_H
static const int MODUTILS_OBJ_H = 1;
-#ident "$Id: insmod.c,v 1.92 2002/11/28 11:27:27 aaronl Exp $"
+#ident "$Id: insmod.c,v 1.93 2003/01/23 04:48:34 andersen Exp $"
/* The relocatable object is manipulated using elfin types. */
@@ -2654,6 +2654,37 @@ static int new_create_this_module(struct obj_file *f, const char *m_name)
return 1;
}
+#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+/* add an entry to the __ksymtab section, creating it if necessary */
+static void new_add_ksymtab(struct obj_file *f, struct obj_symbol *sym)
+{
+ struct obj_section *sec;
+ ElfW(Addr) ofs;
+
+ /* ensure __ksymtab is allocated, EXPORT_NOSYMBOLS creates a non-alloc section.
+ * If __ksymtab is defined but not marked alloc, x out the first character
+ * (no obj_delete routine) and create a new __ksymtab with the correct
+ * characteristics.
+ */
+ sec = obj_find_section(f, "__ksymtab");
+ if (sec && !(sec->header.sh_flags & SHF_ALLOC)) {
+ *((char *)(sec->name)) = 'x'; /* override const */
+ sec = NULL;
+ }
+ if (!sec)
+ sec = obj_create_alloced_section(f, "__ksymtab",
+ tgt_sizeof_void_p, 0);
+ if (!sec)
+ return;
+ sec->header.sh_flags |= SHF_ALLOC;
+ sec->header.sh_addralign = tgt_sizeof_void_p; /* Empty section might
+ be byte-aligned */
+ ofs = sec->header.sh_size;
+ obj_symbol_patch(f, sec->idx, ofs, sym);
+ obj_string_patch(f, sec->idx, ofs + tgt_sizeof_void_p, sym->name);
+ obj_extend_section(sec, 2 * tgt_sizeof_char_p);
+}
+#endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
static int new_create_module_ksymtab(struct obj_file *f)
{
@@ -2811,6 +2842,7 @@ new_init_module(const char *m_name, struct obj_file *f,
#define new_init_module(x, y, z) TRUE
#define new_create_this_module(x, y) 0
+#define new_add_ksymtab(x, y) -1
#define new_create_module_ksymtab(x)
#define query_module(v, w, x, y, z) -1
@@ -3538,6 +3570,142 @@ static void check_tainted_module(struct obj_file *f, char *m_name)
#define check_tainted_module(x, y) do { } while(0);
#endif /* CONFIG_FEATURE_CHECK_TAINTED_MODULE */
+#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+/* add module source, timestamp, kernel version and a symbol for the
+ * start of some sections. this info is used by ksymoops to do better
+ * debugging.
+ */
+static int
+get_module_version(struct obj_file *f, char str[STRVERSIONLEN])
+{
+#ifdef CONFIG_FEATURE_INSMOD_VERSION_CHECKING
+ if (get_modinfo_value(f, "kernel_version") == NULL)
+ return old_get_module_version(f, str);
+ else
+ return new_get_module_version(f, str);
+#else /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
+ strncpy(str, "???", sizeof(str));
+ return -1;
+#endif /* CONFIG_FEATURE_INSMOD_VERSION_CHECKING */
+}
+
+/* add module source, timestamp, kernel version and a symbol for the
+ * start of some sections. this info is used by ksymoops to do better
+ * debugging.
+ */
+static void
+add_ksymoops_symbols(struct obj_file *f, const char *filename,
+ const char *m_name)
+{
+ static const char symprefix[] = "__insmod_";
+ struct obj_section *sec;
+ struct obj_symbol *sym;
+ char *name, *absolute_filename;
+ char str[STRVERSIONLEN], real[PATH_MAX];
+ int i, l, lm_name, lfilename, use_ksymtab, version;
+ struct stat statbuf;
+
+ static const char *section_names[] = {
+ ".text",
+ ".rodata",
+ ".data",
+ ".bss"
+ ".sbss"
+ };
+
+ if (realpath(filename, real)) {
+ absolute_filename = xstrdup(real);
+ }
+ else {
+ int save_errno = errno;
+ error_msg("cannot get realpath for %s", filename);
+ errno = save_errno;
+ perror("");
+ absolute_filename = xstrdup(filename);
+ }
+
+ lm_name = strlen(m_name);
+ lfilename = strlen(absolute_filename);
+
+ /* add to ksymtab if it already exists or there is no ksymtab and other symbols
+ * are not to be exported. otherwise leave ksymtab alone for now, the
+ * "export all symbols" compatibility code will export these symbols later.
+ */
+ use_ksymtab = obj_find_section(f, "__ksymtab") || !flag_export;
+
+ if ((sec = obj_find_section(f, ".this"))) {
+ /* tag the module header with the object name, last modified
+ * timestamp and module version. worst case for module version
+ * is 0xffffff, decimal 16777215. putting all three fields in
+ * one symbol is less readable but saves kernel space.
+ */
+ l = sizeof(symprefix)+ /* "__insmod_" */
+ lm_name+ /* module name */
+ 2+ /* "_O" */
+ lfilename+ /* object filename */
+ 2+ /* "_M" */
+ 2*sizeof(statbuf.st_mtime)+ /* mtime in hex */
+ 2+ /* "_V" */
+ 8+ /* version in dec */
+ 1; /* nul */
+ name = xmalloc(l);
+ if (stat(absolute_filename, &statbuf) != 0)
+ statbuf.st_mtime = 0;
+ version = get_module_version(f, str); /* -1 if not found */
+ snprintf(name, l, "%s%s_O%s_M%0*lX_V%d",
+ symprefix, m_name, absolute_filename,
+ (int)(2*sizeof(statbuf.st_mtime)), statbuf.st_mtime,
+ version);
+ sym = obj_add_symbol(f, name, -1,
+ ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ new_add_ksymtab(f, sym);
+ }
+ free(absolute_filename);
+#ifdef _NOT_SUPPORTED_
+ /* record where the persistent data is going, same address as previous symbol */
+
+ if (f->persist) {
+ l = sizeof(symprefix)+ /* "__insmod_" */
+ lm_name+ /* module name */
+ 2+ /* "_P" */
+ strlen(f->persist)+ /* data store */
+ 1; /* nul */
+ name = xmalloc(l);
+ snprintf(name, l, "%s%s_P%s",
+ symprefix, m_name, f->persist);
+ sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ new_add_ksymtab(f, sym);
+ }
+#endif /* _NOT_SUPPORTED_ */
+ /* tag the desired sections if size is non-zero */
+
+ for (i = 0; i < sizeof(section_names)/sizeof(section_names[0]); ++i) {
+ if ((sec = obj_find_section(f, section_names[i])) &&
+ sec->header.sh_size) {
+ l = sizeof(symprefix)+ /* "__insmod_" */
+ lm_name+ /* module name */
+ 2+ /* "_S" */
+ strlen(sec->name)+ /* section name */
+ 2+ /* "_L" */
+ 8+ /* length in dec */
+ 1; /* nul */
+ name = xmalloc(l);
+ snprintf(name, l, "%s%s_S%s_L%ld",
+ symprefix, m_name, sec->name,
+ (long)sec->header.sh_size);
+ sym = obj_add_symbol(f, name, -1, ELFW(ST_INFO) (STB_GLOBAL, STT_NOTYPE),
+ sec->idx, sec->header.sh_addr, 0);
+ if (use_ksymtab)
+ new_add_ksymtab(f, sym);
+ }
+ }
+}
+#endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+
extern int insmod_main( int argc, char **argv)
{
int opt;
@@ -3788,6 +3956,10 @@ extern int insmod_main( int argc, char **argv)
arch_create_got(f);
hide_special_symbols(f);
+#ifdef CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS
+ add_ksymoops_symbols(f, m_filename, m_name);
+#endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+
if (k_new_syscalls)
new_create_module_ksymtab(f);