From ca65d5c714a12cb5b5e590970e94f5c8ed136dcb Mon Sep 17 00:00:00 2001
From: Peter Wemm <peter@FreeBSD.org>
Date: Tue, 13 Oct 1998 09:27:00 +0000
Subject: [PATCH] Load the full symbol tables if they are present.  This means
 that ddb and tracebacks have access to local symbols.  This is particularly
 important for the Alpha.

---
 sys/kern/link_elf.c     | 88 ++++++++++++++++++++++++++++++++++++-----
 sys/kern/link_elf_obj.c | 88 ++++++++++++++++++++++++++++++++++++-----
 2 files changed, 156 insertions(+), 20 deletions(-)

diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 1a1266b58d1d..578589d3731e 100644
--- a/sys/kern/link_elf.c
+++ b/sys/kern/link_elf.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: link_elf.c,v 1.3 1998/10/09 23:55:31 peter Exp $
+ *	$Id: link_elf.c,v 1.4 1998/10/12 09:13:47 peter Exp $
  */
 
 #include <sys/param.h>
@@ -110,6 +110,8 @@ typedef struct elf_file {
     long		ddbsymcnt;	/* Number of symbols */
     caddr_t		ddbstrtab;	/* String table */
     long		ddbstrcnt;	/* number of bytes in string table */
+    caddr_t		symbase;	/* malloc'ed symbold base */
+    caddr_t		strbase;	/* malloc'ed string base */
 } *elf_file_t;
 
 static int		parse_dynamic(linker_file_t lf);
@@ -196,6 +198,8 @@ parse_module_symbols(linker_file_t lf)
     Elf_Sym*	symtab;
     int		symcnt;
 
+    if (ef->modptr == NULL)
+	return 0;
     pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM);
     if (pointer == NULL)
 	return 0;
@@ -354,6 +358,7 @@ link_elf_load_module(const char *filename, linker_file_t *result)
     ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
     if (ef == NULL)
 	return (ENOMEM);
+    ef->modptr = modptr;
     ef->address = *(caddr_t *)baseptr;
 #ifdef SPARSE_MAPPING
     ef->object = 0;
@@ -425,6 +430,14 @@ link_elf_load_file(const char* filename, linker_file_t* result)
     elf_file_t ef;
     linker_file_t lf;
     char *pathname;
+    Elf_Shdr *shdr;
+    int symtabindex;
+    int symstrindex;
+    int symcnt;
+    int strcnt;
+
+    shdr = NULL;
+    lf = NULL;
 
     pathname = linker_search_path(filename);
     if (pathname == NULL)
@@ -610,24 +623,74 @@ link_elf_load_file(const char* filename, linker_file_t* result)
     lf->size = mapsize;
 
     error = parse_dynamic(lf);
-    if (error) {
-	linker_file_unload(lf);
+    if (error)
 	goto out;
-    }
     error = load_dependancies(lf);
-    if (error) {
-	linker_file_unload(lf);
+    if (error)
 	goto out;
-    }
     error = relocate_file(lf);
-    if (error) {
-	linker_file_unload(lf);
+    if (error)
+	goto out;
+
+    /* Try and load the symbol table if it's present.  (you can strip it!) */
+    nbytes = u.hdr.e_shnum * u.hdr.e_shentsize;
+    if (nbytes == 0 || u.hdr.e_shoff == 0)
+	goto nosyms;
+    shdr = malloc(nbytes, M_LINKER, M_WAITOK);
+    if (shdr == NULL) {
+	error = ENOMEM;
 	goto out;
     }
+    error = vn_rdwr(UIO_READ, nd.ni_vp,
+		    (caddr_t)shdr, nbytes, u.hdr.e_shoff,
+		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+    if (error)
+	goto out;
+    symtabindex = -1;
+    symstrindex = -1;
+    for (i = 0; i < u.hdr.e_shnum; i++) {
+	if (shdr[i].sh_type == SHT_SYMTAB) {
+	    symtabindex = i;
+	    symstrindex = shdr[i].sh_link;
+	}
+    }
+    if (symtabindex < 0 || symstrindex < 0)
+	goto nosyms;
+
+    symcnt = shdr[symtabindex].sh_size;
+    ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK);
+    strcnt = shdr[symstrindex].sh_size;
+    ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK);
+
+    if (ef->symbase == NULL || ef->strbase == NULL) {
+	error = ENOMEM;
+	goto out;
+    }
+    error = vn_rdwr(UIO_READ, nd.ni_vp,
+		    ef->symbase, symcnt, shdr[symtabindex].sh_offset,
+		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+    if (error)
+	goto out;
+    error = vn_rdwr(UIO_READ, nd.ni_vp,
+		    ef->strbase, strcnt, shdr[symstrindex].sh_offset,
+		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+    if (error)
+	goto out;
+
+    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
+    ef->ddbsymtab = (const Elf_Sym *)ef->symbase;
+    ef->ddbstrcnt = strcnt;
+    ef->ddbstrtab = ef->strbase;
+
+nosyms:
 
     *result = lf;
 
 out:
+    if (error && lf)
+	linker_file_unload(lf);
+    if (shdr)
+	free(shdr, M_LINKER);
     VOP_UNLOCK(nd.ni_vp, 0, p);
     vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
 
@@ -648,8 +711,13 @@ link_elf_unload_file(linker_file_t file)
 	    vm_object_deallocate(ef->object);
 	}
 #else
-	free(ef->address, M_LINKER);
+	if (ef->address)
+	    free(ef->address, M_LINKER);
 #endif
+	if (ef->symbase)
+	    free(ef->symbase, M_LINKER);
+	if (ef->strbase)
+	    free(ef->strbase, M_LINKER);
 	free(ef, M_LINKER);
     }
 }
diff --git a/sys/kern/link_elf_obj.c b/sys/kern/link_elf_obj.c
index 1a1266b58d1d..578589d3731e 100644
--- a/sys/kern/link_elf_obj.c
+++ b/sys/kern/link_elf_obj.c
@@ -23,7 +23,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: link_elf.c,v 1.3 1998/10/09 23:55:31 peter Exp $
+ *	$Id: link_elf.c,v 1.4 1998/10/12 09:13:47 peter Exp $
  */
 
 #include <sys/param.h>
@@ -110,6 +110,8 @@ typedef struct elf_file {
     long		ddbsymcnt;	/* Number of symbols */
     caddr_t		ddbstrtab;	/* String table */
     long		ddbstrcnt;	/* number of bytes in string table */
+    caddr_t		symbase;	/* malloc'ed symbold base */
+    caddr_t		strbase;	/* malloc'ed string base */
 } *elf_file_t;
 
 static int		parse_dynamic(linker_file_t lf);
@@ -196,6 +198,8 @@ parse_module_symbols(linker_file_t lf)
     Elf_Sym*	symtab;
     int		symcnt;
 
+    if (ef->modptr == NULL)
+	return 0;
     pointer = preload_search_info(ef->modptr, MODINFO_METADATA|MODINFOMD_SSYM);
     if (pointer == NULL)
 	return 0;
@@ -354,6 +358,7 @@ link_elf_load_module(const char *filename, linker_file_t *result)
     ef = malloc(sizeof(struct elf_file), M_LINKER, M_WAITOK);
     if (ef == NULL)
 	return (ENOMEM);
+    ef->modptr = modptr;
     ef->address = *(caddr_t *)baseptr;
 #ifdef SPARSE_MAPPING
     ef->object = 0;
@@ -425,6 +430,14 @@ link_elf_load_file(const char* filename, linker_file_t* result)
     elf_file_t ef;
     linker_file_t lf;
     char *pathname;
+    Elf_Shdr *shdr;
+    int symtabindex;
+    int symstrindex;
+    int symcnt;
+    int strcnt;
+
+    shdr = NULL;
+    lf = NULL;
 
     pathname = linker_search_path(filename);
     if (pathname == NULL)
@@ -610,24 +623,74 @@ link_elf_load_file(const char* filename, linker_file_t* result)
     lf->size = mapsize;
 
     error = parse_dynamic(lf);
-    if (error) {
-	linker_file_unload(lf);
+    if (error)
 	goto out;
-    }
     error = load_dependancies(lf);
-    if (error) {
-	linker_file_unload(lf);
+    if (error)
 	goto out;
-    }
     error = relocate_file(lf);
-    if (error) {
-	linker_file_unload(lf);
+    if (error)
+	goto out;
+
+    /* Try and load the symbol table if it's present.  (you can strip it!) */
+    nbytes = u.hdr.e_shnum * u.hdr.e_shentsize;
+    if (nbytes == 0 || u.hdr.e_shoff == 0)
+	goto nosyms;
+    shdr = malloc(nbytes, M_LINKER, M_WAITOK);
+    if (shdr == NULL) {
+	error = ENOMEM;
 	goto out;
     }
+    error = vn_rdwr(UIO_READ, nd.ni_vp,
+		    (caddr_t)shdr, nbytes, u.hdr.e_shoff,
+		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+    if (error)
+	goto out;
+    symtabindex = -1;
+    symstrindex = -1;
+    for (i = 0; i < u.hdr.e_shnum; i++) {
+	if (shdr[i].sh_type == SHT_SYMTAB) {
+	    symtabindex = i;
+	    symstrindex = shdr[i].sh_link;
+	}
+    }
+    if (symtabindex < 0 || symstrindex < 0)
+	goto nosyms;
+
+    symcnt = shdr[symtabindex].sh_size;
+    ef->symbase = malloc(symcnt, M_LINKER, M_WAITOK);
+    strcnt = shdr[symstrindex].sh_size;
+    ef->strbase = malloc(strcnt, M_LINKER, M_WAITOK);
+
+    if (ef->symbase == NULL || ef->strbase == NULL) {
+	error = ENOMEM;
+	goto out;
+    }
+    error = vn_rdwr(UIO_READ, nd.ni_vp,
+		    ef->symbase, symcnt, shdr[symtabindex].sh_offset,
+		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+    if (error)
+	goto out;
+    error = vn_rdwr(UIO_READ, nd.ni_vp,
+		    ef->strbase, strcnt, shdr[symstrindex].sh_offset,
+		    UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
+    if (error)
+	goto out;
+
+    ef->ddbsymcnt = symcnt / sizeof(Elf_Sym);
+    ef->ddbsymtab = (const Elf_Sym *)ef->symbase;
+    ef->ddbstrcnt = strcnt;
+    ef->ddbstrtab = ef->strbase;
+
+nosyms:
 
     *result = lf;
 
 out:
+    if (error && lf)
+	linker_file_unload(lf);
+    if (shdr)
+	free(shdr, M_LINKER);
     VOP_UNLOCK(nd.ni_vp, 0, p);
     vn_close(nd.ni_vp, FREAD, p->p_ucred, p);
 
@@ -648,8 +711,13 @@ link_elf_unload_file(linker_file_t file)
 	    vm_object_deallocate(ef->object);
 	}
 #else
-	free(ef->address, M_LINKER);
+	if (ef->address)
+	    free(ef->address, M_LINKER);
 #endif
+	if (ef->symbase)
+	    free(ef->symbase, M_LINKER);
+	if (ef->strbase)
+	    free(ef->strbase, M_LINKER);
 	free(ef, M_LINKER);
     }
 }