From 63b9bbb7d7bcdcb6e0f59dd8da9615d80c537b8d Mon Sep 17 00:00:00 2001 From: Nick Clifton Date: Wed, 5 Aug 2015 16:16:39 +0100 Subject: [PATCH] Change the behaviour of the --only-keep-debug option to objcopy and strip so that the sh_link and sh_info fields in stripped section headers are preserved. 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 | 6 ++ bfd/elf.c | 57 ++++++++++++++++++ binutils/ChangeLog | 6 ++ binutils/doc/binutils.texi | 17 +++++- binutils/testsuite/ChangeLog | 6 ++ binutils/testsuite/binutils-all/objcopy.exp | 67 +++++++++++++++++++++ 6 files changed, 157 insertions(+), 2 deletions(-) diff --git a/bfd/ChangeLog b/bfd/ChangeLog index a8b3646cfe4..601ce3b5f58 100644 --- a/bfd/ChangeLog +++ b/bfd/ChangeLog @@ -1,3 +1,9 @@ +2015-08-05 Nick Clifton + + * 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" Tyler Hicks diff --git a/bfd/elf.c b/bfd/elf.c index 05ee0255d91..67e4240dac1 100644 --- 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; } diff --git a/binutils/ChangeLog b/binutils/ChangeLog index 33c5e7d794c..0b5ff7f569c 100644 --- a/binutils/ChangeLog +++ b/binutils/ChangeLog @@ -1,3 +1,9 @@ +2015-08-05 Nick Clifton + + * 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" Tyler Hicks diff --git a/binutils/doc/binutils.texi b/binutils/doc/binutils.texi index 466f1257229..fef5f3edf7a 100644 --- a/binutils/doc/binutils.texi +++ b/binutils/doc/binutils.texi @@ -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 diff --git a/binutils/testsuite/ChangeLog b/binutils/testsuite/ChangeLog index 1076ca7d079..9255fb901e8 100644 --- a/binutils/testsuite/ChangeLog +++ b/binutils/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2015-08-05 Nick Clifton + + * 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 * lib/utils-lib.exp (run_dump_test): Document DUMPPROG, readelf diff --git a/binutils/testsuite/binutils-all/objcopy.exp b/binutils/testsuite/binutils-all/objcopy.exp index ae21b22ab3c..01d2e17bf23 100644 --- a/binutils/testsuite/binutils-all/objcopy.exp +++ b/binutils/testsuite/binutils-all/objcopy.exp @@ -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" + } } } -- 2.30.2