Change GDB over to GNU General Public License version 2.
[deliverable/binutils-gdb.git] / binutils / ostrip.c
1 /* strip certain symbols from a rel file.
2 Copyright (C) 1986, 1990 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 1, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18 #include "sysdep.h"
19
20 #include <stdio.h>
21 #include <signal.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24
25 #include "getopt.h"
26 #include "bfd.h"
27
28 enum strip_action {
29 strip_undef,
30 strip_all, /* strip all symbols */
31 strip_debug, /* strip all debugger symbols */
32 };
33
34 /* Which symbols to remove. */
35 enum strip_action strip_symbols;
36
37 enum locals_action {
38 locals_undef,
39 locals_start_L, /* discard locals starting with L */
40 locals_all, /* discard all locals */
41 };
42
43 /* Which local symbols to remove. */
44 enum locals_action discard_locals;
45
46 /* The name this program was run with. */
47 char *program_name;
48
49 struct option long_options[] = {
50 {"strip-all", 0, 0, 's'},
51 {"strip-debug", 0, 0, 'S'},
52 {"discard-all", 0, 0, 'x'},
53 {"discard-locals", 0, 0, 'X'},
54 {0, 0, 0, 0},
55 };
56
57 static char *target = NULL;
58
59 static int fatal_error;
60
61 extern char *malloc();
62 extern char *mktemp();
63 extern char *realloc();
64 extern char *strcpy();
65 extern int exit();
66 extern int fprintf();
67 extern int free();
68 extern int getpid();
69 extern int kill();
70 extern int perror();
71 extern int sprintf();
72 extern int unlink();
73
74 #ifdef __STDC__
75 static int strip_bfd(bfd *ibfd, bfd *obfd);
76 static int strip_file(char *filetostrip);
77 static void usage(void);
78 #else
79 static int strip_bfd();
80 static int strip_file();
81 static void usage();
82 #endif /* __STDC__ */
83 static void copy_sections ();
84 static void setup_sections ();
85
86 int main(argc, argv)
87 char **argv;
88 int argc;
89 {
90 int ind;
91 int c;
92 program_name = argv[0];
93
94 strip_symbols = strip_undef; /* default is to strip everything. */
95 discard_locals = locals_undef;
96
97 while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
98 switch (c) {
99 case 0:
100 break;
101 case 's':
102 strip_symbols = strip_all;
103 break;
104 case 'g':
105 case 'S':
106 strip_symbols = strip_debug;
107 break;
108 case 'T':
109 target = optarg;
110 break;
111 case 'x':
112 discard_locals = locals_all;
113 break;
114 case 'X':
115 discard_locals = locals_start_L;
116 break;
117 default:
118 usage ();
119 } /* switch on option */
120 } /* for each option */
121
122 if (strip_symbols == strip_undef && discard_locals == locals_undef) {
123 strip_symbols = strip_all;
124 } /* Default is to strip all symbols. */
125
126
127 if (argc == optind) {
128 return(strip_file("a.out"));
129 } else {
130 int retval = 0;
131
132 for ( ; optind < argc; ++optind) {
133 retval &= strip_file(argv[optind]);
134 } /* for each file to strip */
135
136 return(retval);
137 } /* if no arguments given */
138
139 } /* main() */
140
141 static int delayed_signal;
142
143 void delay_signal(signo)
144 int signo;
145 {
146 delayed_signal = signo;
147 signal(signo, delay_signal);
148 } /* delay_signal() */
149
150 static int sigint_handled = 0;
151 static int sighup_handled = 0;
152 static int sigterm_handled = 0;
153
154 void handle_sigs() {
155 /* Effectively defer handling of asynchronous kill signals. */
156 delayed_signal = 0;
157
158 if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
159 sigint_handled = 1;
160 signal(SIGINT, delay_signal);
161 } /* if not ignored */
162
163 if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
164 sighup_handled = 1;
165 signal(SIGHUP, delay_signal);
166 } /* if not ignored */
167
168 if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
169 sigterm_handled = 1;
170 signal(SIGTERM, delay_signal);
171 } /* if not ignored */
172
173 return;
174 } /* handle_sigs() */
175
176 void unhandle_sigs() {
177 /* Effectively undefer handling. */
178 if (sigint_handled)
179 signal (SIGINT, SIG_DFL);
180 if (sighup_handled)
181 signal (SIGHUP, SIG_DFL);
182 if (sigterm_handled)
183 signal (SIGTERM, SIG_DFL);
184
185 /* Handle any signal that came in while they were deferred. */
186 if (delayed_signal)
187 kill (getpid (), delayed_signal);
188
189 return;
190 } /* unhandle_sigs() */
191
192 static int strip_file(filetostrip)
193 char *filetostrip;
194 {
195 bfd *ibfd;
196 bfd *obfd;
197 char tmpfilename[] = "stXXXXXX";
198
199 if ((ibfd = bfd_openr(filetostrip, (char *)NULL)) == NULL) {
200 bfd_perror(filetostrip);
201 return(1);
202 } /* on error opening input */
203
204 obfd = bfd_openw(mktemp(tmpfilename),
205 target? target: bfd_get_target (ibfd));
206 if (obfd == NULL) {
207 bfd_perror(tmpfilename);
208
209 if (bfd_close(ibfd) == false) {
210 bfd_perror(bfd_get_filename(ibfd));
211 } /* on close error */
212
213 return(1);
214 } /* on error opening output */
215
216 handle_sigs();
217
218 if (bfd_check_format(ibfd, bfd_object) != false) {
219 if (bfd_set_format(obfd, bfd_get_format(ibfd)) != false) {
220 if (!strip_bfd(ibfd, obfd)) {
221 /* success */
222
223 if (bfd_close(ibfd) == false) {
224 bfd_perror(bfd_get_filename(ibfd));
225 } /* on close error */
226
227 if (bfd_close(obfd) == false) {
228 bfd_perror(bfd_get_filename(obfd));
229 } /* on close error */
230
231 rename(tmpfilename, filetostrip);
232 unhandle_sigs();
233 return(0);
234 } /* strip_bfd prints it's own failing messages */
235 } else {
236 bfd_perror(filetostrip);
237 } /* can't set format */
238 } else {
239 /* not an object file */
240 (void) fprintf(stderr, "File %s has format 0x%x that will not be stripped.\n",
241 filetostrip, (unsigned) bfd_get_format(ibfd));
242 } /* if anything fails along the way */
243
244
245 if (bfd_close(ibfd) == false) {
246 bfd_perror(bfd_get_filename(ibfd));
247 } /* on close error */
248
249 if (bfd_close(obfd) == false) {
250 bfd_perror(bfd_get_filename(obfd));
251 } /* on close error */
252
253 if (unlink(tmpfilename)) {
254 perror(tmpfilename);
255 } /* on error */
256
257 unhandle_sigs();
258
259 return(1);
260 } /* strip_file() */
261
262
263 boolean
264 bfd_set_start_address (abfd, new_address)
265 bfd *abfd;
266 bfd_vma new_address;
267 {
268 bfd_get_start_address (abfd) = new_address;
269 return true;
270 }
271
272
273
274 static int
275 strip_bfd(ibfd, obfd)
276 bfd *ibfd;
277 bfd *obfd;
278 {
279 if (bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false
280 || bfd_set_file_flags(obfd, bfd_get_file_flags(ibfd) & ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS | HAS_LOCALS)) == false
281 || bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false) {
282 bfd_perror(bfd_get_filename(ibfd));
283 return(1);
284 } /* on error setting file attributes */
285
286 /* bfd mandates that all output sections be created and sizes set before
287 any output is done. Thus, we traverse all sections twice. */
288
289 fatal_error = 0;
290 bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
291 if (!fatal_error)
292 bfd_map_over_sections (ibfd, copy_sections, (void *)obfd);
293 return fatal_error;
294 }
295
296 static void
297 setup_sections(ibfd, isection, obfd)
298 bfd *ibfd;
299 sec_ptr isection;
300 bfd *obfd;
301 {
302 sec_ptr osection;
303 char *err;
304
305 do {
306 err = "making";
307 osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
308 if (osection == NULL)
309 break;
310 err = "size";
311 if (!bfd_set_section_size(obfd, osection,
312 bfd_section_size(ibfd, isection)))
313 break;
314 err = "vma";
315 if (!bfd_set_section_vma(obfd, osection,
316 bfd_section_vma(ibfd, isection)))
317 break;
318 err = "alignment";
319 if (!bfd_set_section_alignment(obfd, osection,
320 bfd_section_alignment(ibfd, isection)))
321 break;
322 err = "flags";
323 if (!bfd_set_section_flags(obfd, osection,
324 bfd_get_section_flags(ibfd, isection)))
325 break;
326 return;
327 } while (0);
328
329 (void) fprintf(stderr, "file \"%s\", section \"%s\": error in %s: ",
330 bfd_get_filename(ibfd),
331 bfd_section_name(ibfd, isection),
332 err);
333
334 bfd_perror("");
335 fatal_error = 1;
336 }
337
338 static void
339 copy_sections(ibfd, isection, obfd)
340 bfd *ibfd;
341 sec_ptr isection;
342 bfd *obfd;
343 {
344 static char *memhunk = NULL;
345 static unsigned memhunksize = 0;
346
347 sec_ptr osection;
348 unsigned long size;
349 flagword iflg;
350 char *temp;
351
352 osection = bfd_get_section_by_name (obfd,
353 bfd_section_name(ibfd, isection));
354
355 size = bfd_section_size(ibfd, isection);
356 iflg = bfd_get_section_flags(ibfd, isection);
357
358 /* either:
359 we don't need any memory because there's nothing in this section,
360 we had no memory so we got some,
361 we had some memory but not enough so we got more,
362 or we fail to allocat. */
363
364 if (size == 0)
365 return;
366
367 if (memhunk == NULL) {
368 memhunk = malloc (size);
369 memhunksize = size;
370 }
371
372 if (size > memhunksize) {
373 temp = realloc (memhunk, size);
374 memhunksize = size;
375 if (!temp) /* If realloc failed, blow away our mem */
376 free (memhunk);
377 memhunk = temp;
378 }
379
380 if (memhunk == NULL) {
381 /* failed to allocate or reallocate */
382 /* FIXME, we should just copy in pieces. */
383 (void) fprintf(stderr,
384 "Could not allocate %lu bytes in which to copy section.\n", size);
385 return;
386 }
387
388 /* now we have enough memory */
389
390 if (!bfd_get_section_contents(ibfd, isection, memhunk, 0, size)) {
391 bfd_perror(bfd_get_filename(ibfd));
392 fatal_error = 1;
393 return;
394 }
395 if (!bfd_set_section_contents(obfd, osection, memhunk, 0, size)) {
396 bfd_perror(bfd_get_filename(obfd));
397 fatal_error = 1;
398 return;
399 }
400 }
401
402 void
403 usage ()
404 {
405 fprintf (stderr, "\
406 Usage: %s [-gsxSX] [+strip-all] [+strip-debug] [+discard-all]\n\
407 [+discard-locals] file...\n", program_name);
408 exit (1);
409 }
410
411 /*
412 * Local Variables:
413 * comment-column: 0
414 * fill-column: 131
415 * End:
416 */
417
418 /* end of strip.c */
This page took 0.036849 seconds and 4 git commands to generate.