symorder(1): Fix for missing prototypes.
[dragonfly.git] / usr.bin / symorder / symorder.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1980 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * @(#) Copyright (c) 1980 The Regents of the University of California. All rights reserved.
34 * @(#)symorder.c 5.8 (Berkeley) 4/1/91
35 * $FreeBSD: src/usr.bin/symorder/symorder.c,v 1.15 1999/08/28 01:05:57 peter Exp $
36 */
37
38/*
39 * symorder - reorder symbol table
40 */
41
42#include <sys/types.h>
43#include <sys/stat.h>
44#include <a.out.h>
45#include <ctype.h>
46#include <err.h>
47#include <errno.h>
48#include <fcntl.h>
49#include <stdio.h>
50#include <stdlib.h>
51#include <string.h>
52#include <unistd.h>
53#include <netinet/in.h>
54
55#define SPACE 500
56
57#define OKEXIT 0
58#define NOTFOUNDEXIT 1
59#define ERREXIT 2
60
61char *exclude[SPACE];
62struct nlist order[SPACE];
63
64struct exec exec;
65struct stat stb;
66struct nlist *newtab, *symtab;
67off_t sa;
68int nexclude, nsym, strtabsize, symfound, symkept, small, missing, clean;
69char *kfile, *newstrings, *strings, asym[BUFSIZ];
70
71void badfmt(char *);
72int excluded(struct nlist *);
73int inlist(struct nlist *);
74void reorder(struct nlist *, struct nlist *, int);
75int savesymb(struct nlist *);
76static void usage(void);
77
78int
79main(int argc, char **argv)
80{
81 struct nlist *p, *symp;
82 FILE *f, *xfile;
83 int i;
84 char *start, *t, *xfilename;
85 int ch, n, o;
86
87 xfilename = NULL;
88 while ((ch = getopt(argc, argv, "cmtx:")) != -1)
89 switch(ch) {
90 case 'c':
91 clean = 1;
92 break;
93 case 'm':
94 missing = 1;
95 break;
96 case 't':
97 small = 1;
98 break;
99 case 'x':
100 if (xfilename != NULL)
101 usage();
102 xfilename = optarg;
103 break;
104 case '?':
105 default:
106 usage();
107 }
108 argc -= optind;
109 argv += optind;
110
111 if (argc != 2)
112 usage();
113
114 if ((f = fopen(argv[0], "r")) == NULL)
115 err(ERREXIT, "%s", argv[0]);
116
117 for (p = order; fgets(asym, sizeof(asym), f) != NULL;) {
118 for (t = asym; isspace(*t); ++t);
119 if (!*(start = t))
120 continue;
121 while (*++t);
122 if (*--t == '\n')
123 *t = '\0';
124 p->n_un.n_name = strdup(start);
125 ++p;
126 if (++nsym >= sizeof order / sizeof order[0])
127 break;
128 }
129 (void)fclose(f);
130
131 if (xfilename != NULL) {
132 if ((xfile = fopen(xfilename, "r")) == NULL)
133 err(ERREXIT, "%s", xfilename);
134 for (; fgets(asym, sizeof(asym), xfile) != NULL;) {
135 for (t = asym; isspace(*t); ++t);
136 if (!*(start = t))
137 continue;
138 while (*++t);
139 if (*--t == '\n')
140 *t = '\0';
141 exclude[nexclude] = strdup(start);
142 if (++nexclude >= sizeof exclude / sizeof exclude[0])
143 break;
144 }
145 (void)fclose(xfile);
146 }
147
148 kfile = argv[1];
149 if ((f = fopen(kfile, "r")) == NULL)
150 err(ERREXIT, "%s", kfile);
151 if ((o = open(kfile, O_WRONLY)) < 0)
152 err(ERREXIT, "%s", kfile);
153
154 /* read exec header */
155 if ((fread(&exec, sizeof(exec), 1, f)) != 1)
156 badfmt("no exec header");
157 if (N_BADMAG(exec))
158 badfmt("bad magic number");
159 if (exec.a_syms == 0)
160 badfmt("stripped");
161 (void)fstat(fileno(f), &stb);
162 if (stb.st_size < N_STROFF(exec) + sizeof(off_t))
163 badfmt("no string table");
164
165 /* seek to and read the symbol table */
166 sa = N_SYMOFF(exec);
167 (void)fseek(f, sa, SEEK_SET);
168 n = exec.a_syms;
169 if (!(symtab = (struct nlist *)malloc(n)))
170 err(ERREXIT, NULL);
171 if (fread((void *)symtab, 1, n, f) != n)
172 badfmt("corrupted symbol table");
173
174 /* read string table size and string table */
175 if (fread((void *)&strtabsize, sizeof(int), 1, f) != 1 ||
176 strtabsize <= 0)
177 badfmt("corrupted string table");
178 strings = malloc(strtabsize);
179 if (strings == NULL)
180 err(ERREXIT, NULL);
181 /*
182 * Subtract four from strtabsize since strtabsize includes itself,
183 * and we've already read it.
184 */
185 if (fread(strings, 1, strtabsize - sizeof(int), f) !=
186 strtabsize - sizeof(int))
187 badfmt("corrupted string table");
188
189 i = n / sizeof(struct nlist);
190 if (!clean) {
191 newtab = (struct nlist *)malloc(n);
192 if (newtab == NULL)
193 err(ERREXIT, NULL);
194 memset(newtab, 0, n);
195
196 reorder(symtab, newtab, i);
197 free((void *)symtab);
198 symtab = newtab;
199 } else {
200 symkept = i;
201 }
202
203 newstrings = malloc(strtabsize);
204 if (newstrings == NULL)
205 err(ERREXIT, NULL);
206 t = newstrings;
207 for (symp = symtab; --i >= 0; symp++) {
208 if (symp->n_un.n_strx == 0)
209 continue;
210 if (inlist(symp) < 0) {
211 if (small)
212 continue;
213 if (clean && !savesymb(symp))
214 symp->n_type &= ~N_EXT;
215 } else if (clean)
216 symfound++;
217 symp->n_un.n_strx -= sizeof(int);
218 (void)strcpy(t, &strings[symp->n_un.n_strx]);
219 symp->n_un.n_strx = (t - newstrings) + sizeof(int);
220 t += strlen(t) + 1;
221 }
222
223 /* update shrunk sizes */
224 strtabsize = t - newstrings + sizeof(int);
225 n = symkept * sizeof(struct nlist);
226
227 /* fix exec sym size */
228 (void)lseek(o, (off_t)0, SEEK_SET);
229 exec.a_syms = n;
230 if (write(o, (void *)&exec, sizeof(exec)) != sizeof(exec))
231 err(ERREXIT, "%s", kfile);
232
233 (void)lseek(o, sa, SEEK_SET);
234 if (write(o, (void *)symtab, n) != n)
235 err(ERREXIT, "%s", kfile);
236 if (write(o, (void *)&strtabsize, sizeof(int)) != sizeof(int))
237 err(ERREXIT, "%s", kfile);
238 if (write(o, newstrings, strtabsize - sizeof(int)) !=
239 strtabsize - sizeof(int))
240 err(ERREXIT, "%s", kfile);
241
242 ftruncate(o, lseek(o, (off_t)0, SEEK_CUR));
243
244 if ((i = nsym - symfound) > 0) {
245 (void)printf("symorder: %d symbol%s not found:\n",
246 i, i == 1 ? "" : "s");
247 for (i = 0; i < nsym; i++)
248 if (order[i].n_value == 0)
249 printf("%s\n", order[i].n_un.n_name);
250 if (!missing)
251 exit(NOTFOUNDEXIT);
252 }
253 exit(OKEXIT);
254}
255
256int
257savesymb(struct nlist *s)
258{
259 if ((s->n_type & N_EXT) != N_EXT)
260 return 0;
261 switch (s->n_type & N_TYPE) {
262 case N_TEXT:
263 case N_DATA:
264 return 0;
265 default:
266 return 1;
267 }
268}
269
270void
271reorder(struct nlist *st1, struct nlist *st2, int entries)
272{
273 struct nlist *p;
274 int i, n;
275
276 for (p = st1, n = entries; --n >= 0; ++p)
277 if (inlist(p) != -1)
278 ++symfound;
279 for (p = st2 + symfound, n = entries; --n >= 0; ++st1) {
280 if (excluded(st1))
281 continue;
282 i = inlist(st1);
283 if (i == -1)
284 *p++ = *st1;
285 else
286 st2[i] = *st1;
287 ++symkept;
288 }
289}
290
291int
292inlist(struct nlist *p)
293{
294 char *nam;
295 struct nlist *op;
296
297 if (p->n_type & N_STAB || p->n_un.n_strx == 0)
298 return (-1);
299 if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize)
300 badfmt("corrupted symbol table");
301 nam = &strings[p->n_un.n_strx - sizeof(int)];
302 for (op = &order[nsym]; --op >= order; ) {
303 if (strcmp(op->n_un.n_name, nam) != 0)
304 continue;
305 op->n_value = 1;
306 return (op - order);
307 }
308 return (-1);
309}
310
311int
312excluded(struct nlist *p)
313{
314 char *nam;
315 int x;
316
317 if (p->n_type & N_STAB || p->n_un.n_strx == 0)
318 return (0);
319 if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize)
320 badfmt("corrupted symbol table");
321 nam = &strings[p->n_un.n_strx - sizeof(int)];
322 for (x = nexclude; --x >= 0; )
323 if (strcmp(nam, exclude[x]) == 0)
324 return (1);
325 return (0);
326}
327
328void
329badfmt(char *why)
330{
331 errx(ERREXIT, "%s: %s: %s", kfile, why, strerror(EFTYPE));
332}
333
334static void
335usage(void)
336{
337 (void)fprintf(stderr,
338 "usage: symorder [-c] [-m] [-t] [-x excludelist] symlist file\n");
339 exit(ERREXIT);
340}