227 lines
8.1 KiB
Diff
227 lines
8.1 KiB
Diff
commit c06ab0bbb4761a69d2f188675d21d1a9131e9ecb
|
|
Author: Mark Wielaard <mark@klomp.org>
|
|
Date: Sat Oct 13 10:27:47 2018 +0200
|
|
|
|
strip, unstrip: Handle SHT_GROUP correctly.
|
|
|
|
The usage of annobin in Fedora showed a couple of bugs when using
|
|
eu-strip and eu-unstrip on ET_REL files that contain multiple group
|
|
sections.
|
|
|
|
When stripping we should not remove the SHF_GROUP flag from sections
|
|
even if the group section itself might be removed. Either the section
|
|
itself gets removed, and so the flag doesn't matter. Or it gets moved
|
|
together with the group section into the debug file, and then it still
|
|
needs to have the flag set. Also we would "renumber" the section group
|
|
flag field (which isn't a section index, and so shouldn't be changed).
|
|
|
|
Often the group sections have the exact same name (".group"), flags
|
|
(none) and sometimes the same sizes. Which makes matching them hard.
|
|
Extract the group signature and compare those when comparing two
|
|
group sections.
|
|
|
|
Signed-off-by: Mark Wielaard <mark@klomp.org>
|
|
|
|
diff --git a/src/strip.c b/src/strip.c
|
|
index 1f7b3ca..fdebc5e 100644
|
|
--- a/src/strip.c
|
|
+++ b/src/strip.c
|
|
@@ -792,9 +792,13 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
|
|
|
|
if (shdr_info[shdr_info[cnt].group_idx].idx == 0)
|
|
{
|
|
- /* The section group section will be removed. */
|
|
+ /* The section group section might be removed.
|
|
+ Don't remove the SHF_GROUP flag. The section is
|
|
+ either also removed, in which case the flag doesn't matter.
|
|
+ Or it moves with the group into the debug file, then
|
|
+ it will be reconnected with the new group and should
|
|
+ still have the flag set. */
|
|
shdr_info[cnt].group_idx = 0;
|
|
- shdr_info[cnt].shdr.sh_flags &= ~SHF_GROUP;
|
|
}
|
|
}
|
|
|
|
@@ -1368,7 +1372,9 @@ handle_elf (int fd, Elf *elf, const char *prefix, const char *fname,
|
|
&& shdr_info[cnt].data->d_buf != NULL);
|
|
|
|
Elf32_Word *grpref = (Elf32_Word *) shdr_info[cnt].data->d_buf;
|
|
- for (size_t inner = 0;
|
|
+ /* First word is the section group flag.
|
|
+ Followed by section indexes, that need to be renumbered. */
|
|
+ for (size_t inner = 1;
|
|
inner < shdr_info[cnt].data->d_size / sizeof (Elf32_Word);
|
|
++inner)
|
|
if (grpref[inner] < shnum)
|
|
diff --git a/src/unstrip.c b/src/unstrip.c
|
|
index e6f0947..03a0346 100644
|
|
--- a/src/unstrip.c
|
|
+++ b/src/unstrip.c
|
|
@@ -696,6 +696,7 @@ struct section
|
|
{
|
|
Elf_Scn *scn;
|
|
const char *name;
|
|
+ const char *sig;
|
|
Elf_Scn *outscn;
|
|
Dwelf_Strent *strent;
|
|
GElf_Shdr shdr;
|
|
@@ -720,7 +721,8 @@ compare_alloc_sections (const struct section *s1, const struct section *s2,
|
|
|
|
static int
|
|
compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
|
|
- const char *name1, const char *name2)
|
|
+ const char *name1, const char *name2,
|
|
+ const char *sig1, const char *sig2)
|
|
{
|
|
/* Sort by sh_flags as an arbitrary ordering. */
|
|
if (shdr1->sh_flags < shdr2->sh_flags)
|
|
@@ -734,6 +736,10 @@ compare_unalloc_sections (const GElf_Shdr *shdr1, const GElf_Shdr *shdr2,
|
|
if (shdr1->sh_size > shdr2->sh_size)
|
|
return 1;
|
|
|
|
+ /* Are they both SHT_GROUP sections? Then compare signatures. */
|
|
+ if (sig1 != NULL && sig2 != NULL)
|
|
+ return strcmp (sig1, sig2);
|
|
+
|
|
/* Sort by name as last resort. */
|
|
return strcmp (name1, name2);
|
|
}
|
|
@@ -751,7 +757,8 @@ compare_sections (const void *a, const void *b, bool rel)
|
|
return ((s1->shdr.sh_flags & SHF_ALLOC)
|
|
? compare_alloc_sections (s1, s2, rel)
|
|
: compare_unalloc_sections (&s1->shdr, &s2->shdr,
|
|
- s1->name, s2->name));
|
|
+ s1->name, s2->name,
|
|
+ s1->sig, s2->sig));
|
|
}
|
|
|
|
static int
|
|
@@ -986,6 +993,44 @@ get_section_name (size_t ndx, const GElf_Shdr *shdr, const Elf_Data *shstrtab)
|
|
return shstrtab->d_buf + shdr->sh_name;
|
|
}
|
|
|
|
+/* Returns the signature of a group section, or NULL if the given
|
|
+ section isn't a group. */
|
|
+static const char *
|
|
+get_group_sig (Elf *elf, GElf_Shdr *shdr)
|
|
+{
|
|
+ if (shdr->sh_type != SHT_GROUP)
|
|
+ return NULL;
|
|
+
|
|
+ Elf_Scn *symscn = elf_getscn (elf, shdr->sh_link);
|
|
+ if (symscn == NULL)
|
|
+ error (EXIT_FAILURE, 0, _("bad sh_link for group section: %s"),
|
|
+ elf_errmsg (-1));
|
|
+
|
|
+ GElf_Shdr symshdr_mem;
|
|
+ GElf_Shdr *symshdr = gelf_getshdr (symscn, &symshdr_mem);
|
|
+ if (symshdr == NULL)
|
|
+ error (EXIT_FAILURE, 0, _("couldn't get shdr for group section: %s"),
|
|
+ elf_errmsg (-1));
|
|
+
|
|
+ Elf_Data *symdata = elf_getdata (symscn, NULL);
|
|
+ if (symdata == NULL)
|
|
+ error (EXIT_FAILURE, 0, _("bad data for group symbol section: %s"),
|
|
+ elf_errmsg (-1));
|
|
+
|
|
+ GElf_Sym sym_mem;
|
|
+ GElf_Sym *sym = gelf_getsym (symdata, shdr->sh_info, &sym_mem);
|
|
+ if (sym == NULL)
|
|
+ error (EXIT_FAILURE, 0, _("couldn't get symbol for group section: %s"),
|
|
+ elf_errmsg (-1));
|
|
+
|
|
+ const char *sig = elf_strptr (elf, symshdr->sh_link, sym->st_name);
|
|
+ if (sig == NULL)
|
|
+ error (EXIT_FAILURE, 0, _("bad symbol name for group section: %s"),
|
|
+ elf_errmsg (-1));
|
|
+
|
|
+ return sig;
|
|
+}
|
|
+
|
|
/* Fix things up when prelink has moved some allocated sections around
|
|
and the debuginfo file's section headers no longer match up.
|
|
This fills in SECTIONS[0..NALLOC-1].outscn or exits.
|
|
@@ -1111,6 +1156,7 @@ find_alloc_sections_prelink (Elf *debug, Elf_Data *debug_shstrtab,
|
|
sec->scn = elf_getscn (main, i + 1); /* Really just for ndx. */
|
|
sec->outscn = NULL;
|
|
sec->strent = NULL;
|
|
+ sec->sig = get_group_sig (main, &sec->shdr);
|
|
++undo_nalloc;
|
|
}
|
|
}
|
|
@@ -1336,6 +1382,7 @@ more sections in stripped file than debug file -- arguments reversed?"));
|
|
sections[i].scn = scn;
|
|
sections[i].outscn = NULL;
|
|
sections[i].strent = NULL;
|
|
+ sections[i].sig = get_group_sig (stripped, shdr);
|
|
}
|
|
|
|
const struct section *stripped_symtab = NULL;
|
|
@@ -1354,7 +1401,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
|
|
|
|
/* Locate a matching unallocated section in SECTIONS. */
|
|
inline struct section *find_unalloc_section (const GElf_Shdr *shdr,
|
|
- const char *name)
|
|
+ const char *name,
|
|
+ const char *sig)
|
|
{
|
|
size_t l = nalloc, u = stripped_shnum - 1;
|
|
while (l < u)
|
|
@@ -1362,7 +1410,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
|
|
size_t i = (l + u) / 2;
|
|
struct section *sec = §ions[i];
|
|
int cmp = compare_unalloc_sections (shdr, &sec->shdr,
|
|
- name, sec->name);
|
|
+ name, sec->name,
|
|
+ sig, sec->sig);
|
|
if (cmp < 0)
|
|
u = i;
|
|
else if (cmp > 0)
|
|
@@ -1435,7 +1484,8 @@ more sections in stripped file than debug file -- arguments reversed?"));
|
|
else
|
|
{
|
|
/* Look for the section that matches. */
|
|
- sec = find_unalloc_section (shdr, name);
|
|
+ sec = find_unalloc_section (shdr, name,
|
|
+ get_group_sig (unstripped, shdr));
|
|
if (sec == NULL)
|
|
{
|
|
/* An additional unallocated section is fine if not SHT_NOBITS.
|
|
|
|
commit eee4269e53154daaf0251371aacd91ec5db3eb30
|
|
Author: Mark Wielaard <mark@klomp.org>
|
|
Date: Sat Oct 13 10:27:47 2018 +0200
|
|
|
|
unstrip: Renumber the group section indexes.
|
|
|
|
When unstripping we might need to renumber the group section indexes.
|
|
Just like we do when stripping.
|
|
|
|
Signed-off-by: Mark Wielaard <mark@klomp.org>
|
|
|
|
diff --git a/src/unstrip.c b/src/unstrip.c
|
|
index 03a0346..2cfd3b3 100644
|
|
--- a/src/unstrip.c
|
|
+++ b/src/unstrip.c
|
|
@@ -1708,6 +1708,20 @@ more sections in stripped file than debug file -- arguments reversed?"));
|
|
if (shdr_mem.sh_type == SHT_DYNSYM)
|
|
stripped_dynsym = sec;
|
|
}
|
|
+
|
|
+ if (shdr_mem.sh_type == SHT_GROUP)
|
|
+ {
|
|
+ /* We must adjust all the section indices in the group.
|
|
+ Skip the first word, which is the section group flag.
|
|
+ Everything else is a section index. */
|
|
+ Elf32_Word *shndx = (Elf32_Word *) outdata->d_buf;
|
|
+ for (size_t i = 1; i < shdr_mem.sh_size / sizeof (Elf32_Word); ++i)
|
|
+ if (shndx[i] == SHN_UNDEF || shndx[i] >= stripped_shnum)
|
|
+ error (EXIT_FAILURE, 0,
|
|
+ _("group has invalid section index [%zd]"), i);
|
|
+ else
|
|
+ shndx[i] = ndx_section[shndx[i] - 1];
|
|
+ }
|
|
}
|
|
|
|
/* We may need to update the symbol table. */
|