xref: /original-bsd/usr.bin/strip/strip.c (revision c6ddb5f9)
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.12 (Berkeley) 08/07/92";
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 	static int pagesize = -1;
91 	register off_t fsize;
92 
93 	/* If no symbols or data/text relocation info, quit. */
94 	if (!ep->a_syms && !ep->a_trsize && !ep->a_drsize)
95 		return;
96 
97 	/*
98 	 * New file size is the header plus text and data segments; OMAGIC
99 	 * and NMAGIC formats have the text/data immediately following the
100 	 * header.  ZMAGIC format wastes the rest of of header page.
101 	 */
102 	if (ep->a_magic == ZMAGIC)
103 		fsize = pagesize == -1 ? (pagesize = getpagesize()) : pagesize;
104 	else
105 		fsize = sizeof(EXEC);
106 	fsize += ep->a_text + ep->a_data;
107 
108 	/* Set symbol size and relocation info values to 0. */
109 	ep->a_syms = ep->a_trsize = ep->a_drsize = 0;
110 
111 	/* Rewrite the header and truncate the file. */
112 	if (lseek(fd, (off_t)0, SEEK_SET) == -1 ||
113 	    write(fd, ep, sizeof(EXEC)) != sizeof(EXEC) ||
114 	    ftruncate(fd, fsize))
115 		err(0, "%s: %s", fn, strerror(errno));
116 }
117 
118 void
119 s_stab(fn, fd, ep)
120 	const char *fn;
121 	int fd;
122 	EXEC *ep;
123 {
124 	register int cnt, len;
125 	register char *nstr, *nstrbase, *p, *strbase;
126 	register NLIST *sym, *nsym;
127 	struct stat sb;
128 	NLIST *symbase;
129 
130 	/* Quit if no symbols. */
131 	if (ep->a_syms == 0)
132 		return;
133 
134 	/* Stat the file. */
135 	if (fstat(fd, &sb) < 0) {
136 		err(0, "%s: %s", fn, strerror(errno));
137 		return;
138 	}
139 
140 	/* Check size. */
141 	if (sb.st_size > SIZE_T_MAX) {
142 		err(0, "%s: %s", fn, strerror(EFBIG));
143 		return;
144 	}
145 
146 	/* Map the file. */
147 	if ((ep = (EXEC *)mmap(NULL, (size_t)sb.st_size,
148 	    PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)-1) {
149 		err(0, "%s: %s", fn, strerror(errno));
150 		return;
151 	}
152 
153 	/*
154 	 * Initialize old and new symbol pointers.  They both point to the
155 	 * beginning of the symbol table in memory, since we're deleting
156 	 * entries.
157 	 */
158 	sym = nsym = symbase = (NLIST *)((char *)ep + N_SYMOFF(*ep));
159 
160 	/*
161 	 * Allocate space for the new string table, initialize old and
162 	 * new string pointers.  Handle the extra long at the beginning
163 	 * of the string table.
164 	 */
165 	strbase = (char *)ep + N_STROFF(*ep);
166 	if ((nstrbase = malloc((u_int)*(u_long *)strbase)) == NULL)
167 		err(1, "%s", strerror(errno));
168 	nstr = nstrbase + sizeof(u_long);
169 
170 	/*
171 	 * Read through the symbol table.  For each non-debugging symbol,
172 	 * copy it and save its string in the new string table.  Keep
173 	 * track of the number of symbols.
174 	 */
175 	for (cnt = ep->a_syms / sizeof(NLIST); cnt--; ++sym)
176 		if (!(sym->n_type & N_STAB) && sym->strx) {
177 			*nsym = *sym;
178 			nsym->strx = nstr - nstrbase;
179 			p = strbase + sym->strx;
180 			len = strlen(p) + 1;
181 			bcopy(p, nstr, len);
182 			nstr += len;
183 			++nsym;
184 		}
185 
186 	/* Fill in new symbol table size. */
187 	ep->a_syms = (nsym - symbase) * sizeof(NLIST);
188 
189 	/* Fill in the new size of the string table. */
190 	*(u_long *)nstrbase = len = nstr - nstrbase;
191 
192 	/*
193 	 * Copy the new string table into place.  Nsym should be pointing
194 	 * at the address past the last symbol entry.
195 	 */
196 	bcopy(nstrbase, (void *)nsym, len);
197 
198 	/* Truncate to the current length. */
199 	if (ftruncate(fd, (char *)nsym + len - (char *)ep))
200 		err(0, "%s: %s", fn, strerror(errno));
201 	munmap((caddr_t)ep, (size_t)sb.st_size);
202 }
203 
204 void
205 usage()
206 {
207 	(void)fprintf(stderr, "usage: strip [-d] file ...\n");
208 	exit(1);
209 }
210 
211 #if __STDC__
212 #include <stdarg.h>
213 #else
214 #include <varargs.h>
215 #endif
216 
217 void
218 #if __STDC__
219 err(int fatal, const char *fmt, ...)
220 #else
221 err(fatal, fmt, va_alist)
222 	int fatal;
223 	char *fmt;
224         va_dcl
225 #endif
226 {
227 	va_list ap;
228 #if __STDC__
229 	va_start(ap, fmt);
230 #else
231 	va_start(ap);
232 #endif
233 	(void)fprintf(stderr, "strip: ");
234 	(void)vfprintf(stderr, fmt, ap);
235 	va_end(ap);
236 	(void)fprintf(stderr, "\n");
237 	if (fatal)
238 		exit(1);
239 	eval = 1;
240 }
241