summaryrefslogtreecommitdiffstats
path: root/sys/kern/link_elf.c
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1998-10-13 09:27:00 +0000
committerpeter <peter@FreeBSD.org>1998-10-13 09:27:00 +0000
commita368279cfc5b5c1e349a7f695b7739469af4164a (patch)
tree3029d6658bf798d714e424c3faa1e6c095f14513 /sys/kern/link_elf.c
parentf2663735958365d7f75ecf218d992509be005b5a (diff)
downloadFreeBSD-src-a368279cfc5b5c1e349a7f695b7739469af4164a.zip
FreeBSD-src-a368279cfc5b5c1e349a7f695b7739469af4164a.tar.gz
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.
Diffstat (limited to 'sys/kern/link_elf.c')
-rw-r--r--sys/kern/link_elf.c88
1 files changed, 78 insertions, 10 deletions
diff --git a/sys/kern/link_elf.c b/sys/kern/link_elf.c
index 1a1266b..578589d 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);
}
}
OpenPOWER on IntegriCloud