]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - binutils/objcopy.c
Fix an attempt to free a static pointer when using objcopy's symbol addition feature.
[thirdparty/binutils-gdb.git] / binutils / objcopy.c
index 47c5310f2baee663d440213fafa0b483a1e4e49c..ef3b693be4916106d4afd132f50ec90b10b125dc 100644 (file)
@@ -1,5 +1,5 @@
 /* objcopy.c -- copy object file from input to output, optionally massaging it.
-   Copyright (C) 1991-2019 Free Software Foundation, Inc.
+   Copyright (C) 1991-2020 Free Software Foundation, Inc.
 
    This file is part of GNU Binutils.
 
@@ -68,7 +68,7 @@ struct addsym_node
   long      symval;
   flagword  flags;
   char *    section;
-  char *    othersym;
+  const char *  othersym;
 };
 
 typedef struct section_rename
@@ -143,13 +143,14 @@ struct section_list
      COPY and REMOVE are mutually exlusive.  SET and ALTER are mutually exclusive.  */
 #define SECTION_CONTEXT_REMOVE    (1 << 0) /* Remove this section.  */
 #define SECTION_CONTEXT_COPY      (1 << 1) /* Copy this section, delete all non-copied section.  */
-#define SECTION_CONTEXT_SET_VMA   (1 << 2) /* Set the sections' VMA address.  */
-#define SECTION_CONTEXT_ALTER_VMA (1 << 3) /* Increment or decrement the section's VMA address.  */
-#define SECTION_CONTEXT_SET_LMA   (1 << 4) /* Set the sections' LMA address.  */
-#define SECTION_CONTEXT_ALTER_LMA (1 << 5) /* Increment or decrement the section's LMA address.  */
-#define SECTION_CONTEXT_SET_FLAGS (1 << 6) /* Set the section's flags.  */
-#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 7) /* Remove relocations for this section.  */
-#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 8) /* Set alignment for section.  */
+#define SECTION_CONTEXT_KEEP      (1 << 2) /* Keep this section.  */
+#define SECTION_CONTEXT_SET_VMA   (1 << 3) /* Set the sections' VMA address.  */
+#define SECTION_CONTEXT_ALTER_VMA (1 << 4) /* Increment or decrement the section's VMA address.  */
+#define SECTION_CONTEXT_SET_LMA   (1 << 5) /* Set the sections' LMA address.  */
+#define SECTION_CONTEXT_ALTER_LMA (1 << 6) /* Increment or decrement the section's LMA address.  */
+#define SECTION_CONTEXT_SET_FLAGS (1 << 7) /* Set the section's flags.  */
+#define SECTION_CONTEXT_REMOVE_RELOCS (1 << 8) /* Remove relocations for this section.  */
+#define SECTION_CONTEXT_SET_ALIGNMENT (1 << 9) /* Set alignment for section.  */
 
   bfd_vma              vma_val;   /* Amount to change by or set to.  */
   bfd_vma              lma_val;   /* Amount to change by or set to.  */
@@ -332,6 +333,7 @@ enum command_line_switch
   OPTION_INTERLEAVE_WIDTH,
   OPTION_KEEPGLOBAL_SYMBOLS,
   OPTION_KEEP_FILE_SYMBOLS,
+  OPTION_KEEP_SECTION,
   OPTION_KEEP_SYMBOLS,
   OPTION_LOCALIZE_HIDDEN,
   OPTION_LOCALIZE_SYMBOLS,
@@ -386,6 +388,7 @@ static struct option strip_options[] =
   {"input-format", required_argument, 0, 'I'}, /* Obsolete */
   {"input-target", required_argument, 0, 'I'},
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"merge-notes", no_argument, 0, 'M'},
   {"no-merge-notes", no_argument, 0, OPTION_NO_MERGE_NOTES},
@@ -457,6 +460,7 @@ static struct option copy_options[] =
   {"keep-file-symbols", no_argument, 0, OPTION_KEEP_FILE_SYMBOLS},
   {"keep-global-symbol", required_argument, 0, 'G'},
   {"keep-global-symbols", required_argument, 0, OPTION_KEEPGLOBAL_SYMBOLS},
+  {"keep-section", required_argument, 0, OPTION_KEEP_SECTION},
   {"keep-symbol", required_argument, 0, 'K'},
   {"keep-symbols", required_argument, 0, OPTION_KEEP_SYMBOLS},
   {"localize-hidden", no_argument, 0, OPTION_LOCALIZE_HIDDEN},
@@ -589,6 +593,7 @@ copy_usage (FILE *stream, int exit_status)
      --only-keep-debug             Strip everything but the debug information\n\
      --extract-dwo                 Copy only DWO sections\n\
      --extract-symbol              Remove section contents but keep symbols\n\
+     --keep-section <name>         Do not strip section <name>\n\
   -K --keep-symbol <name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
      --localize-hidden             Turn all ELF hidden symbols into locals\n\
@@ -722,6 +727,7 @@ strip_usage (FILE *stream, int exit_status)
   -M  --merge-notes                Remove redundant entries in note sections (default)\n\
       --no-merge-notes             Do not attempt to remove redundant notes\n\
   -N --strip-symbol=<name>         Do not copy symbol <name>\n\
+     --keep-section=<name>         Do not strip section <name>\n\
   -K --keep-symbol=<name>          Do not strip symbol <name>\n\
      --keep-file-symbols           Do not strip file symbol(s)\n\
   -w --wildcard                    Permit wildcard in symbol comparison\n\
@@ -802,7 +808,7 @@ parse_flags (const char *s)
    string can't be parsed.  */
 
 static flagword
-parse_symflags (const char *s, char **other)
+parse_symflags (const char *s, const char **other)
 {
   flagword ret;
   const char *snext;
@@ -1311,6 +1317,10 @@ is_mergeable_note_section (bfd * abfd, asection * sec)
 static bfd_boolean
 is_strip_section_1 (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
 {
+  if (find_section_list (bfd_section_name (sec), FALSE, SECTION_CONTEXT_KEEP)
+      != NULL)
+    return FALSE;
+
   if (sections_removed || sections_copied)
     {
       struct section_list *p;
@@ -1411,16 +1421,16 @@ 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);
+  if (bfd_get_flavour (ibfd) == 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_section_name (isection), ".buildid") == 0);
+  if (bfd_get_flavour (ibfd) == bfd_target_coff_flavour)
+    return strcmp (bfd_section_name (isection), ".buildid") == 0;
 
   return FALSE;
 }
@@ -1443,6 +1453,9 @@ is_hidden_symbol (asymbol *sym)
   return FALSE;
 }
 
+/* Empty name is hopefully never a valid symbol name.  */
+static const char * empty_name = "";
+
 static bfd_boolean
 need_sym_before (struct addsym_node **node, const char *sym)
 {
@@ -1454,10 +1467,12 @@ need_sym_before (struct addsym_node **node, const char *sym)
     {
       if (!ptr->othersym)
        break;
+      if (ptr->othersym == empty_name)
+       continue;
       else if (strcmp (ptr->othersym, sym) == 0)
        {
-         free (ptr->othersym);
-         ptr->othersym = ""; /* Empty name is hopefully never a valid symbol name.  */
+         free ((char *) ptr->othersym);
+         ptr->othersym = empty_name;
          *node = ptr;
          return TRUE;
        }
@@ -1685,7 +1700,7 @@ filter_symbols (bfd *abfd, bfd *obfd, asymbol **osyms,
        {
          if (ptr->othersym)
            {
-             if (strcmp (ptr->othersym, ""))
+             if (ptr->othersym != empty_name)
                fatal (_("'before=%s' not found"), ptr->othersym);
            }
          else
@@ -2067,7 +2082,7 @@ sort_gnu_build_notes (const void * data1, const void * data2)
        return -1;
 
       if (is_deleted_note (pnote2))    /* 1: F   2: O D */
-       return 1;
+       return -1;
 
       return 1;                                /* 1: F   2: O   */
     }
@@ -2450,7 +2465,9 @@ merge_gnu_build_notes (bfd *          abfd,
   bfd_vma        prev_start = 0;
   bfd_vma        prev_end = 0;
 
-  new = new_contents = xmalloc (size);
+  /* Not sure how, but the notes might grow in size.
+     (eg see PR 1774507).  Allow for this here.  */
+  new = new_contents = xmalloc (size * 2);
   for (pnote = pnotes, old = contents;
        pnote < pnotes_end;
        pnote ++)
@@ -2517,8 +2534,11 @@ merge_gnu_build_notes (bfd *          abfd,
 #endif
   
   new_size = new - new_contents;
-  memcpy (contents, new_contents, new_size);
-  size = new_size;
+  if (new_size < size)
+    {
+      memcpy (contents, new_contents, new_size);
+      size = new_size;
+    }
   free (new_contents);
 
  done:
@@ -2575,7 +2595,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       return FALSE;
     }
 
-  if (ibfd->xvec->flavour != bfd_target_elf_flavour)
+  if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
     {
       if ((do_debug_sections & compress) != 0
          && do_debug_sections != compress)
@@ -2636,8 +2656,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
   imach = bfd_get_mach (ibfd);
   if (input_arch)
     {
-      if (bfd_get_arch_info (ibfd) == NULL
-         || bfd_get_arch_info (ibfd)->arch == bfd_arch_unknown)
+      if (iarch == bfd_arch_unknown)
        {
          iarch = input_arch->arch;
          imach = input_arch->mach;
@@ -2646,6 +2665,14 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
        non_fatal (_("Input file `%s' ignores binary architecture parameter."),
                   bfd_get_archive_filename (ibfd));
     }
+  if (iarch == bfd_arch_unknown
+      && bfd_get_flavour (ibfd) != bfd_target_elf_flavour
+      && bfd_get_flavour (obfd) == bfd_target_elf_flavour)
+    {
+      const struct elf_backend_data *bed = get_elf_backend_data (obfd);
+      iarch = bed->arch;
+      imach = 0;
+    }
   if (!bfd_set_arch_mach (obfd, iarch, imach)
       && (ibfd->target_defaulted
          || bfd_get_arch (ibfd) != bfd_get_arch (obfd)))
@@ -2673,7 +2700,7 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
       pe_data_type *pe = pe_data (obfd);
 
       /* Copy PE parameters before changing them.  */
-      if (ibfd->xvec->flavour == bfd_target_coff_flavour
+      if (bfd_get_flavour (ibfd) == bfd_target_coff_flavour
          && bfd_pei_p (ibfd))
        pe->pe_opthdr = pe_data (ibfd)->pe_opthdr;
 
@@ -2868,6 +2895,11 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
          if (! is_mergeable_note_section (ibfd, osec))
            continue;
 
+         /* If the section is going to be completly deleted then
+            do not bother to merge it.  */
+         if (osec->output_section == NULL)
+           continue;
+
          bfd_size_type size = bfd_section_size (osec);
 
          if (size == 0)
@@ -2883,25 +2915,19 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
            {
              bfd_nonfatal_message (NULL, ibfd, osec,
                                    _("warning: could not load note section"));
-             free (merged->contents);
              free (merged);
              continue;
            }
 
          merged->size = merge_gnu_build_notes (ibfd, osec, size,
                                                merged->contents);
-         if (merged->size == size)
-           {
-             /* Merging achieves nothing.  */
-             merge_debug ("Merge of section %s achieved nothing - skipping\n",
-                          bfd_section_name (osec));
-             free (merged->contents);
-             free (merged);
-             continue;
-           }
 
-         if (osec->output_section == NULL
-             || !bfd_set_section_size (osec->output_section, merged->size))
+         /* FIXME: Once we have read the contents in, we must write
+            them out again.  So even if the mergeing has achieved
+            nothing we still add this entry to the merge list.  */
+
+         if (size != merged->size
+             && !bfd_set_section_size (osec->output_section, merged->size))
            {
              bfd_nonfatal_message (NULL, obfd, osec,
                                    _("warning: failed to set merged notes size"));
@@ -3267,16 +3293,16 @@ copy_object (bfd *ibfd, bfd *obfd, const bfd_arch_info_type *input_arch)
                {
                  bfd_nonfatal_message
                    (NULL, obfd, osec,
-                    _("error: failed to copy merged notes into output"));
+                    _("error: failed to locate merged notes"));
                  continue;
                }
            }
 
-         if (! is_mergeable_note_section (obfd, osec))
+         if (merged->contents == NULL)
            {
              bfd_nonfatal_message
                (NULL, obfd, osec,
-                _("error: failed to copy merged notes into output"));
+                _("error: failed to merge notes"));
              continue;
            }
 
@@ -3736,6 +3762,14 @@ copy_file (const char *input_filename, const char *output_filename,
          status = 1;
          return;
        }
+
+      if (gnu_debuglink_filename != NULL)
+       {
+         non_fatal (_("--add-gnu-debuglink ignored for archive %s"),
+                    bfd_get_filename (ibfd));
+         gnu_debuglink_filename = NULL;
+       }
+
       /* This is a no-op on non-Coff targets.  */
       set_long_section_mode (obfd, ibfd, long_section_names);
 
@@ -3913,11 +3947,16 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
   /* Get the, possibly new, name of the output section.  */
   name = bfd_section_name (isection);
   flags = bfd_section_flags (isection);
+  if (bfd_get_flavour (ibfd) != bfd_get_flavour (obfd))
+    {
+      flags &= bfd_applicable_section_flags (ibfd);
+      flags &= bfd_applicable_section_flags (obfd);
+    }
   name = find_section_rename (name, &flags);
 
   /* Prefix sections.  */
-  if ((prefix_alloc_sections_string)
-      && (bfd_section_flags (isection) & SEC_ALLOC))
+  if (prefix_alloc_sections_string
+      && (bfd_section_flags (isection) & SEC_ALLOC) != 0)
     prefix = prefix_alloc_sections_string;
   else if (prefix_sections_string)
     prefix = prefix_sections_string;
@@ -3943,7 +3982,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
           && !is_nondebug_keep_contents_section (ibfd, isection))
     {
       flags &= ~(SEC_HAS_CONTENTS | SEC_LOAD | SEC_GROUP);
-      if (obfd->xvec->flavour == bfd_target_elf_flavour)
+      if (bfd_get_flavour (obfd) == bfd_target_elf_flavour)
        {
          make_nobits = TRUE;
 
@@ -4046,7 +4085,7 @@ setup_section (bfd *ibfd, sec_ptr isection, void *obfdarg)
       if (gsym != NULL)
        {
          gsym->flags |= BSF_KEEP;
-         if (ibfd->xvec->flavour == bfd_target_elf_flavour)
+         if (bfd_get_flavour (ibfd) == bfd_target_elf_flavour)
            elf_group_id (isection) = gsym;
        }
     }
@@ -4584,6 +4623,9 @@ strip_main (int argc, char *argv[])
        case 'R':
          handle_remove_section_option (optarg);
          break;
+       case OPTION_KEEP_SECTION:
+         find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+         break;
        case OPTION_REMOVE_RELOCS:
          handle_remove_relocations_option (optarg);
          break;
@@ -5010,6 +5052,10 @@ copy_main (int argc, char *argv[])
          handle_remove_section_option (optarg);
          break;
 
+       case OPTION_KEEP_SECTION:
+         find_section_list (optarg, TRUE, SECTION_CONTEXT_KEEP);
+         break;
+
         case OPTION_REMOVE_RELOCS:
          handle_remove_relocations_option (optarg);
          break;