Change the behaviour of the --only-keep-debug option to objcopy and strip so that...
authorNick Clifton <nickc@redhat.com>
Wed, 5 Aug 2015 15:16:39 +0000 (16:16 +0100)
committerNick Clifton <nickc@redhat.com>
Wed, 5 Aug 2015 15:16:39 +0000 (16:16 +0100)
bfd * elf.c (_bfd_elf_copy_private_bfd_data): Copy the sh_link and
sh_info fields of sections whose type has been changed to
SHT_NOBITS.

bin * doc/binutils.texi: Document that the --only-keep-debug option
to strip and objcopy preserves the section headers of stripped
sections.

tests * binutils-all/objcopy.exp (keep_debug_symbols_and_check_links):
New proc.  Checks that debug-info-only binaries retain the
sh_link field in stripped sections.

bfd/ChangeLog
bfd/elf.c
binutils/ChangeLog
binutils/doc/binutils.texi
binutils/testsuite/ChangeLog
binutils/testsuite/binutils-all/objcopy.exp

index a8b3646cfe4d486f8247b5d7a684ee603246ddd0..601ce3b5f581c2ecc2ae8d01f21044d234f4c3f8 100644 (file)
@@ -1,3 +1,9 @@
+2015-08-05  Nick Clifton  <nickc@redhat.com>
+
+       * elf.c (_bfd_elf_copy_private_bfd_data): Copy the sh_link and
+       sh_info fields of sections whose type has been changed to
+       SHT_NOBITS.
+
 2015-08-04  Yuriy M. Kaminskiy"  <yumkam@gmail.com>
            Tyler Hicks  <tyhicks@canonical.com>
 
index 05ee0255d9182ddfc8fd9babe6b88934d687248c..67e4240dac196e618e6326221c5d8c8398576d50 100644 (file)
--- a/bfd/elf.c
+++ b/bfd/elf.c
@@ -1203,6 +1203,63 @@ _bfd_elf_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
 
   /* Copy object attributes.  */
   _bfd_elf_copy_obj_attributes (ibfd, obfd);
+
+  /* This is an feature for objcopy --only-keep-debug:  When a section's type
+     is changed to NOBITS, we preserve the sh_link and sh_info fields so that
+     they can be matched up with the original.  */
+  Elf_Internal_Shdr ** iheaders = elf_elfsections (ibfd);
+  Elf_Internal_Shdr ** oheaders = elf_elfsections (obfd);
+
+  if (iheaders != NULL && oheaders != NULL)
+    {
+      unsigned int i;
+
+      for (i = 0; i < elf_numsections (obfd); i++)
+       {
+         unsigned int j;
+         Elf_Internal_Shdr * oheader = oheaders[i];
+
+         if (oheader == NULL
+             || oheader->sh_type != SHT_NOBITS
+             || oheader->sh_size == 0
+             || (oheader->sh_info != 0 && oheader->sh_link != 0))
+           continue;
+
+         /* Scan for the matching section in the input bfd.
+            FIXME: We could use something better than a linear scan here.
+            Unfortunately we cannot compare names as the output string table
+            is empty, so instead we check size, address and type.  */
+         for (j = 0; j < elf_numsections (ibfd); j++)
+           {
+             Elf_Internal_Shdr * iheader = iheaders[j];
+             
+             if (iheader->sh_type != SHT_NOBITS
+                 && iheader->sh_size == oheader->sh_size
+                 && iheader->sh_addr == oheader->sh_addr
+                 && (iheader->sh_info != oheader->sh_info
+                     || iheader->sh_link != oheader->sh_link))
+               {
+                 /* Note: Strictly speaking these assignments are wrong.
+                    The sh_link and sh_info fields should point to the
+                    relevent sections in the output BFD, which may not be in
+                    the same location as they were in the input BFD.  But the
+                    whole point of this action is to preserve the original
+                    values of the sh_link and sh_info fields, so that they
+                    can be matched up with the section headers in the
+                    original file.  So strictly speaking we may be creating
+                    an invalid ELF file, but it is only for a file that just
+                    contains debug info and only for sections without any
+                    contents.  */
+                 if (oheader->sh_link == 0)
+                   oheader->sh_link = iheader->sh_link;
+                 if (oheader->sh_info == 0)
+                   oheader->sh_info = iheader->sh_info;
+                 break;
+               }
+           }
+       }
+    }
+
   return TRUE;
 }
 
index 33c5e7d794cddb8616e7c1badb7fcd0ac279e397..0b5ff7f569c34828f147e9fba58088db5cab3fc9 100644 (file)
@@ -1,3 +1,9 @@
+2015-08-05  Nick Clifton  <nickc@redhat.com>
+
+       * doc/binutils.texi: Document that the --only-keep-debug option
+       to strip and objcopy preserves the section headers of stripped
+       sections.
+
 2015-08-04  Yuriy M. Kaminskiy"  <yumkam@gmail.com>
            Tyler Hicks  <tyhicks@canonical.com>
 
index 466f125722931df9a2c0ac407f4ab0cc913930fc..fef5f3edf7ac6ea1bab9835a48a06ae8abbf846d 100644 (file)
@@ -1731,6 +1731,12 @@ Strip a file, removing contents of any sections that would not be
 stripped by @option{--strip-debug} and leaving the debugging sections
 intact.  In ELF files, this preserves all note sections in the output.
 
+Note - the section headers of the stripped sections are preserved,
+including their sizes, but the contents of the section are discarded.
+The section headers are preserved so that other tools can match up the
+debuginfo file with the real executable, even if that executable has
+been relocated to a different address space.
+
 The intention is that this option will be used in conjunction with
 @option{--add-gnu-debuglink} to create a two part executable.  One a
 stripped binary which will occupy less space in RAM and in a
@@ -3074,9 +3080,16 @@ When stripping a file, perhaps with @option{--strip-debug} or
 which would otherwise get stripped.
 
 @item --only-keep-debug
-Strip a file, removing contents of any sections that would not be
+Strip a file, emptying the contents of any sections that would not be
 stripped by @option{--strip-debug} and leaving the debugging sections
-intact.  In ELF files, this preserves all note sections in the output.
+intact.  In ELF files, this preserves all the note sections in the
+output as well.
+
+Note - the section headers of the stripped sections are preserved,
+including their sizes, but the contents of the section are discarded.
+The section headers are preserved so that other tools can match up the
+debuginfo file with the real executable, even if that executable has
+been relocated to a different address space.
 
 The intention is that this option will be used in conjunction with
 @option{--add-gnu-debuglink} to create a two part executable.  One a
index 1076ca7d07953833d7ceda2de8fc6d47c22895f6..9255fb901e8438dad98d192316286956dd36bd1c 100644 (file)
@@ -1,3 +1,9 @@
+2015-08-05  Nick Clifton  <nickc@redhat.com>
+
+       * binutils-all/objcopy.exp (keep_debug_symbols_and_check_links):
+       New proc.  Checks that debug-info-only binaries retain the
+       sh_link field in stripped sections.
+
 2015-08-04  Nick Clifton  <nickc@redhat.com>
 
        * lib/utils-lib.exp (run_dump_test): Document DUMPPROG, readelf
index ae21b22ab3c2e41937bedff3e3534e7f77cc3cb9..01d2e17bf230e0458141855f2a702d59cef2dce5 100644 (file)
@@ -829,12 +829,70 @@ proc keep_debug_symbols_and_test_copy { prog1 flags1 test1 prog2 flags2 test2 }
     pass $test2
 }
 
+# Tests that in a debug only copy of a file the sections
+# headers whoes types have been changed to NOBITS still
+# retain their sh_link fields.
+
+proc keep_debug_symbols_and_check_links { prog flags test } {
+    global READELF
+
+    remote_file build delete tmpdir/striprog
+    remote_download build tmpdir/copyprog tmpdir/striprog
+    if [is_remote host] {
+       set copyfile [remote_download host tmpdir/striprog]
+    } else {
+       set copyfile tmpdir/striprog
+    }
+
+    set exec_output [binutils_run $prog "$flags ${copyfile}"]
+    if ![string match "" $exec_output] {
+       fail $test
+       return
+    }
+
+    set got [binutils_run $READELF "-S --wide ${copyfile}"]
+
+    set fails 0
+    # Regexp to match a section with NOBITS type and extract its name and sh_link fields
+    while {[regexp \
+               {[^a-zA-Z]+([a-zA-Z0-9_\.]+)[   ]+NOBITS[       ]+[0-9a-fA-F]+ [0-9a-fA-F]+ [0-9a-fA-F]+ [0-9]+[ A]+([0-9]+)(.*)} \
+               $got all name link rest]} {
+       set sh_link 0x$link
+       if {$sh_link == 0} {
+           # Only some NOBITS sections should have a non-zero sh_link field.
+           # Look for them by name.
+           verbose "NOBITS section .$name has a 0 sh_link field\n"
+           switch $name {
+               "rela.*"        { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "rel.*"         { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "hash"          { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "gnu_version"   { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "dynsym"        { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "gnu.version_r" { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "dynamic"       { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+               "symtab"        { set fails 1 ; send_log "Expected non-zero sh_link for .$name\n" }
+           }
+       }
+       set got $rest
+    }
+
+    if {$fails == 0} {
+       pass $test
+    } else {
+       fail $test
+    }
+}
+
+
 set test1 "simple objcopy of executable"
 set test2 "run objcopy of executable"
 set test3 "run stripped executable"
 set test4 "run stripped executable with saving a symbol"
 set test5 "keep only debug data"
 set test6 "simple objcopy of debug data"
+if [is_elf_format] {
+    set test7 "NOBITS sections retain sh_link field"
+}
 
 switch [copy_setup] {
     "1" {
@@ -847,6 +905,9 @@ switch [copy_setup] {
        untested $test4
        untested $test5
        untested $test6
+       if [is_elf_format] {
+           untested $test7
+       }
     }
     "3" {
        copy_executable "$OBJCOPY" "$OBJCOPYFLAGS" "$test1" ""
@@ -855,6 +916,9 @@ switch [copy_setup] {
        unsupported $test4
        unsupported $test5
        unsupported $test6
+       if [is_elf_format] {
+           unsupported $test7
+       }
     }
     "0" {
        copy_executable "$OBJCOPY" "$OBJCOPYFLAGS" "$test1" "$test2"
@@ -862,6 +926,9 @@ switch [copy_setup] {
        strip_executable_with_saving_a_symbol "$STRIP" "-K main -K _main $STRIPFLAGS" "$test4"
        keep_debug_symbols_and_test_copy "$STRIP" "--only-keep-debug $STRIPFLAGS" "$test5" \
                                         "$OBJCOPY" "$OBJCOPYFLAGS" "$test6"
+       if [is_elf_format] {
+           keep_debug_symbols_and_check_links "$STRIP" "--only-keep-debug $STRIPFLAGS" "$test7"
+       }
     }
 }