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