diff options
-rw-r--r-- | NEWS | 4 | ||||
-rw-r--r-- | libdw/ChangeLog | 11 | ||||
-rw-r--r-- | libdw/Makefile.am | 2 | ||||
-rw-r--r-- | libdw/c++/dwarf | 3 | ||||
-rw-r--r-- | libdw/c++/dwarf_edit | 21 | ||||
-rw-r--r-- | libdw/c++/dwarf_output | 286 | ||||
-rw-r--r-- | libdw/c++/line_info.cc | 20 | ||||
-rw-r--r-- | libdw/c++/output-shape.cc | 159 | ||||
-rw-r--r-- | libdw/dwarf_begin_elf.c | 83 | ||||
-rw-r--r-- | libdw/dwarf_end.c | 24 | ||||
-rw-r--r-- | libdw/libdwP.h | 11 | ||||
-rw-r--r-- | src/ChangeLog | 18 | ||||
-rw-r--r-- | src/readelf.c | 86 | ||||
-rwxr-xr-x | tests/run-dwarfcmp-self.sh | 2 |
14 files changed, 433 insertions, 297 deletions
@@ -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 |