diff -aur -x Makefile crash-4.0-3.16/defs.h crash-4.0-3.16-sym/defs.h
--- crash-4.0-3.16/defs.h	2006-12-21 11:54:11 -08:00
+++ crash-4.0-3.16-sym/defs.h	2006-12-22 12:20:36 -08:00
@@ -1759,6 +1759,7 @@
 	ulong dwarf_eh_frame_size;
 };
 
+/* flags for st */
 #define KERNEL_SYMS        (0x1)
 #define MODULE_SYMS        (0x2)
 #define LOAD_MODULE_SYMS   (0x4)
@@ -1770,6 +1771,13 @@
 #define FORCE_DEBUGINFO   (0x80)
 #define CRC_MATCHES      (0x100)
 #define ADD_SYMBOL_FILE  (0x200)
+#define FORCE_V2_MOD_SYM (0x400)
+#ifndef V2_MOD_SYM_WORKS
+#define USE_V2_MOD_SYM() (st->flags & FORCE_V2_MOD_SYM)
+#else
+#define USE_V2_MOD_SYM() (1)
+#endif
+
 
 #endif /* !GDB_COMMON */
 
@@ -1784,6 +1792,8 @@
 #define MOD_REMOTE      (0x4)
 #define MOD_KALLSYMS    (0x8)
 #define MOD_INITRD     (0x10)
+
+#define SEC_FOUND       (0x10000)
 
 struct mod_section_data {
 #if defined(GDB_6_1)
diff -aur -x Makefile crash-4.0-3.16/gdb-6.1/gdb/symtab.c crash-4.0-3.16-sym/gdb-6.1/gdb/symtab.c
--- crash-4.0-3.16/gdb-6.1/gdb/symtab.c	2006-12-21 11:54:11 -08:00
+++ crash-4.0-3.16-sym/gdb-6.1/gdb/symtab.c	2006-12-22 11:33:01 -08:00
@@ -4529,8 +4529,12 @@
 	req->name = lm->mod_namelist;
 	gdb_delete_symbol_file(req);
 
-        sprintf(req->buf, "add-symbol-file %s 0x%lx", lm->mod_namelist, 
-		lm->mod_text_start);
+        sprintf(req->buf, "add-symbol-file %s 0x%lx "
+		"-s .data 0x%lx "
+		"-s .bss 0x%lx "
+		"-s .rodata 0x%lx", lm->mod_namelist, 
+		lm->mod_text_start, lm->mod_data_start, lm->mod_bss_start,
+		lm->mod_rodata_start);
 
        	execute_command(req->buf, FALSE);
 
diff -aur -x Makefile crash-4.0-3.16/help.c crash-4.0-3.16-sym/help.c
--- crash-4.0-3.16/help.c	2006-12-21 11:54:11 -08:00
+++ crash-4.0-3.16-sym/help.c	2006-12-22 12:02:25 -08:00
@@ -3423,6 +3423,7 @@
 "                       If a directory argument is appended, then the search",
 "                       will be restricted to that directory.",
 "                   -D  Deletes the symbolic and debugging data of all modules.",
+"                   -l  Force load of module symbols with new mechanism",
 "                   -r  Reinitialize module data. All currently-loaded symbolic",
 "                       and debugging data will be deleted, and the installed",
 "                       module list will be updated (live system only).",
diff -aur -x Makefile crash-4.0-3.16/kernel.c crash-4.0-3.16-sym/kernel.c
--- crash-4.0-3.16/kernel.c	2006-12-21 11:54:11 -08:00
+++ crash-4.0-3.16-sym/kernel.c	2006-12-22 12:00:13 -08:00
@@ -2307,7 +2307,7 @@
 	address = 0;
 	flag = LIST_MODULE_HDR;
 
-        while ((c = getopt(argcnt, args, "rd:Ds:St:")) != EOF) {
+        while ((c = getopt(argcnt, args, "rd:Ds:St:l")) != EOF) {
                 switch(c)
 		{
                 case 'r':
@@ -2338,6 +2338,15 @@
                                 modref = optarg;
                         else
                                 cmd_usage(pc->curcmd, SYNOPSIS);
+                        break;
+
+                /*
+                 * kmod version 2 symbols do not always load correctly.
+                 * It appears to work on x86, and x86_64, but problems
+                 * have been seen on s390x.  So have it off by default.
+                 */
+                case 'l':
+                        st->flags |= FORCE_V2_MOD_SYM;
                         break;
 
 		case 't':
diff -aur -x Makefile crash-4.0-3.16/symbols.c crash-4.0-3.16-sym/symbols.c
--- crash-4.0-3.16/symbols.c	2006-12-21 11:54:11 -08:00
+++ crash-4.0-3.16-sym/symbols.c	2006-12-27 14:45:03 -08:00
@@ -36,7 +36,9 @@
 static int load_module_index(struct syment *);
 static void section_header_info(bfd *, asection *, void *);
 static void store_section_data(struct load_module *, bfd *, asection *);
-static void calculate_load_order(struct load_module *, bfd *);
+static void calculate_load_order_v1(struct load_module *, bfd *);
+static void calculate_load_order_v2(struct load_module *, bfd *, int,
+        void *, long, unsigned int);
 static void check_insmod_builtin(struct load_module *, int, ulong *);
 static int is_insmod_builtin(struct load_module *, struct syment *);
 struct load_module;
@@ -7049,8 +7051,9 @@
 	i = lm->mod_sections;
 	lm->mod_section_data[i].section = section;
 	lm->mod_section_data[i].priority = prio;
-	lm->mod_section_data[i].flags = section->flags;
+	lm->mod_section_data[i].flags = section->flags & ~SEC_FOUND;
 	lm->mod_section_data[i].size = bfd_section_size(bfd, section);
+	lm->mod_section_data[i].offset = 0;
 	if (strlen(name) < MAX_MOD_SEC_NAME)
 		strcpy(lm->mod_section_data[i].name, name);
 	else
@@ -7102,7 +7105,7 @@
  */
 
 static void
-calculate_load_order(struct load_module *lm, bfd *bfd)
+calculate_load_order_v1(struct load_module *lm, bfd *bfd)
 {
 	int i;
 	asection *section;
@@ -7162,6 +7165,125 @@
 }
 
 /*
+ * Later versions of kmod no longer get the help from insmod,
+ * and while the heuristics might work, it's relatively
+ * straightforward to just try to match the sections in the object file
+ * with exported symbols.
+ *
+ * This works well if kallsyms is set, but may not work so well in other
+ * instances.
+ */
+static void
+calculate_load_order_v2(struct load_module *lm, bfd *bfd, int dynamic,
+	void *minisyms, long symcount, unsigned int size)
+{
+	struct syment *s1, *s2;
+	ulong sec_start, sec_end;
+	bfd_byte *from, *fromend;
+	asymbol *store;
+	asymbol *sym;
+	symbol_info syminfo;
+	char *secname;
+	int i;
+
+	s1 = lm->mod_symtable;
+	s2 = lm->mod_symend;
+	while (s1 < s2) {
+            ulong sym_offset = s1->value - lm->mod_base;
+	    if (MODULE_PSEUDO_SYMBOL(s1)) {
+		    s1++;
+		    continue;
+	    }
+
+            /* Skip over symbols whose sections have been identified. */
+            for (i = 0; i < lm->mod_sections; i++) {
+                    if ((lm->mod_section_data[i].flags & SEC_FOUND) == 0)
+                            continue;
+                    if (sym_offset >= lm->mod_section_data[i].offset
+                        && sym_offset < lm->mod_section_data[i].offset
+                            + lm->mod_section_data[i].size) {
+                            break;
+                    }
+            }
+
+            /* Matched one of the sections. Skip symbol. */
+            if (i < lm->mod_sections) {
+                    if (CRASHDEBUG(2)) {
+                        fprintf(fp, "skip %lx %s\n", s1->value, s1->name);
+                    }
+                    s1++;
+                    continue;
+            }
+
+	    /* Find the symbol in the object file. */
+	    from = (bfd_byte *) minisyms;
+	    fromend = from + symcount * size;
+	    secname = NULL;
+	    for (; from < fromend; from += size) {
+		    if ((sym = bfd_minisymbol_to_symbol(bfd, dynamic, from,
+			    store)) == NULL)
+			    error(FATAL,
+				    "bfd_minisymbol_to_symbol() failed\n");
+
+		    bfd_get_symbol_info(bfd, sym, &syminfo);
+		    if (strcmp(syminfo.name, s1->name) == 0) {
+			    secname = (char *)bfd_get_section_name(bfd, sym->section);
+			    break;
+		    }
+
+	    }
+	    if (secname == NULL) {
+                    if (CRASHDEBUG(1)) {
+                        fprintf(fp, "symbol %s not found in module\n", s1->name);
+                    }
+		    s1++;
+		    continue;
+	    }
+
+	    /* Match the section it came in. */
+	    for (i = 0; i < lm->mod_sections; i++) {
+		    if (STREQ(lm->mod_section_data[i].name, secname)) {
+			    break;
+		    }
+	    }
+
+	    if (i == lm->mod_sections) {
+		    fprintf(fp, "?? Section not found for symbol %s\n",
+			s1->name);
+		    s1++;
+		    continue;
+	    }
+
+            /* Update the offset information for the section */
+	    sec_start = s1->value - syminfo.value;
+	    sec_end = sec_start + lm->mod_section_data[i].size;
+	    lm->mod_section_data[i].offset = sec_start - lm->mod_base;
+            lm->mod_section_data[i].flags |= SEC_FOUND;
+
+	    if (CRASHDEBUG(1)) {
+		    fprintf(fp, "update sec offset sym %s @ %lx  val %lx  section %s\n",
+			    s1->name, s1->value, syminfo.value, secname);
+	    }
+
+	    if (strcmp(secname, ".text") == 0)
+		    lm->mod_text_start = sec_start;
+
+	    if (strcmp(secname, ".bss") == 0)
+		    lm->mod_bss_start = sec_start;
+
+	    if (strcmp(secname, ".data") == 0)
+		    lm->mod_data_start = sec_start;
+
+	    if (strcmp(secname, ".data") == 0)
+		    lm->mod_data_start = sec_start;
+
+	    if (strcmp(secname, ".rodata") == 0)
+		    lm->mod_rodata_start = sec_start;
+            s1++;
+	}
+}
+
+/*
  *  Later versons of insmod store basic address information of each
  *  module in a format that looks like the following example of the
  *  nfsd module:
@@ -7274,8 +7396,8 @@
 	}
 
 	if (CRASHDEBUG(1))
-		fprintf(fp, "load_module_symbols: %s %s %lx\n",
-			modref, namelist, base_addr);
+		fprintf(fp, "load_module_symbols: %s %s %lx %lx\n",
+			modref, namelist, base_addr, kt->flags);
 
 	switch (kt->flags & (KMOD_V1|KMOD_V2))
 	{
@@ -7288,7 +7410,10 @@
                 	strcpy(lm->mod_namelist, namelist);
         	else
                 	strncpy(lm->mod_namelist, namelist, MAX_MOD_NAMELIST-1);
-		goto add_symbols;
+                if (USE_V2_MOD_SYM()) {
+                        goto add_symbols;
+                }
+                
 	}
 
   	if ((mbfd = bfd_openr(namelist, NULL)) == NULL) 
@@ -7308,6 +7433,10 @@
 	else if (symcount == 0)
 		error(FATAL, "no symbols in object file: %s\n", namelist);
 
+        if (CRASHDEBUG(1)) {
+                fprintf(fp, "%ld symbols found in obj file %s\n", symcount,
+                    namelist);
+        }
         sort_x = bfd_make_empty_symbol(mbfd);
         sort_y = bfd_make_empty_symbol(mbfd);
         if (sort_x == NULL || sort_y == NULL)
@@ -7315,8 +7444,8 @@
 
 	gnu_qsort(mbfd, minisyms, symcount, size, sort_x, sort_y);
 
-	store_load_module_symbols(mbfd, FALSE, minisyms, symcount, 
-		size, base_addr, namelist); 
+        store_load_module_symbols(mbfd, FALSE, minisyms, symcount, 
+                size, base_addr, namelist); 
 
 	free(minisyms);
 
@@ -7473,7 +7602,12 @@
 
         bfd_map_over_sections(bfd, section_header_info, MODULE_SECTIONS);
 
-	calculate_load_order(lm, bfd);
+	if (kt->flags & KMOD_V1)
+		calculate_load_order_v1(lm, bfd);
+	else
+		calculate_load_order_v2(lm, bfd, dynamic, minisyms,
+			symcount, size);
+
 
         from = (bfd_byte *) minisyms;
         fromend = from + symcount * size;
@@ -7486,104 +7620,112 @@
                 bfd_get_symbol_info(bfd, sym, &syminfo);
 
 		secname = (char *)bfd_get_section_name(bfd, sym->section);
+                found = 0;
 
-		switch (syminfo.type)
-		{
-		case 'b':
-		case 'B':
-                       if (CRASHDEBUG(2))
-                            fprintf(fp, "%08lx (%c) [%s] %s\n",  
-				(ulong)syminfo.value,
-                                syminfo.type, secname, syminfo.name);
+                if (kt->flags & KMOD_V1) {
+                        switch (syminfo.type)
+                        {
+                        case 'b':
+                        case 'B':
+                               if (CRASHDEBUG(2))
+                                    fprintf(fp, "%08lx (%c) [%s] %s\n",  
+                                        (ulong)syminfo.value,
+                                        syminfo.type, secname, syminfo.name);
 
-                        syminfo.value += lm->mod_bss_start;
-                        strcpy(name, syminfo.name);
-                        strip_module_symbol_end(name);
+                                if (!lm->mod_bss_start)
+                                        break;
 
-                        if (machdep->verify_symbol(name, syminfo.value, 
-			    syminfo.type)) {
-                                sp->value = syminfo.value;
-				sp->type = syminfo.type;
-				
-                                namespace_ctl(NAMESPACE_INSTALL,
-                                        &lm->mod_load_namespace, sp, name); 
+                                syminfo.value += lm->mod_bss_start;
+                                found = 1;
+                                break;
 
-                                if (CRASHDEBUG(1))
-                                    fprintf(fp, "%08lx %s\n",  sp->value,
-                                        name);
+                        case 'd': 
+                        case 'D':
+                                if (CRASHDEBUG(2))
+                                    fprintf(fp, "%08lx (%c) [%s] %s\n",  
+                                        (ulong)syminfo.value,
+                                        syminfo.type, secname, syminfo.name);
+
+                                if (STREQ(secname, ".rodata")) {
+                                        if (!lm->mod_rodata_start)
+                                                break;
+                                        syminfo.value += lm->mod_rodata_start;
+                                } else {
+                                        if (!lm->mod_data_start)
+                                                break;
+                                        syminfo.value += lm->mod_data_start;
+                                }
+                                found = 1;
+                                break;
 
-                                sp++;
-                                lm->mod_load_symcnt++;
-                        }
-			break;
+                        case 't':
+                        case 'T':
+                                if (CRASHDEBUG(2))
+                                    fprintf(fp, "%08lx (%c) [%s] %s\n",  
+                                        (ulong)syminfo.value, 
+                                        syminfo.type, secname, syminfo.name); 
 
-		case 'd': 
-		case 'D':
-                        if (CRASHDEBUG(2))
-                            fprintf(fp, "%08lx (%c) [%s] %s\n",  
-				(ulong)syminfo.value,
-                                syminfo.type, secname, syminfo.name);
+                                if (! lm->mod_text_start) {
+                                        break;
+                                }
 
-			if (STREQ(secname, ".rodata"))
-                        	syminfo.value += lm->mod_rodata_start;
-			else
-                        	syminfo.value += lm->mod_data_start;
+                                if ((st->flags & INSMOD_BUILTIN) &&
+                                    (STREQ(name, "init_module") || 
+                                    STREQ(name, "cleanup_module")))
+                                        break;
+
+                                syminfo.value += lm->mod_text_start;
+                                found = 1;
+                                break;
+
+                        default:
+                                break;
+                        }
+
+                } else {
+                        /* Match the section it came in. */
+                        for (i = 0; i < lm->mod_sections; i++) {
+                                if (STREQ(lm->mod_section_data[i].name, secname)
+                                    && (lm->mod_section_data[i].flags & SEC_FOUND)) {
+                                        break;
+                                }
+                        }
+                        if (i < lm->mod_sections) {
+                                if (CRASHDEBUG(2))
+                                    fprintf(fp, "%08lx (%c) [%s] %s\n",  
+                                        (ulong)syminfo.value, 
+                                        syminfo.type, secname, syminfo.name); 
+
+                                if ((st->flags & INSMOD_BUILTIN) &&
+                                    (STREQ(name, "init_module") || 
+                                    STREQ(name, "cleanup_module"))) {
+                                        found = 0;
+                                } else {
+                                        syminfo.value += lm->mod_section_data[i].offset + lm->mod_base;
+                                        found = 1;
+                                }
+                        }
+                }
 
+                if (found) {
                         strcpy(name, syminfo.name);
                         strip_module_symbol_end(name);
 
-                        if (machdep->verify_symbol(name, syminfo.value, 
-			    syminfo.type)) {
+                        if (machdep->verify_symbol(name, syminfo.value,
+                            syminfo.type)) {
                                 sp->value = syminfo.value;
-				sp->type = syminfo.type;
+                                sp->type = syminfo.type;
                                 namespace_ctl(NAMESPACE_INSTALL,
-                                        &lm->mod_load_namespace, sp, name); 
+                                        &lm->mod_load_namespace, sp, name);
 
                                 if (CRASHDEBUG(1))
-                                    fprintf(fp, "%08lx %s\n",  sp->value,
+                                    fprintf(fp, "installing %c %08lx %s\n",  syminfo.type, sp->value,
                                         name);
 
                                 sp++;
                                 lm->mod_load_symcnt++;
                         }
-			break;
-
-		case 't':
-		case 'T':
-			if (CRASHDEBUG(2))
-			    fprintf(fp, "%08lx (%c) [%s] %s\n",  
-				(ulong)syminfo.value, 
-				syminfo.type, secname, syminfo.name); 
-
-			syminfo.value += lm->mod_text_start;
-			strcpy(name, syminfo.name);
-			strip_module_symbol_end(name);
-
-			if ((st->flags & INSMOD_BUILTIN) &&
-			    (STREQ(name, "init_module") || 
-			    STREQ(name, "cleanup_module")))
-				break;
-
-                	if (machdep->verify_symbol(name, syminfo.value, 
-			    syminfo.type)) {
-                        	sp->value = syminfo.value;
-				sp->type = syminfo.type;
-                                namespace_ctl(NAMESPACE_INSTALL,
-                                        &lm->mod_load_namespace, sp, name);
-
-                                if (CRASHDEBUG(1))
-                                    fprintf(fp, "%08lx %s\n",  sp->value,
-                                	name);
-
-                        	sp++;
-				lm->mod_load_symcnt++;
-                	} 
-
-			break;
-
-		default:
-			break;
-		}
+                }
 	}
 
 	lm->mod_load_symend = &lm->mod_load_symtable[lm->mod_load_symcnt];
