summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/usage.h8
-rw-r--r--modutils/Config.in21
-rw-r--r--modutils/insmod.c113
3 files changed, 139 insertions, 3 deletions
diff --git a/include/usage.h b/include/usage.h
index e5aad2f..beb32fd 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1032,6 +1032,11 @@
" ::shutdown:/bin/umount -a -r\n" \
" ::shutdown:/sbin/swapoff -a\n"
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+ #define USAGE_INSMOD_MAP(a) a
+#else
+ #define USAGE_INSMOD_MAP(a)
+#endif
#define insmod_trivial_usage \
"[OPTION]... MODULE [symbol=value]..."
#define insmod_full_usage \
@@ -1041,7 +1046,8 @@
"\t-k\tMake module autoclean-able.\n" \
"\t-v\tverbose output\n" \
"\t-L\tLock to prevent simultaneous loads of a module\n" \
- "\t-x\tdo not export externs"
+ USAGE_INSMOD_MAP("\t-m\tOutput load map to stdout") \
+ "\t-x\tdo not export externs\n"
#define ip_trivial_usage \
"[ OPTIONS ] { address | link | route | tunnel } { COMMAND | help }"
diff --git a/modutils/Config.in b/modutils/Config.in
index 98aef00..c634e39 100644
--- a/modutils/Config.in
+++ b/modutils/Config.in
@@ -58,6 +58,27 @@ config CONFIG_FEATURE_INSMOD_LOADINKMEM
help
Please submit a patch to add help text for this item.
+config CONFIG_FEATURE_INSMOD_LOAD_MAP
+ bool " Enable load map (-m) option"
+ default n
+ depends on CONFIG_INSMOD
+ help
+ Enabling this, one would be able to get a load map
+ output on stdout. This makes kernel module debugging
+ easier.
+ If you don't plan to debug kernel modules, you
+ don't need this option.
+
+config CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL
+ bool " Symbols in load map"
+ default y
+ depends on CONFIG_FEATURE_INSMOD_LOAD_MAP
+ help
+ Without this option, -m will only output section
+ load map.
+ With this option, -m will also output symbols
+ load map.
+
config CONFIG_LSMOD
bool "lsmod"
default n
diff --git a/modutils/insmod.c b/modutils/insmod.c
index db9e199..af12f36 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.93 2003/01/23 04:48:34 andersen Exp $"
+#ident "$Id: insmod.c,v 1.94 2003/01/23 04:57:35 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.93 2003/01/23 04:48:34 andersen Exp $"
+#ident "$Id: insmod.c,v 1.94 2003/01/23 04:57:35 andersen Exp $"
/* The relocatable object is manipulated using elfin types. */
@@ -3706,6 +3706,98 @@ add_ksymoops_symbols(struct obj_file *f, const char *filename,
}
#endif /* CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS */
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+static void print_load_map(struct obj_file *f)
+{
+ struct obj_symbol *sym;
+ struct obj_symbol **all, **p;
+ struct obj_section *sec;
+ int i, nsyms, *loaded;
+
+ /* Report on the section layout. */
+
+ printf("Sections: Size %-*s Align\n",
+ (int) (2 * sizeof(void *)), "Address");
+
+ for (sec = f->load_order; sec; sec = sec->load_next) {
+ int a;
+ unsigned long tmp;
+
+ for (a = -1, tmp = sec->header.sh_addralign; tmp; ++a)
+ tmp >>= 1;
+ if (a == -1)
+ a = 0;
+
+ printf("%-15s %08lx %0*lx 2**%d\n",
+ sec->name,
+ (long)sec->header.sh_size,
+ (int) (2 * sizeof(void *)),
+ (long)sec->header.sh_addr,
+ a);
+ }
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL
+ /* Quick reference which section indicies are loaded. */
+
+ loaded = alloca(sizeof(int) * (i = f->header.e_shnum));
+ while (--i >= 0)
+ loaded[i] = (f->sections[i]->header.sh_flags & SHF_ALLOC) != 0;
+
+ /* Collect the symbols we'll be listing. */
+
+ for (nsyms = i = 0; i < HASH_BUCKETS; ++i)
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
+ ++nsyms;
+
+ all = alloca(nsyms * sizeof(struct obj_symbol *));
+
+ for (i = 0, p = all; i < HASH_BUCKETS; ++i)
+ for (sym = f->symtab[i]; sym; sym = sym->next)
+ if (sym->secidx <= SHN_HIRESERVE
+ && (sym->secidx >= SHN_LORESERVE || loaded[sym->secidx]))
+ *p++ = sym;
+
+ /* And list them. */
+ printf("\nSymbols:\n");
+ for (p = all; p < all + nsyms; ++p) {
+ char type = '?';
+ unsigned long value;
+
+ sym = *p;
+ if (sym->secidx == SHN_ABS) {
+ type = 'A';
+ value = sym->value;
+ } else if (sym->secidx == SHN_UNDEF) {
+ type = 'U';
+ value = 0;
+ } else {
+ sec = f->sections[sym->secidx];
+
+ if (sec->header.sh_type == SHT_NOBITS)
+ type = 'B';
+ else if (sec->header.sh_flags & SHF_ALLOC) {
+ if (sec->header.sh_flags & SHF_EXECINSTR)
+ type = 'T';
+ else if (sec->header.sh_flags & SHF_WRITE)
+ type = 'D';
+ else
+ type = 'R';
+ }
+ value = sym->value + sec->header.sh_addr;
+ }
+
+ if (ELFW(ST_BIND) (sym->info) == STB_LOCAL)
+ type = tolower(type);
+
+ printf("%0*lx %c %s\n", (int) (2 * sizeof(void *)), value,
+ type, sym->name);
+ }
+#endif
+}
+
+#endif
+
extern int insmod_main( int argc, char **argv)
{
int opt;
@@ -3731,9 +3823,16 @@ extern int insmod_main( int argc, char **argv)
#else
FILE *fp;
#endif
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+ int flag_print_load_map = 0;
+#endif
/* Parse any options */
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+ while ((opt = getopt(argc, argv, "fkqsvxmLo:")) > 0) {
+#else
while ((opt = getopt(argc, argv, "fkqsvxLo:")) > 0) {
+#endif
switch (opt) {
case 'f': /* force loading */
flag_force_load = 1;
@@ -3766,6 +3865,11 @@ extern int insmod_main( int argc, char **argv)
* that. So be careful and plan your life around not
* loading the same module 50 times concurrently. */
break;
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+ case 'm': /* print module load map */
+ flag_print_load_map = 1;
+ break;
+#endif
default:
show_usage();
}
@@ -4005,6 +4109,11 @@ extern int insmod_main( int argc, char **argv)
goto out;
}
+#ifdef CONFIG_FEATURE_INSMOD_LOAD_MAP
+ if(flag_print_load_map)
+ print_load_map(f);
+#endif
+
exit_status = EXIT_SUCCESS;
out: