1/*
2 * Copyright 1987 Sun Microsystems, Inc.  All rights reserved.
3 * Use is subject to license terms.
4 */
5
6/*
7 * Copyright (c) 1980 Regents of the University of California.
8 * All rights reserved.  The Berkeley software License Agreement
9 * specifies the terms and conditions for redistribution.
10 */
11
12#pragma ident	"%Z%%M%	%I%	%E% SMI"
13
14#include <sys/types.h>
15#include <sys/param.h>
16#include <a.out.h>
17
18#define BSIZ 8*1024	/* size of local buffers */
19
20/*
21 * _nlist - retreive attributes from name list (string table version)
22 *
23 * Note: This is a modified form of the original nlist() function.
24 *       It takes a file descriptor instead of a filename argument
25 *       and is intended to be called by nlist(3) and kvmnlist(3K).
26 *       The algorithm has been modified from the original to use local
27 *       (rather than stdio) buffering and issues considerably fewer lseeks.
28 */
29int
30_nlist(int fd, struct nlist *list)
31{
32	struct nlist *p, *q;
33	char *s1, *s2;
34	int soff;
35	int stroff = 0;
36	int n, m;
37	int maxlen, nreq;
38	long sa;		/* symbol address */
39	long ss;		/* start of strings */
40	struct exec buf;
41	struct nlist space[BSIZ/sizeof (struct nlist)];
42	char strs[BSIZ];
43
44	maxlen = 0;
45	for (q = list, nreq = 0; q->n_un.n_name && q->n_un.n_name[0];
46	    q++, nreq++) {
47		q->n_type = 0;
48		q->n_value = 0;
49		q->n_desc = 0;
50		q->n_other = 0;
51		n = strlen(q->n_un.n_name);
52		if (n > maxlen)
53			maxlen = n;
54	}
55	if ((fd == -1) || (lseek(fd, 0L, 0) == -1) ||
56	    (read(fd, (char*)&buf, sizeof buf) != sizeof buf) || N_BADMAG(buf))
57		return (-1);
58	sa = N_SYMOFF(buf);
59	ss = sa + buf.a_syms;
60	n = buf.a_syms;
61	while (n) {
62		m = MIN(n, sizeof (space));
63		lseek(fd, sa, 0);
64		if (read(fd, (char *)space, m) != m)
65			break;
66		sa += m;
67		n -= m;
68		for (q = space; (m -= sizeof (struct nlist)) >= 0; q++) {
69			soff = q->n_un.n_strx;
70			if (soff == 0 || q->n_type & N_STAB)
71				continue;
72			if ((soff + maxlen + 1) >= stroff) {
73				/*
74				 * Read strings into local cache.
75				 * Assumes (maxlen < sizeof (strs)).
76				 */
77				lseek(fd, ss+soff, 0);
78				read(fd, strs, sizeof strs);
79				stroff = soff + sizeof (strs);
80			}
81			for (p = list;
82			     p->n_un.n_name && p->n_un.n_name[0];
83			     p++) {
84				if (p->n_type != 0)
85					continue;
86				s1 = p->n_un.n_name;
87				s2 = &strs[soff-(stroff-sizeof (strs))];
88				while (*s1) {
89					if (*s1++ != *s2++)
90						goto cont;
91				}
92				if (*s2)
93					goto cont;
94				p->n_value = q->n_value;
95				p->n_type = q->n_type;
96				p->n_desc = q->n_desc;
97				p->n_other = q->n_other;
98				if (--nreq == 0)
99					goto alldone;
100				break;
101cont:				;
102			}
103		}
104	}
105alldone:
106	return (nreq);
107}
108