+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 ...
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
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.
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);
}
#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.
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). */
{
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. */
class debug_info_entry
{
+ friend class dwarf_output_collector;
friend class subr::create_container;
public:
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:
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>
}
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
{
// 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
}
};
- /*
-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
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;
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>
{
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>
--- /dev/null
+/* 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;
+}
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> >
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);
}
}
};