xref: /original-bsd/usr.bin/strip/strip.c (revision a100fa84)
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.11 (Berkeley) 06/24/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 	/* Check size. */
135 	if (sb.st_size > SIZE_T_MAX) {
136 		err(0, "%s: %s", fn, strerror(EFBIG));
137 		return;
138 	}
139 
140 	/* Map the file. */
141 	if (fstat(fd, &sb) ||
142 	    (ep = (EXEC *)mmap(NULL, (size_t)sb.st_size,
143 	    PROT_READ | PROT_WRITE, MAP_SHARED, fd, (off_t)0)) == (EXEC *)-1) {
144 		err(0, "%s: %s", fn, strerror(errno));
145 		return;
146 	}
147 
148 	/*
149 	 * Initialize old and new symbol pointers.  They both point to the
150 	 * beginning of the symbol table in memory, since we're deleting
151 	 * entries.
152 	 */
153 	sym = nsym = symbase = (NLIST *)((char *)ep + N_SYMOFF(*ep));
154 
155 	/*
156 	 * Allocate space for the new string table, initialize old and
157 	 * new string pointers.  Handle the extra long at the beginning
158 	 * of the string table.
159 	 */
160 	strbase = (char *)ep + N_STROFF(*ep);
161 	if ((nstrbase = malloc((u_int)*(u_long *)strbase)) == NULL)
162 		err(1, "%s", strerror(errno));
163 	nstr = nstrbase + sizeof(u_long);
164 
165 	/*
166 	 * Read through the symbol table.  For each non-debugging symbol,
167 	 * copy it and save its string in the new string table.  Keep
168 	 * track of the number of symbols.
169 	 */
170 	for (cnt = ep->a_syms / sizeof(NLIST); cnt--; ++sym)
171 		if (!(sym->n_type & N_STAB) && sym->strx) {
172 			*nsym = *sym;
173 			nsym->strx = nstr - nstrbase;
174 			p = strbase + sym->strx;
175 			len = strlen(p) + 1;
176 			bcopy(p, nstr, len);
177 			nstr += len;
178 			++nsym;
179 		}
180 
181 	/* Fill in new symbol table size. */
182 	ep->a_syms = (nsym - symbase) * sizeof(NLIST);
183 
184 	/* Fill in the new size of the string table. */
185 	*(u_long *)nstrbase = len = nstr - nstrbase;
186 
187 	/*
188 	 * Copy the new string table into place.  Nsym should be pointing
189 	 * at the address past the last symbol entry.
190 	 */
191 	bcopy(nstrbase, (void *)nsym, len);
192 
193 	/* Truncate to the current length. */
194 	if (ftruncate(fd, (char *)nsym + len - (char *)ep))
195 		err(0, "%s: %s", fn, strerror(errno));
196 	munmap((caddr_t)ep, (size_t)sb.st_size);
197 }
198 
199 void
200 usage()
201 {
202 	(void)fprintf(stderr, "usage: strip [-d] file ...\n");
203 	exit(1);
204 }
205 
206 #if __STDC__
207 #include <stdarg.h>
208 #else
209 #include <varargs.h>
210 #endif
211 
212 void
213 #if __STDC__
214 err(int fatal, const char *fmt, ...)
215 #else
216 err(fatal, fmt, va_alist)
217 	int fatal;
218 	char *fmt;
219         va_dcl
220 #endif
221 {
222 	va_list ap;
223 #if __STDC__
224 	va_start(ap, fmt);
225 #else
226 	va_start(ap);
227 #endif
228 	(void)fprintf(stderr, "strip: ");
229 	(void)vfprintf(stderr, fmt, ap);
230 	va_end(ap);
231 	(void)fprintf(stderr, "\n");
232 	if (fatal)
233 		exit(1);
234 	eval = 1;
235 }
236