This commit was generated by cvs2svn to track changes on a CVS vendor
[deliverable/binutils-gdb.git] / binutils / strip.c
1 /*** strip.c -- 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 /* BUGS: When there's not enough memory, this should do the copy
19 in pieces rather than just fail as it does now */
20
21 #include "sysdep.h"
22 #include "bfd.h"
23
24 #include "getopt.h"
25
26
27
28 #include <signal.h>
29
30 /* Various program options */
31
32 int show_version = 0;
33
34 /* Which symbols to remove. */
35 enum strip_action {
36 strip_undef,
37 strip_all, /* strip all symbols */
38 strip_debug, /* strip all debugger symbols */
39 } strip_symbols;
40
41 /* Which local symbols to remove. */
42 enum {
43 locals_undef,
44 locals_start_L, /* discard locals starting with L */
45 locals_all, /* discard all locals */
46 } discard_locals;
47
48 extern char *mktemp();
49
50 /* IMPORTS */
51 extern char *program_version;
52 extern char *program_name;
53 extern char *target;
54 extern char *xmalloc();
55
56 PROTO(static boolean, strip_file, (char *filetostrip));
57 PROTO(static void, copy_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
58 PROTO(static void, setup_sections, (bfd *ibfd, sec_ptr isection, bfd *obfd));
59 \f
60 /** main, etc */
61
62 static void
63 usage ()
64 {
65 fprintf (stderr, "strip %s\nUsage: %s [-gsxSX] files ...\n",
66 program_version, program_name);
67 exit (1);
68 }
69
70 struct option long_options[] = {{"strip-all", 0, 0, 's'},
71 {"strip-debug", 0, 0, 'S'},
72 {"discard-all", 0, 0, 'x'},
73 {"discard-locals", 0, 0, 'X'},
74 {0, 0, 0, 0}
75 };
76
77 int
78 main (argc, argv)
79 char **argv;
80 int argc;
81 {
82 int ind;
83 int c;
84 program_name = argv[0];
85
86 strip_symbols = strip_undef; /* default is to strip everything. */
87 discard_locals = locals_undef;
88
89 while ((c = getopt_long (argc, argv, "gsST:xX", long_options, &ind)) != EOF) {
90 switch (c) {
91 case 0:
92 break;
93 case 's':
94 strip_symbols = strip_all;
95 break;
96 case 'g':
97 case 'S':
98 strip_symbols = strip_debug;
99 break;
100 case 'T':
101 target = optarg;
102 break;
103 case 'x':
104 discard_locals = locals_all;
105 break;
106 case 'X':
107 discard_locals = locals_start_L;
108 break;
109 default:
110 usage ();
111 }
112 }
113
114 /* Default is to strip all symbols: */
115 if (strip_symbols == strip_undef && discard_locals == locals_undef) {
116 strip_symbols = strip_all;
117 }
118
119 /* OK, all options now parsed. If no filename specified, do a.out. */
120 if (optind == argc) return !strip_file ("a.out");
121
122 /* We were given several filenames to do: */
123 while (optind < argc)
124 if (!strip_file (argv[optind++])) return 1;
125
126 return 0;
127 }
128 \f
129 /** Hack signals */
130
131 /* Why does strip need to do this, and anyway, if it does shouldn't this be
132 handled by bfd? */
133
134 static int delayed_signal;
135
136 static int sigint_handled = 0;
137 static int sighup_handled = 0;
138 static int sigterm_handled = 0;
139
140 void
141 delay_signal (signo)
142 int signo;
143 {
144 delayed_signal = signo;
145 signal (signo, delay_signal);
146 }
147
148 /* Effectively defer handling of asynchronous kill signals. */
149 void
150 handle_sigs () /* puff puff */
151 {
152 delayed_signal = 0;
153
154 if (signal (SIGINT, SIG_IGN) != SIG_IGN) {
155 sigint_handled = 1;
156 signal (SIGINT, delay_signal);
157 }
158
159 if (signal (SIGHUP, SIG_IGN) != SIG_IGN) {
160 sighup_handled = 1;
161 signal (SIGHUP, delay_signal);
162 }
163
164 if (signal (SIGTERM, SIG_IGN) != SIG_IGN) {
165 sigterm_handled = 1;
166 signal (SIGTERM, delay_signal);
167 }
168
169 return;
170 }
171
172 /* Effectively undefer handling. */
173 void
174 unhandle_sigs () /* put them down */
175 {
176 if (sigint_handled) signal (SIGINT, SIG_DFL);
177
178 if (sighup_handled) signal (SIGHUP, SIG_DFL);
179
180 if (sigterm_handled) signal (SIGTERM, SIG_DFL);
181
182 /* Handle any signal that came in while they were deferred. */
183 if (delayed_signal)
184 kill (getpid (), delayed_signal);
185
186 return;
187 }
188 \f
189
190 static boolean
191 strip_file (filetostrip)
192 char *filetostrip;
193 {
194 static char template[] = "stXXXXXX";
195 char *slash;
196 char *tmpname;
197 bfd *ibfd;
198 bfd *obfd;
199
200 ibfd = bfd_openr (filetostrip, target);
201
202 if (ibfd == NULL) bfd_fatal (filetostrip);
203
204 handle_sigs (); /* light up */
205
206 if (!bfd_check_format (ibfd, bfd_object)) {
207 fprintf (stderr, "Can't strip %s file %s.\n",
208 bfd_format_string (bfd_get_format (ibfd)), filetostrip);
209 exit (1);
210 }
211
212 slash = strrchr( filetostrip, '/' );
213 if ( slash ){
214 *slash = 0;
215 tmpname = xmalloc( strlen(filetostrip) + sizeof(template) + 1 );
216 strcpy( tmpname, filetostrip );
217 strcat( tmpname, "/" );
218 strcat( tmpname, template );
219 mktemp( tmpname );
220 *slash = '/';
221 } else {
222 tmpname = xmalloc( sizeof(template) );
223 strcpy( tmpname, template );
224 mktemp( tmpname );
225 }
226
227 obfd = bfd_openw (mktemp(tmpname), (target ? target : bfd_get_target (ibfd)));
228 if (obfd == NULL) bfd_fatal (tmpname);
229
230 if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
231 bfd_fatal (tmpname);
232
233
234 if ((bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false) ||
235 (bfd_set_file_flags (obfd, (bfd_get_file_flags (ibfd) &
236 ~(HAS_LINENO | HAS_DEBUG | HAS_SYMS |
237 HAS_LOCALS))) == false) ||
238 bfd_set_start_address (obfd, bfd_get_start_address (ibfd)) == false)
239 bfd_fatal (bfd_get_filename (ibfd));
240
241 /* Copy architecture of input file to output file */
242 if (!bfd_set_arch_mach (obfd, bfd_get_architecture (ibfd),
243 bfd_get_machine (ibfd))) {
244 fprintf(stderr, "Output file cannot represent architecture %s",
245 bfd_printable_arch_mach (bfd_get_architecture(ibfd),
246 bfd_get_machine (ibfd)));
247 }
248
249
250 /* bfd mandates that all output sections be created and sizes set before
251 any output is done. Thus, we traverse all sections twice. */
252 bfd_map_over_sections (ibfd, setup_sections, (void *)obfd);
253 bfd_map_over_sections (ibfd, copy_sections, (void *)obfd);
254
255 if (!bfd_close (obfd)) bfd_fatal (filetostrip);
256 if (!bfd_close (ibfd)) bfd_fatal (filetostrip);
257
258 rename(tmpname, filetostrip);
259 free(tmpname);
260
261 unhandle_sigs();
262
263 return true;
264 }
265 \f
266 /** Actually do the work */
267 static void
268 setup_sections (ibfd, isection, obfd)
269 bfd *ibfd;
270 sec_ptr isection;
271 bfd *obfd;
272 {
273 sec_ptr osection;
274 char *err;
275
276 osection = bfd_make_section (obfd, bfd_section_name (ibfd, isection));
277 if (osection == NULL) {
278 err = "making";
279 goto loser;
280 }
281
282 if (!bfd_set_section_size(obfd, osection, bfd_section_size(ibfd, isection))) {
283 err = "size";
284 goto loser;
285 }
286
287 if (!bfd_set_section_vma (obfd, osection, bfd_section_vma (ibfd, isection))) {
288 err = "vma";
289 goto loser;
290 }
291
292 if (bfd_set_section_alignment (obfd, osection,
293 bfd_section_alignment (ibfd, isection))
294 != true) {
295 err = "alignment";
296 goto loser;
297 } /* on error, I presume. */
298
299 if (!bfd_set_section_flags (obfd, osection,
300 bfd_get_section_flags (ibfd, isection))) {
301 err = "flags";
302 goto loser;
303 }
304
305 /* All went well */
306 return;
307
308 loser:
309 fprintf (stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
310 program_name,
311 bfd_get_filename (ibfd), bfd_section_name (ibfd, isection),
312 err, bfd_errmsg (bfd_error));
313 exit (1);
314 }
315
316 static void
317 copy_sections (ibfd, isection, obfd)
318 bfd *ibfd;
319 sec_ptr isection;
320 bfd *obfd;
321 {
322 static unsigned char *memhunk = NULL;
323 static unsigned memhunksize = 0;
324
325 sec_ptr osection;
326 unsigned long size;
327 flagword iflg;
328 unsigned char *temp;
329
330 osection = bfd_get_section_by_name (obfd, bfd_section_name (ibfd, isection));
331
332 size = bfd_section_size (ibfd, isection);
333 iflg = bfd_get_section_flags (ibfd, isection);
334
335 /* either:
336 we don't need any memory because there's nothing in this section,
337 we had no memory so we got some,
338 we had some memory but not enough so we got more,
339 or we fail to allocat. */
340
341 if (size == 0)
342 return;
343
344 if ((iflg & SEC_HAS_CONTENTS) == 0)
345 return;
346
347 if (memhunk == NULL) {
348 memhunk = (unsigned char *) xmalloc (size);
349 memhunksize = size;
350 }
351
352 if (size > memhunksize) {
353 temp = (unsigned char *) xrealloc ((char *) memhunk, size);
354 memhunksize = size;
355 memhunk = temp;
356 }
357
358 /* now we have enough memory, just do it: */
359 if (!bfd_get_section_contents (ibfd, isection, memhunk, 0, size))
360 bfd_fatal (bfd_get_filename (ibfd));
361
362 if (!bfd_set_section_contents (obfd, osection, memhunk, 0, size))
363 bfd_fatal (bfd_get_filename (obfd));
364 }
This page took 0.047218 seconds and 5 git commands to generate.