nlist_ecoff.c revision 1.6 1 /* $NetBSD: nlist_ecoff.c,v 1.6 2000/06/14 06:49:25 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 #include <sys/cdefs.h>
34 #ifndef lint
35 __RCSID("$NetBSD: nlist_ecoff.c,v 1.6 2000/06/14 06:49:25 cgd Exp $");
36 #endif /* not lint */
37
38 #include <sys/param.h>
39 #include <sys/mman.h>
40 #include <sys/stat.h>
41
42 #include <a.out.h>
43 #include <db.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <fcntl.h>
47 #include <kvm.h>
48 #include <limits.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53
54 #include "extern.h"
55
56 #ifdef NLIST_ECOFF
57 #include <sys/exec_ecoff.h>
58
59 typedef struct nlist NLIST;
60 #define _strx n_un.n_strx
61 #define _name n_un.n_name
62
63 #define badfmt(str) \
64 do { \
65 warnx("%s: %s: %s", kfile, str, strerror(EFTYPE)); \
66 punt(); \
67 } while (0)
68
69 #define check(off, size) ((off < 0) || (off + size > mappedsize))
70 #define BAD do { rv = -1; goto out; } while (0)
71 #define BADUNMAP do { rv = -1; goto unmap; } while (0)
72
73 static const char *kfile;
74
75 int
76 create_knlist_ecoff(name, db)
77 const char *name;
78 DB *db;
79 {
80 struct ecoff_exechdr *exechdrp;
81 struct ecoff_symhdr *symhdrp;
82 struct ecoff_extsym *esyms;
83 struct stat st;
84 struct nlist nbuf;
85 DBT key, data;
86 char *mappedfile, *symname, *fsymname, *tmpcp;
87 size_t mappedsize, symnamesize, fsymnamesize;
88 u_long symhdroff, extrstroff;
89 u_long symhdrsize, i, nesyms;
90 int fd, rv;
91
92 rv = -1;
93
94 /*
95 * Open and map the whole file. If we can't open/stat it,
96 * something bad is going on so we punt.
97 */
98 kfile = name;
99 if ((fd = open(name, O_RDONLY, 0)) < 0) {
100 warn("%s", kfile);
101 punt();
102 }
103 if (fstat(fd, &st) < 0) {
104 warn("%s", kfile);
105 punt();
106 }
107 if (st.st_size > SIZE_T_MAX)
108 BAD;
109
110 /*
111 * Map the file in its entirety.
112 */
113 mappedsize = st.st_size;
114 mappedfile = mmap(NULL, mappedsize, PROT_READ, MAP_FILE|MAP_PRIVATE,
115 fd, 0);
116 if (mappedfile == (char *)-1)
117 BAD;
118
119 /*
120 * Make sure we can access the executable's header
121 * directly, and make sure the recognize the executable
122 * as an ECOFF binary.
123 */
124 if (check(0, sizeof *exechdrp))
125 BADUNMAP;
126 exechdrp = (struct ecoff_exechdr *)&mappedfile[0];
127
128 if (ECOFF_BADMAG(exechdrp))
129 BADUNMAP;
130
131 /*
132 * We've recognized it as an ECOFF binary. From here
133 * on out, all errors are fatal.
134 */
135
136 /*
137 * Find the symbol list and string table.
138 */
139 symhdroff = exechdrp->f.f_symptr;
140 symhdrsize = exechdrp->f.f_nsyms;
141
142 if (symhdrsize == 0)
143 badfmt("stripped");
144 if (check(symhdroff, sizeof *symhdrp) || sizeof *symhdrp != symhdrsize)
145 badfmt("bogus symbol table");
146 symhdrp = (struct ecoff_symhdr *)&mappedfile[symhdroff];
147
148 nesyms = symhdrp->esymMax;
149 if (check(symhdrp->cbExtOffset, nesyms * sizeof *esyms))
150 badfmt("bogus external symbol list");
151 esyms = (struct ecoff_extsym *)&mappedfile[symhdrp->cbExtOffset];
152 extrstroff = symhdrp->cbSsExtOffset;
153
154 /*
155 * Set up the data item, pointing to a nlist structure.
156 * which we fill in for each symbol.
157 */
158 data.data = (u_char *)&nbuf;
159 data.size = sizeof(nbuf);
160
161 /*
162 * Create a buffer (to be expanded later, if necessary)
163 * to hold symbol names after we've added underscores
164 * to them.
165 */
166 symnamesize = 1024;
167 if ((symname = malloc(symnamesize)) == NULL) {
168 warn("malloc");
169 punt();
170 }
171
172 /*
173 * Read each symbol and enter it into the database.
174 */
175 for (i = 0; i < nesyms; i++) {
176
177 /*
178 * Find symbol name, copy it (with added underscore) to
179 * temporary buffer, and prepare the database key for
180 * insertion.
181 */
182 fsymname = &mappedfile[extrstroff + esyms[i].es_strindex];
183 fsymnamesize = strlen(fsymname) + 1;
184 while (symnamesize < fsymnamesize + 1) {
185 symnamesize *= 2;
186 if ((symname = realloc(symname, symnamesize)) == NULL) {
187 warn("malloc");
188 punt();
189 }
190 }
191 strcpy(symname, "_");
192 strcat(symname, fsymname);
193
194 key.data = symname;
195 key.size = strlen((char *)key.data);
196
197 /*
198 * Convert the symbol information into an nlist structure,
199 * as best we can.
200 */
201 nbuf.n_value = esyms[i].es_value;
202 nbuf.n_type = N_EXT; /* XXX */
203 nbuf.n_desc = 0; /* XXX */
204 nbuf.n_other = 0; /* XXX */
205
206 /*
207 * Enter the symbol into the database.
208 */
209 if (db->put(db, &key, &data, 0)) {
210 warn("record enter");
211 punt();
212 }
213
214 /*
215 * If it's the kernel version string, we've gotta keep
216 * some extra data around. Under a seperate key,
217 * we enter the first line (i.e. up to the first newline,
218 * with the newline replaced by a NUL to terminate the
219 * entered string) of the version string.
220 */
221 if (strcmp((char *)key.data, VRS_SYM) == 0) {
222 unsigned long vma;
223
224 key.data = (u_char *)VRS_KEY;
225 key.size = sizeof(VRS_KEY) - 1;
226
227 /* Find the version string, relative to start */
228 vma = nbuf.n_value;
229 if (exechdrp->a.text_start <= vma &&
230 vma < (exechdrp->a.text_start + exechdrp->a.tsize))
231 vma = vma - exechdrp->a.text_start +
232 ECOFF_TXTOFF(exechdrp);
233 else if (exechdrp->a.data_start <= vma &&
234 vma < (exechdrp->a.data_start + exechdrp->a.dsize))
235 vma = vma - exechdrp->a.data_start +
236 ECOFF_DATOFF(exechdrp);
237 else {
238 warn("version string neither text nor data");
239 punt();
240 }
241 data.data = strdup(&mappedfile[vma]);
242
243 /* assumes newline terminates version. */
244 if ((tmpcp = strchr(data.data, '\n')) != NULL)
245 *tmpcp = '\0';
246 data.size = strlen((char *)data.data);
247
248 if (db->put(db, &key, &data, 0)) {
249 warn("record enter");
250 punt();
251 }
252
253 /* free pointer created by strdup(). */
254 free(data.data);
255
256 /* Restore to original values */
257 data.data = (u_char *)&nbuf;
258 data.size = sizeof(nbuf);
259 }
260 }
261
262 rv = 0;
263
264 unmap:
265 munmap(mappedfile, mappedsize);
266 out:
267 return (rv);
268 }
269
270 #endif /* NLIST_ECOFF */
271