libdw: Use elf_compress[_gnu] to uncompress debug section data.
authorMark Wielaard <mjw@redhat.com>
Wed, 30 Dec 2015 13:18:40 +0000 (14:18 +0100)
committerMark Wielaard <mjw@redhat.com>
Wed, 6 Jan 2016 13:27:10 +0000 (14:27 +0100)
libdw used its own code for decompressing GNU style .zdebug sections.
Using elf_compress and elf_compress_gnu instead makes it possible to
transparently use either GNU style or ELF style compressed data.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
libdw/ChangeLog
libdw/dwarf_begin_elf.c
libdw/dwarf_end.c
libdw/libdwP.h

index 89d0326..fc80e8d 100644 (file)
@@ -1,3 +1,16 @@
+2015-12-18  Mark Wielaard  <mjw@redhat.com>
+
+       * libdwP.h (struct Dwarf): Remove sectiondata_gzip_mask.
+       (__libdw_free_zdata): Remove.
+       * dwarf_begin_elf.c (inflate_section): Remove.
+       (check_section): Remove __libdw_free_zdata calls. Use elf_compress
+       and elf_compress_gnu to decompress if necessary.
+       (valid_p): Remove __libdw_free_zdata calls.
+       (scngrp_read): Use elf_compress if section is compressed. Remove
+       __libdw_free_zdata calls.
+       * dwarf_end.c (__libdw_free_zdata): Remove.
+       (dwarf_end): Don't call __libdw_free_zdata.
+
 2015-10-28  Mark Wielaard  <mjw@redhat.com>
 
        * libdw.map (ELFUTILS_0.165): New. Add dwelf_scn_gnu_compressed_size.
index 63532fd..6f25e42 100644 (file)
 
 #include "libdwP.h"
 
-#if USE_ZLIB
-# include <endian.h>
-# define crc32         loser_crc32
-# include <zlib.h>
-# undef crc32
-#endif
-
 
 /* Section names.  */
 static const char dwarf_scnnames[IDX_last][18] =
@@ -71,70 +64,6 @@ static const char dwarf_scnnames[IDX_last][18] =
 };
 #define ndwarf_scnnames (sizeof (dwarf_scnnames) / sizeof (dwarf_scnnames[0]))
 
-#if USE_ZLIB
-static Elf_Data *
-inflate_section (Elf_Data * data)
-{
-  /* There is a 12-byte header of "ZLIB" followed by
-     an 8-byte big-endian size.  */
-
-  if (unlikely (data->d_size < 4 + 8)
-      || unlikely (memcmp (data->d_buf, "ZLIB", 4) != 0))
-    return NULL;
-
-  uint64_t size;
-  memcpy (&size, data->d_buf + 4, sizeof size);
-  size = be64toh (size);
-
-  /* Check for unsigned overflow so malloc always allocated
-     enough memory for both the Elf_Data header and the
-     uncompressed section data.  */
-  if (unlikely (sizeof (Elf_Data) + size < size))
-    return NULL;
-
-  Elf_Data *zdata = malloc (sizeof (Elf_Data) + size);
-  if (unlikely (zdata == NULL))
-    return NULL;
-
-  zdata->d_buf = &zdata[1];
-  zdata->d_type = ELF_T_BYTE;
-  zdata->d_version = EV_CURRENT;
-  zdata->d_size = size;
-  zdata->d_off = 0;
-  zdata->d_align = 1;
-
-  z_stream z =
-    {
-      .next_in = data->d_buf + 4 + 8,
-      .avail_in = data->d_size - 4 - 8,
-      .next_out = zdata->d_buf,
-      .avail_out = zdata->d_size
-    };
-  int zrc = inflateInit (&z);
-  while (z.avail_in > 0 && likely (zrc == Z_OK))
-    {
-      z.next_out = zdata->d_buf + (zdata->d_size - z.avail_out);
-      zrc = inflate (&z, Z_FINISH);
-      if (unlikely (zrc != Z_STREAM_END))
-       {
-         zrc = Z_DATA_ERROR;
-         break;
-       }
-      zrc = inflateReset (&z);
-    }
-  if (likely (zrc == Z_OK))
-    zrc = inflateEnd (&z);
-
-  if (unlikely (zrc != Z_OK) || unlikely (z.avail_out != 0))
-    {
-      free (zdata);
-      return NULL;
-    }
-
-  return zdata;
-}
-#endif
-
 static Dwarf *
 check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
 {
@@ -173,7 +102,6 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
       /* The section name must be valid.  Otherwise is the ELF file
         invalid.  */
     err:
-      __libdw_free_zdata (result);
       Dwarf_Sig8_Hash_free (&result->sig8_hash);
       __libdw_seterrno (DWARF_E_INVALID_ELF);
       free (result);
@@ -182,14 +110,14 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
 
   /* Recognize the various sections.  Most names start with .debug_.  */
   size_t cnt;
-  bool compressed = false;
+  bool gnu_compressed = false;
   for (cnt = 0; cnt < ndwarf_scnnames; ++cnt)
     if (strcmp (scnname, dwarf_scnnames[cnt]) == 0)
       break;
     else if (scnname[0] == '.' && scnname[1] == 'z'
             && strcmp (&scnname[2], &dwarf_scnnames[cnt][1]) == 0)
       {
-        compressed = true;
+        gnu_compressed = true;
         break;
       }
 
@@ -201,40 +129,41 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
     /* A section appears twice.  That's bad.  We ignore the section.  */
     return result;
 
+  /* We cannot know whether or not a GNU compressed section has already
+     been uncompressed or not, so ignore any errors.  */
+  if (gnu_compressed)
+    elf_compress_gnu (scn, 0, 0);
+
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0)
+    {
+      if (elf_compress (scn, 0, 0) < 0)
+       {
+         /* If we failed to decompress the section and it's the
+            debug_info section, then fail with specific error rather
+            than the generic NO_DWARF. Without debug_info we can't do
+            anything (see also valid_p()). */
+         if (cnt == IDX_debug_info)
+           {
+             Dwarf_Sig8_Hash_free (&result->sig8_hash);
+             __libdw_seterrno (DWARF_E_COMPRESSED_ERROR);
+             free (result);
+             return NULL;
+           }
+         return result;
+       }
+    }
+
   /* Get the section data.  */
   Elf_Data *data = elf_getdata (scn, NULL);
-  if (data == NULL || data->d_size == 0)
+  if (data == NULL)
+    goto err;
+
+  if (data->d_buf == NULL || data->d_size == 0)
     /* No data actually available, ignore it. */
     return result;
 
   /* We can now read the section data into results. */
-  if (!compressed)
-    result->sectiondata[cnt] = data;
-  else
-    {
-      /* A compressed section. */
-
-#if USE_ZLIB
-      Elf_Data *inflated = inflate_section(data);
-      if (inflated != NULL)
-        {
-          result->sectiondata[cnt] = inflated;
-          result->sectiondata_gzip_mask |= 1U << cnt;
-        }
-#endif
-
-      /* If we failed to decompress the section and it's the debug_info section,
-       * then fail with specific error rather than the generic NO_DWARF. Without
-       * debug_info we can't do anything (see also valid_p()). */
-      if (result->sectiondata[cnt] == NULL && cnt == IDX_debug_info)
-        {
-          __libdw_free_zdata (result);
-          Dwarf_Sig8_Hash_free (&result->sig8_hash);
-          __libdw_seterrno (DWARF_E_COMPRESSED_ERROR);
-          free (result);
-          return NULL;
-        }
-    }
+  result->sectiondata[cnt] = data;
 
   return result;
 }
@@ -253,7 +182,6 @@ valid_p (Dwarf *result)
   if (likely (result != NULL)
       && unlikely (result->sectiondata[IDX_debug_info] == NULL))
     {
-      __libdw_free_zdata (result);
       Dwarf_Sig8_Hash_free (&result->sig8_hash);
       __libdw_seterrno (DWARF_E_NO_DWARF);
       free (result);
@@ -265,7 +193,6 @@ valid_p (Dwarf *result)
       result->fake_loc_cu = (Dwarf_CU *) calloc (1, sizeof (Dwarf_CU));
       if (unlikely (result->fake_loc_cu == NULL))
        {
-         __libdw_free_zdata (result);
          Dwarf_Sig8_Hash_free (&result->sig8_hash);
          __libdw_seterrno (DWARF_E_NOMEM);
          free (result);
@@ -301,13 +228,31 @@ global_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr)
 static Dwarf *
 scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp)
 {
+  GElf_Shdr shdr_mem;
+  GElf_Shdr *shdr = gelf_getshdr (scngrp, &shdr_mem);
+  if (shdr == NULL)
+    {
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_INVALID_ELF);
+      free (result);
+      return NULL;
+    }
+
+  if ((shdr->sh_flags & SHF_COMPRESSED) != 0
+      && elf_compress (scngrp, 0, 0) < 0)
+    {
+      Dwarf_Sig8_Hash_free (&result->sig8_hash);
+      __libdw_seterrno (DWARF_E_COMPRESSED_ERROR);
+      free (result);
+      return NULL;
+    }
+
   /* SCNGRP is the section descriptor for a section group which might
      contain debug sections.  */
   Elf_Data *data = elf_getdata (scngrp, NULL);
   if (data == NULL)
     {
       /* We cannot read the section content.  Fail!  */
-      __libdw_free_zdata (result);
       Dwarf_Sig8_Hash_free (&result->sig8_hash);
       free (result);
       return NULL;
@@ -324,7 +269,6 @@ scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp)
        {
          /* A section group refers to a non-existing section.  Should
             never happen.  */
-         __libdw_free_zdata (result);
          Dwarf_Sig8_Hash_free (&result->sig8_hash);
          __libdw_seterrno (DWARF_E_INVALID_ELF);
          free (result);
index 2108063..6c6d985 100644 (file)
@@ -57,24 +57,6 @@ cu_free (void *arg)
 }
 
 
-#if USE_ZLIB
-void
-internal_function
-__libdw_free_zdata (Dwarf *dwarf)
-{
-  unsigned int gzip_mask = dwarf->sectiondata_gzip_mask;
-  while (gzip_mask != 0)
-    {
-      int i = ffs (gzip_mask);
-      assert (i > 0);
-      --i;
-      assert (i < IDX_last);
-      free (dwarf->sectiondata[i]);
-      gzip_mask &= ~(1U << i);
-    }
-}
-#endif
-
 int
 dwarf_end (Dwarf *dwarf)
 {
@@ -110,8 +92,6 @@ dwarf_end (Dwarf *dwarf)
       /* Free the pubnames helper structure.  */
       free (dwarf->pubnames_sets);
 
-      __libdw_free_zdata (dwarf);
-
       /* Free the ELF descriptor if necessary.  */
       if (dwarf->free_elf)
        elf_end (dwarf->elf);
index 2d233f6..5d095a7 100644 (file)
@@ -147,11 +147,6 @@ struct Dwarf
   /* The section data.  */
   Elf_Data *sectiondata[IDX_last];
 
-#if USE_ZLIB
-  /* The 1 << N bit is set if sectiondata[N] is malloc'd decompressed data.  */
-  unsigned int sectiondata_gzip_mask:IDX_last;
-#endif
-
   /* True if the file has a byte order different from the host.  */
   bool other_byte_order;
 
@@ -440,12 +435,6 @@ extern void *__libdw_allocate (Dwarf *dbg, size_t minsize, size_t align)
 /* Default OOM handler.  */
 extern void __libdw_oom (void) __attribute ((noreturn, visibility ("hidden")));
 
-#if USE_ZLIB
-extern void __libdw_free_zdata (Dwarf *dwarf) internal_function;
-#else
-# define __libdw_free_zdata(dwarf)     ((void) (dwarf))
-#endif
-
 /* Allocate the internal data for a unit not seen before.  */
 extern struct Dwarf_CU *__libdw_intern_next_unit (Dwarf *dbg, bool debug_types)
      __nonnull_attribute__ (1) internal_function;