From: Roland McGrath Date: Mon, 20 Jul 2009 07:56:06 +0000 (-0700) Subject: crap X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=40edc9a44f1faccaf805ebd1bd3c0510345cfd7a;p=thirdparty%2Felfutils.git crap --- diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf index ef2833b43..b94354bc3 100644 --- a/libdw/c++/dwarf +++ b/libdw/c++/dwarf @@ -330,7 +330,6 @@ namespace elfutils } public: - inline const_iterator () : _m_raw (), _m_end (raw::end ()) { @@ -361,6 +360,14 @@ namespace elfutils return !(*this == other); } + struct hasher : public std::unary_function + { + size_t operator () (const const_iterator &i) const + { + return subr::hash_this (i._m_raw); + } + }; + inline const_iterator &operator++ () // prefix { ++_m_raw; @@ -585,6 +592,14 @@ namespace elfutils return !(*this == other); } + struct hasher : public std::unary_function + { + size_t operator () (const const_iterator &i) const + { + return subr::hash_this ((uintptr_t) i._m_die._m_die.addr); + } + }; + inline const_iterator &operator++ () // prefix { int result = ::dwarf_siblingof (&_m_die._m_die, &_m_die._m_die); diff --git a/libdw/c++/dwarf_data b/libdw/c++/dwarf_data index 6b4c8e616..aeef3ad74 100644 --- a/libdw/c++/dwarf_data +++ b/libdw/c++/dwarf_data @@ -128,7 +128,8 @@ namespace elfutils template inline compile_unit (const input &cu, arg_type &arg) - : impl::debug_info_entry (require_cu (cu), arg) + : impl::debug_info_entry (typename impl::debug_info_entry::pointer (), + require_cu (cu), arg) {} // Fetch the CU's DW_AT_stmt_list. diff --git a/libdw/c++/dwarf_output b/libdw/c++/dwarf_output index 2d05665d9..551c97ed7 100644 --- a/libdw/c++/dwarf_output +++ b/libdw/c++/dwarf_output @@ -237,6 +237,7 @@ namespace elfutils class debug_info_entry { + friend class dwarf_output; friend class dwarf_output_collector; public: @@ -329,10 +330,12 @@ namespace elfutils { const typename input::const_iterator here = in++; has_sibling = in != other.end (); - const debug_info_entry *child = c.add_entry (*here, has_sibling); + push_back (NULL); + iterator out = end (); + --out; + const debug_info_entry *child = c.add_entry (out, here, + has_sibling); subr::hash_combine (_m_hash, (uintptr_t) child); - push_back (child); - c.copied (--end (), here, has_sibling); } } @@ -363,6 +366,7 @@ namespace elfutils typedef children_type::const_iterator const_pointer; protected: + value::value_reference _m_ref; const children_type *_m_children; const attributes_type *_m_attributes; void *_m_shape; @@ -379,9 +383,12 @@ namespace elfutils _m_tag (-1) {} - template - inline debug_info_entry (const die_type &die, copier &c) - : _m_children (c.add_children (die.children ())), + template + inline debug_info_entry (const pointer &at, + const input_die &die, + copier_type &c) + : _m_ref (at, subr::nothing ()), + _m_children (c.add_children (die.children ())), _m_attributes (c.add_attributes (die.attributes ())), _m_shape (NULL), // XXX _m_hash (die.tag ()), @@ -501,7 +508,15 @@ namespace elfutils typedef debug_info_entry::attributes_type::value_type attribute; - typedef dwarf_data::compile_unit compile_unit; + class compile_unit + : public dwarf_data::compile_unit + { + public: + template + inline compile_unit (const input &cu, copier_type &c) + : dwarf_data::compile_unit (cu, c) + {} + }; /* Main container anchoring all the output. @@ -674,18 +689,25 @@ namespace elfutils die_map _m_unique; template - inline const die_type *add_entry (const input &other, copier_type &c, + inline const die_type *add_entry (const children_type::iterator &at, + const input &other, copier_type &c, bool has_sibling) { - typename die_map::value_type &x - = *_m_unique.insert (std::make_pair (die_type (other, c), - die_info ())).first; + std::pair + ins = _m_unique.insert (std::make_pair (die_type (at, other, c), + die_info ())); + typename die_map::value_type &x = *ins.first; + if (ins.second) + { + assert (x.second.uses == 0); + if (has_sibling) + x.second.with_sibling = true; + else + x.second.without_sibling = true; + // XXX add_shape (x.first, !has_sibling); + } x.second.uses++; ++_m_total; - if (has_sibling) - x.second.with_sibling = true; - else - x.second.without_sibling = true; return &x.first; } @@ -745,20 +767,87 @@ namespace elfutils template class dwarf_output::copier - : public dwarf_ref_maker // XXX temporary { friend class dwarf_output; private: struct tracker - : public dwarf_ref_tracker + : public dwarf_tracker_base { - typedef dwarf_ref_tracker _base; + typedef dw dwarf1; + typedef dwarf_output dwarf2; + + typedef dwarf_tracker_base _base; + + explicit tracker (const tracker &) + : _base () + { + throw std::logic_error ("not copy-constructible"); + } + + typedef typename _base::cu1 cu1; + typedef typename _base::cu2 cu2; + typedef typename _base::die1 die1; + typedef typename _base::die2 die2; + typedef typename _base::dwarf1_ref dwarf1_ref; + + typedef dwarf_path_finder tracker1; + typedef dwarf_path_finder tracker2; + + tracker1 _m_left; + tracker2 _m_right; + + struct ref_hasher : public std::unary_function + { + inline size_t operator () (const die2 &i) const + { + return i->identity (); + } + }; + + struct same_ref : public std::equal_to + { + inline bool operator () (const die2 &a, const die2 &b) const + { + return a->identity () == b->identity (); + } + }; + + typedef std::pair + > equiv_list; + typedef std::tr1::unordered_map< ::Dwarf_Off, equiv_list> equiv_map; + equiv_map *_m_equiv; + bool _m_delete_equiv; + + inline equiv_list *equiv_to (const die1 &a) + { + return &(*_m_equiv)[a->identity ()]; + } + /* Predicate for DIEs "equal enough" to match as context for a subtree. + The definition we use is that the DIE has the same tag and all its + attributes are equal, excepting that references in attribute values + are not compared. */ + struct equal_enough : public std::binary_function + { + inline bool operator () (const die1 &a, const die2 &b) + { + if (a->tag () != b->tag ()) + return false; + dwarf_tracker_base t; + return (dwarf_comparator (t) + .equals (a->attributes (), b->attributes ())); + } + }; + + public: inline tracker (const dwarf_output_collector &c) - : _base (c._m_tracker) + : _m_right (c._m_tracker, true), + _m_equiv (new equiv_map), _m_delete_equiv (true) {} + inline tracker (const tracker &proto, typename _base::reference_match &matched, const typename _base::left_context_type &lhs, @@ -768,6 +857,165 @@ namespace elfutils : _base (proto, matched, lhs, a, b) {} + + struct walk + { + typename tracker1::walk _m_left; + typename tracker2::walk _m_right; + + inline walk (tracker *w, const cu1 &a, const cu2 &b) + : _m_left (&w->_m_left, a), _m_right (&w->_m_right, b) + {} + }; + + struct step + { + typename tracker1::step _m_left; + typename tracker2::step _m_right; + + inline step (tracker *w, const die1 &a, const die2 &b) + : _m_left (&w->_m_left, a), _m_right (&w->_m_right, b) + {} + }; + + typedef typename tracker1::die_path left_context_type; + inline const left_context_type &left_context (const die1 &die) + { + return _m_left.path_to (die); + } + + typedef typename tracker2::die_path right_context_type; + inline const right_context_type &right_context (const die2 &die) + { + return _m_right.path_to (die); + } + + // Very cheap check for an obvious mismatch of contexts. + inline bool context_quick_mismatch (const left_context_type &a, + const right_context_type &b) + + { + return a.size () != b.size (); + } + + // Full match when context_quick_mismatch has returned false. + inline bool context_match (const left_context_type &a, + const right_context_type &b) + { + return std::equal (a.begin (), a.end (), b.begin (), equal_enough ()); + } + + class reference_match + { + friend class tracker; + private: + equiv_list *_m_elt; + + public: + + inline reference_match () + : _m_elt (NULL) + {} + + inline ~reference_match () + { + if (_m_elt != NULL) + _m_elt->first = NULL; + } + + inline bool cannot_match () const + { + return _m_elt == NULL; + } + + inline void notice_match (const die2 &b, bool matches) const + { + if (matches && _m_elt != NULL) + _m_elt->second.insert (b); + } + }; + + inline bool + reference_matched (reference_match &matched, const die1 &a, const die2 &b) + { + equiv_list *elt = equiv_to (a); + if (elt->first == NULL) + { + /* Record that we have a walk in progress crossing A. + When MATCHED goes out of scope in our caller, its + destructor will reset ELT->first to clear this record. */ + elt->first = &b; + matched._m_elt = elt; + + // Short-circuit if we have already matched B to A. + return elt->second.find (b) != elt->second.end (); + } + + /* We have a circularity. We can tell because ELT->first remains + set from an outer recursion still in progress. + + The circular chain of references rooted at A matches B if B is + also the root of its own circularity and everything along those + parallel chains matches. If the chains hadn't matched so far, + we would not have kept following them to get here. + + We recorded the B that arrived at the first comparison with A. + We actually record the pointer on the caller's stack rather + than a copy of B, just because the iterator might be larger. */ + + return *elt->first == b; + } + + // Share the _m_seen maps with the prototype tracker, + // but start a fresh walk from the given starting point. + inline tracker (const tracker &proto, reference_match &, + const left_context_type &lhs, const die1 &a, + const right_context_type &rhs, const die2 &b) + : _m_left (proto._m_left, lhs, a), + _m_right (proto._m_right, rhs, b), + _m_equiv (proto._m_equiv), _m_delete_equiv (false) + { + // We are starting a recursive consideration of a vs b. + } + + struct maker + { + equiv_list *_m_elt; + + inline maker () + : _m_elt (NULL) + {} + + inline const debug_info_entry *entry () const + { + return &**_m_elt->second.begin (); + } + + inline ~maker () + { + if (_m_elt != NULL) + _m_elt->first = NULL; + } + }; + + inline bool already_made (maker &m, const typename _base::die1 &in, + const debug_info_entry::pointer &at) + { + equiv_list *equiv = equiv_to (in); + if (equiv->first == NULL) + { + /* Record that we have a walk in progress crossing A. + When M goes out of scope in our caller, its + destructor will reset ELT->first to clear this record. */ + equiv->first = &at; + m._m_elt = equiv; + + return equiv->second.begin () != equiv->second.end (); + } + + throw std::logic_error("XXX circularity"); + } + }; dwarf_output_collector *_m_collector; @@ -808,13 +1056,6 @@ namespace elfutils return _m_collector->_m_identifiers.add (x); } - template - inline const value::value_reference *add_reference (const input &x) - { - // XXX temporary kludge (leak!) - return new value::value_reference (x, *this); - } - template inline const value::value_flag *add_flag (const input &x) { @@ -900,17 +1141,30 @@ namespace elfutils template inline const debug_info_entry * - add_entry (const input &x, bool has_sibling) + add_entry (const debug_info_entry::children_type::iterator &at, + const input &in, bool has_sibling) { - return _m_collector->add_entry (x, *this, has_sibling); + typename tracker::maker m; + if (_m_tracker->already_made (m, in, at)) + return m.entry (); + + typename tracker::step into (_m_tracker, in, at); + + const debug_info_entry *die + = _m_collector->add_entry (at, *in, *this, has_sibling); + m._m_elt->second.insert (die->_m_ref.ref); + return die; } - template - inline void copied (const debug_info_entry::children_type::iterator &out, - const input_iter &in, bool /*has_sibling*/) + template + inline const value::value_reference *add_reference (const input &to) { - equivalence (out, in); - // XXX _m_collector->add_shape (*out, !has_sibling); + typename tracker::maker m; + debug_info_entry::pointer at; // XXX + if (_m_tracker->already_made (m, to, at)) + return &m.entry ()->_m_ref; + + throw std::logic_error ("XXX forward reference"); } }; }; diff --git a/libdw/c++/dwarf_tracker b/libdw/c++/dwarf_tracker index ff20d3800..9d3b9bbae 100644 --- a/libdw/c++/dwarf_tracker +++ b/libdw/c++/dwarf_tracker @@ -354,13 +354,34 @@ namespace elfutils tracker1 _m_left; tracker2 _m_right; - typedef std::tr1::unordered_map< - ::Dwarf_Off, std::pair > - > equiv_map; + struct ref_hasher : public std::unary_function + { + inline size_t operator () (const die2 &i) const + { + return i->identity (); + } + }; + + struct same_ref : public std::equal_to + { + inline bool operator () (const die2 &a, const die2 &b) const + { + return a->identity () == b->identity (); + } + }; + + typedef std::pair + > equiv_list; + typedef std::tr1::unordered_map< ::Dwarf_Off, equiv_list> equiv_map; equiv_map *_m_equiv; bool _m_delete_equiv; + inline equiv_list *equiv_to (const die1 &a) + { + return &(*_m_equiv)[a->identity ()]; + } + /* Predicate for DIEs "equal enough" to match as context for a subtree. The definition we use is that the DIE has the same tag and all its attributes are equal, excepting that references in attribute values @@ -382,8 +403,8 @@ namespace elfutils : _m_equiv (new equiv_map), _m_delete_equiv (true) {} - inline dwarf_ref_tracker (const tracker1 &proto) - : _m_left (proto, true), + inline dwarf_ref_tracker (const tracker2 &proto) + : _m_right (proto, true), _m_equiv (new equiv_map), _m_delete_equiv (true) {} @@ -445,7 +466,7 @@ namespace elfutils { friend class dwarf_ref_tracker; private: - typename equiv_map::mapped_type *_m_elt; + equiv_list *_m_elt; public: @@ -467,14 +488,14 @@ namespace elfutils inline void notice_match (const die2 &b, bool matches) const { if (matches && _m_elt != NULL) - _m_elt->second.insert (b->identity ()); + _m_elt->second.insert (b); } }; inline bool reference_matched (reference_match &matched, const die1 &a, const die2 &b) { - typename equiv_map::mapped_type *elt = &(*_m_equiv)[a->identity ()]; + equiv_list *elt = equiv_to (a); if (elt->first == NULL) { /* Record that we have a walk in progress crossing A. @@ -484,7 +505,7 @@ namespace elfutils matched._m_elt = elt; // Short-circuit if we have already matched B to A. - return elt->second.find (b->identity ()) != elt->second.end (); + return elt->second.find (b) != elt->second.end (); } /* We have a circularity. We can tell because ELT->first remains