From: Roland McGrath Date: Mon, 6 Jul 2009 09:03:52 +0000 (-0700) Subject: Split out dwarf_path_finder from dwarf_ref_tracker::tracker. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=643af75b14dd336a4e628a198faa2617d11d1780;p=thirdparty%2Felfutils.git Split out dwarf_path_finder from dwarf_ref_tracker::tracker. --- diff --git a/libdw/ChangeLog b/libdw/ChangeLog index fef45842f..8fef9dc46 100644 --- a/libdw/ChangeLog +++ b/libdw/ChangeLog @@ -1,3 +1,8 @@ +2009-07-06 Roland McGrath + + * c++/dwarf_tracker (tracker): Break out private class into ... + (dwarf_path_finder): ... here. + 2009-07-03 Roland McGrath * c++/dwarf: Give line info stubby to_string methods. diff --git a/libdw/c++/dwarf_tracker b/libdw/c++/dwarf_tracker index f12b3a101..1a442a42f 100644 --- a/libdw/c++/dwarf_tracker +++ b/libdw/c++/dwarf_tracker @@ -57,275 +57,283 @@ namespace elfutils { - // Standard tracker. - template - class dwarf_ref_tracker : public dwarf_tracker_base + // Basic tracker of tree-walk paths to DIEs. + template + class dwarf_path_finder { - private: - typedef dwarf_tracker_base _base; - public: - 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 typename dw::compile_units::const_iterator cu; + typedef typename dw::debug_info_entry::children_type::const_iterator die; + + /* We maintain the current path down the logical DIE tree from the CU + as a stack of iterators pointing to the DIE at each level. */ + typedef std::list die_path; private: - template - struct tracker + // We use a singleton list of a default-constructed iterator as a marker. + static inline const die_path bad_die_path () { - /* We maintain the current path down the logical DIE tree from the CU - as a stack of iterators pointing to the DIE at each level. */ - typedef std::list die_path; + return die_path (1); + } + static inline bool bad_die_path (const die_path &path) + { + typename die_path::const_iterator it = path.begin (); + if (it == path.end ()) + return false; + const die &elt = *it; + return ++it == path.end () && elt == die (); + } - // We use a singleton list of a default-constructed iterator as a marker. - static inline const die_path bad_die_path () - { - return die_path (1); - } - static inline bool bad_die_path (const die_path &path) - { - typename die_path::const_iterator it = path.begin (); - if (it == path.end ()) - return false; - const die &elt = *it; - return ++it == path.end () && elt == die (); - } + /* We record every DIE we have seen here, mapping its .identity () + to the die_path of parent DIEs taken to reach it. */ + typedef std::tr1::unordered_map< ::Dwarf_Off, const die_path> die_map; + die_map *_m_seen; + bool _m_delete_seen; - /* We record every DIE we have seen here, mapping its .identity () - to the die_path of parent DIEs taken to reach it. */ - typedef std::tr1::unordered_map< ::Dwarf_Off, const die_path> die_map; - die_map *_m_seen; - bool _m_delete_seen; + cu _m_root; - cu _m_root; + die_path _m_path; - die_path _m_path; + public: + // Default constructor: an original tracker. + inline dwarf_path_finder () + : _m_seen (new die_map), _m_delete_seen (true) + {} - // Default constructor: an original tracker. - inline tracker () - : _m_seen (new die_map), _m_delete_seen (true) - {} + // Construct a derived tracker: does its own walk, but sharing caches. + inline dwarf_path_finder (const dwarf_path_finder &proto, + const die_path &context, const die &there) + : _m_seen (proto._m_seen), _m_delete_seen (false), + _m_root (proto._m_root), _m_path (context) + { + _m_path.push_back (there); + } - // Construct a derived tracker: does its own walk, but sharing caches. - inline tracker (const tracker &proto, - const die_path &context, const die &there) - : _m_seen (proto._m_seen), _m_delete_seen (false), - _m_root (proto._m_root), _m_path (context) + inline ~dwarf_path_finder () + { + if (_m_delete_seen) + { + delete _m_seen; + // We should never be left with a partial walk on the books. + assert (_m_path.empty ()); + } + } + + // Main hooks for a normal walk. + + /* A walk object does set-up work when constructed and tear-down + work when destroyed, so tear-down is done even for exceptions. */ + struct walk + { + dwarf_path_finder *_m_tracker; + inline walk (dwarf_path_finder *w, const cu &root) + : _m_tracker (w) { - _m_path.push_back (there); + assert (_m_tracker->_m_path.empty ()); + _m_tracker->_m_root = root; } - - inline ~tracker () + inline ~walk () { - if (_m_delete_seen) - { - delete _m_seen; - // We should never be left with a partial walk on the books. - assert (_m_path.empty ()); - } + assert (_m_tracker->_m_path.empty ()); + _m_tracker->_m_root = cu (); } + }; - // Main hooks for a normal walk. - - /* A walk object does set-up work when constructed and tear-down - work when destroyed, so tear-down is done even for exceptions. */ - struct walk + /* A step object does pre-order work when constructed and post-order + work when destroyed, so post-order is done even for exceptions. + While this object lives, HERE is on the _m_path stack. */ + struct step + { + dwarf_path_finder *_m_walker; + inline step (dwarf_path_finder *w, const die &here) + : _m_walker (w) { - tracker *_m_tracker; - inline walk (tracker *w, const cu &root) - : _m_tracker (w) - { - assert (_m_tracker->_m_path.empty ()); - _m_tracker->_m_root = root; - } - inline ~walk () - { - assert (_m_tracker->_m_path.empty ()); - _m_tracker->_m_root = cu (); - } - }; + // Record the path down from the CU to see this DIE. + _m_walker->_m_seen->insert (std::make_pair (here->identity (), + _m_walker->_m_path)); - /* A step object does pre-order work when constructed and post-order - work when destroyed, so post-order is done even for exceptions. - While this object lives, HERE is on the _m_path stack. */ - struct step + // Append this DIE to the path we'll record for its children. + _m_walker->_m_path.push_back (here); + } + inline ~step () { - tracker *_m_walker; - inline step (tracker *w, const die &here) - : _m_walker (w) - { - // Record the path down from the CU to see this DIE. - _m_walker->_m_seen->insert (std::make_pair (here->identity (), - _m_walker->_m_path)); + _m_walker->_m_path.pop_back (); + } + }; - // Append this DIE to the path we'll record for its children. - _m_walker->_m_path.push_back (here); - } - inline ~step () + // Random access to a DIE, find the path of the walk that gets there. + inline const die_path &path_to (const die &a) + { + ::Dwarf_Off id = a->identity (); + std::pair found + = _m_seen->insert (std::make_pair (id, bad_die_path ())); + if (found.second + /* It's not in our _m_seen map. Our main walk recording + into _m_seen is exhaustive, so this can only be a forward + reference. That is, we didn't already hit this DIE in + our top-level walk and so it is not in _m_seen yet. + + We must do a separate walk to find it. Since we know + this is a forward reference, we don't have to start a + fresh walk from the root, just momentarily wind forward + from where we are. */ + && !walk_down_to (a, found.first) + && !walk_over_to (a, found.first) + && !walk_up_to (a, found.first)) + throw std::runtime_error ("DIE not reachable from CU!"); + assert (&found.first->second != NULL); + assert (!bad_die_path (found.first->second)); + return found.first->second; + } + + private: + inline bool walk_to (const typename die::value_type &here, + const die &there, typename die_map::iterator &cache) + { + return walk_to (here.children ().begin (), + here.children ().end (), + there, cache); + } + + bool walk_to (die it, const die &end, + const die &there, typename die_map::iterator &cache) + { + for (; it != end; ++it) { - _m_walker->_m_path.pop_back (); + if (it == there) + { + /* We can't keep the old CACHE iterator and avoid this + find (hash lookup), because there could have been + other insertions in the map since it was taken. + Those can invalidate old iterators. */ + cache = _m_seen->find (there->identity ()); + _m_seen->erase (cache); + cache = _m_seen->insert (cache, + std::make_pair (there->identity (), + _m_path)); + return true; + } + else + { + /* Do "step into" even for !has_children () + because it records this child in _m_seen, + which we will rely on later. */ + step into (this, it); + const typename die::value_type &child = *it; + if (child.has_children () && walk_to (child, there, cache)) + return true; + } } - }; + return false; + } + + /* First descend into the current DIE's children. + _m_path already has the current DIE, so it is ready to go. */ + // XXX is a reference to an owned DIE really possible?? + inline bool walk_down_to (const die &there, + typename die_map::iterator &cache) + { + const die &start = _m_path.back (); + const typename die::value_type &here = *start; + + /* It's common to have a reference to the next sibling DIE. + So bypass the descent to HERE's children if THERE is + HERE's immediate next sibling. */ + if (!here.has_children () || there == ++die (start)) + return false; + + return walk_to (here, there, cache); + } - // Random access to a DIE, find the path of the walk that gets there. - inline const die_path &path_to (const die &a) + /* A step_back object pops the current DIE off _m_path when + constructed, and pushes it back when destroyed. */ + struct step_back + { + dwarf_path_finder *_m_walker; + const die _m_here; + inline step_back (dwarf_path_finder *w, die ©) + : _m_walker (w), _m_here (w->_m_path.back ()) { - ::Dwarf_Off id = a->identity (); - std::pair found - = _m_seen->insert (std::make_pair (id, bad_die_path ())); - if (found.second - /* It's not in our _m_seen map. Our main walk recording - into _m_seen is exhaustive, so this can only be a forward - reference. That is, we didn't already hit this DIE in - our top-level walk and so it is not in _m_seen yet. - - We must do a separate walk to find it. Since we know - this is a forward reference, we don't have to start a - fresh walk from the root, just momentarily wind forward - from where we are. */ - && !walk_down_to (a, found.first) - && !walk_over_to (a, found.first) - && !walk_up_to (a, found.first)) - throw std::runtime_error ("DIE not reachable from CU!"); - assert (&found.first->second != NULL); - assert (!bad_die_path (found.first->second)); - return found.first->second; + w->_m_path.pop_back (); + copy = _m_here; } - - inline bool walk_to (const typename die::value_type &here, - const die &there, typename die_map::iterator &cache) + inline ~step_back () { - return walk_to (here.children ().begin (), - here.children ().end (), - there, cache); + _m_walker->_m_path.push_back (_m_here); } + }; + + /* Now wind the walk forward starting from the current DIE's + immediate sibling. */ + inline bool walk_over_to (const die &there, + typename die_map::iterator &cache) + { + die next; + step_back from (this, next); + ++next; + + return walk_to (next, (_m_path.empty () + ? (*_m_root).children ().end () + : _m_path.back ()->children ().end ()), + there, cache); + } - bool walk_to (die it, const die &end, - const die &there, typename die_map::iterator &cache) + /* A step_up object saves _m_path when constructed + and restores it when destroyed. */ + struct step_up + { + dwarf_path_finder *_m_walker; + die_path _m_save; + inline step_up (dwarf_path_finder *w) + : _m_walker (w), _m_save (w->_m_path) { - for (; it != end; ++it) - { - if (it == there) - { - /* We can't keep the old CACHE iterator and avoid this - find (hash lookup), because there could have been - other insertions in the map since it was taken. - Those can invalidate old iterators. */ - cache = _m_seen->find (there->identity ()); - _m_seen->erase (cache); - cache = _m_seen->insert (cache, - std::make_pair (there->identity (), - _m_path)); - return true; - } - else - { - /* Do "step into" even for !has_children () - because it records this child in _m_seen, - which we will rely on later. */ - step into (this, it); - const typename die::value_type &child = *it; - if (child.has_children () && walk_to (child, there, cache)) - return true; - } - } - return false; } - - /* First descend into the current DIE's children. - _m_path already has the current DIE, so it is ready to go. */ - // XXX is a reference to an owned DIE really possible?? - inline bool walk_down_to (const die &there, - typename die_map::iterator &cache) + inline ~step_up () { - const die &start = _m_path.back (); - const typename die::value_type &here = *start; - - /* It's common to have a reference to the next sibling DIE. - So bypass the descent to HERE's children if THERE is - HERE's immediate next sibling. */ - if (!here.has_children () || there == ++die (start)) - return false; - - return walk_to (here, there, cache); + _m_walker->_m_path.swap (_m_save); } + }; - /* A step_back object pops the current DIE off _m_path when - constructed, and pushes it back when destroyed. */ - struct step_back - { - tracker *_m_walker; - const die _m_here; - inline step_back (tracker *w, die ©) - : _m_walker (w), _m_here (w->_m_path.back ()) - { - w->_m_path.pop_back (); - copy = _m_here; - } - inline ~step_back () - { - _m_walker->_m_path.push_back (_m_here); - } - }; + /* Now wind the walk forward starting from the current DIE's + parent's immediate sibling. */ + inline bool walk_up_to (const die &there, + typename die_map::iterator &cache) + { + if (_m_path.empty ()) + return false; - /* Now wind the walk forward starting from the current DIE's - immediate sibling. */ - inline bool walk_over_to (const die &there, - typename die_map::iterator &cache) - { - die next; - step_back from (this, next); - ++next; - - return walk_to (next, (_m_path.empty () - ? (*_m_root).children ().end () - : _m_path.back ()->children ().end ()), - there, cache); - } + step_up from (this); - /* A step_up object saves _m_path when constructed - and restores it when destroyed. */ - struct step_up - { - tracker *_m_walker; - die_path _m_save; - inline step_up (tracker *w) - : _m_walker (w), _m_save (w->_m_path) + do { + _m_path.pop_back (); + assert (!_m_path.empty ()); + if (walk_over_to (there, cache)) + return true; } - inline ~step_up () - { - _m_walker->_m_path.swap (_m_save); - } - }; - - /* Now wind the walk forward starting from the current DIE's - parent's immediate sibling. */ - inline bool walk_up_to (const die &there, - typename die_map::iterator &cache) - { - if (_m_path.empty ()) - return false; + while (!_m_path.empty ()); - step_up from (this); + return false; + } + }; - do - { - _m_path.pop_back (); - assert (!_m_path.empty ()); - if (walk_over_to (there, cache)) - return true; - } - while (!_m_path.empty ()); + // Standard tracker. + template + class dwarf_ref_tracker : public dwarf_tracker_base + { + private: + typedef dwarf_tracker_base _base; - return false; - } - }; + public: + 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 tracker tracker1; - typedef tracker tracker2; + private: + typedef dwarf_path_finder tracker1; + typedef dwarf_path_finder tracker2; tracker1 _m_left; tracker2 _m_right;