xref: /original-bsd/usr.bin/strip/strip.c (revision 0ac4996f)
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
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
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
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
206 usage()
207 {
208 	(void)fprintf(stderr, "usage: strip [-d] file ...\n");
209 	exit(1);
210 }
211