summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/gen/Makefile.inc6
-rw-r--r--lib/libc/gen/nlist.c225
2 files changed, 228 insertions, 3 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc
index 11e87c5..840b3a9 100644
--- a/lib/libc/gen/Makefile.inc
+++ b/lib/libc/gen/Makefile.inc
@@ -1,5 +1,5 @@
# @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
-# $Id: Makefile.inc,v 1.36 1997/06/25 08:05:02 msmith Exp $
+# $Id: Makefile.inc,v 1.37 1997/07/12 11:16:17 peter Exp $
# machine-independent gen sources
.PATH: ${.CURDIR}/../libc/${MACHINE}/gen ${.CURDIR}/../libc/gen
@@ -29,6 +29,10 @@ SRCS+= _rand48.c drand48.c erand48.c jrand48.c lcong48.c lrand48.c \
# machine-dependent gen sources
.include "${.CURDIR}/../libc/${MACHINE}/gen/Makefile.inc"
+.if defined(BINFORMAT) && ${BINFORMAT} == elf
+CFLAGS+=-D_NLIST_DO_ELF
+.endif
+
.if (${MACHINE} == "tahoe" || ${MACHINE} == "vax")
errlst.o errlst.po:
${CC} -S ${CFLAGS} ${.IMPSRC}
diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c
index 7415cbe..3100a12 100644
--- a/lib/libc/gen/nlist.c
+++ b/lib/libc/gen/nlist.c
@@ -46,7 +46,15 @@ static char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) 6/4/93";
#include <string.h>
#include <unistd.h>
-int __fdnlist __P(( int, struct nlist * ));
+#define _NLIST_DO_AOUT
+
+#ifdef _NLIST_DO_ELF
+#include <elf.h>
+#endif
+
+int __fdnlist __P((int, struct nlist *));
+int __aout_fdnlist __P((int, struct nlist *));
+int __elf_fdnlist __P((int, struct nlist *));
int
nlist(name, list)
@@ -63,13 +71,40 @@ nlist(name, list)
return (n);
}
-#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
+static struct nlist_handlers {
+ int (*fn) __P((int fd, struct nlist *list));
+} nlist_fn[] = {
+#ifdef _NLIST_DO_AOUT
+ { __aout_fdnlist },
+#endif
+#ifdef _NLIST_DO_ELF
+ { __elf_fdnlist },
+#endif
+};
int
__fdnlist(fd, list)
register int fd;
register struct nlist *list;
{
+ int n = -1, i;
+
+ for (i = 0; i < sizeof(nlist_fn) / sizeof(nlist_fn[0]); i++) {
+ n = (nlist_fn[i].fn)(fd, list);
+ if (n != -1)
+ break;
+ }
+ return (n);
+}
+
+#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
+
+#ifdef _NLIST_DO_AOUT
+int
+__aout_fdnlist(fd, list)
+ register int fd;
+ register struct nlist *list;
+{
register struct nlist *p, *symtab;
register caddr_t strtab, a_out_mmap;
register off_t stroff, symoff;
@@ -158,3 +193,189 @@ __fdnlist(fd, list)
munmap(a_out_mmap, (size_t)st.st_size);
return (nent);
}
+#endif
+
+#ifdef _NLIST_DO_ELF
+/*
+ * __elf_is_okay__ - Determine if ehdr really
+ * is ELF and valid for the target platform.
+ *
+ * WARNING: This is NOT a ELF ABI function and
+ * as such it's use should be restricted.
+ */
+int
+__elf_is_okay__(ehdr)
+ register Elf32_Ehdr *ehdr;
+{
+ register int retval = 0;
+ /*
+ * We need to check magic, class size, endianess,
+ * and version before we look at the rest of the
+ * Elf32_Ehdr structure. These few elements are
+ * represented in a machine independant fashion.
+ */
+ if (IS_ELF(*ehdr) &&
+ ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS &&
+ ehdr->e_ident[EI_DATA] == ELF_TARG_DATA &&
+ ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) {
+
+ /* Now check the machine dependant header */
+ if (ehdr->e_machine == ELF_TARG_MACH &&
+ ehdr->e_version == ELF_TARG_VER)
+ retval = 1;
+ }
+ return retval;
+}
+
+int
+__elf_fdnlist(fd, list)
+ register int fd;
+ register struct nlist *list;
+{
+ register struct nlist *p;
+ register caddr_t strtab;
+ register Elf32_Off symoff = 0, symstroff = 0;
+ register Elf32_Word symsize = 0, symstrsize = 0;
+ register Elf32_Sword nent, cc, i;
+ Elf32_Sym sbuf[1024];
+ Elf32_Sym *s;
+ Elf32_Ehdr ehdr;
+ Elf32_Shdr *shdr = NULL;
+ Elf32_Word shdr_size;
+ struct stat st;
+
+ /* Make sure obj is OK */
+ if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
+ read(fd, &ehdr, sizeof(Elf32_Ehdr)) != sizeof(Elf32_Ehdr) ||
+ !__elf_is_okay__(&ehdr) ||
+ fstat(fd, &st) < 0)
+ return (-1);
+
+ /* calculate section header table size */
+ shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
+
+ /* Make sure it's not too big to mmap */
+ if (shdr_size > SIZE_T_MAX) {
+ errno = EFBIG;
+ return (-1);
+ }
+
+ /* mmap section header table */
+ shdr = (Elf32_Shdr *)mmap(NULL, (size_t)shdr_size,
+ PROT_READ, 0, fd, (off_t) ehdr.e_shoff);
+ if (shdr == (Elf32_Shdr *)-1)
+ return (-1);
+
+ /*
+ * Find the symbol table entry and it's corresponding
+ * string table entry. Version 1.1 of the ABI states
+ * that there is only one symbol table but that this
+ * could change in the future.
+ */
+ for (i = 0; i < ehdr.e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB) {
+ symoff = shdr[i].sh_offset;
+ symsize = shdr[i].sh_size;
+ symstroff = shdr[shdr[i].sh_link].sh_offset;
+ symstrsize = shdr[shdr[i].sh_link].sh_size;
+ break;
+ }
+ }
+
+ /* Flush the section header table */
+ munmap((caddr_t)shdr, shdr_size);
+
+ /* Check for files too large to mmap. */
+ 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,
+ (off_t) 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;
+ }
+
+ /* Don't process any further if object is stripped. */
+ /* ELFism - dunno if stripped by looking at header */
+ if (symoff == 0)
+ goto done;
+
+ if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) {
+ nent = -1;
+ goto done;
+ }
+
+ 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 ((p->n_un.n_name[0] == '_' &&
+ !strcmp(&strtab[soff], p->n_un.n_name+1))
+ || !strcmp(&strtab[soff], 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_OBJECT:
+ p->n_type = N_DATA;
+ break;
+ case STT_FUNC:
+ p->n_type = N_TEXT;
+ break;
+ case STT_FILE:
+ p->n_type = N_FN;
+ 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;
+ }
+ }
+ }
+ }
+ done:
+ munmap(strtab, symstrsize);
+
+ return (nent);
+}
+#endif /* _NLIST_DO_ELF */
OpenPOWER on IntegriCloud