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