]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Collect unique DIE shapes in dwarf_output construction.
authorRoland McGrath <roland@redhat.com>
Wed, 8 Jul 2009 09:16:14 +0000 (02:16 -0700)
committerRoland McGrath <roland@redhat.com>
Wed, 8 Jul 2009 10:13:36 +0000 (03:13 -0700)
libdw/ChangeLog
libdw/Makefile.am
libdw/c++/dwarf_data
libdw/c++/dwarf_edit
libdw/c++/dwarf_output
libdw/c++/output-shape.cc [new file with mode: 0644]
libdw/c++/subr.hh

index 8fef9dc461f09214281d0cfead116397230abaa2..81128e3d9252158970c5ed16e821905874ae7aa0 100644 (file)
@@ -1,3 +1,9 @@
+2009-07-08  Roland McGrath  <roland@redhat.com>
+
+       * c++/output-shape.cc: New file.
+       * Makefile.am (libdwpp_a_SOURCES): Add it.
+       * c++/dwarf_output: Call add_shape method there.
+
 2009-07-06  Roland McGrath  <roland@redhat.com>
 
        * c++/dwarf_tracker (tracker): Break out private class into ...
index 0d3e636bb275519833fce4bb0e262fbdf8fba476..baaa190541d6397591fcb342faf2273ea70ce340 100644 (file)
@@ -98,7 +98,7 @@ libdwpp_a_SOURCES = c++/values.cc \
                    c++/known.cc \
                    c++/line_info.cc \
                    c++/edit-values.cc \
-                   c++/output-values.cc
+                   c++/output-values.cc c++/output-shape.cc
 noinst_HEADERS    = c++/dwarf-knowledge.cc \
                    c++/data-values.hh
 
index 0c04eb8261f0f69761f0d580da932ddfe9ff67bb..c49360ce9d2e288e595fb026d131961842c131a5 100644 (file)
@@ -106,23 +106,15 @@ namespace elfutils
       friend class subr::create_container;
       friend class impl::compile_units;
     private:
-      inline compile_unit () :
-       impl::debug_info_entry (::DW_TAG_compile_unit)
-      {}
 
-      template<typename die_type>
-      static inline const die_type &require_cu (const die_type &die)
+      template<typename die_type, typename arg_type>
+      inline void set (const die_type &die, arg_type &arg)
       {
        if (die.tag () != ::DW_TAG_compile_unit)
          throw std::invalid_argument ("not a compile_unit entry");
-       return die;
+       impl::debug_info_entry::set (die, arg);
       }
 
-      template<typename die_type, typename tracker>
-      inline compile_unit (const die_type &die, tracker &t)
-       : impl::debug_info_entry (require_cu (die), t)
-      {}
-
     public:
 
       // Fetch the CU's DW_AT_stmt_list.
index fbd59b3fd0a49637064d5d6592be2e02ca9d6483..ac0a30b4265f061106055c57b3e66449858360df 100644 (file)
@@ -117,7 +117,9 @@ namespace elfutils
        template<typename input, typename tracker>
        static inline void
        equivalence (const iterator &out,
-                    const typename input::const_iterator &in, tracker &t)
+                    const typename input::const_iterator &in,
+                    bool,      // last-sibling
+                    tracker &t)
        {
          t.equivalence (out, in);
        }
index 3d8ea2eb2ce1562fe00500eaf8b48bb288de2ee7..8fed594030a1cc39ca921a0bcd395d3a2732f34e 100644 (file)
 
 #include "dwarf_edit"
 #include "dwarf_ref_maker"
+#include <algorithm>
 #include <functional>
+#include <iterator>
+#include <vector>
 #include <tr1/unordered_set>
 
 /* Read the comments for elfutils::dwarf first.
@@ -293,6 +296,7 @@ namespace elfutils
   protected:
     template<typename input> class copier; // Below.
 
+#if 0
     /* An iterator adapter for use in iterator-based constructors.
        collectify (iterator) yields an iterator on input where *i
        constructs output::value_type (input::value_type v, collector).  */
@@ -304,6 +308,7 @@ namespace elfutils
     {
       return subr::argifier<input, output, dwarf_output_collector &> (c) (in);
     }
+#endif
 
     /* Every kind of value is made by calling into the copier, which
        returns a const pointer into a value_set living in the collector.  */
@@ -426,6 +431,7 @@ namespace elfutils
 
     class debug_info_entry
     {
+      friend class dwarf_output_collector;
       friend class subr::create_container;
 
     public:
@@ -480,18 +486,18 @@ namespace elfutils
       private:
         inline children_type () {}
 
-       template<typename input, typename tracker>
+       template<typename input, typename copier>
        static inline void
-       equivalence (const iterator &out,
-                    const typename input::const_iterator &in, tracker &t)
+       copied (const iterator &out, const typename input::const_iterator &in,
+               bool last_sibling, copier &c)
        {
-         t.equivalence (out, in);
+         c.copied (out, in, last_sibling);
        }
 
-       template<typename input, typename tracker>
-       inline children_type (const input &other, tracker &t)
+       template<typename input, typename copier>
+       inline children_type (const input &other, copier &c)
        {
-         subr::create_container (this, other, t, equivalence<input, tracker>);
+         subr::create_container (this, other, c, copied<input, copier>);
        }
 
       public:
@@ -505,11 +511,12 @@ namespace elfutils
       int _m_tag;
       const attributes_type *_m_attributes;
       children_type _m_children;
+      void *_m_shape;
 
       // This is can only be used by the children_type constructor,
       // which immediately calls set.
       inline debug_info_entry ()
-       : _m_tag (-1), _m_attributes (NULL), _m_children ()
+       : _m_tag (-1), _m_attributes (NULL), _m_children (), _m_shape (NULL)
       {}
 
       template<typename die_type, typename input_dw>
@@ -533,21 +540,6 @@ namespace elfutils
       }
 
     public:
-      inline debug_info_entry (int t)
-       : _m_tag (t), _m_attributes (NULL), _m_children ()
-      {
-       if (unlikely (t <= 0))
-         throw std::invalid_argument ("invalid tag");
-      }
-
-      /* The template constructor lets us copy in from any class that has
-        compatibly iterable containers for attributes and children.  */
-      template<typename die_type, typename input_dw>
-      debug_info_entry (const die_type &die, copier<input_dw> &c)
-       : _m_tag (die.tag ()),
-         _m_attributes (c.add_attributes (die.attributes ())),
-         _m_children (die.children (), c)
-      {}
 
       inline int tag () const
       {
@@ -697,9 +689,12 @@ namespace elfutils
 
     // Constructor copying CUs from an input file (can be any of dwarf,
     // dwarf_edit, or dwarf_output).
+    // Copy construction instantiates a copier derived from the collector.
     template<typename input>
-    inline dwarf_output (const input &, dwarf_output_collector &,
-                        copier<input> = copier<input> ());
+    inline dwarf_output (const input &dw, dwarf_output_collector &c,
+                        copier<input> maker = copier<input> ())
+      : _m_units (dw.compile_units (), maker (c))
+    {}
 
     template<typename file>
     inline bool operator== (const file &other) const
@@ -713,15 +708,6 @@ namespace elfutils
     }
   };
 
-  /*
-template<typename flavor>
-  inline flavor &dwarf_output::attr_value::_base::flavor ()
-  {
-    assert (!"should be impossible");
-    throw std::logic_error ("should be impossible");
-  }
-  */
-
   // Explicit specializations.
   template<>
   std::string
@@ -738,6 +724,7 @@ template<typename flavor>
 
   private:
     typedef dwarf_output::debug_info_entry die_type;
+    typedef die_type::children_type::const_iterator die_ptr;
     typedef die_type::attributes_type attrs_type;
 
     subr::value_set<dwarf_output::value::value_string> _m_strings;
@@ -776,15 +763,42 @@ template<typename flavor>
     template<typename input, typename copier_type>
     inline const attrs_type *add_attributes (const input &x, copier_type &c)
     {
-      std::pair<attrs_set::iterator, bool> p
-       = _m_attr_sets.insert (attrs_type (x, c));
-      if (p.second)
-       {
-         // XXX hook for collection: abbrev building, etc.
-       }
-      return &(*p.first);
+      return &*_m_attr_sets.insert (attrs_type (x, c)).first;
     }
 
+    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);
+
   };
 
   template<class dw>
@@ -904,15 +918,15 @@ template<typename flavor>
     {
       return _m_collector->add_attributes (x, *this);
     }
-  };
 
-  // Copy construction instantiates a copier derived from the collector.
-  template<typename input>
-  inline dwarf_output::dwarf_output (const input &dw,
-                                    dwarf_output_collector &c,
-                                    copier<input> maker)
-    : _m_units (dw.compile_units (), maker (c))
-  {}
+    template<typename input_iter>
+    inline void copied (const debug_info_entry::children_type::iterator &out,
+                       const input_iter &in, bool last_sibling)
+    {
+      equivalence (out, in);
+      _m_collector->add_shape (*out, last_sibling);
+    }
+  };
 };
 
 #endif // <elfutils/dwarf_output>
diff --git a/libdw/c++/output-shape.cc b/libdw/c++/output-shape.cc
new file mode 100644 (file)
index 0000000..fdc40ae
--- /dev/null
@@ -0,0 +1,153 @@
+/* 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_lineptr:
+    case dwarf::VS_macptr:
+    case dwarf::VS_rangelistptr:
+    case dwarf::VS_source_line:
+    case dwarf::VS_source_column:
+      return DW_FORM_udata;
+
+    case dwarf::VS_location:
+      return (attr.second.location ().is_list ()
+             ? DW_FORM_udata : DW_FORM_block);
+
+
+    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));
+}
+
+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;
+}
index 8d42a77ebef877a9cc21525cd92d2c5f394851fd..986b443ac9f1508437f993affc5fc6bdb4bc3adf 100644 (file)
@@ -67,6 +67,8 @@ namespace elfutils
     struct hash<uint64_t> : public integer_hash<uint64_t> {};
     template<>
     struct hash<uint8_t> : public integer_hash<uint8_t> {};
+    template<>
+    struct hash<bool> : public integer_hash<bool> {};
 
     template<typename T1, typename T2>
     struct hash<std::pair<T1, T2> >
@@ -837,16 +839,18 @@ namespace elfutils
       inline create_container (container *me, const input &other,
                               arg_type &arg, hook_type &hook = hook_type ())
        {
-         for (typename input::const_iterator in = other.begin ();
-              in != other.end ();
-              ++in)
+         typename input::const_iterator in = other.begin ();
+         bool last = in == other.end ();
+         while (!last)
            {
              /* Don't copy-construct the entry from *in here because that
                 copies it again into the list and destroys the first copy.  */
              me->push_back (typename container::value_type ());
              typename container::iterator out = --me->end ();
              out->set (*in, arg);
-             hook (out, in, arg);
+             const typename input::const_iterator here = in++;
+             last = in == other.end ();
+             hook (out, in, last, arg);
            }
        }
     };