1331722Seadler/* 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 * 4. Neither the name of the University nor the names of its contributors 141573Srgrimes * may be used to endorse or promote products derived from this software 151573Srgrimes * without specific prior written permission. 161573Srgrimes * 171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201573Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271573Srgrimes * SUCH DAMAGE. 281573Srgrimes */ 291573Srgrimes 301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint) 311573Srgrimesstatic char sccsid[] = "@(#)nlist.c 8.1 (Berkeley) 6/4/93"; 321573Srgrimes#endif /* LIBC_SCCS and not lint */ 3390045Sobrien#include <sys/cdefs.h> 3490045Sobrien__FBSDID("$FreeBSD$"); 351573Srgrimes 3671579Sdeischen#include "namespace.h" 371573Srgrimes#include <sys/param.h> 381573Srgrimes#include <sys/mman.h> 391573Srgrimes#include <sys/stat.h> 401573Srgrimes#include <sys/file.h> 41111618Snectar#include <arpa/inet.h> 421573Srgrimes 431573Srgrimes#include <errno.h> 441573Srgrimes#include <a.out.h> 451573Srgrimes#include <stdio.h> 461573Srgrimes#include <string.h> 471573Srgrimes#include <unistd.h> 4871579Sdeischen#include "un-namespace.h" 491573Srgrimes 50292623Semaste/* i386 is the only current FreeBSD architecture that used a.out format. */ 51292623Semaste#ifdef __i386__ 5228947Speter#define _NLIST_DO_AOUT 53280219Sandrew#endif 5436919Speter#define _NLIST_DO_ELF 5517141Sjkh 5628947Speter#ifdef _NLIST_DO_ELF 5776224Sobrien#include <machine/elf.h> 5876224Sobrien#include <elf-hints.h> 5928947Speter#endif 6028947Speter 6190045Sobrienint __fdnlist(int, struct nlist *); 6290045Sobrienint __aout_fdnlist(int, struct nlist *); 6390045Sobrienint __elf_fdnlist(int, struct nlist *); 64288028Srodrigcint __elf_is_okay__(Elf_Ehdr *); 6528947Speter 661573Srgrimesint 67287793Srodrigcnlist(const char *name, struct nlist *list) 681573Srgrimes{ 691573Srgrimes int fd, n; 701573Srgrimes 71241046Sjilles fd = _open(name, O_RDONLY | O_CLOEXEC, 0); 721573Srgrimes if (fd < 0) 731573Srgrimes return (-1); 741573Srgrimes n = __fdnlist(fd, list); 7556698Sjasone (void)_close(fd); 761573Srgrimes return (n); 771573Srgrimes} 781573Srgrimes 7928947Speterstatic struct nlist_handlers { 8090045Sobrien int (*fn)(int fd, struct nlist *list); 8128947Speter} nlist_fn[] = { 8228947Speter#ifdef _NLIST_DO_AOUT 8328947Speter { __aout_fdnlist }, 8428947Speter#endif 8528947Speter#ifdef _NLIST_DO_ELF 8628947Speter { __elf_fdnlist }, 8728947Speter#endif 8828947Speter}; 891573Srgrimes 901573Srgrimesint 91287793Srodrigc__fdnlist(int fd, struct nlist *list) 921573Srgrimes{ 93287793Srodrigc int n = -1; 94287793Srodrigc unsigned int i; 9528947Speter 96298120Spfg for (i = 0; i < nitems(nlist_fn); i++) { 9728947Speter n = (nlist_fn[i].fn)(fd, list); 9828947Speter if (n != -1) 9928947Speter break; 10028947Speter } 10128947Speter return (n); 10228947Speter} 10328947Speter 10428947Speter#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0) 10528947Speter 10628947Speter#ifdef _NLIST_DO_AOUT 10728947Speterint 108287793Srodrigc__aout_fdnlist(int fd, struct nlist *list) 10928947Speter{ 11090045Sobrien struct nlist *p, *symtab; 11190045Sobrien caddr_t strtab, a_out_mmap; 11290045Sobrien off_t stroff, symoff; 11390045Sobrien u_long symsize; 11490045Sobrien int nent; 1151794Scsgr struct exec * exec; 1161573Srgrimes struct stat st; 1171573Srgrimes 1181794Scsgr /* check that file is at least as large as struct exec! */ 11971579Sdeischen if ((_fstat(fd, &st) < 0) || (st.st_size < sizeof(struct exec))) 1201573Srgrimes return (-1); 1211573Srgrimes 1221573Srgrimes /* Check for files too large to mmap. */ 1231794Scsgr if (st.st_size > SIZE_T_MAX) { 1241573Srgrimes errno = EFBIG; 1251573Srgrimes return (-1); 1261573Srgrimes } 1271794Scsgr 1281573Srgrimes /* 1291794Scsgr * Map the whole a.out file into our address space. 1301794Scsgr * We then find the string table withing this area. 1311794Scsgr * We do not just mmap the string table, as it probably 1321794Scsgr * does not start at a page boundary - we save ourselves a 1331794Scsgr * lot of nastiness by mmapping the whole file. 1341794Scsgr * 1358870Srgrimes * This gives us an easy way to randomly access all the strings, 1368870Srgrimes * without making the memory allocation permanent as with 1371794Scsgr * malloc/free (i.e., munmap will return it to the system). 1381573Srgrimes */ 13921786Salex a_out_mmap = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_PRIVATE, fd, (off_t)0); 14021786Salex if (a_out_mmap == MAP_FAILED) 1411573Srgrimes return (-1); 1421794Scsgr 1431794Scsgr exec = (struct exec *)a_out_mmap; 1441794Scsgr if (N_BADMAG(*exec)) { 1451794Scsgr munmap(a_out_mmap, (size_t)st.st_size); 1461794Scsgr return (-1); 1471794Scsgr } 1481794Scsgr 1491794Scsgr symoff = N_SYMOFF(*exec); 1501794Scsgr symsize = exec->a_syms; 1511794Scsgr stroff = symoff + symsize; 1521794Scsgr 1531794Scsgr /* find the string table in our mmapped area */ 1541794Scsgr strtab = a_out_mmap + stroff; 1551794Scsgr symtab = (struct nlist *)(a_out_mmap + symoff); 1561794Scsgr 1571573Srgrimes /* 1581573Srgrimes * clean out any left-over information for all valid entries. 1591573Srgrimes * Type and value defined to be 0 if not found; historical 1601573Srgrimes * versions cleared other and desc as well. Also figure out 1611573Srgrimes * the largest string length so don't read any more of the 1621573Srgrimes * string table than we have to. 1631573Srgrimes * 1641573Srgrimes * XXX clearing anything other than n_type and n_value violates 1651573Srgrimes * the semantics given in the man page. 1661573Srgrimes */ 1671573Srgrimes nent = 0; 1681573Srgrimes for (p = list; !ISLAST(p); ++p) { 1691573Srgrimes p->n_type = 0; 1701573Srgrimes p->n_other = 0; 1711573Srgrimes p->n_desc = 0; 1721573Srgrimes p->n_value = 0; 1731573Srgrimes ++nent; 1741573Srgrimes } 1751573Srgrimes 1761573Srgrimes while (symsize > 0) { 17790045Sobrien int soff; 1781573Srgrimes 1791794Scsgr symsize-= sizeof(struct nlist); 1801794Scsgr soff = symtab->n_un.n_strx; 1811794Scsgr 1821794Scsgr 1831794Scsgr if (soff != 0 && (symtab->n_type & N_STAB) == 0) 1841573Srgrimes for (p = list; !ISLAST(p); p++) 1851573Srgrimes if (!strcmp(&strtab[soff], p->n_un.n_name)) { 1861794Scsgr p->n_value = symtab->n_value; 1871794Scsgr p->n_type = symtab->n_type; 1881794Scsgr p->n_desc = symtab->n_desc; 1891794Scsgr p->n_other = symtab->n_other; 1901573Srgrimes if (--nent <= 0) 1911573Srgrimes break; 1921573Srgrimes } 1931794Scsgr symtab++; 1941573Srgrimes } 1951794Scsgr munmap(a_out_mmap, (size_t)st.st_size); 1961573Srgrimes return (nent); 1971573Srgrimes} 19828947Speter#endif 19928947Speter 20028947Speter#ifdef _NLIST_DO_ELF 20190045Sobrienstatic void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int); 20238391Sdfr 20328947Speter/* 20428947Speter * __elf_is_okay__ - Determine if ehdr really 20528947Speter * is ELF and valid for the target platform. 20628947Speter * 207108533Sschweikh * WARNING: This is NOT an ELF ABI function and 208108533Sschweikh * as such its use should be restricted. 20928947Speter */ 21028947Speterint 211200150Sed__elf_is_okay__(Elf_Ehdr *ehdr) 21228947Speter{ 21390045Sobrien int retval = 0; 21428947Speter /* 21528947Speter * We need to check magic, class size, endianess, 21628947Speter * and version before we look at the rest of the 21740688Sjdp * Elf_Ehdr structure. These few elements are 21828947Speter * represented in a machine independant fashion. 21928947Speter */ 22028947Speter if (IS_ELF(*ehdr) && 22128947Speter ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS && 22228947Speter ehdr->e_ident[EI_DATA] == ELF_TARG_DATA && 22328947Speter ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) { 22428947Speter 22528947Speter /* Now check the machine dependant header */ 22628947Speter if (ehdr->e_machine == ELF_TARG_MACH && 22728947Speter ehdr->e_version == ELF_TARG_VER) 22828947Speter retval = 1; 22928947Speter } 23028947Speter return retval; 23128947Speter} 23228947Speter 23328947Speterint 234287793Srodrigc__elf_fdnlist(int fd, struct nlist *list) 23528947Speter{ 23690045Sobrien struct nlist *p; 23790045Sobrien Elf_Off symoff = 0, symstroff = 0; 238153504Smarcel Elf_Size symsize = 0, symstrsize = 0; 239153504Smarcel Elf_Ssize cc, i; 24040688Sjdp int nent = -1; 24140688Sjdp int errsave; 24238391Sdfr Elf_Sym sbuf[1024]; 24338391Sdfr Elf_Sym *s; 24438391Sdfr Elf_Ehdr ehdr; 24540688Sjdp char *strtab = NULL; 24638391Sdfr Elf_Shdr *shdr = NULL; 247153504Smarcel Elf_Size shdr_size; 24840688Sjdp void *base; 24928947Speter struct stat st; 25028947Speter 25128947Speter /* Make sure obj is OK */ 25228947Speter if (lseek(fd, (off_t)0, SEEK_SET) == -1 || 25356698Sjasone _read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) || 25428947Speter !__elf_is_okay__(&ehdr) || 25571579Sdeischen _fstat(fd, &st) < 0) 25628947Speter return (-1); 25728947Speter 25828947Speter /* calculate section header table size */ 25928947Speter shdr_size = ehdr.e_shentsize * ehdr.e_shnum; 26028947Speter 26128947Speter /* Make sure it's not too big to mmap */ 26228947Speter if (shdr_size > SIZE_T_MAX) { 26328947Speter errno = EFBIG; 26428947Speter return (-1); 26528947Speter } 26628947Speter 26728947Speter /* mmap section header table */ 268271723Sbdrewery base = mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_PRIVATE, fd, 26940688Sjdp (off_t)ehdr.e_shoff); 27040688Sjdp if (base == MAP_FAILED) 27128947Speter return (-1); 27240688Sjdp shdr = (Elf_Shdr *)base; 27328947Speter 27428947Speter /* 27528947Speter * Find the symbol table entry and it's corresponding 27628947Speter * string table entry. Version 1.1 of the ABI states 27728947Speter * that there is only one symbol table but that this 27828947Speter * could change in the future. 27928947Speter */ 28028947Speter for (i = 0; i < ehdr.e_shnum; i++) { 28128947Speter if (shdr[i].sh_type == SHT_SYMTAB) { 28228947Speter symoff = shdr[i].sh_offset; 28328947Speter symsize = shdr[i].sh_size; 28428947Speter symstroff = shdr[shdr[i].sh_link].sh_offset; 28528947Speter symstrsize = shdr[shdr[i].sh_link].sh_size; 28628947Speter break; 28728947Speter } 28828947Speter } 28928947Speter 29028947Speter /* Check for files too large to mmap. */ 29128947Speter if (symstrsize > SIZE_T_MAX) { 29228947Speter errno = EFBIG; 29340688Sjdp goto done; 29428947Speter } 29528947Speter /* 29628947Speter * Map string table into our address space. This gives us 29728947Speter * an easy way to randomly access all the strings, without 29828947Speter * making the memory allocation permanent as with malloc/free 29928947Speter * (i.e., munmap will return it to the system). 30028947Speter */ 301271723Sbdrewery base = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_PRIVATE, fd, 30240688Sjdp (off_t)symstroff); 30340688Sjdp if (base == MAP_FAILED) 30440688Sjdp goto done; 30540688Sjdp strtab = (char *)base; 30628947Speter 30728947Speter /* 30828947Speter * clean out any left-over information for all valid entries. 30928947Speter * Type and value defined to be 0 if not found; historical 31028947Speter * versions cleared other and desc as well. Also figure out 31128947Speter * the largest string length so don't read any more of the 31228947Speter * string table than we have to. 31328947Speter * 31428947Speter * XXX clearing anything other than n_type and n_value violates 31528947Speter * the semantics given in the man page. 31628947Speter */ 31728947Speter nent = 0; 31828947Speter for (p = list; !ISLAST(p); ++p) { 31928947Speter p->n_type = 0; 32028947Speter p->n_other = 0; 32128947Speter p->n_desc = 0; 32228947Speter p->n_value = 0; 32328947Speter ++nent; 32428947Speter } 32528947Speter 32628947Speter /* Don't process any further if object is stripped. */ 32728947Speter if (symoff == 0) 32828947Speter goto done; 32928947Speter 33028947Speter if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) { 33128947Speter nent = -1; 33228947Speter goto done; 33328947Speter } 33428947Speter 33540688Sjdp while (symsize > 0 && nent > 0) { 33628947Speter cc = MIN(symsize, sizeof(sbuf)); 33756698Sjasone if (_read(fd, sbuf, cc) != cc) 33828947Speter break; 33928947Speter symsize -= cc; 34040688Sjdp for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) { 34140688Sjdp char *name; 34240688Sjdp struct nlist *p; 34328947Speter 34440688Sjdp name = strtab + s->st_name; 34540688Sjdp if (name[0] == '\0') 34628947Speter continue; 34728947Speter for (p = list; !ISLAST(p); p++) { 34828947Speter if ((p->n_un.n_name[0] == '_' && 34940688Sjdp strcmp(name, p->n_un.n_name+1) == 0) 35040688Sjdp || strcmp(name, p->n_un.n_name) == 0) { 35140688Sjdp elf_sym_to_nlist(p, s, shdr, 35240688Sjdp ehdr.e_shnum); 35328947Speter if (--nent <= 0) 35428947Speter break; 35528947Speter } 35628947Speter } 35728947Speter } 35828947Speter } 35928947Speter done: 36040688Sjdp errsave = errno; 36140688Sjdp if (strtab != NULL) 36240688Sjdp munmap(strtab, symstrsize); 36340688Sjdp if (shdr != NULL) 36440688Sjdp munmap(shdr, shdr_size); 36540688Sjdp errno = errsave; 36628947Speter return (nent); 36728947Speter} 36840688Sjdp 36940688Sjdp/* 37040688Sjdp * Convert an Elf_Sym into an nlist structure. This fills in only the 37140688Sjdp * n_value and n_type members. 37240688Sjdp */ 37340688Sjdpstatic void 374287793Srodrigcelf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum) 37540688Sjdp{ 37640688Sjdp nl->n_value = s->st_value; 37740688Sjdp 37840688Sjdp switch (s->st_shndx) { 37940688Sjdp case SHN_UNDEF: 38040688Sjdp case SHN_COMMON: 38140688Sjdp nl->n_type = N_UNDF; 38240688Sjdp break; 38340688Sjdp case SHN_ABS: 38440688Sjdp nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ? 38540688Sjdp N_FN : N_ABS; 38640688Sjdp break; 38740688Sjdp default: 38840688Sjdp if (s->st_shndx >= shnum) 38940688Sjdp nl->n_type = N_UNDF; 39040688Sjdp else { 39140688Sjdp Elf_Shdr *sh = shdr + s->st_shndx; 39240688Sjdp 39340688Sjdp nl->n_type = sh->sh_type == SHT_PROGBITS ? 39440688Sjdp (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) : 39540688Sjdp (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF); 39640688Sjdp } 39740688Sjdp break; 39840688Sjdp } 39940688Sjdp 40040688Sjdp if (ELF_ST_BIND(s->st_info) == STB_GLOBAL || 40140688Sjdp ELF_ST_BIND(s->st_info) == STB_WEAK) 40240688Sjdp nl->n_type |= N_EXT; 40340688Sjdp} 40428947Speter#endif /* _NLIST_DO_ELF */ 405