Initial import from FreeBSD RELENG_4:
[dragonfly.git] / usr.bin / strip / strip.c
1 /*
2  * Copyright (c) 1988, 1993
3  *      The Regents of the University of California.  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
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1988, 1993\n\
37         The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)strip.c     8.1 (Berkeley) 6/6/93";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD: src/usr.bin/strip/strip.c,v 1.12 1999/08/28 01:05:53 peter Exp $";
46 #endif /* not lint */
47
48 #include <sys/types.h>
49 #include <sys/stat.h>
50 #include <sys/mman.h>
51
52 #include <a.out.h>
53 #include <err.h>
54 #include <errno.h>
55 #include <fcntl.h>
56 #include <limits.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 typedef struct exec EXEC;
63 typedef struct nlist NLIST;
64
65 #define strx    n_un.n_strx
66
67 void s_stab __P((const char *, int, EXEC *));
68 void s_sym __P((const char *, int, EXEC *));
69 static void usage __P((void));
70
71 int xflag = 0;
72 int err_val = 0;
73
74 int
75 main(argc, argv)
76         int argc;
77         char *argv[];
78 {
79         register int fd, nb;
80         EXEC head;
81         void (*sfcn)__P((const char *, int, EXEC *));
82         int ch;
83         char *fn;
84
85         sfcn = s_sym;
86         while ((ch = getopt(argc, argv, "dx")) != -1)
87                 switch(ch) {
88                 case 'x':
89                         xflag = 1;
90                         /*FALLTHROUGH*/
91                 case 'd':
92                         sfcn = s_stab;
93                         break;
94                 case '?':
95                 default:
96                         usage();
97                 }
98         argc -= optind;
99         argv += optind;
100
101         while ((fn = *argv++) != NULL) {
102                 if ((fd = open(fn, O_RDWR)) < 0 ||
103                     (nb = read(fd, &head, sizeof(EXEC))) == -1) {
104                         warn("%s", fn);
105                         err_val = 1;
106                         if (fd >= 0 && close(fd)) {
107                                 warn("%s", fn);
108                                 err_val = 1;
109                         }
110                         continue;
111                 }
112                 if (nb != sizeof(EXEC) || N_BADMAG(head)) {
113                         warnx("%s: %s", fn, strerror(EFTYPE));
114                         err_val = 1;
115                         if (close(fd)) {
116                                 warn("%s", fn);
117                                 err_val = 1;
118                         }
119                         continue;
120                 }
121                 sfcn(fn, fd, &head);
122                 if (close(fd)) {
123                         warn("%s", fn);
124                         err_val = 1;
125                 }
126         }
127         exit(err_val);
128 }
129
130 void
131 s_sym(fn, fd, ep)
132         const char *fn;
133         int fd;
134         register EXEC *ep;
135 {
136         register off_t fsize;
137
138         /* If no symbols or data/text relocation info, quit. */
139         if (!ep->a_syms && !ep->a_trsize && !ep->a_drsize)
140                 return;
141
142         /*
143          * New file size is the header plus text and data segments.
144          */
145         fsize = N_DATOFF(*ep) + ep->a_data;
146
147         /* Set symbol size and relocation info values to 0. */
148         ep->a_syms = ep->a_trsize = ep->a_drsize = 0;
149
150         /* Rewrite the header and truncate the file. */
151         if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
152             write(fd, ep, sizeof(EXEC)) != sizeof(EXEC) ||
153             ftruncate(fd, fsize)) {
154                 warn("%s", fn);
155                 err_val = 1;
156         }
157 }
158
159 void
160 s_stab(fn, fd, ep)
161         const char *fn;
162         int fd;
163         EXEC *ep;
164 {
165         register int cnt, len;
166         register char *nstr, *nstrbase, *p, *strbase;
167         register NLIST *sym, *nsym;
168         struct stat sb;
169         NLIST *symbase;
170
171         /* Quit if no symbols. */
172         if (ep->a_syms == 0)
173                 return;
174
175         /* Stat the file. */
176         if (fstat(fd, &sb) < 0) {
177                 warn("%s", fn);
178                 err_val = 1;
179                 return;
180         }
181
182         /* Check size. */
183         if (sb.st_size > SIZE_T_MAX) {
184                 warnx("%s: %s", fn, strerror(EFBIG));
185                 err_val = 1;
186                 return;
187         }
188
189         /* Map the file. */
190         if ((ep = (EXEC *)mmap(NULL, (size_t)sb.st_size,
191             PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)MAP_FAILED) {
192                 warn("%s", fn);
193                 err_val = 1;
194                 return;
195         }
196
197         /*
198          * Initialize old and new symbol pointers.  They both point to the
199          * beginning of the symbol table in memory, since we're deleting
200          * entries.
201          */
202         sym = nsym = symbase = (NLIST *)((char *)ep + N_SYMOFF(*ep));
203
204         /*
205          * Allocate space for the new string table, initialize old and
206          * new string pointers.  Handle the extra long at the beginning
207          * of the string table.
208          */
209         strbase = (char *)ep + N_STROFF(*ep);
210         if ((nstrbase = malloc((size_t)*(u_long *)strbase)) == NULL) {
211                 warn(NULL);
212                 err_val = 1;
213                 munmap((caddr_t)ep, sb.st_size);
214                 return;
215         }
216         nstr = nstrbase + sizeof(u_long);
217
218         /*
219          * Read through the symbol table.  For each non-debugging symbol,
220          * copy it and save its string in the new string table.  Keep
221          * track of the number of symbols.
222          */
223         for (cnt = ep->a_syms / sizeof(NLIST); cnt--; ++sym)
224                 if (!(sym->n_type & N_STAB) && sym->strx) {
225                         *nsym = *sym;
226                         nsym->strx = nstr - nstrbase;
227                         p = strbase + sym->strx;
228                         if (xflag &&
229                             (!(sym->n_type & N_EXT) ||
230                              (sym->n_type & ~N_EXT) == N_FN ||
231                              strcmp(p, "gcc_compiled.") == 0 ||
232                              strcmp(p, "gcc2_compiled.") == 0 ||
233                              strcmp(p, "___gnu_compiled_c") == 0))
234                                 continue;
235                         len = strlen(p) + 1;
236                         bcopy(p, nstr, len);
237                         nstr += len;
238                         ++nsym;
239                 }
240
241         /* Fill in new symbol table size. */
242         ep->a_syms = (nsym - symbase) * sizeof(NLIST);
243
244         /* Fill in the new size of the string table. */
245         *(u_long *)nstrbase = len = nstr - nstrbase;
246
247         /*
248          * Copy the new string table into place.  Nsym should be pointing
249          * at the address past the last symbol entry.
250          */
251         bcopy(nstrbase, (void *)nsym, len);
252
253         /* Truncate to the current length. */
254         if (ftruncate(fd, (char *)nsym + len - (char *)ep)) {
255                 warn("%s", fn);
256                 err_val = 1;
257         }
258         munmap((caddr_t)ep, (size_t)sb.st_size);
259 }
260
261 static void
262 usage()
263 {
264         (void)fprintf(stderr, "usage: strip [-dx] file ...\n");
265         exit(1);
266 }