Clean up usage messages and option parsers.
[deliverable/binutils-gdb.git] / binutils / copy.c
1 /* copy.c -- copy object file from input to output, optionally massaging it.
2 Copyright (C) 1991 Free Software Foundation, Inc.
3
4 This file is part of GNU Binutils.
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
19
20 #include "bfd.h"
21 #include "sysdep.h"
22 #include "bucomm.h"
23 #include <getopt.h>
24
25 asymbol **sympp;
26 char *input_target = NULL;
27 char *output_target = NULL;
28 char *input_filename = NULL;
29 char *output_filename = NULL;
30
31
32 static void setup_sections();
33 static void copy_sections();
34 static boolean verbose;
35
36 /* This flag distinguishes between strip and copy:
37 1 means this is 'strip'; 0 means this is 'copy'.
38 -1 means if we should use argv[0] to decide. */
39 extern int is_strip;
40
41 int show_version = 0;
42
43 enum strip_action
44 {
45 strip_undef,
46 strip_none, /* don't strip */
47 strip_debug, /* strip all debugger symbols */
48 strip_all /* strip all symbols */
49 };
50
51 /* Which symbols to remove. */
52 enum strip_action strip_symbols;
53
54 enum locals_action
55 {
56 locals_undef,
57 locals_start_L, /* discard locals starting with L */
58 locals_all /* discard all locals */
59 };
60
61 /* Which local symbols to remove. */
62 enum locals_action discard_locals;
63
64 /* Options to handle if running as "strip". */
65
66 struct option strip_options[] = {
67 {"strip-all", no_argument, 0, 's'},
68 {"strip-debug", no_argument, 0, 'S'},
69 {"discard-all", no_argument, 0, 'x'},
70 {"discard-locals", no_argument, 0, 'X'},
71 {"input-format", required_argument, 0, 'I'},
72 {"output-format", required_argument, 0, 'O'},
73 {"format", required_argument, 0, 'F'},
74 {"target", required_argument, 0, 'F'},
75
76 {"version", no_argument, 0, 'V'},
77 {"verbose", no_argument, 0, 'v'},
78 {0, no_argument, 0, 0}
79 };
80
81 /* Options to handle if running as "copy". */
82
83 struct option copy_options[] = {
84 {"strip-all", no_argument, 0, 'S'},
85 {"strip-debug", no_argument, 0, 'g'},
86 {"discard-all", no_argument, 0, 'x'},
87 {"discard-locals", no_argument, 0, 'X'},
88 {"input-format", required_argument, 0, 'I'},
89 {"output-format", required_argument, 0, 'O'},
90 {"format", required_argument, 0, 'F'},
91 {"target", required_argument, 0, 'F'},
92
93 {"version", no_argument, 0, 'V'},
94 {"verbose", no_argument, 0, 'v'},
95 {0, no_argument, 0, 0}
96 };
97
98 /* IMPORTS */
99 extern char *program_name;
100 extern char *program_version;
101
102
103 static
104 void
105 copy_usage()
106 {
107 fprintf(stderr, "copy %s\n\
108 Usage: %s [-vVSgxX] [-I format] [-O format] [-F format]\n\
109 [--format=format] [--target=format] [--input-format=format]\n\
110 [--output-format=format] [--strip-all] [--strip-debug]\n\
111 [--discard-all] [--discard-locals] [--verbose] [--version]\n\
112 infile [outfile]\n",
113 program_version, program_name);
114 exit(1);
115 }
116
117 static
118 void
119 strip_usage()
120 {
121 fprintf(stderr, "strip %s\n\
122 Usage: %s [-vVsSgxX] [-I format] [-O format] [-F format]\n\
123 [--format=format] [--target=format] [--input-format=format]\n\
124 [--output-format=format] [--strip-all] [--strip-debug]\n\
125 [--discard-all] [--discard-locals] [--verbose] [--version] file...\n",
126 program_version, program_name);
127 exit(1);
128 }
129
130
131 /* Create a temp file in the same directory as supplied */
132 static
133 char *
134 make_tempname(filename)
135 char *filename;
136 {
137 static char template[] = "stXXXXXX";
138 char *tmpname;
139 char * slash = strrchr( filename, '/' );
140 if (slash != (char *)NULL){
141 *slash = 0;
142 tmpname = xmalloc(strlen(filename) + sizeof(template) + 1 );
143 strcpy(tmpname, filename);
144 strcat(tmpname, "/" );
145 strcat(tmpname, template);
146 mktemp(tmpname );
147 *slash = '/';
148 } else {
149 tmpname = xmalloc(sizeof(template));
150 strcpy(tmpname, template);
151 mktemp(tmpname);
152 }
153 return tmpname;
154 }
155
156 /*
157 All the symbols have been read in and point to their owning input section.
158 They have been relocated to that they are all relative to the base of
159 their owning section. On the way out, all the symbols will be relocated to
160 their new location in the output file, through some complex sums.
161
162 */
163 static void
164 mangle_sections(ibfd, obfd)
165 bfd *ibfd;
166 bfd *obfd;
167 {
168 asection *current = ibfd->sections;
169 for (; current != NULL; current = current->next) {
170 current->output_section = bfd_get_section_by_name(obfd, current->name);
171 current->output_offset = 0;
172 }
173 }
174
175 /* Choose which symbol entries to copy;
176 compact them downward to get rid of the rest.
177 Return the number of symbols to be printed. */
178 static unsigned int
179 filter_symbols (abfd, syms, symcount)
180 bfd *abfd;
181 asymbol **syms;
182 unsigned long symcount;
183 {
184 asymbol **from, **to;
185 unsigned int dst_count = 0;
186 asymbol *sym;
187 char locals_prefix = bfd_get_symbol_leading_char(abfd) == '_' ? 'L' : '.';
188
189 unsigned int src_count;
190 for (from = to = syms, src_count = 0; src_count <symcount; src_count++) {
191 int keep = 0;
192
193 flagword flags = (from[src_count])->flags;
194 sym = from[src_count];
195 if ((flags & BSF_GLOBAL) /* Keep if external */
196 || (sym->section == &bfd_und_section)
197 || (bfd_is_com_section (sym->section)))
198 keep = 1;
199 else if ((flags & BSF_DEBUGGING) != 0) /* debugging symbol */
200 keep = strip_symbols != strip_debug;
201 else /* local symbol */
202 keep = (discard_locals != locals_all)
203 && !(discard_locals == locals_start_L &&
204 sym->name[0] == locals_prefix);
205
206
207 if (keep) {
208 to[dst_count++] = from[src_count];
209 }
210 }
211
212 return dst_count;
213 }
214
215 static
216 void
217 copy_object(ibfd, obfd)
218 bfd *ibfd;
219 bfd *obfd;
220 {
221
222 unsigned int symcount;
223
224
225 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
226 bfd_fatal(output_filename);
227
228
229 if (verbose)
230 printf("copy from %s(%s) to %s(%s)\n",
231 ibfd->filename, ibfd->xvec->name,
232 obfd->filename, obfd->xvec->name);
233
234 if ((bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false)
235 ||
236 (bfd_set_file_flags(obfd, (bfd_get_file_flags(ibfd) &
237 (HAS_LINENO | HAS_DEBUG |
238 HAS_RELOC | HAS_SYMS | D_PAGED |
239 HAS_LOCALS))) == false)) {
240 bfd_fatal(bfd_get_filename(ibfd));
241 }
242
243 /* Copy architecture of input file to output file */
244 if (!bfd_set_arch_mach(obfd, bfd_get_arch(ibfd),
245 bfd_get_mach(ibfd))) {
246 fprintf(stderr, "Output file cannot represent architecture %s\n",
247 bfd_printable_arch_mach(bfd_get_arch(ibfd),
248 bfd_get_mach(ibfd)));
249 }
250 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
251 {
252 bfd_fatal(ibfd->filename);
253 }
254
255 sympp = (asymbol **) xmalloc(get_symtab_upper_bound(ibfd));
256 symcount = bfd_canonicalize_symtab(ibfd, sympp);
257
258 if (strip_symbols == strip_debug || discard_locals != locals_undef)
259 symcount = filter_symbols (ibfd, sympp, symcount);
260
261
262 bfd_set_symtab(obfd, sympp,
263 strip_symbols == strip_all ? 0 : symcount);
264
265 /*
266 bfd mandates that all output sections be created and sizes set before
267 any output is done. Thus, we traverse all sections twice.
268 */
269 bfd_map_over_sections(ibfd, setup_sections, (void *) obfd);
270 bfd_map_over_sections(ibfd, copy_sections, (void *) obfd);
271 mangle_sections(ibfd, obfd);
272 }
273 static
274 char *
275 cat(a,b,c)
276 char *a;
277 char *b;
278 char *c;
279 {
280 int size = strlen(a) + strlen(b) + strlen(c);
281 char *r = xmalloc(size+1);
282 strcpy(r,a);
283 strcat(r,b);
284 strcat(r,c);
285 return r;
286 }
287
288 static void
289 copy_archive(ibfd, obfd)
290 bfd *ibfd;
291 bfd *obfd;
292 {
293 bfd **ptr = &obfd->archive_head;
294 bfd *this_element;
295 /* Read each archive element in turn from the input, copy the
296 contents to a temp file, and keep the temp file handle */
297 char *dir = cat("./#",make_tempname(""),"cd");
298
299 /* Make a temp directory to hold the contents */
300 mkdir(dir,0777);
301 obfd->has_armap = ibfd->has_armap;
302 this_element = bfd_openr_next_archived_file(ibfd, NULL);
303 ibfd->archive_head = this_element;
304 while (this_element != (bfd *)NULL) {
305
306 /* Create an output file for this member */
307 char *output_name = cat(dir, "/",this_element->filename);
308 bfd *output_bfd = bfd_openw(output_name, output_target);
309
310 if (!bfd_set_format(obfd, bfd_get_format(ibfd)))
311 bfd_fatal(output_filename);
312
313 if (output_bfd == (bfd *)NULL) {
314 bfd_fatal(output_name);
315 }
316 if (bfd_check_format(this_element, bfd_object) == true) {
317 copy_object(this_element, output_bfd);
318 }
319
320 bfd_close(output_bfd);
321 /* Now open the newly output file and attatch to our list */
322 output_bfd = bfd_openr(output_name, output_target);
323 /* Mark it for deletion */
324
325 *ptr = output_bfd;
326
327 ptr = &output_bfd->next;
328 this_element->next = bfd_openr_next_archived_file(ibfd, this_element);
329 this_element = this_element->next;
330
331 }
332 *ptr = (bfd *)NULL;
333
334 if (!bfd_close(obfd))
335 bfd_fatal(output_filename);
336
337 /* Now delete all the files that we opened.
338 Construct their names again, unfortunately, but so what;
339 we're about to exit anyway. */
340 for (this_element = ibfd->archive_head;
341 this_element != (bfd *)NULL;
342 this_element = this_element->next)
343 {
344 unlink(cat(dir,"/",this_element->filename));
345 }
346 rmdir(dir);
347 if (!bfd_close(ibfd))
348 bfd_fatal(input_filename);
349
350 }
351
352 static
353 void
354 copy_file(input_filename, output_filename)
355 char *input_filename;
356 char *output_filename;
357 {
358 bfd *ibfd;
359
360 ibfd = bfd_openr(input_filename, input_target);
361 if (ibfd == NULL)
362 bfd_fatal(input_filename);
363
364 if (bfd_check_format(ibfd, bfd_object)) {
365 bfd * obfd = bfd_openw(output_filename, output_target);
366 if (obfd == NULL)
367 bfd_fatal(output_filename);
368
369 copy_object(ibfd, obfd);
370
371 if (ibfd->flags & EXEC_P)
372 obfd->flags |= EXEC_P;
373 if (!bfd_close(obfd))
374 bfd_fatal(output_filename);
375
376 if (!bfd_close(ibfd))
377 bfd_fatal(input_filename);
378 }
379 else if (bfd_check_format(ibfd, bfd_archive)) {
380 bfd * obfd = bfd_openw(output_filename, output_target);
381 if (obfd == NULL)
382 bfd_fatal(output_filename);
383 copy_archive(ibfd, obfd);
384 }
385 }
386
387
388
389 /** Actually do the work */
390 static void
391 setup_sections(ibfd, isection, obfd)
392 bfd *ibfd;
393 sec_ptr isection;
394 bfd *obfd;
395 {
396 sec_ptr osection;
397 char *err;
398
399 osection = bfd_get_section_by_name(obfd, bfd_section_name(ibfd, isection));
400 if (osection == NULL) {
401 osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
402 if (osection == NULL) {
403 err = "making";
404 goto loser;
405 }
406 }
407
408 if (!bfd_set_section_size(obfd,
409 osection,
410 bfd_section_size(ibfd, isection))) {
411 err = "size";
412 goto loser;
413 }
414
415 if (bfd_set_section_vma(obfd,
416 osection,
417 bfd_section_vma(ibfd, isection))
418 == false) {
419 err = "vma";
420 goto loser;
421 } /* on error */
422
423 if (bfd_set_section_alignment(obfd,
424 osection,
425 bfd_section_alignment(ibfd, isection))
426 == false) {
427 err = "alignment";
428 goto loser;
429 } /* on error */
430
431 if (!bfd_set_section_flags(obfd, osection,
432 bfd_get_section_flags(ibfd, isection))) {
433 err = "flags";
434 goto loser;
435 }
436
437 /* All went well */
438 return;
439
440 loser:
441 fprintf(stderr, "%s: file \"%s\", section \"%s\": error in %s: %s\n",
442 program_name,
443 bfd_get_filename(ibfd), bfd_section_name(ibfd, isection),
444 err, bfd_errmsg(bfd_error));
445 exit(1);
446 } /* setup_sections() */
447
448 /*
449 Copy all the section related data from an input section
450 to an output section
451
452 If stripping then don't copy any relocation info
453 */
454 static void
455 copy_sections(ibfd, isection, obfd)
456 bfd *ibfd;
457 sec_ptr isection;
458 bfd *obfd;
459 {
460
461 arelent **relpp;
462 int relcount;
463 sec_ptr osection;
464 bfd_size_type size;
465 osection = bfd_get_section_by_name(obfd,
466 bfd_section_name(ibfd, isection));
467
468 size = bfd_get_section_size_before_reloc(isection);
469
470 if (size == 0)
471 return;
472
473 if (strip_symbols == strip_all
474 || bfd_get_reloc_upper_bound(ibfd, isection) == 0)
475 {
476 bfd_set_reloc(obfd, osection, (arelent **)NULL, 0);
477 }
478 else
479 {
480 relpp = (arelent **) xmalloc(bfd_get_reloc_upper_bound(ibfd, isection));
481 relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, sympp);
482 bfd_set_reloc(obfd, osection, relpp, relcount);
483 }
484
485 isection->_cooked_size = isection->_raw_size;
486 isection->reloc_done =true;
487
488
489 if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS)
490 {
491 PTR memhunk = (PTR) xmalloc((unsigned)size);
492
493 if (!bfd_get_section_contents(ibfd, isection, memhunk, (file_ptr) 0, size))
494 bfd_fatal(bfd_get_filename(ibfd));
495
496 if (!bfd_set_section_contents(obfd, osection, memhunk, (file_ptr)0, size))
497 bfd_fatal(bfd_get_filename(obfd));
498 free(memhunk);
499 }
500
501
502 }
503 int
504 main(argc, argv)
505 int argc;
506 char *argv[];
507 {
508 int i;
509 int c; /* sez which option char */
510
511 program_name = argv[0];
512
513 strip_symbols = strip_undef; /* default is to strip everything. */
514 discard_locals = locals_undef;
515
516 bfd_init();
517
518 if (is_strip < 0) {
519 i = strlen (program_name);
520 is_strip = (i >= 5 && strcmp(program_name+i-5,"strip"));
521 }
522
523 if (is_strip) {
524
525 while ((c = getopt_long(argc, argv, "I:O:F:sSgxXVv",
526 strip_options, (int *) 0))
527 != EOF) {
528 switch (c) {
529 case 'I':
530 input_target = optarg;
531 case 'O':
532 output_target = optarg;
533 break;
534 case 'F':
535 input_target = output_target = optarg;
536 break;
537
538 case 's':
539 strip_symbols = strip_all;
540 break;
541 case 'S':
542 case 'g':
543 strip_symbols = strip_debug;
544 break;
545 case 'x':
546 discard_locals = locals_all;
547 break;
548 case 'X':
549 discard_locals = locals_start_L;
550 break;
551 case 'v':
552 verbose = true;
553 show_version = true;
554 break;
555 case 'V':
556 show_version = true;
557 break;
558 case 0:
559 break; /* we've been given a long option */
560 default:
561 strip_usage ();
562 }
563 }
564
565 i = optind;
566
567 /* Default is to strip all symbols. */
568 if (strip_symbols == strip_undef && discard_locals == locals_undef)
569 strip_symbols = strip_all;
570
571 if (output_target == (char *) NULL)
572 output_target = input_target;
573
574 if (show_version)
575 printf ("%s version %s\n", program_name, program_version);
576 else if (i == argc)
577 strip_usage();
578 for ( ; i < argc; i++) {
579 char *tmpname = make_tempname(argv[i]);
580 copy_file(argv[i], tmpname);
581 rename(tmpname, argv[i]);
582 }
583 return 0;
584 }
585
586 /* Invoked as "copy", not "strip" */
587
588 while ((c = getopt_long(argc, argv, "I:s:O:d:F:b:SgxXVv",
589 strip_options, (int *) 0))
590 != EOF) {
591 switch (c) {
592 case 'I':
593 case 's': /* "source" - 'I' is preferred */
594 input_target = optarg;
595 case 'O':
596 case 'd': /* "destination" - 'O' is preferred */
597 output_target = optarg;
598 break;
599 case 'F':
600 case 'b': /* "both" - 'F' is preferred */
601 input_target = output_target = optarg;
602 break;
603
604 case 'S':
605 strip_symbols = strip_all;
606 break;
607 case 'g':
608 strip_symbols = strip_debug;
609 break;
610 case 'x':
611 discard_locals = locals_all;
612 break;
613 case 'X':
614 discard_locals = locals_start_L;
615 break;
616 case 'v':
617 verbose = true;
618 show_version = true;
619 break;
620 case 'V':
621 show_version = true;
622 break;
623 case 0:
624 break; /* we've been given a long option */
625 default:
626 copy_usage ();
627 }
628 }
629
630 if (show_version)
631 printf ("%s version %s\n", program_name, program_version);
632
633 if (optind == argc)
634 if (show_version)
635 exit(0);
636 else
637 copy_usage();
638
639 input_filename = argv[optind];
640 if (optind + 1 < argc)
641 output_filename = argv[optind+1];
642
643 /* Default is to strip no symbols. */
644 if (strip_symbols == strip_undef && discard_locals == locals_undef)
645 strip_symbols = strip_none;
646
647 if (input_filename == (char *) NULL)
648 copy_usage();
649
650 if (output_target == (char *) NULL)
651 output_target = input_target;
652
653 /* If there is no destination file then create a temp and rename
654 the result into the input */
655
656 if (output_filename == (char *)NULL) {
657 char * tmpname = make_tempname(input_filename);
658 copy_file(input_filename, tmpname);
659 output_filename = input_filename;
660 rename(tmpname, input_filename);
661 }
662 else {
663 copy_file(input_filename, output_filename);
664 }
665 return 0;
666 }
This page took 0.046633 seconds and 4 git commands to generate.