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