From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 98075 invoked by alias); 26 Oct 2018 21:59:24 -0000 Mailing-List: contact elfutils-devel-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Post: List-Help: List-Subscribe: Sender: elfutils-devel-owner@sourceware.org Received: (qmail 98062 invoked by uid 89); 26 Oct 2018 21:59:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Checked: by ClamAV 0.100.1 on sourceware.org X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 spammy=23558, 24187, discard X-Spam-Status: No, score=-26.9 required=5.0 tests=BAYES_00,GIT_PATCH_0,GIT_PATCH_1,GIT_PATCH_2,GIT_PATCH_3,RCVD_IN_DNSWL_NONE,SPF_PASS autolearn=ham version=3.3.2 X-Spam-Checker-Version: SpamAssassin 3.3.2 (2011-06-06) on sourceware.org X-Spam-Level: X-HELO: gnu.wildebeest.org Received: from wildebeest.demon.nl (HELO gnu.wildebeest.org) (212.238.236.112) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 26 Oct 2018 21:59:21 +0000 Received: from tarox.wildebeest.org (tarox.wildebeest.org [172.31.17.39]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by gnu.wildebeest.org (Postfix) with ESMTPSA id 535953301E13; Fri, 26 Oct 2018 23:51:01 +0200 (CEST) Received: by tarox.wildebeest.org (Postfix, from userid 1000) id 4EED246765F7; Fri, 26 Oct 2018 23:51:01 +0200 (CEST) From: Mark Wielaard To: elfutils-devel@sourceware.org Cc: Mark Wielaard Subject: [PATCH 4/4] strip: Add --reloc-debug-sections-only option. Date: Fri, 26 Oct 2018 21:59:00 -0000 Message-Id: <1540590644-22290-5-git-send-email-mark@klomp.org> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1540590644-22290-1-git-send-email-mark@klomp.org> References: <1540590644-22290-1-git-send-email-mark@klomp.org> X-Spam-Flag: NO X-IsSubscribed: yes X-SW-Source: 2018-q4/txt/msg00085.txt.bz2 This option does the same thing as --reloc-debug-sections without doing any other strip operation. This is useful when you want to remove the debug section relocations in a separate ET_REL debug file that was created without --reloc-debug-sections, or for a file (like the linux debug vmlinux) that you don't want to strip, but for which the debug section relocations can be resolved already. Signed-off-by: Mark Wielaard --- src/ChangeLog | 11 ++++ src/strip.c | 155 +++++++++++++++++++++++++++++++++++++++++++++-- tests/ChangeLog | 4 ++ tests/run-strip-reloc.sh | 11 ++++ 4 files changed, 175 insertions(+), 6 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 766c839..0eed9ae 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,14 @@ +2018-10-26 Mark Wielaard + + * strip.c (OPT_RELOC_DEBUG_ONLY): New define. + (options): Add reloc-debug-sections-only. + (reloc_debug_only): New static bool. + (main): Check reloc_debug_only is the only strip option used. + (parse_opt): Handle OPT_RELOC_DEBUG_ONLY. + (handle_debug_relocs): New function. + (handle_elf): Add local variables lastsec_offset and lastsec_size. + Handle reloc_debug_only. + 2018-10-24 Mark Wielaard * strip.c (handle_elf): Extract code to update shdrstrndx into... diff --git a/src/strip.c b/src/strip.c index 1151206..e953c4d 100644 --- a/src/strip.c +++ b/src/strip.c @@ -1,5 +1,5 @@ /* Discard section not used at runtime from object files. - Copyright (C) 2000-2012, 2014, 2015, 2016, 2017 Red Hat, Inc. + Copyright (C) 2000-2012, 2014, 2015, 2016, 2017, 2018 Red Hat, Inc. This file is part of elfutils. Written by Ulrich Drepper , 2000. @@ -61,6 +61,7 @@ ARGP_PROGRAM_BUG_ADDRESS_DEF = PACKAGE_BUGREPORT; #define OPT_STRIP_SECTIONS 0x102 #define OPT_RELOC_DEBUG 0x103 #define OPT_KEEP_SECTION 0x104 +#define OPT_RELOC_DEBUG_ONLY 0x105 /* Definitions of arguments for argp functions. */ @@ -82,6 +83,8 @@ static const struct argp_option options[] = N_("Copy modified/access timestamps to the output"), 0 }, { "reloc-debug-sections", OPT_RELOC_DEBUG, NULL, 0, N_("Resolve all trivial relocations between debug sections if the removed sections are placed in a debug file (only relevant for ET_REL files, operation is not reversable, needs -f)"), 0 }, + { "reloc-debug-sections-only", OPT_RELOC_DEBUG_ONLY, NULL, 0, + N_("Similar to --reloc-debug-sections, but resolve all trivial relocations between debug sections in place. No other stripping is performed (operation is not reversable, incompatible with -f, -g, --remove-comment and --remove-section)"), 0 }, { "remove-comment", OPT_REMOVE_COMMENT, NULL, 0, N_("Remove .comment section"), 0 }, { "remove-section", 'R', "SECTION", 0, N_("Remove the named section. SECTION is an extended wildcard pattern. May be given more than once. Only non-allocated sections can be removed."), 0 }, @@ -159,6 +162,9 @@ static bool permissive; /* If true perform relocations between debug sections. */ static bool reloc_debug; +/* If true perform relocations between debug sections only. */ +static bool reloc_debug_only; + /* Sections the user explicitly wants to keep or remove. */ struct section_pattern { @@ -240,6 +246,12 @@ main (int argc, char *argv[]) error (EXIT_FAILURE, 0, gettext ("--reloc-debug-sections used without -f")); + if (reloc_debug_only && + (debug_fname != NULL || remove_secs != NULL + || remove_comment == true || remove_debug == true)) + error (EXIT_FAILURE, 0, + gettext ("--reloc-debug-sections-only incompatible with -f, -g, --remove-comment and --remove-section")); + /* Tell the library which version we are expecting. */ elf_version (EV_CURRENT); @@ -307,6 +319,10 @@ parse_opt (int key, char *arg, struct argp_state *state) reloc_debug = true; break; + case OPT_RELOC_DEBUG_ONLY: + reloc_debug_only = true; + break; + case OPT_REMOVE_COMMENT: remove_comment = true; break; @@ -774,6 +790,116 @@ process_file (const char *fname) return result; } +/* Processing for --reloc-debug-sections-only. */ +static int +handle_debug_relocs (Elf *elf, Ebl *ebl, Elf *new_elf, + GElf_Ehdr *ehdr, const char *fname, size_t shstrndx, + GElf_Off *last_offset, GElf_Xword *last_size) +{ + + /* Copy over the ELF header. */ + if (gelf_update_ehdr (new_elf, ehdr) == 0) + { + error (0, 0, "couldn't update new ehdr: %s", elf_errmsg (-1)); + return 1; + } + + /* Copy over sections and record end of allocated sections. */ + GElf_Off lastoffset = 0; + Elf_Scn *scn = NULL; + while ((scn = elf_nextscn (elf, scn)) != NULL) + { + /* Get the header. */ + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) == NULL) + { + error (0, 0, "couldn't get shdr: %s", elf_errmsg (-1)); + return 1; + } + + /* Create new section. */ + Elf_Scn *new_scn = elf_newscn (new_elf); + if (new_scn == NULL) + { + error (0, 0, "couldn't create new section: %s", elf_errmsg (-1)); + return 1; + } + + if (gelf_update_shdr (new_scn, &shdr) == 0) + { + error (0, 0, "couldn't update shdr: %s", elf_errmsg (-1)); + return 1; + } + + /* Copy over section data. */ + Elf_Data *data = NULL; + while ((data = elf_getdata (scn, data)) != NULL) + { + Elf_Data *new_data = elf_newdata (new_scn); + if (new_data == NULL) + { + error (0, 0, "couldn't create new section data: %s", + elf_errmsg (-1)); + return 1; + } + *new_data = *data; + } + + /* Record last offset of allocated section. */ + if ((shdr.sh_flags & SHF_ALLOC) != 0) + { + GElf_Off filesz = (shdr.sh_type != SHT_NOBITS + ? shdr.sh_size : 0); + if (lastoffset < shdr.sh_offset + filesz) + lastoffset = shdr.sh_offset + filesz; + } + } + + /* Make sure section header name table is setup correctly, we'll + need it to determine whether to relocate sections. */ + if (update_shdrstrndx (new_elf, shstrndx) != 0) + { + error (0, 0, "error updating shdrstrndx: %s", elf_errmsg (-1)); + return 1; + } + + /* Adjust the relocation sections. */ + remove_debug_relocations (ebl, new_elf, ehdr, fname, shstrndx); + + /* Adjust the offsets of the non-allocated sections, so they come after + the allocated sections. */ + scn = NULL; + while ((scn = elf_nextscn (new_elf, scn)) != NULL) + { + /* Get the header. */ + GElf_Shdr shdr; + if (gelf_getshdr (scn, &shdr) == NULL) + { + error (0, 0, "couldn't get shdr: %s", elf_errmsg (-1)); + return 1; + } + + /* Adjust non-allocated section offsets to be after any allocated. */ + if ((shdr.sh_flags & SHF_ALLOC) == 0) + { + shdr.sh_offset = ((lastoffset + shdr.sh_addralign - 1) + & ~((GElf_Off) (shdr.sh_addralign - 1))); + if (gelf_update_shdr (scn, &shdr) == 0) + { + error (0, 0, "couldn't update shdr: %s", elf_errmsg (-1)); + return 1; + } + + GElf_Off filesz = (shdr.sh_type != SHT_NOBITS + ? shdr.sh_size : 0); + lastoffset = shdr.sh_offset + filesz; + *last_offset = shdr.sh_offset; + *last_size = filesz; + } + } + + return 0; +} /* Maximum size of array allocated on stack. */ #define MAX_STACK_ALLOC (400 * 1024) @@ -790,6 +916,8 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, tmp_debug_fname = NULL; int result = 0; size_t shdridx = 0; + GElf_Off lastsec_offset = 0; + Elf64_Xword lastsec_size = 0; size_t shstrndx; struct shdr_info { @@ -848,7 +976,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, the --reloc-debug-sections option are currently the only reasons we need EBL so don't open the backend unless necessary. */ Ebl *ebl = NULL; - if (remove_debug || reloc_debug) + if (remove_debug || reloc_debug || reloc_debug_only) { ebl = ebl_openbackend (elf); if (ebl == NULL) @@ -937,6 +1065,18 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } } + if (reloc_debug_only) + { + if (handle_debug_relocs (elf, ebl, newelf, ehdr, fname, shstrndx, + &lastsec_offset, &lastsec_size) != 0) + { + result = 1; + goto fail_close; + } + idx = shstrndx; + goto done; /* Skip all actual stripping operations. */ + } + if (debug_fname != NULL) { /* Also create an ELF descriptor for the debug file */ @@ -2339,6 +2479,10 @@ while computing checksum for debug information")); } } + lastsec_offset = shdr_info[shdridx].shdr.sh_offset; + lastsec_size = shdr_info[shdridx].shdr.sh_size; + + done: /* Finally finish the ELF header. Fill in the fields not handled by libelf from the old file. */ newehdr = gelf_getehdr (newelf, &newehdr_mem); @@ -2355,8 +2499,7 @@ while computing checksum for debug information")); /* We need to position the section header table. */ const size_t offsize = gelf_fsize (elf, ELF_T_OFF, 1, EV_CURRENT); - newehdr->e_shoff = ((shdr_info[shdridx].shdr.sh_offset - + shdr_info[shdridx].shdr.sh_size + offsize - 1) + newehdr->e_shoff = ((lastsec_offset + lastsec_size + offsize - 1) & ~((GElf_Off) (offsize - 1))); newehdr->e_shentsize = gelf_fsize (elf, ELF_T_SHDR, 1, EV_CURRENT); @@ -2418,7 +2561,7 @@ while computing checksum for debug information")); || (pwrite_retry (fd, zero, sizeof zero, offsetof (Elf32_Ehdr, e_shentsize)) != sizeof zero) - || ftruncate (fd, shdr_info[shdridx].shdr.sh_offset) < 0) + || ftruncate (fd, lastsec_offset) < 0) { error (0, errno, gettext ("while writing '%s'"), output_fname ?: fname); @@ -2438,7 +2581,7 @@ while computing checksum for debug information")); || (pwrite_retry (fd, zero, sizeof zero, offsetof (Elf64_Ehdr, e_shentsize)) != sizeof zero) - || ftruncate (fd, shdr_info[shdridx].shdr.sh_offset) < 0) + || ftruncate (fd, lastsec_offset) < 0) { error (0, errno, gettext ("while writing '%s'"), output_fname ?: fname); diff --git a/tests/ChangeLog b/tests/ChangeLog index 751a081..0870d4c 100644 --- a/tests/ChangeLog +++ b/tests/ChangeLog @@ -1,3 +1,7 @@ +2018-10-26 Mark Wielaard + + * run-strip-reloc.sh: Add a test for --reloc-debug-sections-only. + 2018-10-12 Mark Wielaard * run-readelf-zdebug.sh: Adjust flags output. diff --git a/tests/run-strip-reloc.sh b/tests/run-strip-reloc.sh index bbc9f58..6e54ab4 100755 --- a/tests/run-strip-reloc.sh +++ b/tests/run-strip-reloc.sh @@ -32,6 +32,8 @@ runtest() { outfile2=out.stripped2 debugfile2=out.debug2 + echo "runtest $infile" + rm -f $outfile1 $debugfile1 $outfile2 $debugfile2 testrun ${abs_top_builddir}/src/strip -o $outfile1 -f $debugfile1 $infile || @@ -67,6 +69,15 @@ runtest() { testrun_compare cat readelf.out1 < readelf.out2 || { echo "*** failure readelf -w compare $infile"; status=1; } + + testrun ${abs_top_builddir}/src/strip --reloc-debug-sections-only \ + $debugfile1 || + { echo "*** failure strip --reloc-debug-sections-only $debugfile1"; \ + status=1; } + + cmp $debugfile1 $debugfile2 || + { echo "*** failure --reloc-debug-sections[-only] $debugfile1 $debugfile2"; \ + status=1; } } # Most simple hello world kernel module for various architectures. -- 1.8.3.1