xref: /original-bsd/usr.bin/strip/strip.c (revision 990ad5b1)
1 /*
2  * Copyright (c) 1988 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1988 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)strip.c	5.7 (Berkeley) 05/26/91";
16 #endif /* not lint */
17 
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <errno.h>
22 #include <a.out.h>
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 typedef struct exec EXEC;
29 typedef struct nlist NLIST;
30 
31 void err __P((const char *fmt, ...));
32 void s_stab __P((const char *, int, EXEC *));
33 void s_sym __P((const char *, int, EXEC *));
34 void usage __P((void));
35 
36 int eval;
37 
38 main(argc, argv)
39 	int argc;
40 	char *argv[];
41 {
42 	register int fd, nb;
43 	EXEC head;
44 	void (*sfcn)__P((const char *, int, EXEC *));
45 	int ch;
46 	char *fn;
47 
48 	sfcn = s_sym;
49 	while ((ch = getopt(argc, argv, "d")) != EOF)
50 		switch(ch) {
51 		case 'd':
52 			sfcn = s_stab;
53 			break;
54 		case '?':
55 		default:
56 			usage();
57 		}
58 	argc -= optind;
59 	argv += optind;
60 
61 	while (fn = *argv++) {
62 		if ((fd = open(fn, O_RDWR)) < 0 ||
63 		    (nb = read(fd, &head, sizeof(EXEC))) == -1) {
64 			err("%s: %s", fn, strerror(errno));
65 			continue;
66 		}
67 		if (nb != sizeof(EXEC) || N_BADMAG(head)) {
68 			err("%s: %s", fn, strerror(EFTYPE));
69 			continue;
70 		}
71 		sfcn(fn, fd, &head);
72 		if (close(fd))
73 			err("%s: %s", fn, strerror(errno));
74 	}
75 	exit(eval);
76 }
77 
78 void
79 s_sym(fn, fd, ep)
80 	const char *fn;
81 	int fd;
82 	register EXEC *ep;
83 {
84 	static int pagesize = -1;
85 	register off_t fsize;
86 
87 	/* If no symbols or data/text relocation info, quit. */
88 	if (!ep->a_syms && !ep->a_trsize && !ep->a_drsize)
89 		return;
90 
91 	/*
92 	 * New file size is the header plus text and data segments; OMAGIC
93 	 * and NMAGIC formats have the text/data immediately following the
94 	 * header.  ZMAGIC format wastes the rest of of header page.
95 	 */
96 	if (ep->a_magic == ZMAGIC)
97 		fsize = pagesize == -1 ? (pagesize = getpagesize()) : pagesize;
98 	else
99 		fsize = sizeof(EXEC);
100 	fsize += ep->a_text + ep->a_data;
101 
102 	/* Set symbol size and relocation info values to 0. */
103 	ep->a_syms = ep->a_trsize = ep->a_drsize = 0;
104 
105 	/* Rewrite the header and truncate the file. */
106 	if (lseek(fd, 0L, SEEK_SET) == -1 ||
107 	    write(fd, ep, sizeof(EXEC)) != sizeof(EXEC) ||
108 	    ftruncate(fd, fsize))
109 		err("%s: %s", fn, strerror(errno));
110 }
111 
112 void
113 s_stab(fn, fd, ep)
114 	const char *fn;
115 	int fd;
116 	EXEC *ep;
117 {
118 	struct stat sb;
119 	register NLIST *bsym2, *sym1, *sym2;
120 	register u_long nsym1, nsym2;
121 	register char *p, *bstr2, *str1, *str2;
122 	register int len, symlen;
123 	off_t fsize;
124 	int nb;
125 	char *bp;
126 
127 	/* Quit if no symbols. */
128 	if (ep->a_syms == 0)
129 		return;
130 
131 	bsym2 = NULL;
132 	bp = bstr2 = NULL;
133 
134 	/* Read the file into memory.			XXX mmap */
135 	if (fstat(fd, &sb))
136 		goto syserr;
137 	if ((bp = malloc(sb.st_size)) == NULL)
138 		goto syserr;
139 	if (lseek(fd, 0L, SEEK_SET) == -1)
140 		goto syserr;
141 	if ((nb = read(fd, bp, (int)sb.st_size)) == -1)
142 		goto syserr;
143 	if (nb != sb.st_size) {
144 		errno = EIO;
145 		goto syserr;
146 	}
147 
148 	/*
149 	 * Allocate space for new symbol and string tables.  Allocate before
150 	 * reading the symbol tables so we can do it all in a single pass.
151 	 * This loses if there weren't any symbols to strip, but that's life.
152 	 */
153 	sym1 = (NLIST *)(bp + N_SYMOFF(*ep));
154 	if ((bsym2 = sym2 = malloc((u_int)ep->a_syms)) == NULL) {
155 		err("%s", strerror(errno));
156 		goto mem;
157 	}
158 	str1 = bp + N_STROFF(*ep);
159 	if ((bstr2 = malloc((u_int)*(u_long *)str1)) == NULL) {
160 		err("%s", strerror(errno));
161 		goto mem;
162 	}
163 	str2 = bstr2 + sizeof(u_long);
164 	symlen = sizeof(u_long);
165 
166 	/*
167 	 * Read through the symbol table.  For each non-debugging symbol,
168 	 * copy it into the new symbol and string tables.  Keep track of
169 	 * how many symbols are copied and the length of the new string
170 	 * table.
171 	 */
172 #define	strx	n_un.n_strx
173 	nsym2 = 0;
174 	for (nsym1 = ep->a_syms / sizeof(NLIST); nsym1--; ++sym1)
175 		if (!(sym1->n_type & N_STAB) && sym1->strx) {
176 			*sym2 = *sym1;
177 			sym2->strx = str2 - bstr2;
178 			p = str1 + sym1->strx;
179 			len = strlen(p) + 1;
180 			bcopy(p, str2, len);
181 			symlen += len;
182 			str2 += len;
183 			++sym2;
184 			++nsym2;
185 		}
186 
187 	/* If no debugging symbols, quit. */
188 	if (!nsym2)
189 		goto mem;
190 
191 	/* Fill in new symbol table size. */
192 	ep->a_syms = nsym2 * sizeof(NLIST);
193 
194 	/* Write out the header. */
195 	if (lseek(fd, 0L, SEEK_SET) == -1 ||
196 	    write(fd, ep, sizeof(EXEC)) != sizeof(EXEC))
197 		goto syserr;
198 
199 	/* Write out the symbol table. */
200 	if (lseek(fd, N_SYMOFF(*ep), SEEK_SET) == -1 ||
201 	    write(fd, bsym2, ep->a_syms) != ep->a_syms)
202 		goto syserr;
203 
204 	/* Fill in the new size of the string table. */
205 	*(u_long *)bstr2 = symlen;
206 
207 	/* Write out the string table. */
208 	if (write(fd, bstr2, symlen) != symlen)
209 		goto syserr;
210 
211 	/* Truncate to the current length. */
212 	if ((fsize = lseek(fd, 0L, SEEK_CUR)) == -1)
213 		goto syserr;
214 	if (ftruncate(fd, fsize))
215 syserr:		err("%s: %s", fn, strerror(errno));
216 
217 mem:	if (bp)
218 		free(bp);
219 	if (bstr2)
220 		free(bstr2);
221 	if (bsym2)
222 		free(bsym2);
223 }
224 
225 void
226 usage()
227 {
228 
229 	(void)fprintf(stderr, "usage: strip [-d] file ...\n");
230 	exit(1);
231 }
232 
233 #if __STDC__
234 #include <stdarg.h>
235 #else
236 #include <varargs.h>
237 #endif
238 
239 void
240 #if __STDC__
241 err(const char *fmt, ...)
242 #else
243 err(fmt, va_alist)
244 	char *fmt;
245         va_dcl
246 #endif
247 {
248 	va_list ap;
249 #if __STDC__
250 	va_start(ap, fmt);
251 #else
252 	va_start(ap);
253 #endif
254 	(void)fprintf(stderr, "strip: ");
255 	(void)vfprintf(stderr, fmt, ap);
256 	va_end(ap);
257 	(void)fprintf(stderr, "\n");
258 	eval = 1;
259 }
260