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