summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillem Jover <guillem@hadrons.org>2009-05-20 04:11:57 +0200
committerGuillem Jover <guillem@hadrons.org>2009-05-20 04:14:19 +0200
commitdcaec44a6fd4ede2b8d8050a7c05185c28f66917 (patch)
treee7fb212f4d91757e9d29a00978c8a63f0b9f7776
parent8dbfb3529b0253ba8067042dabaebe3ad89cb039 (diff)
downloadlibbsd-dcaec44a6fd4ede2b8d8050a7c05185c28f66917.tar.gz
Add nlist function
-rw-r--r--Makefile1
-rw-r--r--Versions3
-rw-r--r--include/nlist.h38
-rw-r--r--man/nlist.377
-rw-r--r--src/local-elf.h197
-rw-r--r--src/nlist.c419
6 files changed, 735 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 393a050..11564e2 100644
--- 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))
diff --git a/Versions b/Versions
index 21123b6..76d8163 100644
--- 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
index 0000000..95af7d8
--- /dev/null
+++ b/include/nlist.h
@@ -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
index 0000000..6a9b367
--- /dev/null
+++ b/man/nlist.3
@@ -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
index 0000000..1ac0fc8
--- /dev/null
+++ b/src/local-elf.h
@@ -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
index 0000000..1db6a06
--- /dev/null
+++ b/src/nlist.c
@@ -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 */