summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRoland McGrath <[email protected]>2011-02-23 19:52:46 -0800
committerRoland McGrath <[email protected]>2011-02-23 19:52:46 -0800
commit725aad5d2f8b78ed21a5e253fb38f9722c2c8b2d (patch)
tree83ef8e065a191c5fa897bf13211df9964cc67f7e
parent47c5323527dcc954d2d60e9ee87211597aabd101 (diff)
Support reading .zdebug_* DWARF sections compressed via zlib.
-rw-r--r--NEWS4
-rw-r--r--libdw/ChangeLog11
-rw-r--r--libdw/dwarf_begin_elf.c83
-rw-r--r--libdw/dwarf_end.c24
-rw-r--r--libdw/libdwP.h13
-rw-r--r--src/ChangeLog14
-rw-r--r--src/readelf.c84
7 files changed, 195 insertions, 38 deletions
diff --git a/NEWS b/NEWS
index 115261e7..e4b2402f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,7 @@
+Version 0.153
+
+libdw: Support reading .zdebug_* DWARF sections compressed via zlib.
+
Version 0.152
Various build and warning nits fixed for newest GCC and Autoconf.
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 8ec74857..b0ba7e00 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,14 @@
+2011-02-23 Roland McGrath <[email protected]>
+
+ * libdwP.h (struct Dwarf) [USE_ZLIB]: New member sectiondata_gzip_mask.
+ Declare __libdw_free_zdata.
+ * dwarf_end.c [USE_ZLIB] (__libdw_free_zdata): New function.
+ (dwarf_end): Call it.
+
+ * dwarf_begin_elf.c (valid_p): Likewise.
+ (check_section, scngrp_read): Likewise.
+ (check_section) [USE_ZLIB]: Grok .z* flavors of sections.
+
2010-10-13 Roland McGrath <[email protected]>
* dwarf.h: Add DW_LANG_Go.
diff --git a/libdw/dwarf_begin_elf.c b/libdw/dwarf_begin_elf.c
index b5fb7c91..9ec7d51f 100644
--- a/libdw/dwarf_begin_elf.c
+++ b/libdw/dwarf_begin_elf.c
@@ -1,5 +1,5 @@
/* Create descriptor from ELF descriptor for processing file.
- Copyright (C) 2002-2010 Red Hat, Inc.
+ Copyright (C) 2002-2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <[email protected]>, 2002.
@@ -61,6 +61,13 @@
#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][17] =
@@ -117,6 +124,7 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
{
/* The section name must be valid. Otherwise is the ELF file
invalid. */
+ __libdw_free_zdata (result);
__libdw_seterrno (DWARF_E_INVALID_ELF);
free (result);
return NULL;
@@ -141,6 +149,76 @@ check_section (Dwarf *result, GElf_Ehdr *ehdr, Elf_Scn *scn, bool inscngrp)
break;
}
+#if USE_ZLIB
+ else if (scnname[0] == '.' && scnname[1] == 'z'
+ && strcmp (&scnname[2], &dwarf_scnnames[cnt][1]) == 0)
+ {
+ /* A compressed section. */
+
+ if (unlikely (result->sectiondata[cnt] != NULL))
+ /* A section appears twice. That's bad. We ignore the section. */
+ break;
+
+ /* Get the section data. */
+ Elf_Data *data = elf_getdata (scn, NULL);
+ if (data != NULL && data->d_size != 0)
+ {
+ /* 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))
+ break;
+
+ uint64_t size;
+ memcpy (&size, data->d_buf + 4, sizeof size);
+ size = be64toh (size);
+
+ Elf_Data *zdata = malloc (sizeof (Elf_Data) + size);
+ if (unlikely (zdata == NULL))
+ break;
+
+ 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;
+ }
+ }
+
+ break;
+ }
+#endif
return result;
}
@@ -159,6 +237,7 @@ valid_p (Dwarf *result)
if (likely (result != NULL)
&& unlikely (result->sectiondata[IDX_debug_info] == NULL))
{
+ __libdw_free_zdata (result);
__libdw_seterrno (DWARF_E_NO_DWARF);
free (result);
result = NULL;
@@ -189,6 +268,7 @@ scngrp_read (Dwarf *result, Elf *elf, GElf_Ehdr *ehdr, Elf_Scn *scngrp)
if (data == NULL)
{
/* We cannot read the section content. Fail! */
+ __libdw_free_zdata (result);
free (result);
return NULL;
}
@@ -204,6 +284,7 @@ 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);
__libdw_seterrno (DWARF_E_INVALID_ELF);
free (result);
return NULL;
diff --git a/libdw/dwarf_end.c b/libdw/dwarf_end.c
index ec10542e..1e733cae 100644
--- a/libdw/dwarf_end.c
+++ b/libdw/dwarf_end.c
@@ -1,5 +1,5 @@
/* Release debugging handling context.
- Copyright (C) 2002-2010 Red Hat, Inc.
+ Copyright (C) 2002-2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <[email protected]>, 2002.
@@ -54,6 +54,8 @@
#include <search.h>
#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
#include "libdwP.h"
#include "cfi.h"
@@ -76,6 +78,24 @@ 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 *dwarf;
@@ -106,6 +126,8 @@ dwarf_end (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);
diff --git a/libdw/libdwP.h b/libdw/libdwP.h
index da6efc53..b84bf02c 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -1,5 +1,5 @@
/* Internal definitions for libdwarf.
- Copyright (C) 2002-2010 Red Hat, Inc.
+ Copyright (C) 2002-2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <[email protected]>, 2002.
@@ -150,6 +150,11 @@ 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;
@@ -385,6 +390,12 @@ 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;
diff --git a/src/ChangeLog b/src/ChangeLog
index c8b897a9..a7c2513d 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,5 +1,19 @@
2011-02-23 Roland McGrath <[email protected]>
+ * readelf.c (section_name): New function.
+ (print_debug_abbrev_section): Use it instead of constant.
+ (print_debug_aranges_section): Likewise.
+ (print_debug_ranges_section): Likewise.
+ (print_debug_units): Likewise.
+ (print_debug_line_section): Likewise.
+ (print_debug_loc_section): Likewise.
+ (print_debug_macinfo_section): Likewise.
+ (print_debug_pubnames_section): Likewise.
+ (print_debug_str_section): Likewise.
+ (print_debug) [USE_ZLIB]: Match .zdebug_* sections too.
+ (print_debug_abbrev_section): Use decoded d_size, not sh_size.
+ (print_debug_str_section): Likewise.
+
* readelf.c (dwarf_attr_string): Grok DW_AT_GNU_odr_signature.
2011-02-11 Roland McGrath <[email protected]>
diff --git a/src/readelf.c b/src/readelf.c
index 0e50a692..78ee2b77 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -1154,6 +1154,13 @@ print_phdr (Ebl *ebl, GElf_Ehdr *ehdr)
}
+static const char *
+section_name (Ebl *ebl, GElf_Ehdr *ehdr, GElf_Shdr *shdr)
+{
+ return elf_strptr (ebl->elf, ehdr->e_shstrndx, shdr->sh_name) ?: "???";
+}
+
+
static void
handle_scngrp (Ebl *ebl, Elf_Scn *scn, GElf_Shdr *shdr)
{
@@ -4406,16 +4413,16 @@ skip_listptr_hole (struct listptr_table *table, size_t *idxp,
static void
print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
" [ Code]\n"),
- elf_ndxscn (scn), ".debug_abbrev", (uint64_t) shdr->sh_offset);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
Dwarf_Off offset = 0;
- while (offset < shdr->sh_size)
+ while (offset < dbg->sectiondata[IDX_debug_abbrev]->d_size)
{
printf (gettext ("\nAbbreviation section at offset %" PRIu64 ":\n"),
offset);
@@ -4477,8 +4484,7 @@ print_debug_abbrev_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
takes care of it. */
static void
print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr, Elf_Scn *scn,
+ Ebl *ebl, GElf_Ehdr *ehdr, Elf_Scn *scn,
GElf_Shdr *shdr, Dwarf *dbg)
{
Dwarf_Aranges *aranges;
@@ -4495,7 +4501,8 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
"\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 " contains %zu entries:\n",
cnt),
- elf_ndxscn (scn), ".debug_aranges", (uint64_t) shdr->sh_offset, cnt);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset, cnt);
/* Compute floor(log16(cnt)). */
size_t tmp = cnt;
@@ -4533,8 +4540,8 @@ print_debug_aranges_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
/* Print content of DWARF .debug_ranges section. */
static void
print_debug_ranges_section (Dwfl_Module *dwflmod,
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr, Elf_Scn *scn, GElf_Shdr *shdr,
+ Ebl *ebl, GElf_Ehdr *ehdr,
+ Elf_Scn *scn, GElf_Shdr *shdr,
Dwarf *dbg)
{
Elf_Data *data = elf_rawdata (scn, NULL);
@@ -4548,7 +4555,8 @@ print_debug_ranges_section (Dwfl_Module *dwflmod,
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), ".debug_ranges", (uint64_t) shdr->sh_offset);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
sort_listptr (&known_rangelistptr, "rangelistptr");
size_t listptr_idx = 0;
@@ -5644,14 +5652,12 @@ attr_callback (Dwarf_Attribute *attrp, void *arg)
static void
print_debug_units (Dwfl_Module *dwflmod,
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)),
- Elf_Scn *scn,
- GElf_Shdr *shdr, Dwarf *dbg,
- bool debug_types)
+ Ebl *ebl, GElf_Ehdr *ehdr,
+ Elf_Scn *scn, GElf_Shdr *shdr,
+ Dwarf *dbg, bool debug_types)
{
const bool silent = !(print_debug_sections & section_info);
- const char *secname = debug_types ? ".debug_types" : ".debug_info";
+ const char *secname = section_name (ebl, ehdr, shdr);
if (!silent)
printf (gettext ("\
@@ -5814,13 +5820,13 @@ print_debug_types_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
static void
-print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
- GElf_Ehdr *ehdr __attribute__ ((unused)),
+print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), ".debug_line", (uint64_t) shdr->sh_offset);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
if (shdr->sh_size == 0)
return;
@@ -5853,7 +5859,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
{
invalid_data:
error (0, 0, gettext ("invalid data in section [%zu] '%s'"),
- elf_ndxscn (scn), ".debug_line");
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
return;
}
unit_length = read_8ubyte_unaligned_inc (dbg, linep);
@@ -5921,7 +5927,7 @@ print_debug_line_section (Dwfl_Module *dwflmod, Ebl *ebl,
error (0, 0,
gettext ("invalid data at offset %tu in section [%zu] '%s'"),
linep - (const unsigned char *) data->d_buf,
- elf_ndxscn (scn), ".debug_line");
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr));
linep = lineendp;
continue;
}
@@ -6304,7 +6310,7 @@ advance address by fixed value %u to %s\n"),
static void
print_debug_loc_section (Dwfl_Module *dwflmod,
- Ebl *ebl __attribute__ ((unused)), GElf_Ehdr *ehdr,
+ Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
Elf_Data *data = elf_rawdata (scn, NULL);
@@ -6318,7 +6324,8 @@ print_debug_loc_section (Dwfl_Module *dwflmod,
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), ".debug_loc", (uint64_t) shdr->sh_offset);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
sort_listptr (&known_loclistptr, "loclistptr");
size_t listptr_idx = 0;
@@ -6427,13 +6434,13 @@ mac_compare (const void *p1, const void *p2)
static void
print_debug_macinfo_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\
\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), ".debug_macinfo", (uint64_t) shdr->sh_offset);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
putc_unlocked ('\n', stdout);
/* There is no function in libdw to iterate over the raw content of
@@ -6599,12 +6606,12 @@ print_pubnames (Dwarf *dbg __attribute__ ((unused)), Dwarf_Global *global,
/* Print the known exported symbols in the DWARF section '.debug_pubnames'. */
static void
print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"),
- elf_ndxscn (scn), ".debug_pubnames", (uint64_t) shdr->sh_offset);
+ elf_ndxscn (scn), section_name (ebl, ehdr, shdr),
+ (uint64_t) shdr->sh_offset);
int n = 0;
(void) dwarf_getpubnames (dbg, print_pubnames, &n, 0);
@@ -6613,12 +6620,13 @@ print_debug_pubnames_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
/* Print the content of the DWARF string section '.debug_str'. */
static void
print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
- Ebl *ebl __attribute__ ((unused)),
- GElf_Ehdr *ehdr __attribute__ ((unused)),
+ Ebl *ebl, GElf_Ehdr *ehdr,
Elf_Scn *scn, GElf_Shdr *shdr, Dwarf *dbg)
{
+ const size_t sh_size = dbg->sectiondata[IDX_debug_str]->d_size;
+
/* Compute floor(log16(shdr->sh_size)). */
- GElf_Addr tmp = shdr->sh_size;
+ GElf_Addr tmp = sh_size;
int digits = 1;
while (tmp >= 16)
{
@@ -6630,12 +6638,12 @@ print_debug_str_section (Dwfl_Module *dwflmod __attribute__ ((unused)),
printf (gettext ("\nDWARF section [%2zu] '%s' at offset %#" PRIx64 ":\n"
" %*s String\n"),
elf_ndxscn (scn),
- ".debug_str", (uint64_t) shdr->sh_offset,
+ section_name (ebl, ehdr, shdr), (uint64_t) shdr->sh_offset,
/* TRANS: the debugstr| prefix makes the string unique. */
digits + 2, sgettext ("debugstr|Offset"));
Dwarf_Off offset = 0;
- while (offset < shdr->sh_size)
+ while (offset < sh_size)
{
size_t len;
const char *str = dwarf_getstring (dbg, offset, &len);
@@ -6981,7 +6989,13 @@ print_debug (Dwfl_Module *dwflmod, Ebl *ebl, GElf_Ehdr *ehdr)
int n;
for (n = 0; n < ndebug_sections; ++n)
- if (strcmp (name, debug_sections[n].name) == 0)
+ if (strcmp (name, debug_sections[n].name) == 0
+#if USE_ZLIB
+ || (name[0] == '.' && name[1] == 'z'
+ && debug_sections[n].name[1] == 'd'
+ && strcmp (&name[2], &debug_sections[n].name[1]) == 0)
+#endif
+ )
{
if ((print_debug_sections | implicit_debug_sections)
& debug_sections[n].bitmask)