]> git.ipfire.org Git - thirdparty/libbsd.git/commitdiff
Add nlist function
authorGuillem Jover <guillem@hadrons.org>
Wed, 20 May 2009 02:11:57 +0000 (04:11 +0200)
committerGuillem Jover <guillem@hadrons.org>
Wed, 20 May 2009 02:14:19 +0000 (04:14 +0200)
Makefile
Versions
include/nlist.h [new file with mode: 0644]
man/nlist.3 [new file with mode: 0644]
src/local-elf.h [new file with mode: 0644]
src/nlist.c [new file with mode: 0644]

index 393a05036da00d70840efbe654bfdba2a4ec2c0d..11564e23826c82a6407a584c00cf382f8b11d7bf 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -33,6 +33,7 @@ LIB_SRCS := \
        strmode.c \
        strlcat.c strlcpy.c \
        fmtcheck.c \
+       nlist.c \
        progname.c \
        vis.c unvis.c
 LIB_SRCS := $(patsubst %,src/%,$(LIB_SRCS))
index 21123b62b8d4ccf8279bc5c3dd9cb7db8937eb13..76d81631bdbb2f288c722a17280557aa9d0192c4 100644 (file)
--- a/Versions
+++ b/Versions
@@ -37,5 +37,8 @@ LIBBSD_0.0 {
 
 LIBBSD_0.1 {
     strmode;
+
+    __fdnlist; /* Private symbol, but libkvm uses it. */
+    nlist;
 } LIBBSD_0.0;
 
diff --git a/include/nlist.h b/include/nlist.h
new file mode 100644 (file)
index 0000000..95af7d8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2009 Guillem Jover
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSD_NLIST_H
+#define LIBBSD_NLIST_H
+
+#include <sys/cdefs.h>
+#include <sys/a.out.h>
+
+__BEGIN_DECLS
+extern int nlist(const char *filename, struct nlist *list);
+__END_DECLS
+
+#endif
+
diff --git a/man/nlist.3 b/man/nlist.3
new file mode 100644 (file)
index 0000000..6a9b367
--- /dev/null
@@ -0,0 +1,77 @@
+.\" Copyright (c) 1980, 1991, 1993
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\"    may be used to endorse or promote products derived from this software
+.\"    without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\"     @(#)nlist.3    8.3 (Berkeley) 4/19/94
+.\" $FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/nlist.3,v 1.7 2001/10/01 16:08:51 ru Exp $
+.\"
+.Dd April 19, 1994
+.Dt NLIST 3
+.Os
+.Sh NAME
+.Nm nlist
+.Nd retrieve symbol table name list from an executable file
+.Sh LIBRARY
+.Lb libc
+.Sh SYNOPSIS
+.In nlist.h
+.Ft int
+.Fn nlist "const char *filename" "struct nlist *nl"
+.Sh DESCRIPTION
+The
+.Fn nlist
+function
+retrieves name list entries from the symbol table of an
+executable file (see
+.Xr a.out 5 ) .
+The argument
+.Fa \&nl
+is set to reference the
+beginning of the list.
+The list is preened of binary and invalid data;
+if an entry in the
+name list is valid, the
+.Fa n_type
+and
+.Fa n_value
+for the entry are copied into the list
+referenced by
+.Fa \&nl .
+No other data is copied.
+The last entry in the list is always
+.Dv NULL .
+.Sh RETURN VALUES
+The number of invalid entries is returned if successful; otherwise,
+if the file
+.Fa filename
+does not exist or is not executable, the returned value is \-1.
+.Sh SEE ALSO
+.Xr a.out 5
+.Sh HISTORY
+A
+.Fn nlist
+function appeared in
+.At v6 .
diff --git a/src/local-elf.h b/src/local-elf.h
new file mode 100644 (file)
index 0000000..1ac0fc8
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2009 Guillem Jover
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
+ * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBBSD_LOCAL_ELF_H
+#define LIBBSD_LOCAL_ELF_H
+
+#include <elf.h>
+
+#define IS_ELF(ehdr) \
+       ((ehdr).e_ident[EI_MAG0] == ELFMAG0 && \
+        (ehdr).e_ident[EI_MAG1] == ELFMAG1 && \
+        (ehdr).e_ident[EI_MAG2] == ELFMAG2 && \
+        (ehdr).e_ident[EI_MAG3] == ELFMAG3)
+
+#define ELF_TARG_VER   EV_CURRENT
+
+#if defined(__alpha__)
+
+#define ELF_TARG_MACH  EM_ALPHA
+#define ELF_TARG_CLASS ELFCLASS64
+#define ELF_TARG_DATA  ELFDATA2LSB
+
+#elif defined(__amd64__)
+
+#define ELF_TARG_MACH  EM_X86_64
+#define ELF_TARG_CLASS ELFCLASS64
+#define ELF_TARG_DATA  ELFDATA2LSB
+
+#elif defined(__arm__)
+
+#define ELF_TARG_MACH  EM_ARM
+#define ELF_TARG_CLASS ELFCLASS32
+#if defined(__ARMEB__)
+#define ELF_TARG_DATA  ELFDATA2MSB
+#else
+#define ELF_TARG_DATA  ELFDATA2LSB
+#endif
+
+#elif defined(__avr32__)
+
+#ifndef EM_AVR32
+#define EM_AVR32       0x18ad
+#endif
+#define ELF_TARG_MACH  EM_AVR32
+#define ELF_TARG_CLASS ELFCLASS32
+#if define(__LITTLE_ENDIAN__)
+#define ELF_TARG_DATA  ELFDATA2LSB
+#elif defined(__BIG_ENDIAN__)
+#define ELF_TARG_DATA  ELFDATA2LMSB
+#else
+#error Unknown AVR32 endianness
+#endif
+
+#elif defined(__hppa__)
+
+#define ELF_TARG_MACH  EM_PARISC
+#define ELF_TARG_CLASS ELFCLASS32
+#define ELF_TARG_DATA  ELFDATA2MSB
+
+#elif defined(__i386__)
+
+#define ELF_TARG_MACH  EM_386
+#define ELF_TARG_CLASS ELFCLASS32
+#define ELF_TARG_DATA  ELFDATA2LSB
+
+#elif defined(__ia64__)
+
+#define ELF_TARG_MACH  EM_IA_64
+#define ELF_TARG_CLASS ELFCLASS64
+#define ELF_TARG_DATA  ELFDATA2LSB
+
+#elif defined(__m32r__)
+
+#define ELF_TARG_MACH  EM_M32R
+#define ELF_TARG_CLASS ELFCLASS32
+#if defined(__LITTLE_ENDIAN__)
+#define ELF_DATA       ELFDATA2LSB
+#elif defined(__BIG_ENDIAN__)
+#define ELF_DATA       ELFDATA2MSB
+#else
+#error Unknown M32R endianness
+#endif
+
+#elif defined(__m68k__)
+
+#define ELF_TARG_MACH  EM_68K
+#define ELF_TARG_CLASS ELFCLASS32
+#define ELF_TARG_DATA  ELFDATA2MSB
+
+#elif defined(__mips__)
+
+#define ELF_TARG_MACH  EM_MIPS
+#define ELF_TARG_CLASS ELFCLASS32
+#if defined(__MIPSEB__)
+#define ELF_TARG_DATA  ELFDATA2MSB
+#else
+#define ELF_TARG_DATA  ELFDATA2LSB
+#endif
+
+#elif defined(__powerpc__)
+
+#define ELF_TARG_MACH  EM_PPC
+#define ELF_TARG_CLASS ELFCLASS32
+#define ELF_TARG_DATA  ELFDATA2MSG
+
+#elif defined(__powerpc64__)
+
+#define ELF_TARG_MACH  EM_PPC64
+#define ELF_TARG_CLASS ELFCLASS64
+#define ELF_TARG_DATA  ELFDATA2MSG
+
+#elif defined(__sparc__)
+
+#if defined(__arch64__)
+#define ELF_TARG_MACH  EM_SPARCV9
+#define ELF_TARG_CLASS ELFCLASS64
+#else
+#define ELF_TARG_MACH  EM_SPARC
+#define ELF_TARG_CLASS ELFCLASS32
+#endif
+#define ELF_TARG_DATA  ELFDATA2MSB
+
+#elif defined(__sh__)
+
+#define ELF_TARG_MACH  EM_SH
+#define ELF_TARG_CLASS ELFCLASS32
+#if define(__LITTLE_ENDIAN__)
+#define ELF_TARG_DATA  ELFDATA2LSB
+#elif defined(__BIG_ENDIAN__)
+#define ELF_TARG_DATA  ELFDATA2LMSB
+#else
+#error Unknown SH endianness
+#endif
+
+#elif defined(__s390__)
+
+#define ELF_TARG_MACH  EM_S390
+#if defined(__s390x__)
+#define ELF_TARG_CLASS ELFCLASS64
+#else
+#define ELF_TARG_CLASS ELFCLASS32
+#endif
+#define ELF_TARG_DATA  ELFDATA2MSG
+
+#else
+
+#error Unknown ELF machine type
+
+#endif
+
+#if ELF_TARG_CLASS == ELFCLASS32
+#define ELF_ST_BIND    ELF32_ST_BIND
+#define ELF_ST_TYPE    ELF32_ST_TYPE
+#define Elf_Word       Elf32_Word
+#define Elf_Sword      Elf32_Sword
+#define Elf_Sym                Elf32_Sym
+#define Elf_Off                Elf32_Off
+#define Elf_Shdr       Elf32_Shdr
+#define Elf_Ehdr       Elf32_Ehdr
+#elif ELF_TARG_CLASS == ELFCLASS64
+#define ELF_ST_BIND    ELF64_ST_BIND
+#define ELF_ST_TYPE    ELF64_ST_TYPE
+#define Elf_Word       Elf64_Word
+#define Elf_Sword      Elf64_Sword
+#define Elf_Sym                Elf64_Sym
+#define Elf_Off                Elf64_Off
+#define Elf_Shdr       Elf64_Shdr
+#define Elf_Ehdr       Elf64_Ehdr
+#else
+#error Unknown ELF class
+#endif
+
+#endif
+
diff --git a/src/nlist.c b/src/nlist.c
new file mode 100644 (file)
index 0000000..1db6a06
--- /dev/null
@@ -0,0 +1,419 @@
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)nlist.c    8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+#include <sys/cdefs.h>
+
+#include <sys/param.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <arpa/inet.h>
+
+#include <errno.h>
+#include <a.out.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#if !defined(__NO_A_OUT_SUPPORT)
+#define _NLIST_DO_AOUT
+#endif
+#define _NLIST_DO_ELF
+
+#ifdef _NLIST_DO_ELF
+#include "local-elf.h"
+#endif
+
+#define SIZE_T_MAX 0xffffffffU
+
+#ifdef _NLIST_DO_AOUT
+static int __aout_fdnlist(int, struct nlist *);
+#endif
+#ifdef _NLIST_DO_ELF
+static int __elf_fdnlist(int, struct nlist *);
+#endif
+
+/* FIXME: This function is used by libkvm0, so we need to export it.
+   It is not declared in the include files though. */
+int __fdnlist(int, struct nlist *);
+
+int
+nlist(name, list)
+       const char *name;
+       struct nlist *list;
+{
+       int fd, n;
+
+       fd = open(name, O_RDONLY, 0);
+       if (fd < 0)
+               return (-1);
+       n = __fdnlist(fd, list);
+       (void)close(fd);
+       return (n);
+}
+
+static struct nlist_handlers {
+       int     (*fn)(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)
+       int fd;
+       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
+static int
+__aout_fdnlist(fd, list)
+       int fd;
+       struct nlist *list;
+{
+       struct nlist *p, *symtab;
+       caddr_t strtab, a_out_mmap;
+       off_t stroff, symoff;
+       u_long symsize;
+       int nent;
+       struct exec * exec;
+       struct stat st;
+
+       /* check that file is at least as large as struct exec! */
+       if ((fstat(fd, &st) < 0) || (st.st_size < sizeof(struct exec)))
+               return (-1);
+
+       /* Check for files too large to mmap. */
+       if (st.st_size > SIZE_T_MAX) {
+               errno = EFBIG;
+               return (-1);
+       }
+
+       /*
+        * Map the whole a.out file into our address space.
+        * We then find the string table withing this area.
+        * We do not just mmap the string table, as it probably
+        * does not start at a page boundary - we save ourselves a
+        * lot of nastiness by mmapping the whole file.
+        *
+        * 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).
+        */
+       a_out_mmap = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0);
+       if (a_out_mmap == MAP_FAILED)
+               return (-1);
+
+       exec = (struct exec *)a_out_mmap;
+       if (N_BADMAG(*exec)) {
+               munmap(a_out_mmap, (size_t)st.st_size);
+               return (-1);
+       }
+
+       symoff = N_SYMOFF(*exec);
+       symsize = exec->a_syms;
+       stroff = symoff + symsize;
+
+       /* find the string table in our mmapped area */
+       strtab = a_out_mmap + stroff;
+       symtab = (struct nlist *)(a_out_mmap + symoff);
+
+       /*
+        * 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;
+       }
+
+       while (symsize > 0) {
+               int soff;
+
+               symsize-= sizeof(struct nlist);
+               soff = symtab->n_un.n_strx;
+
+
+               if (soff != 0 && (symtab->n_type & N_STAB) == 0)
+                       for (p = list; !ISLAST(p); p++)
+                               if (!strcmp(&strtab[soff], p->n_un.n_name)) {
+                                       p->n_value = symtab->n_value;
+                                       p->n_type = symtab->n_type;
+                                       p->n_desc = symtab->n_desc;
+                                       p->n_other = symtab->n_other;
+                                       if (--nent <= 0)
+                                               break;
+                               }
+               symtab++;
+       }
+       munmap(a_out_mmap, (size_t)st.st_size);
+       return (nent);
+}
+#endif
+
+#ifdef _NLIST_DO_ELF
+static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int);
+
+/*
+ * __elf_is_okay__ - Determine if ehdr really
+ * is ELF and valid for the target platform.
+ *
+ * WARNING:  This is NOT an ELF ABI function and
+ * as such its use should be restricted.
+ */
+static int
+__elf_is_okay__(ehdr)
+       Elf_Ehdr *ehdr;
+{
+       int retval = 0;
+       /*
+        * We need to check magic, class size, endianess,
+        * and version before we look at the rest of the
+        * Elf_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;
+}
+
+static int
+__elf_fdnlist(fd, list)
+       int fd;
+       struct nlist *list;
+{
+       struct nlist *p;
+       Elf_Off symoff = 0, symstroff = 0;
+       Elf_Word symsize = 0, symstrsize = 0;
+       Elf_Sword cc, i;
+       int nent = -1;
+       int errsave;
+       Elf_Sym sbuf[1024];
+       Elf_Sym *s;
+       Elf_Ehdr ehdr;
+       char *strtab = NULL;
+       Elf_Shdr *shdr = NULL;
+       Elf_Word shdr_size;
+       void *base;
+       struct stat st;
+
+       /* Make sure obj is OK */
+       if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
+           read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_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 */
+       base = mmap(NULL, (size_t)shdr_size, PROT_READ, 0, fd,
+           (off_t)ehdr.e_shoff);
+       if (base == MAP_FAILED)
+               return (-1);
+       shdr = (Elf_Shdr *)base;
+
+       /*
+        * 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;
+               }
+       }
+
+       /* Check for files too large to mmap. */
+       if (symstrsize > SIZE_T_MAX) {
+               errno = EFBIG;
+               goto done;
+       }
+       /*
+        * 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).
+        */
+       base = mmap(NULL, (size_t)symstrsize, PROT_READ, 0, fd,
+           (off_t)symstroff);
+       if (base == MAP_FAILED)
+               goto done;
+       strtab = (char *)base;
+
+       /*
+        * 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. */
+       if (symoff == 0)
+               goto done;
+               
+       if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) {
+               nent = -1;
+               goto done;
+       }
+
+       while (symsize > 0 && nent > 0) {
+               cc = MIN(symsize, sizeof(sbuf));
+               if (read(fd, sbuf, cc) != cc)
+                       break;
+               symsize -= cc;
+               for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) {
+                       char *name;
+                       struct nlist *p;
+
+                       name = strtab + s->st_name;
+                       if (name[0] == '\0')
+                               continue;
+                       for (p = list; !ISLAST(p); p++) {
+                               if ((p->n_un.n_name[0] == '_' &&
+                                   strcmp(name, p->n_un.n_name+1) == 0)
+                                   || strcmp(name, p->n_un.n_name) == 0) {
+                                       elf_sym_to_nlist(p, s, shdr,
+                                           ehdr.e_shnum);
+                                       if (--nent <= 0)
+                                               break;
+                               }
+                       }
+               }
+       }
+  done:
+       errsave = errno;
+       if (strtab != NULL)
+               munmap(strtab, symstrsize);
+       if (shdr != NULL)
+               munmap(shdr, shdr_size);
+       errno = errsave;
+       return (nent);
+}
+
+/*
+ * Convert an Elf_Sym into an nlist structure.  This fills in only the
+ * n_value and n_type members.
+ */
+static void
+elf_sym_to_nlist(nl, s, shdr, shnum)
+       struct nlist *nl;
+       Elf_Sym *s;
+       Elf_Shdr *shdr;
+       int shnum;
+{
+       nl->n_value = s->st_value;
+
+       switch (s->st_shndx) {
+       case SHN_UNDEF:
+       case SHN_COMMON:
+               nl->n_type = N_UNDF;
+               break;
+       case SHN_ABS:
+               nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ?
+                   N_FN : N_ABS;
+               break;
+       default:
+               if (s->st_shndx >= shnum)
+                       nl->n_type = N_UNDF;
+               else {
+                       Elf_Shdr *sh = shdr + s->st_shndx;
+
+                       nl->n_type = sh->sh_type == SHT_PROGBITS ?
+                           (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) :
+                           (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF);
+               }
+               break;
+       }
+
+       if (ELF_ST_BIND(s->st_info) == STB_GLOBAL ||
+           ELF_ST_BIND(s->st_info) == STB_WEAK)
+               nl->n_type |= N_EXT;
+}
+#endif /* _NLIST_DO_ELF */