nlist.c revision 111618
11573Srgrimes/* 21573Srgrimes * Copyright (c) 1989, 1993 31573Srgrimes * The Regents of the University of California. All rights reserved. 41573Srgrimes * 51573Srgrimes * Redistribution and use in source and binary forms, with or without 61573Srgrimes * modification, are permitted provided that the following conditions 71573Srgrimes * are met: 81573Srgrimes * 1. Redistributions of source code must retain the above copyright 91573Srgrimes * notice, this list of conditions and the following disclaimer. 101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111573Srgrimes * notice, this list of conditions and the following disclaimer in the 121573Srgrimes * documentation and/or other materials provided with the distribution. 131573Srgrimes * 3. All advertising materials mentioning features or use of this software 141573Srgrimes * must display the following acknowledgement: 151573Srgrimes * This product includes software developed by the University of 161573Srgrimes * California, Berkeley and its contributors. 171573Srgrimes * 4. Neither the name of the University nor the names of its contributors 181573Srgrimes * may be used to endorse or promote products derived from this software 191573Srgrimes * without specific prior written permission. 201573Srgrimes * 211573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311573Srgrimes * SUCH DAMAGE. 321573Srgrimes */ 331573Srgrimes 341573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 351573Srgrimesstatic char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) 6/4/93"; 361573Srgrimes#endif /* LIBC_SCCS and not lint */ 3790045Sobrien#include <sys/cdefs.h> 3890045Sobrien__FBSDID("$FreeBSD: head/lib/libc/gen/nlist.c 111618 2003-02-27 13:40:01Z nectar $"); 391573Srgrimes 4071579Sdeischen#include "namespace.h" 411573Srgrimes#include <sys/param.h> 421573Srgrimes#include <sys/mman.h> 431573Srgrimes#include <sys/stat.h> 441573Srgrimes#include <sys/file.h> 45111618Snectar#include <arpa/inet.h> 461573Srgrimes 471573Srgrimes#include <errno.h> 481573Srgrimes#include <a.out.h> 491573Srgrimes#include <stdio.h> 501573Srgrimes#include <string.h> 511573Srgrimes#include <unistd.h> 5271579Sdeischen#include "un-namespace.h" 531573Srgrimes 5428947Speter#define _NLIST_DO_AOUT 5536919Speter#define _NLIST_DO_ELF 5617141Sjkh 5728947Speter#ifdef _NLIST_DO_ELF 5876224Sobrien#include <machine/elf.h> 5976224Sobrien#include <elf-hints.h> 6028947Speter#endif 6128947Speter 6290045Sobrienint __fdnlist(int, struct nlist *); 6390045Sobrienint __aout_fdnlist(int, struct nlist *); 6490045Sobrienint __elf_fdnlist(int, struct nlist *); 6528947Speter 661573Srgrimesint 671573Srgrimesnlist(name, list) 681573Srgrimes const char *name; 691573Srgrimes struct nlist *list; 701573Srgrimes{ 711573Srgrimes int fd, n; 721573Srgrimes 7356698Sjasone fd = _open(name, O_RDONLY, 0); 741573Srgrimes if (fd < 0) 751573Srgrimes return (-1); 761573Srgrimes n = __fdnlist(fd, list); 7756698Sjasone (void)_close(fd); 781573Srgrimes return (n); 791573Srgrimes} 801573Srgrimes 8128947Speterstatic struct nlist_handlers { 8290045Sobrien int (*fn)(int fd, struct nlist *list); 8328947Speter} nlist_fn[] = { 8428947Speter#ifdef _NLIST_DO_AOUT 8528947Speter { __aout_fdnlist }, 8628947Speter#endif 8728947Speter#ifdef _NLIST_DO_ELF 8828947Speter { __elf_fdnlist }, 8928947Speter#endif 9028947Speter}; 911573Srgrimes 921573Srgrimesint 931573Srgrimes__fdnlist(fd, list) 9490045Sobrien int fd; 9590045Sobrien struct nlist *list; 961573Srgrimes{ 9728947Speter int n = -1, i; 9828947Speter 9928947Speter for (i = 0; i < sizeof(nlist_fn) / sizeof(nlist_fn[0]); i++) { 10028947Speter n = (nlist_fn[i].fn)(fd, list); 10128947Speter if (n != -1) 10228947Speter break; 10328947Speter } 10428947Speter return (n); 10528947Speter} 10628947Speter 10728947Speter#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0) 10828947Speter 10928947Speter#ifdef _NLIST_DO_AOUT 11028947Speterint 11128947Speter__aout_fdnlist(fd, list) 11290045Sobrien int fd; 11390045Sobrien struct nlist *list; 11428947Speter{ 11590045Sobrien struct nlist *p, *symtab; 11690045Sobrien caddr_t strtab, a_out_mmap; 11790045Sobrien off_t stroff, symoff; 11890045Sobrien u_long symsize; 11990045Sobrien int nent; 1201794Scsgr struct exec * exec; 1211573Srgrimes struct stat st; 1221573Srgrimes 1231794Scsgr /* check that file is at least as large as struct exec! */ 12471579Sdeischen if ((_fstat(fd, &st) < 0) || (st.st_size < sizeof(struct exec))) 1251573Srgrimes return (-1); 1261573Srgrimes 1271573Srgrimes /* Check for files too large to mmap. */ 1281794Scsgr if (st.st_size > SIZE_T_MAX) { 1291573Srgrimes errno = EFBIG; 1301573Srgrimes return (-1); 1311573Srgrimes } 1321794Scsgr 1331573Srgrimes /* 1341794Scsgr * Map the whole a.out file into our address space. 1351794Scsgr * We then find the string table withing this area. 1361794Scsgr * We do not just mmap the string table, as it probably 1371794Scsgr * does not start at a page boundary - we save ourselves a 1381794Scsgr * lot of nastiness by mmapping the whole file. 1391794Scsgr * 1408870Srgrimes * This gives us an easy way to randomly access all the strings, 1418870Srgrimes * without making the memory allocation permanent as with 1421794Scsgr * malloc/free (i.e., munmap will return it to the system). 1431573Srgrimes */ 14421786Salex a_out_mmap = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); 14521786Salex if (a_out_mmap == MAP_FAILED) 1461573Srgrimes return (-1); 1471794Scsgr 1481794Scsgr exec = (struct exec *)a_out_mmap; 1491794Scsgr if (N_BADMAG(*exec)) { 1501794Scsgr munmap(a_out_mmap, (size_t)st.st_size); 1511794Scsgr return (-1); 1521794Scsgr } 1531794Scsgr 1541794Scsgr symoff = N_SYMOFF(*exec); 1551794Scsgr symsize = exec->a_syms; 1561794Scsgr stroff = symoff + symsize; 1571794Scsgr 1581794Scsgr /* find the string table in our mmapped area */ 1591794Scsgr strtab = a_out_mmap + stroff; 1601794Scsgr symtab = (struct nlist *)(a_out_mmap + symoff); 1611794Scsgr 1621573Srgrimes /* 1631573Srgrimes * clean out any left-over information for all valid entries. 1641573Srgrimes * Type and value defined to be 0 if not found; historical 1651573Srgrimes * versions cleared other and desc as well. Also figure out 1661573Srgrimes * the largest string length so don't read any more of the 1671573Srgrimes * string table than we have to. 1681573Srgrimes * 1691573Srgrimes * XXX clearing anything other than n_type and n_value violates 1701573Srgrimes * the semantics given in the man page. 1711573Srgrimes */ 1721573Srgrimes nent = 0; 1731573Srgrimes for (p = list; !ISLAST(p); ++p) { 1741573Srgrimes p->n_type = 0; 1751573Srgrimes p->n_other = 0; 1761573Srgrimes p->n_desc = 0; 1771573Srgrimes p->n_value = 0; 1781573Srgrimes ++nent; 1791573Srgrimes } 1801573Srgrimes 1811573Srgrimes while (symsize > 0) { 18290045Sobrien int soff; 1831573Srgrimes 1841794Scsgr symsize-= sizeof(struct nlist); 1851794Scsgr soff = symtab->n_un.n_strx; 1861794Scsgr 1871794Scsgr 1881794Scsgr if (soff != 0 && (symtab->n_type & N_STAB) == 0) 1891573Srgrimes for (p = list; !ISLAST(p); p++) 1901573Srgrimes if (!strcmp(&strtab[soff], p->n_un.n_name)) { 1911794Scsgr p->n_value = symtab->n_value; 1921794Scsgr p->n_type = symtab->n_type; 1931794Scsgr p->n_desc = symtab->n_desc; 1941794Scsgr p->n_other = symtab->n_other; 1951573Srgrimes if (--nent <= 0) 1961573Srgrimes break; 1971573Srgrimes } 1981794Scsgr symtab++; 1991573Srgrimes } 2001794Scsgr munmap(a_out_mmap, (size_t)st.st_size); 2011573Srgrimes return (nent); 2021573Srgrimes} 20328947Speter#endif 20428947Speter 20528947Speter#ifdef _NLIST_DO_ELF 20690045Sobrienstatic void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int); 20738391Sdfr 20828947Speter/* 20928947Speter * __elf_is_okay__ - Determine if ehdr really 21028947Speter * is ELF and valid for the target platform. 21128947Speter * 212108533Sschweikh * WARNING: This is NOT an ELF ABI function and 213108533Sschweikh * as such its use should be restricted. 21428947Speter */ 21528947Speterint 21628947Speter__elf_is_okay__(ehdr) 21790045Sobrien Elf_Ehdr *ehdr; 21828947Speter{ 21990045Sobrien int retval = 0; 22028947Speter /* 22128947Speter * We need to check magic, class size, endianess, 22228947Speter * and version before we look at the rest of the 22340688Sjdp * Elf_Ehdr structure. These few elements are 22428947Speter * represented in a machine independant fashion. 22528947Speter */ 22628947Speter if (IS_ELF(*ehdr) && 22728947Speter ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS && 22828947Speter ehdr->e_ident[EI_DATA] == ELF_TARG_DATA && 22928947Speter ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) { 23028947Speter 23128947Speter /* Now check the machine dependant header */ 23228947Speter if (ehdr->e_machine == ELF_TARG_MACH && 23328947Speter ehdr->e_version == ELF_TARG_VER) 23428947Speter retval = 1; 23528947Speter } 23628947Speter return retval; 23728947Speter} 23828947Speter 23928947Speterint 24028947Speter__elf_fdnlist(fd, list) 24190045Sobrien int fd; 24290045Sobrien struct nlist *list; 24328947Speter{ 24490045Sobrien struct nlist *p; 24590045Sobrien Elf_Off symoff = 0, symstroff = 0; 24690045Sobrien Elf_Word symsize = 0, symstrsize = 0; 24790045Sobrien Elf_Sword cc, i; 24840688Sjdp int nent = -1; 24940688Sjdp int errsave; 25038391Sdfr Elf_Sym sbuf[1024]; 25138391Sdfr Elf_Sym *s; 25238391Sdfr Elf_Ehdr ehdr; 25340688Sjdp char *strtab = NULL; 25438391Sdfr Elf_Shdr *shdr = NULL; 25538391Sdfr Elf_Word shdr_size; 25640688Sjdp void *base; 25728947Speter struct stat st; 25828947Speter 25928947Speter /* Make sure obj is OK */ 26028947Speter if (lseek(fd, (off_t)0, SEEK_SET) == -1 || 26156698Sjasone _read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) || 26228947Speter !__elf_is_okay__(&ehdr) || 26371579Sdeischen _fstat(fd, &st) < 0) 26428947Speter return (-1); 26528947Speter 26628947Speter /* calculate section header table size */ 26728947Speter shdr_size = ehdr.e_shentsize * ehdr.e_shnum; 26828947Speter 26928947Speter /* Make sure it's not too big to mmap */ 27028947Speter if (shdr_size > SIZE_T_MAX) { 27128947Speter errno = EFBIG; 27228947Speter return (-1); 27328947Speter } 27428947Speter 27528947Speter /* mmap section header table */ 27640688Sjdp base = mmap(NULL, (size_t)shdr_size, PROT_READ, 0, fd, 27740688Sjdp (off_t)ehdr.e_shoff); 27840688Sjdp if (base == MAP_FAILED) 27928947Speter return (-1); 28040688Sjdp shdr = (Elf_Shdr *)base; 28128947Speter 28228947Speter /* 28328947Speter * Find the symbol table entry and it's corresponding 28428947Speter * string table entry. Version 1.1 of the ABI states 28528947Speter * that there is only one symbol table but that this 28628947Speter * could change in the future. 28728947Speter */ 28828947Speter for (i = 0; i < ehdr.e_shnum; i++) { 28928947Speter if (shdr[i].sh_type == SHT_SYMTAB) { 29028947Speter symoff = shdr[i].sh_offset; 29128947Speter symsize = shdr[i].sh_size; 29228947Speter symstroff = shdr[shdr[i].sh_link].sh_offset; 29328947Speter symstrsize = shdr[shdr[i].sh_link].sh_size; 29428947Speter break; 29528947Speter } 29628947Speter } 29728947Speter 29828947Speter /* Check for files too large to mmap. */ 29928947Speter if (symstrsize > SIZE_T_MAX) { 30028947Speter errno = EFBIG; 30140688Sjdp goto done; 30228947Speter } 30328947Speter /* 30428947Speter * Map string table into our address space. This gives us 30528947Speter * an easy way to randomly access all the strings, without 30628947Speter * making the memory allocation permanent as with malloc/free 30728947Speter * (i.e., munmap will return it to the system). 30828947Speter */ 30940688Sjdp base = mmap(NULL, (size_t)symstrsize, PROT_READ, 0, fd, 31040688Sjdp (off_t)symstroff); 31140688Sjdp if (base == MAP_FAILED) 31240688Sjdp goto done; 31340688Sjdp strtab = (char *)base; 31428947Speter 31528947Speter /* 31628947Speter * clean out any left-over information for all valid entries. 31728947Speter * Type and value defined to be 0 if not found; historical 31828947Speter * versions cleared other and desc as well. Also figure out 31928947Speter * the largest string length so don't read any more of the 32028947Speter * string table than we have to. 32128947Speter * 32228947Speter * XXX clearing anything other than n_type and n_value violates 32328947Speter * the semantics given in the man page. 32428947Speter */ 32528947Speter nent = 0; 32628947Speter for (p = list; !ISLAST(p); ++p) { 32728947Speter p->n_type = 0; 32828947Speter p->n_other = 0; 32928947Speter p->n_desc = 0; 33028947Speter p->n_value = 0; 33128947Speter ++nent; 33228947Speter } 33328947Speter 33428947Speter /* Don't process any further if object is stripped. */ 33528947Speter if (symoff == 0) 33628947Speter goto done; 33728947Speter 33828947Speter if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) { 33928947Speter nent = -1; 34028947Speter goto done; 34128947Speter } 34228947Speter 34340688Sjdp while (symsize > 0 && nent > 0) { 34428947Speter cc = MIN(symsize, sizeof(sbuf)); 34556698Sjasone if (_read(fd, sbuf, cc) != cc) 34628947Speter break; 34728947Speter symsize -= cc; 34840688Sjdp for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) { 34940688Sjdp char *name; 35040688Sjdp struct nlist *p; 35128947Speter 35240688Sjdp name = strtab + s->st_name; 35340688Sjdp if (name[0] == '\0') 35428947Speter continue; 35528947Speter for (p = list; !ISLAST(p); p++) { 35628947Speter if ((p->n_un.n_name[0] == '_' && 35740688Sjdp strcmp(name, p->n_un.n_name+1) == 0) 35840688Sjdp || strcmp(name, p->n_un.n_name) == 0) { 35940688Sjdp elf_sym_to_nlist(p, s, shdr, 36040688Sjdp ehdr.e_shnum); 36128947Speter if (--nent <= 0) 36228947Speter break; 36328947Speter } 36428947Speter } 36528947Speter } 36628947Speter } 36728947Speter done: 36840688Sjdp errsave = errno; 36940688Sjdp if (strtab != NULL) 37040688Sjdp munmap(strtab, symstrsize); 37140688Sjdp if (shdr != NULL) 37240688Sjdp munmap(shdr, shdr_size); 37340688Sjdp errno = errsave; 37428947Speter return (nent); 37528947Speter} 37640688Sjdp 37740688Sjdp/* 37840688Sjdp * Convert an Elf_Sym into an nlist structure. This fills in only the 37940688Sjdp * n_value and n_type members. 38040688Sjdp */ 38140688Sjdpstatic void 38240688Sjdpelf_sym_to_nlist(nl, s, shdr, shnum) 38340688Sjdp struct nlist *nl; 38440688Sjdp Elf_Sym *s; 38540688Sjdp Elf_Shdr *shdr; 38640688Sjdp int shnum; 38740688Sjdp{ 38840688Sjdp nl->n_value = s->st_value; 38940688Sjdp 39040688Sjdp switch (s->st_shndx) { 39140688Sjdp case SHN_UNDEF: 39240688Sjdp case SHN_COMMON: 39340688Sjdp nl->n_type = N_UNDF; 39440688Sjdp break; 39540688Sjdp case SHN_ABS: 39640688Sjdp nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ? 39740688Sjdp N_FN : N_ABS; 39840688Sjdp break; 39940688Sjdp default: 40040688Sjdp if (s->st_shndx >= shnum) 40140688Sjdp nl->n_type = N_UNDF; 40240688Sjdp else { 40340688Sjdp Elf_Shdr *sh = shdr + s->st_shndx; 40440688Sjdp 40540688Sjdp nl->n_type = sh->sh_type == SHT_PROGBITS ? 40640688Sjdp (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) : 40740688Sjdp (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF); 40840688Sjdp } 40940688Sjdp break; 41040688Sjdp } 41140688Sjdp 41240688Sjdp if (ELF_ST_BIND(s->st_info) == STB_GLOBAL || 41340688Sjdp ELF_ST_BIND(s->st_info) == STB_WEAK) 41440688Sjdp nl->n_type |= N_EXT; 41540688Sjdp} 41628947Speter#endif /* _NLIST_DO_ELF */ 417