[PATCH 2/4] dwarf_begin_elf: new error for compression failure

Jonathan Lebon jlebon at redhat.com
Mon May 11 19:38:14 UTC 2015


In order to provide better feedback to users, a distinction is made
between finding no dwarf info (E_NO_DWARF) and finding dwarf info but
which is compressed and failed to decompress (E_COMPRESSED_ERROR). This
can occur for example if elfutils was built without zlib support, or if
the compressed section is invalid.

Signed-off-by: Jonathan Lebon <jlebon at redhat.com>
---
 libdw/dwarf_begin_elf.c | 147 ++++++++++++++++++++++++++++--------------------
 libdw/dwarf_error.c     |   1 +
 libdw/libdwP.h          |   1 +
 3 files changed, 88 insertions(+), 61 deletions(-)

diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index 3950cf9..1f95c60 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -71,6 +71,70 @@ 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)
 {
@@ -146,71 +210,32 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
   /* We can now read the section data into results. */
   if (!compressed)
     result->sectiondata[cnt] = data;
-#if USE_ZLIB
   else
     {
-        /* A compressed section. */
-
-	    /* 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 result;
-
-	    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 result;
-
-	    Elf_Data *zdata = malloc (sizeof (Elf_Data) + size);
-	    if (unlikely (zdata == NULL))
-	      return result;
-
-	    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);
-	    else
-	      {
-		result->sectiondata[cnt] = zdata;
-		result->sectiondata_gzip_mask |= 1U << cnt;
-	      }
-    }
+      /* 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;
+        }
+    }
+
   return result;
 }
 
diff --git a/libdw/dwarf_error.c b/libdw/dwarf_error.c
index aa97a68..fe38999 100644
--- a/libdw/dwarf_error.c
+++ b/libdw/dwarf_error.c
@@ -62,6 +62,7 @@ static const char *errmsgs[] =
     [DWARF_E_IO_ERROR] = N_("I/O error"),
     [DWARF_E_INVALID_ELF] = N_("invalid ELF file"),
     [DWARF_E_NO_DWARF] = N_("no DWARF information"),
+    [DWARF_E_COMPRESSED_ERROR] = N_("cannot decompress DWARF"),
     [DWARF_E_NOELF] = N_("no ELF file"),
     [DWARF_E_GETEHDR_ERROR] = N_("cannot get ELF header"),
     [DWARF_E_NOMEM] = N_("out of memory"),
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index fc77960..2d233f6 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -97,6 +97,7 @@ enum
   DWARF_E_IO_ERROR,
   DWARF_E_INVALID_ELF,
   DWARF_E_NO_DWARF,
+  DWARF_E_COMPRESSED_ERROR,
   DWARF_E_NOELF,
   DWARF_E_GETEHDR_ERROR,
   DWARF_E_NOMEM,
-- 
2.1.0



More information about the elfutils-devel mailing list