namespace elfutils
{
- // Standard tracker.
- template<class dwarf1, class dwarf2>
- class dwarf_ref_tracker : public dwarf_tracker_base<dwarf1, dwarf2>
+ // Basic tracker of tree-walk paths to DIEs.
+ template<typename dw>
+ class dwarf_path_finder
{
- private:
- typedef dwarf_tracker_base<dwarf1, dwarf2> _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> die_path;
private:
- template<typename cu, typename die>
- 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> 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<typename die_map::iterator, bool> 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<typename die_map::iterator, bool> 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 dwarf1, class dwarf2>
+ class dwarf_ref_tracker : public dwarf_tracker_base<dwarf1, dwarf2>
+ {
+ private:
+ typedef dwarf_tracker_base<dwarf1, dwarf2> _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<cu1, die1> tracker1;
- typedef tracker<cu2, die2> tracker2;
+ private:
+ typedef dwarf_path_finder<dwarf1> tracker1;
+ typedef dwarf_path_finder<dwarf2> tracker2;
tracker1 _m_left;
tracker2 _m_right;