summaryrefslogtreecommitdiffstats
path: root/sys/boot/common
diff options
context:
space:
mode:
authorpeter <peter@FreeBSD.org>1998-10-02 08:04:56 +0000
committerpeter <peter@FreeBSD.org>1998-10-02 08:04:56 +0000
commita79bd7a6936b3a8aaf3380ee46f024d3a28c85ac (patch)
treec9caacf819531efd502706e53b9eb3ec3e7e1e4c /sys/boot/common
parent5a6b93580f29cf14bf248c85ae0743ae6a85f7a0 (diff)
downloadFreeBSD-src-a79bd7a6936b3a8aaf3380ee46f024d3a28c85ac.zip
FreeBSD-src-a79bd7a6936b3a8aaf3380ee46f024d3a28c85ac.tar.gz
First shot at loading elf symbols. Things are a bit strange because
of the ..umm.. "wierd" way binutils lays out the file. The section headers are nearly at the end of the file and this is a problem when loading from a .gz file which can't seek backwards (or has a limited reverse seek, ~2K from memory). This is intended to be compatable with the ddb/db_elf.c code and the alpha/libalpha/elf_freebsd.c layout. I've studied these (which are NetBSD derived) but did it a bit differently. Naturally the process is similar since it's supposed to end up with the same result.
Diffstat (limited to 'sys/boot/common')
-rw-r--r--sys/boot/common/bootstrap.h4
-rw-r--r--sys/boot/common/load_elf.c139
2 files changed, 129 insertions, 14 deletions
diff --git a/sys/boot/common/bootstrap.h b/sys/boot/common/bootstrap.h
index 2fadee0..1c4d00f 100644
--- a/sys/boot/common/bootstrap.h
+++ b/sys/boot/common/bootstrap.h
@@ -23,7 +23,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: bootstrap.h,v 1.8 1998/09/26 10:51:37 dfr Exp $
+ * $Id: bootstrap.h,v 1.9 1998/09/30 19:25:26 peter Exp $
*/
#include <sys/types.h>
@@ -193,6 +193,8 @@ extern int elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module
#define MODINFOMD_AOUTEXEC 0x0001 /* a.out exec header */
#define MODINFOMD_ELFHDR 0x0002 /* ELF header */
+#define MODINFOMD_ELFSSYM 0x0003 /* ELF start of symbols */
+#define MODINFOMD_ELFESYM 0x0004 /* ELF end of symbols */
#define MODINFOMD_NOCOPY 0x8000 /* don't copy this metadata to the kernel */
#define KLD_IDENT_SYMNAME "kld_identifier_"
diff --git a/sys/boot/common/load_elf.c b/sys/boot/common/load_elf.c
index efef519..42a1573 100644
--- a/sys/boot/common/load_elf.c
+++ b/sys/boot/common/load_elf.c
@@ -24,7 +24,7 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
- * $Id: load_aout.c,v 1.6 1998/09/26 10:51:38 dfr Exp $
+ * $Id: load_elf.c,v 1.1 1998/09/30 19:38:26 peter Exp $
*/
#include <sys/param.h>
@@ -39,7 +39,7 @@
#include "bootstrap.h"
-static int elf_loadimage(int fd, vm_offset_t *loadaddr, Elf_Ehdr *ehdr, int kernel);
+static int elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *loadaddr, Elf_Ehdr *ehdr, int kernel);
#if 0
static vm_offset_t elf_findkldident(struct loaded_module *mp, Elf_Ehdr *ehdr);
static int elf_fixupkldmod(struct loaded_module *mp, Elf_Ehdr *ehdr);
@@ -152,7 +152,7 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
printf("%s at %p\n", filename, (void *) addr);
- mp->m_size = elf_loadimage(fd, &addr, &ehdr, kernel);
+ mp->m_size = elf_loadimage(mp, fd, &addr, &ehdr, kernel);
if (mp->m_size == 0)
goto ioerr;
mp->m_addr = addr; /* save the aligned load address */
@@ -185,15 +185,23 @@ elf_loadmodule(char *filename, vm_offset_t dest, struct loaded_module **result)
* the Elf header, load the image at (addr)
*/
static int
-elf_loadimage(int fd, vm_offset_t *addr, Elf_Ehdr *ehdr, int kernel)
+elf_loadimage(struct loaded_module *mp, int fd, vm_offset_t *addr,
+ Elf_Ehdr *ehdr, int kernel)
{
- int i;
+ int i, j;
Elf_Phdr *phdr;
+ Elf_Shdr *shdr;
+ Elf_Ehdr local_ehdr;
int ret;
vm_offset_t firstaddr;
vm_offset_t lastaddr;
vm_offset_t off;
void *buf;
+ size_t resid, chunk;
+ vm_offset_t dest;
+ char *secname;
+ vm_offset_t shdrpos;
+ vm_offset_t ssym, esym;
ret = 0;
firstaddr = lastaddr = 0;
@@ -225,29 +233,27 @@ elf_loadimage(int fd, vm_offset_t *addr, Elf_Ehdr *ehdr, int kernel)
if (phdr[i].p_type != PT_LOAD)
continue;
- printf("segment %d: 0x%lx@0x%lx -> 0x%lx-0x%lx\n", i,
+ printf("Segment: 0x%lx@0x%lx -> 0x%lx-0x%lx",
(long)phdr[i].p_filesz, (long)phdr[i].p_offset,
(long)(phdr[i].p_vaddr + off),
- (long)(phdr[i].p_vaddr + off + phdr[i].p_filesz - 1));
+ (long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
if (lseek(fd, phdr[i].p_offset, SEEK_SET) == -1) {
- printf("elf_loadexec: cannot seek\n");
+ printf("\nelf_loadexec: cannot seek\n");
goto out;
}
if (archsw.arch_readin(fd, phdr[i].p_vaddr + off, phdr[i].p_filesz) !=
phdr[i].p_filesz) {
- printf("elf_loadexec: archsw.readin failed\n");
+ printf("\nelf_loadexec: archsw.readin failed\n");
goto out;
}
/* clear space from oversized segments; eg: bss */
if (phdr[i].p_filesz < phdr[i].p_memsz) {
- size_t resid, chunk;
- vm_offset_t dest;
-
- printf(".. extended: clearing 0x%lx-0x%lx\n",
+ printf(" (bss: 0x%lx-0x%lx)",
(long)(phdr[i].p_vaddr + off + phdr[i].p_filesz),
(long)(phdr[i].p_vaddr + off + phdr[i].p_memsz - 1));
+ /* no archsw.arch_bzero */
buf = malloc(PAGE_SIZE);
bzero(buf, PAGE_SIZE);
resid = phdr[i].p_memsz - phdr[i].p_filesz;
@@ -260,6 +266,7 @@ elf_loadimage(int fd, vm_offset_t *addr, Elf_Ehdr *ehdr, int kernel)
}
free(buf);
}
+ printf("\n");
if (firstaddr < (phdr[i].p_vaddr + off))
firstaddr = phdr[i].p_vaddr + off;
@@ -267,6 +274,112 @@ elf_loadimage(int fd, vm_offset_t *addr, Elf_Ehdr *ehdr, int kernel)
lastaddr = phdr[i].p_vaddr + off + phdr[i].p_memsz;
}
+ /*
+ * Now grab the symbol tables. This isn't easy if we're reading a
+ * .gz file. I think the rule is going to have to be that you must
+ * strip a file to remove symbols before gzipping it so that we do not
+ * try to lseek() on it. The layout is a bit wierd, but it's what
+ * the NetBSD-derived ddb/db_elf.c wants.
+ */
+ lastaddr = roundup(lastaddr, sizeof(long));
+ chunk = ehdr->e_shnum * ehdr->e_shentsize;
+ shdr = malloc(chunk);
+ if (shdr == NULL)
+ goto nosyms;
+ ssym = lastaddr;
+ printf("Symbols: ELF Ehdr @ 0x%x; ", lastaddr);
+ lastaddr += sizeof(*ehdr);
+ lastaddr = roundup(lastaddr, sizeof(long));
+ /* Copy out executable header modified for base offsets */
+ local_ehdr = *ehdr;
+ local_ehdr.e_phoff = 0;
+ local_ehdr.e_phentsize = 0;
+ local_ehdr.e_phnum = 0;
+ local_ehdr.e_shoff = lastaddr - ssym;
+ archsw.arch_copyin(&local_ehdr, ssym, sizeof(*ehdr));
+ if (lseek(fd, ehdr->e_shoff, SEEK_SET) == -1) {
+ printf("elf_loadimage: cannot lseek() to section headers\n");
+ lastaddr = ssym; /* wind back */
+ ssym = 0;
+ goto nosyms;
+ }
+ if (read(fd, shdr, chunk) != chunk) {
+ printf("elf_loadimage: read section headers failed\n");
+ lastaddr = ssym; /* wind back */
+ ssym = 0;
+ goto nosyms;
+ }
+ shdrpos = lastaddr;
+ printf("Section table: 0x%x@0x%x\n", chunk, shdrpos);
+ lastaddr += chunk;
+ lastaddr = roundup(lastaddr, sizeof(long));
+ for (i = 0; i < ehdr->e_shnum; i++) {
+ switch(shdr[i].sh_type) {
+ /*
+ * These are the symbol tables. Their names are relative to
+ * an arbitary string table.
+ */
+ case SHT_SYMTAB: /* Symbol table */
+ secname = "symtab";
+ break;
+ case SHT_DYNSYM: /* Dynamic linking symbol table */
+ secname = "dynsym";
+ break;
+ /*
+ * And here are the string tables. These can be referred to from
+ * a number of sources, including the dynsym, the section table
+ * names itself, etc.
+ */
+ case SHT_STRTAB: /* String table */
+ secname = "strtab";
+ break;
+ default: /* Skip it */
+ continue;
+ }
+ for (j = 0; j < ehdr->e_phnum; j++) {
+ if (phdr[j].p_type != PT_LOAD)
+ continue;
+ if (shdr[i].sh_offset >= phdr[j].p_offset &&
+ (shdr[i].sh_offset + shdr[i].sh_size <=
+ phdr[j].p_offset + phdr[j].p_filesz)) {
+ shdr[i].sh_offset = 0;
+ shdr[i].sh_size = 0;
+ break;
+ }
+ }
+ if (shdr[i].sh_offset == 0 || shdr[i].sh_size == 0)
+ continue; /* alread loaded in a PT_LOAD above */
+
+ printf("%s: 0x%x@0x%x -> 0x%x-0x%x\n", secname,
+ shdr[i].sh_size, shdr[i].sh_offset,
+ lastaddr, lastaddr + shdr[i].sh_size);
+
+ if (lseek(fd, shdr[i].sh_offset, SEEK_SET) == -1) {
+ printf("\nelf_loadimage: could not seek for symbols - skipped!\n");
+ shdr[i].sh_offset = 0;
+ shdr[i].sh_size = 0;
+ continue;
+ }
+ if (archsw.arch_readin(fd, lastaddr, shdr[i].sh_size) !=
+ shdr[i].sh_size) {
+ printf("\nelf_loadimage: could not read symbols - skipped!\n");
+ shdr[i].sh_offset = 0;
+ shdr[i].sh_size = 0;
+ continue;
+ }
+ /* Reset offsets relative to ssym */
+ shdr[i].sh_offset = lastaddr - ssym;
+ lastaddr += shdr[i].sh_size;
+ lastaddr = roundup(lastaddr, sizeof(long));
+ }
+ archsw.arch_copyin(shdr, lastaddr, sizeof(*ehdr));
+ esym = lastaddr;
+
+ mod_addmetadata(mp, MODINFOMD_ELFSSYM, sizeof(ssym), &ssym);
+ mod_addmetadata(mp, MODINFOMD_ELFESYM, sizeof(esym), &esym);
+
+nosyms:
+
ret = lastaddr - firstaddr;
*addr = firstaddr;
out:
OpenPOWER on IntegriCloud