1 /*
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1988, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)strip.c 8.3 (Berkeley) 05/16/95";
16 #endif /* not lint */
17
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <sys/mman.h>
21
22 #include <a.out.h>
23 #include <err.h>
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <limits.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 typedef struct exec EXEC;
33 typedef struct nlist NLIST;
34
35 #define strx n_un.n_strx
36
37 void s_stab __P((const char *, int, EXEC *));
38 void s_sym __P((const char *, int, EXEC *));
39 void usage __P((void));
40
41 int
main(argc,argv)42 main(argc, argv)
43 int argc;
44 char *argv[];
45 {
46 register int fd, nb;
47 EXEC head;
48 void (*sfcn)__P((const char *, int, EXEC *));
49 int ch, eval;
50 char *fn;
51
52 sfcn = s_sym;
53 while ((ch = getopt(argc, argv, "d")) != EOF)
54 switch(ch) {
55 case 'd':
56 sfcn = s_stab;
57 break;
58 case '?':
59 default:
60 usage();
61 }
62 argc -= optind;
63 argv += optind;
64
65 for (eval = 0; (fn = *argv++) != NULL;) {
66 if ((fd = open(fn, O_RDWR)) < 0) {
67 warn("%s", fn);
68 eval = 1;
69 continue;
70 }
71 if ((nb = read(fd, &head, sizeof(EXEC))) == -1) {
72 warn("%s", fn);
73 (void)close(fd);
74 eval = 1;
75 continue;
76 }
77 if (nb != sizeof(EXEC) || N_BADMAG(head)) {
78 warnx("%s: %s", fn, strerror(EFTYPE));
79 (void)close(fd);
80 eval = 1;
81 continue;
82 }
83 sfcn(fn, fd, &head);
84 if (close(fd)) {
85 warn("%s", fn);
86 eval = 1;
87 }
88 }
89 exit(eval);
90 }
91
92 void
s_sym(fn,fd,ep)93 s_sym(fn, fd, ep)
94 const char *fn;
95 int fd;
96 register EXEC *ep;
97 {
98 register off_t fsize;
99
100 /* If no symbols or data/text relocation info, quit. */
101 if (!ep->a_syms && !ep->a_trsize && !ep->a_drsize)
102 return;
103
104 /*
105 * New file size is the header plus text and data segments.
106 */
107 fsize = N_DATOFF(*ep) + ep->a_data;
108
109 /* Set symbol size and relocation info values to 0. */
110 ep->a_syms = ep->a_trsize = ep->a_drsize = 0;
111
112 /* Rewrite the header and truncate the file. */
113 if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
114 write(fd, ep, sizeof(EXEC)) != sizeof(EXEC) ||
115 ftruncate(fd, fsize))
116 err(0, "%s: %s", fn, strerror(errno));
117 }
118
119 void
s_stab(fn,fd,ep)120 s_stab(fn, fd, ep)
121 const char *fn;
122 int fd;
123 EXEC *ep;
124 {
125 register int cnt, len;
126 register char *nstr, *nstrbase, *p, *strbase;
127 register NLIST *sym, *nsym;
128 struct stat sb;
129 NLIST *symbase;
130
131 /* Quit if no symbols. */
132 if (ep->a_syms == 0)
133 return;
134
135 /* Stat the file. */
136 if (fstat(fd, &sb) < 0) {
137 err(0, "%s: %s", fn, strerror(errno));
138 return;
139 }
140
141 /* Check size. */
142 if (sb.st_size > SIZE_T_MAX) {
143 err(0, "%s: %s", fn, strerror(EFBIG));
144 return;
145 }
146
147 /* Map the file. */
148 if ((ep = (EXEC *)mmap(NULL, (size_t)sb.st_size,
149 PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)-1) {
150 err(0, "%s: %s", fn, strerror(errno));
151 return;
152 }
153
154 /*
155 * Initialize old and new symbol pointers. They both point to the
156 * beginning of the symbol table in memory, since we're deleting
157 * entries.
158 */
159 sym = nsym = symbase = (NLIST *)((char *)ep + N_SYMOFF(*ep));
160
161 /*
162 * Allocate space for the new string table, initialize old and
163 * new string pointers. Handle the extra long at the beginning
164 * of the string table.
165 */
166 strbase = (char *)ep + N_STROFF(*ep);
167 if ((nstrbase = malloc((u_int)*(u_long *)strbase)) == NULL)
168 err(1, "%s", strerror(errno));
169 nstr = nstrbase + sizeof(u_long);
170
171 /*
172 * Read through the symbol table. For each non-debugging symbol,
173 * copy it and save its string in the new string table. Keep
174 * track of the number of symbols.
175 */
176 for (cnt = ep->a_syms / sizeof(NLIST); cnt--; ++sym)
177 if (!(sym->n_type & N_STAB) && sym->strx) {
178 *nsym = *sym;
179 nsym->strx = nstr - nstrbase;
180 p = strbase + sym->strx;
181 len = strlen(p) + 1;
182 bcopy(p, nstr, len);
183 nstr += len;
184 ++nsym;
185 }
186
187 /* Fill in new symbol table size. */
188 ep->a_syms = (nsym - symbase) * sizeof(NLIST);
189
190 /* Fill in the new size of the string table. */
191 *(u_long *)nstrbase = len = nstr - nstrbase;
192
193 /*
194 * Copy the new string table into place. Nsym should be pointing
195 * at the address past the last symbol entry.
196 */
197 bcopy(nstrbase, (void *)nsym, len);
198
199 /* Truncate to the current length. */
200 if (ftruncate(fd, (char *)nsym + len - (char *)ep))
201 err(0, "%s: %s", fn, strerror(errno));
202 munmap((caddr_t)ep, (size_t)sb.st_size);
203 }
204
205 void
usage()206 usage()
207 {
208 (void)fprintf(stderr, "usage: strip [-d] file ...\n");
209 exit(1);
210 }
211