diff options
author | Guillem Jover <guillem@hadrons.org> | 2009-05-20 04:11:57 +0200 |
---|---|---|
committer | Guillem Jover <guillem@hadrons.org> | 2009-05-20 04:14:19 +0200 |
commit | dcaec44a6fd4ede2b8d8050a7c05185c28f66917 (patch) | |
tree | e7fb212f4d91757e9d29a00978c8a63f0b9f7776 | |
parent | 8dbfb3529b0253ba8067042dabaebe3ad89cb039 (diff) | |
download | libbsd-dcaec44a6fd4ede2b8d8050a7c05185c28f66917.tar.gz |
Add nlist function
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | Versions | 3 | ||||
-rw-r--r-- | include/nlist.h | 38 | ||||
-rw-r--r-- | man/nlist.3 | 77 | ||||
-rw-r--r-- | src/local-elf.h | 197 | ||||
-rw-r--r-- | src/nlist.c | 419 |
6 files changed, 735 insertions, 0 deletions
@@ -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)) @@ -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 */ |