Blame SOURCES/elfutils-0.174-strip-unstrip-group.patch

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