xref: /netbsd-src/usr.sbin/kvm_mkdb/nlist_ecoff.c (revision 76dfffe33547c37f8bdd446e3e4ab0f3c16cea4b)
1 /*	$NetBSD: nlist_ecoff.c,v 1.3 1996/10/03 23:14:23 cgd Exp $	*/
2 
3 /*
4  * Copyright (c) 1996 Christopher G. Demetriou.  All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *      This product includes software developed by Christopher G. Demetriou
17  *	for the NetBSD Project.
18  * 4. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #ifndef lint
34 static char *rcsid = "$NetBSD: nlist_ecoff.c,v 1.3 1996/10/03 23:14:23 cgd Exp $";
35 #endif /* not lint */
36 
37 #include <sys/param.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 
41 #include <a.out.h>
42 #include <db.h>
43 #include <err.h>
44 #include <errno.h>
45 #include <fcntl.h>
46 #include <kvm.h>
47 #include <limits.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <unistd.h>
52 
53 #include "extern.h"
54 
55 #ifdef NLIST_ECOFF
56 #include <sys/exec_ecoff.h>
57 
58 typedef struct nlist NLIST;
59 #define	_strx	n_un.n_strx
60 #define	_name	n_un.n_name
61 
62 #define	badfmt(str)							\
63 	do {								\
64 		warnx("%s: %s: %s", kfile, str, strerror(EFTYPE));	\
65 		punt();							\
66 	} while (0)
67 
68 #define	check(off, size)	((off < 0) || (off + size > mappedsize))
69 #define	BAD			do { rv = -1; goto out; } while (0)
70 #define	BADUNMAP		do { rv = -1; goto unmap; } while (0)
71 
72 static const char *kfile;
73 
74 int
75 create_knlist_ecoff(name, db)
76 	const char *name;
77 	DB *db;
78 {
79 	struct ecoff_exechdr *exechdrp;
80 	struct ecoff_symhdr *symhdrp;
81 	struct ecoff_extsym *esyms;
82 	struct stat st;
83 	struct nlist nbuf;
84 	DBT key, data;
85 	char *mappedfile, *symname, *fsymname, *tmpcp;
86 	size_t mappedsize, symnamesize, fsymnamesize;
87 	u_long symhdroff, extrstroff;
88 	u_long symhdrsize, i, nesyms;
89 	int fd, rv;
90 
91 	rv = -1;
92 
93 	/*
94 	 * Open and map the whole file.  If we can't open/stat it,
95 	 * something bad is going on so we punt.
96 	 */
97 	kfile = name;
98 	if ((fd = open(name, O_RDONLY, 0)) < 0) {
99 		warn("%s", kfile);
100 		punt();
101 	}
102 	if (fstat(fd, &st) < 0) {
103 		warn("%s", kfile);
104 		punt();
105 	}
106 	if (st.st_size > SIZE_T_MAX)
107 		BAD;
108 
109 	/*
110 	 * Map the file in its entirety.
111 	 */
112 	mappedsize = st.st_size;
113 	mappedfile = mmap(NULL, mappedsize, PROT_READ, 0, fd, 0);
114 	if (mappedfile == (char *)-1)
115 		BAD;
116 
117 	/*
118 	 * Make sure we can access the executable's header
119 	 * directly, and make sure the recognize the executable
120 	 * as an ECOFF binary.
121 	 */
122 	if (check(0, sizeof *exechdrp))
123 		BADUNMAP;
124 	exechdrp = (struct ecoff_exechdr *)&mappedfile[0];
125 
126 	if (ECOFF_BADMAG(exechdrp))
127 		BADUNMAP;
128 
129 	/*
130 	 * We've recognized it as an ECOFF binary.  From here
131 	 * on out, all errors are fatal.
132 	 */
133 
134 	/*
135 	 * Find the symbol list and string table.
136 	 */
137 	symhdroff = exechdrp->f.f_symptr;
138 	symhdrsize = exechdrp->f.f_nsyms;
139 
140 	if (symhdrsize == 0)
141 		badfmt("stripped");
142 	if (check(symhdroff, sizeof *symhdrp) || sizeof *symhdrp != symhdrsize)
143 		badfmt("bogus symbol table");
144 	symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff];
145 
146 	nesyms = symhdrp->esymMax;
147 	if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms))
148 		badfmt("bogus external symbol list");
149 	esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset];
150 	extrstroff = symhdrp->cbSsExtOffset;
151 
152 	/*
153 	 * Set up the data item, pointing to a nlist structure.
154 	 * which we fill in for each symbol.
155 	 */
156 	data.data = (u_char *)&nbuf;
157 	data.size = sizeof(nbuf);
158 
159 	/*
160 	 * Create a buffer (to be expanded later, if necessary)
161 	 * to hold symbol names after we've added underscores
162 	 * to them.
163 	 */
164 	symnamesize = 1024;
165 	if ((symname = malloc(symnamesize)) == NULL) {
166 		warn("malloc");
167 		punt();
168 	}
169 
170 	/*
171 	 * Read each symbol and enter it into the database.
172 	 */
173 	for (i = 0; i < nesyms; i++) {
174 
175 		/*
176 		 * Find symbol name, copy it (with added underscore) to
177 		 * temporary buffer, and prepare the database key for
178 		 * insertion.
179 		 */
180 		fsymname = &mappedfile[extrstroff + esyms[i].es_strindex];
181 		fsymnamesize = strlen(fsymname) + 1;
182 		while (symnamesize < fsymnamesize + 1) {
183 			symnamesize *= 2;
184 			if ((symname = realloc(symname, symnamesize)) == NULL) {
185 				warn("malloc");
186 				punt();
187 			}
188 		}
189 		strcpy(symname, "_");
190 		strcat(symname, fsymname);
191 
192 		key.data = symname;
193 		key.size = strlen((char *)key.data);
194 
195 		/*
196 		 * Convert the symbol information into an nlist structure,
197 		 * as best we can.
198 		 */
199 		nbuf.n_value = esyms[i].es_value;
200 		nbuf.n_type = N_EXT;				/* XXX */
201 		nbuf.n_desc = 0;				/* XXX */
202 		nbuf.n_other = 0;				/* XXX */
203 
204 		/*
205 		 * Enter the symbol into the database.
206 		 */
207 		if (db->put(db, &key, &data, 0)) {
208 			warn("record enter");
209 			punt();
210 		}
211 
212 		/*
213 		 * If it's the kernel version string, we've gotta keep
214 		 * some extra data around.  Under a seperate key,
215 		 * we enter the first line (i.e. up to the first newline,
216 		 * with the newline replaced by a NUL to terminate the
217 		 * entered string) of the version string.
218 		 */
219 		if (strcmp((char *)key.data, VRS_SYM) == 0) {
220 			unsigned long vma;
221 
222 			key.data = (u_char *)VRS_KEY;
223 			key.size = sizeof(VRS_KEY) - 1;
224 
225 			/* Find the version string, relative to start */
226 			vma = nbuf.n_value;
227 			if (exechdrp->a.text_start <= vma &&
228 		            vma < (exechdrp->a.text_start + exechdrp->a.tsize))
229                 		vma = vma - exechdrp->a.text_start +
230 				    ECOFF_TXTOFF(exechdrp);
231 			else if (exechdrp->a.data_start <= vma &&
232 			    vma < (exechdrp->a.data_start + exechdrp->a.dsize))
233 				vma = vma - exechdrp->a.data_start +
234 				    ECOFF_DATOFF(exechdrp);
235 			else {
236 				warn("version string neither text nor data");
237 				punt();
238 			}
239 			data.data = strdup(&mappedfile[vma]);
240 
241 			/* assumes newline terminates version. */
242 			if ((tmpcp = strchr(data.data, '\n')) != NULL)
243 				*tmpcp = '\0';
244 			data.size = strlen((char *)data.data);
245 
246 			if (db->put(db, &key, &data, 0)) {
247 				warn("record enter");
248 				punt();
249 			}
250 
251 			/* free pointer created by strdup(). */
252 			free(data.data);
253 
254 			/* Restore to original values */
255 			data.data = (u_char *)&nbuf;
256 			data.size = sizeof(nbuf);
257 		}
258 	}
259 
260 	rv = 0;
261 
262 unmap:
263 	munmap(mappedfile, mappedsize);
264 out:
265 	return (rv);
266 }
267 
268 #endif /* NLIST_ECOFF */
269