diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2018-10-11 17:20:12 +0200 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2018-10-11 17:54:03 +0200 |
commit | 5da108a40dd24c7d3e4183ec9ae1904bb3f01575 (patch) | |
tree | b3aacdcce39ec53a581137229e4a30ccb235f09d /src | |
parent | c8dd3e3985dce3ae94bb09d6df82a516852e78c4 (diff) | |
parent | 52b6b2f1f49e7385527e9f311f248092be0c0b61 (diff) |
Merge tag 'elfutils-0.174'
elfutils 0.174 release
Change-Id: Ibcbdfca61cf0b65391ab6d0ad00f18ba61027e07
Diffstat (limited to 'src')
-rw-r--r-- | src/ChangeLog | 83 | ||||
-rw-r--r-- | src/addr2line.c | 1 | ||||
-rw-r--r-- | src/ar.c | 1 | ||||
-rw-r--r-- | src/arlib.c | 2 | ||||
-rw-r--r-- | src/arlib2.c | 1 | ||||
-rw-r--r-- | src/elfcmp.c | 27 | ||||
-rw-r--r-- | src/elfcompress.c | 62 | ||||
-rw-r--r-- | src/elflint.c | 18 | ||||
-rw-r--r-- | src/findtextrel.c | 3 | ||||
-rw-r--r-- | src/nm.c | 1 | ||||
-rw-r--r-- | src/objdump.c | 1 | ||||
-rw-r--r-- | src/ranlib.c | 1 | ||||
-rw-r--r-- | src/readelf.c | 42 | ||||
-rw-r--r-- | src/size.c | 1 | ||||
-rw-r--r-- | src/stack.c | 1 | ||||
-rw-r--r-- | src/strings.c | 1 | ||||
-rw-r--r-- | src/strip.c | 128 | ||||
-rw-r--r-- | src/unstrip.c | 35 |
18 files changed, 335 insertions, 74 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d21585c9..b0db6fbd 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -26,6 +26,89 @@ 2017-05-04 Ulf Hermann <ulf.hermann@qt.io> * ar.c: Open files in O_BINARY. + +2018-09-13 Mark Wielaard <mark@klomp.org> + + * readelf.c (print_shdr): Get number of section with elf_getshdrnum. + (print_phdr): Likewise. + +2018-09-13 Mark Wielaard <mark@klomp.org> + + * strip.c (handle_elf): Check against shstrndx, not e_shstrndx. + Explicitly set shdrstrndx for debug file. + * unstrip.c (copy_elf): Explicitly copy shstrndx. + (find_alloc_sections_prelink): Document shnum usage. + +2018-09-13 Mark Wielaard <mark@klomp.org> + + * elflint.c (check_elf_header): Use shnum instead of e_shnum for all + checks. + (check_symtab): Use shstrndx instead of e_shstrndx to get section + names. + +2018-09-13 Mark Wielaard <mark@klomp.org> + + * elfcmp.c (main): Get, check and shdrstrndx for section names. + +2018-09-12 Mark Wielaard <mark@klomp.org> + + * elfcmp.c (main): Call ebl_section_strip_p without ehdr. + * strip.c (handle_elf): Likewise. + +2018-09-12 Mark Wielaard <mark@klomp.org> + + * elflint.c (check_symtab): Call ebl_check_special_symbol without + ehdr. + +2018-07-30 Mark Wielaard <mark@klomp.org> + + * strip.c (handle_elf): Track allocated/unallocated sections seen. Set + section offset of unallocated sections after handling all allocated + sections. + +2018-08-18 Mark Wielaard <mark@klomp.org> + + * readelf.c (print_debug_aranges_section): Make sure there is enough + data to read the header segment size. + +2018-08-18 Mark Wielaard <mark@klomp.org> + + * elflint.c (check_sysv_hash): Calculate needed size using unsigned + long long int to prevent overflow. + (check_sysv_hash64): Calculate maxwords used separately before + comparison to prevent overflow. + +2018-07-24 Mark Wielaard <mark@klomp.org> + + * unstrip.c (compare_unalloc_sections): Also compare sh_size. + +2018-07-21 Mark Wielaard <mark@klomp.org> + + * unstrip.c (adjust_all_relocs): Skip SHT_GROUP sections. + +2018-07-21 Mark Wielaard <mark@klomp.org> + + * elfcompress.c (get_sections): New function. + (process_file): Check whether section needs to change. Don't rewrite + file if no section data needs changing. + (main): Update 'force' help text. + +2018-07-21 Mark Wielaard <mark@klomp.org> + + * elfcompress.c (process_file): Swap fchmod and fchown calls. + +2018-07-04 Mark Wielaard <mark@klomp.org> + + * readelf.c (print_debug_addr_section): Rename index var to uidx. + (attr_callback): Rename index var to word. + (print_debug_str_offsets_section): Rename index var to uidx. + +2018-07-04 Ross Burton <ross.burton@intel.com> + + * addr2line.c: Remove error.h include. + * ar.c: Likewise. + * arlib.c: Likewise and add system.h include. + * arlib2.c: Likewise. * elfcmp.c: Likewise. * elfcompress.c: Likewise. * elflint.c: Likewise. diff --git a/src/addr2line.c b/src/addr2line.c index 7bf54321..32660f7a 100644 --- a/src/addr2line.c +++ b/src/addr2line.c @@ -23,7 +23,6 @@ #include <argp.h> #include <assert.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <inttypes.h> #include <libdwfl.h> @@ -22,7 +22,6 @@ #include <argp.h> #include <assert.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <libintl.h> diff --git a/src/arlib.c b/src/arlib.c index e0839aab..778e0878 100644 --- a/src/arlib.c +++ b/src/arlib.c @@ -21,7 +21,6 @@ #endif #include <assert.h> -#include <error.h> #include <gelf.h> #include <inttypes.h> #include <libintl.h> @@ -31,6 +30,7 @@ #include <libeu.h> +#include "system.h" #include "arlib.h" diff --git a/src/arlib2.c b/src/arlib2.c index 553fc57b..11f44e5d 100644 --- a/src/arlib2.c +++ b/src/arlib2.c @@ -20,7 +20,6 @@ # include <config.h> #endif -#include <error.h> #include <libintl.h> #include <limits.h> #include <string.h> diff --git a/src/elfcmp.c b/src/elfcmp.c index 7ca7efa3..65d02c06 100644 --- a/src/elfcmp.c +++ b/src/elfcmp.c @@ -23,7 +23,6 @@ #include <argp.h> #include <assert.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <locale.h> #include <libintl.h> @@ -36,7 +35,7 @@ #include <printversion.h> #include "../libelf/elf-knowledge.h" #include "../libebl/libeblP.h" - +#include "system.h" /* Prototypes of local functions. */ static Elf *open_file (const char *fname, int *fdp, Ebl **eblp); @@ -236,6 +235,22 @@ main (int argc, char *argv[]) DIFFERENCE; } + size_t shstrndx1; + size_t shstrndx2; + if (elf_getshdrstrndx (elf1, &shstrndx1) != 0) + error (2, 0, gettext ("cannot get hdrstrndx of '%s': %s"), + fname1, elf_errmsg (-1)); + if (elf_getshdrstrndx (elf2, &shstrndx2) != 0) + error (2, 0, gettext ("cannot get hdrstrndx of '%s': %s"), + fname2, elf_errmsg (-1)); + if (shstrndx1 != shstrndx2) + { + if (! quiet) + error (0, 0, gettext ("%s %s diff: shdr string index"), + fname1, fname2); + DIFFERENCE; + } + /* Iterate over all sections. We expect the sections in the two files to match exactly. */ Elf_Scn *scn1 = NULL; @@ -252,10 +267,10 @@ main (int argc, char *argv[]) scn1 = elf_nextscn (elf1, scn1); shdr1 = gelf_getshdr (scn1, &shdr1_mem); if (shdr1 != NULL) - sname1 = elf_strptr (elf1, ehdr1->e_shstrndx, shdr1->sh_name); + sname1 = elf_strptr (elf1, shstrndx1, shdr1->sh_name); } while (scn1 != NULL - && ebl_section_strip_p (ebl1, ehdr1, shdr1, sname1, true, false)); + && ebl_section_strip_p (ebl1, shdr1, sname1, true, false)); GElf_Shdr shdr2_mem; GElf_Shdr *shdr2; @@ -265,10 +280,10 @@ main (int argc, char *argv[]) scn2 = elf_nextscn (elf2, scn2); shdr2 = gelf_getshdr (scn2, &shdr2_mem); if (shdr2 != NULL) - sname2 = elf_strptr (elf2, ehdr2->e_shstrndx, shdr2->sh_name); + sname2 = elf_strptr (elf2, shstrndx2, shdr2->sh_name); } while (scn2 != NULL - && ebl_section_strip_p (ebl2, ehdr2, shdr2, sname2, true, false)); + && ebl_section_strip_p (ebl2, shdr2, sname2, true, false)); if (scn1 == NULL || scn2 == NULL) break; diff --git a/src/elfcompress.c b/src/elfcompress.c index 78dc27a4..1d6a9672 100644 --- a/src/elfcompress.c +++ b/src/elfcompress.c @@ -1,5 +1,5 @@ /* Compress or decompress an ELF file. - Copyright (C) 2015, 2016 Red Hat, Inc. + Copyright (C) 2015, 2016, 2018 Red Hat, Inc. This file is part of elfutils. This file is free software; you can redistribute it and/or modify @@ -18,7 +18,6 @@ #include <config.h> #include <assert.h> #include <argp.h> -#include <error.h> #include <stdbool.h> #include <stdlib.h> #include <inttypes.h> @@ -34,6 +33,7 @@ #include ELFUTILS_HEADER(ebl) #include ELFUTILS_HEADER(dwelf) #include <gelf.h> +#include "system.h" #include "libeu.h" #include "printversion.h" @@ -289,6 +289,15 @@ process_file (const char *fname) return (sections[ndx / WORD_BITS] & (1U << (ndx % WORD_BITS))) != 0; } + /* How many sections are we going to change? */ + size_t get_sections (void) + { + size_t s = 0; + for (size_t i = 0; i < shnum / WORD_BITS + 1; i++) + s += __builtin_popcount (sections[i]); + return s; + } + int cleanup (int res) { elf_end (elf); @@ -425,6 +434,9 @@ process_file (const char *fname) names change and whether there is a symbol table that might need to be adjusted be if the section header name table is changed. + If nothing needs changing, and the input and output file are the + same, we are done. + Second a collection pass that creates the Elf sections and copies the data. This pass will compress/decompress section data when needed. And it will collect all data needed if we'll need to @@ -467,7 +479,26 @@ process_file (const char *fname) if (section_name_matches (sname)) { - if (shdr->sh_type != SHT_NOBITS + if (!force && type == T_DECOMPRESS + && (shdr->sh_flags & SHF_COMPRESSED) == 0 + && strncmp (sname, ".zdebug", strlen (".zdebug")) != 0) + { + if (verbose > 0) + printf ("[%zd] %s already decompressed\n", ndx, sname); + } + else if (!force && type == T_COMPRESS_ZLIB + && (shdr->sh_flags & SHF_COMPRESSED) != 0) + { + if (verbose > 0) + printf ("[%zd] %s already compressed\n", ndx, sname); + } + else if (!force && type == T_COMPRESS_GNU + && strncmp (sname, ".zdebug", strlen (".zdebug")) == 0) + { + if (verbose > 0) + printf ("[%zd] %s already GNU compressed\n", ndx, sname); + } + else if (shdr->sh_type != SHT_NOBITS && (shdr->sh_flags & SHF_ALLOC) == 0) { set_section (ndx); @@ -521,6 +552,14 @@ process_file (const char *fname) } } + if (foutput == NULL && get_sections () == 0) + { + if (verbose > 0) + printf ("Nothing to do.\n"); + fnew = NULL; + return cleanup (0); + } + if (adjust_names) { names = dwelf_strtab_init (true); @@ -1238,17 +1277,20 @@ process_file (const char *fname) elf_end (elfnew); elfnew = NULL; -#if HAVE_DECL_FCHMOD - /* Try to match mode and owner.group of the original file. */ - if (fchmod (fdnew, st.st_mode & 07777) != 0) - if (verbose >= 0) - error (0, errno, "Couldn't fchmod %s", fnew); -#endif #if HAVE_DECL_FCHOWN + /* Try to match mode and owner.group of the original file. + Note to set suid bits we have to make sure the owner is setup + correctly first. Otherwise fchmod will drop them silently + or fchown may clear them. */ if (fchown (fdnew, st.st_uid, st.st_gid) != 0) if (verbose >= 0) error (0, errno, "Couldn't fchown %s", fnew); #endif +#if HAVE_DECL_FCHMOD + if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0) + if (verbose >= 0) + error (0, errno, "Couldn't fchmod %s", fnew); +#endif /* Finally replace the old file with the new file. */ if (foutput == NULL) @@ -1283,7 +1325,7 @@ main (int argc, char **argv) N_("Print a message for each section being (de)compressed"), 0 }, { "force", 'f', NULL, 0, - N_("Force compression of section even if it would become larger"), + N_("Force compression of section even if it would become larger or update/rewrite the file even if no section would be (de)compressed"), 0 }, { "permissive", 'p', NULL, 0, N_("Relax a few rules to handle slightly broken ELF files"), diff --git a/src/elflint.c b/src/elflint.c index 37e2def7..e6efda56 100644 --- a/src/elflint.c +++ b/src/elflint.c @@ -24,7 +24,6 @@ #include <assert.h> #include <byteswap.h> #include <endian.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <inttypes.h> @@ -542,7 +541,7 @@ invalid number of program header table entries\n")); if (ehdr->e_shentsize != 0 && ehdr->e_shentsize != sizeof (Elf64_Shdr)) ERROR (gettext ("invalid section header size: %hd\n"), ehdr->e_shentsize); - else if (ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize > size) + else if (ehdr->e_shoff + shnum * ehdr->e_shentsize > size) ERROR (gettext ("invalid section header position or size\n")); } } @@ -797,7 +796,7 @@ section [%2d] '%s': symbol %zu: function in COMMON section is nonsense\n"), st_value = sym->st_value; if (GELF_ST_TYPE (sym->st_info) != STT_TLS) { - if (! ebl_check_special_symbol (ebl, ehdr, sym, name, + if (! ebl_check_special_symbol (ebl, sym, name, destshdr)) { if (st_value - sh_addr > destshdr->sh_size) @@ -957,7 +956,7 @@ section [%2d] '%s': symbol %zu: non-local section symbol\n"), destshdr = gelf_getshdr (gscn, &destshdr_mem); assert (destshdr != NULL); const char *sname = elf_strptr (ebl->elf, - ehdr->e_shstrndx, + shstrndx, destshdr->sh_name); if (sname != NULL) { @@ -978,7 +977,7 @@ section [%2d] '%s': symbol %zu: non-local section symbol\n"), const char *sname = ((destshdr == NULL || xndx == SHN_UNDEF) ? NULL - : elf_strptr (ebl->elf, ehdr->e_shstrndx, + : elf_strptr (ebl->elf, shstrndx, destshdr->sh_name)); if (sname == NULL) { @@ -998,7 +997,7 @@ section [%2d] '%s'\n"), if (destshdr != NULL) { /* Found it. */ - if (!ebl_check_special_symbol (ebl, ehdr, sym, name, + if (!ebl_check_special_symbol (ebl, sym, name, destshdr)) { if (ehdr->e_type != ET_REL @@ -2024,7 +2023,7 @@ check_sysv_hash (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, Elf32_Word nbucket = ((Elf32_Word *) data->d_buf)[0]; Elf32_Word nchain = ((Elf32_Word *) data->d_buf)[1]; - if (shdr->sh_size < (2 + nbucket + nchain) * sizeof (Elf32_Word)) + if (shdr->sh_size < (2ULL + nbucket + nchain) * sizeof (Elf32_Word)) { ERROR (gettext ("\ section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), @@ -2078,7 +2077,10 @@ check_sysv_hash64 (Ebl *ebl, GElf_Shdr *shdr, Elf_Data *data, int idx, Elf64_Xword nbucket = ((Elf64_Xword *) data->d_buf)[0]; Elf64_Xword nchain = ((Elf64_Xword *) data->d_buf)[1]; - if (shdr->sh_size < (2 + nbucket + nchain) * sizeof (Elf64_Xword)) + uint64_t maxwords = shdr->sh_size / sizeof (Elf64_Xword); + if (maxwords < 2 + || maxwords - 2 < nbucket + || maxwords - 2 - nbucket < nchain) { ERROR (gettext ("\ section [%2d] '%s': hash table section is too small (is %ld, expected %ld)\n"), diff --git a/src/findtextrel.c b/src/findtextrel.c index 642c0237..76456195 100644 --- a/src/findtextrel.c +++ b/src/findtextrel.c @@ -23,7 +23,6 @@ #include <argp.h> #include <assert.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <libdw.h> @@ -37,7 +36,7 @@ #include <unistd.h> #include <printversion.h> - +#include "system.h" struct segments { @@ -26,7 +26,6 @@ #include <ctype.h> #include <dwarf.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <inttypes.h> diff --git a/src/objdump.c b/src/objdump.c index 0f2206de..0c7c95ab 100644 --- a/src/objdump.c +++ b/src/objdump.c @@ -21,7 +21,6 @@ #endif #include <argp.h> -#include <error.h> #include <fcntl.h> #include <inttypes.h> #include <libintl.h> diff --git a/src/ranlib.c b/src/ranlib.c index 0aab1c2c..6e78671b 100644 --- a/src/ranlib.c +++ b/src/ranlib.c @@ -24,7 +24,6 @@ #include <argp.h> #include <assert.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <libintl.h> diff --git a/src/readelf.c b/src/readelf.c index 157ead61..90a14061 100644 --- a/src/readelf.c +++ b/src/readelf.c @@ -24,7 +24,6 @@ #include <ctype.h> #include <dwarf.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <inttypes.h> @@ -1190,15 +1189,24 @@ print_shdr (Ebl *ebl, GElf_Ehdr *ehdr) size_t shstrndx; if (! print_file_header) - printf (gettext ("\ -There are %d section headers, starting at offset %#" PRIx64 ":\n\ + { + size_t sections; + if (unlikely (elf_getshdrnum (ebl->elf, §ions) < 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot get number of sections: %s"), + elf_errmsg (-1)); + + printf (gettext ("\ +There are %zd section headers, starting at offset %#" PRIx64 ":\n\ \n"), - ehdr->e_shnum, ehdr->e_shoff); + sections, ehdr->e_shoff); + } /* Get the section header string table index. */ if (unlikely (elf_getshdrstrndx (ebl->elf, &shstrndx) < 0)) error (EXIT_FAILURE, 0, - gettext ("cannot get section header string table index")); + gettext ("cannot get section header string table index: %s"), + elf_errmsg (-1)); puts (gettext ("Section Headers:")); @@ -1390,7 +1398,13 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr) } } - if (ehdr->e_shnum == 0) + size_t sections; + if (unlikely (elf_getshdrnum (ebl->elf, §ions) < 0)) + error (EXIT_FAILURE, 0, + gettext ("cannot get number of sections: %s"), + elf_errmsg (-1)); + + if (sections == 0) /* No sections in the file. Punt. */ return; @@ -5267,14 +5281,14 @@ print_debug_addr_section (Dwfl_Module *dwflmod __attribute__ ((unused)), addresses /= 10; } - unsigned int index = 0; + unsigned int uidx = 0; size_t index_offset = readp - (const unsigned char *) data->d_buf; printf (" Addresses start at offset 0x%zx:\n", index_offset); while (readp <= next_unitp - address_size) { Dwarf_Addr addr = read_addr_unaligned_inc (address_size, dbg, readp); - printf (" [%*u] ", digits, index++); + printf (" [%*u] ", digits, uidx++); print_dwarf_addr (dwflmod, address_size, addr, addr); printf ("\n"); } @@ -5453,6 +5467,8 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)), goto next_table; } + if (readp + 1 > readendp) + goto invalid_data; unsigned int segment_size = *readp++; printf (gettext (" Segment size: %6" PRIu64 "\n\n"), (uint64_t) segment_size); @@ -6972,12 +6988,12 @@ attr_callback (Dwarf_Attribute *attrp, void *arg) } if (form != DW_FORM_addr ) { - Dwarf_Word index; - if (dwarf_formudata (attrp, &index) != 0) + Dwarf_Word word; + if (dwarf_formudata (attrp, &word) != 0) goto attrval_out; printf (" %*s%-20s (%s) [%" PRIx64 "] ", (int) (level * 2), "", dwarf_attr_name (attr), - dwarf_form_name (form), index); + dwarf_form_name (form), word); } else printf (" %*s%-20s (%s) ", @@ -10261,7 +10277,7 @@ print_debug_str_offsets_section (Dwfl_Module *dwflmod __attribute__ ((unused)), offsets /= 10; } - unsigned int index = 0; + unsigned int uidx = 0; size_t index_offset = readp - (const unsigned char *) data->d_buf; printf (" Offsets start at 0x%zx:\n", index_offset); while (readp <= next_unitp - offset_size) @@ -10273,7 +10289,7 @@ print_debug_str_offsets_section (Dwfl_Module *dwflmod __attribute__ ((unused)), offset = read_8ubyte_unaligned_inc (dbg, readp); const char *str = dwarf_getstring (dbg, offset, NULL); printf (" [%*u] [%*" PRIx64 "] \"%s\"\n", - digits, index++, (int) offset_size * 2, offset, str ?: "???"); + digits, uidx++, (int) offset_size * 2, offset, str ?: "???"); } printf ("\n"); @@ -21,7 +21,6 @@ #endif #include <argp.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <inttypes.h> diff --git a/src/stack.c b/src/stack.c index 1d8b2adf..0e99ea71 100644 --- a/src/stack.c +++ b/src/stack.c @@ -18,7 +18,6 @@ #include <config.h> #include <assert.h> #include <argp.h> -#include <error.h> #include <stdlib.h> #include <inttypes.h> #include <stdio.h> diff --git a/src/strings.c b/src/strings.c index 45559f46..d4c4c9ec 100644 --- a/src/strings.c +++ b/src/strings.c @@ -25,7 +25,6 @@ #include <ctype.h> #include <endian.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <gelf.h> #include <inttypes.h> diff --git a/src/strip.c b/src/strip.c index 00d10e2a..a85a2306 100644 --- a/src/strip.c +++ b/src/strip.c @@ -24,7 +24,6 @@ #include <assert.h> #include <byteswap.h> #include <endian.h> -#include <error.h> #include <fcntl.h> #include <fnmatch.h> #include <gelf.h> @@ -654,6 +653,11 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, memset (shdr_info, '\0', (shnum + 2) * sizeof (struct shdr_info)); } + /* Track whether allocated sections all come before non-allocated ones. */ + bool seen_allocated = false; + bool seen_unallocated = false; + bool mixed_allocated_unallocated = false; + /* Prepare section information data structure. */ scn = NULL; cnt = 1; @@ -669,6 +673,17 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, if (gelf_getshdr (scn, &shdr_info[cnt].shdr) == NULL) INTERNAL_ERROR (fname); + /* Normally (in non-ET_REL files) we see all allocated sections first, + then all non-allocated. */ + if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) + seen_unallocated = true; + else + { + if (seen_unallocated && seen_allocated) + mixed_allocated_unallocated = true; + seen_allocated = true; + } + /* Get the name of the section. */ shdr_info[cnt].name = elf_strptr (elf, shstrndx, shdr_info[cnt].shdr.sh_name); @@ -794,10 +809,10 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, /* Check whether the section can be removed. Since we will create a new .shstrtab assume it will be removed too. */ if (remove_shdrs ? !(shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) - : (ebl_section_strip_p (ebl, ehdr, &shdr_info[cnt].shdr, + : (ebl_section_strip_p (ebl, &shdr_info[cnt].shdr, shdr_info[cnt].name, remove_comment, remove_debug) - || cnt == ehdr->e_shstrndx + || cnt == shstrndx || section_name_matches (remove_secs, shdr_info[cnt].name))) { /* The user might want to explicitly keep this one. */ @@ -955,7 +970,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, original table in the debug file. Unless it is a redundant data marker to a debug (data only) section. */ - if (! (ebl_section_strip_p (ebl, ehdr, + if (! (ebl_section_strip_p (ebl, &shdr_info[scnidx].shdr, shdr_info[scnidx].name, remove_comment, @@ -1058,7 +1073,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, && shdr_info[cnt].debug_data == NULL && shdr_info[cnt].shdr.sh_type != SHT_NOTE && shdr_info[cnt].shdr.sh_type != SHT_GROUP - && cnt != ehdr->e_shstrndx); + && cnt != shstrndx); /* Set the section header in the new file. */ GElf_Shdr debugshdr = shdr_info[cnt].shdr; @@ -1111,7 +1126,42 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, debugehdr->e_version = ehdr->e_version; debugehdr->e_entry = ehdr->e_entry; debugehdr->e_flags = ehdr->e_flags; - debugehdr->e_shstrndx = ehdr->e_shstrndx; + + size_t shdrstrndx; + if (elf_getshdrstrndx (elf, &shdrstrndx) < 0) + { + error (0, 0, gettext ("%s: error while getting shdrstrndx: %s"), + fname, elf_errmsg (-1)); + result = 1; + goto fail_close; + } + + if (shstrndx < SHN_LORESERVE) + debugehdr->e_shstrndx = shdrstrndx; + else + { + debugehdr->e_shstrndx = SHN_XINDEX; + Elf_Scn *scn0 = elf_getscn (debugelf, 0); + GElf_Shdr shdr0_mem; + GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem); + if (shdr0 == NULL) + { + error (0, 0, gettext ("%s: error getting zero section: %s"), + debug_fname, elf_errmsg (-1)); + result = 1; + goto fail_close; + } + + shdr0->sh_link = shdrstrndx; + if (gelf_update_shdr (scn0, shdr0) == 0) + { + error (0, 0, gettext ("%s: error while updating zero section: %s"), + debug_fname, elf_errmsg (-1)); + result = 1; + goto fail_close; + } + + } if (unlikely (gelf_update_ehdr (debugelf, debugehdr) == 0)) { @@ -1164,7 +1214,7 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, the .shstrtab section which we would add again. */ bool removing_sections = !(cnt == idx || (cnt == idx + 1 - && shdr_info[ehdr->e_shstrndx].idx == 0)); + && shdr_info[shstrndx].idx == 0)); if (output_fname == NULL && !removing_sections) goto fail_close; @@ -1528,24 +1578,58 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname, } } - /* If we have to, compute the offset of the section. */ - if (shdr_info[cnt].shdr.sh_offset == 0) - shdr_info[cnt].shdr.sh_offset - = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1) - & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1))); - - /* Set the section header in the new file. */ - if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0)) - /* There cannot be any overflows. */ - INTERNAL_ERROR (fname); + /* If we have to, compute the offset of the section. + If allocate and unallocated sections are mixed, we only update + the allocated ones now. The unallocated ones come second. */ + if (! mixed_allocated_unallocated + || (shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) != 0) + { + if (shdr_info[cnt].shdr.sh_offset == 0) + shdr_info[cnt].shdr.sh_offset + = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1) + & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1))); + + /* Set the section header in the new file. */ + if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0)) + /* There cannot be any overflows. */ + INTERNAL_ERROR (fname); - /* Remember the last section written so far. */ - GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS - ? shdr_info[cnt].shdr.sh_size : 0); - if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz) - lastoffset = shdr_info[cnt].shdr.sh_offset + filesz; + /* Remember the last section written so far. */ + GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS + ? shdr_info[cnt].shdr.sh_size : 0); + if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz) + lastoffset = shdr_info[cnt].shdr.sh_offset + filesz; + } } + /* We might have to update the unallocated sections after we done the + allocated ones. lastoffset is set to right after the last allocated + section. */ + if (mixed_allocated_unallocated) + for (cnt = 1; cnt <= shdridx; ++cnt) + if (shdr_info[cnt].idx > 0) + { + scn = elf_getscn (newelf, shdr_info[cnt].idx); + if ((shdr_info[cnt].shdr.sh_flags & SHF_ALLOC) == 0) + { + if (shdr_info[cnt].shdr.sh_offset == 0) + shdr_info[cnt].shdr.sh_offset + = ((lastoffset + shdr_info[cnt].shdr.sh_addralign - 1) + & ~((GElf_Off) (shdr_info[cnt].shdr.sh_addralign - 1))); + + /* Set the section header in the new file. */ + if (unlikely (gelf_update_shdr (scn, &shdr_info[cnt].shdr) == 0)) + /* There cannot be any overflows. */ + INTERNAL_ERROR (fname); + + /* Remember the last section written so far. */ + GElf_Off filesz = (shdr_info[cnt].shdr.sh_type != SHT_NOBITS + ? shdr_info[cnt].shdr.sh_size : 0); + if (lastoffset < shdr_info[cnt].shdr.sh_offset + filesz) + lastoffset = shdr_info[cnt].shdr.sh_offset + filesz; + } + } + /* Adjust symbol references if symbol tables changed. */ if (any_symtab_changes) /* Find all relocation sections which use this symbol table. */ diff --git a/src/unstrip.c b/src/unstrip.c index d8adf2f9..ae37d576 100644 --- a/src/unstrip.c +++ b/src/unstrip.c @@ -31,7 +31,6 @@ #include <argp.h> #include <assert.h> #include <errno.h> -#include <error.h> #include <fcntl.h> #include <fnmatch.h> #include <libintl.h> @@ -48,6 +47,7 @@ #include <gelf.h> #include <libebl.h> #include <libdwfl.h> +#include "system.h" #include "libdwelf.h" #include "libeu.h" #include "printversion.h" @@ -239,8 +239,27 @@ copy_elf (Elf *outelf, Elf *inelf) ELF_CHECK (gelf_newehdr (outelf, gelf_getclass (inelf)), _("cannot create ELF header: %s")); + size_t shstrndx; + ELF_CHECK (elf_getshdrstrndx (inelf, &shstrndx) == 0, + _("cannot get shdrstrndx:%s")); + GElf_Ehdr ehdr_mem; GElf_Ehdr *ehdr = gelf_getehdr (inelf, &ehdr_mem); + if (shstrndx < SHN_LORESERVE) + ehdr->e_shstrndx = shstrndx; + else + { + ehdr->e_shstrndx = SHN_XINDEX; + Elf_Scn *scn0 = elf_getscn (outelf, 0); + GElf_Shdr shdr0_mem; + GElf_Shdr *shdr0 = gelf_getshdr (scn0, &shdr0_mem); + ELF_CHECK (shdr0 != NULL, + _("cannot get new zero section: %s")); + shdr0->sh_link = shstrndx; + ELF_CHECK (gelf_update_shdr (scn0, shdr0), + _("cannot update new zero section: %s")); + } + ELF_CHECK (gelf_update_ehdr (outelf, ehdr), _("cannot copy ELF header: %s")); @@ -564,7 +583,11 @@ adjust_all_relocs (Elf *elf, Elf_Scn *symtab, const GElf_Shdr *symshdr, GElf_Shdr shdr_mem; GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem); ELF_CHECK (shdr != NULL, _("cannot get section header: %s")); - if (shdr->sh_type != SHT_NOBITS && shdr->sh_link == new_sh_link) + /* Don't redo SHT_GROUP, groups are in both the stripped and debug, + it will already have been done by adjust_relocs for the + stripped_symtab. */ + if (shdr->sh_type != SHT_NOBITS && shdr->sh_type != SHT_GROUP + && shdr->sh_link == new_sh_link) adjust_relocs (scn, scn, shdr, map, symshdr); } } @@ -706,6 +729,12 @@ compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2, if (shdr1->sh_flags > shdr2->sh_flags) return 1; + /* Sizes should be the same. */ + if (shdr1->sh_size < shdr2->sh_size) + return -1; + if (shdr1->sh_size > shdr2->sh_size) + return 1; + /* Sort by name as last resort. */ return strcmp (name1, name2); } @@ -1016,7 +1045,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab, _("cannot read '.gnu.prelink_undo' section: %s")); uint_fast16_t phnum; - uint_fast16_t shnum; + uint_fast16_t shnum; /* prelink doesn't handle > SHN_LORESERVE. */ if (ehdr.e32.e_ident[EI_CLASS] == ELFCLASS32) { phnum = ehdr.e32.e_phnum; |