summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpefo <pefo@openbsd.org>1996-05-17 20:03:59 +0000
committerpefo <pefo@openbsd.org>1996-05-17 20:03:59 +0000
commitbc468043d60e65443b0ac7595fecb27147b09f40 (patch)
tree16f8e5c531bd8293ebd0d41a7f29701985843e7d
parentfrom Hiroyuki Ito: (diff)
downloadwireguard-openbsd-bc468043d60e65443b0ac7595fecb27147b09f40.tar.xz
wireguard-openbsd-bc468043d60e65443b0ac7595fecb27147b09f40.zip
Addition of elf support.
-rw-r--r--lib/libc/gen/nlist.c127
-rw-r--r--usr.sbin/kvm_mkdb/nlist.c215
2 files changed, 335 insertions, 7 deletions
diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c
index e3b31868865..5e8ff2f8c1d 100644
--- a/lib/libc/gen/nlist.c
+++ b/lib/libc/gen/nlist.c
@@ -58,7 +58,7 @@ static char rcsid[] = "$NetBSD: nlist.c,v 1.6 1995/09/29 04:19:59 cgd Exp $";
#include <sys/exec_ecoff.h>
#endif
#ifdef DO_ELF
-#include <sys/exec_elf.h>
+#include <elf_abi.h>
#endif
#include <stdio.h>
#include <string.h>
@@ -262,7 +262,130 @@ __elf_fdnlist(fd, list)
register int fd;
register struct nlist *list;
{
- return (-1);
+ register struct nlist *p;
+ register caddr_t strtab;
+ register off_t symstroff, symoff;
+ register u_long symsize;
+ register int nent, cc, i;
+ Elf32_Sym sbuf[1024];
+ Elf32_Sym *s;
+ size_t symstrsize;
+ char *shstr;
+ Elf32_Ehdr eh;
+ Elf32_Shdr *sh = NULL;
+ struct stat st;
+
+ if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
+ read(fd, &eh, sizeof(eh)) != sizeof(eh) ||
+ !IS_ELF(eh) ||
+ fstat(fd, &st) < 0)
+ return (-1);
+
+ sh = (Elf32_Shdr *)malloc(sizeof(Elf32_Shdr) * eh.e_shnum);
+
+ if (lseek (fd, eh.e_shoff, SEEK_SET) < 0)
+ return(-1);
+
+ if (read(fd, sh, sizeof(Elf32_Shdr) * eh.e_shnum) <
+ sizeof(Elf32_Shdr) * eh.e_shnum)
+ return (-1);
+
+ shstr = (char *)malloc(sh[eh.e_shstrndx].sh_size);
+ if (lseek (fd, sh[eh.e_shstrndx].sh_offset, SEEK_SET) < 0)
+ return(-1);
+ if (read(fd, shstr, sh[eh.e_shstrndx].sh_size) <
+ sh[eh.e_shstrndx].sh_size)
+ return(-1);
+
+ for (i = 0; i < eh.e_shnum; i++) {
+ if (strcmp (shstr + sh[i].sh_name, ".strtab") == 0) {
+ symstroff = sh[i].sh_offset;
+ symstrsize = sh[i].sh_size;
+ }
+ else if (strcmp (shstr + sh[i].sh_name, ".symtab") == 0) {
+ symoff = sh[i].sh_offset;
+ symsize = sh[i].sh_size;
+ }
+ }
+
+ /* Check for files too large to mmap. */
+ /* XXX is this really possible? */
+ if (symstrsize > SIZE_T_MAX) {
+ errno = EFBIG;
+ return (-1);
+ }
+ /*
+ * Map string table into our address space. This gives us
+ * an easy way to randomly access all the strings, without
+ * making the memory allocation permanent as with malloc/free
+ * (i.e., munmap will return it to the system).
+ */
+ strtab = mmap(NULL, (size_t)symstrsize, PROT_READ, 0, fd, symstroff);
+ if (strtab == (char *)-1)
+ return (-1);
+ /*
+ * clean out any left-over information for all valid entries.
+ * Type and value defined to be 0 if not found; historical
+ * versions cleared other and desc as well. Also figure out
+ * the largest string length so don't read any more of the
+ * string table than we have to.
+ *
+ * XXX clearing anything other than n_type and n_value violates
+ * the semantics given in the man page.
+ */
+ nent = 0;
+ for (p = list; !ISLAST(p); ++p) {
+ p->n_type = 0;
+ p->n_other = 0;
+ p->n_desc = 0;
+ p->n_value = 0;
+ ++nent;
+ }
+ if (lseek(fd, symoff, SEEK_SET) == -1)
+ return (-1);
+
+ while (symsize > 0) {
+ cc = MIN(symsize, sizeof(sbuf));
+ if (read(fd, sbuf, cc) != cc)
+ break;
+ symsize -= cc;
+ for (s = sbuf; cc > 0; ++s, cc -= sizeof(*s)) {
+ register int soff = s->st_name;
+
+ if (soff == 0)
+ continue;
+ for (p = list; !ISLAST(p); p++) {
+ if (!strcmp(&strtab[soff],
+ eh.e_machine == EM_MIPS ?
+ p->n_un.n_name+1 :
+ p->n_un.n_name)) {
+ p->n_value = s->st_value;
+
+ /*XXX type conversion is pretty rude... */
+ switch(ELF32_ST_TYPE(s->st_info)) {
+ case STT_NOTYPE:
+ p->n_type = N_UNDF;
+ break;
+ case STT_FUNC:
+ p->n_type = N_TEXT;
+ break;
+ case STT_OBJECT:
+ p->n_type = N_DATA;
+ break;
+ }
+ if(ELF32_ST_BIND(s->st_info) == STB_LOCAL)
+ p->n_type = N_EXT;
+ p->n_desc = 0;
+ p->n_other = 0;
+ if (--nent <= 0)
+ break;
+ }
+ }
+ }
+ }
+ munmap(strtab, symstrsize);
+
+ return (nent);
}
#endif /* DO_ELF */
diff --git a/usr.sbin/kvm_mkdb/nlist.c b/usr.sbin/kvm_mkdb/nlist.c
index a6738940fae..d506638aca3 100644
--- a/usr.sbin/kvm_mkdb/nlist.c
+++ b/usr.sbin/kvm_mkdb/nlist.c
@@ -33,9 +33,12 @@
#ifndef lint
/*static char sccsid[] = "from: @(#)nlist.c 8.1 (Berkeley) 6/6/93";*/
-static char *rcsid = "$Id: nlist.c,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $";
+static char *rcsid = "$Id: nlist.c,v 1.2 1996/05/17 20:04:55 pefo Exp $";
#endif /* not lint */
+#define DO_AOUT /* always do a.out */
+#define DO_ELF /* and elf too */
+
#include <sys/param.h>
#include <a.out.h>
@@ -52,6 +55,14 @@ static char *rcsid = "$Id: nlist.c,v 1.1.1.1 1995/10/18 08:47:39 deraadt Exp $";
#include "extern.h"
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+#ifdef DO_ELF
+#include <elf_abi.h>
+#endif
+
typedef struct nlist NLIST;
#define _strx n_un.n_strx
#define _name n_un.n_name
@@ -62,8 +73,10 @@ static void badread __P((int, char *));
static char *kfile;
-void
-create_knlist(name, db)
+#if defined(DO_AOUT)
+
+int
+__aout_knlist(name, db)
char *name;
DB *db;
{
@@ -82,11 +95,12 @@ create_knlist(name, db)
/* Read in exec structure. */
nr = read(fd, &ebuf, sizeof(struct exec));
if (nr != sizeof(struct exec))
- badfmt("no exec header");
+ return(-1);
/* Check magic number and symbol count. */
if (N_BADMAG(ebuf))
- badfmt("bad magic number");
+ return(-1);
+
if (!ebuf.a_syms)
badfmt("stripped");
@@ -174,8 +188,174 @@ create_knlist(name, db)
}
}
(void)fclose(fp);
+ return(0);
}
+#endif
+
+#ifdef DO_ELF
+int
+__elf_knlist(name, db)
+ char *name;
+ DB *db;
+{
+ register struct nlist *p;
+ register caddr_t strtab;
+ register off_t symstroff, symoff;
+ register u_long symsize;
+ register u_long kernvma, kernoffs;
+ register int cc, i;
+ Elf32_Sym sbuf;
+ Elf32_Sym *s;
+ size_t symstrsize;
+ char *shstr, buf[1024];
+ Elf32_Ehdr eh;
+ Elf32_Shdr *sh = NULL;
+ struct stat st;
+ DBT data, key;
+ NLIST nbuf;
+ FILE *fp;
+
+ kfile = name;
+ if ((fp = fopen(name, "r")) < 0)
+ err(1, "%s", name);
+
+ if (fseek(fp, (off_t)0, SEEK_SET) == -1 ||
+ fread(&eh, sizeof(eh), 1, fp) != 1 ||
+ !IS_ELF(eh))
+ return(-1);
+
+ sh = (Elf32_Shdr *)malloc(sizeof(Elf32_Shdr) * eh.e_shnum);
+
+ if (fseek (fp, eh.e_shoff, SEEK_SET) < 0)
+ badfmt("no exec header");
+
+ if (fread(sh, sizeof(Elf32_Shdr) * eh.e_shnum, 1, fp) != 1)
+ badfmt("no exec header");
+
+ shstr = (char *)malloc(sh[eh.e_shstrndx].sh_size);
+ if (fseek (fp, sh[eh.e_shstrndx].sh_offset, SEEK_SET) < 0)
+ badfmt("corrupt file");
+ if (fread(shstr, sh[eh.e_shstrndx].sh_size, 1, fp) != 1)
+ badfmt("corrupt file");
+
+ for (i = 0; i < eh.e_shnum; i++) {
+ if (strcmp (shstr + sh[i].sh_name, ".strtab") == 0) {
+ symstroff = sh[i].sh_offset;
+ symstrsize = sh[i].sh_size;
+ }
+ else if (strcmp (shstr + sh[i].sh_name, ".symtab") == 0) {
+ symoff = sh[i].sh_offset;
+ symsize = sh[i].sh_size;
+ }
+ else if (strcmp (shstr + sh[i].sh_name, ".text") == 0) {
+ kernvma = sh[i].sh_addr;
+ kernoffs = sh[i].sh_offset;
+ }
+ }
+
+
+ /* Check for files too large to mmap. */
+ /* XXX is this really possible? */
+ if (symstrsize > SIZE_T_MAX) {
+ badfmt("corrupt file");
+ }
+ /*
+ * Map string table into our address space. This gives us
+ * an easy way to randomly access all the strings, without
+ * making the memory allocation permanent as with malloc/free
+ * (i.e., munmap will return it to the system).
+ */
+ strtab = mmap(NULL, (size_t)symstrsize, PROT_READ, 0, fileno(fp), symstroff);
+ if (strtab == (char *)-1)
+ badfmt("corrupt file");
+
+ if (fseek(fp, symoff, SEEK_SET) == -1)
+ badfmt("corrupt file");
+
+ data.data = (u_char *)&nbuf;
+ data.size = sizeof(NLIST);
+
+ /* Read each symbol and enter it into the database. */
+ while (symsize > 0) {
+ symsize -= sizeof(Elf32_Sym);
+ if (fread((char *)&sbuf, sizeof(sbuf), 1, fp) != 1) {
+ if (feof(fp))
+ badfmt("corrupted symbol table");
+ err(1, "%s", name);
+ }
+ if (!sbuf.st_name)
+ continue;
+
+ nbuf.n_value = sbuf.st_value;
+
+ /*XXX type conversion is pretty rude... */
+ switch(ELF32_ST_TYPE(sbuf.st_info)) {
+ case STT_NOTYPE:
+ nbuf.n_type = N_UNDF;
+ break;
+ case STT_FUNC:
+ nbuf.n_type = N_TEXT;
+ break;
+ case STT_OBJECT:
+ nbuf.n_type = N_DATA;
+ break;
+ }
+ if(ELF32_ST_BIND(sbuf.st_info) == STB_LOCAL)
+ nbuf.n_type = N_EXT;
+
+ if(eh.e_machine == EM_MIPS) {
+ *buf = '_';
+ strcpy(buf+1,strtab + sbuf.st_name);
+ key.data = (u_char *)buf;
+ }
+ else {
+ key.data = (u_char *)(strtab + sbuf.st_name);
+ }
+ key.size = strlen((char *)key.data);
+ if (db->put(db, &key, &data, 0))
+ err(1, "record enter");
+
+ if (strcmp((char *)key.data, VRS_SYM) == 0) {
+ long cur_off, voff;
+ /*
+ * Calculate offset to the version string in the
+ * file. kernvma is where the kernel is really
+ * loaded; kernoffs is where in the file it starts.
+ */
+ voff = nbuf.n_value - kernvma + kernoffs;
+ cur_off = ftell(fp);
+ if (fseek(fp, voff, SEEK_SET) == -1)
+ badfmt("corrupted string table");
+
+ /*
+ * Read version string up to, and including newline.
+ * This code assumes that a newline terminates the
+ * version line.
+ */
+ if (fgets(buf, sizeof(buf), fp) == NULL)
+ badfmt("corrupted string table");
+
+ key.data = (u_char *)VRS_KEY;
+ key.size = sizeof(VRS_KEY) - 1;
+ data.data = (u_char *)buf;
+ data.size = strlen(buf);
+ if (db->put(db, &key, &data, 0))
+ err(1, "record enter");
+
+ /* Restore to original values. */
+ data.data = (u_char *)&nbuf;
+ data.size = sizeof(NLIST);
+ if (fseek(fp, cur_off, SEEK_SET) == -1)
+ badfmt("corrupted string table");
+ }
+ }
+ munmap(strtab, symstrsize);
+ (void)fclose(fp);
+ return(0);
+}
+#endif /* DO_ELF */
+
static void
badread(nr, p)
int nr;
@@ -185,3 +365,28 @@ badread(nr, p)
err(1, "%s", kfile);
badfmt(p);
}
+
+static struct knlist_handlers {
+ int (*fn) __P((char *name, DB *db));
+} nlist_fn[] = {
+#ifdef DO_AOUT
+ { __aout_knlist },
+#endif
+#ifdef DO_ELF
+ { __elf_knlist },
+#endif
+};
+
+void
+create_knlist(name, db)
+ char *name;
+ DB *db;
+{
+ int n, i;
+
+ for (i = 0; i < sizeof(nlist_fn)/sizeof(nlist_fn[0]); i++) {
+ n = (nlist_fn[i].fn)(name, db);
+ if (n != -1)
+ break;
+ }
+}