include file handling changes
[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,
108 "Usage %s [-vVSgxX] [-I informat] [-O outformat] infile [outfile]\n",
109 program_name);
110 exit(1);
111 }
112
113 static
114 void
115 strip_usage()
116 {
117 fprintf(stderr, "Usage %s [-vVsSgxX] [-I informat] [-O outformat] filename ...\n", program_name);
118 exit(1);
119 }
120
121
122 /* Create a temp file in the same directory as supplied */
123 static
124 char *
125 make_tempname(filename)
126 char *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 */
154 static void
155 mangle_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
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. */
169 static unsigned int
170 filter_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
206 static
207 void
208 copy_object(ibfd, obfd)
209 bfd *ibfd;
210 bfd *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
225 if ((bfd_set_start_address(obfd, bfd_get_start_address(ibfd)) == false)
226 ||
227 (bfd_set_file_flags(obfd, (bfd_get_file_flags(ibfd) &
228 (HAS_LINENO | HAS_DEBUG |
229 HAS_RELOC | HAS_SYMS | D_PAGED |
230 HAS_LOCALS))) == false)) {
231 bfd_fatal(bfd_get_filename(ibfd));
232 }
233
234 /* Copy architecture of input file to output file */
235 if (!bfd_set_arch_mach(obfd, bfd_get_arch(ibfd),
236 bfd_get_mach(ibfd))) {
237 fprintf(stderr, "Output file cannot represent architecture %s\n",
238 bfd_printable_arch_mach(bfd_get_arch(ibfd),
239 bfd_get_mach(ibfd)));
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
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);
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 }
264 static
265 char *
266 cat(a,b,c)
267 char *a;
268 char *b;
269 char *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
279 static void
280 copy_archive(ibfd, obfd)
281 bfd *ibfd;
282 bfd *obfd;
283 {
284 bfd **ptr = &obfd->archive_head;
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 */
288 char *dir = cat("./#",make_tempname(""),"cd");
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);
294 ibfd->archive_head = this_element;
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);
300
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
318 ptr = &output_bfd->next;
319 this_element->next = bfd_openr_next_archived_file(ibfd, this_element);
320 this_element = this_element->next;
321
322 }
323 *ptr = (bfd *)NULL;
324
325 if (!bfd_close(obfd))
326 bfd_fatal(output_filename);
327
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. */
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 }
337 rmdir(dir);
338 if (!bfd_close(ibfd))
339 bfd_fatal(input_filename);
340
341 }
342
343 static
344 void
345 copy_file(input_filename, output_filename)
346 char *input_filename;
347 char *output_filename;
348 {
349 bfd *ibfd;
350
351 ibfd = bfd_openr(input_filename, input_target);
352 if (ibfd == NULL)
353 bfd_fatal(input_filename);
354
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);
359
360 copy_object(ibfd, obfd);
361
362 if (ibfd->flags & EXEC_P)
363 obfd->flags |= EXEC_P;
364 if (!bfd_close(obfd))
365 bfd_fatal(output_filename);
366
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 }
376 }
377
378
379
380 /** Actually do the work */
381 static void
382 setup_sections(ibfd, isection, obfd)
383 bfd *ibfd;
384 sec_ptr isection;
385 bfd *obfd;
386 {
387 sec_ptr osection;
388 char *err;
389
390 osection = bfd_get_section_by_name(obfd, bfd_section_name(ibfd, isection));
391 if (osection == NULL) {
392 osection = bfd_make_section(obfd, bfd_section_name(ibfd, isection));
393 if (osection == NULL) {
394 err = "making";
395 goto loser;
396 }
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
431 loser:
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
439 /*
440 Copy all the section related data from an input section
441 to an output section
442
443 If stripping then don't copy any relocation info
444 */
445 static void
446 copy_sections(ibfd, isection, obfd)
447 bfd *ibfd;
448 sec_ptr isection;
449 bfd *obfd;
450 {
451
452 arelent **relpp;
453 int relcount;
454 sec_ptr osection;
455 bfd_size_type size;
456 osection = bfd_get_section_by_name(obfd,
457 bfd_section_name(ibfd, isection));
458
459 size = bfd_get_section_size_before_reloc(isection);
460
461 if (size == 0)
462 return;
463
464 if (strip_symbols == strip_all
465 || bfd_get_reloc_upper_bound(ibfd, isection) == 0)
466 {
467 bfd_set_reloc(obfd, osection, (arelent **)NULL, 0);
468 }
469 else
470 {
471 relpp = (arelent **) xmalloc(bfd_get_reloc_upper_bound(ibfd, isection));
472 relcount = bfd_canonicalize_reloc(ibfd, isection, relpp, sympp);
473 bfd_set_reloc(obfd, osection, relpp, relcount);
474 }
475
476 isection->_cooked_size = isection->_raw_size;
477 isection->reloc_done =true;
478
479
480 if (bfd_get_section_flags(ibfd, isection) & SEC_HAS_CONTENTS)
481 {
482 PTR memhunk = (PTR) xmalloc((unsigned)size);
483
484 if (!bfd_get_section_contents(ibfd, isection, memhunk, (file_ptr) 0, size))
485 bfd_fatal(bfd_get_filename(ibfd));
486
487 if (!bfd_set_section_contents(obfd, osection, memhunk, (file_ptr)0, size))
488 bfd_fatal(bfd_get_filename(obfd));
489 free(memhunk);
490 }
491
492
493 }
494 int
495 main(argc, argv)
496 int argc;
497 char *argv[];
498 {
499 int i;
500 int c; /* sez which option char */
501 int option_index = 0; /* used by getopt and ignored by us */
502
503 program_name = argv[0];
504
505 strip_symbols = strip_undef; /* default is to strip everything. */
506 discard_locals = locals_undef;
507
508 bfd_init();
509
510 if (is_strip < 0) {
511 i = strlen (program_name);
512 is_strip = (i >= 5 && strcmp(program_name+i-5,"strip"));
513 }
514
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;
542 break;
543 case 'v':
544 verbose = true;
545 show_version = true;
546 break;
547 case 'V':
548 show_version = true;
549 break;
550 case 0:
551 break; /* we've been given a long option */
552 default:
553 strip_usage ();
554 }
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
566 if (show_version)
567 printf ("%s version %s\n", program_name, program_version);
568 else if (i == argc)
569 strip_usage();
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
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;
590 break;
591 case 'F':
592 case 'b': /* "both" - 'F' is preferred */
593 input_target = output_target = optarg;
594 break;
595
596 case 'S':
597 strip_symbols = strip_all;
598 break;
599 case 'g':
600 strip_symbols = strip_debug;
601 break;
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;
611 break;
612 case 'V':
613 show_version = true;
614 break;
615 case 0:
616 break; /* we've been given a long option */
617 default:
618 copy_usage ();
619 }
620 }
621
622 if (show_version)
623 printf ("%s version %s\n", program_name, program_version);
624
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
639 if (input_filename == (char *) NULL)
640 copy_usage();
641
642 if (output_target == (char *) NULL)
643 output_target = input_target;
644
645 /* If there is no destination file then create a temp and rename
646 the result into the input */
647
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 }
657 return 0;
658 }