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