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