Add new switch to objcopy: --add-gnu-debuglink=<file>
authorNick Clifton <nickc@redhat.com>
Thu, 12 Jun 2003 07:23:31 +0000 (07:23 +0000)
committerNick Clifton <nickc@redhat.com>
Thu, 12 Jun 2003 07:23:31 +0000 (07:23 +0000)
Allows packages to be shipped in two forms, a stripped executable and debug
info file.

bfd/bfd-in2.h
bfd/opncls.c
binutils/ChangeLog
binutils/NEWS
binutils/doc/binutils.texi
binutils/objcopy.c

index ebe5bcab2588019d4b5413cdaea615ff498f28b0..072812e4f14b3c1efc2d052c39bd7021b4f5ae4a 100644 (file)
@@ -905,9 +905,15 @@ bfd_make_writable PARAMS ((bfd *abfd));
 bfd_boolean
 bfd_make_readable PARAMS ((bfd *abfd));
 
+unsigned long
+bfd_calc_gnu_debuglink_crc32 PARAMS ((unsigned long crc, const unsigned char *buf, bfd_size_type len));
+
 char *
 bfd_follow_gnu_debuglink PARAMS ((bfd *abfd, const char *dir));
 
+bfd_boolean
+bfd_add_gnu_debuglink PARAMS ((bfd * abfd, const char * filename));
+
 /* Extracted from libbfd.c.  */
 
 /* Byte swapping macros for user section data.  */
index 47719797df39a8011eeee766d61bd1f812e6e78e..b6b4097983ad315d30382b52e29d0abbeab490ec 100644 (file)
@@ -716,28 +716,32 @@ bfd_release (abfd, block)
    without debug symbols).
 */
 
-static unsigned long  calc_crc32                  PARAMS ((unsigned long, const unsigned char *, size_t));
 static char *         get_debug_link_info         PARAMS ((bfd *, unsigned long *));
 static bfd_boolean    separate_debug_file_exists  PARAMS ((const char *, const unsigned long));
 static char *         find_separate_debug_file    PARAMS ((bfd *, const char *));
 
+#define GNU_DEBUGLINK  ".gnu_debuglink"
 /*
-INTERNAL_FUNCTION
-       calc_crc32
+FUNCTION
+       bfd_calc_gnu_debuglink_crc32
 
 SYNOPSIS
-       unsigned long calc_crc32 (unsigned long crc, const unsigned char *buf, size_t len);
+       unsigned long bfd_calc_gnu_debuglink_crc32 (unsigned long crc, const unsigned char *buf, bfd_size_type len);
 
 DESCRIPTION
-       Advance the CRC32 given by @var{crc} through @var{len}
-       bytes of @var{buf}. Return the updated CRC32 value.
+       Computes a CRC value as used in the .gnu_debuglink section.
+       Advances the previously computed @var{crc} value by computing
+       and adding in the crc32 for @var{len} bytes of @var{buf}.
+
+RETURNS
+       Return the updated CRC32 value.
 */     
 
-static unsigned long
-calc_crc32 (crc, buf, len)
+unsigned long
+bfd_calc_gnu_debuglink_crc32 (crc, buf, len)
      unsigned long crc;
      const unsigned char *buf;
-     size_t len;
+     bfd_size_type len;
 {
   static const unsigned long crc32_table[256] =
     {
@@ -808,7 +812,7 @@ INTERNAL_FUNCTION
        get_debug_link_info
 
 SYNOPSIS
-       char *get_debug_link_info (bfd *abfd, unsigned long *crc32_out)
+       char * get_debug_link_info (bfd * abfd, unsigned long * crc32_out)
 
 DESCRIPTION
        fetch the filename and CRC32 value for any separate debuginfo
@@ -818,8 +822,8 @@ DESCRIPTION
 
 static char *
 get_debug_link_info (abfd, crc32_out)
-     bfd *abfd;
-     unsigned long *crc32_out;
+     bfd * abfd;
+     unsigned long * crc32_out;
 {
   asection * sect;
   bfd_size_type debuglink_size;
@@ -831,14 +835,17 @@ get_debug_link_info (abfd, crc32_out)
   BFD_ASSERT (abfd);
   BFD_ASSERT (crc32_out);
 
-  sect = bfd_get_section_by_name (abfd, ".gnu_debuglink");
+  sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK);
 
   if (sect == NULL)
     return NULL;
 
   debuglink_size = bfd_section_size (abfd, sect);  
 
-  contents = xmalloc (debuglink_size);
+  contents = malloc (debuglink_size);
+  if (contents == NULL)
+    return NULL;
+
   ret = bfd_get_section_contents (abfd, sect, contents,
                                  (file_ptr)0, debuglink_size);
   if (! ret)
@@ -877,7 +884,7 @@ separate_debug_file_exists (name, crc)
   static char buffer [8 * 1024];
   unsigned long file_crc = 0;
   int fd;
-  int count;
+  bfd_size_type count;
 
   BFD_ASSERT (name);
 
@@ -886,7 +893,7 @@ separate_debug_file_exists (name, crc)
     return FALSE;
 
   while ((count = read (fd, buffer, sizeof (buffer))) > 0)
-    file_crc = calc_crc32 (file_crc, buffer, count);
+    file_crc = bfd_calc_gnu_debuglink_crc32 (file_crc, buffer, count);
 
   close (fd);
 
@@ -930,16 +937,21 @@ find_separate_debug_file (abfd, debug_file_directory)
     return NULL;
 
   basename = get_debug_link_info (abfd, & crc32);
-
   if (basename == NULL)
     return NULL;
+
   if (strlen (basename) < 1)
     {
       free (basename);
       return NULL;
     }
 
-  dir = xstrdup (abfd->filename);
+  dir = strdup (abfd->filename);
+  if (dir == NULL)
+    {
+      free (basename);
+      return NULL;
+    }
   BFD_ASSERT (strlen (dir) != 0);
   
   /* Strip off filename part.  */
@@ -950,11 +962,17 @@ find_separate_debug_file (abfd, debug_file_directory)
   dir[i + 1] = '\0';
   BFD_ASSERT (dir[i] == '/' || dir[0] == '\0')
 
-  debugfile = xmalloc (strlen (debug_file_directory) + 1
-                      + strlen (dir)
-                      + strlen (".debug/")
-                      + strlen (basename) 
-                      + 1);
+  debugfile = malloc (strlen (debug_file_directory) + 1
+                     + strlen (dir)
+                     + strlen (".debug/")
+                     + strlen (basename) 
+                     + 1);
+  if (debugfile == NULL)
+    {
+      free (basename);
+      free (dir);
+      return NULL;
+    }
 
   /* First try in the same directory as the original file:  */
   strcpy (debugfile, dir);
@@ -1037,3 +1055,114 @@ bfd_follow_gnu_debuglink (abfd, dir)
 #endif
   return find_separate_debug_file (abfd, dir);
 }
+
+/*
+FUNCTION
+       bfd_add_gnu_debuglink
+
+SYNOPSIS
+       bfd_boolean bfd_add_gnu_debuglink (bfd * abfd, const char * filename);
+
+DESCRIPTION
+
+       Takes a @var{BFD} and adds a .gnu_debuglink section containing a link
+       to the specified @var{filename}.  The filename should be relative to
+       the current directory.
+
+RETURNS
+       <<TRUE>> is returned if all is ok.  Otherwise <<FALSE>> is returned
+       and bfd_error is set.  
+*/
+
+bfd_boolean
+bfd_add_gnu_debuglink (abfd, filename)
+     bfd *abfd;
+     const char * filename;
+{
+  asection * sect;
+  bfd_size_type debuglink_size;
+  unsigned long crc32;
+  char * contents;
+  bfd_size_type crc_offset;
+  FILE * handle;
+  static char buffer[8 * 1024];
+  size_t count;
+
+  if (abfd == NULL || filename == NULL)
+    {
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
+    }
+
+  /* Make sure that we can read the file.
+     XXX - Should we attempt to locate the debug info file using the same
+     algorithm as gdb ?  At the moment, since we are creating the
+     .gnu_debuglink section, we insist upon the user providing us with a
+     correct-for-section-creation-time path, but this need not conform to
+     the gdb location algorithm.  */
+  handle = fopen (filename, FOPEN_RB);
+  if (handle == NULL)
+    {
+      bfd_set_error (bfd_error_system_call);
+      return FALSE;
+    }
+
+  crc32 = 0;
+  while ((count = fread (buffer, 1, sizeof buffer, handle)) > 0)
+    crc32 = bfd_calc_gnu_debuglink_crc32 (crc32, buffer, count);
+  fclose (handle);
+
+  /* Strip off any path components in filename,
+     now that we no longer need them.  */
+  filename = lbasename (filename);
+  
+  sect = bfd_get_section_by_name (abfd, GNU_DEBUGLINK);
+  if (sect)
+    {
+      /* Section already exists.  */
+      bfd_set_error (bfd_error_invalid_operation);
+      return FALSE;
+    }
+
+  sect = bfd_make_section (abfd, GNU_DEBUGLINK);
+  if (sect == NULL)
+    return FALSE;
+
+  if (! bfd_set_section_flags (abfd, sect,
+                              SEC_HAS_CONTENTS | SEC_DEBUGGING))
+    /* XXX Should we delete the section from the bfd ?  */
+    return FALSE;
+
+  
+  debuglink_size = strlen (filename) + 1;
+  debuglink_size += 3;
+  debuglink_size &= ~3;
+  debuglink_size += 4;
+
+  if (! bfd_set_section_size (abfd, sect, debuglink_size))
+    /* XXX Should we delete the section from the bfd ?  */
+    return FALSE;
+  
+  contents = malloc (debuglink_size);
+  if (contents == NULL)
+    {
+      /* XXX Should we delete the section from the bfd ?  */
+      bfd_set_error (bfd_error_no_memory);
+      return FALSE;
+    }
+
+  strcpy (contents, filename);
+  crc_offset = debuglink_size - 4;
+
+  bfd_put_32 (abfd, crc32, (bfd_byte *) (contents + crc_offset));
+
+  if (! bfd_set_section_contents (abfd, sect, contents,
+                                 (file_ptr)0, debuglink_size))
+    {
+      /* XXX Should we delete the section from the bfd ?  */
+      free (contents);
+      return FALSE;
+    }
+
+  return TRUE;
+}
index b883f3ee9c4c4abd2d27063f59d15cd8dc378af7..7008bf99222eec19102fe61eb6820b2b82152822 100644 (file)
@@ -1,3 +1,21 @@
+2003-06-11  Nick Clifton  <nickc@redhat.com>
+
+       * objcopy.c (gnu_debuglink_filename): New variable.
+        (OPTION_ADD_GNU_DEBUGLINK): New switch
+        (copy_options): Describe --add-gnu-debuglink switch.
+        Mention that --strip-debug removes sections as well.
+        (is_strip_section): Process the sections removed and kept
+        lists before checking for debugging sections.
+        (add_redefine_syms_file): Make function static.
+        (copy_object): Use is_strip_section.
+        Check to see if a .gnu_debuglink section should be added.  If
+        so, call bfd_add_gnu_debuglink.
+        (setup_section): Use is_strip_section.
+        (copy_section): Use is_strip_section.
+        (copy_main): Handle OPTION_ADD_GNU_DEBUGLINK.
+       * NEWS: Mention new objcopy switch.
+        * doc/binutils.texi: Document new switch.
+
 2003-06-11  H.J. Lu <hongjiu.lu@intel.com>
 
        * po/Make-in (DESTDIR): New.
index 2531bf2f864ea9d41e77812c354fecbe00e67282..8d92dcb0860cc9bb0d63efe4baf077d509bb336c 100644 (file)
@@ -1,5 +1,9 @@
 -*- text -*-
 
+* objcopy now accepts --add-gnu-debuglink=<file> to insert a .gnu_debuglink
+  section into a (presumably stripped) executable.  This allows the debug
+  information for the file to be held in a seperate file.
+  
 * BFD marks the sections .comment and .note as 'n' in the BSD/POSIX
   single-character representation.  This can be checked by running nm
   with the -a switch.
index 9c12f780364ae9e9a6583deb498df0d0925774f3..90c871ad87e489454adcc6185bb67fdbb33a3ebd 100644 (file)
@@ -932,21 +932,26 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{-I} @var{bfdname}|@option{--input-target=}@var{bfdname}]
         [@option{-O} @var{bfdname}|@option{--output-target=}@var{bfdname}]
         [@option{-B} @var{bfdarch}|@option{--binary-architecture=}@var{bfdarch}]
-        [@option{-S}|@option{--strip-all}] [@option{-g}|@option{--strip-debug}]
+        [@option{-S}|@option{--strip-all}]
+        [@option{-g}|@option{--strip-debug}]
+        [@option{--add-gnu-debuglink=}@var{path-to-file}]
         [@option{-K} @var{symbolname}|@option{--keep-symbol=}@var{symbolname}]
         [@option{-N} @var{symbolname}|@option{--strip-symbol=}@var{symbolname}]
         [@option{-G} @var{symbolname}|@option{--keep-global-symbol=}@var{symbolname}]
         [@option{-L} @var{symbolname}|@option{--localize-symbol=}@var{symbolname}]
         [@option{-W} @var{symbolname}|@option{--weaken-symbol=}@var{symbolname}]
-        [@option{-x}|@option{--discard-all}] [@option{-X}|@option{--discard-locals}]
+        [@option{-x}|@option{--discard-all}]
+        [@option{-X}|@option{--discard-locals}]
         [@option{-b} @var{byte}|@option{--byte=}@var{byte}]
         [@option{-i} @var{interleave}|@option{--interleave=}@var{interleave}]
         [@option{-j} @var{sectionname}|@option{--only-section=}@var{sectionname}]
         [@option{-R} @var{sectionname}|@option{--remove-section=}@var{sectionname}]
         [@option{-p}|@option{--preserve-dates}]
         [@option{--debugging}]
-        [@option{--gap-fill=}@var{val}] [@option{--pad-to=}@var{address}]
-        [@option{--set-start=}@var{val}] [@option{--adjust-start=}@var{incr}]
+        [@option{--gap-fill=}@var{val}]
+        [@option{--pad-to=}@var{address}]
+        [@option{--set-start=}@var{val}]
+        [@option{--adjust-start=}@var{incr}]
         [@option{--change-addresses=}@var{incr}]
         [@option{--change-section-address} @var{section}@{=,+,-@}@var{val}]
         [@option{--change-section-lma} @var{section}@{=,+,-@}@var{val}]
@@ -955,10 +960,10 @@ objcopy [@option{-F} @var{bfdname}|@option{--target=}@var{bfdname}]
         [@option{--set-section-flags} @var{section}=@var{flags}]
         [@option{--add-section} @var{sectionname}=@var{filename}]
         [@option{--rename-section} @var{oldname}=@var{newname}[,@var{flags}]]
-        [@option{--change-leading-char} ] [@option{--remove-leading-char}]
-        [@option{--srec-len=}@var{ival} ] [@option{--srec-forceS3}]
-        [@option{--redefine-sym} @var{old}=@var{new} ]
-        [@option{--redefine-syms=}@var{filename} ]
+        [@option{--change-leading-char}] [@option{--remove-leading-char}]
+        [@option{--srec-len=}@var{ival}] [@option{--srec-forceS3}]
+        [@option{--redefine-sym} @var{old}=@var{new}]
+        [@option{--redefine-syms=}@var{filename}]
         [@option{--weaken}]
         [@option{--keep-symbols=}@var{filename}]
         [@option{--strip-symbols=}@var{filename}]
@@ -1069,11 +1074,15 @@ Do not copy relocation and symbol information from the source file.
 
 @item -g
 @itemx --strip-debug
-Do not copy debugging symbols from the source file.
+Do not copy debugging symbols or sections from the source file.
 
 @item --strip-unneeded
 Strip all symbols that are not needed for relocation processing.
 
+@item --add-gnu-debuglink=@var{path-to-file}
+Creates a .gnu_debuglink section which contains a reference to @var{path-to-file}
+and adds it to the output file.
+
 @item -K @var{symbolname}
 @itemx --keep-symbol=@var{symbolname}
 Copy only symbol @var{symbolname} from the source file.  This option may
@@ -2054,15 +2063,16 @@ and the Info entries for @file{binutils}.
 
 @smallexample
 @c man begin SYNOPSIS strip
-strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname} ]
-      [@option{-I} @var{bfdname} |@option{--input-target=}@var{bfdname} ]
-      [@option{-O} @var{bfdname} |@option{--output-target=}@var{bfdname} ]
-      [@option{-s}|@option{--strip-all}] [@option{-S}|@option{-g}|@option{-d}|@option{--strip-debug}]
-      [@option{-K} @var{symbolname} |@option{--keep-symbol=}@var{symbolname} ]
-      [@option{-N} @var{symbolname} |@option{--strip-symbol=}@var{symbolname} ]
-      [@option{-x}|@option{--discard-all} ] [@option{-X} |@option{--discard-locals}]
-      [@option{-R} @var{sectionname} |@option{--remove-section=}@var{sectionname} ]
-      [@option{-o} @var{file} ] [@option{-p}|@option{--preserve-dates}]
+strip [@option{-F} @var{bfdname} |@option{--target=}@var{bfdname}]
+      [@option{-I} @var{bfdname} |@option{--input-target=}@var{bfdname}]
+      [@option{-O} @var{bfdname} |@option{--output-target=}@var{bfdname}]
+      [@option{-s}|@option{--strip-all}]
+      [@option{-S}|@option{-g}|@option{-d}|@option{--strip-debug}]
+      [@option{-K} @var{symbolname} |@option{--keep-symbol=}@var{symbolname}]
+      [@option{-N} @var{symbolname} |@option{--strip-symbol=}@var{symbolname}]
+      [@option{-x}|@option{--discard-all}] [@option{-X} |@option{--discard-locals}]
+      [@option{-R} @var{sectionname} |@option{--remove-section=}@var{sectionname}]
+      [@option{-o} @var{file}] [@option{-p}|@option{--preserve-dates}]
       [@option{-v} |@option{--verbose}] [@option{-V}|@option{--version}]
       [@option{--help}] [@option{--info}]
       @var{objfile}@dots{}
index 68402e86bfba0e05849612f7753298a484bc72ad..cdda827003ea149bff24f2038826fe9f4923fce8 100644 (file)
@@ -110,6 +110,8 @@ static const char * find_section_rename
   PARAMS ((bfd *, sec_ptr, flagword *));
 static void add_section_rename
   PARAMS ((const char *, const char *, flagword));
+static void add_redefine_syms_file 
+  PARAMS ((const char *));
 
 #define RETURN_NONFATAL(s) {bfd_nonfatal (s); status = 1; return;}
 
@@ -217,6 +219,10 @@ struct section_add
 /* List of sections to add to the output BFD.  */
 static struct section_add *add_sections;
 
+/* If non-NULL the argument to --add-gnu-debuglink.
+   This should be the filename to store in the .gnu_debuglink section.  */
+static const char * gnu_debuglink_filename = NULL;
+
 /* Whether to convert debugging information.  */
 static bfd_boolean convert_debugging = FALSE;
 
@@ -277,6 +283,7 @@ static char *prefix_alloc_sections_string = 0;
 #define OPTION_PREFIX_SECTIONS (OPTION_PREFIX_SYMBOLS + 1)
 #define OPTION_PREFIX_ALLOC_SECTIONS (OPTION_PREFIX_SECTIONS + 1)
 #define OPTION_FORMATS_INFO (OPTION_PREFIX_ALLOC_SECTIONS + 1)
+#define OPTION_ADD_GNU_DEBUGLINK (OPTION_FORMATS_INFO + 1)
 
 /* Options to handle if running as "strip".  */
 
@@ -309,6 +316,7 @@ static struct option strip_options[] =
 
 static struct option copy_options[] =
 {
+  {"add-gnu-debuglink", required_argument, 0, OPTION_ADD_GNU_DEBUGLINK},
   {"add-section", required_argument, 0, OPTION_ADD_SECTION},
   {"adjust-start", required_argument, 0, OPTION_CHANGE_START},
   {"adjust-vma", required_argument, 0, OPTION_CHANGE_ADDRESSES},
@@ -410,9 +418,10 @@ copy_usage (stream, exit_status)
      --debugging                   Convert debugging information, if possible\n\
   -p --preserve-dates              Copy modified/access timestamps to the output\n\
   -j --only-section <name>         Only copy section <name> into the output\n\
+     --add-gnu-debuglink=<file>    Add section .gnu_debuglink linking to <file>\n\
   -R --remove-section <name>       Remove section <name> from the output\n\
   -S --strip-all                   Remove all symbol and relocation information\n\
-  -g --strip-debug                 Remove all debugging symbols\n\
+  -g --strip-debug                 Remove all debugging symbols & sections\n\
      --strip-unneeded              Remove all symbols not needed by relocations\n\
   -N --strip-symbol <name>         Do not copy symbol <name>\n\
   -K --keep-symbol <name>          Only copy symbol <name>\n\
@@ -487,7 +496,7 @@ strip_usage (stream, exit_status)
   -p --preserve-dates              Copy modified/access timestamps to the output\n\
   -R --remove-section=<name>       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\n\
+  -g -S -d --strip-debug           Remove all debugging symbols & sections\n\
      --strip-unneeded              Remove all symbols not needed by relocations\n\
   -N --strip-symbol=<name>         Do not copy symbol <name>\n\
   -K --keep-symbol=<name>          Only copy symbol <name>\n\
@@ -752,24 +761,28 @@ is_strip_section (abfd, sec)
      bfd *abfd ATTRIBUTE_UNUSED;
      asection *sec;
 {
-  struct section_list *p;
+  if (sections_removed || sections_copied)
+    {
+      struct section_list *p;
+
+      p = find_section_list (bfd_get_section_name (abfd, sec), FALSE);
+
+      if (sections_removed && p != NULL && p->remove)
+       return TRUE;
+      if (sections_copied && (p == NULL || ! p->copy))
+       return TRUE;
+    }
 
-  if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0
-      && (strip_symbols == STRIP_DEBUG
+  if ((bfd_get_section_flags (abfd, sec) & SEC_DEBUGGING) != 0)
+    {
+      if (strip_symbols == STRIP_DEBUG
          || strip_symbols == STRIP_UNNEEDED
          || strip_symbols == STRIP_ALL
          || discard_locals == LOCALS_ALL
-         || convert_debugging))
-    return TRUE;
-
-  if (! sections_removed && ! sections_copied)
-    return FALSE;
+         || convert_debugging)
+       return TRUE;
+    }
 
-  p = find_section_list (bfd_get_section_name (abfd, sec), FALSE);
-  if (sections_removed && p != NULL && p->remove)
-    return TRUE;
-  if (sections_copied && (p == NULL || ! p->copy))
-    return TRUE;
   return FALSE;
 }
 
@@ -976,7 +989,7 @@ redefine_list_append (cause, source, target)
 /* Handle the --redefine-syms option.  Read lines containing "old new"
    from the file, and add them to the symbol redefine list.  */
 
-void
+static void
 add_redefine_syms_file (filename)
      const char *filename;
 {
@@ -1182,6 +1195,8 @@ copy_object (ibfd, obfd)
 
       for (padd = add_sections; padd != NULL; padd = padd->next)
        {
+         flagword flags;
+
          padd->section = bfd_make_section (obfd, padd->name);
          if (padd->section == NULL)
            {
@@ -1190,45 +1205,47 @@ copy_object (ibfd, obfd)
              status = 1;
              return;
            }
-         else
-           {
-             flagword flags;
-
-             if (! bfd_set_section_size (obfd, padd->section, padd->size))
-               RETURN_NONFATAL (bfd_get_filename (obfd));
 
-             pset = find_section_list (padd->name, FALSE);
-             if (pset != NULL)
-               pset->used = TRUE;
+         if (! bfd_set_section_size (obfd, padd->section, padd->size))
+           RETURN_NONFATAL (bfd_get_filename (obfd));
 
-             if (pset != NULL && pset->set_flags)
-               flags = pset->flags | SEC_HAS_CONTENTS;
-             else
-               flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
+         pset = find_section_list (padd->name, FALSE);
+         if (pset != NULL)
+           pset->used = TRUE;
 
-             if (! bfd_set_section_flags (obfd, padd->section, flags))
-               RETURN_NONFATAL (bfd_get_filename (obfd));
+         if (pset != NULL && pset->set_flags)
+           flags = pset->flags | SEC_HAS_CONTENTS;
+         else
+           flags = SEC_HAS_CONTENTS | SEC_READONLY | SEC_DATA;
 
-             if (pset != NULL)
-               {
-                 if (pset->change_vma != CHANGE_IGNORE)
-                   if (! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
-                     RETURN_NONFATAL (bfd_get_filename (obfd));
+         if (! bfd_set_section_flags (obfd, padd->section, flags))
+           RETURN_NONFATAL (bfd_get_filename (obfd));
 
-                 if (pset->change_lma != CHANGE_IGNORE)
-                   {
-                     padd->section->lma = pset->lma_val;
+         if (pset != NULL)
+           {
+             if (pset->change_vma != CHANGE_IGNORE)
+               if (! bfd_set_section_vma (obfd, padd->section, pset->vma_val))
+                 RETURN_NONFATAL (bfd_get_filename (obfd));
 
-                     if (! bfd_set_section_alignment
-                         (obfd, padd->section,
-                          bfd_section_alignment (obfd, padd->section)))
-                       RETURN_NONFATAL (bfd_get_filename (obfd));
-                   }
+             if (pset->change_lma != CHANGE_IGNORE)
+               {
+                 padd->section->lma = pset->lma_val;
+                 
+                 if (! bfd_set_section_alignment
+                     (obfd, padd->section,
+                      bfd_section_alignment (obfd, padd->section)))
+                   RETURN_NONFATAL (bfd_get_filename (obfd));
                }
            }
        }
     }
 
+  if (gnu_debuglink_filename != NULL)
+    {
+      if (! bfd_add_gnu_debuglink (obfd, gnu_debuglink_filename))
+       RETURN_NONFATAL (gnu_debuglink_filename);
+    }
+
   if (gap_fill_set || pad_to_set)
     {
       asection **set;
@@ -1761,23 +1778,13 @@ setup_section (ibfd, isection, obfdarg)
   const char * name;
   char *prefix = NULL;
 
-  if ((bfd_get_section_flags (ibfd, isection) & SEC_DEBUGGING) != 0
-      && (strip_symbols == STRIP_DEBUG
-         || strip_symbols == STRIP_UNNEEDED
-         || strip_symbols == STRIP_ALL
-         || discard_locals == LOCALS_ALL
-         || convert_debugging))
+  if (is_strip_section (ibfd, isection))
     return;
 
   p = find_section_list (bfd_section_name (ibfd, isection), FALSE);
   if (p != NULL)
     p->used = TRUE;
 
-  if (sections_removed && p != NULL && p->remove)
-    return;
-  if (sections_copied && (p == NULL || ! p->copy))
-    return;
-
   /* Get the, possibly new, name of the output section.  */
   name = find_section_rename (ibfd, isection, & flags);
 
@@ -1913,31 +1920,21 @@ copy_section (ibfd, isection, obfdarg)
   if (status != 0)
     return;
 
-  flags = bfd_get_section_flags (ibfd, isection);
-  if ((flags & SEC_DEBUGGING) != 0
-      && (strip_symbols == STRIP_DEBUG
-         || strip_symbols == STRIP_UNNEEDED
-         || strip_symbols == STRIP_ALL
-         || discard_locals == LOCALS_ALL
-         || convert_debugging))
+  if (is_strip_section (ibfd, isection))
     return;
 
+  flags = bfd_get_section_flags (ibfd, isection);
   if ((flags & SEC_GROUP) != 0)
     return;
 
-  p = find_section_list (bfd_section_name (ibfd, isection), FALSE);
-
-  if (sections_removed && p != NULL && p->remove)
-    return;
-  if (sections_copied && (p == NULL || ! p->copy))
-    return;
-
   osection = isection->output_section;
   size = bfd_get_section_size_before_reloc (isection);
 
   if (size == 0 || osection == 0)
     return;
 
+  p = find_section_list (bfd_get_section_name (ibfd, isection), FALSE);
+
   /* Core files do not need to be relocated.  */
   if (bfd_get_format (obfd) == bfd_core)
     relsize = 0;
@@ -2418,6 +2415,10 @@ copy_main (argc, argv)
          strip_symbols = STRIP_UNNEEDED;
          break;
 
+       case OPTION_ADD_GNU_DEBUGLINK:
+         gnu_debuglink_filename = optarg;
+         break;
+
        case 'K':
          add_specific_symbol (optarg, &keep_specific_list);
          break;
@@ -2789,7 +2790,8 @@ copy_main (argc, argv)
          break;
 
        case 0:
-         break;                /* we've been given a long option */
+         /* We've been given a long option.  */
+         break;
 
        case 'H':
        case 'h':