summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NEWS4
-rw-r--r--libdw/ChangeLog11
-rw-r--r--libdw/Makefile.am2
-rw-r--r--libdw/c++/dwarf3
-rw-r--r--libdw/c++/dwarf_edit21
-rw-r--r--libdw/c++/dwarf_output286
-rw-r--r--libdw/c++/line_info.cc20
-rw-r--r--libdw/c++/output-shape.cc159
-rw-r--r--libdw/dwarf_begin_elf.c83
-rw-r--r--libdw/dwarf_end.c24
-rw-r--r--libdw/libdwP.h11
-rw-r--r--src/ChangeLog18
-rw-r--r--src/readelf.c86
-rwxr-xr-xtests/run-dwarfcmp-self.sh2
14 files changed, 433 insertions, 297 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 704dc116..7fb6eb00 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -10,6 +10,17 @@
* c++/dwarf-knowledge.cc (expected_value_space):
Grok DW_AT_GNU_odr_signature.
+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-12-07 Petr Machata <[email protected]>
* c++/subr.hh (sharing_stack::element::pop): Remove. Move the
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 279e8599..3fcfdb71 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -101,7 +101,7 @@ libdwpp_a_SOURCES = c++/values.cc \
c++/known.cc \
c++/line_info.cc \
c++/edit-values.cc \
- c++/output-values.cc c++/output-shape.cc
+ c++/output-values.cc
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf
index 085f0f92..9553bd69 100644
--- a/libdw/c++/dwarf
+++ b/libdw/c++/dwarf
@@ -1126,7 +1126,8 @@ namespace elfutils
}
/* Return a value unique to us while we're in memory.
- This is a stable pointer into the Dwarf_Files data. */
+ This is a stable pointer into the Dwarf_Files data
+ or to a static empty string. */
inline uintptr_t identity () const
{
return (uintptr_t) name ();
diff --git a/libdw/c++/dwarf_edit b/libdw/c++/dwarf_edit
index e7ed54e1..854c2769 100644
--- a/libdw/c++/dwarf_edit
+++ b/libdw/c++/dwarf_edit
@@ -164,22 +164,11 @@ namespace elfutils
template<typename die_type, typename arg_type>
inline void set (const die_type &die, arg_type &arg)
{
- try
- {
- _m_tag = die.tag ();
- attributes_type t_attrs (die.attributes (), arg);
- _m_attributes.swap (t_attrs);
- children_type t_children (die.children (), arg);
- _m_children.swap (t_children);
- }
- catch (...)
- {
- // Never leave a partially-formed DIE.
- _m_tag = -1;
- _m_attributes.clear ();
- _m_children.clear ();
- throw;
- };
+ _m_tag = die.tag ();
+ attributes_type t_attrs (die.attributes (), arg);
+ _m_attributes.swap (t_attrs);
+ children_type t_children (die.children (), arg);
+ _m_children.swap (t_children);
}
public:
diff --git a/libdw/c++/dwarf_output b/libdw/c++/dwarf_output
index b7bbaadc..e792a929 100644
--- a/libdw/c++/dwarf_output
+++ b/libdw/c++/dwarf_output
@@ -151,6 +151,12 @@ namespace elfutils
friend class dwarf_output;
friend class dwarf_output_collector;
+ __attribute__((used)) die_info_pair *info () const
+ {
+ return reinterpret_cast<die_info_pair *>
+ (const_cast<debug_info_entry *> (this));
+ }
+
public:
class attributes_type
: public dwarf_data::attributes_type<dwarf_output, value>
@@ -403,13 +409,18 @@ namespace elfutils
: _base (i, dummy)
{}
- /* The hash of a value_reference is its referent's identity,
- because we can have multiple value_reference objects that
- wind up pointing to the same entry. This method is virtual
- for the circular_reference case, below. */
- virtual size_t hash () const
+ /* The hash of a value_reference is its referent's local hash,
+ which only takes non-reference values into account. This
+ method is virtual for the circular_reference case, below. */
+ inline size_t hash () const
+ {
+ struct die_info *info = get_die_info ();
+ return info->_m_reference_hash;
+ }
+
+ virtual die_info *get_die_info () const
{
- return ref->identity ();
+ return &ref->info ()->second;
}
};
@@ -584,10 +595,21 @@ namespace elfutils
std::bitset<2> _m_with_sibling;
unsigned int _m_uses;
- inline die_info ()
+ /* The local hash of the die, set when die_info is created.
+ Uses only none-reference values. */
+ size_t _m_local_hash;
+
+ /* The reference hash of the die, based on just reference
+ attribute values. Needs all local hashes of referenced dies
+ to be set. */
+ size_t _m_reference_hash;
+
+ inline die_info (size_t local_hash)
: _m_parent (NULL), _m_refs (),
_m_originals (), _m_original_cost (0),
- _m_with_sibling (), _m_uses (0)
+ _m_with_sibling (), _m_uses (0),
+ _m_local_hash (local_hash),
+ _m_reference_hash (0)
{}
inline ~die_info ()
@@ -982,11 +1004,12 @@ namespace elfutils
inline die_info_pair *add_entry (int tag,
const children_type *children,
- const attrs_type *attrs)
+ const attrs_type *attrs,
+ die_info *info)
{
std::pair <die_map::iterator, bool>
ins = _m_unique.insert (std::make_pair (die_type (tag, children, attrs),
- die_info ()));
+ *info));
die_info_pair &x = *ins.first;
if (ins.second)
x.second.assert_unused ();
@@ -994,39 +1017,6 @@ namespace elfutils
return &x;
}
- struct shape_type
- {
- typedef std::vector<std::pair<int, int> > attrs_type;
- attrs_type _m_attrs;
- bool _m_has_children;
- size_t _m_hash;
-
- friend class subr::hashed_hasher<shape_type>;
- typedef subr::hashed_hasher<shape_type> hasher;
-
- inline void hashnadd (int name, int form);
- inline shape_type (const die_type &die, bool last_sibling);
-
- inline bool operator== (const shape_type &other) const
- {
- return (_m_hash == other._m_hash
- && _m_has_children == other._m_has_children
- && _m_attrs == other._m_attrs);
- }
- inline bool operator!= (const shape_type &other) const
- {
- return !(*this == other);
- }
- };
-
- typedef subr::nothing shape_info;
-
- typedef std::tr1::unordered_map<shape_type, shape_info,
- shape_type::hasher> shape_map;
- shape_map _m_shapes;
-
- void add_shape (die_type &die, bool last_sibling);
-
struct stats_cmp
: public std::binary_function<const die_map::value_type *,
const die_map::value_type *,
@@ -1206,6 +1196,7 @@ namespace elfutils
{
private:
const std::vector<entry *> *_m_entry;
+ bool _m_final;
inline circular_reference (const circular_reference &)
: value::value_reference ()
@@ -1216,14 +1207,16 @@ namespace elfutils
public:
inline circular_reference (const entry *die, copier *)
: value::value_reference (),
- _m_entry (new std::vector<entry *> (1, const_cast<entry *> (die)))
+ _m_entry (new std::vector<entry *> (1, const_cast<entry *> (die))),
+ _m_final (false)
{
die->dump () << " new circular_reference " << this << "\n";
}
inline bool final () const
{
- return _m_entry == NULL;
+ // XXX was return _m_entry == NULL;
+ return _m_final;
}
inline typename std::vector<entry *>::const_iterator pending () const
@@ -1241,8 +1234,10 @@ namespace elfutils
{
pending_entry ()->dump () << " placed circular_reference "
<< this << "\n";
- delete _m_entry;
- _m_entry = NULL;
+ // XXX Keeping around for local hash...
+ _m_final = true;
+ // delete _m_entry;
+ // _m_entry = NULL;
}
inline ~circular_reference ()
@@ -1256,14 +1251,11 @@ namespace elfutils
}
/* We have a special case for a reference attribute that is part
- of a circular chain. That value always hashes as zero, so that
- each entry in a circular chain of references has the same hash
- value as any entry that it otherwise matches and that has any
- (eventually) circular reference as the corresponding
- attribute's value. */
- virtual size_t hash () const
+ of a circular chain. It gets calculated from the
+ pending_entry. */
+ virtual die_info *get_die_info () const
{
- return 0;
+ return pending_entry ()->get_die_info ();
}
};
@@ -1298,9 +1290,14 @@ namespace elfutils
// Set if _m_children contains any entries not already final.
bool _m_unfinished_children;
+ // The die_info that will be used when putting the die into
+ // the collector. Stores local hash as soon as all children
+ // are defined in defined_self ().
+ die_info *_m_info;
+
inline pending_entry (int tag)
: _m_finalizing (NULL), _m_self (NULL), _m_matched (NULL),
- _m_tag (tag), _m_unfinished_children (false)
+ _m_tag (tag), _m_unfinished_children (false), _m_info (NULL)
{}
inline ~pending_entry ()
@@ -1385,6 +1382,84 @@ namespace elfutils
typedef typename final_children_getter::
template copy<debug_info_entry::children_type> get_final_children;
+ inline size_t get_reference_hash (std::vector<const entry *> &stack) const
+ {
+ assert (_m_info != NULL);
+
+ // Could already have been set by forward reference.
+ if (_m_info->_m_reference_hash != 0)
+ return _m_info->_m_reference_hash;
+
+ size_t rhash = _m_info->_m_local_hash;
+ size_t attr_rhashes = 0;
+ for (attr_map::const_iterator it = _m_attributes.begin ();
+ it != _m_attributes.end ();
+ ++it)
+ {
+ // XXX XOR is for order irrelevance, but shouldn't be necessary.
+ // See also calculate_local_hash, which does the same.
+ const entry *ref
+ = dynamic_cast<const entry *> (it->second._m_value);
+ if (ref != NULL)
+ {
+ // Workaround weird case (bug?)
+ // https://fedorahosted.org/pipermail/elfutils-devel/2011-February/001792.html
+ if (it->first == DW_AT_containing_type
+ && ref->_m_pending == this)
+ continue;
+ else
+ attr_rhashes ^= ref->get_reference_hash (stack);
+ }
+ }
+ subr::hash_combine (rhash, attr_rhashes);
+
+ return rhash;
+ }
+
+ inline size_t calculate_local_hash ()
+ {
+ // Calculate the local hash for this new die.
+ // XOR the attribute values together (so order doesn't matter)
+ // but exclude reference attributes values (just include
+ // their tag). XXX - shouldn't be necessary, double check.
+ size_t lhash = _m_tag;
+ size_t attr_hash = 0;
+ for (attr_map::const_iterator it = _m_attributes.begin ();
+ it != _m_attributes.end ();
+ ++it)
+ {
+ if (it->second.what_space () != dwarf::VS_reference)
+ attr_hash ^= subr::hash_this (*it);
+ else
+ attr_hash ^= (it->first << 3);
+ }
+ subr::hash_combine (lhash, attr_hash);
+
+ size_t children_hash = 0;
+ for (typename std::vector<entry *>::const_iterator it
+ = _m_children.begin ();
+ it != _m_children.end ();
+ ++it)
+ {
+ // child lhash is always in the die_info, which might
+ // be in the pending_entry when not yet finalized, or
+ // part of the finalized child die_info.
+ size_t child_lhash;
+ struct pending_entry *pending = (*it)->_m_pending;
+ if (pending)
+ child_lhash = pending->_m_info->_m_local_hash;
+ else
+ {
+ die_info_pair *final_child = get_final_child (*it);
+ child_lhash = final_child->second._m_local_hash;
+ }
+ subr::hash_combine (children_hash, child_lhash);
+ }
+ subr::hash_combine (lhash, children_hash);
+
+ return lhash;
+ }
+
inline die_info_pair *final (copier *c,
::Dwarf_Off offset, ::Dwarf_Off cost)
{
@@ -1404,7 +1479,7 @@ namespace elfutils
(_m_children, std::ptr_fun (get_final_child)),
fresh);
- _m_matched = co->add_entry (_m_tag, children, attrs);
+ _m_matched = co->add_entry (_m_tag, children, attrs, _m_info);
}
// Final bookkeeping in the collector for this copied entry.
@@ -1514,7 +1589,7 @@ namespace elfutils
built in the output has one of these in place of a value_reference.
These all live in the _m_entries map, one per input-side DIE. */
struct entry
- : public value::value_dispatch
+ : public value::value_reference
{
::Dwarf_Off _m_offset; // For debugging and statistics only.
::Dwarf_Off _m_cost; // For statistics only.
@@ -1603,10 +1678,9 @@ namespace elfutils
}
/* We are no longer an undefined entry, so decrement the count.
- Then finalize as much as we can now. We attempt finalization
- even when the count is nonzero, so that a leaf entry with no
- forward references finishes immediately, and so then can its
- parents and on up if they don't own any pending references. */
+ But don't finalize yet. Since all children are known now we
+ can create a candidate die_info that includes the local hash
+ for this entry. */
inline void defined_self (copier *c)
{
assert (_m_final == NULL);
@@ -1614,9 +1688,9 @@ namespace elfutils
assert (c->_m_undefined_entries > 0);
--c->_m_undefined_entries;
dump () << " defined_self => " << c->_m_undefined_entries << "\n";
- finalize (c);
- if (_m_final == NULL)
- assert (c->_m_undefined_entries > 0);
+
+ size_t lhash = _m_pending->calculate_local_hash ();
+ _m_pending->_m_info = new die_info (lhash);
}
/* A reference-following matching operation noticed along
@@ -1649,6 +1723,48 @@ namespace elfutils
*p.second = true;
}
+ /* Recursively sets up reference hashes for the die_info of this
+ pending_entry. Depends on all local hashes having been setup
+ already. At this point all entries are still pending. */
+ inline void setup_reference_hash () const
+ {
+ std::vector<const entry *> stack;
+ _m_pending->_m_info->_m_reference_hash = get_reference_hash (stack);
+ assert (stack.empty ());
+
+ for (typename std::vector<entry *>::const_iterator it
+ = _m_pending->_m_children.begin ();
+ it != _m_pending->_m_children.end ();
+ ++it)
+ (*it)->setup_reference_hash ();
+ }
+
+ inline size_t get_reference_hash (std::vector<const entry *> &stack) const
+ {
+ if (std::find (stack.begin (), stack.end (), this) != stack.end ())
+ {
+ std::cout << "Reference chain cycle detected\n"
+ << "offset=[0x" << std::hex << _m_offset << std::dec
+ << "] already on the reference chain stack\n";
+ typename std::vector<const entry *>::iterator it;
+ for (it = stack.begin ();
+ it != stack.end ();
+ it++)
+ {
+ std::cout << "offset=[0x" << std::hex << (*it)->_m_offset
+ << std::dec << "] "
+ << dwarf::tags::name ((*it)->_m_pending->_m_tag)
+ << "\n";
+ }
+ abort ();
+ }
+
+ stack.push_back (this);
+ size_t res = _m_pending->get_reference_hash (stack);
+ stack.pop_back ();
+ return res;
+ }
+
// Attempt to turn the pending entry into a final entry.
void finalize (copier *c)
{
@@ -1780,6 +1896,15 @@ namespace elfutils
assert (_m_pending != NULL);
return _m_parent->_m_pending->child (_m_self_idx);
}
+
+ /* The local hash of the debug_info_entry if we are already
+ final, otherwise get it from the pending_entry. */
+ inline die_info *get_die_info () const
+ {
+ if (_m_final)
+ return &_m_final->second;
+ return _m_pending->_m_info;
+ }
};
// This object lives while we are copying one particular input DIE.
@@ -1821,21 +1946,13 @@ namespace elfutils
assert (_m_in->_m_pending == NULL);
_m_in->_m_pending = _m_out;
- try
- {
- // This calls add_reference for each pending reference.
- _m_out->_m_attributes.set (in.attributes (), *this);
+ // This calls add_reference for each pending reference.
+ _m_out->_m_attributes.set (in.attributes (), *this);
- for (input_die_ptr i = in.children ().begin ();
- i != in.children ().end ();
- ++i)
- add_child (*i);
- }
- catch (...)
- {
- _m_in->_m_pending = NULL;
- throw;
- }
+ for (input_die_ptr i = in.children ().begin ();
+ i != in.children ().end ();
+ ++i)
+ add_child (*i);
_m_out = NULL;
_m_in->defined_self (_m_copier);
@@ -1874,11 +1991,22 @@ namespace elfutils
return *_m_copier;
}
- /* Complain if we still have dangling references.
+ /* Walk over the whole cu again to set reference hashes up.
+ Then try to finalize everything at once.
+ Complain if we still have dangling references.
If not, it should be impossible to have pending entries left. */
inline die_info_pair *final_unit () const
{
assert (_m_out == NULL);
+
+ // First walk over the whole CU tree again to setup the
+ // reference hash for each die_info.
+ _m_in->setup_reference_hash ();
+
+ // We should now be able to finalize everything at once.
+ if (_m_copier->_m_undefined_entries == 0)
+ _m_in->finalize (_m_copier);
+
if (unlikely (_m_in->_m_final == NULL))
{
_m_in->dump_entry ();
diff --git a/libdw/c++/line_info.cc b/libdw/c++/line_info.cc
index e613c16b..df7a2172 100644
--- a/libdw/c++/line_info.cc
+++ b/libdw/c++/line_info.cc
@@ -61,6 +61,15 @@ stringform (Dwarf_Attribute *attr)
return false;
}
+/* Returns true if the attribute represents a valid zero udata.
+ This represents "no-file". */
+static bool
+zero_formudata (Dwarf_Attribute *attr)
+{
+ Dwarf_Word zero;
+ return dwarf_formudata (attr, &zero) == 0 && zero == 0;
+}
+
/* Mock up a dummy attribute with a special kludge that get_files groks.
We use these for source_file objects consed directly from an index
rather than from a real attribute. */
@@ -91,7 +100,7 @@ get_files (const Dwarf_Attribute *attr, Dwarf_Files **files, Dwarf_Word *idx)
Dwarf_Word
dwarf::source_file::mtime () const
{
- if (stringform (thisattr ()))
+ if (stringform (thisattr ()) || zero_formudata (thisattr ()))
return 0;
Dwarf_Files *files;
@@ -106,7 +115,7 @@ dwarf::source_file::mtime () const
Dwarf_Word
dwarf::source_file::size () const
{
- if (stringform (thisattr ()))
+ if (stringform (thisattr ()) || zero_formudata (thisattr ()))
return 0;
Dwarf_Files *files;
@@ -118,12 +127,16 @@ dwarf::source_file::size () const
return result;
}
+static const char *no_file = "";
+
const char *
dwarf::source_file::name () const
{
const char *result;
if (stringform (thisattr ()))
result = dwarf_formstring (thisattr ());
+ else if (zero_formudata (thisattr ()))
+ result = no_file;
else
{
Dwarf_Files *files;
@@ -154,6 +167,9 @@ dwarf::source_file::to_string () const
return plain_string (result);
}
+ if (zero_formudata (thisattr ()))
+ return plain_string (no_file);
+
Dwarf_Files *files;
Dwarf_Word idx;
xif (thisattr (), get_files (thisattr (), &files, &idx));
diff --git a/libdw/c++/output-shape.cc b/libdw/c++/output-shape.cc
deleted file mode 100644
index 8d25b389..00000000
--- a/libdw/c++/output-shape.cc
+++ /dev/null
@@ -1,159 +0,0 @@
-/* elfutils::dwarf_output abbrev generation.
- Copyright (C) 2009 Red Hat, Inc.
- This file is part of Red Hat elfutils.
-
- Red Hat elfutils is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by the
- Free Software Foundation; version 2 of the License.
-
- Red Hat elfutils is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License along
- with Red Hat elfutils; if not, write to the Free Software Foundation,
- Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
-
- In addition, as a special exception, Red Hat, Inc. gives You the
- additional right to link the code of Red Hat elfutils with code licensed
- under any Open Source Initiative certified open source license
- (http://www.opensource.org/licenses/index.php) which requires the
- distribution of source code with any binary distribution and to
- distribute linked combinations of the two. Non-GPL Code permitted under
- this exception must only link to the code of Red Hat elfutils through
- those well defined interfaces identified in the file named EXCEPTION
- found in the source code files (the "Approved Interfaces"). The files
- of Non-GPL Code may instantiate templates or use macros or inline
- functions from the Approved Interfaces without causing the resulting
- work to be covered by the GNU General Public License. Only Red Hat,
- Inc. may make changes or additions to the list of Approved Interfaces.
- Red Hat's grant of this exception is conditioned upon your not adding
- any new exceptions. If you wish to add a new Approved Interface or
- exception, please contact Red Hat. You must obey the GNU General Public
- License in all respects for all of the Red Hat elfutils code and other
- code used in conjunction with Red Hat elfutils except the Non-GPL Code
- covered by this exception. If you modify this file, you may extend this
- exception to your version of the file, but you are not obligated to do
- so. If you do not wish to provide this exception without modification,
- you must delete this exception statement from your version and license
- this file solely under the GPL without exception.
-
- Red Hat elfutils is an included package of the Open Invention Network.
- An included package of the Open Invention Network is a package for which
- Open Invention Network licensees cross-license their patents. No patent
- license is granted, either expressly or impliedly, by designation as an
- included package. Should you wish to participate in the Open Invention
- Network licensing program, please visit www.openinventionnetwork.com
- <http://www.openinventionnetwork.com>. */
-
-#include <config.h>
-#include "dwarf_output"
-
-using namespace elfutils;
-
-static inline int
-attr_form (int tag, const dwarf_output::attribute &attr)
-{
- switch (attr.second.what_space ())
- {
- case dwarf::VS_address:
- return DW_FORM_addr;
-
- case dwarf::VS_flag:
- return DW_FORM_flag;
-
- case dwarf::VS_reference:
- return DW_FORM_ref_addr;
-
- case dwarf::VS_string:
- case dwarf::VS_identifier:
- return DW_FORM_string;
-
- case dwarf::VS_constant:
- if (! attr.second.constant_is_integer ())
- return DW_FORM_block;
- /* Fall through. */
-
- case dwarf::VS_dwarf_constant:
- case dwarf::VS_source_line:
- case dwarf::VS_source_column:
- return DW_FORM_udata;
-
- case dwarf::VS_location:
- if (!attr.second.location ().is_list ())
- return DW_FORM_block;
- /* Fall through. */
-
- case dwarf::VS_lineptr:
- case dwarf::VS_macptr:
- case dwarf::VS_rangelistptr:
- /* For class *ptr (including loclistptr), the one of data[48] that
- matches offset_size is the only form encoding to use. Other data*
- forms can mean the attribute is class constant instead. */
- return DW_FORM_data4;
-
- case dwarf::VS_source_file:
- switch (attr.first)
- {
- case DW_AT_decl_file:
- case DW_AT_call_file:
- return DW_FORM_udata;
-
- case DW_AT_comp_dir:
- return DW_FORM_string;
-
- case DW_AT_name:
- switch (tag)
- {
- case DW_TAG_compile_unit:
- case DW_TAG_partial_unit:
- return DW_FORM_string;
- }
- break;
- }
- throw std::runtime_error ("source_file value unexpected in "
- + to_string (attr));
-
- case dwarf::VS_discr_list:
- return DW_FORM_block;
- }
-
- throw std::logic_error ("strange value_space");
-}
-
-inline void
-dwarf_output_collector::shape_type::hashnadd (int name, int form)
-{
- subr::hash_combine (_m_hash, name);
- subr::hash_combine (_m_hash, form);
- _m_attrs.push_back (std::make_pair (name, form));
-}
-
-inline
-dwarf_output_collector::shape_type::shape_type (const die_type &die,
- bool last_sibling)
- : _m_has_children (die.has_children ()), _m_hash (8675309 << _m_has_children)
-{
- if (!last_sibling)
- hashnadd (DW_AT_sibling, DW_FORM_ref_udata);
-
- for (die_type::attributes_type::const_iterator it = die.attributes ().begin ();
- it != die.attributes ().end ();
- ++it)
- hashnadd (it->first, attr_form (die.tag (), *it));
-}
-#if 0
-void
-dwarf_output_collector::add_shape (die_type &die, bool last_sibling)
-{
- assert (die._m_shape == NULL);
-
- shape_map::value_type &x
- = *_m_shapes.insert (std::make_pair (shape_type (die, last_sibling),
- shape_info ())).first;
- // x.second.nusers++, etc.
-
- die._m_shape = &x;
-}
-#endif
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 58f3f908..0baa0e38 100644
--- a/libdw/libdwP.h
+++ b/libdw/libdwP.h
@@ -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;
@@ -392,6 +397,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 096c4e7a..938e7a29 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,21 @@
+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]>
* elfcmp.c (verbose): New variable.
diff --git a/src/readelf.c b/src/readelf.c
index 30c2be09..808511ef 100644
--- a/src/readelf.c
+++ b/src/readelf.c
@@ -1,5 +1,5 @@
/* Print information from ELF file in human-readable form.
- Copyright (C) 1999-2010 Red Hat, Inc.
+ Copyright (C) 1999-2011 Red Hat, Inc.
This file is part of Red Hat elfutils.
Written by Ulrich Drepper <[email protected]>, 1999.
@@ -1155,6 +1155,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)
{
@@ -3777,16 +3784,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);
@@ -3848,8 +3855,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;
@@ -3866,7 +3872,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;
@@ -3904,8 +3911,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);
@@ -3919,7 +3926,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;
@@ -5015,14 +5023,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 ("\
@@ -5185,13 +5191,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;
@@ -5224,7 +5230,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);
@@ -5292,7 +5298,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;
}
@@ -5675,7 +5681,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);
@@ -5689,7 +5695,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;
@@ -5798,13 +5805,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
@@ -5970,12 +5977,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);
@@ -5984,12 +5991,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)
{
@@ -6001,12 +6009,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);
@@ -6352,7 +6360,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)
diff --git a/tests/run-dwarfcmp-self.sh b/tests/run-dwarfcmp-self.sh
index efc14047..02bf4be4 100755
--- a/tests/run-dwarfcmp-self.sh
+++ b/tests/run-dwarfcmp-self.sh
@@ -62,7 +62,7 @@ runtest ../src/unstrip
runtest ../*/*.so
# These are the biggest ones.
-runtest ../src/dwarflint
+runtest ../dwarflint/dwarflint
runtest ../src/dwarfcmp
runtest ../src/dwarfcmp-test