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