xref: /csrg-svn/lib/libc/gen/nlist.c (revision 61111)
121349Sdist /*
2*61111Sbostic  * Copyright (c) 1989, 1993
3*61111Sbostic  *	The Regents of the University of California.  All rights reserved.
439649Sbostic  *
542625Sbostic  * %sccs.include.redist.c%
621349Sdist  */
716668Sralph 
826572Sdonn #if defined(LIBC_SCCS) && !defined(lint)
9*61111Sbostic static char sccsid[] = "@(#)nlist.c	8.1 (Berkeley) 06/04/93";
1039649Sbostic #endif /* LIBC_SCCS and not lint */
1121349Sdist 
1253106Storek #include <sys/param.h>
1353106Storek #include <sys/mman.h>
1453106Storek #include <sys/stat.h>
1539649Sbostic #include <sys/file.h>
1654371Sbostic 
1754371Sbostic #include <errno.h>
181972Swnj #include <a.out.h>
191972Swnj #include <stdio.h>
2046597Sdonn #include <string.h>
2139649Sbostic #include <unistd.h>
221972Swnj 
2346597Sdonn int
nlist(name,list)241972Swnj nlist(name, list)
2546597Sdonn 	const char *name;
2653106Storek 	struct nlist *list;
271972Swnj {
2853106Storek 	int fd, n;
291972Swnj 
3053106Storek 	fd = open(name, O_RDONLY, 0);
3153106Storek 	if (fd < 0)
3253106Storek 		return (-1);
3353113Smckusick 	n = __fdnlist(fd, list);
3453106Storek 	(void)close(fd);
3553106Storek 	return (n);
3653106Storek }
3739649Sbostic 
3853106Storek #define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
3939649Sbostic 
4053106Storek int
__fdnlist(fd,list)4153106Storek __fdnlist(fd, list)
4253106Storek 	register int fd;
4353106Storek 	register struct nlist *list;
4453106Storek {
4553106Storek 	register struct nlist *p, *s;
4653106Storek 	register caddr_t strtab;
4753106Storek 	register off_t stroff, symoff;
4853106Storek 	register u_long symsize;
4954371Sbostic 	register int nent, cc;
5054371Sbostic 	size_t strsize;
5153106Storek 	struct nlist nbuf[1024];
5253106Storek 	struct exec exec;
5353106Storek 	struct stat st;
5439649Sbostic 
5553106Storek 	if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
5653106Storek 	    read(fd, &exec, sizeof(exec)) != sizeof(exec) ||
5753106Storek 	    N_BADMAG(exec) || fstat(fd, &st) < 0)
5853106Storek 		return (-1);
5939649Sbostic 
6053106Storek 	symoff = N_SYMOFF(exec);
6153106Storek 	symsize = exec.a_syms;
6253106Storek 	stroff = symoff + symsize;
6354371Sbostic 
6454371Sbostic 	/* Check for files too large to mmap. */
6554371Sbostic 	if (st.st_size - stroff > SIZE_T_MAX) {
6654371Sbostic 		errno = EFBIG;
6754371Sbostic 		return (-1);
6854371Sbostic 	}
6939649Sbostic 	/*
7053106Storek 	 * Map string table into our address space.  This gives us
7153106Storek 	 * an easy way to randomly access all the strings, without
7253106Storek 	 * making the memory allocation permanent as with malloc/free
7353106Storek 	 * (i.e., munmap will return it to the system).
7453106Storek 	 */
7554371Sbostic 	strsize = st.st_size - stroff;
7654371Sbostic 	strtab = mmap(NULL, (size_t)strsize, PROT_READ, 0, fd, stroff);
7753106Storek 	if (strtab == (char *)-1)
7853106Storek 		return (-1);
7953106Storek 	/*
8039649Sbostic 	 * clean out any left-over information for all valid entries.
8139649Sbostic 	 * Type and value defined to be 0 if not found; historical
8239649Sbostic 	 * versions cleared other and desc as well.  Also figure out
8339649Sbostic 	 * the largest string length so don't read any more of the
8439649Sbostic 	 * string table than we have to.
8553106Storek 	 *
8653106Storek 	 * XXX clearing anything other than n_type and n_value violates
8753106Storek 	 * the semantics given in the man page.
8839649Sbostic 	 */
8953106Storek 	nent = 0;
9053106Storek 	for (p = list; !ISLAST(p); ++p) {
9139649Sbostic 		p->n_type = 0;
9239649Sbostic 		p->n_other = 0;
9339649Sbostic 		p->n_desc = 0;
9439649Sbostic 		p->n_value = 0;
9553106Storek 		++nent;
961972Swnj 	}
9753106Storek 	if (lseek(fd, symoff, SEEK_SET) == -1)
9853106Storek 		return (-1);
991972Swnj 
10053106Storek 	while (symsize > 0) {
10153106Storek 		cc = MIN(symsize, sizeof(nbuf));
10253106Storek 		if (read(fd, nbuf, cc) != cc)
10353106Storek 			break;
10453106Storek 		symsize -= cc;
10553106Storek 		for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) {
10653106Storek 			register int soff = s->n_un.n_strx;
10753106Storek 
10853106Storek 			if (soff == 0 || (s->n_type & N_STAB) != 0)
10953106Storek 				continue;
11053106Storek 			for (p = list; !ISLAST(p); p++)
11153106Storek 				if (!strcmp(&strtab[soff], p->n_un.n_name)) {
11253106Storek 					p->n_value = s->n_value;
11353106Storek 					p->n_type = s->n_type;
11453106Storek 					p->n_desc = s->n_desc;
11553106Storek 					p->n_other = s->n_other;
11653106Storek 					if (--nent <= 0)
11753106Storek 						break;
11853106Storek 				}
11953106Storek 		}
1201972Swnj 	}
12153106Storek 	munmap(strtab, strsize);
12253106Storek 	return (nent);
1231972Swnj }
124