summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorUlf Hermann <ulf.hermann@qt.io>2018-10-11 17:20:12 +0200
committerUlf Hermann <ulf.hermann@qt.io>2018-10-11 17:54:03 +0200
commit5da108a40dd24c7d3e4183ec9ae1904bb3f01575 (patch)
treeb3aacdcce39ec53a581137229e4a30ccb235f09d /src
parentc8dd3e3985dce3ae94bb09d6df82a516852e78c4 (diff)
parent52b6b2f1f49e7385527e9f311f248092be0c0b61 (diff)
Merge tag 'elfutils-0.174'
elfutils 0.174 release Change-Id: Ibcbdfca61cf0b65391ab6d0ad00f18ba61027e07
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog83
-rw-r--r--src/addr2line.c1
-rw-r--r--src/ar.c1
-rw-r--r--src/arlib.c2
-rw-r--r--src/arlib2.c1
-rw-r--r--src/elfcmp.c27
-rw-r--r--src/elfcompress.c62
-rw-r--r--src/elflint.c18
-rw-r--r--src/findtextrel.c3
-rw-r--r--src/nm.c1
-rw-r--r--src/objdump.c1
-rw-r--r--src/ranlib.c1
-rw-r--r--src/readelf.c42
-rw-r--r--src/size.c1
-rw-r--r--src/stack.c1
-rw-r--r--src/strings.c1
-rw-r--r--src/strip.c128
-rw-r--r--src/unstrip.c35
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>
diff --git a/src/ar.c b/src/ar.c
index bec68876..44edbd35 100644
--- a/src/ar.c
+++ b/src/ar.c
@@ -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
{
diff --git a/src/nm.c b/src/nm.c
index 6ab22b25..cd9df51c 100644
--- a/src/nm.c
+++ b/src/nm.c
@@ -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, &sections) < 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, &sections) < 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");
diff --git a/src/size.c b/src/size.c
index 9e5c20a1..d9b98672 100644
--- a/src/size.c
+++ b/src/size.c
@@ -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;