/* objcopy.c -- copy object file from input to output, optionally massaging it.
- Copyright (C) 1991-2014 Free Software Foundation, Inc.
+ Copyright (C) 1991-2015 Free Software Foundation, Inc.
This file is part of GNU Binutils.
/* List of sections to add to the output BFD. */
static struct section_add *add_sections;
+/* List of sections to update in the output BFD. */
+static struct section_add *update_sections;
+
/* List of sections to dump from the output BFD. */
static struct section_add *dump_sections;
/* Whether to compress/decompress DWARF debug sections. */
static enum
{
- nothing,
- compress,
- decompress
+ nothing = 0,
+ compress = 1 << 0,
+ compress_zlib = compress | 1 << 1,
+ compress_gnu_zlib = compress | 1 << 2,
+ compress_gabi_zlib = compress | 1 << 3,
+ decompress = 1 << 4
} do_debug_sections = nothing;
/* Whether to change the leading character in symbol names. */
enum command_line_switch
{
OPTION_ADD_SECTION=150,
+ OPTION_UPDATE_SECTION,
OPTION_DUMP_SECTION,
OPTION_CHANGE_ADDRESSES,
OPTION_CHANGE_LEADING_CHAR,
{
{"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
{"add-section", required_argument, 0, OPTION_ADD_SECTION},
+ {"update-section", required_argument, 0, OPTION_UPDATE_SECTION},
{"adjust-start", required_argument, 0, OPTION_CHANGE_START},
{"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
{"adjust-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_ADDRESS},
{"change-section-vma", required_argument, 0, OPTION_CHANGE_SECTION_VMA},
{"change-start", required_argument, 0, OPTION_CHANGE_START},
{"change-warnings", no_argument, 0, OPTION_CHANGE_WARNINGS},
- {"compress-debug-sections", no_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS},
+ {"compress-debug-sections", optional_argument, 0, OPTION_COMPRESS_DEBUG_SECTIONS},
{"debugging", no_argument, 0, OPTION_DEBUGGING},
{"decompress-debug-sections", no_argument, 0, OPTION_DECOMPRESS_DEBUG_SECTIONS},
{"disable-deterministic-archives", no_argument, 0, 'U'},
-w --wildcard Permit wildcard in symbol comparison\n\
-x --discard-all Remove all non-global symbols\n\
-X --discard-locals Remove any compiler-generated symbols\n\
- -i --interleave [<number>] Only copy N out of every <number> bytes\n\
+ -i --interleave[=<number>] Only copy N out of every <number> bytes\n\
--interleave-width <number> Set N for --interleave\n\
-b --byte <num> Select byte <num> in every interleaved block\n\
--gap-fill <val> Fill gaps between sections with <val>\n\
--set-section-flags <name>=<flags>\n\
Set section <name>'s properties to <flags>\n\
--add-section <name>=<file> Add section <name> found in <file> to output\n\
+ --update-section <name>=<file>\n\
+ Update contents of section <name> with\n\
+ contents found in <file>\n\
--dump-section <name>=<file> Dump the contents of section <name> into <file>\n\
--rename-section <old>=<new>[,<flags>] Rename section <old> to <new>\n\
--long-section-names {enable|disable|keep}\n\
<commit>\n\
--subsystem <name>[:<version>]\n\
Set PE subsystem to <name> [& <version>]\n\
- --compress-debug-sections Compress DWARF debug sections using zlib\n\
+ --compress-debug-sections[={none|zlib|zlib-gnu|zlib-gabi}]\n\
+ Compress DWARF debug sections using zlib\n\
--decompress-debug-sections Decompress DWARF debug sections using zlib\n\
-v --verbose List all object files modified\n\
@<file> Read options from <file>\n\
-U --disable-deterministic-archives\n\
Disable -D behavior (default)\n"));
fprintf (stream, _("\
- -R --remove-section=<name> Remove section <name> from the output\n\
+ -R --remove-section=<name> Also remove section <name> from the output\n\
-s --strip-all Remove all symbol and relocation information\n\
-g -S -d --strip-debug Remove all debugging symbols & sections\n\
--strip-dwo Remove all DWO sections\n\
return strncmp (name + len - 4, ".dwo", 4) == 0;
}
+/* Return TRUE if section SEC is in the update list. */
+
+static bfd_boolean
+is_update_section (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+ if (update_sections != NULL)
+ {
+ struct section_add *pupdate;
+
+ for (pupdate = update_sections;
+ pupdate != NULL;
+ pupdate = pupdate->next)
+ {
+ if (strcmp (sec->name, pupdate->name) == 0)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
/* See if a non-group section is being removed. */
static bfd_boolean
if (p && q)
fatal (_("error: section %s matches both remove and copy options"),
bfd_get_section_name (abfd, sec));
+ if (p && is_update_section (abfd, sec))
+ fatal (_("error: section %s matches both update and remove options"),
+ bfd_get_section_name (abfd, sec));
if (p != NULL)
return TRUE;
return FALSE;
}
+static bfd_boolean
+is_nondebug_keep_contents_section (bfd *ibfd, asection *isection)
+{
+ /* Always keep ELF note sections. */
+ if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+ return (elf_section_type (isection) == SHT_NOTE);
+
+ /* Always keep the .buildid section for PE/COFF.
+
+ Strictly, this should be written "always keep the section storing the debug
+ directory", but that may be the .text section for objects produced by some
+ tools, which it is not sensible to keep. */
+ if (ibfd->xvec->flavour == bfd_target_coff_flavour)
+ return (strcmp (bfd_get_section_name (ibfd, isection), ".buildid") == 0);
+
+ return FALSE;
+}
+
/* Return true if SYM is a hidden symbol. */
static bfd_boolean
if (ibfd->xvec->byteorder != obfd->xvec->byteorder
&& ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN
&& obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN)
- fatal (_("Unable to change endianness of input file(s)"));
+ {
+ /* PR 17636: Call non-fatal so that we return to our parent who
+ may need to tidy temporary files. */
+ non_fatal (_("Unable to change endianness of input file(s)"));
+ return FALSE;
+ }
if (!bfd_set_format (obfd, bfd_get_format (ibfd)))
{
return FALSE;
}
+ if (ibfd->sections == NULL)
+ {
+ non_fatal (_("error: the input file '%s' has no sections"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
+ if ((do_debug_sections & compress) != 0
+ && do_debug_sections != compress
+ && ibfd->xvec->flavour != bfd_target_elf_flavour)
+ {
+ non_fatal (_("--compress-debug-sections=[zlib|zlib-gnu|zlib-gabi] is unsupported on `%s'"),
+ bfd_get_archive_filename (ibfd));
+ return FALSE;
+ }
+
if (verbose)
printf (_("copy from `%s' [%s] to `%s' [%s]\n"),
bfd_get_archive_filename (ibfd), bfd_get_target (ibfd),
bfd_nonfatal_message (NULL, ibfd, NULL, NULL);
return FALSE;
}
+ /* PR 17512: file: d6323821
+ If the symbol table could not be loaded do not pretend that we have
+ any symbols. This trips us up later on when we load the relocs. */
+ if (symcount == 0)
+ {
+ free (isympp);
+ osympp = isympp = NULL;
+ }
/* BFD mandates that all output sections be created and sizes set before
any output is done. Thus, we traverse all sections multiple times. */
}
}
+ if (update_sections != NULL)
+ {
+ struct section_add *pupdate;
+
+ for (pupdate = update_sections;
+ pupdate != NULL;
+ pupdate = pupdate->next)
+ {
+ asection *osec;
+
+ pupdate->section = bfd_get_section_by_name (ibfd, pupdate->name);
+ if (pupdate->section == NULL)
+ {
+ non_fatal (_("error: %s not found, can't be updated"), pupdate->name);
+ return FALSE;
+ }
+
+ osec = pupdate->section->output_section;
+ if (! bfd_set_section_size (obfd, osec, pupdate->size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec, NULL);
+ return FALSE;
+ }
+ }
+ }
+
if (dump_sections != NULL)
{
struct section_add * pdump;
bfd_byte * contents = xmalloc (size);
if (bfd_get_section_contents (ibfd, sec, contents, 0, size))
- fwrite (contents, 1, size, f);
+ {
+ if (fwrite (contents, 1, size, f) != size)
+ {
+ non_fatal (_("error writing section contents to %s (error: %s)"),
+ pdump->filename,
+ strerror (errno));
+ return FALSE;
+ }
+ }
else
bfd_nonfatal_message (NULL, ibfd, sec,
_("could not retrieve section contents"));
}
}
+ if (update_sections != NULL)
+ {
+ struct section_add *pupdate;
+
+ for (pupdate = update_sections;
+ pupdate != NULL;
+ pupdate = pupdate->next)
+ {
+ asection *osec;
+
+ osec = pupdate->section->output_section;
+ if (! bfd_set_section_contents (obfd, osec, pupdate->contents,
+ 0, pupdate->size))
+ {
+ bfd_nonfatal_message (NULL, obfd, osec, NULL);
+ return FALSE;
+ }
+ }
+ }
+
if (gnu_debuglink_filename != NULL)
{
if (! bfd_fill_in_gnu_debuglink_section
{
status = 1;
bfd_nonfatal_message (NULL, obfd, NULL, NULL);
- return;
+ goto cleanup_and_exit;
}
while (!status && this_element != NULL)
bfd_boolean del = TRUE;
bfd_boolean ok_object;
+ /* PR binutils/17533: Do not allow directory traversal
+ outside of the current directory tree by archive members. */
+ if (! is_valid_archive_path (bfd_get_filename (this_element)))
+ {
+ non_fatal (_("illegal pathname found in archive member: %s"),
+ bfd_get_filename (this_element));
+ status = 1;
+ goto cleanup_and_exit;
+ }
+
/* Create an output file for this member. */
output_name = concat (dir, "/",
bfd_get_filename (this_element), (char *) 0);
{
output_name = make_tempdir (output_name);
if (output_name == NULL)
- fatal (_("cannot create tempdir for archive copying (error: %s)"),
- strerror (errno));
+ {
+ non_fatal (_("cannot create tempdir for archive copying (error: %s)"),
+ strerror (errno));
+ status = 1;
+ goto cleanup_and_exit;
+ }
l = (struct name_list *) xmalloc (sizeof (struct name_list));
l->name = output_name;
{
bfd_nonfatal_message (output_name, NULL, NULL, NULL);
status = 1;
- return;
+ goto cleanup_and_exit;
}
if (ok_object)
{
status = 1;
bfd_nonfatal_message (filename, NULL, NULL, NULL);
- return;
}
filename = bfd_get_filename (ibfd);
{
status = 1;
bfd_nonfatal_message (filename, NULL, NULL, NULL);
- return;
}
+ cleanup_and_exit:
/* Delete all the files that we opened. */
for (l = list; l != NULL; l = l->next)
{
unlink (l->name);
}
}
+
rmdir (dir);
}
switch (do_debug_sections)
{
case compress:
+ case compress_zlib:
+ case compress_gnu_zlib:
+ case compress_gabi_zlib:
ibfd->flags |= BFD_COMPRESS;
+ /* Don't check if input is ELF here since this information is
+ only available after bfd_check_format_matches is called. */
+ if (do_debug_sections == compress_gabi_zlib)
+ ibfd->flags |= BFD_COMPRESS_GABI;
break;
case decompress:
ibfd->flags |= BFD_DECOMPRESS;
if (! copy_object (ibfd, obfd, input_arch))
status = 1;
- if (!bfd_close (obfd))
+ /* PR 17512: file: 0f15796a.
+ If the file could not be copied it may not be in a writeable
+ state. So use bfd_close_all_done to avoid the possibility of
+ writing uninitialised data into the file. */
+ if (! (status ? bfd_close_all_done (obfd) : bfd_close (obfd)))
{
status = 1;
bfd_nonfatal_message (output_filename, NULL, NULL, NULL);
flags = p->flags | (flags & (SEC_HAS_CONTENTS | SEC_RELOC));
else if (strip_symbols == STRIP_NONDEBUG
&& (flags & (SEC_ALLOC | SEC_GROUP)) != 0
- && !(ibfd->xvec->flavour == bfd_target_elf_flavour
- && elf_section_type (isection) == SHT_NOTE))
+ && !is_nondebug_keep_contents_section (ibfd, isection))
{
flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
if (obfd->xvec->flavour == bfd_target_elf_flavour)
elf_section_type (osection) = SHT_NOBITS;
size = bfd_section_size (ibfd, isection);
+ size = bfd_convert_section_size (ibfd, isection, obfd, size);
if (copy_byte >= 0)
size = (size + interleave - 1) / interleave * copy_width;
else if (extract_symbol)
/* Copy merge entity size. */
osection->entsize = isection->entsize;
+ /* Copy compress status. */
+ osection->compress_status = isection->compress_status;
+
/* This used to be mangle_section; we do here to avoid using
bfd_get_section_by_name since some formats allow multiple
sections with the same name. */
if (is_strip_section (ibfd, isection))
return TRUE;
+ if (is_update_section (ibfd, isection))
+ return TRUE;
+
flags = bfd_get_section_flags (ibfd, isection);
if ((flags & SEC_GROUP) != 0)
return TRUE;
temp_relpp = (arelent **) xmalloc (relsize);
for (i = 0; i < relcount; i++)
- if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
- keep_specific_htab))
- temp_relpp [temp_relcount++] = relpp [i];
+ {
+ /* PR 17512: file: 9e907e0c. */
+ if (relpp[i]->sym_ptr_ptr)
+ if (is_specified_symbol (bfd_asymbol_name (*relpp[i]->sym_ptr_ptr),
+ keep_specific_htab))
+ temp_relpp [temp_relcount++] = relpp [i];
+ }
relcount = temp_relcount;
free (relpp);
relpp = temp_relpp;
return;
osection = isection->output_section;
- size = bfd_get_section_size (isection);
+ /* The output SHF_COMPRESSED section size is different from input if
+ ELF classes of input and output aren't the same. We must use the
+ output section size here, which has been updated in setup_section
+ via bfd_convert_section_size. */
+ size = bfd_get_section_size (osection);
if (bfd_get_section_flags (ibfd, isection) & SEC_HAS_CONTENTS
&& bfd_get_section_flags (obfd, osection) & SEC_HAS_CONTENTS)
{
bfd_byte *memhunk = NULL;
- if (!bfd_get_full_section_contents (ibfd, isection, &memhunk))
+ if (!bfd_get_full_section_contents (ibfd, isection, &memhunk)
+ || !bfd_convert_section_contents (ibfd, isection, obfd,
+ &memhunk))
{
status = 1;
bfd_nonfatal_message (NULL, ibfd, isection, NULL);
int i;
char *output_file = NULL;
- while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvw",
+ while ((c = getopt_long (argc, argv, "I:O:F:K:N:R:o:sSpdgxXHhVvwDU",
strip_options, (int *) 0)) != EOF)
{
switch (c)
}
}
+/* Allocate and return a pointer to a struct section_add, initializing the
+ structure using ARG, a string in the format "sectionname=filename".
+ The returned structure will have its next pointer set to NEXT. The
+ OPTION field is the name of the command line option currently being
+ parsed, and is only used if an error needs to be reported. */
+
+static struct section_add *
+init_section_add (const char *arg,
+ struct section_add *next,
+ const char *option)
+{
+ struct section_add *pa;
+ const char *s;
+
+ s = strchr (arg, '=');
+ if (s == NULL)
+ fatal (_("bad format for %s"), option);
+
+ pa = (struct section_add *) xmalloc (sizeof (struct section_add));
+ pa->name = xstrndup (arg, s - arg);
+ pa->filename = s + 1;
+ pa->next = next;
+ pa->contents = NULL;
+ pa->size = 0;
+
+ return pa;
+}
+
+/* Load the file specified in PA, allocating memory to hold the file
+ contents, and store a pointer to the allocated memory in the contents
+ field of PA. The size field of PA is also updated. All errors call
+ FATAL. */
+
+static void
+section_add_load_file (struct section_add *pa)
+{
+ size_t off, alloc;
+ FILE *f;
+
+ /* We don't use get_file_size so that we can do
+ --add-section .note.GNU_stack=/dev/null
+ get_file_size doesn't work on /dev/null. */
+
+ f = fopen (pa->filename, FOPEN_RB);
+ if (f == NULL)
+ fatal (_("cannot open: %s: %s"),
+ pa->filename, strerror (errno));
+
+ off = 0;
+ alloc = 4096;
+ pa->contents = (bfd_byte *) xmalloc (alloc);
+ while (!feof (f))
+ {
+ off_t got;
+
+ if (off == alloc)
+ {
+ alloc <<= 1;
+ pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
+ }
+
+ got = fread (pa->contents + off, 1, alloc - off, f);
+ if (ferror (f))
+ fatal (_("%s: fread failed"), pa->filename);
+
+ off += got;
+ }
+
+ pa->size = off;
+
+ fclose (f);
+}
+
static int
copy_main (int argc, char *argv[])
{
struct stat statbuf;
const bfd_arch_info_type *input_arch = NULL;
- while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:w",
+ while ((c = getopt_long (argc, argv, "b:B:i:I:j:K:N:s:O:d:F:L:G:R:SpgxXHhVvW:wDU",
copy_options, (int *) 0)) != EOF)
{
switch (c)
break;
case OPTION_ADD_SECTION:
- {
- const char *s;
- size_t off, alloc;
- struct section_add *pa;
- FILE *f;
-
- s = strchr (optarg, '=');
-
- if (s == NULL)
- fatal (_("bad format for %s"), "--add-section");
-
- pa = (struct section_add *) xmalloc (sizeof (struct section_add));
- pa->name = xstrndup (optarg, s - optarg);
- pa->filename = s + 1;
-
- /* We don't use get_file_size so that we can do
- --add-section .note.GNU_stack=/dev/null
- get_file_size doesn't work on /dev/null. */
-
- f = fopen (pa->filename, FOPEN_RB);
- if (f == NULL)
- fatal (_("cannot open: %s: %s"),
- pa->filename, strerror (errno));
-
- off = 0;
- alloc = 4096;
- pa->contents = (bfd_byte *) xmalloc (alloc);
- while (!feof (f))
- {
- off_t got;
-
- if (off == alloc)
- {
- alloc <<= 1;
- pa->contents = (bfd_byte *) xrealloc (pa->contents, alloc);
- }
-
- got = fread (pa->contents + off, 1, alloc - off, f);
- if (ferror (f))
- fatal (_("%s: fread failed"), pa->filename);
-
- off += got;
- }
-
- pa->size = off;
-
- fclose (f);
+ add_sections = init_section_add (optarg, add_sections,
+ "--add-section");
+ section_add_load_file (add_sections);
+ break;
- pa->next = add_sections;
- add_sections = pa;
- }
+ case OPTION_UPDATE_SECTION:
+ update_sections = init_section_add (optarg, update_sections,
+ "--update-section");
+ section_add_load_file (update_sections);
break;
case OPTION_DUMP_SECTION:
- {
- const char *s;
- struct section_add *pa;
-
- s = strchr (optarg, '=');
-
- if (s == NULL)
- fatal (_("bad format for %s"), "--dump-section");
-
- pa = (struct section_add *) xmalloc (sizeof * pa);
- pa->name = xstrndup (optarg, s - optarg);
- pa->filename = s + 1;
- pa->next = dump_sections;
- pa->contents = NULL;
- dump_sections = pa;
- }
+ dump_sections = init_section_add (optarg, dump_sections,
+ "--dump-section");
break;
case OPTION_CHANGE_START:
break;
case OPTION_COMPRESS_DEBUG_SECTIONS:
- do_debug_sections = compress;
+ if (optarg)
+ {
+ if (strcasecmp (optarg, "none") == 0)
+ do_debug_sections = decompress;
+ else if (strcasecmp (optarg, "zlib") == 0)
+ do_debug_sections = compress_zlib;
+ else if (strcasecmp (optarg, "zlib-gnu") == 0)
+ do_debug_sections = compress_gnu_zlib;
+ else if (strcasecmp (optarg, "zlib-gabi") == 0)
+ do_debug_sections = compress_gabi_zlib;
+ else
+ fatal (_("unrecognized --compress-debug-sections type `%s'"),
+ optarg);
+ }
+ else
+ do_debug_sections = compress;
break;
case OPTION_DEBUGGING:
create_symbol_htabs ();
+ if (argv != NULL)
+ bfd_set_error_program_name (argv[0]);
+
if (is_strip)
strip_main (argc, argv);
else