Subject: loadfile/ELF fixes, take 2
To: None <tech-kern@netbsd.org>
From: Ben Harris <bjh21@netbsd.org>
List: tech-kern
Date: 07/30/2001 01:11:06
This is a second attempt at fixing the way that ELF symbol tables are
loaded into the kernel.  You'll notice it's a lot bigger than the last
one.

This patch basically causes both loadfile and DDB to use the sh_link
member of the symbol table's section header to find the string table,
rather than having loadfile load all the STRTABs and having DDB ignore all
the ones not called ".strtab".

Another small change is that loadfile no longer reserves space for string
tables it doesn't load.  There are a few other obvious improvements that
could be made to loadfile, but I'd like to get these ones in first.

This change does introduce a compatibility problem, in that old versions
of DDB won't be able to find the symbol table provided by the new
loadfile, since it won't provide all the necessary information.  New
versions of DDB should work with old loadfiles (and hence anything which
emulates the old loadfile).

I've tested this on arm26, and made sure it actually works this time.

Any comments?

Index: lib/libsa/loadfile.c
===================================================================
RCS file: /cvsroot/syssrc/sys/lib/libsa/loadfile.c,v
retrieving revision 1.13
diff -u -u -r1.13 loadfile.c
--- lib/libsa/loadfile.c	2001/07/19 18:55:38	1.13
+++ lib/libsa/loadfile.c	2001/07/29 23:51:07
@@ -274,10 +274,9 @@
 {
 	Elf_Shdr *shp;
 	Elf_Off off;
-	int i;
+	int i, j;
 	size_t sz;
 	int first;
-	int havesyms;
 	paddr_t minp = ~0, maxp = 0, pos = 0;
 	paddr_t offset = marks[MARK_START], shpp, elfp = NULL;

@@ -372,20 +371,24 @@
 		maxp += roundup(sz, sizeof(long));

 		/*
-		 * Now load the symbol sections themselves.  Make sure the
-		 * sections are aligned. Don't bother with string tables if
-		 * there are no symbol sections.
+		 * Now load the symbol sections themselves.  Make sure
+		 * the sections are aligned. Don't bother with any
+		 * string table that isn't referenced by a symbol
+		 * table.
 		 */
 		off = roundup((sizeof(Elf_Ehdr) + sz), sizeof(long));

-		for (havesyms = i = 0; i < elf->e_shnum; i++)
-			if (shp[i].sh_type == SHT_SYMTAB)
-				havesyms = 1;
-
 		for (first = 1, i = 0; i < elf->e_shnum; i++) {
-			if (shp[i].sh_type == SHT_SYMTAB ||
-			    shp[i].sh_type == SHT_STRTAB) {
-				if (havesyms && (flags & LOAD_SYM)) {
+			switch (shp[i].sh_type) {
+			case SHT_STRTAB:
+				for (j = 0; j < elf->e_shnum; j++)
+					if (shp[j].sh_type == SHT_SYMTAB &&
+					    shp[j].sh_link == i)
+						goto havesym;
+				break;
+			havesym:
+			case SHT_SYMTAB:
+				if (flags & LOAD_SYM) {
 					PROGRESS(("%s%ld", first ? " [" : "+",
 					    (u_long)shp[i].sh_size));
 					if (lseek(fd, shp[i].sh_offset,
@@ -412,7 +415,7 @@
 			BCOPY(shp, shpp, sz);
 			FREE(shp, sz);

-			if (havesyms && first == 0)
+			if (first == 0)
 				PROGRESS(("]"));
 		}
 	}
Index: ddb/db_elf.c
===================================================================
RCS file: /cvsroot/syssrc/sys/ddb/db_elf.c,v
retrieving revision 1.14
diff -u -u -r1.14 db_elf.c
--- ddb/db_elf.c	2001/01/17 19:50:03	1.14
+++ ddb/db_elf.c	2001/07/29 23:51:07
@@ -104,8 +104,8 @@
 	Elf_Ehdr *elf;
 	Elf_Shdr *shp;
 	Elf_Sym *symp, *symtab_start, *symtab_end;
-	char *shstrtab, *strtab_start, *strtab_end;
-	int i;
+	char *strtab_start, *strtab_end;
+	int i, j;

 	if (ALIGNED_POINTER(symtab, long) == 0) {
 		printf("[ %s symbol table has bad start address %p ]\n",
@@ -147,24 +147,24 @@
 	}

 	/*
-	 * Find the section header string table (.shstrtab), and look up
-	 * the symbol table (.symtab) and string table (.strtab) via their
-	 * names in shstrtab, rather than by table type.
-	 * This works in the presence of multiple string tables, such as
-	 * stabs data found when booting netbsd.gdb.
+	 * Find the first (and, we hope, only) SHT_SYMTAB section in
+	 * the file, and the SHT_STRTAB section that goes with it.
 	 */
 	shp = (Elf_Shdr *)((char *)symtab + elf->e_shoff);
-	shstrtab = (char*)symtab + shp[elf->e_shstrndx].sh_offset;
 	for (i = 0; i < elf->e_shnum; i++) {
-		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0) {
-			strtab_start = (char *)symtab + shp[i].sh_offset;
-			strtab_end = (char *)symtab + shp[i].sh_offset +
-			    shp[i].sh_size;
-		} else if (strcmp(".symtab", shstrtab+shp[i].sh_name) == 0) {
+		if (shp[i].sh_type == SHT_SYMTAB) {
+			/* Got the symbol table. */
 			symtab_start = (Elf_Sym *)((char *)symtab +
 			    shp[i].sh_offset);
 			symtab_end = (Elf_Sym *)((char *)symtab +
 			    shp[i].sh_offset + shp[i].sh_size);
+			/* Find the string table to go with it. */
+			j = shp[i].sh_link;
+			strtab_start = (char *)symtab + shp[j].sh_offset;
+			strtab_end = (char *)symtab + shp[j].sh_offset +
+			    shp[j].sh_size;
+			/* There should only be one symbol table. */
+			break;
 		}
 	}

@@ -207,13 +207,11 @@
 {
 	Elf_Ehdr *elf = STAB_TO_EHDR(stab);
 	Elf_Shdr *shp = STAB_TO_SHDR(stab, elf);
-	char *shstrtab;
 	int i;

-	shstrtab = (char*)elf + shp[elf->e_shstrndx].sh_offset;
 	for (i = 0; i < elf->e_shnum; i++) {
-		if (strcmp(".strtab", shstrtab+shp[i].sh_name) == 0)
-			return ((char*)elf + shp[i].sh_offset);
+		if (shp[i].sh_type == SHT_SYMTAB)
+			return ((char*)elf + shp[shp[i].sh_link].sh_offset);
 	}

 	return (NULL);

-- 
Ben Harris                                                   <bjh21@netbsd.org>
Portmaster, NetBSD/arm26               <URL:http://www.netbsd.org/Ports/arm26/>