diff options
| author | Mark Wielaard <[email protected]> | 2018-09-14 12:28:58 +0200 |
|---|---|---|
| committer | Mark Wielaard <[email protected]> | 2018-09-14 12:28:58 +0200 |
| commit | 029c76f0d4b06584e370b5fc0112712ba99a6219 (patch) | |
| tree | 20c91ff0dc7125251b26ded357e71c542b67d5cc /src | |
| parent | 94c975eefdfbfa9319b7bab69600c76fe6be7910 (diff) | |
| parent | 52b6b2f1f49e7385527e9f311f248092be0c0b61 (diff) | |
Merge branch 'master' into mjw/RH-DTSdts-0.174
elfutils 0.174 release
Removed new M68K and RISCV tests.
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 95 | ||||
| -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 | 58 | ||||
| -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, 345 insertions, 72 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index 6d962bbb..6a702ee1 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,98 @@ +2018-09-13 Mark Wielaard <[email protected]> + + * readelf.c (print_shdr): Get number of section with elf_getshdrnum. + (print_phdr): Likewise. + +2018-09-13 Mark Wielaard <[email protected]> + + * 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 <[email protected]> + + * 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 <[email protected]> + + * elfcmp.c (main): Get, check and shdrstrndx for section names. + +2018-09-12 Mark Wielaard <[email protected]> + + * elfcmp.c (main): Call ebl_section_strip_p without ehdr. + * strip.c (handle_elf): Likewise. + +2018-09-12 Mark Wielaard <[email protected]> + + * elflint.c (check_symtab): Call ebl_check_special_symbol without + ehdr. + +2018-07-30 Mark Wielaard <[email protected]> + + * 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 <[email protected]> + + * readelf.c (print_debug_aranges_section): Make sure there is enough + data to read the header segment size. + +2018-08-18 Mark Wielaard <[email protected]> + + * 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 <[email protected]> + + * unstrip.c (compare_unalloc_sections): Also compare sh_size. + +2018-07-21 Mark Wielaard <[email protected]> + + * unstrip.c (adjust_all_relocs): Skip SHT_GROUP sections. + +2018-07-21 Mark Wielaard <[email protected]> + + * 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 <[email protected]> + + * elfcompress.c (process_file): Swap fchmod and fchown calls. + +2018-07-04 Mark Wielaard <[email protected]> + + * 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 <[email protected]> + + * 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. + * findtextrel.c: Likewise. + * nm.c: Likewise. + * objdump.c: Likewise. + * ranlib.c: Likewise. + * readelf.c: Likewise. + * stack.c: Likewise. + * strings.c: Likewise. + * strip.c: Likewise. + * unstrip.c: Likewise. + 2018-06-25 Mark Wielaard <[email protected]> * readelf.c (print_decoded_line_section): Use dwarf_next_lines diff --git a/src/addr2line.c b/src/addr2line.c index 5acafa00..b7eb893e 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 50464207..d5dc1ff2 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 25378a45..6ba6af41 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" @@ -286,6 +286,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); @@ -422,6 +431,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 @@ -464,7 +476,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); @@ -518,6 +549,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); @@ -1235,13 +1274,16 @@ process_file (const char *fname) elf_end (elfnew); elfnew = NULL; - /* Try to match mode and owner.group of the original file. */ - if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0) - if (verbose >= 0) - error (0, errno, "Couldn't fchmod %s", fnew); + /* 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); + if (fchmod (fdnew, st.st_mode & ALLPERMS) != 0) + if (verbose >= 0) + error (0, errno, "Couldn't fchmod %s", fnew); /* Finally replace the old file with the new file. */ if (foutput == NULL) @@ -1276,7 +1318,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 0a26d97d..3d445954 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 8f1e239a..49731592 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 0dd9a6aa..6b365d5c 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 cc0ee233..b9083484 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 faed61a6..bddcd703 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> @@ -1185,15 +1184,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:")); @@ -1385,7 +1393,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; @@ -5262,14 +5276,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"); } @@ -5448,6 +5462,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); @@ -6967,12 +6983,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) ", @@ -10256,7 +10272,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) @@ -10268,7 +10284,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 52ae3a86..c5f347e1 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 03d0f133..ef40d5ec 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 773ed548..4a3db1b5 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> @@ -662,6 +661,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; @@ -677,6 +681,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); @@ -802,10 +817,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. */ @@ -963,7 +978,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, @@ -1066,7 +1081,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; @@ -1119,7 +1134,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)) { @@ -1172,7 +1222,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; @@ -1536,24 +1586,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 f368e696..e6f09478 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")); @@ -563,7 +582,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); } } @@ -705,6 +728,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); } @@ -1015,7 +1044,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; |
