]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
closest yet roland/dwarf_output-tracker
authorRoland McGrath <roland@redhat.com>
Thu, 20 Aug 2009 03:59:19 +0000 (20:59 -0700)
committerRoland McGrath <roland@redhat.com>
Thu, 20 Aug 2009 03:59:19 +0000 (20:59 -0700)
libdw/c++/dwarf
libdw/c++/dwarf_comparator
libdw/c++/dwarf_data
libdw/c++/dwarf_output
libdw/c++/dwarf_tracker
libdw/c++/values.cc
src/dwarfcmp.cc
tests/print-die.hh

index 61d9f8dae3a9d774395707bced24e0f8930f59f4..13257421db4721e802b492fbfa83645cd755df44 100644 (file)
@@ -946,7 +946,10 @@ namespace elfutils
       typedef attr_value mapped_type;
       typedef attribute value_type;
 
-      static const bool ordered = false;
+      static inline bool ordered ()
+      {
+       return false;
+      }
 
       inline attributes_type (const attributes_type &a)
        : attributes_base (a)
@@ -1285,7 +1288,11 @@ namespace elfutils
       typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type; // XXX reloc
       typedef key_type value_type;
 
-      static const bool ordered = false;
+      static inline bool ordered ()
+      {
+       return false;
+      }
+
       inline bool canonical () const
       {
        return false;
@@ -2320,7 +2327,10 @@ namespace elfutils
       typedef _base::iterator iterator;
       typedef _base::const_iterator const_iterator;
 
-      static const bool ordered = true;
+      static inline bool ordered ()
+      {
+       return true;
+      }
 
       struct hasher : public subr::container_hasher<arange_list> {};
 
@@ -2377,7 +2387,7 @@ namespace elfutils
        // Since we are not const, coalesce in place.
        coalesce (*this);
 
-       if (list::ordered && other.canonical ()
+       if (list::ordered () && other.canonical ()
            && size () != other.size ())
          return false;
 
@@ -2386,13 +2396,13 @@ namespace elfutils
          return true;
 
        // If he was sorted and canonical and we didn't match, it's conclusive.
-       if (list::ordered && other.canonical ())
+       if (list::ordered () && other.canonical ())
          return false;
 
        // Make a sorted and canonicalized copy to compare to.
        _base his (other);
        if (size () > his.size ()
-           || (list::ordered && size () == his.size ()))
+           || (list::ordered () && size () == his.size ()))
          // Coalescing can only make him smaller.
          return false;
        coalesce (his);
@@ -2402,7 +2412,7 @@ namespace elfutils
       template<typename list>
       inline bool operator== (const list &other) const
       {
-       if (list::ordered && other.canonical ()
+       if (list::ordered () && other.canonical ()
            && size () < other.size ())
          // Coalescing can only make us smaller.
          return false;
@@ -2412,7 +2422,7 @@ namespace elfutils
          return true;
 
        // Make a non-const copy that will coalesce in its operator==.
-       if (list::ordered && other.canonical ())
+       if (list::ordered () && other.canonical ())
          return size () != other.size () && arange_list (*this) == other;
 
        return arange_list (other) == *this;
index 9bba00586919b04ab354fd7645c63eeeda2a909d..7ba2475c3386b5f10e876bea2103f9533223b136 100644 (file)
@@ -160,8 +160,8 @@ namespace elfutils
     {}
 
     inline dwarf_tracker_base (const dwarf_tracker_base &, reference_match &,
-                              const left_context_type &, const die1 &,
-                              const right_context_type &, const die2 &)
+                              const left_context_type &,
+                              const right_context_type &)
     {}
   };
 
@@ -306,7 +306,7 @@ namespace elfutils
        }
 
       if (it1 != end1 && it2 != end2
-         && !(attributes1::ordered && attributes2::ordered))
+         && !(attributes1::ordered () && attributes2::ordered ()))
        {
          /* We have the same number of attributes, but the names don't match.
 
@@ -494,7 +494,7 @@ namespace elfutils
       bool result = !has_children;
       if (has_children)
        {
-         tracker t (_m_tracker, matched, lhs, ref1, rhs, ref2);
+         tracker t (_m_tracker, matched, lhs, rhs);
          result = dwarf_comparator (t).match (a.children (), b.children ());
        }
 
index d11efdb308963c71db04316678f46e6809facc26..b4de970de7a07d0dfbbab483fbba18e44f24423b 100644 (file)
@@ -1327,12 +1327,16 @@ namespace elfutils
 
       inline const std::string &string () const
       {
+       if (dynamic_cast<const typename vw::value_source_file *> (_m_value))
+         return source_file ().name ();
        return static_cast<const std::string &>
          (variant<typename vw::value_string> ());
       }
 
       inline std::string &string ()
       {
+       if (dynamic_cast<const typename vw::value_source_file *> (_m_value))
+         return source_file ().name ();
        return static_cast<std::string &>
          (variant<typename vw::value_string> ());
       }
@@ -1554,7 +1558,10 @@ namespace elfutils
       typedef typename base_type::value_type value_type;
       typedef typename base_type::mapped_type mapped_type;
 
-      static const bool ordered = true;
+      static inline bool ordered ()
+      {
+       return true;
+      }
 
       template<typename attrs>
       inline operator attrs () const
index 08a1b1548ed4d8200631703ea049043174696936..488ba1e26fe89300a4b65235aff9403169afc6d9 100644 (file)
@@ -1092,17 +1092,17 @@ namespace elfutils
       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 ());
+       return std::equal (a.begin (), a.end () - 1, b.begin (), equal_enough ());
       }
 
 #if 0             // XXX
       // 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),
+                     const left_context_type &lhs,
+                     const right_context_type &rhs)
+       : _m_left (proto._m_left, lhs),
+         _m_right (proto._m_right, rhs),
          _m_equiv (proto._m_equiv), _m_delete_equiv (false)
       {
        // We are starting a recursive consideration of a vs b.
@@ -1401,10 +1401,13 @@ namespace elfutils
          // It's finished, resolve the final reference.
          return _m_final->second.self ();
 
-       /* This entry is still dangling or pending.
-          Count the referrer's pending reference.  */
+       /* This entry is still dangling or pending.  Count the referrer's
+          pending reference.  We account this as a dangling reference
+          either if we have really not been seen yet at all, or if we are
+          still under construction--i.e. before resolve_refs has run.  */
 
-       referrer->count_pending (_m_pending == NULL, this, "refer");
+       referrer->count_pending (_m_pending == NULL || _m_building != NULL,
+                                this, "refer");
        _m_patch.push_back (std::make_pair (referrer, backptr));
 
        dump () << " nrefs " << _m_patch.size () << "\n";
@@ -1854,6 +1857,9 @@ namespace elfutils
        assert (_m_out == NULL);
        if (unlikely (_m_in->_m_final == NULL))
          {
+           std::cout.flush ();
+           _m_copier->dump_seen ();
+           std::cout.flush ();
            assert (_m_in->_m_pending != NULL);
            assert (_m_in->_m_pending->dangling ());
            throw std::runtime_error
index ee4b02fb62da4780a811c926a6509760147e3bb7..23a8a6af2546301a84ab0f7054810ff447ccd226 100644 (file)
@@ -54,6 +54,7 @@
 #include "dwarf_comparator"
 #include <tr1/unordered_map>
 #include <tr1/unordered_set>
+#include <deque>
 
 namespace elfutils
 {
@@ -66,26 +67,50 @@ namespace elfutils
     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;
+       as a stack of iterators pointing to the DIE at each level.
+
+       Note that the path to a DIE includes the iterator to that DIE
+       itself as the last element.  This is necessary to permit sharing
+       our _m_seen cache across CUs.  That sharing is useful when CUs
+       might share children (i.e. they use DW_TAG_imported_unit).
+       But when they do, then the "construct a derived tracker that
+       jump-starts a walk" case for following a reference might be for
+       a reference to another CU than the one the base tracker is
+       walking (_m_root).  When path_to finds the "context" path to the
+       referent, the iterator that jump-starts a new walk must be an
+       iterator pointing to the referent, but must be an iterator
+       somewhere in the _m_root CU's tree, not another CU's.
+
+       NOTE!!! XXX
+       This scenario means we can have a die_path in our _m_seen that
+       is not from our current _m_root CU.  This is only safe as long
+       as we are sure that we have already completely walked the other
+       CU that die_path came from so all its entries are in _m_seen.
+       This ensures that a derived tracker that jump-starts its walk at
+       a path in another CU will never actually have to do any walking.
+       If it ever walked, it could go awry failing to recognize the end
+       of its CU's children list--it's not _m_root->children ().end ().
+       If we want to generalize dwarf_path_finder so it can be used as
+       a generic cache when we might not have walked whole CUs, then we
+       need to change things.  We'd have to store _m_root along with
+       _m_path in _m_seen so that a derived tracker made from path_to
+       "context" can use the right _m_root.
+    */
+    typedef std::deque<die> die_path;
 
   private:
-    // We use a singleton list of a default-constructed iterator as a marker.
+    // We use an empty list as a marker; every path includes at least one DIE.
     static inline const die_path bad_die_path ()
     {
-      return die_path (1);
+      return die_path ();
     }
     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 ();
+      return path.empty ();
     }
 
-    /* We record every DIE we have seen here, mapping its .identity ()
-       to the die_path of parent DIEs taken to reach it.  */
+    /* We record every DIE we have seen here, mapping its .identity () to
+       the die_path of parent DIEs taken to reach it, including itself.  */
     typedef std::tr1::unordered_map<dwarf::debug_info_entry::identity_type,
                                    const die_path> die_map;
     die_map *_m_seen;
@@ -111,14 +136,13 @@ namespace elfutils
       : _m_seen (proto._m_seen), _m_delete_seen (false)
     {}
 
-    // Construct a derived tracker that jump-starts a walk.
+    /* Construct a derived tracker that jump-starts a walk.
+       CONTEXT is from a path_to call made on PROTO.  */
     inline dwarf_path_finder (const dwarf_path_finder &proto,
-                             const die_path &context, const die &there)
+                             const die_path &context)
       : _m_seen (proto._m_seen), _m_delete_seen (false),
        _m_root (proto._m_root), _m_path (context)
-    {
-      _m_path.push_back (there);
-    }
+    {}
 
     inline ~dwarf_path_finder ()
     {
@@ -156,15 +180,18 @@ namespace elfutils
     struct step
     {
       dwarf_path_finder *_m_walker;
-      inline step (dwarf_path_finder *w, const die &here)
+      inline step (dwarf_path_finder *w, const die &here,
+                  bool record = true)
        : _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));
-
-       // Append this DIE to the path we'll record for its children.
+       // Append this DIE to the path we'll record for it and its children.
        _m_walker->_m_path.push_back (here);
+
+       // Record the path down from the CU to see this DIE.
+       assert (!bad_die_path (_m_walker->_m_path));
+       if (record)
+         _m_walker->_m_seen->insert (std::make_pair (here->identity (),
+                                                     _m_walker->_m_path));
       }
       inline ~step ()
       {
@@ -226,6 +253,10 @@ namespace elfutils
                 Those can invalidate old iterators.  */
              cache = _m_seen->find (there);
              _m_seen->erase (cache);
+
+             // Include the iterator we've found in the path to itself.
+             step into (this, it, false);
+
              cache = _m_seen->insert (cache, std::make_pair (there, _m_path));
              return true;
            }
@@ -302,8 +333,7 @@ namespace elfutils
       die_path _m_save;
       inline step_up (dwarf_path_finder *w)
        : _m_walker (w), _m_save (w->_m_path)
-      {
-      }
+      {}
       inline ~step_up ()
       {
        _m_walker->_m_path.swap (_m_save);
@@ -472,7 +502,8 @@ namespace elfutils
     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 ());
+      // Ignore the last element, which is the target DIE itself.
+      return std::equal (a.begin (), a.end () - 1, b.begin (), equal_enough ());
     }
 
     class reference_match
@@ -539,10 +570,10 @@ namespace elfutils
     // Share the _m_seen maps with the prototype tracker,
     // but start a fresh walk from the given starting point.
     inline dwarf_ref_tracker (const dwarf_ref_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),
+                             const left_context_type &lhs,
+                             const right_context_type &rhs)
+      : _m_left (proto._m_left, lhs),
+       _m_right (proto._m_right, rhs),
        _m_equiv (proto._m_equiv), _m_delete_equiv (false)
     {
       // We are starting a recursive consideration of a vs b.
index f012434bcddd6527c83d21f1376c8be3c6cd0fe2..c8f65bb389f341b361952168d37a2e72de1ad082 100644 (file)
@@ -63,7 +63,6 @@ using namespace elfutils;
 using namespace std;
 
 #include "dwarf-knowledge.cc"
-
 \f
 // dwarf::attr_value disambiguation and dispatch.
 
index 1ab2744ad6e5a63794d9a2ffc12d22a6153be1cf..91081587768e16f557fced0639707f72500ff505 100644 (file)
@@ -146,9 +146,9 @@ struct talker : public dwarf_ref_tracker<dwarf1, dwarf2>
   {}
 
   inline talker (const talker &proto, typename _tracker::reference_match &m,
-                const typename _tracker::left_context_type &l, const die1 &a,
-                const typename _tracker::right_context_type &r, const die2 &b)
-    : _tracker (static_cast<const _tracker &> (proto), m, l, a, r, b),
+                const typename _tracker::left_context_type &l,
+                const typename _tracker::right_context_type &r)
+    : _tracker (static_cast<const _tracker &> (proto), m, l, r),
       a_ (NULL), b_ (NULL)
   {
   }
index 7b4fa3f54274e3c57688b28b52ce930ff44baf98..d946a9eb6955ca043df0da0bebee2bae09dd39e3 100644 (file)
@@ -39,6 +39,8 @@
 
 static bool print_offset;
 static bool sort_attrs;
+static bool elide_refs;
+static bool dump_refs;
 
 static enum { copy_none, copy_edit, copy_output } make_copy;
 
@@ -63,6 +65,20 @@ print_die_main (int &argc, char **&argv, unsigned int &depth)
       ++argv;
     }
 
+  if (argc > 1 && !strcmp (argv[1], "--norefs"))
+    {
+      elide_refs = true;
+      --argc;
+      ++argv;
+    }
+
+  if (argc > 1 && !strcmp (argv[1], "--dump-refs"))
+    {
+      dump_refs = true;
+      --argc;
+      ++argv;
+    }
+
   if (argc > 1 && !strcmp (argv[1], "--sort-attrs"))
     {
       sort_attrs = true;
@@ -92,7 +108,8 @@ print_die_main (int &argc, char **&argv, unsigned int &depth)
 }
 
 static int next_ref = 1;
-typedef tr1::unordered_map< ::Dwarf_Off, int> refs_map;
+typedef tr1::unordered_map<dwarf::debug_info_entry::identity_type,
+                          int> refs_map;
 
 template<typename attrs_type,
         void (*act) (const typename attrs_type::value_type &, refs_map &)
@@ -114,7 +131,7 @@ public:
 
   static inline void walk (const attrs_type &attrs, refs_map &r)
   {
-    if (attrs_type::ordered || !sort_attrs)
+    if (attrs_type::ordered () || !sort_attrs)
       for (iterator i = attrs.begin (); i != attrs.end (); ++i)
        (*act) (*i, r);
     else
@@ -133,8 +150,13 @@ void
 print_attr (const typename attrs_type::value_type &attr, refs_map &refs)
 {
   if (!print_offset && attr.second.what_space () == dwarf::VS_reference)
-    cout << " " << dwarf::attributes::name (attr.first) << "=\"#ref"
-        << dec << refs[attr.second.reference ()->identity ()] << "\"";
+    {
+      if (elide_refs)
+       cout << " " << dwarf::attributes::name (attr.first) << "=\"ref\"";
+      else
+       cout << " " << dwarf::attributes::name (attr.first) << "=\"#ref"
+            << dec << refs[attr.second.reference ()->identity ()] << "\"";
+    }
   else
     cout << " " << to_string (attr);
 }
@@ -174,6 +196,9 @@ prewalk_die (const typename file::debug_info_entry &die, refs_map &refs)
   prewalk_attrs (die.attributes (), refs);
 }
 
+static int nth;
+static std::map<int, int> nth_ref;
+
 template<typename file>
 static void
 print_die (const typename file::debug_info_entry &die,
@@ -182,14 +207,21 @@ print_die (const typename file::debug_info_entry &die,
   string prefix (indent, ' ');
   const string tag = dwarf::tags::name (die.tag ());
 
+  ++nth;
+  if (dump_refs)
+    cout << dec << nth << ": ";
+
   cout << prefix << "<" << tag;
   if (print_offset)
-    cout << " offset=[" << die.offset () << "]";
-  else
+    cout << " offset=[" << hex << die.offset () << "]";
+  else if (!elide_refs)
     {
       refs_map::const_iterator it = refs.find (die.identity ());
       if (it != refs.end ())
-       cout << " ref=\"ref" << dec << it->second << "\"";
+       {
+         cout << " ref=\"ref" << dec << it->second << "\"";
+         nth_ref[nth] = it->second;
+       }
     }
 
   print_attrs (die.attributes (), refs);
@@ -214,6 +246,12 @@ print_die (const typename file::debug_info_entry &die,
     cout << "/>\n";
 }
 
+static inline void
+dump_nth (pair<int, int> p)
+{
+  cout << dec << p.first << ": ref" << p.second << "\n";
+}
+
 template<typename file>
 static void
 print_cu (const typename file::compile_unit &cu, const unsigned int limit)
@@ -223,10 +261,13 @@ print_cu (const typename file::compile_unit &cu, const unsigned int limit)
 
   refs_map refs;
 
-  if (!print_offset)
+  if (!print_offset && !elide_refs)
     prewalk_die<file> (die, refs);
 
   print_die<file> (die, 1, limit, refs);
+
+  if (dump_refs)
+    for_each (nth_ref.begin (), nth_ref.end (), dump_nth);
 }
 
 template<typename file>