Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / usr.bin / symorder / symorder.c
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  * $DragonFly: src/usr.bin/symorder/symorder.c,v 1.2 2003/06/17 04:29:32 dillon Exp $
37  */
38
39 /*
40  * symorder - reorder symbol table
41  */
42
43 #include <sys/types.h>
44 #include <sys/stat.h>
45 #include <a.out.h>
46 #include <ctype.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <string.h>
53 #include <unistd.h>
54
55 #define SPACE           500
56
57 #define OKEXIT          0
58 #define NOTFOUNDEXIT    1
59 #define ERREXIT         2
60
61 char    *exclude[SPACE];
62 struct  nlist order[SPACE];
63
64 struct  exec exec;
65 struct  stat stb;
66 struct  nlist *newtab, *symtab;
67 off_t   sa;
68 int     nexclude, nsym, strtabsize, symfound, symkept, small, missing, clean;
69 char    *kfile, *newstrings, *strings, asym[BUFSIZ];
70
71 void badfmt __P((char *));
72 int excluded __P((struct nlist *));
73 int inlist __P((struct nlist *));
74 void reorder __P((struct nlist *, struct nlist *, int));
75 int savesymb __P((struct nlist *));
76 static void usage __P((void));
77
78 int
79 main(argc, argv)
80         int argc;
81         char **argv;
82 {
83         register struct nlist *p, *symp;
84         register FILE *f, *xfile;
85         register int i;
86         register char *start, *t, *xfilename;
87         int ch, n, o;
88
89         xfilename = NULL;
90         while ((ch = getopt(argc, argv, "cmtx:")) != -1)
91                 switch(ch) {
92                 case 'c':
93                         clean = 1;
94                         break;
95                 case 'm':
96                         missing = 1;
97                         break;
98                 case 't':
99                         small = 1;
100                         break;
101                 case 'x':
102                         if (xfilename != NULL)
103                                 usage();
104                         xfilename = optarg;
105                         break;
106                 case '?':
107                 default:
108                         usage();
109                 }
110         argc -= optind;
111         argv += optind;
112
113         if (argc != 2)
114                 usage();
115
116         if ((f = fopen(argv[0], "r")) == NULL)
117                 err(ERREXIT, "%s", argv[0]);
118
119         for (p = order; fgets(asym, sizeof(asym), f) != NULL;) {
120                 for (t = asym; isspace(*t); ++t);
121                 if (!*(start = t))
122                         continue;
123                 while (*++t);
124                 if (*--t == '\n')
125                         *t = '\0';
126                 p->n_un.n_name = strdup(start);
127                 ++p;
128                 if (++nsym >= sizeof order / sizeof order[0])
129                         break;
130         }
131         (void)fclose(f);
132
133         if (xfilename != NULL) {
134                 if ((xfile = fopen(xfilename, "r")) == NULL)
135                         err(ERREXIT, "%s", xfilename);
136                 for (; fgets(asym, sizeof(asym), xfile) != NULL;) {
137                         for (t = asym; isspace(*t); ++t);
138                         if (!*(start = t))
139                                 continue;
140                         while (*++t);
141                         if (*--t == '\n')
142                                 *t = '\0';
143                         exclude[nexclude] = strdup(start);
144                         if (++nexclude >= sizeof exclude / sizeof exclude[0])
145                                 break;
146                 }
147                 (void)fclose(xfile);
148         }
149
150         kfile = argv[1];
151         if ((f = fopen(kfile, "r")) == NULL)
152                 err(ERREXIT, "%s", kfile);
153         if ((o = open(kfile, O_WRONLY)) < 0)
154                 err(ERREXIT, "%s", kfile);
155
156         /* read exec header */
157         if ((fread(&exec, sizeof(exec), 1, f)) != 1)
158                 badfmt("no exec header");
159         if (N_BADMAG(exec))
160                 badfmt("bad magic number");
161         if (exec.a_syms == 0)
162                 badfmt("stripped");
163         (void)fstat(fileno(f), &stb);
164         if (stb.st_size < N_STROFF(exec) + sizeof(off_t))
165                 badfmt("no string table");
166
167         /* seek to and read the symbol table */
168         sa = N_SYMOFF(exec);
169         (void)fseek(f, sa, SEEK_SET);
170         n = exec.a_syms;
171         if (!(symtab = (struct nlist *)malloc(n)))
172                 err(ERREXIT, NULL);
173         if (fread((void *)symtab, 1, n, f) != n)
174                 badfmt("corrupted symbol table");
175
176         /* read string table size and string table */
177         if (fread((void *)&strtabsize, sizeof(int), 1, f) != 1 ||
178             strtabsize <= 0)
179                 badfmt("corrupted string table");
180         strings = malloc(strtabsize);
181         if (strings == NULL)
182                 err(ERREXIT, NULL);
183         /*
184          * Subtract four from strtabsize since strtabsize includes itself,
185          * and we've already read it.
186          */
187         if (fread(strings, 1, strtabsize - sizeof(int), f) !=
188             strtabsize - sizeof(int))
189                 badfmt("corrupted string table");
190
191         i = n / sizeof(struct nlist);
192         if (!clean) {
193                 newtab = (struct nlist *)malloc(n);
194                 if (newtab == (struct nlist *)NULL)
195                         err(ERREXIT, NULL);
196                 memset(newtab, 0, n);
197
198                 reorder(symtab, newtab, i);
199                 free((void *)symtab);
200                 symtab = newtab;
201         } else {
202                 symkept = i;
203         }
204
205         newstrings = malloc(strtabsize);
206         if (newstrings == NULL)
207                 err(ERREXIT, NULL);
208         t = newstrings;
209         for (symp = symtab; --i >= 0; symp++) {
210                 if (symp->n_un.n_strx == 0)
211                         continue;
212                 if (inlist(symp) < 0) {
213                         if (small)
214                                 continue;
215                         if (clean && !savesymb(symp))
216                                 symp->n_type &= ~N_EXT;
217                 } else if (clean)
218                         symfound++;
219                 symp->n_un.n_strx -= sizeof(int);
220                 (void)strcpy(t, &strings[symp->n_un.n_strx]);
221                 symp->n_un.n_strx = (t - newstrings) + sizeof(int);
222                 t += strlen(t) + 1;
223         }
224
225         /* update shrunk sizes */
226         strtabsize = t - newstrings + sizeof(int);
227         n = symkept * sizeof(struct nlist);
228
229         /* fix exec sym size */
230         (void)lseek(o, (off_t)0, SEEK_SET);
231         exec.a_syms = n;
232         if (write(o, (void *)&exec, sizeof(exec)) != sizeof(exec))
233                 err(ERREXIT, "%s", kfile);
234
235         (void)lseek(o, sa, SEEK_SET);
236         if (write(o, (void *)symtab, n) != n)
237                 err(ERREXIT, "%s", kfile);
238         if (write(o, (void *)&strtabsize, sizeof(int)) != sizeof(int))
239                 err(ERREXIT, "%s", kfile);
240         if (write(o, newstrings, strtabsize - sizeof(int)) !=
241             strtabsize - sizeof(int))
242                 err(ERREXIT, "%s", kfile);
243
244         ftruncate(o, lseek(o, (off_t)0, SEEK_CUR));
245
246         if ((i = nsym - symfound) > 0) {
247                 (void)printf("symorder: %d symbol%s not found:\n",
248                     i, i == 1 ? "" : "s");
249                 for (i = 0; i < nsym; i++)
250                         if (order[i].n_value == 0)
251                                 printf("%s\n", order[i].n_un.n_name);
252                 if (!missing)
253                         exit(NOTFOUNDEXIT);
254         }
255         exit(OKEXIT);
256 }
257
258 int
259 savesymb(s)
260         register struct nlist *s;
261 {
262         if ((s->n_type & N_EXT) != N_EXT)
263                 return 0;
264         switch (s->n_type & N_TYPE) {
265                 case N_TEXT:
266                 case N_DATA:    
267                         return 0;
268                 default:        
269                         return 1;
270         }
271 }
272
273 void
274 reorder(st1, st2, entries)
275         register struct nlist *st1, *st2;
276         int entries;
277 {
278         register struct nlist *p;
279         register int i, n;
280
281         for (p = st1, n = entries; --n >= 0; ++p)
282                 if (inlist(p) != -1)
283                         ++symfound;
284         for (p = st2 + symfound, n = entries; --n >= 0; ++st1) {
285                 if (excluded(st1))
286                         continue;
287                 i = inlist(st1);
288                 if (i == -1)
289                         *p++ = *st1;
290                 else
291                         st2[i] = *st1;
292                 ++symkept;
293         }
294 }
295
296 int
297 inlist(p)
298         register struct nlist *p;
299 {
300         register char *nam;
301         register struct nlist *op;
302
303         if (p->n_type & N_STAB || p->n_un.n_strx == 0)
304                 return (-1);
305         if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize)
306                 badfmt("corrupted symbol table");
307         nam = &strings[p->n_un.n_strx - sizeof(int)];
308         for (op = &order[nsym]; --op >= order; ) {
309                 if (strcmp(op->n_un.n_name, nam) != 0)
310                         continue;
311                 op->n_value = 1;
312                 return (op - order);
313         }
314         return (-1);
315 }
316
317 int
318 excluded(p)
319         register struct nlist *p;
320 {
321         register char *nam;
322         register int x;
323
324         if (p->n_type & N_STAB || p->n_un.n_strx == 0)
325                 return (0);
326         if (p->n_un.n_strx < sizeof(int) || p->n_un.n_strx >= strtabsize)
327                 badfmt("corrupted symbol table");
328         nam = &strings[p->n_un.n_strx - sizeof(int)];
329         for (x = nexclude; --x >= 0; )
330                 if (strcmp(nam, exclude[x]) == 0)
331                         return (1);
332         return (0);
333 }
334
335 void
336 badfmt(why)
337         char *why;
338 {
339         errx(ERREXIT, "%s: %s: %s", kfile, why, strerror(EFTYPE));
340 }
341
342 static void
343 usage()
344 {
345         (void)fprintf(stderr,
346             "usage: symorder [-c] [-m] [-t] [-x excludelist] symlist file\n");
347         exit(ERREXIT);
348 }