This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 06/10] libdwfl: Use elf_compress[_gnu] to decompress string, symbol and reloc data.


This makes usage of the libdwfl symbol functions work out of the box even
when some sections (string, symbol or xndx) are compressed. For ET_REL
files this makes relocations just work by making sure the target section
is decompressed first before relocations are applied.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
---
 libdwfl/ChangeLog              |  10 ++++
 libdwfl/dwfl_module_getdwarf.c |  99 ++++++++++++++++++++++++++++++++---
 libdwfl/relocate.c             | 116 ++++++++++++++++++++++++++++++++---------
 libebl/ChangeLog               |   4 ++
 libebl/eblopenbackend.c        |   4 +-
 5 files changed, 201 insertions(+), 32 deletions(-)

diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index 30a5205..b653564 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,13 @@
+2015-12-18  Mark Wielaard  <mjw@redhat.com>
+
+	* dwfl_module_getdwarf.c (find_symtab): Uncompress symstr, xndx, sym
+	sections and aux_str, aux_xndx and aux_sym sections if necessary.
+	* relocate.c (relocate_getsym): Uncompress symtab and symtab_shndx
+	if necessary.
+	(resolve_symbol): Uncompress strtab section if necessary.
+	(relocate_section): Uncompress the section the relocations apply to
+	if necessary.
+
 2015-12-01  Mark Wielaard  <mjw@redhat.com>
 
 	* link_map.c (dwfl_link_map_report): Track whether in.d_buf comes
diff --git a/libdwfl/dwfl_module_getdwarf.c b/libdwfl/dwfl_module_getdwarf.c
index 8483fa2..f86baf7 100644
--- a/libdwfl/dwfl_module_getdwarf.c
+++ b/libdwfl/dwfl_module_getdwarf.c
@@ -1120,10 +1120,39 @@ find_symtab (Dwfl_Module *mod)
       goto aux_cleanup; /* This cleans up some more and tries find_dynsym.  */
     }
 
-  /* Cache the data; MOD->syments and MOD->first_global were set above.  */
+  /* Cache the data; MOD->syments and MOD->first_global were set
+     above.  If any of the sections is compressed, uncompress it
+     first.  Only the string data setion could theoretically be
+     compressed GNU style (as .zdebug_str).  Everything else only ELF
+     gabi style (SHF_COMPRESSED).  */
+
+  Elf_Scn *symstrscn = elf_getscn (mod->symfile->elf, strshndx);
+  if (symstrscn == NULL)
+    goto elferr;
+
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr = gelf_getshdr (symstrscn, &shdr_mem);
+  if (shdr == NULL)
+    goto elferr;
+
+  size_t shstrndx;
+  if (elf_getshdrstrndx (mod->symfile->elf, &shstrndx) < 0)
+    goto elferr;
+
+  const char *sname = elf_strptr (mod->symfile->elf, shstrndx, shdr->sh_name);
+  if (sname == NULL)
+    goto elferr;
+
+  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
+    /* Try to uncompress, but it might already have been, an error
+       might just indicate, already uncompressed.  */
+    elf_compress_gnu (symstrscn, 0, 0);
 
-  mod->symstrdata = elf_getdata (elf_getscn (mod->symfile->elf, strshndx),
-				 NULL);
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+    if (elf_compress (symstrscn, 0, 0) < 0)
+      goto elferr;
+
+  mod->symstrdata = elf_getdata (symstrscn, NULL);
   if (mod->symstrdata == NULL || mod->symstrdata->d_buf == NULL)
     goto elferr;
 
@@ -1131,17 +1160,33 @@ find_symtab (Dwfl_Module *mod)
     mod->symxndxdata = NULL;
   else
     {
+      shdr = gelf_getshdr (xndxscn, &shdr_mem);
+      if (shdr == NULL)
+	goto elferr;
+
+      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+	if (elf_compress (xndxscn, 0, 0) < 0)
+	  goto elferr;
+
       mod->symxndxdata = elf_getdata (xndxscn, NULL);
       if (mod->symxndxdata == NULL || mod->symxndxdata->d_buf == NULL)
 	goto elferr;
     }
 
+  shdr = gelf_getshdr (symscn, &shdr_mem);
+  if (shdr == NULL)
+    goto elferr;
+
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+    if (elf_compress (symscn, 0, 0) < 0)
+      goto elferr;
+
   mod->symdata = elf_getdata (symscn, NULL);
   if (mod->symdata == NULL || mod->symdata->d_buf == NULL)
     goto elferr;
 
   // Sanity check number of symbols.
-  GElf_Shdr shdr_mem, *shdr = gelf_getshdr (symscn, &shdr_mem);
+  shdr = gelf_getshdr (symscn, &shdr_mem);
   if (shdr == NULL || shdr->sh_entsize == 0
       || mod->syments > mod->symdata->d_size / shdr->sh_entsize
       || (size_t) mod->first_global > mod->syments)
@@ -1164,9 +1209,33 @@ find_symtab (Dwfl_Module *mod)
 	  return;
 	}
 
-      mod->aux_symstrdata = elf_getdata (elf_getscn (mod->aux_sym.elf,
-						     aux_strshndx),
-					 NULL);
+      Elf_Scn *aux_strscn = elf_getscn (mod->aux_sym.elf, aux_strshndx);
+      if (aux_strscn == NULL)
+	goto elferr;
+
+      shdr = gelf_getshdr (aux_strscn, &shdr_mem);
+      if (shdr == NULL)
+	goto elferr;
+
+      size_t aux_shstrndx;
+      if (elf_getshdrstrndx (mod->aux_sym.elf, &aux_shstrndx) < 0)
+	goto elferr;
+
+      sname = elf_strptr (mod->aux_sym.elf, aux_shstrndx,
+				      shdr->sh_name);
+      if (sname == NULL)
+	goto elferr;
+
+      if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
+	/* Try to uncompress, but it might already have been, an error
+	   might just indicate, already uncompressed.  */
+	elf_compress_gnu (aux_strscn, 0, 0);
+
+      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+	if (elf_compress (aux_strscn, 0, 0) < 0)
+	  goto elferr;
+
+      mod->aux_symstrdata = elf_getdata (aux_strscn, NULL);
       if (mod->aux_symstrdata == NULL || mod->aux_symstrdata->d_buf == NULL)
 	goto aux_cleanup;
 
@@ -1174,12 +1243,28 @@ find_symtab (Dwfl_Module *mod)
 	mod->aux_symxndxdata = NULL;
       else
 	{
+	  shdr = gelf_getshdr (aux_xndxscn, &shdr_mem);
+	  if (shdr == NULL)
+	    goto elferr;
+
+	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+	    if (elf_compress (aux_xndxscn, 0, 0) < 0)
+	      goto elferr;
+
 	  mod->aux_symxndxdata = elf_getdata (aux_xndxscn, NULL);
 	  if (mod->aux_symxndxdata == NULL
 	      || mod->aux_symxndxdata->d_buf == NULL)
 	    goto aux_cleanup;
 	}
 
+      shdr = gelf_getshdr (aux_symscn, &shdr_mem);
+      if (shdr == NULL)
+	goto elferr;
+
+      if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+	if (elf_compress (aux_symscn, 0, 0) < 0)
+	  goto elferr;
+
       mod->aux_symdata = elf_getdata (aux_symscn, NULL);
       if (mod->aux_symdata == NULL || mod->aux_symdata->d_buf == NULL)
 	goto aux_cleanup;
diff --git a/libdwfl/relocate.c b/libdwfl/relocate.c
index 2dc6737..fc88df3 100644
--- a/libdwfl/relocate.c
+++ b/libdwfl/relocate.c
@@ -123,23 +123,32 @@ relocate_getsym (Dwfl_Module *mod,
 	    {
 	      GElf_Shdr shdr_mem, *shdr = gelf_getshdr (scn, &shdr_mem);
 	      if (shdr != NULL)
-		switch (shdr->sh_type)
-		  {
-		  default:
-		    continue;
-		  case SHT_SYMTAB:
-		    cache->symelf = relocated;
-		    cache->symdata = elf_getdata (scn, NULL);
-		    cache->strtabndx = shdr->sh_link;
-		    if (unlikely (cache->symdata == NULL))
-		      return DWFL_E_LIBELF;
-		    break;
-		  case SHT_SYMTAB_SHNDX:
-		    cache->symxndxdata = elf_getdata (scn, NULL);
-		    if (unlikely (cache->symxndxdata == NULL))
+		{
+		  /* We need uncompressed data.  */
+		  if ((shdr->sh_type == SHT_SYMTAB
+		       || shdr->sh_type == SHT_SYMTAB_SHNDX)
+		      && (shdr->sh_flags & SHF_COMPRESSED) != 0)
+		    if (elf_compress (scn, 0, 0) < 0)
 		      return DWFL_E_LIBELF;
-		    break;
-		  }
+
+		  switch (shdr->sh_type)
+		    {
+		    default:
+		      continue;
+		    case SHT_SYMTAB:
+		      cache->symelf = relocated;
+		      cache->symdata = elf_getdata (scn, NULL);
+		      cache->strtabndx = shdr->sh_link;
+		      if (unlikely (cache->symdata == NULL))
+			return DWFL_E_LIBELF;
+		      break;
+		    case SHT_SYMTAB_SHNDX:
+		      cache->symxndxdata = elf_getdata (scn, NULL);
+		      if (unlikely (cache->symxndxdata == NULL))
+			return DWFL_E_LIBELF;
+		      break;
+		    }
+		}
 	      if (cache->symdata != NULL && cache->symxndxdata != NULL)
 		break;
 	    }
@@ -203,9 +212,34 @@ resolve_symbol (Dwfl_Module *referer, struct reloc_symtab_cache *symtab,
 	  /* Cache the strtab for this symtab.  */
 	  assert (referer->symfile == NULL
 		  || referer->symfile->elf != symtab->symelf);
-	  symtab->symstrdata = elf_getdata (elf_getscn (symtab->symelf,
-							symtab->strtabndx),
-					    NULL);
+
+	  Elf_Scn *scn = elf_getscn (symtab->symelf, symtab->strtabndx);
+	  if (scn == NULL)
+	    return DWFL_E_LIBELF;
+
+	  GElf_Shdr shdr_mem;
+	  GElf_Shdr *shdr = gelf_getshdr (scn, &shdr_mem);
+	  if (shdr == NULL)
+	    return DWFL_E_LIBELF;
+
+	  if (symtab->symshstrndx == SHN_UNDEF
+	      && elf_getshdrstrndx (symtab->symelf, &symtab->symshstrndx) < 0)
+	    return DWFL_E_LIBELF;
+
+	  const char *sname = elf_strptr (symtab->symelf, symtab->symshstrndx,
+					  shdr->sh_name);
+	  if (sname == NULL)
+	    return DWFL_E_LIBELF;
+
+	  /* If the section is already decompressed, that isn't an error.  */
+	  if (strncmp (sname, ".zdebug", strlen (".zdebug")) == 0)
+	    elf_compress_gnu (scn, 0, 0);
+
+	  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+	    if (elf_compress (scn, 0, 0) < 0)
+	      return DWFL_E_LIBELF;
+
+	  symtab->symstrdata = elf_getdata (scn, NULL);
 	  if (unlikely (symtab->symstrdata == NULL
 			|| symtab->symstrdata->d_buf == NULL))
 	    return DWFL_E_LIBELF;
@@ -446,22 +480,56 @@ relocate_section (Dwfl_Module *mod, Elf *relocated, const GElf_Ehdr *ehdr,
 		  Elf_Scn *scn, GElf_Shdr *shdr,
 		  Elf_Scn *tscn, bool debugscn, bool partial)
 {
-  /* First, fetch the name of the section these relocations apply to.  */
+  /* First, fetch the name of the section these relocations apply to.
+     Then try to decompress both relocation and target section.  */
   GElf_Shdr tshdr_mem;
   GElf_Shdr *tshdr = gelf_getshdr (tscn, &tshdr_mem);
+  if (tshdr == NULL)
+    return DWFL_E_LIBELF;
+
   const char *tname = elf_strptr (relocated, shstrndx, tshdr->sh_name);
   if (tname == NULL)
     return DWFL_E_LIBELF;
 
-  if (unlikely (tshdr->sh_type == SHT_NOBITS) || unlikely (tshdr->sh_size == 0))
-    /* No contents to relocate.  */
-    return DWFL_E_NOERROR;
-
   if (debugscn && ! ebl_debugscn_p (mod->ebl, tname))
     /* This relocation section is not for a debugging section.
        Nothing to do here.  */
     return DWFL_E_NOERROR;
 
+  if (strncmp (tname, ".zdebug", strlen ("zdebug")) == 0)
+    elf_compress_gnu (tscn, 0, 0);
+
+  if ((tshdr->sh_flags & SHF_COMPRESSED) != 0)
+    if (elf_compress (tscn, 0, 0) < 0)
+      return DWFL_E_LIBELF;
+
+  /* Reload Shdr in case section was just decompressed.  */
+  tshdr = gelf_getshdr (tscn, &tshdr_mem);
+  if (tshdr == NULL)
+    return DWFL_E_LIBELF;
+
+  if (unlikely (tshdr->sh_type == SHT_NOBITS)
+      || unlikely (tshdr->sh_size == 0))
+    /* No contents to relocate.  */
+    return DWFL_E_NOERROR;
+
+  const char *sname = elf_strptr (relocated, shstrndx, shdr->sh_name);
+  if (sname == NULL)
+    return DWFL_E_LIBELF;
+
+  if (strncmp (sname, ".zdebug", strlen ("zdebug")) == 0)
+    elf_compress_gnu (scn, 0, 0);
+
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+    if (elf_compress (scn, 0, 0) < 0)
+      return DWFL_E_LIBELF;
+
+  /* Reload Shdr in case section was just decompressed.  */
+  GElf_Shdr shdr_mem;
+  shdr = gelf_getshdr (scn, &shdr_mem);
+  if (shdr == NULL)
+    return DWFL_E_LIBELF;
+
   /* Fetch the section data that needs the relocations applied.  */
   Elf_Data *tdata = elf_rawdata (tscn, NULL);
   if (tdata == NULL)
diff --git a/libebl/ChangeLog b/libebl/ChangeLog
index d040c08..4d365c5 100644
--- a/libebl/ChangeLog
+++ b/libebl/ChangeLog
@@ -1,3 +1,7 @@
+2015-12-18  Mark Wielaard  <mjw@redhat.com>
+
+	* eblopenbackend.c (default_debugscn_p): Also match .zdebug sections.
+
 2015-09-24  Jose E. Marchesi  <jose.marchesi@oracle.com>
 
 	* Makefile.am (AM_CFLAGS): Use -fPIC instead of -fpic to avoid
diff --git a/libebl/eblopenbackend.c b/libebl/eblopenbackend.c
index b301400..372ef2a 100644
--- a/libebl/eblopenbackend.c
+++ b/libebl/eblopenbackend.c
@@ -662,7 +662,9 @@ default_debugscn_p (const char *name)
   const size_t ndwarf_scn_names = (sizeof (dwarf_scn_names)
 				   / sizeof (dwarf_scn_names[0]));
   for (size_t cnt = 0; cnt < ndwarf_scn_names; ++cnt)
-    if (strcmp (name, dwarf_scn_names[cnt]) == 0)
+    if (strcmp (name, dwarf_scn_names[cnt]) == 0
+	|| (strncmp (name, ".zdebug", strlen (".zdebug")) == 0
+	    && strcmp (&name[2], &dwarf_scn_names[cnt][1]) == 0))
       return true;
 
   return false;
-- 
2.5.0

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]