]> Git Repo - binutils.git/blob - binutils/copy.c
* config/sparc/xm-sun4os4.h: Declare free() to return int.
[binutils.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         || (bfd_is_com_section (sym->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 }
This page took 0.062125 seconds and 4 git commands to generate.