xref: /original-bsd/lib/libc/gen/nlist.c (revision c3e32dec)
1 /*
2  * Copyright (c) 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #if defined(LIBC_SCCS) && !defined(lint)
9 static char sccsid[] = "@(#)nlist.c	8.1 (Berkeley) 06/04/93";
10 #endif /* LIBC_SCCS and not lint */
11 
12 #include <sys/param.h>
13 #include <sys/mman.h>
14 #include <sys/stat.h>
15 #include <sys/file.h>
16 
17 #include <errno.h>
18 #include <a.out.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <unistd.h>
22 
23 int
24 nlist(name, list)
25 	const char *name;
26 	struct nlist *list;
27 {
28 	int fd, n;
29 
30 	fd = open(name, O_RDONLY, 0);
31 	if (fd < 0)
32 		return (-1);
33 	n = __fdnlist(fd, list);
34 	(void)close(fd);
35 	return (n);
36 }
37 
38 #define	ISLAST(p)	(p->n_un.n_name == 0 || p->n_un.n_name[0] == 0)
39 
40 int
41 __fdnlist(fd, list)
42 	register int fd;
43 	register struct nlist *list;
44 {
45 	register struct nlist *p, *s;
46 	register caddr_t strtab;
47 	register off_t stroff, symoff;
48 	register u_long symsize;
49 	register int nent, cc;
50 	size_t strsize;
51 	struct nlist nbuf[1024];
52 	struct exec exec;
53 	struct stat st;
54 
55 	if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
56 	    read(fd, &exec, sizeof(exec)) != sizeof(exec) ||
57 	    N_BADMAG(exec) || fstat(fd, &st) < 0)
58 		return (-1);
59 
60 	symoff = N_SYMOFF(exec);
61 	symsize = exec.a_syms;
62 	stroff = symoff + symsize;
63 
64 	/* Check for files too large to mmap. */
65 	if (st.st_size - stroff > SIZE_T_MAX) {
66 		errno = EFBIG;
67 		return (-1);
68 	}
69 	/*
70 	 * Map string table into our address space.  This gives us
71 	 * an easy way to randomly access all the strings, without
72 	 * making the memory allocation permanent as with malloc/free
73 	 * (i.e., munmap will return it to the system).
74 	 */
75 	strsize = st.st_size - stroff;
76 	strtab = mmap(NULL, (size_t)strsize, PROT_READ, 0, fd, stroff);
77 	if (strtab == (char *)-1)
78 		return (-1);
79 	/*
80 	 * clean out any left-over information for all valid entries.
81 	 * Type and value defined to be 0 if not found; historical
82 	 * versions cleared other and desc as well.  Also figure out
83 	 * the largest string length so don't read any more of the
84 	 * string table than we have to.
85 	 *
86 	 * XXX clearing anything other than n_type and n_value violates
87 	 * the semantics given in the man page.
88 	 */
89 	nent = 0;
90 	for (p = list; !ISLAST(p); ++p) {
91 		p->n_type = 0;
92 		p->n_other = 0;
93 		p->n_desc = 0;
94 		p->n_value = 0;
95 		++nent;
96 	}
97 	if (lseek(fd, symoff, SEEK_SET) == -1)
98 		return (-1);
99 
100 	while (symsize > 0) {
101 		cc = MIN(symsize, sizeof(nbuf));
102 		if (read(fd, nbuf, cc) != cc)
103 			break;
104 		symsize -= cc;
105 		for (s = nbuf; cc > 0; ++s, cc -= sizeof(*s)) {
106 			register int soff = s->n_un.n_strx;
107 
108 			if (soff == 0 || (s->n_type & N_STAB) != 0)
109 				continue;
110 			for (p = list; !ISLAST(p); p++)
111 				if (!strcmp(&strtab[soff], p->n_un.n_name)) {
112 					p->n_value = s->n_value;
113 					p->n_type = s->n_type;
114 					p->n_desc = s->n_desc;
115 					p->n_other = s->n_other;
116 					if (--nent <= 0)
117 						break;
118 				}
119 		}
120 	}
121 	munmap(strtab, strsize);
122 	return (nent);
123 }
124