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