1/* $NetBSD: nlist_aout.c,v 1.8 2003/08/07 11:25:23 agc Exp $ */
2
3/*-
4 * Copyright (c) 1990, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32/*-
33 * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
34 *
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 *    notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 *    notice, this list of conditions and the following disclaimer in the
42 *    documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 *    must display the following acknowledgement:
45 *	This product includes software developed by the University of
46 *	California, Berkeley and its contributors.
47 * 4. Neither the name of the University nor the names of its contributors
48 *    may be used to endorse or promote products derived from this software
49 *    without specific prior written permission.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 */
63
64#include <sys/cdefs.h>
65#ifndef lint
66#if 0
67static char sccsid[] = "from: @(#)nlist.c	8.1 (Berkeley) 6/6/93";
68#else
69__RCSID("$NetBSD: nlist_aout.c,v 1.8 2003/08/07 11:25:23 agc Exp $");
70#endif
71#endif /* not lint */
72
73#include <sys/param.h>
74
75#include <a.out.h>
76#include <db.h>
77#include <err.h>
78#include <errno.h>
79#include <fcntl.h>
80#include <kvm.h>
81#include <limits.h>
82#include <stdio.h>
83#include <stdlib.h>
84#include <string.h>
85#include <unistd.h>
86
87#include "extern.h"
88
89#ifdef NLIST_AOUT
90
91typedef struct nlist NLIST;
92#define	_strx	n_un.n_strx
93#define	_name	n_un.n_name
94
95#define	badfmt(str)							\
96	do {								\
97		warnx("%s: %s: %s", kfile, str, strerror(EFTYPE));	\
98		punt();							\
99	} while (0)
100
101static void	badread __P((int, char *));
102static u_long	get_kerntext __P((const char *kfn));
103
104static const char *kfile;
105
106int
107create_knlist_aout(name, db)
108	const char *name;
109	DB *db;
110{
111	int nsyms;
112	struct exec ebuf;
113	FILE *fp;
114	NLIST nbuf;
115	DBT data, key;
116	int fd, nr, strsize;
117	u_long kerntextoff;
118	char *strtab, buf[1024];
119
120	kfile = name;
121	if ((fd = open(name, O_RDONLY, 0)) < 0) {
122		warn("%s", kfile);
123		punt();
124	}
125
126	/* Read in exec structure. */
127	nr = read(fd, &ebuf, sizeof(struct exec));
128	if (nr != sizeof(struct exec)) {
129		(void)close(fd);
130		return (-1);
131	}
132
133	/* Check magic number. */
134	if (N_BADMAG(ebuf)) {
135		(void)close(fd);
136		return (-1);
137	}
138
139	/*
140	 * We've recognized it as an a.out binary.  From here
141	 * on out, all errors are fatal.
142	 */
143
144	/* Check symbol count. */
145	if (!ebuf.a_syms)
146		badfmt("stripped");
147
148	/* Seek to string table. */
149	if (lseek(fd, N_STROFF(ebuf), SEEK_SET) == -1)
150		badfmt("corrupted string table");
151
152	/* Read in the size of the symbol table. */
153	nr = read(fd, (char *)&strsize, sizeof(strsize));
154	if (nr != sizeof(strsize))
155		badread(nr, "no symbol table");
156
157	/* Read in the string table. */
158	strsize -= sizeof(strsize);
159	if (!(strtab = malloc(strsize))) {
160		warn("malloc");
161		punt();
162	}
163	if ((nr = read(fd, strtab, strsize)) != strsize)
164		badread(nr, "corrupted symbol table");
165
166	/* Seek to symbol table. */
167	if (!(fp = fdopen(fd, "r"))) {
168		warn("%s", name);
169		punt();
170	}
171	if (fseek(fp, N_SYMOFF(ebuf), SEEK_SET) == -1) {
172		warn("%s", name);
173		punt();
174	}
175
176	data.data = (u_char *)&nbuf;
177	data.size = sizeof(NLIST);
178
179	kerntextoff = get_kerntext(name);
180
181	/* Read each symbol and enter it into the database. */
182	nsyms = ebuf.a_syms / sizeof(struct nlist);
183	while (nsyms--) {
184		if (fread((char *)&nbuf, sizeof (NLIST), 1, fp) != 1) {
185			if (feof(fp))
186				badfmt("corrupted symbol table");
187			warn("%s", name);
188			punt();
189		}
190		if (!nbuf._strx || nbuf.n_type&N_STAB)
191			continue;
192
193		key.data = (u_char *)strtab + nbuf._strx - sizeof(long);
194		key.size = strlen((char *)key.data);
195		if (db->put(db, &key, &data, 0)) {
196			warn("record enter");
197			punt();
198		}
199
200		if (strcmp((char *)key.data, VRS_SYM) == 0) {
201			long cur_off, voff;
202			/*
203			 * Calculate offset relative to a normal (non-kernel)
204			 * a.out.  Kerntextoff is where the kernel is really
205			 * loaded; N_TXTADDR is where a normal file is loaded.
206			 * From there, locate file offset in text or data.
207			 */
208			voff = nbuf.n_value - kerntextoff + N_TXTADDR(ebuf);
209			if ((nbuf.n_type & N_TYPE) == N_TEXT)
210				voff += N_TXTOFF(ebuf) - N_TXTADDR(ebuf);
211			else
212				voff += N_DATOFF(ebuf) - N_DATADDR(ebuf);
213			cur_off = ftell(fp);
214			if (fseek(fp, voff, SEEK_SET) == -1)
215				badfmt("corrupted string table");
216
217			/*
218			 * Read version string up to, and including newline.
219			 * This code assumes that a newline terminates the
220			 * version line.
221			 */
222			if (fgets(buf, sizeof(buf), fp) == NULL)
223				badfmt("corrupted string table");
224
225			key.data = (u_char *)VRS_KEY;
226			key.size = sizeof(VRS_KEY) - 1;
227			data.data = (u_char *)buf;
228			data.size = strlen(buf);
229			if (db->put(db, &key, &data, 0)) {
230				warn("record enter");
231				punt();
232			}
233
234			/* Restore to original values. */
235			data.data = (u_char *)&nbuf;
236			data.size = sizeof(NLIST);
237			if (fseek(fp, cur_off, SEEK_SET) == -1)
238				badfmt("corrupted string table");
239		}
240	}
241	(void)fclose(fp);
242
243	return (0);
244}
245
246static void
247badread(nr, p)
248	int nr;
249	char *p;
250{
251	if (nr < 0) {
252		warn("%s", kfile);
253		punt();
254	}
255	badfmt(p);
256}
257
258/*
259 * Instead of compiling in KERNTEXTOFF or KERNBASE, try to
260 * determine the text start address from a standard symbol.
261 * For backward compatibility, use the old compiled-in way
262 * when the standard symbol name is not found.
263 */
264static u_long
265get_kerntext(name)
266	const char *name;
267{
268	struct nlist nl[2];
269
270	memset((caddr_t)nl, 0, sizeof(nl));
271	nl[0].n_un.n_name = "_kernel_text";
272
273	if (nlist(name, nl) != 0) {
274		warnx("%s: %s symbol missing",
275		    name, nl[0].n_un.n_name);
276		punt();
277	}
278
279	return (nl[0].n_value);
280}
281#endif /* NLIST_AOUT */
282