]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Add libdw/c++/ from origin/dwarf branch
authorDjordje Todorovic <djordje.todorovic@rt-rk.com>
Tue, 26 Sep 2017 13:11:06 +0000 (15:11 +0200)
committerMark Wielaard <mark@klomp.org>
Fri, 6 Oct 2017 12:41:37 +0000 (14:41 +0200)
Signed-off-by: Djordje Todorovic <djordje.todorovic@rt-rk.com>
16 files changed:
libdw/c++/data-values.hh [new file with mode: 0644]
libdw/c++/dwarf [new file with mode: 0644]
libdw/c++/dwarf-knowledge.cc [new file with mode: 0644]
libdw/c++/dwarf_comparator [new file with mode: 0644]
libdw/c++/dwarf_data [new file with mode: 0644]
libdw/c++/dwarf_edit [new file with mode: 0644]
libdw/c++/dwarf_output [new file with mode: 0644]
libdw/c++/dwarf_ref_maker [new file with mode: 0644]
libdw/c++/dwarf_tracker [new file with mode: 0644]
libdw/c++/edit-values.cc [new file with mode: 0644]
libdw/c++/exception.cc [new file with mode: 0644]
libdw/c++/known.cc [new file with mode: 0644]
libdw/c++/line_info.cc [new file with mode: 0644]
libdw/c++/output-values.cc [new file with mode: 0644]
libdw/c++/subr.hh [new file with mode: 0644]
libdw/c++/values.cc [new file with mode: 0644]

diff --git a/libdw/c++/data-values.hh b/libdw/c++/data-values.hh
new file mode 100644 (file)
index 0000000..71244ee
--- /dev/null
@@ -0,0 +1,105 @@
+/* elfutils::dwarf_data common internal templates.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "dwarf_data"
+
+template<typename v, typename subtype>
+static inline bool is_a (const typename v::value_dispatch *value)
+{
+  return dynamic_cast<const subtype *> (value) != NULL;
+}
+
+namespace elfutils
+{
+  template<class impl, typename v>
+  dwarf::value_space
+  dwarf_data::attr_value<impl, v>::what_space () const
+  {
+    if (is_a<v, typename v::value_flag> (_m_value))
+      return dwarf::VS_flag;
+    if (is_a<v, typename v::value_dwarf_constant> (_m_value))
+      return dwarf::VS_dwarf_constant;
+    if (is_a<v, typename v::value_reference> (_m_value))
+      return dwarf::VS_reference;
+    if (is_a<v, typename v::value_lineptr> (_m_value))
+      return dwarf::VS_lineptr;
+    if (is_a<v, typename v::value_macptr> (_m_value))
+      return dwarf::VS_macptr;
+    if (is_a<v, typename v::value_rangelistptr> (_m_value))
+      return dwarf::VS_rangelistptr;
+    if (is_a<v, typename v::value_identifier> (_m_value))
+      return dwarf::VS_identifier;
+    if (is_a<v, typename v::value_string> (_m_value))
+      return dwarf::VS_string;
+    if (is_a<v, typename v::value_source_file> (_m_value))
+      return dwarf::VS_source_file;
+    if (is_a<v, typename v::value_source_line> (_m_value))
+      return dwarf::VS_source_line;
+    if (is_a<v, typename v::value_source_column> (_m_value))
+      return dwarf::VS_source_column;
+    if (is_a<v, typename v::value_address> (_m_value))
+      return dwarf::VS_address;
+    if (is_a<v, typename v::value_constant> (_m_value)
+       || is_a<v, typename v::value_constant_block> (_m_value))
+      return dwarf::VS_constant;
+    if (is_a<v, typename v::value_location> (_m_value))
+      return dwarf::VS_location;
+
+    throw std::logic_error ("attr_value has no known value_space!");
+  }
+
+  template<typename attr_pair>
+  static inline std::string
+  attribute_string (const attr_pair &attr)
+  {
+    std::string result = dwarf::attributes::name (attr.first);
+    result += "=";
+    result += attr.second.to_string ();
+    return result;
+  }
+
+  template<typename die_type>
+  std::string
+  die_string (const die_type &die)
+  {
+    std::string result ("<");
+    result += dwarf::tags::name (die.tag ());
+
+    typename die_type::attributes_type::const_iterator name_attr
+      = die.attributes ().find (::DW_AT_name);
+    if (name_attr != die.attributes ().end ())
+      {
+       result += " ";
+       result += to_string (*name_attr);
+      }
+
+    result += die.has_children () ? ">" : "/>";
+    return result;
+  }
+
+};
diff --git a/libdw/c++/dwarf b/libdw/c++/dwarf
new file mode 100644 (file)
index 0000000..5e06dde
--- /dev/null
@@ -0,0 +1,2476 @@
+/* -*- C++ -*- interfaces for libdw.
+   Copyright (C) 2009-2011 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF
+#define _ELFUTILS_DWARF        1
+
+#include "libdw.h"
+#include "dwarf.h"
+#include "subr.hh"
+#include <stdexcept>
+
+#include <list>
+#include <map>
+#include <set>
+#include <vector>
+#include <algorithm>
+#include <functional>
+#include <tr1/unordered_map>
+
+/* Abstractly, one DWARF object file consists of a few containers.
+   (We omit .debug_frame for now.  It does not interact with the others.)
+
+   1. list of compilation units                (.debug_info)
+   2. map of PC ranges to CU           (.debug_aranges)
+   3. map of global names to CU+DIE    (.debug_pubnames)
+   4. map of type names to CU+DIE      (.debug_pubtypes)
+
+   These maps refer to the CUs in .debug_info and optimize lookups
+   compared to simple iteration.
+
+   A compile_unit is a debug_info_entry.
+   A debug_info_entry consists of a tag (int/enum), and two containers:
+   children and attributes.  The attributes are an unordered map of name
+   (int/enum) to attribute value (complex variant record).  Children are
+   in an ordered list, each also a debug_info_entry.
+
+   dwarf.compile_units ()              works like list<compile_unit>
+       -> compile_unit : debug_info_entry
+               .attributes ()          like unordered_map<int, attr_value>
+               .children ()            works like list<debug_info_entry>
+                       -> debug_info_entry
+                               .attributes ()
+                               .children ()
+
+  A compile_unit is not deeply special, it's just a debug_info_entry.
+  It has its own class just for some convenience methods that only
+  make sense for a compile_unit DIE.
+
+  This is the "logical" view of the file, grafting and eliding parts of the
+  raw information that are purely the structural elements of DWARF and not
+  part of the abstract semantics.  In the file reader (elfutils::dwarf),
+  these containers form a layer above the raw containers that expose the
+  file data directly (as the libdw C interfaces do).
+
+  dwarf.raw_compile_units ()           works like list<compile_unit>
+       -> compile_unit : debug_info_entry
+               .raw_attributes ()      like unordered_map<int, attr_value>
+               .raw_children ()        works like list<debug_info_entry>
+                       -> debug_info_entry
+                               .raw_attributes ()
+                               .raw_children ()
+
+  compile_units () elides DW_TAG_partial_unit members,
+  raw_compile_units () includes them.
+
+  attributes () elides DW_AT_sibling, raw_attributes () includes it.
+
+  raw_children () reports DW_TAG_imported_unit as any other child.
+  children () flattens imported units into the containing list.
+
+  The == and != comparisons for dwarf and debug_info_entry objects compare
+  their logical containers, not the raw containers.  The comparisons are
+  defined via templates, so you can compare elfutils::dwarf with any other
+  class that implements the same structure of containers with input iterators.
+
+  The elfutils::dwarf class and its inner classes form a thin, read-only
+  layer of virtual containers that ideally could inline away entirely to
+  calls into the C libdw API and small amounts of stack storage.  The tree
+  of objects described above never exists in memory in its entirety.  The
+  objects are constructed on the fly in each call to a container method.
+
+  See the dwarf_edit and dwarf_output headers for other classes that are
+  template-compatible with the "logical view" interface above, but do not
+  support any of the "raw" container variants.  These == and != comparisons
+  are template-driven too, so all different classes can be compared.
+
+  The output classes have template-driven copy constructors, so they can be
+  copied from files or substructures of the elfutils::dwarf input classes.
+
+  ------ XXX to be done: more file-level containers
+
+  input side only:
+
+  units_by_addr : map<pair<begin,end>, CU> and map<address, CU>
+       use dwarf_getarange_addr
+
+  pub{names,types} : map<string, debug_info_entry> (across all CUs)
+
+  output too:
+
+  pubnames_map : map<string, debug_info_entry>
+  pub{names,types}_units : map<compile_unit, pubnames_map>
+       too much lang knowledge to autogenerate for now,
+       output will do it explicitly
+
+ */
+
+// DWARF reader interfaces: front end to <libdw.h> routines
+namespace elfutils
+{
+  template<typename type>
+  inline std::string to_string (const type &item)
+  {
+    return item.to_string ();
+  }
+
+  template<typename key1, typename value1, class pair2>
+  inline bool operator== (const std::pair<key1, value1> &a, const pair2 &b)
+  {
+    return a.first == b.first && a.second == b.second;
+  }
+
+  // Used like std::vector<elt>, but is really just a simple fixed array.
+  template<typename elt>
+  class const_vector
+  {
+  private:
+    size_t _m_size;
+    const elt *_m_array;
+
+  public:
+    typedef size_t size_type;
+    typedef ptrdiff_t difference_type;
+    typedef elt value_type;
+    typedef const elt *const_iterator;
+
+    const_vector ()
+      : _m_size (0), _m_array (NULL) {}
+    const_vector (const const_vector &v)
+      : _m_size (v._m_size), _m_array (v._m_array) {}
+    const_vector (const elt *start, const elt *stop)
+      : _m_size (stop - start), _m_array (start) {}
+    const_vector (const ::Dwarf_Block &b)
+      : _m_size (b.length), _m_array (reinterpret_cast<const elt *> (b.data)) {}
+
+    inline const_vector &operator= (const const_vector &v)
+    {
+      _m_size = v._m_size;
+      _m_array = v._m_array;
+      return *this;
+    }
+
+    inline size_t size () const
+    {
+      return _m_size;
+    }
+    inline bool empty () const
+    {
+      return _m_size == 0;
+    }
+
+    const_iterator begin () const
+    {
+      return _m_array;
+    }
+    const_iterator end () const
+    {
+      return &_m_array[_m_size];
+    }
+
+    template<typename other>
+    inline operator other () const
+    {
+      return other (begin (), end ());
+    }
+
+    template<typename vec>
+    inline bool operator== (const vec &other) const
+    {
+      return (other.size () == size ()
+             && std::equal (begin (), end (), other.begin ()));
+    }
+    template<typename vec>
+    inline bool operator!= (const vec &other) const
+    {
+      return !(*this == other);
+    }
+
+  };
+
+  // One DWARF object file.
+  class dwarf
+  {
+  private:
+    static const char *known_tag (int);
+    static const char *known_attribute (int);
+
+  public:
+    typedef subr::known<__typeof ("DW_TAG_"), known_tag> tags;
+    typedef subr::known<__typeof ("DW_AT_"), known_attribute> attributes;
+
+    template<typename attribute>
+    static inline std::string attribute_name (const attribute &attr)
+    {
+      int code = attr.first;
+      return attributes::name (code);
+    }
+
+    template<int key>
+    class known_enum
+    {
+    public:
+      static size_t prefix_length ();
+      static const char *identifier (int);
+      inline static const char *name (int value)
+      {
+       const char *id = identifier (value);
+       return id != NULL ? id + prefix_length () : NULL;
+      }
+
+      // XXX perhaps have iterator/lookup methods like a read-only map?
+    };
+
+    typedef known_enum< ::DW_AT_producer> forms;
+    typedef known_enum< ::DW_AT_location> ops;
+
+  private:
+    static void throw_libdw (::Dwarf *dw); // XXX raises (...)
+    static void throw_libdw (::Dwarf_CU *); // XXX raises (...)
+
+    inline void xif (bool fail) const
+    {
+      if (unlikely (fail))
+       throw_libdw (_m_dw);
+    }
+    static inline void xif (::Dwarf_CU *cu, bool fail)
+    {
+      if (unlikely (fail))
+       throw_libdw (cu);
+    }
+
+    static inline void xif (const ::Dwarf_Attribute *attr, bool fail)
+    {
+      xif (attr->cu, fail);
+    }
+    static inline void xif (const ::Dwarf_Die *die, bool fail)
+    {
+      xif (die->cu, fail);
+    }
+
+    template<typename raw, typename raw_element, typename element,
+            bool skip (const raw_element &)>
+    class skipping_wrapper
+    {
+    protected:
+      typedef typename raw::const_iterator raw_iterator;
+
+      raw _m_raw;
+
+    protected:
+      inline skipping_wrapper (const raw &r) : _m_raw (r) {}
+
+    public:
+      inline skipping_wrapper (const skipping_wrapper &w) : _m_raw (w._m_raw) {}
+
+      /*
+       iterator: wraps raw iterator, skips DW_AT_sibling
+       size/empty: search for DW_AT_sibling, adjust raw size
+      */
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, element>
+      {
+       friend class skipping_wrapper<raw, raw_element, element, skip>;
+      private:
+       raw_iterator _m_raw;
+       const raw_iterator _m_end;
+
+       inline void jiggle ()
+       {
+         while (_m_raw != _m_end && unlikely (skip (*_m_raw)))
+           ++_m_raw;
+       }
+
+      public:
+       inline const_iterator ()
+         : _m_raw (), _m_end (raw::end ())
+       {
+       }
+
+       const_iterator (const const_iterator &i)
+         : _m_raw (i._m_raw), _m_end (i._m_end) {}
+
+       // Start at the raw position and skip as necessary.
+       const_iterator (const raw_iterator &begin, const raw_iterator &end)
+         : _m_raw (begin), _m_end (end)
+       {
+         jiggle ();
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_raw = other._m_raw;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return _m_raw == other._m_raw;
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       struct hasher : public std::unary_function<const_iterator, size_t>
+       {
+         size_t operator () (const const_iterator &i) const
+         {
+           return subr::hash_this (i._m_raw);
+         }
+       };
+
+       inline const_iterator &operator++ () // prefix
+       {
+         ++_m_raw;
+         jiggle ();
+         return *this;
+       }
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+
+       inline element operator* () const
+       {
+         return static_cast<element> (*_m_raw);
+       }
+      };
+
+      inline const_iterator begin () const
+      {
+       return const_iterator (_m_raw.begin (), _m_raw.end ());
+      }
+      inline const_iterator end () const
+      {
+       const raw_iterator raw_end = _m_raw.end ();
+       return const_iterator (raw_end, raw_end);
+      }
+    };
+
+  public:
+    /*
+      getstring
+    */
+
+    class attribute;
+    class attr_value;
+    class location_attr;
+    class range_list;
+    class ranges;
+    class line_info_table;
+    class file_table;
+    class line_table;
+    class line_entry;
+    class dwarf_enum;
+
+    class debug_info_entry
+    {
+    private:
+      ::Dwarf_Die _m_die;
+      inline ::Dwarf_Die *thisdie () const
+      {
+       return const_cast< ::Dwarf_Die *> (&_m_die);
+      }
+
+      friend class dwarf;
+      friend class attr_value;
+    protected:
+
+      inline void xif (bool fail) const
+      {
+       dwarf::xif (_m_die.cu, fail);
+      }
+
+      inline debug_info_entry ()
+      {
+       memset (&_m_die, 0, sizeof _m_die);
+      }
+
+    public:
+      debug_info_entry (const debug_info_entry &die) : _m_die (die._m_die) {}
+
+      inline debug_info_entry (const dwarf &dw, ::Dwarf_Off off)
+      {
+       dw.xif (::dwarf_offdie (dw._m_dw, off, &_m_die) == NULL);
+      }
+
+      /* Return the compile_unit entry containing this entry.
+        Note this might be a DW_TAG_partial_unit.  */
+      inline debug_info_entry compile_unit () const
+      {
+       debug_info_entry result;
+       xif (::dwarf_diecu (thisdie (), &result._m_die, NULL, NULL) == NULL);
+       return result;
+      }
+
+      // Containers, see class definitions below.
+      class raw_children_type;
+      inline raw_children_type raw_children () const;
+      class raw_attributes_type;
+      raw_attributes_type raw_attributes () const;
+      class children_type;
+      inline children_type children () const;
+      class attributes_type;
+      attributes_type attributes () const;
+
+      class const_pointer;
+
+      inline std::string to_string () const;
+
+      inline int tag () const
+      {
+       int t = ::dwarf_tag (thisdie ());
+       xif (t <= 0);
+       return t;
+      }
+
+      bool has_children () const
+      {
+       int has = ::dwarf_haschildren (thisdie ());
+       xif (has < 0);
+       return has != 0;
+      }
+
+      /*
+       const char *tag_name () const
+       const_string tag_name () const // "name" or "0x123"
+      */
+
+      template<typename die>
+      bool operator== (const die &other) const
+      {
+       return (tag () == other.tag ()
+               && attributes () == other.attributes ()
+               && children () == other.children ());
+      }
+      template<typename die>
+      bool operator!= (const die &other) const
+      {
+       return !(*this == other);
+      }
+
+      ::Dwarf_Off offset () const
+      {
+       return ::dwarf_dieoffset (thisdie ());
+      }
+
+      inline const dwarf::ranges ranges () const
+      {
+       return dwarf::ranges (*this);
+      }
+
+      /* This is an identity pointer that only matches the very same
+        DIE in the very same file (same opened Dwarf instance).  */
+      typedef uintptr_t identity_type;
+      inline identity_type identity () const
+      {
+       return (uintptr_t) _m_die.addr;
+      }
+
+      ::Dwarf_Off cost () const;
+    };
+
+    // Container for raw list of child DIEs, intended to be a compatible with
+    // a read-only, unidirectional subset of std::list<debug_info_entry>.
+    class debug_info_entry::raw_children_type
+    {
+      friend class debug_info_entry;
+    private:
+      const debug_info_entry &_m_die;
+
+    protected:
+      inline raw_children_type (const debug_info_entry &die) : _m_die (die) {}
+
+    public:
+      typedef debug_info_entry value_type;
+
+      inline raw_children_type (const raw_children_type &c)
+       : _m_die (c._m_die)
+      {}
+
+      bool empty () const
+      {
+       return begin () == end ();
+      }
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, debug_info_entry>
+      {
+       friend class debug_info_entry;
+       friend class attr_value;
+      private:
+       debug_info_entry _m_die;
+
+       inline const_iterator ()
+       {}
+
+       inline const_iterator (const debug_info_entry &parent)
+       {
+         int result = ::dwarf_child (parent.thisdie (), &_m_die._m_die);
+         parent.xif (result < 0);
+       }
+
+       // Construct from a reference attribute.
+       inline const_iterator (Dwarf_Attribute *attr)
+       {
+         dwarf::xif (attr, ::dwarf_formref_die (attr, &_m_die._m_die) == NULL);
+       }
+
+      public:
+       inline const_iterator (const const_iterator &i) : _m_die (i._m_die) {}
+
+       inline const debug_info_entry &operator* () const
+       {
+         if (unlikely (_m_die._m_die.addr == NULL))
+           throw std::runtime_error ("dereferencing end iterator");
+         return _m_die;
+       }
+       inline const debug_info_entry *operator-> () const
+       {
+         return &(operator* ());
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_die = other._m_die;
+         return *this;
+       }
+
+       // Assign directly from a DIE, as if "taking its address".
+       inline const_iterator &operator= (const debug_info_entry &die)
+       {
+         _m_die = die;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return _m_die._m_die.addr == other._m_die._m_die.addr;
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       struct hasher : public std::unary_function<const_iterator, size_t>
+       {
+         size_t operator () (const const_iterator &i) const
+         {
+           return subr::hash_this ((uintptr_t) i._m_die._m_die.addr);
+         }
+       };
+
+       inline const_iterator &operator++ () // prefix
+       {
+         int result = ::dwarf_siblingof (&_m_die._m_die, &_m_die._m_die);
+         _m_die.xif (result < 0);
+         if (result > 0)       // Hit the end.
+           *this = const_iterator ();
+         return *this;
+       }
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+      };
+      const_iterator begin () const
+      {
+       return const_iterator (_m_die);
+      }
+      static inline const_iterator end ()
+      {
+       return const_iterator ();
+      }
+
+      template<typename other_children>
+      bool operator== (const other_children &other) const
+      {
+       return subr::container_equal (*this, other);
+      }
+      template<typename other_children>
+      bool operator!= (const other_children &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    // Container for list of raw attributes as (name, value) pairs,
+    // intended to be compatible with a read-only, unidirectional
+    // subset of std::list<std::pair<int, attr_value>>.
+    class debug_info_entry::raw_attributes_type
+    {
+      friend class debug_info_entry;
+    private:
+      const debug_info_entry &_m_die;
+
+      raw_attributes_type (const debug_info_entry &die)
+       : _m_die (die)
+      {}
+
+    public:
+      typedef attribute value_type;
+
+      inline raw_attributes_type (const raw_attributes_type &a)
+       : _m_die (a._m_die)
+      {}
+
+      size_t size () const;
+      inline bool empty () const
+      {
+       return size () == 0;
+      }
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, attribute>
+      {
+       friend class raw_attributes_type;
+      private:
+       debug_info_entry _m_die;
+       ptrdiff_t _m_offset; // Offset for next iteration in dwarf_getattrs.
+       ::Dwarf_Attribute _m_attr;
+
+       /* We get called up to twice per iteration.  The first time, we
+          store *ATTR in the instance variable and return DWARF_CB_OK so
+          that we might be called again.  The second time, we return
+          DWARF_CB_ABORT so that the iteration will stop at the next
+          attribute's offset.  */
+       static int getattrs_callback (Dwarf_Attribute *attr, void *arg)
+       {
+         const_iterator *i = static_cast<const_iterator *> (arg);
+         if (i->_m_attr.valp == NULL)
+           {
+             i->_m_attr = *attr;
+             return DWARF_CB_OK;
+           }
+         return DWARF_CB_ABORT;
+       }
+
+       inline const_iterator (const debug_info_entry &die, ptrdiff_t offset)
+         : _m_die (die), _m_offset (offset), _m_attr ()
+       {}
+
+       inline const_iterator (ptrdiff_t offset)
+         : _m_die (), _m_offset (offset), _m_attr ()
+       {}
+
+      public:
+       // Default constructor: invalid for anything but operator=.
+       inline const_iterator ()
+         : _m_die (), _m_offset (-1), _m_attr ()
+       {}
+
+       inline const_iterator (const const_iterator &i)
+         : _m_die (i._m_die), _m_offset (i._m_offset), _m_attr (i._m_attr)
+       {}
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_die = other._m_die;
+         _m_offset = other._m_offset;
+         _m_attr = other._m_attr;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return (_m_die._m_die.addr == other._m_die._m_die.addr
+                 && _m_attr.valp == other._m_attr.valp);
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       inline const_iterator &operator++ () // prefix
+       {
+         _m_attr.valp = NULL;
+         int result = ::dwarf_getattrs (&_m_die._m_die, &getattrs_callback,
+                                        (void *) this, _m_offset);
+         _m_die.xif (result < 0);
+         _m_offset = result;
+         if (result == 1)
+           // End iterators have no live pointers.
+           _m_die._m_die.addr = NULL;
+         return *this;
+       }
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+
+       inline attribute operator* () const
+       {
+         if (unlikely (_m_attr.valp == NULL))
+           throw std::runtime_error ("dereferencing end iterator");
+         return attribute (_m_die, _m_attr);
+       }
+      };
+      inline const_iterator begin () const
+      {
+       const_iterator i = const_iterator (_m_die, 0);
+       return ++i;
+      }
+      static inline const_iterator end ()
+      {
+       return const_iterator (1);
+      }
+
+      // XXX can do faster internal (?)
+      inline const_iterator find (int name) const
+      {
+       const_iterator i = begin ();
+       while (i != end () && (*i).first != name)
+         ++i;
+       return i;
+      }
+    };
+
+    // Container for list of child DIEs, intended to be a compatible with
+    // a read-only, unidirectional subset of std::list<debug_info_entry>.
+    // Same as raw_children, but flattens DW_TAG_imported_unit children.
+    class debug_info_entry::children_type
+      : public debug_info_entry::raw_children_type
+    {
+      friend class debug_info_entry;
+    private:
+
+      inline children_type (const debug_info_entry &die)
+       : raw_children_type::raw_children_type (die) {}
+
+    public:
+      typedef debug_info_entry value_type;
+
+      inline children_type (const children_type &c)
+       : raw_children_type (c)
+      {}
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, debug_info_entry>
+      {
+       friend class children_type;
+      private:
+
+       typedef raw_children_type::const_iterator raw_iterator;
+       subr::sharing_stack<raw_iterator> _m_stack;
+
+       /* Push and pop until _m_stack.top () == raw_children_type::end ()
+          or it's looking at a DIE other than DW_TAG_imported_unit.  */
+       inline void jiggle ()
+       {
+         while (true)
+           {
+             const raw_iterator &i = _m_stack.const_top ();
+
+             if (i == raw_children_type::end ())
+               {
+                 /* We're at the end of this raw DIE.
+                    Pop out to the iterator on the importing unit.  */
+                 _m_stack.pop ();
+
+                 if (_m_stack.empty ())
+                   // That was the outermost unit, this is the end.
+                   break;
+
+                 continue;
+               }
+
+             if (i->tag () == ::DW_TAG_imported_unit)
+               // We have an imported unit.  Look at its referent.
+               _m_stack.push (i->attributes ().at (::DW_AT_import)
+                              .reference ()->raw_children ().begin ());
+             else
+               // This is some other DIE.  Iterate on it.
+               break;
+           }
+       }
+
+      public:
+       inline const_iterator ()
+         : _m_stack ()
+       {}
+
+       inline const_iterator (const raw_iterator &i)
+       {
+         _m_stack.push (i);
+         jiggle ();
+       }
+
+       inline const_iterator (const const_iterator &i)
+         : _m_stack (i._m_stack)
+       {}
+
+       // Construct directly from a DIE, as if "taking its address".
+       inline const_iterator (const debug_info_entry &die)
+       {
+         raw_iterator it;
+         it = die;
+         _m_stack.push (it);
+         jiggle ();
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_stack = other._m_stack;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return _m_stack == other._m_stack;
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       inline const debug_info_entry &operator* () const
+       {
+         return *_m_stack.top ();
+       }
+       inline const debug_info_entry *operator-> () const
+       {
+         return &(operator* ());
+       }
+
+       inline const_iterator &operator++ () // prefix
+       {
+         ++_m_stack.top ();
+         jiggle ();
+         return *this;
+       }
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+      };
+
+      // Actually always const.
+      typedef const_iterator iterator;
+
+      const_iterator begin () const
+      {
+       return const_iterator (raw_children_type::begin ());
+      }
+      const_iterator end () const
+      {
+       return const_iterator (raw_children_type::end ());
+      }
+
+      template<typename other_children>
+      bool operator== (const other_children &other) const
+      {
+       return subr::container_equal (*this, other);
+      }
+      template<typename other_children>
+      bool operator!= (const other_children &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    class debug_info_entry::const_pointer
+      : public debug_info_entry::children_type::const_iterator
+    {};
+
+  private:
+    static inline bool skip_sibling (const attribute &attr)
+    {
+      return attr.first == ::DW_AT_sibling;
+    }
+
+    // Circumvent C++ namespace lookup.
+    typedef class debug_info_entry::raw_attributes_type die_raw_attrs;
+    typedef skipping_wrapper<die_raw_attrs, attribute, attribute, skip_sibling>
+    attributes_base;
+
+  public:
+    // Container for attributes, indexed by name, intended to be compatible
+    // with a read-only subset of std::unordered_map<int, attr_value>.
+    // This excludes DW_AT_sibling.
+    class debug_info_entry::attributes_type : public attributes_base
+    {
+      friend class dwarf;
+    private:
+      inline attributes_type (const raw_attributes_type &raw)
+       : attributes_base (raw) {}
+
+    public:
+      typedef int key_type;
+      typedef attr_value mapped_type;
+      typedef attribute value_type;
+
+      static inline bool ordered ()
+      {
+       return false;
+      }
+
+      inline attributes_type (const attributes_type &a)
+       : attributes_base (a)
+      {}
+
+      typedef attributes_base::const_iterator const_iterator;
+
+      /*
+       iterator: wraps raw_attributes iterator, skips DW_AT_sibling
+       size/empty: search for DW_AT_sibling, adjust raw_attributes size
+       */
+
+      inline const_iterator find (int name) const
+      {
+       if (unlikely (name == ::DW_AT_sibling))
+         return end ();
+       return const_iterator (_m_raw.find (name), _m_raw.end ());
+      }
+
+      /*
+       Same as find (), but if the attribute name isn't found,
+       but there is  is an abstract_origin or specification
+       attribute, then will try to find_integrate () the name
+       from that reference.
+      */
+      inline const_iterator find_integrate (int name) const
+      {
+       const_iterator result = find (name);
+       if (result != end ())
+         return result;
+
+       result = find (DW_AT_abstract_origin);
+       if (result == end ())
+         result = find (DW_AT_specification);
+
+       if (result != end ())
+         {
+           debug_info_entry integrate = (*(*result).second.reference ());
+           return integrate.attributes ().find_integrate (name);
+         }
+
+       return end ();
+      }
+
+      inline const attr_value at (int name)
+      {
+       const_iterator i = find (name);
+       if (unlikely (i == end ()))
+         throw std::out_of_range ("XXX");
+       return (*i).second;
+      }
+      inline const attr_value operator[] (int name)
+      {
+       return at (name);
+      }
+
+      // We are rvalue-coercible into a std::map, which is sorted by name.
+      inline operator std::map<int, attr_value> () const
+      {
+       return std::map<int, attr_value> (begin (), end ());
+      }
+      /*
+      template<typename attrs>
+      inline operator attrs () const
+      {
+       return attrs (begin (), end ());
+      }
+      */
+
+      template<typename attrs>
+      bool operator== (const attrs &other) const
+      {
+       /* Our container is unordered (i.e., in file order).  A set of
+          attributes is conceptually equal if all the pairs match,
+          regardless of the order.  But the container_equal algorithm will
+          compare corresponding elements in order.  So we need an ordered
+          map of our attributes for the comparison.  */
+       const std::map<int, attr_value> mine = *this;
+       const std::map<int, typename attrs::mapped_type> his = other;
+       return mine.size () == his.size () && subr::container_equal (mine, his);
+      }
+
+      template<typename attrs>
+      bool operator!= (const attrs &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    class compile_unit : public debug_info_entry
+    {
+    public:
+      inline compile_unit (const debug_info_entry &die)
+       : debug_info_entry (die) {}
+
+      // Fetch the CU's DW_AT_stmt_list.
+      const line_info_table line_info () const;
+
+      // Convenience methods for line_info_table sub-containers.
+      inline const file_table files () const
+      {
+       return line_info ().files ();
+      }
+      inline const line_table lines () const
+      {
+       return line_info ().lines ();
+      }
+
+      /*
+       containers/iterators:
+
+       XXX macros
+
+       abbrevs (punt)
+
+      */
+    };
+
+    // These are the kinds of values that attributes can have.
+    enum value_space
+      {
+       // These spaces refer purely to DWARF concepts.
+       VS_flag,                // Boolean.
+       VS_dwarf_constant,      // Known DW_X_* space of integer constants.
+       VS_discr_list,          // Block as used for DW_AT_discr_list.
+       VS_reference,           // Pointer to another DIE.
+       VS_lineptr,             // Pointer into .debug_line section.
+       VS_macptr,              // Pointer into .debug_macinfo section.
+       VS_rangelistptr,        // Pointer into .debug_ranges section.
+
+       // These spaces refer to textual details of the program source.
+       VS_identifier,          // String, identifier in source language.
+       VS_string,              // String, miscellaneous use.
+       VS_source_file,         // Source file, string or index into file table.
+       VS_source_line,         // Line number in source file.
+       VS_source_column,       // Column number in source file.
+
+       // These spaces refer to target-format values in the debuggee.
+       VS_address,        // Address constant.
+       VS_constant,       // Other constant, integer or in target formats.
+       VS_location,       // Location expression or location list.
+      };
+
+    /* A source file can be just a file name.  When represented in the
+       .debug_line file table, it can also have a modtime and a file size.
+       If the modtime or size stored is zero, it doesn't count.  */
+    class source_file
+    {
+      friend class attr_value;
+      friend class file_table;
+      friend class line_entry;
+    private:
+      ::Dwarf_Attribute _m_attr;
+      inline ::Dwarf_Attribute *thisattr () const
+      {
+       return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+      }
+
+      source_file (const Dwarf_Attribute &attr) : _m_attr (attr) {}
+
+    public:
+      std::string to_string () const;
+
+      const char *name () const;
+      ::Dwarf_Word mtime () const;
+      ::Dwarf_Word size () const;
+
+      template<typename other_file>
+      bool operator== (const other_file &other) const
+      {
+       if (mtime () != 0)
+         {
+           ::Dwarf_Word other_mtime = other.mtime ();
+           if (other_mtime != 0 && other_mtime != mtime ())
+             return false;
+         }
+       if (size () != 0)
+         {
+           ::Dwarf_Word other_size = other.size ();
+           if (other_size != 0 && other_size != size ())
+             return false;
+         }
+       return subr::name_equal<typeof (other.name ())> () (name (),
+                                                           other.name ());
+      }
+      template<typename other_file>
+      inline bool operator!= (const other_file &other) const
+      {
+       return !(*this == other);
+      }
+
+      /* Return a value unique to us while we're in memory.
+        This is a stable pointer into the Dwarf_Files data
+         or to a static empty string.  */
+      inline uintptr_t identity () const
+      {
+       return (uintptr_t) name ();
+      }
+    };
+
+    // This describes the value of an attribute.
+    class attr_value
+    {
+      friend class attribute;
+      friend class location_attr;
+      friend class range_list;
+      friend class dwarf_enum;
+    private:
+      const int _m_tag;
+      ::Dwarf_Attribute _m_attr;
+      inline ::Dwarf_Attribute *thisattr () const
+      {
+       return const_cast< ::Dwarf_Attribute *> (&_m_attr);
+      }
+      inline int whatattr () const
+      {
+       return ::dwarf_whatattr (thisattr ());
+      }
+
+      attr_value (int tag, const ::Dwarf_Attribute &attr)
+       : _m_tag (tag), _m_attr (attr) {}
+
+      inline bool same (const attr_value &other) const
+      {
+       return _m_attr.valp == other._m_attr.valp;
+      }
+
+    public:
+      // not copyable, don't worry about ref lifetime(?)
+      // attr_value (const attr_value &v) : _m_attr (v.attr) {}
+
+      value_space what_space () const;
+      inline std::string to_string () const;
+
+      // Return an iterator on which * will yield the referent debug_info_entry.
+      inline debug_info_entry::children_type::const_iterator
+      reference () const
+      {
+       return (debug_info_entry::raw_children_type::const_iterator
+               (thisattr ()));
+      }
+
+      // XXX reloc, dwfl
+      ::Dwarf_Addr address () const;
+
+      bool flag () const;
+
+      const location_attr location () const;
+
+      const char *string () const;
+      inline const char *identifier () const
+      {
+       return string ();
+      }
+
+      const dwarf::source_file source_file () const;
+      inline unsigned int source_line () const
+      {
+       return constant ();
+      }
+      inline unsigned int source_column () const
+      {
+       return constant ();
+      }
+
+      // XXX reloc
+      ::Dwarf_Word constant () const;
+      ::Dwarf_Sword signed_constant () const;
+      const_vector<uint8_t> constant_block () const;
+      bool constant_is_integer () const;
+
+      inline const dwarf_enum dwarf_constant () const
+      {
+       return dwarf_enum (*this);
+      }
+
+      inline const range_list ranges () const
+      {
+       return range_list (*this);
+      }
+
+      const line_info_table line_info () const;
+
+      // XXX macptr
+
+      template<typename value>
+      inline bool operator== (const value &other) const
+      {
+       const value_space what = what_space ();
+       if (likely (other.what_space () == what))
+         switch (what)
+           {
+           case VS_reference:
+             // Stateless reference equality is just identity.
+             return (reference ()->identity ()
+                     == other.reference ()->identity ());
+
+           case VS_flag:
+             return flag () == other.flag ();
+
+           case VS_rangelistptr:
+             return ranges () == other.ranges ();
+
+           case VS_lineptr:
+             return line_info () == other.line_info ();
+
+           case VS_macptr:     // XXX punt for now, treat as constant
+             /*FALLTHRU*/
+           case VS_dwarf_constant:
+             return constant () == other.constant ();
+
+           case VS_constant:
+             if (constant_is_integer ())
+               return (other.constant_is_integer ()
+                       && constant () == other.constant ());
+             return (!other.constant_is_integer ()
+                     && constant_block () == other.constant_block ());
+
+           case VS_source_line:
+             return source_line () == other.source_line ();
+           case VS_source_column:
+             return source_column () == other.source_column ();
+
+           case VS_identifier:
+             return subr::name_equal<typeof (other.identifier ())> ()
+               (identifier (), other.identifier ());
+
+           case VS_string:
+             return subr::name_equal<typeof (other.string ())> ()
+               (string (), other.string ());
+
+           case VS_address:
+             return address () == other.address ();
+
+           case VS_source_file:
+             return source_file () == other.source_file ();
+
+           case VS_location:
+             return location () == other.location ();
+
+           case VS_discr_list:
+             throw std::runtime_error ("XXX unimplemented");
+           }
+       return false;
+      }
+      template<typename value>
+      inline bool operator!= (const value &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    /* The DW_AT_ranges attribute yields a range list.
+       XXX reloc
+       This is equivalent to unordered_set<pair<Dwarf_Addr, Dwarf_Addr> >.  */
+    class range_list
+    {
+      friend class attr_value;
+    private:
+      const attr_value _m_attr;
+
+      range_list (const attr_value &attr) : _m_attr (attr) {}
+
+    public:
+      typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type; // XXX reloc
+      typedef key_type value_type;
+
+      static inline bool ordered ()
+      {
+       return false;
+      }
+
+      inline bool canonical () const
+      {
+       return false;
+      }
+
+      inline range_list (const range_list &other)
+       : _m_attr (other._m_attr)
+      {}
+
+      std::string to_string () const;
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, value_type>
+      {
+       friend class range_list;
+      protected:
+       ::Dwarf_Addr _m_base;   // XXX reloc
+       ::Dwarf_Addr _m_begin;  // XXX reloc
+       ::Dwarf_Addr _m_end;    // XXX reloc
+       ::Dwarf_CU *_m_cu;
+       unsigned char *_m_readptr;
+
+       static unsigned char *formptr (int secndx, Dwarf_Attribute *);
+       const_iterator (int secndx, Dwarf_Attribute *, unsigned char *readptr);
+
+      public:
+       // Default constructor: only valid for operator=.
+       inline const_iterator ()
+         : _m_base (-1), _m_begin (0), _m_end (0), _m_cu (NULL), _m_readptr ((unsigned char *)1)
+       {}
+
+       inline const_iterator (const const_iterator &i)
+         : _m_base (i._m_base), _m_begin (i._m_begin), _m_end (i._m_end),
+           _m_cu (i._m_cu), _m_readptr (i._m_readptr)
+       {}
+
+       inline value_type operator* () const
+       {
+         if (unlikely (_m_readptr == (unsigned char *)-1))
+           throw std::runtime_error ("dereferencing end iterator");
+         return std::make_pair (_m_base + _m_begin, _m_base + _m_end);
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_base = other._m_base;
+         _m_begin = other._m_begin;
+         _m_end = other._m_end;
+         _m_cu = other._m_cu;
+         _m_readptr = other._m_readptr;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return _m_readptr == other._m_readptr && _m_cu == other._m_cu;
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       const_iterator &operator++ (); // prefix
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+      };
+
+      const_iterator begin () const;
+      const_iterator end () const
+      {
+       return const_iterator (-1, _m_attr.thisattr (), (unsigned char *)-1);
+      }
+
+      const_iterator find (const key_type &match) const
+      {
+       return std::find (begin (), end (), match);
+      }
+
+    private:
+      struct entry_contains
+       : public std::binary_function<key_type, ::Dwarf_Addr, bool>
+      {
+       inline bool operator() (const key_type &range, const ::Dwarf_Addr addr)
+         const
+       {
+         return addr >= range.first && addr < range.second;
+       }
+      };
+
+    public:
+      const_iterator find (const ::Dwarf_Addr addr) const
+      {
+       return std::find_if (begin (), end (),
+                            std::bind2nd (entry_contains (), addr));
+      }
+
+      inline operator std::set<key_type> () const
+      {
+       return std::set<key_type> (begin (), end ());
+      }
+
+      template<typename ranges>
+      inline bool operator== (const ranges &other) const
+      {
+       /* Our container is unordered (i.e., in file order).  A range list
+          is conceptually equal if all the pairs match, regardless of the
+          order.  But the std::equal algorithm will compare corresponding
+          elements in order.  So we need an ordered set for comparison.  */
+       std::set<key_type> mine = *this;
+       coalesce (mine);
+       std::set<key_type> his = other;
+       coalesce (his);
+       return mine == his;
+      }
+      template<typename ranges>
+      inline bool operator!= (const ranges &other) const
+      {
+       return !(*this == other);
+      }
+
+      // Not very wise to call.
+      size_t size () const
+      {
+       return subr::length (begin (), end ());
+      }
+    };
+
+    /* A location attribute yields a location expression.
+       Either it's a single expression, or a map of PC to location.  */
+    class location_attr
+    {
+      friend class attr_value;
+    private:
+      attr_value _m_attr;
+
+      location_attr (const attr_value &attr) : _m_attr (attr) {}
+
+      inline bool same (const location_attr &it) const
+      {
+       return _m_attr.same (it._m_attr);
+      }
+
+      template<typename pair>
+      struct nonempty : public std::unary_function<pair, bool>
+      {
+       inline bool operator () (const pair &x)
+       {
+         return !x.second.empty ();
+       }
+      };
+
+      template<typename pair>
+      struct any : public std::unary_function<pair, bool>
+      {
+       inline bool operator () (const pair &)
+       {
+         return true;
+       }
+      };
+
+    public:
+      typedef size_t size_type;
+      typedef ptrdiff_t difference_type;
+      // XXX need proper type for exprs
+      typedef const_vector<uint8_t> mapped_type;
+      typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type; // XXX reloc
+      typedef std::pair<const key_type, mapped_type> value_type;
+
+      std::string to_string () const;
+
+      bool is_list () const;
+
+      inline mapped_type location () const
+      {
+       if (is_list ())
+         throw std::runtime_error ("location is list, not single location");
+       return _m_attr.constant_block ();
+      }
+
+      class const_iterator
+       : public range_list::const_iterator
+      {
+       friend class location_attr;
+      private:
+       ::Dwarf_Block _m_block;
+
+       void advance ();
+
+       // For end iterator.
+       inline explicit const_iterator (Dwarf_Attribute *attr)
+         : dwarf::range_list::const_iterator (-1, attr, (unsigned char *)-1)
+         , _m_block ()
+       {}
+
+      public:
+       typedef location_attr::value_type value_type;
+
+       inline const_iterator ()
+         : _m_block ()
+       {}
+
+       inline const_iterator (const const_iterator &i)
+         : range_list::const_iterator (i), _m_block (i._m_block)
+       {}
+
+       inline const_iterator &operator= (const const_iterator &i)
+       {
+         range_list::const_iterator::operator= (i);
+         _m_block = i._m_block;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &it) const
+       {
+         return _m_block.data == it._m_block.data;
+       }
+       inline bool operator!= (const const_iterator &it) const
+       {
+         return !(*this == it);
+       };
+
+       const_iterator &operator++ (); // prefix
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+
+       inline value_type operator* () const
+       {
+         if (unlikely (_m_block.data == NULL))
+           throw std::runtime_error ("dereferencing end iterator");
+
+         return value_type (key_type (_m_base + _m_begin, _m_base + _m_end),
+                            const_vector<uint8_t> (_m_block));
+       }
+      };
+
+      const_iterator begin () const;
+      inline const_iterator end () const
+      {
+       return const_iterator (_m_attr.thisattr ());
+      }
+
+      inline bool empty () const
+      {
+       if (is_list ())
+         return std::find_if (begin (), end (),
+                              nonempty<value_type> ()) == end ();
+       return location ().empty ();
+      }
+      inline size_type size () const
+      {
+       if (is_list ())
+         return subr::length (begin (), end ());
+       return location ().empty () ? 0 : 1;
+      }
+
+      template<typename other_attr>
+      bool operator== (const other_attr &other) const
+      {
+       if (empty ())
+         return (other.empty ()
+                 || std::find_if (other.begin (), other.end (),
+                                  nonempty<typename other_attr::value_type> ()
+                                  ) == other.end ());
+
+       if (!is_list () && !other.is_list ())
+         return !other.empty () && location () == other.location ();
+
+       return subr::container_equal (*this, other);
+      }
+      template<typename other_file>
+      inline bool operator!= (const other_file &other) const
+      {
+       return !(*this == other);
+      }
+
+      /*
+       XXX missing: find, at; by key_type or by PC
+       XXX worse than that: multiple overlapping matches!
+       */
+    };
+
+    /* This describes a CU's file table.  It works like a read-only
+       std::vector<source_file>, and also supports lookup by name.  */
+    class file_table
+    {
+    private:
+      ::Dwarf_Files *_m_files;
+
+    public:
+      typedef size_t size_type;
+      typedef ptrdiff_t difference_type;
+      typedef source_file value_type;
+
+      inline file_table (::Dwarf_Files *const files)
+       : _m_files (files) {}
+      inline file_table (const file_table &t)
+       : _m_files (t._m_files) {}
+
+      inline file_table &operator= (const file_table &t)
+      {
+       _m_files = t._m_files;
+       return *this;
+      }
+
+      typedef subr::indexed_iterator<file_table> const_iterator;
+
+      inline bool empty () const
+      {
+       return size () == 0;
+      }
+
+      size_t size () const;
+
+      inline const_iterator begin () const
+      {
+       return const_iterator (*this, 0);
+      }
+      inline const_iterator end () const
+      {
+       return const_iterator (*this, size ());
+      }
+
+      const source_file at (size_t idx) const;
+      const source_file operator[] (size_t idx) const
+      {
+       return at (idx);
+      }
+
+      // Look up by matching file name.
+      const_iterator find (const source_file &) const;
+      const_iterator find (const char *filename) const
+      {
+       const_iterator i = begin ();
+       while (i != end () && strcmp ((*i).name (), filename) != 0)
+         ++i;
+       return i;
+      }
+      template<typename string>
+      const_iterator find (const string &filename) const
+      {
+       const_iterator i = begin ();
+       while (i != end () && filename != (*i).name ())
+         ++i;
+       return i;
+      }
+    };
+
+    // This describes one entry in the line information table.
+    class line_entry
+    {
+    private:
+      ::Dwarf_Line *_m_line;
+
+    public:
+      line_entry (::Dwarf_Line *entry) : _m_line (entry) {}
+      line_entry (const line_entry &entry) : _m_line (entry._m_line) {}
+
+      // XXX reloc, dwfl
+      ::Dwarf_Addr address () const;
+
+      bool statement () const;
+      bool basic_block () const;
+      bool end_sequence () const;
+      bool prologue_end () const;
+      bool epilogue_begin () const;
+
+      const source_file file () const;
+      unsigned int line () const;
+      unsigned int column () const;
+
+      template<typename entry>
+      bool operator< (const entry &other) const
+      {
+       return address () < other.address ();
+      }
+      template<typename entry>
+      bool operator> (const entry &other) const
+      {
+       return address () > other.address ();
+      }
+      template<typename entry>
+      bool operator<= (const entry &other) const
+      {
+       return address () <= other.address ();
+      }
+      template<typename entry>
+      bool operator>= (const entry &other) const
+      {
+       return address () >= other.address ();
+      }
+
+      template<typename entry>
+      inline bool operator== (const entry &other) const
+      {
+       return (address () == other.address ()
+               && line () == other.line ()
+               && column () == other.column ()
+               && statement () == other.statement ()
+               && basic_block () == other.basic_block ()
+               && end_sequence () == other.end_sequence ()
+               && prologue_end () == other.prologue_end ()
+               && epilogue_begin () == other.epilogue_begin ()
+               && file () == other.file ());
+      }
+      template<typename entry>
+      inline bool operator!= (const entry &other) const
+      {
+       return !(*this == other);
+      }
+      // Short-circuit for our own type.
+      bool operator== (const line_entry &other) const;
+    };
+
+    /* This describes a CU's line information table.
+       It works like a read-only std::vector<line_entry>,
+       and also supports lookup by address.
+       XXX later, by file/line
+    */
+    class line_table
+    {
+    private:
+      ::Dwarf_Lines *_m_lines;
+
+    public:
+      typedef size_t size_type;
+      typedef ptrdiff_t difference_type;
+      typedef line_entry value_type;
+
+      inline line_table (::Dwarf_Lines *const lines)
+       : _m_lines (lines) {}
+      inline line_table (const line_table &t)
+       : _m_lines (t._m_lines) {}
+
+      inline line_table &operator= (const line_table &t)
+      {
+       _m_lines = t._m_lines;
+       return *this;
+      }
+
+      std::string to_string () const;
+
+      typedef subr::indexed_iterator<line_table> const_iterator;
+
+      inline bool empty () const
+      {
+       return size () == 0;
+      }
+
+      size_t size () const;
+
+      inline const_iterator begin () const
+      {
+       return const_iterator (*this, 0);
+      }
+      inline const_iterator end () const
+      {
+       return const_iterator (*this, size ());
+      }
+
+      const line_entry at (size_t idx) const;
+      const line_entry operator[] (size_t idx) const
+      {
+       return at (idx);
+      }
+
+      template<typename table>
+      inline bool operator== (const table &other) const
+      {
+       return size () == other.size () && subr::container_equal (*this, other);
+      }
+      template<typename table>
+      inline bool operator!= (const table &other) const
+      {
+       return !(*this == other);
+      }
+      // Short-circuit for comparing to self.
+      inline bool operator== (const line_table &other) const
+      {
+       return (_m_lines == other._m_lines
+               || subr::container_equal (*this, other));
+      }
+
+      // Look up by matching address.
+      const_iterator find (::Dwarf_Addr) const;
+    };
+
+    // The DW_AT_stmt_list attribute yields a line info table.
+    class line_info_table
+    {
+    private:
+      ::Dwarf_Files *_m_files;
+
+    public:
+      inline line_info_table (::Dwarf_Files *const t)
+       : _m_files (t) {}
+      inline line_info_table (const line_info_table &t)
+       : _m_files (t._m_files) {}
+
+      inline line_info_table &operator= (const line_info_table &t)
+      {
+       _m_files = t._m_files;
+       return *this;
+      }
+
+      std::string to_string () const;
+
+      inline const file_table files () const
+      {
+       return file_table (_m_files);
+      }
+      const line_table lines () const;
+
+      template<typename table>
+      inline bool operator== (const table &other) const
+      {
+       return lines () == other.lines ();
+      }
+      template<typename table>
+      inline bool operator!= (const table &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    class dwarf_enum
+    {
+      friend class attr_value;
+    private:
+      const attr_value _m_attr;
+
+      dwarf_enum (const attr_value &attr) : _m_attr (attr) {}
+
+    public:
+      inline operator unsigned int () const
+      {
+       return _m_attr.constant ();
+      }
+
+      std::string to_string () const;
+
+      const char *identifier () const;
+      const char *name () const;
+
+      // Return the DW_AT_* indicating which enum this value belongs to.
+      unsigned int which () const
+      {
+       return _m_attr.whatattr ();
+      }
+
+      template<typename constant>
+      inline bool operator== (const constant &other) const
+      {
+       return (static_cast<unsigned int> (*this)
+               == static_cast<unsigned int> (other));
+      }
+      template<typename constant>
+      inline bool operator!= (const constant &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    // This describes one attribute, equivalent to pair<const int, attr_value>.
+    class attribute
+    {
+      friend class debug_info_entry::raw_attributes_type::const_iterator;
+      friend class attr_value;
+    private:
+      inline ::Dwarf_Attribute *thisattr () const
+      {
+       return second.thisattr ();
+      }
+
+      class lhs
+      {
+       friend class attribute;
+      private:
+       const attribute &_m_attr;
+
+       lhs (attribute &attr) : _m_attr (attr) {}
+
+      public:
+       operator int () const
+       {
+         return ::dwarf_whatattr (_m_attr.thisattr ());
+       }
+      };
+
+      attribute (const debug_info_entry &die, const ::Dwarf_Attribute &attr)
+       : first (*this), second (die.tag (), attr) {}
+
+    public:
+      lhs first;
+      attr_value second;
+
+      inline attribute (const attribute &a)
+       : first (*this), second (a.second) {}
+
+      // This lets pair<...> x = (attribute) y work.
+      template<typename value>
+      operator std::pair<const int, value> () const
+      {
+       return std::make_pair (static_cast<int> (first), value (second));
+      }
+
+      template<typename pair>
+      inline bool operator== (const pair &other) const
+      {
+       return first == other.first && second == other.second;
+      }
+      template<typename pair>
+      inline bool operator!= (const pair &other) const
+      {
+       return !(*this == other);
+      }
+
+      inline std::string to_string () const;
+    };
+
+    /* This works like range_list, but is based on a debug_info_entry using
+       dwarf_ranges.  If the entry has DW_AT_low_pc and DW_AT_high_pc, this
+       will present a singleton list; if it has a DW_AT_ranges, it will be
+       the same as the range_list presentation.  If neither, an empty list.  */
+    class ranges
+    {
+      friend class debug_info_entry;
+    private:
+      debug_info_entry _m_die;
+
+      ranges (const debug_info_entry &die) : _m_die (die) {}
+
+    public:
+      typedef std::pair< ::Dwarf_Addr, ::Dwarf_Addr> key_type; // XXX reloc
+      typedef key_type value_type;
+
+      ranges (const ranges &other) : _m_die (other._m_die) {}
+
+      std::string to_string () const;
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, value_type>
+      {
+       friend class ranges;
+      private:
+       debug_info_entry _m_die;
+       ::Dwarf_Addr _m_base;   // XXX reloc
+       ::Dwarf_Addr _m_begin;  // XXX reloc
+       ::Dwarf_Addr _m_end;    // XXX reloc
+       ptrdiff_t _m_offset;
+
+       inline const_iterator (const debug_info_entry &die)
+         : _m_die (die), _m_offset (0) {}
+
+      public:
+       inline const_iterator (const const_iterator &i)
+         : _m_die (i._m_die), _m_base (i._m_base),
+           _m_begin (i._m_begin), _m_end (i._m_end),
+           _m_offset (i._m_offset) {}
+
+       inline value_type operator* () const
+       {
+         if (unlikely (_m_offset == 0))
+           throw std::runtime_error ("dereferencing end iterator");
+         return std::make_pair (_m_begin, _m_end);
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_die = other._m_die;
+         _m_base = other._m_base;
+         _m_begin = other._m_begin;
+         _m_end = other._m_end;
+         _m_offset = other._m_offset;
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return (_m_die._m_die.addr == other._m_die._m_die.addr
+                 && _m_offset == other._m_offset);
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       const_iterator &operator++ () // prefix
+       {
+         do
+           _m_offset = dwarf_ranges (_m_die.thisdie (), _m_offset,
+                                     &_m_base, &_m_begin, &_m_end);
+         // Skip over empty ranges.
+         while (_m_offset != 0 && _m_begin == _m_end);
+         return *this;
+       }
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+      };
+
+      const_iterator begin () const
+      {
+       const_iterator it (_m_die);
+       return ++it;
+      }
+      const_iterator end () const
+      {
+       return const_iterator (_m_die);
+      }
+
+      inline bool empty () const
+      {
+       return begin () == end ();
+      }
+
+      const_iterator find (const key_type &match) const
+      {
+       return std::find (begin (), end (), match);
+      }
+
+    private:
+      struct entry_contains
+       : public std::binary_function<key_type, ::Dwarf_Addr, bool>
+      {
+       inline bool operator() (const key_type &range, const ::Dwarf_Addr addr)
+         const
+       {
+         return addr >= range.first && addr < range.second;
+       }
+      };
+
+    public:
+      const_iterator find (const ::Dwarf_Addr addr) const
+      {
+       return std::find_if (begin (), end (),
+                            std::bind2nd (entry_contains (), addr));
+      }
+
+      inline operator std::set<key_type> () const
+      {
+       return std::set<key_type> (begin (), end ());
+      }
+
+      template<typename ranges>
+      inline bool operator== (const ranges &other) const
+      {
+       /* Our container is unordered (i.e., in file order).  A range list
+          is conceptually equal if all the pairs match, regardless of the
+          order.  But the std::equal algorithm will compare corresponding
+          elements in order.  So we need an ordered set for comparison.  */
+       std::set<key_type> mine = *this;
+       coalesce (mine);
+       std::set<key_type> his = other;
+       coalesce (his);
+       return mine == his;
+      }
+      template<typename ranges>
+      inline bool operator!= (const ranges &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    // Container for raw CUs in file order, intended to be compatible
+    // with a read-only subset of std::list<compile_unit>.
+    class raw_compile_units_type
+    {
+      friend class dwarf;
+    private:
+      const dwarf &_m_file;
+
+      raw_compile_units_type (const dwarf &file) : _m_file (file) {}
+
+    public:
+      typedef compile_unit value_type;
+
+      inline raw_compile_units_type (const raw_compile_units_type &u)
+       : _m_file (u._m_file) {}
+
+      class const_iterator
+       : public std::iterator<std::input_iterator_tag, compile_unit>
+      {
+       friend class raw_compile_units_type;
+      private:
+       debug_info_entry _m_die;
+       const dwarf *_m_file;   // XXX
+       ::Dwarf_Off _m_next;    // XXX
+
+       inline const_iterator (const dwarf &file)
+         : _m_file (&file), _m_next (0) {}
+
+      public:
+       inline const_iterator ()
+         : _m_die (), _m_file (NULL), _m_next (-1)
+       {}
+
+       inline const_iterator (const const_iterator &i)
+         : _m_die (i._m_die), _m_file (i._m_file), _m_next (i._m_next) {}
+
+       inline const debug_info_entry &operator* () const
+       {
+         if (unlikely (_m_next == (::Dwarf_Off) -1))
+           throw std::runtime_error ("dereferencing end iterator");
+         return _m_die;
+       }
+       inline const debug_info_entry *operator-> () const
+       {
+         return &(operator* ());
+       }
+
+       inline const_iterator &operator= (const const_iterator &other)
+       {
+         _m_die = other._m_die;
+         _m_next = other._m_next;
+         _m_file = other._m_file; // XXX
+         return *this;
+       }
+
+       inline bool operator== (const const_iterator &other) const
+       {
+         return _m_next == other._m_next && _m_file == other._m_file;
+       }
+       inline bool operator!= (const const_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       inline const_iterator &operator++ () // prefix
+       {
+         // XXX should be rewritten to use libdw_findcu internals
+         // slow way for first crack to avoid DSO issues
+         _m_next = _m_file->nextcu (_m_next, _m_die.thisdie ());
+         if (_m_next == (::Dwarf_Off) -1)
+           // End iterators have no file pointer.
+           _m_file = NULL;
+         return *this;
+       }
+       inline const_iterator operator++ (int) // postfix
+       {
+         const_iterator prev = *this;
+         ++*this;
+         return prev;
+       }
+      };
+
+      const_iterator begin () const
+      {
+       const_iterator it (_m_file);
+       return ++it;
+      }
+      static inline const_iterator end ()
+      {
+       return const_iterator ();
+      }
+    };
+    inline raw_compile_units_type raw_compile_units () const
+    {
+      return raw_compile_units_type (*this);
+    }
+
+  private:
+    static inline bool skip_partial_unit (const compile_unit &unit)
+    {
+      switch (unit.tag ())
+       {
+       case ::DW_TAG_partial_unit:
+         return true;
+       case ::DW_TAG_compile_unit:
+         return false;
+       default:
+         throw std::exception(); // XXX invalid dwarf
+       }
+    }
+
+    typedef skipping_wrapper<class raw_compile_units_type,
+                            compile_unit, compile_unit,
+                            skip_partial_unit> compile_units_base;
+
+  public:
+
+    // Container for logical CUs in file order, intended to be compatible
+    // with a read-only subset of std::list<compile_unit>.
+    class compile_units_type : public compile_units_base
+    {
+      friend class dwarf;
+    private:
+      compile_units_type (class raw_compile_units_type raw) : compile_units_base (raw) {}
+
+    public:
+      typedef compile_unit value_type;
+
+      compile_units_type (const compile_units_type &u) : compile_units_base (u) {}
+
+      template<typename units>
+      bool operator== (const units &other) const
+      {
+       return subr::container_equal (*this, other);
+      }
+      template<typename units>
+      bool operator!= (const units &other) const
+      {
+       return !(*this == other);
+      }
+    };
+    inline class compile_units_type compile_units () const
+    {
+      return compile_units_type (raw_compile_units ());
+    }
+
+  private:
+    ::Dwarf *_m_dw;
+
+  public:
+    // XXX temp hack
+    inline ::Dwarf_Off nextcu (::Dwarf_Off offset, ::Dwarf_Die *die) const
+    {
+      ::Dwarf_Off next;
+      ::size_t header_size;
+      int result = ::dwarf_nextcu (_m_dw, offset, &next, &header_size,
+                                  NULL, NULL, NULL);
+      xif (result < 0);
+      if (result == 0)
+       xif (::dwarf_offdie (_m_dw, offset + header_size, die) == NULL);
+      else
+       memset (die, 0, sizeof *die);
+      return next;
+    }
+
+    inline dwarf (::Dwarf *dw) : _m_dw (dw) {};
+
+    inline dwarf (const dwarf &dw) : _m_dw (dw._m_dw) {};
+
+    template<typename file>
+    inline bool operator== (const file &other) const
+    {
+      return compile_units () == other.compile_units ();
+    }
+    template<typename file>
+    inline bool operator!= (const file &other) const
+    {
+      return !(*this == other);
+    }
+
+    // XXX reloc
+    class arange_list
+      : public std::set<std::pair< ::Dwarf_Addr, ::Dwarf_Addr> >
+    {
+    private:
+      typedef std::set<std::pair< ::Dwarf_Addr, ::Dwarf_Addr> > _base;
+
+    public:
+      typedef _base::key_type key_type;
+      typedef _base::value_type value_type;
+      typedef _base::iterator iterator;
+      typedef _base::const_iterator const_iterator;
+
+      static inline bool ordered ()
+      {
+       return true;
+      }
+
+      struct hasher : public subr::container_hasher<arange_list> {};
+
+      inline arange_list () {}
+      inline arange_list (const arange_list &other)
+       : _base (static_cast<const _base &> (other))
+      {}
+
+      template<typename iterator>
+      arange_list (iterator first, iterator last)
+       : _base (first, last)
+      {}
+
+      template<typename input>
+      inline arange_list (const input &other)
+       : _base (other.begin (), other.end ())
+      {}
+
+      std::string to_string () const;
+
+      inline std::string to_string ()
+      {
+       coalesce (*this);
+       return ((const arange_list *) this)->to_string ();
+      }
+
+      inline bool canonical () const
+      {
+       // Can't be sure.
+       return false;
+      }
+
+      inline bool canonical ()
+      {
+       // Make it so.
+       coalesce (*this);
+       return true;
+      }
+
+      inline bool operator== (arange_list &other)
+      {
+       // Since we are not const, coalesce both in place.
+       coalesce (other);
+       if (size () < other.size ())
+         // Coalescing can only make us smaller.
+         return false;
+       coalesce (*this);
+       return size () == other.size () && subr::container_equal (*this, other);
+      }
+
+      template<typename list>
+      inline bool operator== (const list &other)
+      {
+       // Since we are not const, coalesce in place.
+       coalesce (*this);
+
+       if (list::ordered () && other.canonical ()
+           && size () != other.size ())
+         return false;
+
+       // If he happens to be sorted and canonical, we'll match.
+       if (subr::container_equal (*this, other))
+         return true;
+
+       // If he was sorted and canonical and we didn't match, it's conclusive.
+       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 ()))
+         // Coalescing can only make him smaller.
+         return false;
+       coalesce (his);
+       return subr::container_equal (*this, his);
+      }
+
+      template<typename list>
+      inline bool operator== (const list &other) const
+      {
+       if (list::ordered () && other.canonical ()
+           && size () < other.size ())
+         // Coalescing can only make us smaller.
+         return false;
+
+       // If we both happen to be sorted and canonical, we'll match.
+       if (subr::container_equal (*this, other))
+         return true;
+
+       // Make a non-const copy that will coalesce in its operator==.
+       if (list::ordered () && other.canonical ())
+         return size () != other.size () && arange_list (*this) == other;
+
+       return arange_list (other) == *this;
+      }
+    };
+
+  private:
+    struct arange_less
+      : public std::binary_function<compile_unit, compile_unit, bool>
+    {
+      inline bool operator() (const compile_unit &a, const compile_unit &b)
+       const
+      {
+       return a.offset () < b.offset ();
+      }
+    };
+
+  public:
+    typedef std::map<compile_unit, arange_list, arange_less> aranges_map;
+
+    aranges_map aranges () const;
+
+  private:
+    static bool adjacency (const arange_list::key_type &a,
+                          const arange_list::key_type &b)
+    {
+      return a.second == b.first;
+    }
+
+    // Coalesce adjacent ranges.
+    static void coalesce (std::set<arange_list::key_type> &set)
+    {
+      for (std::set<arange_list::key_type>::iterator i = set.begin ();
+          (i = std::adjacent_find (i, set.end (), adjacency)) != set.end ();
+          ++i)
+       {
+         std::set<arange_list::key_type>::iterator j = i;
+         std::set<arange_list::key_type>::iterator k = ++j;
+         while (++k != set.end () && adjacency (*j, *k))
+           ++j;
+         const arange_list::key_type joined (i->first, j->second);
+         set.erase (i, k);
+         i = set.insert (joined).first;
+       }
+    }
+  };
+
+  inline class dwarf::debug_info_entry::raw_children_type
+  dwarf::debug_info_entry::raw_children () const
+  {
+    return raw_children_type (*this);
+  }
+
+  inline class dwarf::debug_info_entry::children_type
+  dwarf::debug_info_entry::children () const
+  {
+    return children_type (*this);
+  }
+
+  inline class dwarf::debug_info_entry::raw_attributes_type
+  dwarf::debug_info_entry::raw_attributes () const
+  {
+    return raw_attributes_type (*this);
+  }
+
+  inline class dwarf::debug_info_entry::attributes_type
+  dwarf::debug_info_entry::attributes () const
+  {
+    return attributes_type (raw_attributes ());
+  }
+
+  // Explicit specializations.
+  template<>
+  std::string
+  to_string<dwarf::debug_info_entry> (const dwarf::debug_info_entry &);
+  inline std::string dwarf::debug_info_entry::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+  template<>
+  std::string to_string<dwarf::attribute> (const dwarf::attribute &);
+  inline std::string dwarf::attribute::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+  template<>
+  std::string to_string<dwarf::attr_value> (const dwarf::attr_value &);
+  inline std::string dwarf::attr_value::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+  template<>
+  std::string to_string<dwarf::dwarf_enum> (const dwarf::dwarf_enum &);
+  inline std::string dwarf::dwarf_enum::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+
+};
+
+#endif // <elfutils/dwarf>
diff --git a/libdw/c++/dwarf-knowledge.cc b/libdw/c++/dwarf-knowledge.cc
new file mode 100644 (file)
index 0000000..ea80091
--- /dev/null
@@ -0,0 +1,212 @@
+/* -*- C++ -*- interfaces for libdw.
+   Copyright (C) 2009-2011 Red Hat, Inc.
+
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include "dwarf"
+
+using namespace std;
+using namespace elfutils;
+
+#define VS(what)       (1U << dwarf::VS_##what)
+
+/* Return a bitmask of value spaces expected for this attribute of this tag.
+   Primarily culled from the DWARF 3 spec: 7.5.4, Figure 20.  Updated to
+   DWARF 4, plus some GNU additions.  */
+
+static unsigned int
+expected_value_space (int attr, int tag)
+{
+  switch (attr)
+    {
+    case DW_AT_sibling:
+    case DW_AT_common_reference:
+    case DW_AT_containing_type:
+    case DW_AT_default_value:
+    case DW_AT_abstract_origin:
+    case DW_AT_base_types:
+    case DW_AT_friend:
+    case DW_AT_priority:
+    case DW_AT_specification:
+    case DW_AT_type:
+    case DW_AT_use_location:
+    case DW_AT_data_location:
+    case DW_AT_extension:
+    case DW_AT_small:
+    case DW_AT_object_pointer:
+    case DW_AT_namelist_item:
+      return VS(reference);
+
+    case DW_AT_location:
+    case DW_AT_string_length:
+    case DW_AT_return_addr:
+    case DW_AT_frame_base:
+    case DW_AT_segment:
+    case DW_AT_static_link:
+    case DW_AT_vtable_elem_location:
+    case DW_AT_GNU_call_site_value:
+    case DW_AT_GNU_call_site_data_value:
+    case DW_AT_GNU_call_site_target:
+    case DW_AT_GNU_call_site_target_clobbered:
+      return VS(location);
+
+    case DW_AT_data_member_location:
+      return VS(location) | VS(constant);
+
+    case DW_AT_name:
+      switch (tag)
+       {
+       case DW_TAG_compile_unit:
+       case DW_TAG_partial_unit:
+         return VS(source_file);
+       default:
+         return VS(identifier);
+       }
+
+    case DW_AT_ordering:
+    case DW_AT_language:
+    case DW_AT_visibility:
+    case DW_AT_inline:
+    case DW_AT_accessibility:
+    case DW_AT_address_class:
+    case DW_AT_calling_convention:
+    case DW_AT_encoding:
+    case DW_AT_identifier_case:
+    case DW_AT_virtuality:
+    case DW_AT_endianity:
+      return VS(dwarf_constant);
+
+    case DW_AT_byte_size:
+    case DW_AT_byte_stride:
+    case DW_AT_bit_size:
+    case DW_AT_bit_offset:
+    case DW_AT_bit_stride:
+    case DW_AT_lower_bound:
+    case DW_AT_upper_bound:
+    case DW_AT_count:
+    case DW_AT_allocated:
+    case DW_AT_associated:
+      return VS(reference) | VS(constant) | VS(location); // XXX non-loc expr
+
+    case DW_AT_stmt_list:
+      return VS(lineptr);
+    case DW_AT_macro_info:
+      return VS(macptr);
+    case DW_AT_ranges:
+      return VS(rangelistptr);
+
+    case DW_AT_low_pc:
+    case DW_AT_high_pc:
+    case DW_AT_entry_pc:
+      return VS(address);
+
+    case DW_AT_discr:
+      return VS(reference);
+    case DW_AT_discr_value:
+      return VS(constant);
+    case DW_AT_discr_list:
+      return VS(discr_list);
+
+    case DW_AT_import:
+      return VS(reference);
+
+    case DW_AT_comp_dir:
+      return VS(source_file);
+
+    case DW_AT_const_value:
+      return VS(constant) | VS(string) | VS(address);
+
+    case DW_AT_is_optional:
+    case DW_AT_prototyped:
+    case DW_AT_artificial:
+    case DW_AT_declaration:
+    case DW_AT_external:
+    case DW_AT_variable_parameter:
+    case DW_AT_use_UTF8:
+    case DW_AT_mutable:
+    case DW_AT_main_subprogram:
+    case DW_AT_threads_scaled:
+    case DW_AT_explicit:
+    case DW_AT_elemental:
+    case DW_AT_pure:
+    case DW_AT_recursive:
+    case DW_AT_const_expr:
+    case DW_AT_enum_class:
+    case DW_AT_GNU_tail_call:
+    case DW_AT_GNU_all_tail_call_sites:
+    case DW_AT_GNU_all_call_sites:
+    case DW_AT_GNU_all_source_call_sites:
+    case DW_AT_GNU_vector:
+      return VS(flag);
+
+    case DW_AT_producer:
+      return VS(string);
+
+    case DW_AT_start_scope:
+    case DW_AT_data_bit_offset:
+      return VS(constant);
+
+    case DW_AT_binary_scale:
+    case DW_AT_decimal_scale:
+    case DW_AT_decimal_sign:
+    case DW_AT_digit_count:
+      return VS(constant);
+
+    case DW_AT_decl_file:
+    case DW_AT_call_file:
+      return VS(source_file);
+    case DW_AT_decl_line:
+    case DW_AT_call_line:
+      return VS(source_line);
+    case DW_AT_decl_column:
+    case DW_AT_call_column:
+      return VS(source_column);
+
+    case DW_AT_trampoline:
+      return VS(address) | VS(flag) | VS(reference) | VS(string);
+
+    case DW_AT_description:
+    case DW_AT_picture_string:
+      return VS(string);
+
+    case DW_AT_linkage_name:
+    case DW_AT_MIPS_linkage_name:
+    case DW_AT_GNU_template_name:
+      return VS(identifier);
+
+    /* XXX Note these are not the same, the first is related to C++
+       ODR (one-definition-rule checking), the later to .debug_type
+       references. Should be its own class really.  */
+    case DW_AT_GNU_odr_signature:
+      return VS(constant);
+    case DW_AT_signature:
+      return VS(reference);
+    }
+
+  return 0;
+}
diff --git a/libdw/c++/dwarf_comparator b/libdw/c++/dwarf_comparator
new file mode 100644 (file)
index 0000000..9a5a127
--- /dev/null
@@ -0,0 +1,575 @@
+/* elfutils::dwarf_comparator -- -*- C++ -*- templates for comparing DWARF data
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF_COMPARATOR
+#define _ELFUTILS_DWARF_COMPARATOR     1
+
+#include "dwarf"
+
+namespace elfutils
+{
+  // Prototypical stub for reference tracker object.
+  // This keeps no state, and no two contexts ever match.
+  template<class dwarf1, class dwarf2>
+  struct dwarf_tracker_base
+  {
+    typedef typename dwarf1::compile_units_type::const_iterator cu1;
+    typedef typename dwarf2::compile_units_type::const_iterator cu2;
+    typedef typename dwarf1::debug_info_entry dwarf1_die;
+    typedef typename dwarf2::debug_info_entry dwarf2_die;
+    typedef typename dwarf1_die::children_type::const_iterator die1;
+    typedef typename dwarf2_die::children_type::const_iterator die2;
+    typedef typename dwarf1_die::attributes_type::const_iterator attr1;
+    typedef typename dwarf2_die::attributes_type::const_iterator attr2;
+
+    // This object is created to start a walk and destroyed to finish one.
+    struct walk
+    {
+      inline walk (dwarf_tracker_base *, const cu1 &, const cu2 &)
+      {
+      }
+      inline ~walk ()
+      {
+      }
+    };
+
+    // This object is created in pre-order and destroyed in post-order.
+    struct step
+    {
+      inline step (dwarf_tracker_base *, const die1 &, const die2 &)
+      {
+      }
+      inline ~step ()
+      {
+      }
+    };
+
+    /* This is enough like step that they should probably be merged.
+       But it's separate.  */
+    struct visitor
+    {
+      inline visitor (dwarf_tracker_base *,
+                     const typename dwarf1::debug_info_entry &,
+                     const typename dwarf2::debug_info_entry &)
+      {
+      }
+      inline ~visitor ()
+      {
+      }
+    };
+
+    inline bool mismatch (cu1 &, const cu1 &, // at, end
+                         cu2 &, const cu2 &)
+    {
+      return false;
+    }
+
+    inline bool mismatch (die1 &, const die1 &, // at, end
+                         die2 &, const die2 &)
+    {
+      return false;
+    }
+
+    inline bool mismatch (attr1 &, const attr1 &, // at, end
+                         attr2 &, const attr2 &)
+    {
+      return false;
+    }
+
+    struct left_context_type {};
+    struct right_context_type {};
+
+    // Return the lhs context of an arbitrary DIE.
+    inline const left_context_type left_context (const die1 &)
+    {
+      return left_context_type ();
+    }
+
+    // Return the rhs context of an arbitrary DIE.
+    inline const right_context_type right_context (const die2 &)
+    {
+      return right_context_type ();
+    }
+
+    inline bool context_quick_mismatch (const left_context_type &,
+                                       const right_context_type &)
+
+    {
+      return true;
+    }
+
+    inline bool context_match (const left_context_type &,
+                              const right_context_type &)
+    {
+      return false;
+    }
+
+    struct reference_match {};
+
+    // This call is used purely in hopes of a cache hit.
+    inline bool prematch (reference_match &, const die1 &, const die2 &)
+    {
+      return false;
+    }
+
+    // This call is used only as part of a real reference lookup.
+    inline bool reference_matched (reference_match &,
+                                  const die1 &, const die2 &)
+    {
+      return false;
+    }
+
+    // Check for a negative cache hit after prematch or reference_match.
+    inline bool cannot_match (reference_match &, const die1 &, const die2 &)
+    {
+      return false;
+    }
+
+    // This can cache a result.
+    inline bool notice_match (reference_match &, const die1 &, const die2 &,
+                             bool result)
+    {
+      return result;
+    }
+
+    template<typename item1, typename item2>
+    inline bool identical (const item1 &, const item2 &)
+    {
+      return false;
+    }
+
+    inline dwarf_tracker_base ()
+    {}
+
+    typedef dwarf_tracker_base subtracker;
+    inline dwarf_tracker_base (const dwarf_tracker_base &, reference_match &,
+                              const left_context_type &,
+                              const right_context_type &)
+    {}
+  };
+
+  template<class dwarf1, class dwarf2,
+          bool ignore_refs = false,
+          class tracker = dwarf_tracker_base<dwarf1, dwarf2>
+          >
+  class dwarf_comparator
+    : public std::binary_function<dwarf1, dwarf2, bool>
+  {
+  private:
+    tracker &_m_tracker;
+
+    typedef dwarf_comparator<dwarf1, dwarf2, false,
+                            typename tracker::subtracker> subcomparator;
+
+    template<typename item1, typename item2>
+    struct matcher : public std::binary_function<item1, item2, bool>
+    {
+      dwarf_comparator &_m_cmp;
+      matcher (dwarf_comparator &cmp)
+       : _m_cmp (cmp)
+      {}
+
+      inline bool operator () (const item1 &a, const item2 &b)
+      {
+       return _m_cmp.match_deref (a, b);
+      }
+    };
+#define MATCHER(item) \
+    matcher<typename dwarf1::item::const_iterator, \
+           typename dwarf2::item::const_iterator> (*this)
+
+    inline bool match (const dwarf1 &a, const dwarf2 &b)
+    {
+      return match (a.compile_units (), b.compile_units ());
+    }
+
+    typedef typename dwarf1::compile_units_type compile_units1;
+    typedef typename dwarf2::compile_units_type compile_units2;
+    typedef typename dwarf1::compile_units_type::const_iterator cu1_it;
+    typedef typename dwarf2::compile_units_type::const_iterator cu2_it;
+    inline bool match (const compile_units1 &a, const compile_units2 &b)
+    {
+      cu1_it it1 = a.begin ();
+      cu2_it it2 = b.begin ();
+      const cu1_it end1 = a.end ();
+      const cu2_it end2 = b.end ();
+      do
+       {
+         if (subr::container_equal
+             (it1, end1, it2, end2, MATCHER (compile_units_type)))
+           return true;
+       }
+      while (_m_tracker.mismatch (it1, end1, it2, end2));
+      return false;
+    }
+
+    typedef typename dwarf1::debug_info_entry die1;
+    typedef typename dwarf2::debug_info_entry die2;
+    inline bool match_deref (const cu1_it &a, const cu2_it &b)
+    {
+      typename tracker::walk in (&_m_tracker, a, b);
+      return equals (*a, *b);
+    }
+
+    inline bool match (const die1 &a, const die2 &b)
+    {
+      typename tracker::visitor visit (&_m_tracker, a, b);
+      if (a.tag () != b.tag ())
+       return nomatch (a, b, "DIE tag");
+      if (!equals (a.attributes (), b.attributes ()))
+       return nomatch (a, b, "DIE attrs");
+      if (!equals (a.children (), b.children ()))
+       return nomatch (a, b, "DIE children");
+      return true;
+    }
+
+    template<typename in, typename out>
+    static inline void populate (out &o, const in &map)
+    {
+      for (typename in::const_iterator i = map.begin ();
+          i != map.end ();
+          ++i)
+       o.insert (std::make_pair ((*i).first, i));
+    }
+
+    typedef typename dwarf1::debug_info_entry::attributes_type attributes1;
+    typedef typename dwarf2::debug_info_entry::attributes_type attributes2;
+    typedef typename attributes1::const_iterator ait1;
+    typedef typename attributes2::const_iterator ait2;
+    typedef std::map<int, ait1> ait1_map;
+    typedef std::map<int, ait2> ait2_map;
+
+    struct match_lhs
+      : public std::binary_function<ait1, ait2, bool>
+    {
+      inline bool operator () (const ait1 &it1, const ait2 &it2)
+      {
+       return (*it1).first == (*it2).first;
+      }
+    };
+
+    struct match_rhs
+      : public std::binary_function<ait1, ait2, bool>
+    {
+      dwarf_comparator &_m_cmp;
+      match_rhs (dwarf_comparator &cmp)
+       : _m_cmp (cmp)
+      {}
+
+      inline bool operator () (const ait1 &it1, const ait2 &it2)
+      {
+       return _m_cmp.equals ((*it1).second, (*it2).second);
+      }
+    };
+
+    struct match_sorted
+      : public std::binary_function<typename ait1_map::value_type,
+                                   typename ait2_map::value_type,
+                                   bool>
+    {
+      dwarf_comparator &_m_cmp;
+      match_sorted (dwarf_comparator<dwarf1, dwarf2, ignore_refs, tracker> &cmp)
+       : _m_cmp (cmp)
+      {}
+
+      inline bool operator () (const typename ait1_map::value_type &x,
+                              const typename ait2_map::value_type &y)
+      {
+       return (x.first == y.first
+               && _m_cmp.equals ((*x.second).second, (*y.second).second));
+      }
+    };
+
+    inline bool match (const attributes1 &a, const attributes2 &b)
+    {
+      ait1 it1 = a.begin ();
+      ait2 it2 = b.begin ();
+      const ait1 end1 = a.end ();
+      const ait2 end2 = b.end ();
+      if (subr::container_equal (it1, end1, it2, end2, match_lhs ()))
+       {
+         // The set of attributes matches, in order.  Compare the values.
+         it1 = a.begin ();
+         it2 = b.begin ();
+         do
+           {
+             if (subr::container_equal (it1, end1, it2, end2,
+                                        match_rhs (*this)))
+               return true;
+           }
+         while (_m_tracker.mismatch (it1, end1, it2, end2));
+         return false;
+       }
+
+      if (it1 != end1 && it2 != end2
+         && !(attributes1::ordered () && attributes2::ordered ()))
+       {
+         /* We have the same number of attributes, but the names don't
+            match.  Populate two sorted maps and compare those.  */
+
+         ait1_map sorted1;
+         populate (sorted1, a);
+
+         ait2_map sorted2;
+         populate (sorted2, b);
+
+         std::pair<typename ait1_map::iterator,
+                   typename ait2_map::iterator> result
+           = std::mismatch (sorted1.begin (), sorted1.end (),
+                            sorted2.begin (), match_sorted (*this));
+         if (result.first == sorted1.end ()
+             && result.second == sorted2.end ())
+           return true;
+
+         it1 = result.first->second;
+         it2 = result.second->second;
+       }
+
+      return _m_tracker.mismatch (it1, end1, it2, end2);
+    }
+
+    typedef typename dwarf1::debug_info_entry::children_type children1;
+    typedef typename dwarf2::debug_info_entry::children_type children2;
+    typedef typename children1::const_iterator cit1;
+    typedef typename children2::const_iterator cit2;
+
+    inline bool match_child (const cit1 &a, const cit2 &b)
+    {
+      typename tracker::step into (&_m_tracker, a, b);
+      return equals (*a, *b);
+    }
+
+    inline bool match_deref (const cit1 &a, const cit2 &b)
+    {
+      // Maybe the tracker has already cached a correspondence of DIEs.
+      typename tracker::reference_match matched;
+      if (_m_tracker.prematch (matched, a, b))
+       return true;
+
+      if (_m_tracker.cannot_match (matched, a, b))
+       return nomatch (*a, *b, "children cached");
+
+      bool result = match_child (a, b);
+
+      // Let the tracker cache a result for its reference_matched.
+      return _m_tracker.notice_match (matched, a, b, result);
+    }
+
+    inline bool match (const children1 &a, const children2 &b)
+    {
+      cit1 it1 = a.begin ();
+      cit2 it2 = b.begin ();
+      const cit1 end1 = a.end ();
+      const cit2 end2 = b.end ();
+      do
+       if (subr::container_equal (it1, end1, it2, end2,
+                                  MATCHER (debug_info_entry::children_type)))
+         return true;
+      while (_m_tracker.mismatch (it1, end1, it2, end2));
+      return false;
+    }
+
+    typedef typename dwarf1::attribute attribute1;
+    typedef typename dwarf2::attribute attribute2;
+    inline bool match (const attribute1 &a, const attribute2 &b)
+    {
+      return a.first == b.first && equals (a.second, b.second);
+    }
+
+    typedef typename dwarf1::attr_value attr_value1;
+    typedef typename dwarf2::attr_value attr_value2;
+    inline bool match (const attr_value1 &a, const attr_value2 &b)
+    {
+      const dwarf::value_space what = a.what_space ();
+      if (what == b.what_space ())
+       switch (what)
+         {
+         case dwarf::VS_reference:
+           return reference_match (a.reference (), b.reference ());
+
+         case dwarf::VS_flag:
+           return a.flag () == b.flag ();
+
+         case dwarf::VS_rangelistptr:
+           return a.ranges () == b.ranges ();
+
+         case dwarf::VS_lineptr:
+           return a.line_info () == b.line_info ();
+
+         case dwarf::VS_macptr:        // XXX punt for now, treat as constant
+           return a.constant () == b.constant ();
+
+         case dwarf::VS_dwarf_constant:
+           return a.dwarf_constant () == b.dwarf_constant ();
+
+         case dwarf::VS_constant:
+           if (a.constant_is_integer ())
+             return (b.constant_is_integer ()
+                     && a.constant () == b.constant ());
+           return (!b.constant_is_integer ()
+                   && subr::container_equal (a.constant_block (),
+                                             b.constant_block ()));
+
+         case dwarf::VS_source_line:
+           return a.source_line () == b.source_line ();
+         case dwarf::VS_source_column:
+           return a.source_column () == b.source_column ();
+
+         case dwarf::VS_identifier:
+           return subr::name_equal<typeof (b.identifier ())> ()
+             (a.identifier (), b.identifier ());
+
+         case dwarf::VS_string:
+           return subr::name_equal<typeof (b.string ())> ()
+             (a.string (), b.string ());
+
+         case dwarf::VS_address:
+           return a.address () == b.address ();
+
+         case dwarf::VS_source_file:
+           return a.source_file () == b.source_file ();
+
+         case dwarf::VS_location:
+           return a.location () == b.location ();
+
+         case dwarf::VS_discr_list:
+           throw std::runtime_error ("XXX unimplemented");
+         }
+      return false;
+    }
+
+    // This is a convenient place to hack for debugging output and such.
+    inline bool nomatch (const die1 &, const die2 &, const char *)
+    {
+      return false;
+    }
+
+    /* We call references equal if they are literally the same DIE,
+       or if they are identical subtrees sitting in matching contexts.
+       The tracker's context_match method decides what that means.  */
+    inline bool reference_match (const cit1 &ref1, const cit2 &ref2)
+    {
+      if (ignore_refs)
+       return true;
+
+      const die1 &a = *ref1;
+      const die2 &b = *ref2;
+
+      if (a.identity () == b.identity ()) // Object identity.
+       return true;
+
+      // Simplest mismatches with the cheapest checks first.
+      if (a.tag () != b.tag ())
+       return nomatch (a, b, "tag");
+
+      const bool has_children = a.has_children ();
+      if (has_children != b.has_children ())
+       return nomatch (a, b, "has_children");
+
+      // Maybe the tracker has already cached a correspondence of references.
+      typename tracker::reference_match matched;
+      if (_m_tracker.reference_matched (matched, ref1, ref2))
+       return true;
+
+      if (_m_tracker.cannot_match (matched, ref1, ref2))
+       return nomatch (a, b, "cached");
+
+      // Now we really have to get the tracker involved.
+      const typename tracker::left_context_type &lhs
+       = _m_tracker.left_context (ref1);
+      const typename tracker::right_context_type &rhs
+       = _m_tracker.right_context (ref2);
+
+      bool result = true;
+
+      /* First do the cheap mismatch check on the contexts, then check the
+        contents and contexts in ascending order of costliness of a check.  */
+      if (_m_tracker.context_quick_mismatch (lhs, rhs))
+       result = nomatch (a, b, "quick context");
+
+      /* To compare the children, we have to clone the tracker and use a
+        new one, in case of any reference attributes in their subtrees.
+        The new tracker jump-starts its walk to the referenced DIE from
+        the root of the CU.
+
+        We use the subtracker and subcomparator for the attributes as well,
+        in case the main tracker has side-effects like printing.  */
+
+      typename tracker::subtracker t (_m_tracker, matched, lhs, rhs);
+      subcomparator cmp (t);
+
+      if (result && !cmp.equals (a.attributes (), b.attributes ()))
+       result = nomatch (a, b, "attribute");
+
+      if (result && !_m_tracker.context_match (lhs, rhs))
+       result = nomatch (a, b, "context");
+
+      if (result && has_children && !cmp.equals (a.children (), b.children ()))
+       result = nomatch (a, b, "children");
+
+      // Let the tracker cache a result for its reference_matched.
+      return _m_tracker.notice_match (matched, ref1, ref2, result);
+    }
+
+    // This is what the public equals method uses for references.
+    inline bool match (const cit1 &a, const cit2 &b)
+    {
+      return reference_match (a, b);
+    }
+
+  public:
+    inline explicit dwarf_comparator (tracker &t)
+      : _m_tracker (t)
+    {}
+
+    inline bool operator () (const dwarf1 &a, const dwarf2 &b)
+    {
+      return match (a, b);
+    }
+
+    template<typename item1, typename item2>
+    inline bool equals (const item1 &a, const item2 &b)
+    {
+      return _m_tracker.identical (a, b) || match (a, b);
+    }
+
+    /* Predicate for DIEs "equal enough" to match as context for a subtree.
+       The definition we use is that the DIE has the same tag and all its
+       attributes are equal, excepting that references in attribute values
+       are not compared.  */
+    static inline bool equal_enough (const die1 &a, const die2 &b)
+    {
+      dwarf_tracker_base<dwarf1, dwarf2> context_tracker;
+      return (a.tag () == b.tag ()
+             && (dwarf_comparator<dwarf1, dwarf2, true> (context_tracker)
+                 .equals (a.attributes (), b.attributes ())));
+    }
+  };
+};
+
+#endif // <elfutils/dwarf_comparator>
diff --git a/libdw/c++/dwarf_data b/libdw/c++/dwarf_data
new file mode 100644 (file)
index 0000000..76c478a
--- /dev/null
@@ -0,0 +1,1534 @@
+/* elfutils::dwarf_data -- internal DWARF data representations in -*- C++ -*-
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF_DATA
+#define _ELFUTILS_DWARF_DATA   1
+
+#include "dwarf"
+#include <cassert>
+#include <bitset>
+
+/* This contains common classes/templates used by dwarf_output and dwarf_edit.
+
+   These are implementations of the "boring" components of the dwarf
+   object interface.
+*/
+
+namespace elfutils
+{
+  // This is a class only for scoping purposes.
+  // It contains no members, only inner classes.
+  class dwarf_data
+  {
+  public:
+
+    // Main container anchoring all the output.
+    template<class impl>
+    class compile_units_type : public std::list<typename impl::compile_unit>
+    {
+      friend class subr::create_container;
+
+    protected:
+      typedef std::list<typename impl::compile_unit> _base;
+
+      // Constructor copying CUs from input container.
+      template<typename input, typename arg_type>
+      inline compile_units_type (const input &other, arg_type &arg)
+       : _base (subr::argify<input, compile_units_type, arg_type &>
+                (other.begin (), arg),
+                subr::argify<input, compile_units_type, arg_type &>
+                (other.end (), arg))
+      {}
+
+    public:
+      // Default constructor: an empty container, no CUs.
+      inline compile_units_type () {}
+
+      template<typename other_children>
+      bool operator== (const other_children &other) const
+      {
+       return subr::container_equal (*this, other);
+      }
+      template<typename other_children>
+      bool operator!= (const other_children &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    template<class impl>
+    class compile_unit : public impl::debug_info_entry
+    {
+      friend class subr::create_container;
+      friend class impl::compile_units_type;
+
+    protected:
+      template<typename input>
+      static inline const input &require_cu (const input &cu)
+      {
+       if (cu.tag () != ::DW_TAG_compile_unit)
+         throw std::runtime_error
+           ("top-level debug_info_entry must be DW_TAG_compile_unit");
+       return cu;
+      }
+
+      template<typename die_type, typename arg_type>
+      inline void set (const die_type &die, arg_type &arg)
+      {
+       impl::debug_info_entry::set (require_cu (die), arg);
+      }
+
+    public:
+      explicit inline compile_unit ()
+       : impl::debug_info_entry ()
+      {
+       this->_m_tag = ::DW_TAG_compile_unit;
+      }
+
+      inline compile_unit (const compile_unit &other)
+       : impl::debug_info_entry (require_cu (other))
+      {}
+
+      template<typename input, typename arg_type>
+      inline compile_unit (const input &cu, arg_type &arg)
+       : impl::debug_info_entry (typename impl::debug_info_entry::pointer (),
+                                 require_cu (cu), arg)
+      {}
+
+      /* Assignment details are up to the base class.
+        We just ensure it's really a compile_unit.  */
+      inline compile_unit &
+      operator= (const typename impl::debug_info_entry &other)
+      {
+       impl::debug_info_entry::operator= (require_cu (other));
+       return *this;
+      }
+
+      // Fetch the CU's DW_AT_stmt_list.
+      inline const typename impl::line_info_table &line_info () const
+      {
+       return this->attributes ().at (::DW_AT_stmt_list).line_info ();
+      }
+
+      // Convenience methods for line_info_table sub-containers.
+      inline const typename impl::line_table &lines () const
+      {
+       return line_info ().lines ();
+      }
+
+#if 0 // XXX const issues
+      inline typename impl::line_info_table &line_info ()
+      {
+       return this->attributes ()[::DW_AT_stmt_list].line_info ();
+      }
+
+      inline typename impl::line_table &lines ()
+      {
+       return line_info ().lines ();
+      }
+#endif
+    };
+
+    class source_file
+    {
+    private:
+      std::string _m_name;
+      ::Dwarf_Word _m_mtime;
+      ::Dwarf_Word _m_size;
+
+    public:
+
+      struct hasher
+       : public std::unary_function<source_file, size_t>
+      {
+       size_t operator () (const source_file &v) const
+       {
+         size_t hash = 0;
+         subr::hash_combine (hash, v._m_name);
+         subr::hash_combine (hash, v._m_mtime);
+         subr::hash_combine (hash, v._m_size);
+         return hash;
+       }
+      };
+
+      source_file () : _m_name (), _m_mtime (0), _m_size (0) {}
+      source_file (const std::string &n, ::Dwarf_Word m = 0, ::Dwarf_Word s = 0)
+       : _m_name (n), _m_mtime (m), _m_size (s) {}
+      source_file (const char *n, ::Dwarf_Word m = 0, ::Dwarf_Word s = 0)
+       : _m_name (n), _m_mtime (m), _m_size (s) {}
+
+      template<typename file>
+      source_file (const file &other)
+       : _m_name (other.name ()),
+         _m_mtime (other.mtime ()), _m_size (other.size ()) {}
+
+      template<typename file>
+      inline source_file &operator= (const file &other)
+      {
+       _m_name = other.name ();
+       _m_mtime = other.mtime ();
+       _m_size = other.size ();
+       return *this;
+      }
+      inline source_file &operator= (const std::string &n)
+      {
+       _m_name = n;
+       _m_mtime = 0;
+       _m_size = 0;
+       return *this;
+      }
+      inline source_file &operator= (const char *n)
+      {
+       _m_name = n;
+       _m_mtime = 0;
+       _m_size = 0;
+       return *this;
+      }
+
+      std::string to_string () const;
+
+      inline std::string &name ()
+      {
+       return _m_name;
+      }
+      inline const std::string &name () const
+      {
+       return _m_name;
+      }
+      inline ::Dwarf_Word &mtime ()
+      {
+       return _m_mtime;
+      }
+      inline ::Dwarf_Word mtime () const
+      {
+       return _m_mtime;
+      }
+      inline ::Dwarf_Word &size ()
+      {
+       return _m_size;
+      }
+      inline ::Dwarf_Word size () const
+      {
+       return _m_size;
+      }
+
+      template<typename other_file>
+      bool operator== (const other_file &other) const
+      {
+       if (mtime () != 0)
+         {
+           ::Dwarf_Word other_mtime = other.mtime ();
+           if (other_mtime != 0 && other_mtime != mtime ())
+             return false;
+         }
+       if (size () != 0)
+         {
+           ::Dwarf_Word other_size = other.size ();
+           if (other_size != 0 && other_size != size ())
+             return false;
+         }
+       return name () == other.name ();
+      }
+      template<typename other_file>
+      inline bool operator!= (const other_file &other) const
+      {
+       return !(*this == other);
+      }
+
+      // Return a value unique to us while we're in memory.
+      inline uintptr_t identity () const
+      {
+       return (uintptr_t) this;
+      }
+    };
+
+  private:
+
+    /* This is the common base class for all line_entry<T> instantiations.
+       For some reason beyond my ken, std::bitset<flag_count>::reference
+       as a return type is rejected by the compiler when used in a template
+       class, but not a non-template class.  Go figure.  */
+    class line_entry_common
+    {
+    protected:
+      unsigned int _m_line;
+      unsigned int _m_column;
+
+      enum flag_bit
+       {
+         flag_statement,
+         flag_basic_block,
+         flag_end_sequence,
+         flag_prologue_end,
+         flag_epilogue_begin,
+         flag_count
+       };
+      std::bitset<flag_count> _m_flags;
+
+    public:
+      line_entry_common ()
+       : _m_line (0), _m_column (0) {}
+
+      inline unsigned int &line ()
+      {
+       return _m_line;
+      }
+      inline unsigned int line () const
+      {
+       return _m_line;
+      }
+      inline unsigned int &column ()
+      {
+       return _m_column;
+      }
+      inline unsigned int column () const
+      {
+       return _m_column;
+      }
+
+#define _DWARF_EDIT_LE_FLAG(what)                      \
+      bool what () const                               \
+      {                                                        \
+       return _m_flags[flag_##what];                   \
+      }                                                        \
+      std::bitset<flag_count>::reference what ()       \
+      {                                                        \
+       return _m_flags[flag_##what];                   \
+      }
+      _DWARF_EDIT_LE_FLAG (statement)
+      _DWARF_EDIT_LE_FLAG (basic_block)
+      _DWARF_EDIT_LE_FLAG (end_sequence)
+      _DWARF_EDIT_LE_FLAG (prologue_end)
+      _DWARF_EDIT_LE_FLAG (epilogue_begin)
+#undef _DWARF_EDIT_LE_FLAG
+    };
+
+  public:
+    /* This holds a line table entry.
+       It's parameterized by the source_file representation.  */
+    template<typename source_file>
+    class line_entry : public line_entry_common
+    {
+    private:
+      ::Dwarf_Addr _m_addr;    // XXX dwfl, reloc
+      source_file _m_file;
+
+    public:
+
+      struct hasher
+       : public std::unary_function<line_entry, size_t>
+      {
+       size_t operator () (const line_entry &v) const
+       {
+         size_t hash = 0;
+         subr::hash_combine (hash, v._m_addr);
+         subr::hash_combine (hash, v._m_file);
+         subr::hash_combine (hash, v._m_line);
+         subr::hash_combine (hash, v._m_column);
+         return hash;
+       }
+      };
+
+      line_entry (::Dwarf_Addr addr)
+       : line_entry_common (), _m_addr (addr), _m_file ()
+      {}
+
+      template<typename entry>
+      line_entry (const entry &other)
+       : line_entry_common (), _m_addr (0), _m_file ()
+      {
+       *this = other;
+      }
+
+      template<typename entry>
+      line_entry &operator= (const entry &other)
+      {
+       _m_addr = other.address ();
+       _m_file = other.file ();
+       _m_line = other.line ();
+       _m_column = other.column ();
+       statement () = other.statement ();
+       basic_block () = other.basic_block ();
+       end_sequence () = other.end_sequence ();
+       prologue_end () = other.prologue_end ();
+       epilogue_begin () = other.epilogue_begin ();
+       return *this;
+      }
+
+      inline ::Dwarf_Addr &address ()
+      {
+       return _m_addr;
+      }
+      inline ::Dwarf_Addr address () const
+      {
+       return _m_addr;
+      }
+      inline source_file &file ()
+      {
+       return _m_file;
+      }
+      inline const source_file &file () const
+      {
+       return _m_file;
+      }
+
+      template<typename entry>
+      bool operator< (const entry &other) const
+      {
+       return address () < other.address ();
+      }
+      template<typename entry>
+      bool operator> (const entry &other) const
+      {
+       return address () > other.address ();
+      }
+      template<typename entry>
+      bool operator<= (const entry &other) const
+      {
+       return address () <= other.address ();
+      }
+      template<typename entry>
+      bool operator>= (const entry &other) const
+      {
+       return address () >= other.address ();
+      }
+
+      template<typename entry>
+      inline bool operator== (const entry &other) const
+      {
+       return (address () == other.address ()
+               && line () == other.line ()
+               && column () == other.column ()
+               && statement () == other.statement ()
+               && basic_block () == other.basic_block ()
+               && end_sequence () == other.end_sequence ()
+               && prologue_end () == other.prologue_end ()
+               && epilogue_begin () == other.epilogue_begin ()
+               && file () == other.file ());
+      }
+      template<typename entry>
+      inline bool operator!= (const entry &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    /* This holds a line table.
+       It's parameterized by the line_entry representation.  */
+    template<typename line_entry>
+    class line_table : public std::vector<line_entry>
+    {
+    private:
+      typedef std::vector<line_entry> _base;
+
+    public:
+      typedef typename _base::size_type size_type;
+      typedef typename _base::difference_type difference_type;
+      typedef typename _base::value_type value_type;
+      typedef typename _base::iterator iterator;
+      typedef typename _base::const_iterator const_iterator;
+
+      struct hasher : public subr::container_hasher<line_table> {};
+
+      line_table () {}
+
+      template<typename table>
+      line_table (const table &other) : _base (other.begin (), other.end ()) {}
+
+      std::string to_string () const;
+
+      template<typename table>
+      inline bool operator== (const table &other) const
+      {
+       return (_base::size () == other.size ()
+               && subr::container_equal (*this, other));
+      }
+      template<typename table>
+      inline bool operator!= (const table &other) const
+      {
+       return !(*this == other);
+      }
+
+      // Look up by matching address.
+      iterator find (::Dwarf_Addr);
+      const_iterator find (::Dwarf_Addr) const;
+    };
+
+    /* This holds the entirety of line information.
+       The line_table is all there actually is.  */
+    template<typename line_table>
+    class line_info_table
+    {
+    private:
+      line_table _m_lines;
+
+    public:
+      struct hasher : public std::unary_function<line_info_table, size_t>
+      {
+       inline size_t operator () (const line_info_table &info) const
+       {
+         return subr::hash_this (info._m_lines);
+       }
+      };
+
+      inline line_info_table () {}
+
+      template<typename table>
+      inline line_info_table (const table &other)
+       : _m_lines (other.lines ())
+      {}
+
+      template<typename table>
+      inline line_info_table &operator= (const table &other)
+      {
+       _m_lines = line_table (other.lines ());
+       return *this;
+      }
+
+      std::string to_string () const;
+
+      inline line_table &lines ()
+      {
+       return _m_lines;
+      }
+      inline const line_table &lines () const
+      {
+       return _m_lines;
+      }
+
+      template<typename table>
+      inline bool operator== (const table &other) const
+      {
+       return lines () == other.lines ();
+      }
+      template<typename table>
+      inline bool operator!= (const table &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    class dwarf_enum
+      : private std::pair< ::Dwarf_Word, unsigned int>
+    {
+    private:
+      typedef std::pair< ::Dwarf_Word, unsigned int> _base;
+
+    protected:
+      inline dwarf_enum ()
+       : _base (0, 0)
+      {}
+
+    public:
+      friend class subr::base_hasher<dwarf_enum, _base>;
+      typedef subr::base_hasher<dwarf_enum, _base> hasher;
+
+      inline dwarf_enum (unsigned int attr, unsigned int value)
+       : _base (value, attr)
+      {}
+
+      template<typename constant>
+      inline dwarf_enum (const constant &other)
+       : _base (static_cast<unsigned int> (other), other.which ())
+      {}
+
+      // Return the DW_AT_* indicating which enum this value belongs to.
+      inline unsigned int which () const
+      {
+       return this->second;
+      }
+
+      inline operator unsigned int () const
+      {
+       return this->first;
+      }
+
+      inline dwarf_enum &operator= (::Dwarf_Word value)
+      {
+       this->first = value;
+       return *this;
+      }
+
+      inline dwarf_enum &operator= (const dwarf_enum& other)
+      {
+       if (this->second == 0)
+         {
+           throw std::logic_error ("dwarf_enum default constructed");
+           this->second = other.second;
+         }
+       else if (this->second != other.second)
+         throw std::runtime_error
+           ("cannot assign dwarf_constant () from "
+            + dwarf::attributes::name (other.second) + "to "
+            + dwarf::attributes::name (this->second));
+
+       this->first = other.first;
+       return *this;
+      }
+
+      template<typename constant>
+      inline dwarf_enum &operator= (const constant& other)
+      {
+       return *this = dwarf_enum (other.which (), other);
+      }
+
+      std::string to_string () const;
+
+      const char *identifier () const;
+      const char *name () const;
+
+      template<typename constant>
+      inline bool operator== (const constant &other) const
+      {
+       return (static_cast<unsigned int> (*this)
+               == static_cast<unsigned int> (other));
+      }
+      template<typename constant>
+      inline bool operator!= (const constant &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    // Same as set<pair<Dwarf_Addr, Dwarf_Addr>>.
+    typedef dwarf::arange_list range_list;
+
+    class location_attr
+      : public std::map<dwarf::location_attr::key_type, std::vector<uint8_t> >
+    {
+    private:
+      typedef std::map<dwarf::location_attr::key_type,
+                      std::vector<uint8_t> > _base;
+
+      template<typename pair>
+      struct nonempty : public std::unary_function<pair, bool>
+      {
+       inline bool operator () (const pair &x)
+       {
+         return !x.second.empty ();
+       }
+      };
+
+    public:
+      typedef _base::size_type size_type;
+      typedef _base::difference_type difference_type;
+      typedef _base::key_type key_type;
+      typedef _base::mapped_type mapped_type;
+      typedef _base::value_type value_type;
+      typedef _base::iterator iterator;
+      typedef _base::const_iterator const_iterator;
+
+      struct hasher : public subr::container_hasher<location_attr> {};
+
+      inline location_attr () : _base () {}
+      inline location_attr (const location_attr &other)
+       : _base (static_cast<const _base &> (other)) {}
+      template<typename loc>
+      inline location_attr (const loc &other) : _base ()
+      {
+       *this = other;
+      }
+
+      template<typename loc>
+      inline location_attr &operator= (const loc &other)
+      {
+       clear ();
+       if (other.empty ())
+         ;
+       else if (other.is_list ())
+         for (typename loc::const_iterator i = other.begin ();
+              i != other.end ();
+              ++i)
+           {
+             const typename loc::mapped_type &x = (*i).second;
+             (*this)[(*i).first] = mapped_type (x.begin (), x.end ());
+           }
+       else
+         {
+           mapped_type v = other.location ();
+           (*this)[key_type (0, -1)] = v;
+         }
+       return *this;
+      }
+
+      inline bool is_list () const
+      {
+       if (empty ())
+         return false;
+       if (size () > 1)
+         return true;
+
+       const key_type &elt = begin ()->first;
+       return !(elt.first == 0 && elt.second == (Dwarf_Addr) -1);
+      }
+
+      inline mapped_type &location ()
+      {
+       if (empty ())
+         return (*this)[key_type (0, -1)];
+
+       value_type &v = *begin ();
+       if (v.first.first != 0 || v.first.second != (Dwarf_Addr) -1
+           || size () > 1)
+         throw std::runtime_error ("location is list, not single location");
+
+       return v.second;
+      }
+      inline const mapped_type &location () const
+      {
+       if (size () == 1)
+         {
+           const value_type &v = *begin ();
+           if (v.first.first == 0 && v.first.second == (Dwarf_Addr) -1)
+             return v.second;
+         }
+       throw std::runtime_error ("location is list, not single location");
+      }
+
+      template<typename other_attr>
+      bool operator== (const other_attr &other) const
+      {
+       if (empty ())
+         return (other.empty ()
+                 || std::find_if (other.begin (), other.end (),
+                                  nonempty<typename other_attr::value_type> ()
+                                  ) == other.end ());
+       if (!is_list ())
+         return (!other.is_list () && !other.empty ()
+                 && subr::container_equal (location (), other.location ()));
+
+       return other.is_list () && subr::container_equal (*this, other);
+      }
+      template<typename other_attr>
+      inline bool operator!= (const other_attr &other) const
+      {
+       return !(*this == other);
+      }
+
+      std::string to_string () const;
+    };
+
+    template<typename impl, bool alloc_values = true>
+    struct value
+    {
+      struct value_dispatch
+      {
+       virtual ~value_dispatch () {}
+      };
+
+      typedef value_dispatch value_cell_type;
+
+      static const bool delete_value = alloc_values;
+
+      template<typename flavor>
+      static inline flavor &
+      variant (flavor *&, const value_dispatch *&)
+      {
+       assert (!alloc_values);
+       throw std::logic_error ("can't happen!");
+      }
+
+      template<typename flavor>
+      static inline flavor &
+      variant (flavor *&result, value_dispatch *&value)
+      {
+       assert (alloc_values);
+       if (value == NULL)
+        {
+          result = new flavor;
+          value = result;
+          return *result;
+        }
+       result = dynamic_cast<flavor *> (value);
+       if (result == NULL)
+         throw std::runtime_error ("wrong value type");
+       return *result;
+      }
+
+      template<typename arg_type>
+      struct maker
+      {
+       inline explicit maker (const arg_type &) {}
+
+       template<typename flavor, typename input>
+       static inline void
+       make (value_dispatch *&v, flavor *&result,
+             int /*whatattr*/, const input &x, arg_type &arg)
+       {
+         assert (alloc_values);
+         v = result = new flavor (x, arg);
+       }
+      };
+
+      template<typename arg_type>
+      static inline maker<arg_type> make (arg_type &arg)
+      {
+       return maker<arg_type> (arg);
+      }
+
+      struct value_string : public value_dispatch, public std::string
+      {
+       typedef std::tr1::hash<std::string> hasher;
+
+       inline value_string () {}
+
+       template<typename string, typename arg_type>
+       inline value_string (const string &s, arg_type &)
+         : std::string (s)
+       {}
+
+       template<typename string>
+       inline value_string (const string &s)
+         : std::string (s)
+       {}
+
+       std::string to_string () const
+       {
+         std::string result ("\"");
+         result += *this;
+         result += "\"";
+         return result;
+       }
+      };
+
+      struct value_identifier : public value_string
+      {
+       inline value_identifier () {}
+
+       template<typename id, typename arg_type>
+       inline value_identifier (const id &s, arg_type &arg)
+         : value_string (s, arg)
+       {}
+
+       template<typename id>
+       inline value_identifier (const id &s)
+         : value_string (s)
+       {}
+      };
+
+      struct value_reference : public value_dispatch
+      {
+       typedef typename impl::debug_info_entry::pointer value_type;
+       value_type ref;
+
+       // Default constructor: reference to nowhere, invalid.
+       inline value_reference ()
+         : ref ()
+       {}
+
+       /* This is only kosher for a pointer into the same dwarf_edit
+          object.  This is what plain assignment does.  This just uses
+          this pointer, rather than translating it from another file
+          into this one (which requires a tracker).  */
+       inline value_reference (const value_type &i, subr::nothing &)
+         : ref (i)
+       {}
+
+       template<typename iter, typename tracker>
+       inline value_reference (const iter &i, tracker &t)
+         : ref ()              // Invalid until t.finish ().
+       {
+         t.refer (&ref, i);
+       }
+      };
+
+      struct value_flag : public value_dispatch
+      {
+       bool flag;
+
+       inline value_flag (bool t = true)
+         : flag (t)
+       {}
+
+       template<typename arg_type>
+       inline value_flag (bool t, arg_type &)
+         : flag (t)
+       {}
+      };
+
+      struct value_address : public value_dispatch
+      {
+       // XXX dwfl, reloc
+       ::Dwarf_Addr addr;
+
+       inline value_address (::Dwarf_Addr x = 0)
+         : addr (x)
+       {}
+
+       template<typename arg_type>
+       inline value_address (::Dwarf_Addr x, arg_type &)
+         : addr (x)
+       {}
+
+       struct hasher : public std::unary_function<value_address, size_t>
+       {
+         inline size_t operator () (const value_address &c) const
+         {
+           return c.addr;
+         }
+       };
+
+       inline operator ::Dwarf_Addr () const
+       {
+         return addr;
+       }
+
+       inline bool operator== (::Dwarf_Addr x) const
+       {
+         return addr == x;
+       }
+      };
+
+      struct value_rangelistptr : public value_dispatch, public range_list
+      {
+       inline value_rangelistptr () {}
+
+       template<typename list, typename arg_type>
+       inline value_rangelistptr (const list &other, arg_type &)
+         : range_list (other)
+       {}
+
+       template<typename list>
+       inline value_rangelistptr (const list &other)
+         : range_list (other)
+       {}
+      };
+
+      struct value_lineptr : public value_dispatch, public impl::line_info_table
+      {
+       inline value_lineptr () {}
+
+       template<typename table, typename arg_type>
+       inline value_lineptr (const table &other, arg_type &)
+         : impl::line_info_table (other)
+       {}
+      };
+
+      struct value_constant : public value_dispatch
+      {
+       union
+       {
+         ::Dwarf_Word word;
+         ::Dwarf_Sword sword;
+       };
+
+       inline value_constant (::Dwarf_Word value = 0)
+         : word (value)
+       {}
+
+       template<typename arg_type>
+       inline value_constant (::Dwarf_Word x, arg_type &)
+         : word (x)
+       {}
+
+       struct hasher : public std::unary_function<value_constant, size_t>
+       {
+         inline size_t operator () (const value_constant &c) const
+         {
+           return c.word;
+         }
+       };
+
+       inline operator ::Dwarf_Word () const
+       {
+         return word;
+       }
+
+       inline bool operator== (::Dwarf_Word x) const
+       {
+         return word == x;
+       }
+      };
+
+      struct value_constant_block : public value_dispatch,
+                                   public std::vector<uint8_t>
+      {
+       typedef subr::hash<std::vector<uint8_t> > hasher;
+
+       inline value_constant_block () {}
+
+       template<typename block, typename arg_type>
+       inline value_constant_block (const block &b, arg_type &)
+         : std::vector<uint8_t> (b.begin (), b.end ())
+       {}
+
+       template<typename block>
+       inline value_constant_block (const block &b)
+         : std::vector<uint8_t> (b.begin (), b.end ())
+       {}
+      };
+
+      struct value_dwarf_constant : public value_dispatch, public dwarf_enum
+      {
+       inline value_dwarf_constant () {}
+
+       template<typename constant>
+       inline value_dwarf_constant (const constant &other)
+         : dwarf_enum (other)
+       {}
+
+       template<typename constant, typename arg_type>
+       inline value_dwarf_constant (const constant &other, arg_type &)
+         : dwarf_enum (other)
+       {}
+      };
+
+      struct value_source_file : public value_dispatch, public source_file
+      {
+       inline value_source_file () {}
+
+       template<typename file, typename arg_type>
+       inline value_source_file (const file &other, arg_type &)
+         : source_file (other)
+       {}
+
+       template<typename file>
+       inline value_source_file (const file &other)
+         : source_file (other)
+       {}
+      };
+
+      struct value_source_line : public value_dispatch
+      {
+       unsigned int n;
+
+       inline value_source_line (unsigned int x = 0)
+         : n (x)
+       {}
+
+       template<typename arg_type>
+       inline value_source_line (unsigned int m, arg_type &)
+         : n (m)
+       {}
+
+       struct hasher : public std::unary_function<value_source_line, size_t>
+       {
+         inline size_t operator () (const value_source_line &c) const
+         {
+           return c.n;
+         }
+       };
+
+       inline operator unsigned int () const
+       {
+         return n;
+       }
+
+       inline bool operator== (unsigned int x) const
+       {
+         return n == x;
+       }
+      };
+
+      class value_source_column : public value_source_line
+      {
+      };
+
+      struct value_macptr : public value_dispatch {};
+
+      struct value_location : public value_dispatch, public location_attr
+      {
+       inline value_location () {}
+
+       template<typename loc, typename arg_type>
+       inline value_location (const loc &other, arg_type &)
+         : location_attr (other)
+       {}
+
+       template<typename loc>
+       inline value_location (const loc &other)
+         : location_attr (other)
+       {}
+      };
+    };
+
+    // Forward decl.
+    template<class impl, typename v = value<impl> > class attributes_type;
+
+    template<class impl, typename vw = value<impl> >
+    class attr_value
+    {
+      friend class attributes_type<impl, vw>;
+      friend class value<impl>;
+
+    protected:
+      typename vw::value_cell_type *_m_value;
+      typedef typename impl::debug_info_entry::pointer die_ptr;
+
+      template<typename value, typename arg_type = subr::nothing>
+      struct init
+      {
+       inline init (attr_value *av, int whatattr,
+                    const value &other, arg_type &arg)
+       {
+         do_init (av, whatattr, other, arg);
+       }
+
+       inline init (attr_value *av, int whatattr, const value &other)
+       {
+         arg_type dummy;
+         do_init (av, whatattr, other, dummy);
+       }
+
+       static inline void do_init (attr_value *av, int whatattr,
+                                   const value &other, arg_type &arg)
+       {
+         switch (other.what_space ())
+           {
+#define _DWARF_DATA_AV_MAKE(flavor, fetch)                                   \
+             case dwarf::VS_##flavor:                                        \
+               {                                                             \
+                 typename vw::value_##flavor *p;                             \
+                 vw::make (arg)                                              \
+                   .make (av->_m_value, p, whatattr, other.fetch (), arg);   \
+               }                                                             \
+             break
+
+             _DWARF_DATA_AV_MAKE (identifier, identifier);
+             _DWARF_DATA_AV_MAKE (string, string);
+             _DWARF_DATA_AV_MAKE (flag, flag);
+             _DWARF_DATA_AV_MAKE (rangelistptr, ranges);
+             _DWARF_DATA_AV_MAKE (lineptr, line_info);
+             _DWARF_DATA_AV_MAKE (address, address);
+             _DWARF_DATA_AV_MAKE (source_line, source_line);
+             _DWARF_DATA_AV_MAKE (source_file, source_file);
+             _DWARF_DATA_AV_MAKE (dwarf_constant, dwarf_constant);
+             _DWARF_DATA_AV_MAKE (reference, reference);
+             _DWARF_DATA_AV_MAKE (location, location);
+             //_DWARF_DATA_AV_MAKE (macptr, macros);   XXX
+
+           case dwarf::VS_constant:
+             if (other.constant_is_integer ())
+               {
+                 typename vw::value_constant *p;
+                 vw::make (arg).make (av->_m_value, p, whatattr,
+                                      other.constant (), arg);
+               }
+             else
+               {
+                 typename vw::value_constant_block *p;
+                 vw::make (arg).make (av->_m_value, p, whatattr,
+                                      other.constant_block (), arg);
+               }
+             break;
+
+           default:
+           case dwarf::VS_discr_list:
+             throw std::runtime_error ("XXX unimplemented");
+
+#undef _DWARF_DATA_AV_MAKE
+           }
+       }
+      };
+
+      // This is kosher only when freshly default-constructed.
+      template<typename value, typename arg_type>
+      inline void set (int whatattr, const value &other, arg_type &arg)
+      {
+       assert (_m_value == NULL);
+       init<value, arg_type> me (this, whatattr, other, arg);
+      }
+
+      template<typename flavor>
+      inline flavor &const_variant () const
+      {
+       flavor *p = dynamic_cast<flavor *> (_m_value);
+       if (p == NULL)
+         throw std::runtime_error (_m_value != NULL ? "wrong value type"
+                                   : "uninitialized attr_value (const?)");
+       return *p;
+      }
+
+      template<typename flavor>
+      inline const flavor &variant () const
+      {
+       return const_variant<const flavor> ();
+      }
+
+      template<typename flavor>
+      inline flavor &variant ()
+      {
+       flavor *p;
+       return vw::variant (p, _m_value);
+      }
+
+      template<typename value>
+      inline attr_value &copy (const value &other)
+      {
+       if (_m_value != NULL)
+         {
+           delete _m_value;
+           _m_value = NULL;
+         }
+       init<value> me (this, 0, other);
+       return *this;
+      }
+
+    public:
+      attr_value (const attr_value &other)
+       : _m_value (NULL)
+      {
+       if (other._m_value != NULL)
+         init<attr_value> me (this, 0, other);
+      }
+
+      inline attr_value ()
+       : _m_value (NULL)
+      {}
+
+      ~attr_value ()
+      {
+       if (vw::delete_value && _m_value != NULL)
+         delete _m_value;
+      }
+
+      template<typename value>
+      inline attr_value &operator= (const value &other)
+      {
+       return copy (other);
+      }
+
+      /* This is the same as the generic template one,
+        but we have to define it explicitly to override
+        the default assignment operator.  */
+      inline attr_value &operator= (const attr_value &other)
+      {
+       return copy (other);
+      }
+
+      dwarf::value_space what_space () const;
+      inline std::string to_string () const;
+
+      inline const bool &flag () const
+      {
+       return variant<typename vw::value_flag> ().flag;
+      }
+
+      inline bool &flag ()
+      {
+       return variant<typename vw::value_flag> ().flag;
+      }
+
+      // XXX dwfl, reloc
+      inline const ::Dwarf_Addr &address () const
+      {
+       return variant<typename vw::value_address> ().addr;
+      }
+
+      // XXX dwfl, reloc
+      inline ::Dwarf_Addr &address ()
+      {
+       return variant<typename vw::value_address> ().addr;
+      }
+
+      inline const die_ptr &reference () const
+      {
+       return variant<typename vw::value_reference> ().ref;
+      }
+
+      inline die_ptr &reference ()
+      {
+       return variant<typename vw::value_reference> ().ref;
+      }
+
+      inline const location_attr &location () const
+      {
+       return static_cast<const location_attr &>
+         (variant<typename vw::value_location> ());
+      }
+
+      inline location_attr &location ()
+      {
+       return static_cast<location_attr &>
+         (variant<typename vw::value_location> ());
+      }
+
+      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> ());
+      }
+
+      inline const std::string &identifier () const
+      {
+       return static_cast<const std::string &>
+         (variant<typename vw::value_identifier> ());
+      }
+
+      inline std::string &identifier ()
+      {
+       return static_cast<std::string &>
+         (variant<typename vw::value_identifier> ());
+      }
+
+      inline const typename impl::source_file &source_file () const
+      {
+       return static_cast<const typename impl::source_file &>
+         (variant<typename vw::value_source_file> ());
+      }
+
+      inline typename impl::source_file &source_file ()
+      {
+       return static_cast<typename impl::source_file &>
+         (variant<typename vw::value_source_file> ());
+      }
+
+      inline const unsigned int &source_line () const
+      {
+       return variant<typename vw::value_source_line> ().n;
+      }
+
+      inline unsigned int &source_line ()
+      {
+       return variant<typename vw::value_source_line> ().n;
+      }
+
+      inline const unsigned int &source_column () const
+      {
+       return variant<typename vw::value_source_column> ().n;
+      }
+
+      inline unsigned int &source_column ()
+      {
+       return variant<typename vw::value_source_column> ().n;
+      }
+
+      inline const ::Dwarf_Word &constant () const
+      {
+       return variant<typename vw::value_constant> ().word;
+      }
+
+      inline ::Dwarf_Word &constant ()
+      {
+       return variant<typename vw::value_constant> ().word;
+      }
+
+      inline const ::Dwarf_Sword &signed_constant () const
+      {
+       return variant<typename vw::value_constant> ().sword;
+      }
+
+      inline ::Dwarf_Sword &signed_constant ()
+      {
+       return variant<typename vw::value_constant> ().sword;
+      }
+
+      inline const std::vector<uint8_t> &constant_block () const
+      {
+       return static_cast<const std::vector<uint8_t> &>
+         (variant<typename vw::value_constant_block> ());
+      }
+
+      inline std::vector<uint8_t> &constant_block ()
+      {
+       return static_cast<std::vector<uint8_t> &>
+         (variant<typename vw::value_constant_block> ());
+      }
+
+      inline const typename impl::dwarf_enum &dwarf_constant () const
+      {
+       return variant<typename vw::value_dwarf_constant> ();
+      }
+
+      inline typename impl::dwarf_enum &dwarf_constant ()
+      {
+       return variant<typename vw::value_dwarf_constant> ();
+      }
+
+      inline bool constant_is_integer () const
+      {
+       return (dynamic_cast<const typename vw::value_constant *> (_m_value)
+               != NULL);
+      }
+
+      inline const typename impl::range_list &ranges () const
+      {
+       return static_cast<const range_list &>
+         (variant<const typename vw::value_rangelistptr> ());
+      }
+
+      inline typename impl::range_list &ranges ()
+      {
+       return static_cast<range_list &>
+         (variant<typename vw::value_rangelistptr> ());
+      }
+
+      inline const typename impl::line_info_table &line_info () const
+      {
+       return static_cast<const typename impl::line_info_table &>
+         (variant<const typename vw::value_lineptr> ());
+      }
+
+      inline typename impl::line_info_table &line_info ()
+      {
+       return static_cast<typename impl::line_info_table &>
+         (variant<typename vw::value_lineptr> ());
+      }
+
+      // macptr
+
+      template<typename value>
+      inline bool operator== (const value &other) const
+      {
+       const dwarf::value_space what = what_space ();
+       if (likely (other.what_space () == what))
+         switch (what)
+           {
+           case dwarf::VS_identifier:
+             return identifier () == other.identifier ();
+           case dwarf::VS_string:
+             return string () == other.string ();
+           case dwarf::VS_reference:
+             return reference () == other.reference ();
+           case dwarf::VS_flag:
+             return flag () == other.flag ();
+           case dwarf::VS_rangelistptr:
+             return ranges () == other.ranges ();
+           case dwarf::VS_lineptr:
+             return line_info () == other.line_info ();
+           case dwarf::VS_constant:
+             if (constant_is_integer ())
+               return (other.constant_is_integer ()
+                       && constant () == other.constant ());
+             return (!other.constant_is_integer ()
+                     && constant_block () == other.constant_block ());
+           case dwarf::VS_source_file:
+             return source_file () == other.source_file ();
+           case dwarf::VS_source_line:
+             return source_line () == other.source_line ();
+           case dwarf::VS_source_column:
+             return source_column () == other.source_column ();
+           case dwarf::VS_address:
+             return address () == other.address ();
+           case dwarf::VS_location:
+             return location () == other.location ();
+           case dwarf::VS_dwarf_constant:
+             return dwarf_constant () == other.dwarf_constant ();
+#if 0
+           case dwarf::VS_macptr:
+             return macptr () == other.macptr ();
+#endif
+           default:
+           case dwarf::VS_discr_list:
+             throw std::runtime_error ("XXX unimplemented");
+           }
+       return false;
+      }
+      template<typename value>
+      inline bool operator!= (const value &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    template<class impl, typename v>
+    class attributes_type
+      : public std::map<int, typename impl::attr_value>
+    {
+      friend class impl::me;
+    protected:
+      typedef std::map<int, typename impl::attr_value> base_type;
+
+      inline attributes_type () {}
+
+      template<typename iter>
+      inline attributes_type (const iter &from, const iter &to)
+       : base_type (from, to)
+      {}
+
+      template<typename input, typename arg_type>
+      inline void set (const input &other, arg_type &c)
+      {
+       for (typename input::const_iterator attr = other.begin ();
+            attr != other.end ();
+            ++attr)
+         (*this)[(*attr).first].set ((*attr).first, (*attr).second, c);
+      }
+
+    public: // XXX should be protected
+
+      /* We don't use the base_type (begin, end) iterator constructor here
+        for good reason.  The ref-maker needs to collect back-pointers
+        into our mapped_value (attr_value) objects.  It would not fly to
+        have that done in a temporary attr_value object that gets copied
+        into the map cell by assignment.  We must make sure that when a
+        value_reference is constructed, it is really the one sitting in
+        our map that the ref-maker will want to update later.  */
+      template<typename input, typename arg_type>
+      inline attributes_type (const input &other, arg_type &c)
+       : base_type ()
+      {
+       set (other, c);
+      }
+
+    public:
+      typedef typename base_type::key_type key_type;
+      typedef typename base_type::value_type value_type;
+      typedef typename base_type::mapped_type mapped_type;
+
+      static inline bool ordered ()
+      {
+       return true;
+      }
+
+      template<typename attrs>
+      inline operator attrs () const
+      {
+       return attrs (base_type::begin (), base_type::end ());
+      }
+    };
+
+  };
+
+  // Explicit specializations.
+  template<>
+  std::string to_string<dwarf_data::dwarf_enum> (const dwarf_data::dwarf_enum&);
+  inline std::string dwarf_data::dwarf_enum::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+
+  template<class impl, typename v>
+  inline std::string dwarf_data::attr_value<impl, v>::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+
+};
+
+#endif
diff --git a/libdw/c++/dwarf_edit b/libdw/c++/dwarf_edit
new file mode 100644 (file)
index 0000000..f5c3e7f
--- /dev/null
@@ -0,0 +1,376 @@
+/* elfutils::dwarf_edit -- mutable DWARF representation in -*- C++ -*-
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF_EDIT
+#define _ELFUTILS_DWARF_EDIT   1
+
+#include "dwarf"
+#include "dwarf_data"
+#include "dwarf_ref_maker"
+
+#include <type_traits>
+
+
+/* Read the comments for elfutils::dwarf first.
+
+   The elfutils::dwarf_edit class is template-compatible with the logical
+   containers described in elfutils::dwarf, and copy-constructible from the
+   input class.
+
+   The elfutils::dwarf_edit containers are mutable, unlike the input
+   classes.  You can modify the DWARF directly in all the normal ways the
+   corresponding std containers have, or build it up from scratch.  When
+   you have it how you want it, you can pass it into elfutils::dwarf_output.
+
+   The dwarf_edit classes will use unreasonable amounts of memory for large
+   DWARF data sets, like from reading in whole large program and DSO files.
+   To transform input files efficiently, you should construct dwarf_output
+   directly from input dwarf with transformations applied on the fly, and
+   not use dwarf_edit at all.
+
+   dwarf_edit is the only mutable representation and so it's easy to use in
+   a straightforward imperative style.  Use it for transformations on small
+   data files, or for creating small data sets from scratch.  */
+
+// DWARF manipulation interfaces (pure object construction)
+namespace elfutils
+{
+  template<typename elt>
+  inline bool operator== (const std::vector<elt> &a, const const_vector<elt> &b)
+  {
+    return a.size () == b.size () && subr::container_equal (a, b);
+  }
+
+  class dwarf_edit
+  {
+  private:
+    friend class dwarf_data;
+    typedef dwarf_edit me;
+
+  public:
+    typedef dwarf_data::source_file source_file;
+    typedef dwarf_data::line_entry<source_file> line_entry;
+    typedef dwarf_data::line_table<line_entry> line_table;
+    typedef dwarf_data::line_info_table<line_table> line_info_table;
+    typedef dwarf_data::dwarf_enum dwarf_enum;
+    typedef dwarf_data::range_list range_list;
+    typedef dwarf_data::location_attr location_attr;
+    typedef dwarf_data::attr_value<dwarf_edit> attr_value;
+
+    class debug_info_entry
+    {
+      friend class subr::create_container;
+
+    public:
+      typedef dwarf_data::attributes_type<dwarf_edit> attributes_type;
+
+      class children_type : public std::list<debug_info_entry>
+      {
+       friend class debug_info_entry;
+      private:
+        inline children_type () {}
+
+       template<typename input, typename tracker>
+       static inline void
+       equivalence (const iterator &out,
+                    const typename input::const_iterator &in,
+                    bool,      // last-sibling
+                    tracker &t)
+       {
+         out->set (*in, t);
+         t.equivalence (out, in);
+       }
+
+       template<typename input, typename tracker>
+       inline children_type (const input &other, tracker &t)
+       {
+         subr::create_container (this, other, t, equivalence<input, tracker>);
+       }
+
+      public:
+       typedef debug_info_entry value_type;
+
+       inline iterator add_entry (int tag, const iterator &pos)
+       {
+         return insert (pos, debug_info_entry (tag));
+       }
+
+       inline iterator add_entry (int tag)
+       {
+         return add_entry (tag, end ());
+       }
+      };
+
+      typedef children_type::iterator pointer;
+      typedef children_type::const_iterator const_pointer;
+
+    protected:
+      int _m_tag;
+      attributes_type _m_attributes;
+      children_type _m_children;
+
+      // This is can only be used by the children_type constructor,
+      // which immediately calls set.
+      inline debug_info_entry ()
+       : _m_tag (-1), _m_attributes (), _m_children ()
+      {}
+
+      template<typename die_type, typename arg_type>
+      inline void set (const die_type &die, arg_type &arg)
+      {
+       try
+         {
+           _m_tag = die.tag ();
+           attributes_type t_attrs (die.attributes (), arg);
+           _m_attributes.swap (t_attrs);
+           children_type t_children (die.children (), arg);
+           _m_children.swap (t_children);
+         }
+       catch (...)
+         {
+           // Never leave a partially-formed DIE.
+           _m_tag = -1;
+           _m_attributes.clear ();
+           _m_children.clear ();
+           throw;
+         };
+      }
+
+    public:
+      inline debug_info_entry (int t)
+       : _m_tag (t), _m_attributes (), _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 tracker>
+      debug_info_entry (const die_type &die, tracker &t)
+       : _m_tag (die.tag ()),
+         _m_attributes (die.attributes (), t),
+         _m_children (die.children (), t)
+      {}
+
+      inline std::string to_string () const;
+
+      inline int tag () const
+      {
+       return _m_tag;
+      }
+
+      inline bool has_children () const
+      {
+       return !_m_children.empty ();
+      }
+
+      inline children_type &children ()
+      {
+       return _m_children;
+      }
+      inline const children_type &children () const
+      {
+       return _m_children;
+      }
+
+      inline attributes_type &attributes ()
+      {
+       return _m_attributes;
+      }
+      inline const attributes_type &attributes () const
+      {
+       return _m_attributes;
+      }
+
+      template<typename die>
+      bool operator== (const die &other) const
+      {
+       return (other.tag () == tag ()
+               && other.attributes () == attributes ()
+               && other.children () == children ());
+      }
+      template<typename die>
+      bool operator!= (const die &other) const
+      {
+       return !(*this == other);
+      }
+
+      inline dwarf::debug_info_entry::identity_type identity () const
+      {
+       return (uintptr_t) this;
+      }
+
+      inline ::Dwarf_Off offset () const
+      {
+       return identity ();
+      }
+
+      inline ::Dwarf_Off cost () const
+      {
+       return 0;
+      }
+
+      // Convenience entry point.
+      inline pointer add_entry (int child_tag)
+      {
+       return children ().add_entry (child_tag);
+      }
+    };
+
+    typedef debug_info_entry::attributes_type::value_type attribute;
+
+    typedef dwarf_data::compile_unit<dwarf_edit> compile_unit;
+
+    // Main container anchoring all the output.
+    class compile_units_type
+      : public dwarf_data::compile_units_type<dwarf_edit>
+    {
+      friend class dwarf_edit;
+
+    private:
+      inline compile_units_type (const compile_units_type &)
+       : dwarf_data::compile_units_type<dwarf_edit> ()
+      {
+       throw std::logic_error
+         ("must copy-construct top-level dwarf_edit object instead");
+      }
+
+      // Constructor copying CUs from input container.
+      template<typename input, typename tracker>
+      inline compile_units_type (const input &other, tracker &t)
+      {
+       subr::create_container (this, other, t);
+      }
+
+    public:
+      // Default constructor: an empty container, no CUs.
+      inline compile_units_type () {}
+
+      inline compile_unit &add_unit ()
+      {
+       push_back (compile_unit ());
+       return back ();
+      }
+    };
+
+  private:
+    compile_units_type _m_units;
+
+    typedef dwarf_ref_maker<dwarf_edit, dwarf_edit> edit_ref_maker;
+
+  public:
+    class compile_units_type &compile_units ()
+    {
+      return _m_units;
+    }
+    const class compile_units_type &compile_units () const
+    {
+      return _m_units;
+    }
+
+    // Convenience entry point.
+    inline compile_unit &add_unit ()
+    {
+      return compile_units ().add_unit ();
+    }
+
+    // Default constructor: an empty container, no CUs.
+    inline dwarf_edit () {}
+
+    // Constructor copying CUs from an input file (dwarf or dwarf_edit).
+    template<typename input, typename tracker>
+    inline dwarf_edit (const input &dw, tracker &t,
+                      subr::guard<tracker> guard = subr::guard<tracker> ())
+      : _m_units (dw.compile_units (), guard (t))
+    {
+      guard.clear ();
+    }
+
+    // Copying constructor with default ref-maker.
+    template<typename input>
+    inline dwarf_edit (const input &dw,
+                      dwarf_ref_maker<dwarf_edit, input> t
+                      = dwarf_ref_maker<dwarf_edit, input> (),
+                      subr::guard<dwarf_ref_maker<dwarf_edit, input> > guard
+                      = subr::guard<dwarf_ref_maker<dwarf_edit, input> > ())
+      : _m_units (dw.compile_units (), guard (t))
+    {
+      guard.clear ();
+    }
+
+    // We have to write this explicitly or it will do default-copying!
+    inline dwarf_edit (const dwarf_edit &dw,
+                      edit_ref_maker t = edit_ref_maker (),
+                      subr::guard<edit_ref_maker > guard
+                      = subr::guard<edit_ref_maker > ())
+      : _m_units (dw.compile_units (), guard (t))
+    {
+      guard.clear ();
+    }
+
+    template<typename file>
+    inline bool operator== (const file &other) const
+    {
+      return compile_units () == other.compile_units ();
+    }
+    template<typename file>
+    inline bool operator!= (const file &other) const
+    {
+      return !(*this == other);
+    }
+  };
+
+  // Explicit specializations.
+  template<>
+  std::string to_string<dwarf_edit::debug_info_entry>
+  (const dwarf_edit::debug_info_entry &);
+  inline std::string dwarf_edit::debug_info_entry::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+  template<>
+  std::string to_string<dwarf_edit::attribute> (const dwarf_edit::attribute &);
+  template<>
+  std::string to_string<dwarf_edit::attr_value> (const dwarf_edit::attr_value&);
+
+  template<>
+  std::string dwarf_edit::line_table::to_string () const;
+  template<>
+  std::string dwarf_edit::line_info_table::to_string () const;
+
+  // Explicit instantiations.
+  extern template class dwarf_data::line_entry<dwarf_edit::source_file>;
+  extern template class dwarf_data::line_table<dwarf_edit::line_entry>;
+  extern template class dwarf_data::line_info_table<dwarf_edit::line_table>;
+  extern template class dwarf_data::attr_value<dwarf_edit>;
+  extern template class dwarf_data::value<dwarf_edit>;
+
+};
+
+#endif // <elfutils/dwarf_edit>
diff --git a/libdw/c++/dwarf_output b/libdw/c++/dwarf_output
new file mode 100644 (file)
index 0000000..07799c1
--- /dev/null
@@ -0,0 +1,2912 @@
+/* elfutils::dwarf_output -- DWARF file generation in -*- C++ -*-
+   Copyright (C) 2009, 2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF_OUTPUT
+#define _ELFUTILS_DWARF_OUTPUT 1
+
+#include "dwarf"
+#include "dwarf_edit"
+#include "dwarf_comparator"
+#include <algorithm>
+#include <functional>
+#include <iterator>
+#include <vector>
+#include <stack>
+#include <queue>
+#include <bitset>
+#include <set>
+#include <tr1/unordered_set>
+
+/* Read the comments for elfutils::dwarf first.
+
+   The elfutils::dwarf_output class is template-compatible with the logical
+   containers described in elfutils::dwarf and elfutils::dwarf_edit.
+
+   The dwarf_output representation of the DWARF data is immutable once
+   created.  The only way to create the object is by copy-construction
+   from another compatible object: dwarf, dwarf_edit, or dwarf_output.
+   Construction collects all the information necessary to generate the
+   formatted DWARF sections.  */
+
+namespace elfutils
+{
+  class dwarf_output_collector;
+
+  class dwarf_output
+  {
+  private:
+    friend class dwarf_output_collector;
+    friend class dwarf_data;
+    typedef dwarf_output me;
+
+  public:
+    typedef dwarf_data::source_file source_file;
+    typedef dwarf_data::line_entry<source_file> line_entry;
+    typedef dwarf_data::line_table<line_entry> line_table;
+    typedef dwarf_data::line_info_table<line_table> line_info_table;
+    typedef dwarf_data::dwarf_enum dwarf_enum;
+    typedef dwarf_data::range_list range_list;
+    typedef dwarf_data::location_attr location_attr;
+
+    class compile_units_type;
+    class debug_info_entry;
+    class attr_value;
+
+  protected:
+    static inline void never_copy ()
+    {
+      throw std::logic_error
+       ("must copy-construct top-level dwarf_output object instead");
+    }
+
+    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).  */
+    template<typename input, typename output>
+    static inline typename subr::argifier<input, output,
+                                         dwarf_output_collector &>::result_type
+    collectify (const typename input::const_iterator &in,
+               dwarf_output_collector &c)
+    {
+      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.  */
+    struct value
+      : public dwarf_data::value<dwarf_output, false>
+    {
+      typedef const value_dispatch value_cell_type;
+
+      typedef dwarf_data::value<dwarf_output> data;
+
+      template<typename copier_type> struct maker;
+
+      template<typename arg_type>
+      static inline maker<arg_type> make (arg_type &arg)
+      {
+       return maker<arg_type> (arg);
+      }
+
+      struct value_reference;  // Defined below.
+    };
+
+    struct die_info;
+    typedef std::pair<const debug_info_entry, die_info> die_info_pair;
+
+  public:
+
+    class debug_info_entry
+    {
+      friend class dwarf_output;
+      friend class dwarf_output_collector;
+
+      __attribute__((used)) die_info_pair *info () const
+      {
+       return reinterpret_cast<die_info_pair *>
+         (const_cast<debug_info_entry *> (this));
+      }
+
+    public:
+      class attributes_type
+       : public dwarf_data::attributes_type<dwarf_output, value>
+      {
+       friend class dwarf_output;
+
+      private:
+       typedef dwarf_data::attributes_type<dwarf_output, value> _base;
+
+       size_t _m_hash;
+
+       inline attributes_type ()
+         : _base (), _m_hash (0)
+       {}
+
+       struct same_attr : public std::equal_to<value_type>
+       {
+         bool operator () (const value_type &a,
+                           const value_type &b) const
+         {
+           return a.first == b.first && a.second.is (b.second);
+         }
+       };
+
+       inline void do_hash ()
+       {
+         // Precompute our hash value based on our contents.
+         for (iterator i = begin (); i != end (); ++i)
+           subr::hash_combine (_m_hash, *i);
+       }
+
+       inline const _base &base () const
+       {
+         return *this;
+       }
+
+      public:
+       template<typename iter>
+       inline attributes_type (const iter &from, const iter &to)
+         : _base (from, to), _m_hash (0)
+       {
+         do_hash ();
+       }
+
+       friend class subr::hashed_hasher<attributes_type>;
+       typedef subr::hashed_hasher<attributes_type> hasher;
+
+       template<typename input, typename arg_type>
+       inline attributes_type (const input &other, arg_type &c)
+         : _base (other, c), _m_hash (0)
+       {
+         do_hash ();
+       }
+
+       inline bool is (const attributes_type &these) const
+       {
+         return (_m_hash == these._m_hash
+                 && size () == these.size ()
+                 && std::equal (begin (), end (), these.begin (),
+                                same_attr ()));
+       }
+      };
+
+      class children_type
+       : public std::vector<die_info_pair *>
+      {
+       friend class dwarf_output;
+       friend class dwarf_output_collector;
+
+      protected:
+       typedef std::vector<die_info_pair *> _base;
+
+       size_t _m_hash;
+
+       inline void set_hash ()
+       {
+         _m_hash = 0;
+         for (_base::iterator i = _base::begin (); i != _base::end (); ++i)
+           subr::hash_combine (_m_hash, (uintptr_t) *i);
+       }
+
+        inline children_type () {}
+
+       inline const _base &info () const
+       {
+         return *this;
+       }
+
+       struct deref
+         : public std::unary_function<die_info_pair *,
+                                      const debug_info_entry &>
+       {
+         inline deref (...) {}
+         inline const debug_info_entry &operator () (die_info_pair *) const;
+       };
+
+       template<typename circular>
+       inline void reify_children (die_info_pair *, bool, unsigned int &)
+         const;
+
+      public:
+       template<typename iter>
+       inline children_type (const iter &first, const iter &last)
+         : _base (first, last)
+       {
+         set_hash ();
+       }
+
+       friend class subr::hashed_hasher<children_type>;
+       typedef subr::hashed_hasher<children_type> hasher;
+
+       typedef debug_info_entry value_type;
+       typedef debug_info_entry &reference;
+       typedef debug_info_entry &const_reference;
+       typedef debug_info_entry *pointer;
+       typedef debug_info_entry *const_pointer;
+
+       inline bool is (const children_type &these) const
+       {
+         return (_m_hash == these._m_hash
+                 && size () == these.size ()
+                 && std::equal (_base::begin (), _base::end (),
+                                these._base::begin ()));
+       }
+
+       typedef subr::wrapped_input_iterator<
+         _base, deref, const debug_info_entry> const_iterator;
+       typedef const_iterator iterator;
+
+       inline const_iterator begin () const
+       {
+         return const_iterator (_base::begin (), subr::nothing ());
+       }
+
+       inline const_iterator end () const
+       {
+         return const_iterator (_base::end (), subr::nothing ());
+       }
+      };
+
+      typedef children_type::iterator pointer;
+      typedef children_type::const_iterator const_pointer;
+
+    protected:
+      const children_type *_m_children;
+      const attributes_type *_m_attributes;
+      size_t _m_hash;
+      int _m_tag;
+
+      // This is can only be used by the children_type constructor,
+      // which immediately calls set.
+      inline debug_info_entry ()
+       : _m_children (NULL),
+         _m_attributes (NULL),
+         _m_hash (0),
+         _m_tag (-1)
+      {}
+
+      inline debug_info_entry (int what,
+                              const children_type *childs,
+                              const attributes_type *attrs)
+       : _m_children (childs),
+         _m_attributes (attrs),
+         _m_tag (what)
+      {
+       set_hash ();
+      }
+
+      inline void set_hash ()
+      {
+       _m_hash = _m_tag;
+       subr::hash_combine (_m_hash, *_m_attributes);
+       subr::hash_combine (_m_hash, *_m_children);
+      }
+
+    public:
+      friend class subr::hashed_hasher<debug_info_entry>;
+      typedef subr::hashed_hasher<debug_info_entry> hasher;
+
+      inline bool is (const debug_info_entry &that) const
+      {
+       return (_m_hash == that._m_hash
+               && _m_tag == that._m_tag
+               && _m_attributes == that._m_attributes
+               && _m_children == that._m_children);
+      }
+
+      inline std::string to_string () const;
+
+      inline int tag () const
+      {
+       return _m_tag;
+      }
+
+      inline bool has_children () const
+      {
+       return !_m_children->empty ();
+      }
+
+      inline const children_type &children () const
+      {
+       return *_m_children;
+      }
+
+      inline const attributes_type &attributes () const
+      {
+       return *_m_attributes;
+      }
+
+      template<typename die>
+      bool operator== (const die &other) const
+      {
+       return (other.tag () == tag ()
+               && other.attributes () == attributes ()
+               && other.children () == children ());
+      }
+      template<typename die>
+      bool operator!= (const die &other) const
+      {
+       return !(*this == other);
+      }
+
+      inline dwarf::debug_info_entry::identity_type identity () const
+      {
+       return (uintptr_t) this;
+      }
+
+      inline ::Dwarf_Off offset () const
+      {
+       return identity ();
+      }
+
+      inline ::Dwarf_Off cost () const
+      {
+       return 0;
+      }
+    };
+
+    struct value::value_reference
+      : public dwarf_data::value<dwarf_output, false>::value_reference
+    {
+      typedef dwarf_data::value<dwarf_output, false>::value_reference _base;
+
+      // Default constructor: reference to nowhere, invalid.
+      inline value_reference ()
+       : _base ()
+      {}
+
+      inline value_reference (const value_type &i, subr::nothing &dummy)
+       : _base (i, dummy)
+      {}
+
+      /* The hash of a value_reference is its referent's local hash,
+        which only takes non-reference values into account.  This
+        method is virtual for the circular_reference case, below.  */
+      inline size_t hash () const
+      {
+       struct die_info *info = get_die_info ();
+       return info->_m_reference_hash;
+      }
+
+      virtual die_info *get_die_info () const
+      {
+       return &ref->info ()->second;
+      }
+    };
+
+    class attr_value
+      : public dwarf_data::attr_value<dwarf_output, value>
+    {
+      friend class dwarf_output;
+
+    private:
+      typedef dwarf_data::attr_value<dwarf_output, value> _base;
+
+    public:
+      inline std::string to_string () const;
+
+      /* These constructors can only be used by the containers
+        used in the collector.  The attributes_type map in an
+        actual debug_info_entry object is always const.  */
+      inline attr_value ()
+       : _base ()
+      {}
+
+      inline attr_value (const attr_value &other)
+       : _base ()
+      {
+       _m_value = other._m_value;
+      }
+
+      /* Two identical values in fact share the same cell in the collector.
+        So we can use simple pointer comparison here.  */
+      inline bool is (const attr_value &that) const
+      {
+       return _m_value == that._m_value;
+      }
+
+      // The is () test works only on a dwarf_output sharing the same collector.
+      inline bool operator== (const attr_value &other) const
+      {
+       return is (other) || _base::operator== (other);
+      }
+      inline bool operator!= (const attr_value &other) const
+      {
+       return !(*this == other);
+      }
+
+      /* We can use the _m_value pointer itself as a perfect hash,
+        because all identical values share the same cell in the
+        collector.  The exception to this is for references.  See
+        value_reference::hash.  */
+      struct hasher : public std::unary_function<attr_value, size_t>
+      {
+       inline size_t operator () (const attr_value &v) const
+       {
+         const value::value_reference *ref
+           = dynamic_cast<const value::value_reference *> (v._m_value);
+         return ref == NULL ? (uintptr_t) v._m_value : ref->hash ();
+       }
+      };
+    };
+
+    typedef debug_info_entry::attributes_type::value_type attribute;
+
+    typedef dwarf_data::compile_unit<dwarf_output> compile_unit;
+
+    /* Main container anchoring all the output.
+
+       This is the only container that actually lives in the dwarf_output
+       object.  All others live in the dwarf_output_collector's sets, and
+       we return const references to those copies.
+
+       This list is actually mutable as a std::list.  But note that you
+       should never remove a compile_unit, though you can reorder the
+       list.  Nothing is ever removed from the collector, so your final
+       output file can wind up with unreferenced data being encoded.  If
+       you do remove any elements, then you should start a fresh collector
+       and construct a new dwarf_output object by copying using that
+       collector (or, equivalently, call o.compile_units ().recollect (C)
+       on the new collector C).  */
+    class compile_units_type
+      : public dwarf_data::compile_units_type<dwarf_output>
+    {
+      friend class dwarf_output;
+
+    private:
+      inline compile_units_type (const compile_units_type &)
+       : dwarf_data::compile_units_type<dwarf_output> ()
+      {
+       never_copy ();
+      }
+
+      template<typename input, typename copier_type>
+      static inline void
+      cu_maker (const iterator &out,
+               const typename input::const_iterator &in,
+               bool,   // last-sibling
+               copier_type &c)
+      {
+       c.make_unit (in, out);
+      }
+
+      // Constructor copying CUs from input container.
+      template<typename input, typename copier>
+      inline compile_units_type (const input &other, copier &c)
+      {
+       subr::create_container (this, other, c, cu_maker<input, copier>);
+      }
+
+    public:
+      // Default constructor: an empty container, no CUs.
+      inline compile_units_type () {}
+    };
+
+  private:
+    compile_units_type _m_units;
+
+  public:
+    class compile_units_type &compile_units ()
+    {
+      return _m_units;
+    }
+    const class compile_units_type &compile_units () const
+    {
+      return _m_units;
+    }
+
+  private:
+    // Bind default copy-constructor and prevent it.
+    inline dwarf_output (const dwarf_output &)
+    {
+      throw std::logic_error ("copying dwarf_output requires a collector");
+    }
+
+  public:
+    // Constructor for an empty file, can add to its compile_units ().
+    inline dwarf_output () {}
+
+    /* Constructor copying CUs from an input file (can be any of dwarf,
+       dwarf_edit, or dwarf_output).  Supply your own copier to reuse a
+       copier across multiple input files.  This is worthwhile only if
+       they share a string table and such in memory.  */
+    template<typename input>
+    inline dwarf_output (const input &dw, copier<input> &maker)
+      : _m_units (dw.compile_units (), maker)
+    {}
+
+    // Normal construction instantiates a copier derived from the collector.
+    template<typename input>
+    inline dwarf_output (const input &dw, dwarf_output_collector &c)
+    {
+      copier<input> maker (c);
+      compile_units_type tmp_units (dw.compile_units (), maker);
+      _m_units.swap (tmp_units);
+    }
+
+    template<typename file>
+    inline bool operator== (const file &other) const
+    {
+      return compile_units () == other.compile_units ();
+    }
+    template<typename file>
+    inline bool operator!= (const file &other) const
+    {
+      return !(*this == other);
+    }
+
+  protected:
+    struct die_info
+    {
+      die_info_pair *_m_parent;
+      std::queue<value::value_reference *> _m_refs;
+      std::set< ::Dwarf_Off> _m_originals; // XXX fix for cross-file sharing input
+      size_t _m_original_cost;
+      std::bitset<2> _m_with_sibling;
+      unsigned int _m_uses;
+
+      /* The local hash of the die, set when die_info is created.
+        Uses only none-reference values.  */
+      size_t _m_local_hash;
+
+      /* The reference hash of the die, based on just reference
+        attribute values.  Needs all local hashes of referenced dies
+        to be set.  */
+      size_t _m_reference_hash;
+
+      inline die_info (size_t local_hash)
+       : _m_parent (NULL), _m_refs (),
+         _m_originals (), _m_original_cost (0),
+         _m_with_sibling (), _m_uses (0),
+         _m_local_hash (local_hash),
+         _m_reference_hash (0)
+      {}
+
+      inline ~die_info ()
+      {
+       while (!_m_refs.empty ())
+         {
+           delete _m_refs.front ();
+           _m_refs.pop ();
+         }
+      }
+
+      inline void original (unsigned int &incoming_count,
+                           ::Dwarf_Off off, ::Dwarf_Off cost)
+      {
+       assert ((::Dwarf_Off) (size_t) cost == cost);
+       if (_m_originals.insert (off).second)
+         {
+           ++incoming_count;
+           _m_original_cost += cost;
+         }
+      }
+
+      inline std::set< ::Dwarf_Off>::size_type count_originals () const
+      {
+       return _m_originals.size ();
+      }
+
+      inline ptrdiff_t original_cost () const
+      {
+       return _m_original_cost;
+      }
+
+      inline ::Dwarf_Off original_offset () const
+      {
+       return *_m_originals.begin ();
+      }
+
+      template<typename streamish>
+      inline streamish &dump_originals (streamish &out) const
+      {
+       out << std::hex;
+       for (typename std::set< ::Dwarf_Off>::const_iterator i
+              = _m_originals.begin ();
+            i !=_m_originals.end ();
+            ++i)
+         out << " " << *i;
+       return out << std::dec;
+      }
+
+      inline ptrdiff_t output_cost () const
+      {
+       // XXX temporary proxy
+       return (double (_m_original_cost) / double (count_originals ())) + 0.5;
+      }
+
+      inline std::ostream &list_originals (std::ostream &o) const
+      {
+       for (std::set< ::Dwarf_Off>::const_iterator i = _m_originals.begin ();
+            i != _m_originals.end ();
+            ++i)
+         o << " " << std::hex << *i;
+       return o;
+      }
+
+      inline unsigned int uses () const
+      {
+       return _m_uses;
+      }
+
+      inline void assert_unused () const
+      {
+       assert (uses () == 0);
+       assert (_m_with_sibling.none ());
+       assert (_m_refs.empty ());
+      }
+
+      inline void self (value::value_reference *ref)
+      {
+       _m_refs.push (ref);
+      }
+
+      inline void
+      self (const debug_info_entry::pointer &ref)
+      {
+       subr::nothing dummy;
+       self (new value::value_reference (ref, dummy));
+      }
+
+      inline void
+      self (const debug_info_entry::children_type::_base::const_iterator &ref)
+      {
+       self (debug_info_entry::pointer (ref, subr::nothing ()));
+      }
+
+      inline bool selfless () const
+      {
+       return _m_refs.empty ();
+      }
+
+      inline value::value_reference *self () const
+      {
+       assert (!selfless ());
+       return _m_refs.front ();
+      }
+
+      template<typename circular>
+      inline void
+      reify_refs (const debug_info_entry::pointer &ref)
+      {
+       for (size_t n = _m_refs.size (); n > 0; --n)
+         {
+           value::value_reference *self_ref = _m_refs.front ();
+           self_ref->ref = ref;
+           _m_refs.pop ();
+           _m_refs.push (self_ref);
+
+           circular *circle = dynamic_cast<circular *> (self_ref);
+           if (circle != NULL && !circle->final ())
+             circle->placed ();
+         }
+      }
+
+      template<typename circular>
+      inline void
+      placed (die_info_pair *parent, const debug_info_entry::pointer &ref,
+             bool have_sibling, unsigned int &total)
+      {
+       // Record first parent.
+       if (_m_parent == NULL)
+         {
+           assert (uses () == 0 || parent == NULL);
+           _m_parent = parent;
+         }
+       else
+         assert (uses () > 0);
+
+       if (selfless ())
+         {
+           assert (uses () == 0);
+           self (ref);
+         }
+       else
+         reify_refs<circular> (ref);
+
+       ++total;
+       ++_m_uses;
+       _m_with_sibling[have_sibling] = true;
+      }
+    };
+  };
+
+  // Explicit specializations.
+  template<>
+  std::string to_string<dwarf_output::debug_info_entry>
+  (const dwarf_output::debug_info_entry &);
+  inline std::string dwarf_output::debug_info_entry::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+  template<>
+  std::string
+  to_string<dwarf_output::attribute> (const dwarf_output::attribute &);
+  template<>
+  std::string
+  to_string<dwarf_output::attr_value> (const dwarf_output::attr_value &);
+
+  inline std::string dwarf_output::attr_value::to_string () const
+  {
+    return elfutils::to_string (*this); // Use that.
+  }
+
+  template<typename copier_type>
+  struct dwarf_output::value::maker
+  {
+    inline explicit maker (copier_type &) {}
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_string *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_string (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_identifier *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_identifier (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_reference *&,
+                     int, const input &x, copier_type &c)
+    {
+      c.add_reference (x, &v);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_flag *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_flag (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_address *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_address (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_rangelistptr *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_ranges (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_lineptr *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_line_info (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_constant *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_constant (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_constant_block *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_constant_block (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_dwarf_constant *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_dwarf_constant (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_source_file *&,
+                     int attr, const input &x, copier_type &c)
+    {
+      v = c ().add_source_file (attr, x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_source_line *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_source_line (x);
+    }
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_source_column *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_source_column (x);
+    }
+
+    // XXX macptr
+
+    template<typename input>
+    inline void make (const value_dispatch *&v, value_location *&,
+                     int, const input &x, copier_type &c)
+    {
+      v = c ().add_location (x);
+    }
+  };
+
+  template<>
+  struct dwarf_output::value::maker<subr::nothing>
+  {
+    inline explicit maker (subr::nothing &) {}
+
+    template<typename... args>
+    inline void make (args&&...)
+    {
+      throw std::logic_error ("dwarf_output cannot be default-constructed");
+    }
+  };
+
+  template<>
+  inline subr::nostream &
+  dwarf_output::die_info::dump_originals (subr::nostream &out) const
+  {
+    return out;
+  }
+
+  /* This is the wrapper in the guts of a children_type iterator.
+     It turns the real pointer we store into a debug_info_entry
+     reference for the generic tree-walk API.  */
+  inline const dwarf_output::debug_info_entry &
+  dwarf_output::debug_info_entry::children_type::deref::operator ()
+    (dwarf_output::die_info_pair *p) const
+  {
+    return p->first;
+  }
+
+  /* This is called when a children_type is installed freshly in the collector.
+     Fill in its back pointers.  */
+  template<typename circular>
+  inline void
+  dwarf_output::debug_info_entry::children_type::
+  reify_children (die_info_pair *parent, bool placed, unsigned int &total) const
+  {
+    _base::const_iterator i = _base::begin ();
+    bool have_sibling = i != _base::end ();
+    while (have_sibling)
+      {
+       const const_iterator here (i, subr::nothing ());
+       have_sibling = ++i != _base::end ();
+       die_info &child = (*here.base ())->second;
+       if (placed)
+         child.placed<circular> (parent, here, have_sibling, total);
+       else
+         child.reify_refs<circular> (here);
+      }
+  }
+
+  class dwarf_output_collector
+  {
+    friend class dwarf_output;
+
+  private:
+    unsigned int _m_total;
+    unsigned int _m_incoming;
+
+    typedef dwarf_output::die_info die_info;
+    typedef dwarf_output::die_info_pair die_info_pair;
+    typedef dwarf_output::debug_info_entry die_type;
+    typedef die_type::attributes_type attrs_type;
+    typedef die_type::children_type children_type;
+    typedef children_type::const_iterator die_ptr;
+
+    // Simple value sets for leaf types.
+    subr::value_set<dwarf_output::value::value_string> _m_strings;
+    subr::value_set<dwarf_output::value::value_identifier> _m_identifiers;
+    subr::value_set<dwarf_output::value::value_address> _m_address;
+    subr::value_set<dwarf_output::value::value_rangelistptr> _m_ranges;
+    subr::value_set<dwarf_output::value::value_lineptr> _m_line_info;
+    subr::value_set<dwarf_output::value::value_constant> _m_constants;
+    subr::value_set<dwarf_output::value::value_constant_block> _m_const_block;
+    subr::value_set<dwarf_output::value::value_dwarf_constant> _m_dwarf_const;
+    subr::value_set<dwarf_output::value::value_source_file> _m_source_file;
+    subr::value_set<dwarf_output::value::value_source_line> _m_source_line;
+    subr::value_set<dwarf_output::value::value_source_column> _m_source_column;
+    subr::value_set<dwarf_output::value::value_location> _m_locations;
+
+    // The set of Boolean flags is a doubleton.
+    static const dwarf_output::value::value_flag flag_true;
+    static const dwarf_output::value::value_flag flag_false;
+    static inline const dwarf_output::value::value_flag *flag (bool flag)
+    {
+      return flag ? &flag_true : &flag_false;
+    }
+
+    // Set of attribute maps.
+    typedef std::pair<attrs_type, int> attrs_pair;
+    subr::dynamic_equality_set<attrs_pair> _m_attr_sets;
+
+    template<typename match_type>
+    inline const attrs_pair *
+    add_attributes (int tag, const attrs_type &candidate, match_type &matcher)
+    {
+      return _m_attr_sets.add (std::make_pair (candidate, tag), matcher);
+    }
+
+    // Set of children lists.
+    subr::identity_set<children_type> _m_broods;
+
+    inline const children_type *
+    add_children (const children_type &candidate, bool &fresh)
+    {
+      std::pair<subr::identity_set<children_type>::iterator, bool> p
+       = _m_broods.insert (candidate);
+      const children_type &result = *p.first;
+      fresh = p.second;
+      return &result;
+    }
+
+    // Set of unique DIEs.
+    typedef subr::identity_map<die_type, die_info> die_map;
+    die_map _m_unique;
+
+    inline die_info_pair *add_entry (int tag,
+                                    const children_type *children,
+                                    const attrs_type *attrs,
+                                    die_info *info)
+    {
+      std::pair <die_map::iterator, bool>
+       ins = _m_unique.insert (std::make_pair (die_type (tag, children, attrs),
+                                               *info));
+      die_info_pair &x = *ins.first;
+      if (ins.second)
+       x.second.assert_unused ();
+
+      return &x;
+    }
+
+    struct stats_cmp
+      : public std::binary_function<const die_map::value_type *,
+                                   const die_map::value_type *,
+                                   void>
+    {
+      inline bool operator () (const die_map::value_type *a,
+                              const die_map::value_type *b) const
+      {
+       // Sort by number of input entries collected into this one entry.
+       if (a->second.count_originals () != b->second.count_originals ())
+         return a->second.count_originals () > b->second.count_originals ();
+
+       // Secondarily sort by aggregate input cost.
+       if (a->second.original_cost () != b->second.original_cost ())
+         return a->second.original_cost () > b->second.original_cost ();
+
+       // Finally, sort by input file order.
+       return a->second.original_offset () > b->second.original_offset ();
+      }
+    };
+
+    typedef std::multiset<const die_map::value_type *, stats_cmp
+                         > die_stats_order;
+
+    struct die_stats_sorter
+      : public std::unary_function<die_map::value_type, void>
+    {
+      die_stats_order &_m_order;
+      inline explicit die_stats_sorter (die_stats_order &o) : _m_order (o) {}
+
+      inline void operator () (const die_map::value_type &elt)
+      {
+       _m_order.insert (&elt);
+      }
+    };
+
+    static void die_stats (std::ostream &out, const die_map::value_type *elt)
+    {
+      const die_info *info = &elt->second;
+      out << std::dec << info->uses ()
+         << "\thash=" << std::hex << subr::hash_this (elt->first)
+         << "\t(" << info->_m_with_sibling.to_string () << ") "
+         << std::dec << info->original_cost ()
+         << " (" << (info->original_cost () - info->output_cost ())
+         << ")\t" << to_string (elt->first) << "\t";
+      info->list_originals (out)
+       << "\n";
+    }
+
+    struct attr_collision
+    {
+      std::ostream &_m_out;
+      inline explicit attr_collision (std::ostream &out) : _m_out (out) {}
+
+      inline void
+      operator () (size_t hash,
+                  const subr::dynamic_equality_set<attrs_pair>::bucket_type &b)
+       const
+      {
+       _m_out << "attrs bucket " << std::hex << hash
+              << std::dec << ": " << b.size () << " collisions\n";
+       subr::for_each (b, *this);
+      }
+
+      inline void operator () (const attrs_pair &attrs) const
+      {
+       _m_out << "\t" << dwarf::tags::name (attrs.second)
+              << " " << attrs.first.size ();
+       subr::for_each (attrs.first, *this);
+       _m_out << "\n";
+      }
+
+      inline void operator () (const attrs_type::value_type &attr) const
+      {
+       _m_out << " " << dwarf::attributes::name (attr.first);
+      }
+    };
+
+    const bool _m_ignore_context;
+
+    inline dwarf_output_collector (const dwarf_output_collector &)
+      : _m_ignore_context (false)
+    {
+      throw std::logic_error ("cannot copy-construct");
+    }
+
+  public:
+    inline dwarf_output_collector (bool ignore = true) // XXX
+      : _m_total (0), _m_incoming (0), _m_ignore_context (ignore)
+    {}
+
+    inline bool ignore_context () const
+    {
+      return _m_ignore_context;
+    }
+
+    void stats (std::ostream &out = std::cout) const
+    {
+      out << "collected " << std::dec << _m_unique.size ()
+         << " unique of " << _m_total << " total from "
+         << _m_incoming << " DIEs\n";
+
+      subr::container_hash_stats (out, "strings", _m_strings);
+      subr::container_hash_stats (out, "identifiers", _m_identifiers);
+      subr::container_hash_stats (out, "address", _m_address);
+      subr::container_hash_stats (out, "ranges", _m_ranges);
+      subr::container_hash_stats (out, "line_info", _m_line_info);
+      subr::container_hash_stats (out, "constants", _m_constants);
+      subr::container_hash_stats (out, "const_block", _m_const_block);
+      subr::container_hash_stats (out, "dwarf_const", _m_dwarf_const);
+      subr::container_hash_stats (out, "source_file", _m_source_file);
+      subr::container_hash_stats (out, "source_line", _m_source_line);
+      subr::container_hash_stats (out, "source_column", _m_source_column);
+      subr::container_hash_stats (out, "locations", _m_locations);
+
+      subr::container_hash_stats (out, "broods", _m_broods);
+      _m_attr_sets.hash_stats (out, "attr_sets", attr_collision (out));
+
+      die_stats_order ordered;
+      subr::for_each (_m_unique, die_stats_sorter (ordered));
+      subr::for_each (ordered, std::bind1st (std::ptr_fun (die_stats), out));
+    }
+  };
+
+  template<typename dw>
+  class dwarf_output::copier
+  {
+    friend class dwarf_output;
+  private:
+    typedef typename dw::debug_info_entry input_die;
+    typedef typename input_die::children_type::const_iterator input_die_ptr;
+
+    dwarf_output_collector *_m_collector;
+
+    /* A copier::entry represents one dw::debug_info_entry from the input,
+       indexed by identity.  With real input files (dw=dwarf), that means
+       one input entry for each unique DIE offset in each file.  (We also
+       record its offset in the input file, just for use in debugging and
+       statistics output.)  An entry is in one of four states:
+
+       undefined: we have seen references in attributes, but have not yet
+       seen the entry itself in the copying walk of the input DIE tree;
+
+       pending: the entry is in the midst of being copied, or it has
+       references to non-final entries;
+
+       final: the entry is finished and stored in the collector, but
+       is not yet pointed to by any real children_type vector;
+
+       placed: the entry is final and at least one logical parent's
+       children_type vector is also finished and stored in the collector,
+       permitting final bookkeeping and reference iterator updates.
+
+       Whenever there are no undefined entries outstanding, it should by
+       definition be possible to turn every pending entry into a final
+       entry.  To avoid complex bookkeeping, we simply keep track of the
+       total count of undefined entries.  When we first encounter an entry
+       or a reference to it before we've copied, we increment that count.
+       Upon completing the copying of an entry, we decrement it.  If that
+       makes the count reach zero, we immediately "finalize" the entry,
+       which is recursive on all its references and children not yet final.
+
+    */
+
+    struct entry;              // Below.
+    struct entry_copier;       // Below.
+    struct entry_finalizer;    // Below.
+
+    /* An attr_value cell points to one of these when it's a reference to
+       an entry not already in the collector at finalization time, i.e. a
+       circular reference.  To compare circular references during attribute
+       finalization, we follow the pending () pointer; see dwarf_pending,
+       below.  Thereafter, the base type's ref element is initialized and
+       we can use that directly.  */
+    class circular_reference
+      : public value::value_reference
+    {
+    private:
+      const std::vector<entry *> *_m_entry;
+      bool _m_final;
+
+      inline circular_reference (const circular_reference &)
+       : value::value_reference ()
+      {
+       throw std::logic_error ("cannot copy-construct");
+      }
+
+    public:
+      inline circular_reference (const entry *die, copier *)
+       : value::value_reference (),
+         _m_entry (new std::vector<entry *> (1, const_cast<entry *> (die))),
+         _m_final (false)
+      {
+       die->dump () << " new circular_reference " << this << "\n";
+      }
+
+      inline bool final () const
+      {
+       // XXX was return _m_entry == NULL;
+       return _m_final;
+      }
+
+      inline typename std::vector<entry *>::const_iterator pending () const
+      {
+       return _m_entry->begin ();
+      }
+
+      inline entry *pending_entry () const
+      {
+       return *pending ();
+      }
+
+      // We've been stored in the collector, so we are no longer pending.
+      inline void placed ()
+      {
+       pending_entry ()->dump () << " placed circular_reference "
+                                 << this << "\n";
+       // XXX Keeping around for local hash...
+       _m_final = true;
+       // delete _m_entry;
+       // _m_entry = NULL;
+      }
+
+      inline ~circular_reference ()
+      {
+       if (unlikely (_m_entry != NULL))
+         {
+           pending_entry ()->dump () << " destroy circular_reference "
+                                     << this << "\n";
+           delete _m_entry;
+         }
+      }
+
+      /* We have a special case for a reference attribute that is part
+        of a circular chain.  It gets calculated from the
+        pending_entry. */
+      virtual die_info *get_die_info () const
+      {
+       return pending_entry ()->get_die_info ();
+      }
+    };
+
+    struct pending_entry
+    {
+      /* Pointers to each entry that appears in _m_attributes.
+        When a referent is already final, the entry * does not
+        appear in the attr_value and does not count here.  */
+      std::stack<const value::value_dispatch **> _m_pending_refs;
+
+      // Set if we are attempting to finalize this entry right now.
+      entry_finalizer *_m_finalizing;
+
+      // Reference to ourself, pre-built in a circularity.
+      circular_reference *_m_self;
+
+      /* Cache of the final entry we already know we will become.
+        We'll set this when the walk of a reference comparison hits
+        this entry while finalizing another entry and records that it
+        is identical to an existing final entry.  When the main walk
+        doing finalization hits us, we can short-circuit matching our
+        redundant entry in the collector sets.  */
+      die_info_pair *_m_matched;
+
+      std::set<uintptr_t> _m_mismatched;
+
+      typedef dwarf_data::attributes_type<dwarf_output, value> attr_map;
+      attr_map _m_attributes;
+      std::vector<entry *> _m_children;
+      const int _m_tag;
+
+      // Set if _m_children contains any entries not already final.
+      bool _m_unfinished_children;
+
+      // The die_info that will be used when putting the die into
+      // the collector. Stores local hash as soon as all children
+      // are defined in defined_self ().
+      die_info *_m_info;
+
+      inline pending_entry (int tag)
+       : _m_finalizing (NULL), _m_self (NULL), _m_matched (NULL),
+         _m_tag (tag), _m_unfinished_children (false), _m_info (NULL)
+      {}
+
+      inline ~pending_entry ()
+      {
+       if (unlikely (_m_self != NULL))
+         {
+           if (_m_self->final ())
+             entry::debug () << "XXX ~pending_entry _m_self is final\n";
+           else
+             _m_self->pending_entry ()->dump () << " ~pending_entry _m_self\n";
+           delete _m_self;
+         }
+      }
+
+      inline typename std::vector<entry *>::const_iterator
+      child (typename std::vector<entry *>::size_type i) const
+      {
+       return _m_children.begin () + i;
+      }
+
+      /* Finalize each pending entry that we refer to.
+        This is called only when we have a non-empty _m_pending_refs.  */
+      inline void finalize_refs (copier *c)
+      {
+       do
+         {
+           const value::value_dispatch **const attr = _m_pending_refs.top ();
+           const entry *ref = dynamic_cast<const entry *> (*attr);
+           if (ref != NULL)
+             *attr = const_cast<entry *> (ref)->finalize_ref (c);
+           _m_pending_refs.pop ();
+         }
+       while (!_m_pending_refs.empty ());
+      }
+
+      // Finalize each unfinished child.
+      inline void finalize_children (copier *c)
+      {
+       _m_unfinished_children = false;
+       subr::for_each
+         (_m_children,
+          std::bind2nd (std::mem_fun (&entry::get_finalized),
+                        std::make_pair (c, &_m_unfinished_children)));
+      }
+
+      /* This is called from finalize_ref (below) when we are
+        resolving a circular reference attribute.  We cache the
+        uninitialized reference in _m_self, and return it.  */
+      inline value::value_reference *
+      make_circular_reference (const entry *self, copier *c)
+      {
+       if (_m_self == NULL)
+         _m_self = new circular_reference (self, c);
+       return _m_self;
+      }
+
+      typedef std::pair <debug_info_entry::attributes_type, int> attrs_pair;
+      struct attrs_matcher
+      {
+       copier *_m_copier;
+       inline explicit attrs_matcher (copier *c) : _m_copier (c) {}
+
+       inline bool operator () (const attrs_pair &a, const attrs_pair &b)
+       {
+         return (a.second == b.second
+                 && _m_copier->attrs_match (a.first, b.first));
+       }
+      };
+
+      /* We can only get here when all our children have been finalized.
+        So all we have to do is fetch that pointer.  */
+      static inline die_info_pair *get_final_child (entry *child)
+      {
+       assert (child->_m_final != NULL);
+       return child->_m_final;
+      }
+
+      typedef typename subr::wrapped_input_iterator<
+       std::vector<entry *>,
+       std::pointer_to_unary_function<entry *, die_info_pair *>
+       > final_children_getter;
+      typedef typename final_children_getter::
+      template copy<debug_info_entry::children_type> get_final_children;
+
+      inline size_t get_reference_hash (std::vector<const entry *> &stack) const
+      {
+       assert (_m_info != NULL);
+
+       // Could already have been set by forward reference.
+       if (_m_info->_m_reference_hash != 0)
+         return _m_info->_m_reference_hash;
+
+       size_t rhash = _m_info->_m_local_hash;
+       size_t attr_rhashes = 0;
+       for (attr_map::const_iterator it = _m_attributes.begin ();
+             it != _m_attributes.end ();
+             ++it)
+          {
+           // XXX XOR is for order irrelevance, but shouldn't be necessary.
+           // See also calculate_local_hash, which does the same.
+           const entry *ref
+             = dynamic_cast<const entry *> (it->second._m_value);
+           if (ref != NULL)
+             {
+               // Workaround weird cases of self-referential DIE.
+               // This really is a bug in the producer and dwarflint
+               // should warn about it. But it is easy to work around
+               // so just do it for now, by ignoring such values.
+               if (ref->_m_pending == this)
+                 continue;
+               else
+                 attr_rhashes ^= ref->get_reference_hash (stack);
+             }
+          }
+       subr::hash_combine (rhash, attr_rhashes);
+
+       return rhash;
+      }
+
+      inline size_t calculate_local_hash ()
+      {
+       // Calculate the local hash for this new die.
+       // XOR the attribute values together (so order doesn't matter)
+       // but exclude reference attributes values (just include
+       // their tag). XXX - shouldn't be necessary, double check.
+       size_t lhash = _m_tag;
+       size_t attr_hash = 0;
+       for (attr_map::const_iterator it = _m_attributes.begin ();
+            it != _m_attributes.end ();
+            ++it)
+         {
+           if (it->second.what_space () != dwarf::VS_reference)
+             attr_hash ^= subr::hash_this (*it);
+           else
+             attr_hash ^= (it->first << 3);
+         }
+       subr::hash_combine (lhash, attr_hash);
+
+       size_t children_hash = 0;
+       for (typename std::vector<entry *>::const_iterator it
+              = _m_children.begin ();
+            it != _m_children.end ();
+            ++it)
+         {
+           // child lhash is always in the die_info, which might
+           // be in the pending_entry when not yet finalized, or
+           // part of the finalized child die_info.
+           size_t child_lhash;
+           struct pending_entry *pending = (*it)->_m_pending;
+           if (pending)
+             child_lhash = pending->_m_info->_m_local_hash;
+           else
+             {
+               die_info_pair *final_child = get_final_child (*it);
+               child_lhash = final_child->second._m_local_hash;
+             }
+           subr::hash_combine (children_hash, child_lhash);
+         }
+       subr::hash_combine (lhash, children_hash);
+
+       return lhash;
+      }
+
+      inline die_info_pair *final (copier *c,
+                                  ::Dwarf_Off offset, ::Dwarf_Off cost)
+      {
+       dwarf_output_collector *const co = c->_m_collector;
+
+       assert (_m_pending_refs.empty ());
+
+       bool fresh = false;
+       if (_m_matched == NULL)
+         {
+           attrs_matcher equalator (c);
+           const debug_info_entry::attributes_type *attrs
+             = &co->add_attributes (_m_tag, _m_attributes, equalator)->first;
+
+           const debug_info_entry::children_type *children
+             = co->add_children (get_final_children ()
+                                 (_m_children, std::ptr_fun (get_final_child)),
+                                 fresh);
+
+           _m_matched = co->add_entry (_m_tag, children, attrs, _m_info);
+         }
+
+       // Final bookkeeping in the collector for this copied entry.
+       _m_matched->second.original (co->_m_incoming, offset, cost);
+
+       /* Now our entry is finalized in the collector (either newly
+          created there, or discovered to be a duplicate already
+          there).  If this was part of a circularity, it created the
+          _m_self object and stored pointers to it in the collector
+          attributes maps.  Now move that object into the final
+          entry's _m_refs list.  From there it will get initialized.  */
+       if (_m_self != NULL)
+         {
+           assert (!_m_self->final ());
+           _m_self->pending_entry ()->dump ()
+             << " register circular_reference " << _m_self << " "
+             << _m_matched->first.to_string () << " from";
+           _m_matched->second.dump_originals (entry::debug ()) << "\n";
+           _m_matched->second.self (_m_self);
+           _m_self = NULL;
+         }
+
+       /* Now we have a children_type in the collector.  Fix up all
+          the backpointers to point into that _m_broods copy.  Also
+          make sure each child gets its _m_parent pointer.  Even if
+          this candidate children_type didn't actually get inserted
+          into the set (was not unique), we may need to reify new refs
+          to these children.  */
+       _m_matched->first._m_children->reify_children<circular_reference>
+         (_m_matched, fresh, co->_m_total);
+
+       return _m_matched;
+      }
+
+      inline void notice_mismatch (const die_info_pair *not_me)
+      {
+       _m_mismatched.insert ((uintptr_t) not_me);
+      }
+
+      inline bool cached_mismatch (const die_info_pair *not_me)
+      {
+       return _m_mismatched.find ((uintptr_t) not_me) != _m_mismatched.end ();
+      }
+
+      static inline void dump_pending_ref (const value::value_dispatch **attr)
+      {
+       const entry *ref = dynamic_cast<const entry *> (*attr);
+       if (ref != NULL)
+         ref->debug () << " " << std::hex << ref->_m_offset << std::dec;
+       else
+         {
+           const circular_reference *circular
+             = dynamic_cast<const circular_reference *> (*attr);
+           if (circular != NULL && !circular->final ())
+             {
+               ref = circular->pending_entry ();
+               ref->debug () << " *" << std::hex << ref->_m_offset << std::dec;
+             }
+         }
+      }
+
+      inline void dump_tree (const entry *self) const
+      {
+       self->dump (true) << " " << dwarf::tags::name (_m_tag) << " "
+                         << _m_children.size () << " children, "
+                         << _m_pending_refs.size () << " refs";
+       //subr::for_each (_m_pending_refs, dump_pending_ref); XXX
+       self->debug () << "\n";
+       subr::for_each (_m_children, std::mem_fun (&entry::dump_entry));
+       self->dump (false, true) << " ends\n";
+      }
+    };
+
+    // This keeps state in the pending_entry's _m_finalizing pointer while live.
+    struct entry_finalizer
+    {
+      entry *const _m_entry;
+
+      inline entry_finalizer (entry *die)
+       : _m_entry (die)
+      {
+       _m_entry->debug () << std::flush;
+       assert (_m_entry->_m_pending->_m_finalizing == NULL);
+       _m_entry->_m_pending->_m_finalizing = this;
+       _m_entry->dump (true) << " finalizing\n";
+      }
+
+      inline ~entry_finalizer ()
+      {
+       if (unlikely (_m_entry->_m_pending != NULL))
+         {
+           assert (_m_entry->_m_pending->_m_finalizing == this);
+           _m_entry->_m_pending->_m_finalizing = NULL;
+           _m_entry->dump (false, true) << " failed to finalize!\n";
+         }
+       else
+         {
+           _m_entry->dump (false, true) << " finalized\n";
+           assert (_m_entry->_m_final != NULL);
+           _m_entry->dump_entry ();
+         }
+      }
+    };
+
+    /* This is what we record about each input DIE we have considered.
+       An attr_value that is a dangling reference to a DIE not yet
+       built in the output has one of these in place of a value_reference.
+       These all live in the _m_entries map, one per input-side DIE.  */
+    struct entry
+      : public value::value_reference
+    {
+      ::Dwarf_Off _m_offset; // For debugging and statistics only.
+      ::Dwarf_Off _m_cost;   // For statistics only.
+
+      // Completed DIE in the collector, or NULL.
+      die_info_pair *_m_final;
+
+      // Pending entry made with new, or NULL.
+      pending_entry *_m_pending;
+
+      // Set if we are building this in the copying walk right now.
+      entry_copier *_m_building;
+
+      // Set if we are in attrs_match on this entry right now.
+      die_info_pair *_m_comparing;
+
+      /* When we're final but not placed, we allocate a singleton vector
+        here and set a value_reference to an iterator in that vector.
+        That will be replaced with the iterator into a proper children
+        vector when we're placed.  */
+      debug_info_entry::children_type::_base *_m_final_ref;
+
+      // First parent, for tracker purposes.
+      entry *_m_parent;
+      typename std::vector<entry *>::size_type _m_self_idx;
+
+      inline entry ()
+       : _m_offset (0), _m_final (NULL), _m_pending (NULL),
+         _m_building (NULL), _m_comparing (NULL),
+         _m_final_ref (NULL), _m_parent (NULL), _m_self_idx (0)
+      {}
+
+      inline void setup (copier *c, const input_die &in)
+      {
+       if (_m_offset == 0)
+         {
+           _m_offset = in.offset ();
+           ++c->_m_undefined_entries;
+           dump () << " seen => " << c->_m_undefined_entries << "\n";
+         }
+      }
+
+      inline ~entry ()
+      {
+       assert (_m_building == NULL);
+       if (_m_final_ref != NULL)
+         delete _m_final_ref;
+
+       // This should only hit in an exception case abandoning the copier.
+       if (unlikely (_m_pending != NULL))
+         delete _m_pending;
+      }
+
+      /* If we need a reference before we're placed, fake one up with
+        a singleton vector pointing to us, stored in _m_final_ref.  */
+      inline value::value_reference *self ()
+      {
+       if (_m_final->second.selfless ())
+         {
+           assert (_m_final_ref == NULL);
+           _m_final_ref
+             = new debug_info_entry::children_type::_base (1, _m_final);
+           _m_final->second.self (_m_final_ref->begin ());
+         }
+       return _m_final->second.self ();
+      };
+
+      /* Called by entry_copier::add_reference, below.
+        We're adding a reference attribute pointing to this input entry.  */
+      inline void refer (entry *referrer, const value::value_dispatch **backptr)
+      {
+       referrer->dump () << " refers to "
+                         << std::hex << _m_offset << std::dec
+                         << " (" << (_m_final ? "final"
+                                     : _m_pending ? "pending" : "undefined")
+                         << (_m_building ? ", building" : "") << ")\n";
+
+       if (_m_final != NULL)
+         // It's finished, resolve the final reference.
+         *backptr = self ();
+       else
+         {
+           *backptr = this;
+           referrer->_m_pending->_m_pending_refs.push (backptr);
+         }
+      }
+
+      /* We are no longer an undefined entry, so decrement the count.
+        But don't finalize yet. Since all children are known now we
+        can create a candidate die_info that includes the local hash
+        for this entry.  */
+      inline void defined_self (copier *c)
+      {
+       assert (_m_final == NULL);
+       assert (_m_pending != NULL);
+       assert (c->_m_undefined_entries > 0);
+       --c->_m_undefined_entries;
+       dump () << " defined_self => " << c->_m_undefined_entries << "\n";
+
+       size_t lhash = _m_pending->calculate_local_hash ();
+       _m_pending->_m_info = new die_info (lhash);
+      }
+
+      /* A reference-following matching operation noticed along
+        the way that we have a doppleganger in the collector.  */
+      inline void record_prematch (die_info_pair *doppleganger,
+                                  bool lhs)
+      {
+       doppleganger->second.dump_originals
+         (dump ()
+          << " record_prematch to " << doppleganger->first.to_string ()
+          << " from")
+         << (lhs ? " on lhs\n" : " on rhs\n");
+       /* XXX disabled! tentative circularity matches taint this record!
+          must record taint to avoid caching, or punt caching.
+        */
+       //_m_pending->_m_matched = doppleganger;
+      }
+
+      /* This is called by finalize_children.  In case of imported_unit
+        use in the input, we could already have finalized this earlier
+        in the copying walk of the logical CU, so there is nothing to
+        do.  Or, inside a circularity in finalize_refs, we might be
+        finalizing this child already in an outer recursion.  In that
+        case, we can't finish it here.  */
+      inline void get_finalized (const std::pair<copier *, bool *> p)
+      {
+       if (_m_final == NULL && _m_pending->_m_finalizing == NULL)
+         finalize (p.first);
+       if (_m_final == NULL)
+         *p.second = true;
+      }
+
+      /* Recursively sets up reference hashes for the die_info of this
+        pending_entry.  Depends on all local hashes having been setup
+        already.  At this point all entries are still pending.  */
+      inline void setup_reference_hash () const
+      {
+       std::vector<const entry *> stack;
+       _m_pending->_m_info->_m_reference_hash = get_reference_hash (stack);
+       assert (stack.empty ());
+
+        for (typename std::vector<entry *>::const_iterator it
+               = _m_pending->_m_children.begin ();
+             it != _m_pending->_m_children.end ();
+             ++it)
+         (*it)->setup_reference_hash ();
+      }
+
+      inline size_t get_reference_hash (std::vector<const entry *> &stack) const
+      {
+       if (std::find (stack.begin (), stack.end (), this) != stack.end ())
+         {
+           std::cout << "Reference chain cycle detected\n"
+                     << "offset=[0x" << std::hex << _m_offset << std::dec
+                     << "] already on the reference chain stack\n";
+           typename std::vector<const entry *>::iterator it;
+           for (it = stack.begin ();
+                it != stack.end ();
+                it++)
+             {
+               std::cout << "offset=[0x" << std::hex << (*it)->_m_offset
+                         << std::dec << "] "
+                         << dwarf::tags::name ((*it)->_m_pending->_m_tag)
+                         << "\n";
+             }
+           abort ();
+         }
+
+       stack.push_back (this);
+       size_t res = _m_pending->get_reference_hash (stack);
+       stack.pop_back ();
+       return res;
+      }
+
+      // Attempt to turn the pending entry into a final entry.
+      void finalize (copier *c)
+      {
+       entry_finalizer finalizing (this);
+
+       if (c->_m_undefined_entries == 0)
+         {
+           // Nothing is undefined, so we can resolve pending references.
+           if (!_m_pending->_m_pending_refs.empty ())
+             {
+               dump (true) << " finalize_refs\n";
+               _m_pending->finalize_refs (c);
+               dump (false, true) << " finalize_refs done\n";
+             }
+
+           // Now we can finish off all our children.
+           if (_m_pending->_m_unfinished_children)
+             {
+               dump (true) << " finalize_children\n";
+               _m_pending->finalize_children (c);
+               dump (false, true) << " finalize_children done\n";
+             }
+         }
+
+       /* If there were no pending references or children to finish, or
+          if we just finished them all off, we can finally finalize!  */
+       if (_m_pending->_m_pending_refs.empty ()
+           && !_m_pending->_m_unfinished_children)
+         {
+           // Create it in the collector.
+           _m_final = _m_pending->final (c, _m_offset, _m_cost);
+
+           // No more pending_entry required!
+           delete _m_pending;
+           _m_pending = NULL;
+         }
+      }
+
+      // Called by a referrer trying to finalize us.
+      inline const value_dispatch *finalize_ref (copier *c)
+      {
+       assert (c->_m_undefined_entries == 0);
+       if (_m_final == NULL)
+         {
+           if (_m_pending->_m_finalizing == NULL)
+             finalize (c);
+           if (_m_final == NULL)
+             {
+               dump () << " finalize_ref caught circularity\n" << std::flush;
+
+               /* We are recursing inside a finalize call.
+                  This means we have a circular reference.  */
+               return _m_pending->make_circular_reference (this, c);
+             }
+         }
+       return self ();
+      }
+
+// Toggle this to enable massive debugging spew during construction.
+// #define _DWARF_OUTPUT_DEBUG_SPEW 1
+#ifdef _DWARF_OUTPUT_DEBUG_SPEW
+      static inline std::ostream &debug ()
+      {
+       return std::cout;
+      }
+
+      static inline std::ostream &
+      debug_prefix (bool in = false, bool out = false, bool print = true)
+      {
+       static std::string prefix;
+       if (out)
+         prefix.erase (--prefix.end ());
+       if (print)
+         debug () << prefix;
+       if (in)
+         prefix.push_back (' ');
+       return debug ();
+      }
+
+      std::ostream &dump (bool in = false, bool out = false) const
+      {
+       debug_prefix (in, out) << "XXX " << std::hex << _m_offset << std::dec;
+       if (_m_pending != NULL && _m_pending->_m_finalizing != NULL)
+         debug () << " (finalizing "
+                  << (void *) _m_pending->_m_finalizing << ")";
+       return debug ();
+      }
+
+      void dump_entry () const
+      {
+       if (_m_final != NULL)
+         {
+           dump () << " final " << _m_final->first.to_string ()
+                   << " hash=" << std::hex << subr::hash_this (_m_final->first)
+                   << " from";
+           _m_final->second.dump_originals (debug ()) << "\n";
+         }
+       else if (_m_pending != NULL)
+         _m_pending->dump_tree (this);
+       else
+         dump () << " undefined\n";
+      }
+#else
+      static inline subr::nostream &debug ()
+      {
+       static subr::nostream n;
+       return n;
+      }
+
+      static inline subr::nostream &
+      debug_prefix (bool = false, bool = false, bool = true)
+      {
+       return debug ();
+      }
+
+      inline subr::nostream &dump (bool = false, bool = false) const
+      {
+       return debug ();
+      }
+
+      inline void dump_entry () const
+      {}
+#endif
+
+      // Find ourselves in a parent pending_entry's children vector.
+      inline typename std::vector<entry *>::const_iterator pending_self () const
+      {
+       debug () << std::flush;
+       assert (_m_pending != NULL);
+       return _m_parent->_m_pending->child (_m_self_idx);
+      }
+
+      /* The local hash of the debug_info_entry if we are already
+        final, otherwise get it from the pending_entry. */
+      inline die_info *get_die_info () const
+      {
+       if (_m_final)
+         return &_m_final->second;
+       return _m_pending->_m_info;
+      }
+    };
+
+    // This object lives while we are copying one particular input DIE.
+    struct entry_copier
+    {
+      copier *_m_copier;
+      entry *_m_in;
+      pending_entry *_m_out;
+
+      /* On creation we set _m_building in DIE's record.
+        It should never be set already.  */
+      inline entry_copier (copier *c, entry *die, const input_die &in)
+       : _m_copier (c),
+         _m_in (die),
+         _m_out (new pending_entry (in.tag ()))
+      {
+       if (unlikely (_m_in->_m_building != NULL))
+         throw std::runtime_error ("detected cycle in logical DWARF tree");
+       _m_in->_m_building = this;
+       _m_in->_m_cost = in.cost ();
+       _m_in->dump (true) << " copying (cost=" << _m_in->_m_cost << ")\n";
+      }
+
+      // On destruction, we clear _m_building.
+      inline ~entry_copier ()
+      {
+       _m_in->dump (false, true) << " copied\n";
+       assert (_m_in->_m_building == this);
+       _m_in->_m_building = NULL;
+       if (unlikely (_m_out != NULL)) // Exception unwind case only.
+         delete _m_out;
+      }
+
+      /* Populate _m_out from the corresponding input DIE.  This invokes
+        all the main work of copying.  The interesting parts happen in
+        add_reference and add_child, below.  */
+      inline void populate (const input_die &in)
+      {
+       assert (_m_in->_m_pending == NULL);
+       _m_in->_m_pending = _m_out;
+
+       try
+         {
+           // This calls add_reference for each pending reference.
+           _m_out->_m_attributes.set (in.attributes (), *this);
+
+           for (input_die_ptr i = in.children ().begin ();
+                i != in.children ().end ();
+                ++i)
+             add_child (*i);
+         }
+       catch (...)
+         {
+           _m_in->_m_pending = NULL;
+           throw;
+         }
+
+       _m_out = NULL;
+       _m_in->defined_self (_m_copier);
+      }
+
+      // We're adding a reference attribute inside populate, above.
+      inline void add_reference (const input_die_ptr &to,
+                                const value::value_dispatch **backptr)
+      {
+       _m_copier->enter (*to)->refer (_m_in, backptr);
+      }
+
+      // We're adding a child entry inside populate, above.
+      inline void add_child (const input_die &in)
+      {
+       entry *child = _m_copier->enter (in);
+       _m_out->_m_children.push_back (child);
+
+       /* If the input used DW_TAG_imported_unit, then the logical walk
+          can hit the same DIE twice.  If so, we short-circuit right here.  */
+       if (child->_m_final == NULL && child->_m_pending == NULL)
+         {
+           child->_m_parent = _m_in;
+           child->_m_self_idx = _m_out->_m_children.size () - 1;
+           entry_copier (_m_copier, child, in).populate (in);
+         }
+
+       if (child->_m_final == NULL)
+         // Record that it didn't finalize immediately, we'll do it later.
+         _m_out->_m_unfinished_children = true;
+      }
+
+      // Use "c ()" as a shorthand to get the copier out of the entry_copier.
+      inline copier &operator () () const
+      {
+       return *_m_copier;
+      }
+
+      /* Walk over the whole cu again to set reference hashes up.
+        Then try to finalize everything at once.
+        Complain if we still have dangling references.
+        If not, it should be impossible to have pending entries left.  */
+      inline die_info_pair *final_unit () const
+      {
+       assert (_m_out == NULL);
+
+       // First walk over the whole CU tree again to setup the
+       // reference hash for each die_info.
+       _m_in->setup_reference_hash ();
+
+       // We should now be able to finalize everything at once.
+       if (_m_copier->_m_undefined_entries == 0)
+         _m_in->finalize (_m_copier);
+
+       if (unlikely (_m_in->_m_final == NULL))
+         {
+           _m_in->dump_entry ();
+           _m_in->debug () << std::flush;
+           assert (_m_copier->_m_undefined_entries > 0);
+           throw std::runtime_error
+             ("compile_unit contains dangling reference attributes");
+         }
+       assert (_m_copier->_m_undefined_entries == 0);
+       return _m_in->_m_final;
+      }
+    };
+
+    struct unit_copier : public entry_copier
+    {
+      inline unit_copier (copier *c, const typename dw::compile_unit &in)
+       : entry_copier (c, c->enter (in), in)
+      {
+       populate (in);
+      }
+    };
+
+    struct dump_unplaced
+      : public std::unary_function<circular_reference *, void>
+    {
+      inline void operator () (circular_reference *ref)
+      {
+       std::cout << "XXX unplaced ref to "
+                 << std::hex << (ref->pending_entry ())->_m_offset
+                 << std::dec << "\n";
+      }
+    };
+
+    // Create a whole CU in the output.
+    inline void
+    make_unit (const typename dw::compile_units_type::const_iterator &in,
+              const compile_units_type::iterator &out)
+    {
+      die_info_pair *cu = unit_copier (this, *in).final_unit ();
+
+      // This really just increments _m_total for us, but also _m_uses.
+      cu->second.placed<circular_reference> (NULL,
+                                            cu->first.children ().end (),
+                                            false, _m_collector->_m_total);
+
+      *out = cu->first;
+    }
+
+    typedef std::tr1::unordered_map< ::Dwarf_Off, entry> entry_map;
+    entry_map _m_entries;
+    unsigned int _m_undefined_entries; // Count of _m_entries not copied yet.
+
+    inline entry *enter (const input_die &in)
+    {
+      entry *die = &_m_entries[in.identity ()];
+      die->setup (this, in);
+      return die;
+    }
+
+    /* This is an entire shadow of the dwarf:: interface, sufficient to
+       instantiate dwarf_comparator below.  All its objects are
+       ephemeral and simply wrap a pending_entry and its constituents.
+       We always start with finalized attributes, but those can include
+       circular_reference objects pointing to pending entries that can't
+       be finalized until the finalization that this comparison is part
+       of has been done.  Hence these objects have to bifurcate between
+       wrapping pending_entry and wrapping die_info_pair.  */
+    class pending_dwarf
+    {
+    public:
+      class debug_info_entry;
+      class attr_value;
+      typedef std::pair<const int, attr_value> attribute;
+
+      typedef debug_info_entry compile_unit;
+
+    private:
+
+      // Both debug_info_entry and iterators just hold this pair of pointers.
+      struct entry_pointers
+      {
+       entry *pending;
+       die_info_pair *final;
+
+       inline entry_pointers (entry *a, die_info_pair *b)
+         : pending (a), final (b)
+       {}
+      };
+
+      struct pending_cu
+       : public std::unary_function<dwarf_output::compile_unit, compile_unit>
+      {
+       inline const compile_unit
+       operator () (const dwarf_output::compile_unit &) const
+       {
+         throw std::logic_error ("XXX implement me");
+       }
+      };
+
+    public:
+      // Not really used so far, just for completeness.
+      typedef subr::wrapped_input_container<class dwarf_output::compile_units_type,
+                                           pending_cu> compile_units_type;
+
+      class debug_info_entry
+      {
+      private:
+       entry_pointers _m_ptr;
+
+       static inline const debug_info_entry
+       child (const entry_pointers &ptr, size_t i)
+       {
+         if (ptr.final == NULL)
+           return debug_info_entry (ptr.pending->_m_pending->_m_children[i]);
+         return debug_info_entry (ptr.final->first.children ().info ()[i]);
+       }
+
+       // Turns an attribute into an attribute!
+       struct pending_attr
+         : public std::unary_function<dwarf_output::attribute, attribute>
+       {
+         inline pending_attr (const subr::nothing &) {}
+
+         inline const attribute
+         operator () (const dwarf_output::attribute &attr) const
+         {
+           return attribute (attr.first, attr.second);
+         }
+       };
+
+      public:
+       inline debug_info_entry ()
+         : _m_ptr (NULL, NULL)
+       {}
+
+       inline debug_info_entry (const debug_info_entry &entry)
+         : _m_ptr (entry._m_ptr)
+       {}
+
+       inline explicit debug_info_entry (die_info_pair *die)
+         : _m_ptr (NULL, die)
+       {}
+
+       inline explicit debug_info_entry (entry *die)
+         : _m_ptr (die, die->_m_final)
+       {}
+
+       inline bool final () const
+       {
+         return _m_ptr.final != NULL;
+       }
+
+       inline die_info_pair *get_final () const
+       {
+         assert (_m_ptr.final != NULL);
+         return _m_ptr.final;
+       }
+
+       inline entry *get_pending () const
+       {
+         assert (_m_ptr.pending != NULL);
+         return _m_ptr.pending;
+       }
+
+       inline bool is (const debug_info_entry &other) const
+       {
+         return (_m_ptr.final == other._m_ptr.final
+                 && (final () || _m_ptr.pending == other._m_ptr.pending));
+       }
+
+       // Used by the tracker.
+       inline std::pair<die_info_pair *, entry *> context () const
+       {
+         return std::make_pair (_m_ptr.final, _m_ptr.pending);
+       }
+
+       inline int tag () const
+       {
+         return (_m_ptr.final != NULL
+                 ? _m_ptr.final->first.tag ()
+                 : _m_ptr.pending->_m_pending->_m_tag);
+       }
+
+       typedef subr::wrapped_input_container<typename pending_entry::attr_map,
+                                             pending_attr> attributes_type;
+
+       inline const attributes_type attributes () const
+       {
+         return attributes_type (_m_ptr.final == NULL
+                                 ? _m_ptr.pending->_m_pending->_m_attributes
+                                 : _m_ptr.final->first._m_attributes->base (),
+                                 subr::nothing ());
+       }
+
+       class children_type
+       {
+         friend class debug_info_entry;
+       private:
+         entry_pointers _m_ptr;
+
+         inline explicit children_type (const entry_pointers &ptr)
+           : _m_ptr (ptr)
+         {}
+
+       public:
+         class const_iterator
+           : public std::iterator<std::input_iterator_tag, debug_info_entry>
+         {
+           friend class children_type;
+           friend class attr_value;
+
+         private:
+           dwarf_output::debug_info_entry::children_type::
+           _base::const_iterator _m_final_iter;
+           typename std::vector<entry *>::const_iterator _m_pending_iter;
+           bool _m_final;
+
+           inline const_iterator
+           (const dwarf_output::debug_info_entry::const_pointer &i)
+             : _m_final_iter (i.base ()), _m_final (true)
+           {}
+
+           inline const_iterator
+           (const typename std::vector<entry *>::const_iterator &i)
+             : _m_pending_iter (i), _m_final (false)
+           {}
+
+           /* We have what appears to be a final reference attribute.
+              If it's actually a circular_reference, it might really
+              not be final after all.  */
+           inline void init_from_ref (const value::value_reference *ref)
+           {
+             const circular_reference *circle
+               = dynamic_cast<const circular_reference *> (ref);
+             _m_final = circle == NULL || circle->final ();
+             if (_m_final)
+               _m_final_iter = ref->ref;
+             else
+               _m_pending_iter = circle->pending ();
+           }
+
+           // This is called only by attr_value::reference, below.
+           inline const_iterator (const value::value_reference *ref)
+           {
+             init_from_ref (ref);
+             assert ((**this).identity () == (**this).identity ());
+           }
+
+           /* This is called only by attr_value::reference, below.
+              We have what appears to be a reference to a pending entry.
+              In fact, this entry might already have been finalized even
+              though this reference to it has not been.  */
+           inline const_iterator (entry *ref)
+             : _m_final (ref->_m_final != NULL)
+           {
+             if (_m_final)
+               init_from_ref (ref->self ());
+             else
+               _m_pending_iter = ref->pending_self ();
+             assert ((**this).identity () == (**this).identity ());
+           }
+
+         public:
+           inline const_iterator ()
+           {}
+
+           inline const_iterator (const const_iterator &other)
+           {
+             *this = other;
+           }
+
+           inline const debug_info_entry operator* () const
+           {
+             return (_m_final
+                     ? debug_info_entry (*_m_final_iter)
+                     : debug_info_entry (*_m_pending_iter));
+           }
+
+           inline bool operator== (const const_iterator &other) const
+           {
+             return (_m_final == other._m_final
+                     && (_m_final
+                         ? _m_final_iter == other._m_final_iter
+                         : _m_pending_iter == other._m_pending_iter));
+           }
+           inline bool operator!= (const const_iterator &other) const
+           {
+             return !(*this == other);
+           }
+
+           inline const_iterator &operator= (const const_iterator &other)
+           {
+             _m_final = other._m_final;
+             if (_m_final)
+               _m_final_iter = other._m_final_iter;
+             else
+               _m_pending_iter = other._m_pending_iter;
+             return *this;
+           }
+
+           inline const_iterator &operator++ () // prefix
+           {
+             if (_m_final)
+               ++_m_final_iter;
+             else
+               ++_m_pending_iter;
+             return *this;
+           }
+           inline const_iterator operator++ (int) // postfix
+           {
+             const const_iterator old = *this;
+             ++*this;
+             return old;
+           }
+         };
+
+         inline bool empty () const
+         {
+           return size () == 0;
+         }
+
+         inline size_t size () const
+         {
+           return (_m_ptr.final != NULL
+                   ? _m_ptr.final->first.children ().size ()
+                   : _m_ptr.pending->_m_pending->_m_children.size ());
+         }
+
+         inline const_iterator begin () const
+         {
+           return (_m_ptr.final != NULL
+                   ? const_iterator (_m_ptr.final->first.children ()
+                                     .begin ())
+                   : const_iterator (_m_ptr.pending->_m_pending->_m_children
+                                     .begin ()));
+         }
+
+         inline const_iterator end () const
+         {
+           return (_m_ptr.final != NULL
+                   ? const_iterator (_m_ptr.final->first.children ()
+                                     .end ())
+                   : const_iterator (_m_ptr.pending->_m_pending->_m_children
+                                     .end ()));
+         }
+       };
+
+       typedef typename children_type::const_iterator const_pointer;
+       typedef const_pointer pointer;
+
+       inline const children_type children () const
+       {
+         return children_type (_m_ptr);
+       }
+
+       inline bool has_children () const
+       {
+         return !children ().empty ();
+       }
+
+       inline uintptr_t identity () const
+       {
+         return (uintptr_t) _m_ptr.final ?: (uintptr_t) _m_ptr.pending;
+       }
+
+       inline ::Dwarf_Off original_offset () const
+       {
+         if (_m_ptr.final == NULL)
+           return _m_ptr.pending->_m_offset;
+         return _m_ptr.final->second.original_offset ();
+       }
+      };
+
+      // This wrapper class exists only to enhance reference variant.
+      struct attr_value
+       : public dwarf_output::attr_value
+      {
+       inline attr_value (const dwarf_output::attr_value &other)
+         : dwarf_output::attr_value (other)
+       {}
+
+       // An entry * in a pending_entry's attr_map counts as a reference.
+       inline dwarf::value_space what_space () const
+       {
+         return (dynamic_cast<const entry *> (this->_m_value) != NULL
+                 ? dwarf::VS_reference
+                 : dwarf_output::attr_value::what_space ());
+       }
+
+       inline typename debug_info_entry::const_pointer reference () const
+       {
+         const entry *ref = dynamic_cast<const entry *> (_m_value);
+         if (ref == NULL)
+           // Either really a final reference, or a circular reference.
+           return typename debug_info_entry::const_pointer
+             (dynamic_cast<const value::value_reference *> (_m_value));
+
+         /* This is an attribute comparison inside the attrs_match
+            comparator.  The attribute sets passed to attrs_match
+            directly don't hit this--they've already been finalized.
+            But following those references we got to another
+            pending_entry and its attributes that are not yet
+            finalized.  If attrs_match winds up returning true, these
+            will never be finalized because they are duplicates.  */
+         return typename debug_info_entry::const_pointer
+           (const_cast<entry *> (ref));
+       }
+      };
+
+      // Convenience wrapper.
+      static inline const typename debug_info_entry::attributes_type
+      attributes (const dwarf_output::debug_info_entry::attributes_type &attrs)
+      {
+       return typename debug_info_entry::attributes_type (attrs.base (),
+                                                          subr::nothing ());
+      }
+    };
+
+    /* This is a specialized tracker used solely in attrs_match, below.
+       We are comparing final entries already in the collector against
+       the almost-final pending_entry ready to be stored.  Both sides
+       are pending_dwarf rather than dwarf_output begin the left-hand
+       side, because a reference attribute of a "final" entry can be a
+       circular_reference that still points back to a pending entry.  */
+    class tracker
+      : public dwarf_tracker_base<pending_dwarf, pending_dwarf>
+    {
+    private:
+      typedef dwarf_tracker_base<pending_dwarf, pending_dwarf> _base;
+
+      const bool _m_ignore_context;
+
+      inline bool ignore_context () const
+      {
+       return _m_ignore_context;
+      }
+
+    public:
+      typedef typename _base::cu1 cu1;
+      typedef typename _base::cu2 cu2;
+      typedef typename _base::die1 die1;
+      typedef typename _base::die2 die2;
+
+      inline explicit tracker (copier *c)
+       : _m_ignore_context (c->_m_collector->ignore_context ())
+      {}
+
+      typedef die_info_pair *left_context_type;
+      typedef std::pair<die_info_pair *, entry *> right_context_type;
+
+      // Return the lhs context of an arbitrary DIE.
+      inline left_context_type left_context (const die1 &ref)
+      {
+       return (*ref).get_final ();
+      }
+
+      // Return the rhs context of an arbitrary DIE.
+      inline const right_context_type right_context (const die2 &ref)
+      {
+       return (*ref).context ();
+      }
+
+      /* Comparing two final DIEs for context.  They match only if their
+        immediate parents are the same final entry in the collector, or
+        if they are both top-level children of a CU.  */
+      inline bool final_context_match (die_info_pair *a, die_info_pair *b)
+      {
+       a = a->second._m_parent;
+       b = b->second._m_parent;
+       if (a == b)
+         return true;
+       if (a == NULL || b == NULL)
+         return false;
+       return a->second._m_parent == NULL && b->second._m_parent == NULL;
+      }
+
+      inline bool context_quick_mismatch (const left_context_type &lhs,
+                                         const right_context_type &rhs)
+
+      {
+       if (ignore_context ())
+         return false;
+
+       if (rhs.first != NULL)
+         // Comparing final to final.
+         return !final_context_match (lhs, rhs.first);
+
+       // Comparing final to pending.  XXX track depth??
+       return ((rhs.second->_m_parent == NULL)
+               != (lhs->second._m_parent == NULL));
+      }
+
+      inline bool context_match (const left_context_type &lhs,
+                                const right_context_type &rhs)
+      {
+       if (ignore_context ())
+         return true;
+
+       if (rhs.first != NULL)
+         // Comparing final to final.
+         return final_context_match (lhs, rhs.first);
+
+       // Comparing final to pending.
+       die_info_pair *a = lhs->second._m_parent;
+       entry *b = rhs.second->_m_parent;
+       while (a != NULL)
+         {
+           if (b == NULL)
+             return false;
+
+           if (a->second._m_parent == NULL)
+             /* A is the top-level CU entry.
+                We don't compare the CU attributes.
+                It's a match if B is also up to its top level.  */
+             return b->_m_parent == NULL;
+
+           if (!(dwarf_comparator<dwarf_output, pending_dwarf>::equal_enough
+                 (a->first, typename pending_dwarf::debug_info_entry (b))))
+             return false;
+
+           a = a->second._m_parent;
+           b = b->_m_parent;
+         }
+
+       // We can only get here if these were actually CU references.
+       return b == NULL;
+      }
+
+#ifdef _DWARF_OUTPUT_DEBUG_SPEW
+      static inline std::ostream &
+      dump (const typename pending_dwarf::debug_info_entry &a,
+           const typename pending_dwarf::debug_info_entry &b,
+           bool in = false, bool out = false)
+      {
+       return entry::debug_prefix (in, out)
+         << "XXX " << (a.final () ? "final " : "pending ")
+         << std::hex << a.original_offset ()
+         << " vs " << (b.final () ? "final " : "pending ")
+         << b.original_offset () << std::dec;
+      }
+
+      static inline std::ostream &
+      dump (const die1 &ref1, const die2 &ref2,
+           bool in = false, bool out = false)
+      {
+       return dump (*ref1, *ref2, in, out);
+      }
+
+      struct step : public _base::step
+      {
+       inline step (tracker *t, const die1 &a, const die2 &b)
+         : _base::step (t, a, b)
+       {
+         dump (*a, *b, true) << " cmp\n";
+       }
+       inline ~step ()
+       {
+         entry::debug_prefix (false, true, false);
+       }
+      };
+#else
+      static inline subr::nostream &
+      dump (const typename pending_dwarf::debug_info_entry &,
+           const typename pending_dwarf::debug_info_entry &,
+           bool = false, bool = false)
+      {
+       return entry::debug ();
+      }
+
+      static inline subr::nostream &
+      dump (const die1 &, const die2 &,
+           bool = false, bool = false)
+      {
+       return entry::debug ();
+      }
+#endif
+
+      class reference_match
+      {
+       entry *_m_pending;
+
+      public:
+       inline reference_match ()
+         : _m_pending (NULL)
+       {
+         entry::debug_prefix (true, false, false);
+       }
+
+       inline bool prematch (tracker *, const die1 &ref1, const die2 &ref2)
+       {
+         const typename pending_dwarf::debug_info_entry a = *ref1;
+         const typename pending_dwarf::debug_info_entry b = *ref2;
+
+         dump (a, b) << " reference_match\n";
+
+         if (!a.final ())
+           // XXX pending circular lhs can never match ???
+           return !b.final () && a.get_pending () == b.get_pending ();
+
+         die_info_pair *const lhs = a.get_final ();
+
+         if (b.final ())
+           return lhs == b.get_final ();
+
+         entry *const rhs = b.get_pending ();
+
+         if (rhs->_m_pending->_m_matched != NULL)
+           return lhs == rhs->_m_pending->_m_matched;
+
+         if (rhs->_m_comparing != NULL)
+           {
+             /* We have a circularity on the right-hand side.  We can tell
+                because _m_comparing remains set from an outer recursion
+                still in progress.
+
+                The circular chain of references rooted at A matches B if B
+                is also the root of its own circularity and everything along
+                those parallel chains matches.  If the chains hadn't matched
+                so far, we would not have kept following them to get here.
+
+                So, this matches if what we were comparing to was the same A.
+                If it didn't match, we have left _m_pending clear, which makes
+                negative_cache trigger (below).  */
+
+             if (rhs->_m_comparing != lhs)
+               return false;
+
+             dump (a, b) << " tentative circular match\n";
+             return true;
+           }
+
+         if (rhs->_m_pending->cached_mismatch (lhs))
+           return false;
+
+         /* Record that we have a walk in progress crossing B.  When this
+            reference_match object goes out of scope in our caller, its
+            destructor will reset _m_comparing to clear this record.  */
+         rhs->_m_comparing = lhs;
+         _m_pending = rhs;
+         return false;
+       }
+
+       inline bool negative_cache () const
+       {
+         return _m_pending == NULL;
+       }
+
+       inline ~reference_match ()
+       {
+         if (_m_pending != NULL)
+           {
+             assert (_m_pending->_m_comparing != NULL);
+             _m_pending->_m_comparing = NULL;
+           }
+         entry::debug_prefix (false, true, false);
+       }
+      };
+
+      // This call is used purely in hopes of a cache hit.
+      inline bool prematch (reference_match &matched,
+                           const die1 &a, const die2 &b)
+      {
+       bool same = matched.prematch (this, a, b);
+       dump (a, b) << " prematch => " << same << "\n";
+       return same;
+      }
+
+      // This call is used only as part of a real reference lookup.
+      inline bool reference_matched (reference_match &matched,
+                                    const die1 &a, const die2 &b)
+      {
+       bool same = matched.prematch (this, a, b);
+       dump (a, b) << " reference_matched => " << same << "\n";
+       return same;
+      }
+
+      // Check for a negative cache hit after prematch or reference_match.
+      inline bool cannot_match (reference_match &matched,
+                               const die1 &, const die2 &)
+      {
+       return matched.negative_cache ();
+      }
+
+      // This can cache a result.
+      inline bool notice_match (reference_match &matched,
+                               const die1 &ref1, const die2 &ref2,
+                               bool result)
+      {
+       if (result && matched.negative_cache ())
+         {
+           /* This positive result is from a tentative match of congruent
+              circular references.  That doesn't mean they really match,
+              only that they might if the rest of their trees do.  Don't
+              cache it as a match now.  */
+           dump (ref1, ref2) << " should ignore tentative match\n";
+           return result;
+         }
+
+       const typename pending_dwarf::debug_info_entry a = *ref1;
+       const typename pending_dwarf::debug_info_entry b = *ref2;
+       dump (a, b) << " notice_match (" << result << ")\n";
+       if (result)
+         {
+           /* We've found two matching entries.  If we just matched a
+              final entry to a pending entry, cache that knowledge so
+              we don't bother with the whole hash lookup and comparison
+              when we come to finalizing that pending entry itself.  */
+
+           if (a.final ())
+             {
+               if (!b.final ())
+                 b.get_pending ()->record_prematch (a.get_final (), false);
+             }
+           else if (b.final ())
+             a.get_pending ()->record_prematch (b.get_final (), true);
+         }
+       else
+         b.get_pending ()->_m_pending->notice_mismatch (a.get_final ());
+       return result;
+      }
+
+      template<typename item1, typename item2>
+      inline bool identical (const item1 &, const item2 &)
+      {
+       return false;
+      }
+
+      inline bool identical (const typename pending_dwarf::debug_info_entry &a,
+                            const typename pending_dwarf::debug_info_entry &b)
+      {
+       return a.is (b);
+      }
+
+      inline bool identical (const typename pending_dwarf::attr_value &a,
+                            const typename pending_dwarf::attr_value &b)
+      {
+       return a.is (b);
+      }
+
+      typedef tracker subtracker;
+      inline tracker (const tracker &proto, reference_match &,
+                     const left_context_type &,
+                     const right_context_type &)
+       : _m_ignore_context (proto._m_ignore_context)
+      {}
+    };
+
+    typedef dwarf_comparator<pending_dwarf, pending_dwarf,
+                            false, tracker> comparator;
+
+    // This is what the entire pending_dwarf class exists for.
+    inline bool attrs_match (const debug_info_entry::attributes_type &a,
+                            const debug_info_entry::attributes_type &b)
+    {
+      tracker t (this);
+      return comparator (t).equals (pending_dwarf::attributes (a),
+                                   pending_dwarf::attributes (b));
+    }
+
+    /* We're likely to come across the same strings/identifiers and source
+       files many times in a copying run.  When they are the very same
+       pointers into the input dwarf object data, we can optimize the
+       ordinary string hash lookup in the value_set by caching the mapping
+       of input pointers to output values.  */
+    template<typename value_type>
+    struct string_cache
+    {
+      std::map<uintptr_t, const value_type *> _m_cache;
+
+      template<typename input>
+      inline const value_type *add (subr::value_set<value_type> &set,
+                                   uintptr_t key, const input &x)
+      {
+       const value_type *&cache = _m_cache[key];
+       if (cache == NULL)
+         cache = set.add (x);
+       return cache;
+      }
+
+      inline const value_type *add (subr::value_set<value_type> &set,
+                                   const char *x)
+      {
+       return add (set, (uintptr_t) x, x);
+      }
+
+      inline const value_type *add (subr::value_set<value_type> &set,
+                                   const std::string &x)
+      {
+       return add (set, (uintptr_t) &x, x);
+      }
+
+      template<typename input>
+      inline const value_type *add (subr::value_set<value_type> &set,
+                                   const input &x)
+      {
+       return set.add (x);
+      }
+    };
+
+    string_cache<value::value_string> _m_strings;
+    string_cache<value::value_identifier> _m_identifiers;
+
+    std::tr1::unordered_map<
+      uintptr_t, const value::value_source_file *> _m_source_file_cache;
+
+    template<typename input>
+    inline const value::value_source_file *add_source_file (int /*whatattr*/,
+                                                           const input &x)
+    {
+      const value::value_source_file *&cache
+       = _m_source_file_cache[x.identity ()];
+      if (cache == NULL)
+       cache = _m_collector->_m_source_file.add (x);
+      return cache;
+    }
+
+    template<typename input>
+    inline const value::value_string *add_string (const input &x)
+    {
+      return _m_strings.add (_m_collector->_m_strings, x);
+    }
+
+    template<typename input>
+    inline const value::value_string *add_identifier (const input &x)
+    {
+      return _m_identifiers.add (_m_collector->_m_identifiers, x);
+    }
+
+    template<typename input>
+    inline const value::value_flag *add_flag (const input &x)
+    {
+      return dwarf_output_collector::flag (x);
+    }
+
+    template<typename input>
+    inline const value::value_address *add_address (const input &x)
+    {
+      return _m_collector->_m_address.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_rangelistptr *add_ranges (const input &x)
+    {
+      return _m_collector->_m_ranges.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_lineptr *add_line_info (const input &x)
+    {
+      return _m_collector->_m_line_info.add (x, *_m_collector);
+    }
+
+    template<typename input>
+    inline const value::value_constant *add_constant (const input &x)
+    {
+      return _m_collector->_m_constants.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_constant_block *
+    add_constant_block (const input &x)
+    {
+      return _m_collector->_m_const_block.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_dwarf_constant *
+    add_dwarf_constant (const input &x)
+    {
+      return _m_collector->_m_dwarf_const.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_source_line *add_source_line (const input &x)
+    {
+      return _m_collector->_m_source_line.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_source_column *add_source_column (const input &x)
+    {
+      return _m_collector->_m_source_column.add (x);
+    }
+
+    template<typename input>
+    inline const value::value_location *add_location (const input &x)
+    {
+      return _m_collector->_m_locations.add (x);
+    }
+
+  public:
+    inline explicit copier (dwarf_output_collector &c)
+      : _m_collector (&c), _m_entries (), _m_undefined_entries (0)
+    {}
+
+    inline operator dwarf_output_collector & () const
+    {
+      return *_m_collector;
+    }
+  };
+
+  // Explicit instantiations.
+  extern template class dwarf_data::value<dwarf_output, false>;
+  extern template class dwarf_data::attr_value<dwarf_output,
+                                              dwarf_output::value>;
+  extern template class dwarf_data::attributes_type<dwarf_output,
+                                                   dwarf_output::value>;
+  extern template class dwarf_data::compile_unit<dwarf_output>;
+  extern template class dwarf_data::compile_units_type<dwarf_output>;
+
+  extern template class dwarf_output::copier<dwarf>;
+  extern template class dwarf_output::copier<dwarf_edit>;
+};
+
+#endif // <elfutils/dwarf_output>
diff --git a/libdw/c++/dwarf_ref_maker b/libdw/c++/dwarf_ref_maker
new file mode 100644 (file)
index 0000000..5df223d
--- /dev/null
@@ -0,0 +1,167 @@
+/* elfutils::dwarf_ref_maker -- -*- C++ -*- template type specification
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF_REF_MAKER
+#define _ELFUTILS_DWARF_REF_MAKER      1
+
+#include "dwarf"
+#include <tr1/unordered_map>
+#include <vector>
+
+namespace elfutils
+{
+  // Prototypical stub for reference maker object.
+  // This keeps no state and can't really be used.
+  template<class output, class input>
+  struct dwarf_ref_maker_base
+  {
+    typedef typename input::debug_info_entry input_entry;
+    typedef typename input_entry::children_type::const_iterator input_ref;
+    typedef typename output::debug_info_entry::pointer output_ref;
+
+    // These are called around a whole-file construction.
+    inline void start () {}
+
+    // If called, all pointers passed in since start () before are bogus.
+    inline void abort () {}
+
+    // Construction is complete: now snap in all recorded references.
+    inline void finish (output &file) {}
+
+    // The referenced output DIE has been constructed to match the input DIE.
+    inline void equivalence (const output_ref &to, const input_ref &from)
+    {
+    }
+
+    // *REF is an uninitialized attr_value.reference ().
+    // It's meant to refer to the output DIE equivalent to the given input DIE.
+    inline void refer (output_ref *ref, const input_ref &target)
+    {
+      throw std::logic_error ("dwarf_ref_maker_base cannot make references");
+    }
+  };
+
+  // Simple maker used for a single copy-construction.
+  template<class output, class input>
+  class dwarf_ref_maker : public dwarf_ref_maker_base<output, input>
+  {
+  public:
+    typedef typename input::debug_info_entry input_entry;
+    typedef typename output::debug_info_entry output_entry;
+    typedef typename input_entry::children_type::const_iterator input_ref;
+    typedef typename output_entry::children_type::iterator output_ref;
+
+  private:
+
+    struct seen
+    {
+      bool _m_known;
+      output_ref _m_out;
+      std::vector<output_ref *> _m_refs;
+
+      inline seen ()
+       : _m_known (false), _m_out (), _m_refs ()
+      {}
+
+      // Copy construction only valid for initial state.
+      inline seen (const seen &other)
+       : _m_known (false), _m_out (), _m_refs ()
+      {
+       if (unlikely (other._m_known) || unlikely (!other._m_refs.empty ()))
+         throw std::logic_error
+           ("seen copy constructs only from default-constructed");
+      }
+
+      inline void resolve ()
+      {
+       for (; !_m_refs.empty (); _m_refs.pop_back ())
+         *_m_refs.back () = _m_out;
+      }
+
+      inline void resolve (const output_ref &to)
+      {
+       _m_out = to;
+       _m_known = true;
+       resolve ();
+      }
+
+      inline void refer (output_ref *out)
+      {
+       _m_refs.push_back (out);
+       if (_m_known)
+         resolve ();
+      }
+    };
+
+    std::tr1::unordered_map<dwarf::debug_info_entry::identity_type,
+                           seen> _m_map;
+
+  public:
+    inline dwarf_ref_maker ()
+      : _m_map ()
+    {}
+
+    inline dwarf_ref_maker (const dwarf_ref_maker &other)
+      : _m_map ()
+    {
+      if (unlikely (!other._m_map.empty ()))
+       throw std::logic_error
+         ("dwarf_ref_maker copy constructs only from default-constructed");
+    }
+
+    inline ~dwarf_ref_maker ()
+    {}
+
+    inline void abort ()
+    {
+      _m_map.clear ();
+    }
+
+    inline void equivalence (const output_ref &out, const input_ref &in)
+    {
+      _m_map[in->identity ()].resolve (out);
+    }
+
+    inline void refer (output_ref *out, const input_ref &in)
+    {
+      _m_map[in->identity ()].refer (out);
+    }
+
+    inline void finish (output &file)
+    {
+      while (_m_map.begin () != _m_map.end ())
+       if (_m_map.begin ()->second._m_known)
+         _m_map.erase (_m_map.begin ());
+       else
+         throw std::logic_error ("construction finished with unresolved refs");
+    }
+  };
+
+};
+
+#endif // <elfutils/dwarf_ref_maker>
diff --git a/libdw/c++/dwarf_tracker b/libdw/c++/dwarf_tracker
new file mode 100644 (file)
index 0000000..581c914
--- /dev/null
@@ -0,0 +1,738 @@
+/* elfutils::dwarf_ref_tracker -- DWARF reference tracking in -*- C++ -*-
+   Copyright (C) 2009-2011 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_DWARF_TRACKER
+#define _ELFUTILS_DWARF_TRACKER        1
+
+#include "subr.hh"
+#include "dwarf"
+#include "dwarf_comparator"
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+
+namespace elfutils
+{
+  // Basic tracker of tree-walk paths to DIEs.
+  template<typename dw>
+  class dwarf_path_finder
+  {
+  public:
+    typedef typename dw::compile_units_type::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.
+
+       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 subr::sharing_stack<die> die_path;
+
+  private:
+    // 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 ();
+    }
+    static inline bool bad_die_path (const die_path &path)
+    {
+      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, including itself.  */
+    typedef std::tr1::unordered_map<dwarf::debug_info_entry::identity_type,
+                                   const die_path> die_map;
+    die_map *_m_seen;
+
+    /* The original object that this was cloned from, or NULL if this is
+       it.  That object owns the _m_seen map and will delete it.  */
+    dwarf_path_finder *_m_owner;
+
+    /* A cloned object used for walking ahead to satisfy path_to.
+       This is only ever set in an original object, where _m_owner is NULL.  */
+    dwarf_path_finder *_m_walkahead;
+
+    // The total number of DIEs visited in this object's walk.
+    unsigned int _m_steps_taken;
+
+    cu _m_root;
+
+    die_path _m_path;
+
+    explicit dwarf_path_finder (const dwarf_path_finder &)
+    {
+      throw std::logic_error ("not copy-constructible");
+    }
+
+    explicit dwarf_path_finder (dwarf_path_finder *owner)
+      : _m_seen (owner->_m_seen), _m_owner (owner),
+       _m_walkahead (NULL), _m_steps_taken (owner->_m_steps_taken),
+       _m_root (owner->_m_root), _m_path (owner->_m_path)
+    {
+    }
+
+    inline bool at_top () const
+    {
+      return _m_path.empty ();
+    }
+
+    inline const die &current_die () const
+    {
+      assert (!at_top ());
+      return _m_path.top ();
+    }
+
+    inline dwarf::debug_info_entry::identity_type current_identity () const
+    {
+      return (*current_die ()).identity ();
+    }
+
+    inline die current_end () const
+    {
+      assert (!at_top ());
+      const typename die_path::const_reverse_iterator i = ++_m_path.rbegin ();
+      return (i == _m_path.rend ()
+             ? (*_m_root).children ().end ()
+             : (**i).children ().end ());
+    }
+
+    // Append this DIE to the path we'll record for it and its children.
+    inline void step_forward (const die &here)
+    {
+      _m_path.push (here);
+      assert (!bad_die_path (_m_path));
+      ++_m_steps_taken;
+      record_step ();
+    }
+
+    inline void step_back ()
+    {
+      _m_path.pop ();
+    }
+
+    inline void clear_walkahead ()
+    {
+      delete _m_walkahead;
+      _m_walkahead = NULL;
+    }
+
+    inline void clear_walk ()
+    {
+      if (_m_walkahead != NULL)
+       clear_walkahead ();
+      _m_steps_taken = 0;
+    }
+
+    // Record the path down from the CU to see this DIE.
+    inline void record_step ()
+    {
+      if (_m_walkahead != NULL)
+       {
+         if (_m_steps_taken == _m_walkahead->_m_steps_taken)
+           // We have caught up to the walkahead, so it's now superfluous.
+           clear_walkahead ();
+         else
+           // The walkahead is past us, so there is nothing to record.
+           assert (_m_steps_taken < _m_walkahead->_m_steps_taken);
+       }
+      else
+       _m_seen->insert (std::make_pair (current_identity (), _m_path));
+    }
+
+  public:
+    // Default constructor: an original tracker.
+    inline dwarf_path_finder ()
+      : _m_seen (new die_map), _m_owner (NULL),
+       _m_walkahead (NULL), _m_steps_taken (0)
+    {}
+
+    // Construct a derived tracker: does its own whole walk, but sharing caches.
+    inline dwarf_path_finder (const dwarf_path_finder &proto, bool)
+      : _m_seen (proto._m_seen), _m_owner (&proto),
+       _m_walkahead (NULL), _m_steps_taken (0)
+    {}
+
+    /* Construct a derived tracker that jump-starts a walk.
+       CONTEXT is from a path_to call made on PROTO.  */
+    inline dwarf_path_finder (dwarf_path_finder &proto,
+                             const die_path &context)
+      : _m_seen (proto._m_seen), _m_owner (proto._m_owner ?: &proto),
+       _m_walkahead (NULL), _m_steps_taken (0),
+       _m_root (proto._m_root), _m_path (context)
+    {}
+
+    inline ~dwarf_path_finder ()
+    {
+      if (_m_owner == NULL)
+       {
+         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;
+      bool _m_jumped;
+
+      inline walk (dwarf_path_finder *w, const cu &root)
+       : _m_tracker (w), _m_jumped (false)
+      {
+       assert (_m_tracker->_m_path.empty ());
+       assert (_m_tracker->_m_steps_taken == 0);
+       assert (_m_tracker->_m_walkahead == NULL);
+       _m_tracker->_m_root = root;
+      }
+
+      inline ~walk ()
+      {
+       if (_m_jumped)
+         _m_tracker->_m_path.clear ();
+       else
+         assert (_m_tracker->_m_path.empty ());
+       _m_tracker->clear_walk ();
+      }
+
+      inline void jump (const typename dw::debug_info_entry &there)
+      {
+       _m_jumped = true;
+       _m_tracker->prime_path_to (there);
+      }
+    };
+
+    /* 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)
+      {
+       _m_walker->step_forward (here);
+      }
+      inline ~step ()
+      {
+       _m_walker->step_back ();
+      }
+    };
+
+    inline void unreachable (const typename dw::debug_info_entry &) const
+    {
+      throw std::runtime_error ("DIE not reachable from CU!");
+    }
+
+    inline void prime_path_to (const typename dw::debug_info_entry &there)
+    {
+      if (_m_owner != NULL)
+       {
+         /* Since this is a cloned tracker,
+            _m_steps_taken counting does not matter.  */
+         assert (this != _m_owner->_m_walkahead);
+         _m_path = path_to (there);
+       }
+      else
+       {
+         /* Spin the walk ahead until we get THERE.  */
+         const dwarf::debug_info_entry::identity_type id = there.identity ();
+         if (_m_seen->find (id) != _m_seen->end ())
+           {
+             /* We're walking backwards now.  We have to repeat the
+                whole walk to recover our _m_steps_taken state correctly.  */
+             _m_path.clear ();
+             clear_walk ();
+           }
+
+         if (at_top ())
+           {
+             /* We have to get the walk started.  */
+             const die first = (*_m_root).children ().begin ();
+             if (first == (*_m_root).children ().end ())
+               unreachable (there); // Empty CU!
+
+             step_forward (first);
+             if ((*first).identity () == id)
+               return;
+           }
+
+         /* We have not walked past it yet, so just keep walking.  */
+         if (! walk_to (id))
+           unreachable (there);
+       }
+    }
+
+    // Random access to a DIE, find the path of the walk that gets there.
+    inline const die_path &path_to (const die &a)
+    {
+      return path_to (*a);
+    }
+
+    inline const die_path &path_to (const typename dw::debug_info_entry &a)
+    {
+      if (_m_owner != NULL)
+       return _m_owner->path_to (a);
+
+      const dwarf::debug_info_entry::identity_type id = a.identity ();
+      const typename die_map::const_iterator found = _m_seen->find (id);
+      if (found != _m_seen->end ())
+       return 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 walk ahead to find it.  */
+      return walk_ahead_to (a, id);
+    }
+
+  private:
+    /* Do some walkahead to find the target entry.
+       This can only be used on the master object, not its clones.  */
+    inline const die_path &
+    walk_ahead_to (const typename dw::debug_info_entry &a,
+                  dwarf::debug_info_entry::identity_type id)
+    {
+      assert (_m_owner == NULL);
+      if (_m_walkahead == NULL)
+       // Create our walkahead clone.
+       _m_walkahead = new dwarf_path_finder (this);
+      if (! _m_walkahead->walk_to (id))
+       unreachable (a);
+      return _m_walkahead->_m_path;
+    }
+
+    // Do some actual walkahead.  This is used only on the walkahead clone.
+    inline bool walk_to (dwarf::debug_info_entry::identity_type id)
+    {
+      return walk_down_to (id) || walk_over_to (id) || walk_up_to (id);
+    }
+
+    // Descend into child HERE (already pushed) looking for THERE.
+    inline bool walk_in_to (const typename die::value_type &here,
+                           dwarf::debug_info_entry::identity_type there)
+    {
+      return (here.has_children ()
+             && walk_through_to (here.children ().begin (),
+                                 here.children ().end (),
+                                 there));
+    }
+
+    // Walk through siblings [IT,END) looking for THERE.
+    bool walk_through_to (die it, const die &end,
+                         dwarf::debug_info_entry::identity_type there)
+    {
+      for (; it != end; ++it)
+       {
+         /* Do step_forward even for a childless non-match, because it
+            records this DIE in _m_seen, which we will rely on later.  */
+         step_forward (it);
+
+         const typename die::value_type &child = *it;
+
+         /* Note that we compare identities here, rather than passing down
+            a THERE iterator and comparing iterators.  In dwarf_output, we
+            can have multiple iterators into distinct children_type vectors
+            that all point to the same entry.  A reference could be one of
+            these iterators, and all mean the same entry.  */
+         if (child.identity () == there || walk_in_to (child, there))
+           return true;
+
+         // Come back out of this child to look at the next.
+         step_back ();
+       }
+      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 (dwarf::debug_info_entry::identity_type there)
+    {
+      return walk_in_to (*current_die (), there);
+    }
+
+    /* Now wind the walk forward starting from the current DIE's
+       immediate sibling.  If we fail, we wind up at this DIE's parent.  */
+    inline bool walk_over_to (dwarf::debug_info_entry::identity_type there)
+    {
+      // Fetch the current DIE and end-point before we step back.
+      die here (current_die ());
+      const die end = current_end ();
+
+      step_back ();
+      return walk_through_to (++here, end, there);
+    }
+
+    /* We have already stepped back from the current DIE to its parent.
+       Now wind the walk forward from that parent's immediate sibling.  */
+    inline bool walk_up_to (dwarf::debug_info_entry::identity_type there)
+    {
+      while (!at_top ())
+       if (walk_over_to (there))
+         return true;
+      return false;
+    }
+  };
+
+  // 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;
+
+    explicit dwarf_ref_tracker (const dwarf_ref_tracker &)
+       : _base ()
+    {
+      throw std::logic_error ("not copy-constructible");
+    }
+
+  public:
+    typedef typename _base::cu1 cu1;
+    typedef typename _base::cu2 cu2;
+    typedef typename _base::die1 die1;
+    typedef typename _base::die2 die2;
+    class reference_match;
+
+  protected:
+    typedef dwarf_path_finder<dwarf1> tracker1;
+    typedef dwarf_path_finder<dwarf2> tracker2;
+
+    tracker1 _m_left;
+    tracker2 _m_right;
+
+    struct ref_hasher : public std::unary_function<die2, size_t>
+    {
+      inline size_t operator () (const die2 &i) const
+      {
+       return (*i).identity ();
+      }
+    };
+
+    struct same_ref : public std::equal_to<die2>
+    {
+      inline bool operator () (const die2 &a, const die2 &b) const
+      {
+       return (*a).identity () == (*b).identity ();
+      }
+    };
+
+    typedef std::tr1::unordered_map<dwarf::debug_info_entry::identity_type,
+                                   reference_match *> active_map;
+    active_map _m_active;
+
+    typedef std::pair<const die2 *,
+                     std::tr1::unordered_set<die2, ref_hasher, same_ref>
+                     > equiv_list;
+    typedef std::tr1::unordered_map<dwarf::debug_info_entry::identity_type,
+                                   equiv_list> equiv_map;
+    equiv_map *_m_equiv;
+    bool _m_delete_equiv;
+
+    inline equiv_list *equiv_to (const die1 &a)
+    {
+      return &(*_m_equiv)[a->identity ()];
+    }
+
+    struct equal_enough : public std::binary_function<die1, die2, bool>
+    {
+      inline bool operator () (const die1 &a, const die2 &b)
+      {
+       return dwarf_comparator<dwarf1, dwarf2>::equal_enough (*a, *b);
+      }
+    };
+
+  public:
+    inline dwarf_ref_tracker ()
+      : _m_equiv (new equiv_map), _m_delete_equiv (true)
+    {}
+
+    inline dwarf_ref_tracker (const tracker1 &proto)
+      : _m_left (proto, true),
+       _m_equiv (new equiv_map), _m_delete_equiv (true)
+    {}
+
+    inline ~dwarf_ref_tracker ()
+    {
+      if (_m_delete_equiv)
+       delete _m_equiv;
+    }
+
+    inline void reset ()
+    {
+      _m_equiv->clear ();
+      assert (!_m_right->_m_delete_seen);
+      _m_right._m_seen->clear ();
+    }
+
+    struct walk
+    {
+      typename tracker1::walk _m_left;
+      typename tracker2::walk _m_right;
+
+      inline walk (dwarf_ref_tracker *w, const cu1 &a, const cu2 &b)
+       : _m_left (&w->_m_left, a), _m_right (&w->_m_right, b)
+      {}
+
+      // Wind forward to cache everything up through A and B.
+      inline void jump (const typename dwarf1::debug_info_entry &a,
+                       const typename dwarf2::debug_info_entry &b)
+      {
+       _m_left.jump (a);
+       _m_right.jump (b);
+      }
+    };
+
+    struct step
+    {
+      typename tracker1::step _m_left;
+      typename tracker2::step _m_right;
+
+      inline step (dwarf_ref_tracker *w, const die1 &a, const die2 &b)
+       : _m_left (&w->_m_left, a), _m_right (&w->_m_right, b)
+      {}
+    };
+
+    typedef typename tracker1::die_path left_context_type;
+    inline const left_context_type &left_context (const die1 &die)
+    {
+      return _m_left.path_to (die);
+    }
+
+    typedef typename tracker2::die_path right_context_type;
+    inline const right_context_type &right_context (const die2 &die)
+    {
+      return _m_right.path_to (die);
+    }
+
+    // Very cheap check for an obvious mismatch of contexts.
+    inline bool context_quick_mismatch (const left_context_type &a,
+                                       const right_context_type &b)
+
+    {
+      return a.size () != b.size ();
+    }
+
+    // Full match when context_quick_mismatch has returned false.
+    inline bool context_match (const left_context_type &a,
+                              const right_context_type &b)
+    {
+      equal_enough equalator;
+      // Ignore the top of the stack, which is the target DIE itself.
+      return a.equal (b, equalator, 1);
+    }
+
+    class reference_match
+    {
+      friend class dwarf_ref_tracker;
+    protected:
+      equiv_list *_m_lhs;
+      typename active_map::value_type *_m_rhs;
+      active_map *_m_active;
+
+    public:
+
+      inline reference_match ()
+       : _m_lhs (NULL), _m_rhs (NULL), _m_active (NULL)
+      {}
+
+      inline ~reference_match ()
+      {
+       if (_m_lhs != NULL)
+         _m_lhs->first = NULL;
+       if (_m_rhs != NULL)
+         _m_active->erase (_m_rhs->first);
+      }
+    };
+
+    /* A prematch during the main tree walk does the same cache lookup
+       as real reference matching.  But it doesn't record itself as a
+       "walk in progress" for the circularity-catching logic.  Doing so
+       can break that logic for comparison purposes.  Since we key our
+       cache on identity, a lookup can hit a shared DIE as well as one
+       that is truly involved in our current walk.  If we hit a shared
+       DIE on the main walk, and within that recursion (i.e. somewhere
+       in its children or along its own references) we encounter a
+       circularity, we'd take the main-walk's equiv_list record as the
+       root of the circularity on one side, while on the other side the
+       DIEs may not have been shared and so the same circularity is
+       actually rooted at the second instance of an identical DIE.  */
+    inline bool prematch (reference_match &matched,
+                         const die1 &a, const die2 &b)
+    {
+      return reference_matched (matched, a, b, false);
+    }
+
+    inline bool
+    reference_matched (reference_match &matched, const die1 &a, const die2 &b,
+                      bool record = true)
+    {
+      equiv_list *elt = equiv_to (a);
+      if (elt->first == NULL)
+       {
+         matched._m_lhs = elt;
+
+         if (record)
+           /* Record that we have a walk in progress crossing A.
+              When MATCHED goes out of scope in our caller, its
+              destructor will reset ELT->first to clear this record.  */
+           elt->first = &b;
+
+         // Short-circuit if we have already matched B to A.
+         return elt->second.find (b) != elt->second.end ();
+       }
+
+      /* We have a circularity on the left-hand side.  We can tell because
+        ELT->first remains set from an outer recursion still in progress.
+
+        The circular chain of references rooted at A matches B if B is
+        also the root of its own circularity and everything along those
+        parallel chains matches.  If the chains hadn't matched so far,
+        we would not have kept following them to get here.
+
+        We recorded the B that arrived at the first comparison with A.
+        We actually record the pointer on the caller's stack rather
+        than a copy of B, just because the iterator might be larger.  */
+
+      if ((**elt->first).identity () == (*b).identity ())
+       return true;
+
+      /* Our right-hand side is not in lock-step on a matching circularity.
+        But it's still possible this is a matching reference nonetheless.
+        A difference in the sharing vs duplication of DIEs between the
+        left-hand and right-hand sides could mean that one side's chain of
+        references reaches the same cycle sooner than the other's.
+
+        Consider:
+
+               A1 -> A2 -> ... -> A1' -> A2 ...
+               B1 -> B2 -> ... -> B1  -> B2 ...
+
+        Here A1' is an identical copy of A1, duplicated in the A object.
+        Otherwise A1 matches B1, A2 matches B2, etc.  The B walk started
+        at B1 and hits it again at the step comparing B1 to A1'.  But the
+        A walk has not hit A1 again yet (and perhaps it never will), so
+        our test above does not match.
+
+        This is the simplest example.  There might be more steps of the
+        reference chain that have duplicates on one side but have been
+        consolidated to a single entry on the other.  There can also be
+        multiple reference attributes at each node that differ on this
+        issue, making all manner of tangled graphs that all really match
+        the same simpler graph (and thus each other).
+
+        Now we start recording the state of the right-hand side reference
+        chain walk, and keep going.  When the right-hand side then becomes
+        circular, we check that it has coincided with the left-hand side.
+
+        This is guaranteed to terminate, at least.  It should never have
+        any false positives, since that continuing walk would eventually
+        find the differences.  We hope it doesn't have any false negatives
+        either, but to be sure of that would require more graph theory
+        than your humble writer can bring to bear.  */
+
+      const std::pair<typename active_map::iterator, bool> p
+       = _m_active.insert (std::make_pair ((*b).identity (), &matched));
+      if (p.second)
+       {
+         assert (p.first->second == &matched);
+         matched._m_lhs = elt;
+         matched._m_active = &_m_active;
+         matched._m_rhs = &*p.first;
+         return false;
+       }
+
+      assert (p.first->second != &matched);
+      return p.first->second->_m_lhs == elt;
+    }
+
+    inline bool cannot_match (reference_match &matched,
+                             const die1 &, const die2 &)
+    {
+      return matched._m_lhs == NULL && matched._m_rhs == NULL;
+    }
+
+    inline bool notice_match (reference_match &/*matched*/,
+                             const die1 &, const die2 &/*b*/, bool matches)
+    {
+      /* XXX not reliable!
+        This match could be predicated on a tentative match of a
+        circular ref inside.  We can't cache that!
+      if (matches && matched._m_lhs != NULL)
+       matched._m_lhs->second.insert (b);
+      */
+      return matches;
+    }
+
+    typedef dwarf_ref_tracker subtracker;
+
+    // Share the _m_seen maps with the prototype tracker,
+    // but start a fresh walk from the given starting point.
+    inline dwarf_ref_tracker (dwarf_ref_tracker &proto, reference_match &,
+                             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 LHS vs RHS.
+    }
+  };
+};
+
+#endif // <elfutils/dwarf_tracker>
diff --git a/libdw/c++/edit-values.cc b/libdw/c++/edit-values.cc
new file mode 100644 (file)
index 0000000..aefb5fd
--- /dev/null
@@ -0,0 +1,67 @@
+/* elfutils::dwarf_edit attribute value interfaces.
+   Copyright (C) 2009-2010 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include "dwarf_edit"
+#include "data-values.hh"
+
+using namespace elfutils;
+
+// Explicit instantiations.
+template class dwarf_data::line_entry<dwarf_edit::source_file>;
+template class dwarf_data::line_table<dwarf_edit::line_entry>;
+template class dwarf_data::line_info_table<dwarf_edit::line_table>;
+template class dwarf_data::attr_value<dwarf_edit>;
+template class dwarf_data::value<dwarf_edit>;
+
+template<>
+std::string
+to_string<dwarf_edit::attribute> (const dwarf_edit::attribute &attr)
+{
+  return attribute_string (attr);
+}
+
+namespace elfutils
+{
+  template<>
+  std::string to_string (const dwarf_edit::debug_info_entry &die)
+  {
+    return die_string (die);
+  }
+};
+
+std::string
+dwarf_data::source_file::to_string () const
+{
+  if (likely (_m_mtime == 0) && likely (_m_size == 0))
+    return "\"" + _m_name + "\"";
+
+  std::ostringstream os;
+  os << "{\"" << _m_name << "," << _m_mtime << "," << _m_size << "}";
+  return os.str ();
+}
diff --git a/libdw/c++/exception.cc b/libdw/c++/exception.cc
new file mode 100644 (file)
index 0000000..fbd504f
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- C++ -*- exceptions for libdw.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <cassert>
+#include "dwarf"
+
+extern "C"
+{
+#include "libdwP.h"
+}
+
+using namespace elfutils;
+using namespace std;
+
+
+/* Throw
+ */
+void
+dwarf::throw_libdw (::Dwarf *)
+{
+  throw std::runtime_error (::dwarf_errmsg (-1));
+}
+
+// This is just for things that can't find the Dwarf pointer directly.
+void
+dwarf::throw_libdw (::Dwarf_CU *cu)
+{
+  throw_libdw (cu->dbg);
+}
diff --git a/libdw/c++/known.cc b/libdw/c++/known.cc
new file mode 100644 (file)
index 0000000..6f09e47
--- /dev/null
@@ -0,0 +1,230 @@
+/* Known named integer values in DWARF.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include "dwarf"
+#include "dwarf_edit"
+#include "known-dwarf.h"
+
+using namespace elfutils;
+using namespace std;
+
+
+const char *
+dwarf::known_tag (int tag)
+{
+  switch (tag)
+    {
+#define ONE_KNOWN_DW_TAG(name, id)             case id: return #id;
+#define ONE_KNOWN_DW_TAG_DESC(name, id, desc)  ONE_KNOWN_DW_TAG (name, id)
+      ALL_KNOWN_DW_TAG
+    }
+  return NULL;
+}
+
+const char *
+dwarf::known_attribute (int name)
+{
+  switch (name)
+    {
+#define ONE_KNOWN_DW_AT(name, id)              case id: return #id;
+#define ONE_KNOWN_DW_AT_DESC(name, id, desc)   ONE_KNOWN_DW_AT (name, id)
+      ALL_KNOWN_DW_AT
+    }
+  return NULL;
+}
+
+namespace elfutils
+{
+  template<int key>
+  size_t
+  dwarf::known_enum<key>::prefix_length ()
+  {
+    return 0;
+  }
+
+  template<int key>
+  const char *
+  dwarf::known_enum<key>::identifier (int value)
+  {
+    return NULL;
+  }
+
+#define ALL_KNOWN_ENUM                         \
+  KNOWN_ENUM (accessibility, ACCESS)           \
+  KNOWN_ENUM (encoding, ATE)                   \
+  KNOWN_ENUM (calling_convention, CC)          \
+  KNOWN_ENUM (decimal_sign, DS)                        \
+  KNOWN_ENUM (endianity, END)                  \
+  KNOWN_ENUM (identifier_case, ID)             \
+  KNOWN_ENUM (inline, INL)                     \
+  KNOWN_ENUM (language, LANG)                  \
+  KNOWN_ENUM (ordering, ORD)                   \
+  KNOWN_ENUM (virtuality, VIRTUALITY)          \
+  KNOWN_ENUM (visibility, VIS)
+
+#define ONE_KNOWN_DW_ACCESS(name, id)          KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_ATE(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_CC(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_DS(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_END(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_ID(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_INL(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_LANG(name, id)            KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_LANG_DESC(name, id, desc) KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_ORD(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_INL(name, id)             KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_VIRTUALITY(name, id)      KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_VIS(name, id)             KNOWN_ENUM_CASE (id)
+
+  // Stupid C++ doesn't do [x] = y initializers.
+#define KNOWN_ENUM(attr, enum)                         \
+  template<>                                           \
+  size_t                                               \
+  dwarf::known_enum<DW_AT_##attr>::prefix_length ()    \
+  {                                                    \
+    return sizeof ("DW_" #enum "_") - 1;               \
+  }                                                    \
+  template<>                                           \
+  const char *                                         \
+  dwarf::known_enum<DW_AT_##attr>::identifier (int value)      \
+  {                                                    \
+    switch (value)                                     \
+      {                                                        \
+       ALL_KNOWN_DW_##enum                             \
+      }                                                        \
+    return NULL;                                       \
+  }
+#define KNOWN_ENUM_CASE(id)    case id: return #id;
+
+  ALL_KNOWN_ENUM
+
+  // Not really enum cases, but pretend they are.
+#define ONE_KNOWN_DW_FORM(name, id)            KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_OP(name, id)              KNOWN_ENUM_CASE (id)
+#define ONE_KNOWN_DW_OP_DESC(name, id, desc)   KNOWN_ENUM_CASE (id)
+  KNOWN_ENUM (producer, FORM)
+  KNOWN_ENUM (location, OP)
+
+#undef KNOWN_ENUM
+#undef KNOWN_ENUM_CASE
+};
+
+static const char *
+known_identifier (unsigned int which, unsigned int value)
+{
+  switch (which)
+    {
+# define KNOWN_ENUM(attr, enum)                                                \
+      case DW_AT_##attr:                                               \
+       return dwarf::known_enum<DW_AT_##attr>::identifier (value);
+
+      ALL_KNOWN_ENUM
+
+# undef KNOWN_ENUM
+    }
+
+  return NULL;
+}
+
+static const char *
+known_name (unsigned int which, unsigned int value)
+{
+  switch (which)
+    {
+# define KNOWN_ENUM(attr, enum)                                                \
+      case DW_AT_##attr:                                               \
+       return dwarf::known_enum<DW_AT_##attr>::name (value);
+
+      ALL_KNOWN_ENUM
+
+# undef KNOWN_ENUM
+    }
+
+  return NULL;
+}
+
+template<typename constant>
+static inline const char *
+enum_identifier (const constant &value)
+{
+  return known_identifier (value.which (), value);
+}
+
+template<typename constant>
+static inline const char *
+enum_name (const constant &value)
+{
+  return known_name (value.which (), value);
+}
+
+const char *
+dwarf::dwarf_enum::identifier () const
+{
+  return enum_identifier (*this);
+}
+
+const char *
+dwarf::dwarf_enum::name () const
+{
+  return enum_name (*this);
+}
+
+const char *
+dwarf_data::dwarf_enum::identifier () const
+{
+  return enum_identifier (*this);
+}
+
+const char *
+dwarf_data::dwarf_enum::name () const
+{
+  return enum_name (*this);
+}
+
+template<class value_type>
+static inline std::string
+enum_string (const value_type &value)
+{
+  const char *known = value.name ();
+  return known == NULL ? subr::hex_string (value) : std::string (known);
+}
+
+template<>
+string
+to_string<dwarf::dwarf_enum> (const dwarf::dwarf_enum &value)
+{
+  return enum_string (value);
+}
+
+template<>
+string
+to_string<dwarf_data::dwarf_enum> (const dwarf_data::dwarf_enum &value)
+{
+  return enum_string (value);
+}
diff --git a/libdw/c++/line_info.cc b/libdw/c++/line_info.cc
new file mode 100644 (file)
index 0000000..f8c3ac9
--- /dev/null
@@ -0,0 +1,364 @@
+/* -*- C++ -*- interfaces for libdw.
+   Copyright (C) 2009-2011 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <cassert>
+#include "dwarf"
+
+extern "C"
+{
+#include "libdwP.h"
+}
+
+using namespace elfutils;
+using namespace std;
+
+
+// dwarf::line_info_table
+
+const dwarf::line_info_table
+dwarf::attr_value::line_info () const
+{
+  assert (dwarf_whatattr (thisattr ()) == DW_AT_stmt_list);
+
+  CUDIE (cudie, _m_attr.cu);
+  Dwarf_Lines *lines;
+  size_t n;
+  xif (thisattr (), dwarf_getsrclines (&cudie, &lines, &n) < 0);
+
+  return line_info_table (_m_attr.cu->files);
+}
+
+const dwarf::line_table
+dwarf::line_info_table::lines () const
+{
+  return line_table (_m_files->cu->lines);
+}
+\f
+// dwarf::source_file
+
+const class dwarf::source_file
+dwarf::attr_value::source_file () const
+{
+  switch (what_space ())
+    {
+    case VS_string:
+    case VS_source_file:
+      break;
+    default:
+      throw std::runtime_error ("XXX not a file name");
+    }
+  return dwarf::source_file (_m_attr);
+}
+
+static bool
+stringform (Dwarf_Attribute *attr)
+{
+  if (attr->valp != NULL)
+    switch (dwarf_whatform (attr))
+      {
+      case DW_FORM_string:
+      case DW_FORM_strp:
+       return true;
+      }
+  return false;
+}
+
+/* Returns true if the attribute represents a valid zero udata.
+   This represents "no-file".  */
+static bool
+zero_formudata (Dwarf_Attribute *attr)
+{
+  Dwarf_Word zero;
+  return dwarf_formudata (attr, &zero) == 0 && zero == 0;
+}
+
+/* Mock up a dummy attribute with a special kludge that get_files groks.
+   We use these for source_file objects consed directly from an index
+   rather than from a real attribute.  */
+static inline const Dwarf_Attribute
+dummy_source_file (Dwarf_CU *cu, unsigned int idx)
+{
+  const Dwarf_Attribute dummy = { idx, DW_FORM_indirect, NULL, cu };
+  return dummy;
+}
+
+static bool
+get_files (const Dwarf_Attribute *attr, Dwarf_Files **files, Dwarf_Word *idx)
+{
+  if (attr->valp == NULL)
+    {
+      // Dummy hack created by dummy_source_file, above.
+      assert (attr->form == DW_FORM_indirect);
+      *files = attr->cu->files;
+      *idx = attr->code;
+      return false;
+    }
+
+  CUDIE (cudie, attr->cu);
+  return (dwarf_formudata (const_cast<Dwarf_Attribute *> (attr), idx) < 0
+         || dwarf_getsrcfiles (&cudie, files, NULL) < 0);
+}
+
+Dwarf_Word
+dwarf::source_file::mtime () const
+{
+  if (stringform (thisattr ()) || zero_formudata (thisattr ()))
+    return 0;
+
+  Dwarf_Files *files;
+  Dwarf_Word idx;
+  xif (thisattr (), get_files (thisattr (), &files, &idx));
+
+  Dwarf_Word result;
+  xif (thisattr (), dwarf_filesrc (files, idx, &result, NULL) == NULL);
+  return result;
+}
+
+Dwarf_Word
+dwarf::source_file::size () const
+{
+  if (stringform (thisattr ()) || zero_formudata (thisattr ()))
+    return 0;
+
+  Dwarf_Files *files;
+  Dwarf_Word idx;
+  xif (thisattr (), get_files (thisattr (), &files, &idx));
+
+  Dwarf_Word result;
+  xif (thisattr (), dwarf_filesrc (files, idx, NULL, &result) == NULL);
+  return result;
+}
+
+static const char *no_file = "";
+
+const char *
+dwarf::source_file::name () const
+{
+  const char *result;
+  if (stringform (thisattr ()))
+    result = dwarf_formstring (thisattr ());
+  else if (zero_formudata (thisattr ()))
+    result = no_file;
+  else
+    {
+      Dwarf_Files *files;
+      Dwarf_Word idx;
+      xif (thisattr (), get_files (thisattr (), &files, &idx));
+     result = dwarf_filesrc (files, idx, NULL, NULL);
+    }
+  xif (thisattr (), result == NULL);
+  return result;
+}
+
+static inline string
+plain_string (const char *filename)
+{
+  string result ("\"");
+  result += filename;
+  result += "\"";
+  return result;
+}
+
+string
+dwarf::source_file::to_string () const
+{
+  if (stringform (thisattr ()))
+    {
+      const char *result = dwarf_formstring (thisattr ());
+      xif (thisattr (), result == NULL);
+      return plain_string (result);
+    }
+
+  if (zero_formudata (thisattr ()))
+    return plain_string (no_file);
+
+  Dwarf_Files *files;
+  Dwarf_Word idx;
+  xif (thisattr (), get_files (thisattr (), &files, &idx));
+
+  Dwarf_Word file_mtime;
+  Dwarf_Word file_size;
+  const char *result = dwarf_filesrc (files, idx, &file_mtime, &file_size);
+  xif (thisattr (), result == NULL);
+
+  if (likely (file_mtime == 0) && likely (file_size == 0))
+    return plain_string (result);
+
+  std::ostringstream os;
+  os << "{\"" << result << "," << file_mtime << "," << file_size << "}";
+  return os.str ();
+}
+\f
+// dwarf::file_table
+
+size_t
+dwarf::file_table::size () const
+{
+  return _m_files->nfiles;
+}
+
+const dwarf::source_file
+dwarf::file_table::at (size_t idx) const
+{
+  if (unlikely (idx >= _m_files->nfiles))
+    throw std::out_of_range ("XXX fileidx");
+
+  return dwarf::source_file (dummy_source_file (_m_files->cu, idx));
+}
+
+dwarf::file_table::const_iterator
+dwarf::file_table::find (const source_file &src) const
+{
+  if (src._m_attr.cu->files == _m_files)
+    {
+      // Same table, just cons an iterator using its index.
+      Dwarf_Files *files;
+      Dwarf_Word idx;
+      xif (files->cu, get_files (&src._m_attr, &files, &idx));
+      return const_iterator (*this, idx);
+    }
+
+  // Not from this table, just match on file name.
+  return find (src.name ());
+}
+\f
+// dwarf::line_table
+
+size_t
+dwarf::line_table::size () const
+{
+  return _m_lines->nlines;
+}
+
+const dwarf::line_entry
+dwarf::line_table::at (size_t idx) const
+{
+  if (unlikely (idx >= _m_lines->nlines))
+    throw std::out_of_range ("XXX line table index");
+
+  return line_entry (reinterpret_cast<Dwarf_Line *> (&_m_lines->info[idx]));
+}
+
+dwarf::line_table::const_iterator
+dwarf::line_table::find (Dwarf_Addr address) const
+{
+  size_t idx = _m_lines->nlines; // end ()
+  if (likely (idx > 0))
+    {
+      CUDIE (cudie, _m_lines->info[0].files->cu);
+      Dwarf_Line *line = dwarf_getsrc_die (&cudie, address);
+      if (line != NULL)
+       idx = line - &_m_lines->info[0];
+    }
+  return const_iterator (*this, idx);
+}
+\f
+// dwarf::line_entry
+
+const dwarf::source_file
+dwarf::line_entry::file () const
+{
+  return dwarf::source_file (dummy_source_file (_m_line->files->cu,
+                                               _m_line->file));
+}
+
+#define LINEFIELD(type, method, field)         \
+  type                                         \
+  dwarf::line_entry::method () const           \
+  {                                            \
+    return _m_line->field;                     \
+  }
+
+LINEFIELD (Dwarf_Addr, address, addr) // XXX dwfl?
+LINEFIELD (unsigned int, line, line)
+LINEFIELD (unsigned int, column, column)
+LINEFIELD (bool, statement, is_stmt)
+LINEFIELD (bool, basic_block, basic_block)
+LINEFIELD (bool, end_sequence, end_sequence)
+LINEFIELD (bool, prologue_end, prologue_end)
+LINEFIELD (bool, epilogue_begin, epilogue_begin)
+
+#undef LINEFIELD
+
+bool
+dwarf::line_entry::operator== (const dwarf::line_entry &other) const
+{
+  Dwarf_Line *const a = _m_line;
+  Dwarf_Line *const b = other._m_line;
+
+  if (a == b)
+    return true;
+
+  if (a->addr != b->addr
+      || a->line != b->line
+      || a->column != b->column
+      || a->is_stmt != b->is_stmt
+      || a->basic_block != b->basic_block
+      || a->end_sequence != b->end_sequence
+      || a->prologue_end != b->prologue_end
+      || a->epilogue_begin != b->epilogue_begin)
+    return false;
+
+  // Everything else matches, now have to try the file.
+  if (a->files == b->files)
+    // Same table, just compare indices.
+    return a->file == b->file;
+
+  Dwarf_Word atime;
+  Dwarf_Word asize;
+  const char *aname = dwarf_linesrc (a, &atime, &asize);
+  xif (a->files->cu, aname == NULL);
+  Dwarf_Word btime;
+  Dwarf_Word bsize;
+  const char *bname = dwarf_linesrc (b, &btime, &bsize);
+  xif (b->files->cu, bname == NULL);
+
+  /* The mtime and size only count when encoded as nonzero.
+     If either side is zero, we don't consider the field.  */
+
+  if (atime != btime && atime != 0 && btime != 0)
+    return false;
+
+  if (asize != bsize && asize != 0 && bsize != 0)
+    return false;
+
+  return !strcmp (aname, bname);
+}
+\f
+// dwarf::compile_unit convenience functions.
+
+const dwarf::line_info_table
+dwarf::compile_unit::line_info () const
+{
+  Dwarf_Lines *l;
+  size_t n;
+  xif (dwarf_getsrclines (thisdie (), &l, &n) < 0);
+
+  return line_info_table (thisdie ()->cu->files);
+}
diff --git a/libdw/c++/output-values.cc b/libdw/c++/output-values.cc
new file mode 100644 (file)
index 0000000..199c72b
--- /dev/null
@@ -0,0 +1,64 @@
+/* elfutils::dwarf_output attribute value interfaces.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include "dwarf_output"
+#include "data-values.hh"
+
+#include <typeinfo>
+
+using namespace elfutils;
+
+// Explicit instantiations.
+template class dwarf_data::value<dwarf_output, false>;
+template class dwarf_data::attr_value<dwarf_output, dwarf_output::value>;
+template class dwarf_data::attributes_type<dwarf_output, dwarf_output::value>;
+template class dwarf_data::compile_unit<dwarf_output>;
+template class dwarf_data::compile_units_type<dwarf_output>;
+
+template class dwarf_output::copier<dwarf>;
+template class dwarf_output::copier<dwarf_edit>;
+
+template<>
+std::string
+to_string<dwarf_output::attribute> (const dwarf_output::attribute &attr)
+{
+  return attribute_string (attr);
+}
+
+namespace elfutils
+{
+  template<>
+  std::string to_string (const dwarf_output::debug_info_entry &die)
+  {
+    return die_string (die);
+  }
+};
+
+const dwarf_output::value::value_flag dwarf_output_collector::flag_true (1);
+const dwarf_output::value::value_flag dwarf_output_collector::flag_false (0);
diff --git a/libdw/c++/subr.hh b/libdw/c++/subr.hh
new file mode 100644 (file)
index 0000000..dc4fd4a
--- /dev/null
@@ -0,0 +1,1507 @@
+/* Private helper classes for elfutils -*- C++ -*- interfaces.
+   Copyright (C) 2009-2011 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _ELFUTILS_SUBR_HH
+#define _ELFUTILS_SUBR_HH      1
+
+#include <iterator>
+#include <functional>
+#include <cstring>
+#include <cassert>
+#include <iostream>
+#include <sstream>
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+#include <vector>
+#include <deque>
+#include <stack>
+#include <set>
+#include <algorithm>
+#include <utility>
+#include <stdexcept>
+
+namespace elfutils
+{
+  namespace subr
+  {
+    template<typename container_type, typename op_type>
+    inline void for_each (container_type &container, op_type op)
+    {
+      std::for_each (container.begin (), container.end (), op);
+    }
+
+    template<typename T>
+    struct hash : public T::hasher {};
+
+    template<typename T>
+    static inline size_t hash_this (const T &v)
+    {
+      return hash<T> () (v);
+    }
+
+    template <typename T>
+    inline void hash_combine (size_t &seed, const T &v)
+    {
+      seed ^= hash_this (v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+    }
+
+    template <typename T1, typename T2>
+    inline void hash_combine (size_t &seed, const std::pair<T1,T2> &v)
+    {
+      hash_combine (seed, v.first);
+      hash_combine (seed, v.second);
+    }
+
+    template<typename T, typename B>
+    struct base_hasher : public std::unary_function<T, size_t>
+    {
+      size_t operator () (const T &v) const
+      {
+       return hash_this<B> (v);
+      }
+    };
+
+    template<typename T1, typename T2>
+    struct cast_hasher : public std::unary_function<T1, size_t>
+    {
+      inline size_t operator () (const T1 &x) const
+      {
+       return hash_this (static_cast<T2> (x));
+      }
+    };
+
+    template<typename T, T magic>
+    struct integer_hash : public std::unary_function<T, size_t>
+    {
+      inline size_t operator () (const T &x) const
+      {
+       return x * magic;
+      }
+    };
+    template<>
+    struct hash<unsigned int>
+      : public integer_hash<unsigned int, 0x9e370001U>
+    {};
+    template<>
+    struct hash<uint64_t>
+      : public integer_hash<uint64_t, 0x9e37fffffffc0001ULL>
+    {};
+
+    template<>
+    struct hash<int> : public cast_hasher<int, unsigned int> {};
+    template<>
+    struct hash<uint8_t> : public cast_hasher<uint8_t, unsigned int> {};
+    template<>
+    struct hash<bool> : public cast_hasher<bool, unsigned int> {};
+
+    template<typename T1, typename T2>
+    struct hash<std::pair<T1, T2> >
+      : public std::unary_function<std::pair<T1, T2>, size_t>
+    {
+      inline size_t operator () (const std::pair<T1, T2> &x) const
+      {
+       size_t h = 0;
+       hash_combine (h, x);
+       return h;
+      }
+    };
+
+    template<typename T,
+            void (*combiner) (size_t &, const typename T::value_type &)
+              = hash_combine<typename T::value_type>,
+            size_t initial_hash = 0>
+    class container_hasher
+      : public std::unary_function<T, size_t>
+    {
+    private:
+      struct hasher
+      {
+       size_t &_m_hash;
+       inline explicit hasher (size_t &hash) : _m_hash (hash) {}
+       inline void operator () (const typename T::value_type &x)
+       {
+         return (*combiner) (_m_hash, x);
+       }
+      };
+    public:
+      inline size_t operator () (const T &x) const
+      {
+       size_t hash = initial_hash;
+       for_each (x, hasher (hash));
+       return hash;
+      }
+    };
+
+    template<typename T>
+    struct hash<std::vector<T> >
+      : public container_hasher<std::vector<T> >
+    {
+    };
+
+    template<>
+    struct hash<std::string>
+      : public std::tr1::hash<std::string>
+    {
+    };
+
+    template<class T>
+    struct hashed_hasher
+      : public std::unary_function<T, size_t>
+    {
+      size_t operator () (const T &v) const
+      {
+       return v._m_hash;
+      }
+    };
+
+    template<typename string>
+    struct name_equal : public std::binary_function<const char *, string, bool>
+    {
+      template<typename mystring>
+      inline bool operator () (const mystring &me, const string &you) const
+      {
+       return you == me;
+      }
+    };
+
+    // Explicit specialization.
+    template<>
+    struct name_equal<const char *>
+      : public std::binary_function<const char *, const char *, bool>
+    {
+      bool operator () (const char *me, const char *you) const
+      {
+       return !strcmp (me, you);
+      }
+      template<typename mystring>
+      inline bool operator () (const mystring &me, const char *you) const
+      {
+       return me == you;
+      }
+    };
+
+    static inline std::string hex_string (int code)
+    {
+      std::ostringstream os;
+      os << std::hex << std::showbase << code;
+      return os.str ();
+    }
+
+    template<typename prefix_type, const char *lookup_known (int)>
+    struct known
+    {
+      // The names in the table are the identifiers, with prefix.
+      static inline std::string identifier (int code)
+      {
+       const char *known = lookup_known (code);
+       return known == NULL ? hex_string (code) : std::string (known);
+      }
+
+      // For the pretty name, skip over the prefix.
+      static inline std::string name (int code)
+      {
+       const char *known = lookup_known (code);
+       return (known == NULL ? hex_string (code)
+               : std::string (&known[sizeof (prefix_type) - 1]));
+      }
+    };
+
+    // This is like std::equal_to but for comparing two different types.
+    template<typename t1, typename t2>
+    struct equal_to : public std::binary_function<t1, t2, bool>
+    {
+      inline bool operator () (const t1 &a, const t2 &b) const
+      {
+       return a == b;
+      }
+    };
+
+    /* On a single type, our equal_to is like std::equal_to, but
+       we short-circuit for the case of matching pointers.  */
+    template<typename T>
+    struct equal_to<T, T> : public std::binary_function<T, T, bool>
+    {
+      inline bool operator () (const T &a, const T &b) const
+      {
+       return &a == &b || a == b;
+      }
+    };
+
+    template<typename t1, typename t2, typename pred_type>
+    class deref
+      : public std::binary_function<typename t1::const_iterator,
+                                   typename t2::const_iterator,
+                                   bool>
+    {
+    private:
+      pred_type _m_pred;
+
+    public:
+      inline deref ()
+       : _m_pred ()
+      {}
+
+      inline deref (const pred_type &pred)
+       : _m_pred (pred)
+      {}
+
+      inline bool operator () (const typename t1::const_iterator &a,
+                              const typename t2::const_iterator &b) const
+      {
+       return _m_pred (*a, *b);
+      }
+    };
+
+    template<typename t1, typename t2>
+    struct deref_equal_to
+      : public deref<t1, t2,
+                    equal_to<typename t1::value_type, typename t2::value_type>
+                    >
+    {};
+
+    template<typename iter1, typename iter2, typename pred_type>
+    inline bool container_equal (iter1 &first1, const iter1 &last1,
+                                iter2 &first2, const iter2 &last2,
+                                pred_type pred)
+    {
+      while (first1 != last1)
+       {
+         if (first2 == last2 || !pred (first1, first2))
+           return false;
+         ++first1;
+         ++first2;
+       }
+      return first2 == last2;
+    }
+
+    template<typename t1, typename t2, typename pred_type>
+    inline bool container_equal (const t1 &a, const t2 &b, pred_type pred,
+                                typename t1::size_type skip = 0)
+    {
+      typename t1::const_iterator first1 = a.begin ();
+      typename t1::const_iterator last1 = a.end ();
+      typename t2::const_iterator first2 = b.begin ();
+      typename t2::const_iterator last2 = b.end ();
+      while (skip-- > 0)
+       {
+         if (first1 == last1)
+           return first2 == last2;
+         if (first2 == last2)
+           return first1 == last1;
+         ++first1;
+         ++first2;
+       }
+      return container_equal (first1, last1, first2, last2, pred);
+    }
+
+    template<typename t1, typename t2>
+    inline bool container_equal (const t1 &a, const t2 &b)
+    {
+      return container_equal (a, b, deref_equal_to<t1, t2> ());
+    }
+
+    template<typename t1, typename t2>
+    inline bool container_tail_equal (const t1 &a, const t2 &b,
+                                     typename t1::size_type skip = 0)
+    {
+      return container_equal (a, b, deref_equal_to<t1, t2> (), skip);
+    }
+
+    template<typename iter>
+    inline typename iter::difference_type length (iter i, const iter &end)
+    {
+      typename iter::difference_type n = 0;
+      while (i != end)
+       ++i, ++n;
+      return n;
+    }
+
+    template<typename array, typename element = typename array::value_type>
+    class indexed_iterator
+      : public std::iterator<std::random_access_iterator_tag,
+                            typename array::value_type,
+                            typename array::difference_type>
+    {
+    private:
+      typedef typename array::size_type index_type;
+
+      array _m_contents;
+      index_type _m_idx;
+
+    public:
+      indexed_iterator (array contents, index_type idx)
+       : _m_contents (contents), _m_idx (idx) {}
+      indexed_iterator (const indexed_iterator &i)
+       : _m_contents (i._m_contents), _m_idx (i._m_idx) {}
+
+      inline element operator* () const
+      {
+       return _m_contents[_m_idx];
+      }
+      template<typename elt>
+      inline elt operator* () const
+      {
+       return _m_contents[_m_idx];
+      }
+      template<typename elt>
+      inline elt *operator-> () const
+      {
+       return &_m_contents[_m_idx];
+      }
+      template<typename elt>
+      inline elt operator[] (const index_type &n) const
+      {
+       return _m_contents[_m_idx + n];
+      }
+
+      inline indexed_iterator operator+ (const indexed_iterator &i) const
+      {
+       return indexed_iterator (_m_contents, _m_idx + i._m_idx);
+      }
+      inline indexed_iterator operator+ (const typename array::difference_type
+                                        &i) const
+      {
+       return indexed_iterator (_m_contents, _m_idx + i);
+      }
+      inline typename array::difference_type
+      operator- (const indexed_iterator &i) const
+      {
+       return _m_idx - i._m_idx;
+      }
+
+      inline bool operator== (const indexed_iterator &i) const
+      {
+       return _m_idx == i._m_idx;
+      }
+      inline bool operator!= (const indexed_iterator &i) const
+      {
+       return _m_idx != i._m_idx;
+      }
+      inline bool operator< (const indexed_iterator &i) const
+      {
+       return _m_idx < i._m_idx;
+      }
+      inline bool operator> (const indexed_iterator &i) const
+      {
+       return _m_idx > i._m_idx;
+      }
+      inline bool operator<= (const indexed_iterator &i) const
+      {
+       return _m_idx <= i._m_idx;
+      }
+      inline bool operator>= (const indexed_iterator &i) const
+      {
+       return _m_idx >= i._m_idx;
+      }
+
+      inline indexed_iterator &operator= (const indexed_iterator &i)
+      {
+       _m_idx = i._m_idx;
+       return *this;
+      }
+      inline indexed_iterator &operator+= (const index_type &n)
+      {
+       _m_idx += n;
+       return *this;
+      }
+      inline indexed_iterator &operator-= (const index_type &n)
+      {
+       _m_idx -= n;
+       return *this;
+      }
+
+      inline indexed_iterator &operator++ () // prefix
+      {
+       ++_m_idx;
+       return *this;
+      }
+      inline indexed_iterator operator++ (int) // postfix
+      {
+       return indexed_iterator (_m_contents, _m_idx++);
+      }
+      inline indexed_iterator &operator-- () // prefix
+      {
+       --_m_idx;
+       return *this;
+      }
+      inline indexed_iterator operator-- (int) // postfix
+      {
+       return indexed_iterator (_m_contents, _m_idx--);
+      }
+    };
+
+    // Pair of some value and its precomputed hash.
+    template<typename T>
+    class hashed_value
+      : public std::pair<size_t, const T>
+    {
+    private:
+      typedef std::pair<size_t, const T> _base;
+
+    public:
+      typedef T value_type;
+
+      struct hasher
+       : public std::unary_function<hashed_value, size_t>
+      {
+       inline size_t operator () (const hashed_value &v) const
+       {
+         return v.first;
+       }
+      };
+
+      hashed_value (const value_type &v)
+       : _base (hash_this (v), v) {}
+      hashed_value (const hashed_value &v)
+       : _base (v.first, v.second) {}
+
+      bool operator== (const hashed_value &other) const
+      {
+       return other.first == this->first && other.second == this->second;
+      }
+    };
+
+    // Set of hashed_value's.
+    template<typename value_type>
+    class value_set
+      : public std::tr1::unordered_set<hashed_value<value_type>,
+                                      struct hashed_value<value_type>::hasher>
+    {
+    public:
+      typedef hashed_value<value_type> hashed_value_type;
+
+    private:
+      typedef std::tr1::unordered_set<hashed_value_type,
+                                     struct hashed_value_type::hasher> _base;
+
+    public:
+      const value_type *add (const value_type &v)
+      {
+       std::pair<class _base::iterator, bool> p
+         = _base::insert (hashed_value_type (v));
+       if (p.second)
+         {
+           // XXX hook for collection: abbrev building, etc.
+         }
+       return &p.first->second;
+      };
+
+      template<typename input>
+      const value_type *add (const input &v)
+      {
+       return add (value_type (v));
+      }
+
+      template<typename input, typename arg_type>
+      const value_type *add (const input &v, arg_type &arg)
+      {
+       return add (value_type (v, arg));
+      }
+    };
+
+    // A container of hashed_value's that itself acts like a hashed_value.
+    // The parameter class should be a std::container<hashed_value<something>>.
+    template<typename container>
+    class hashed_container : public container
+    {
+    private:
+      typedef container _base;
+      typedef typename container::value_type elt_type;
+
+    public:
+      typedef typename elt_type::value_type value_type;
+
+    protected:
+      size_t _m_hash;
+
+      inline void set_hash ()
+      {
+       _m_hash = container_hasher<container> () (*this);
+      }
+
+    public:
+      friend class hashed_hasher<hashed_container>;
+      typedef hashed_hasher<hashed_container> hasher;
+
+      template<typename iterator>
+      hashed_container (iterator first, iterator last)
+       : _base (first, last)
+      {
+       set_hash ();
+      }
+
+      template<typename other_container>
+      hashed_container (const other_container &other)
+       : _base (other.begin (), other.end ())
+      {
+       set_hash ();
+      }
+
+      bool operator== (const hashed_container &other) const
+      {
+       return (other._m_hash == _m_hash &&
+               other.size () == _base::size ()
+               && std::equal (_base::begin (), _base::end (), other.begin (),
+                              equal_to<elt_type, elt_type> ()));
+      }
+    };
+
+    // A vector of hashed_value's that itself acts like a hashed_value.
+    template<typename value_type>
+    struct hashed_vector
+      : public hashed_container<std::vector<hashed_value<value_type> > >
+    {};
+
+    // An unordered_map of hashed_value's that itself acts like a hashed_value.
+    template<typename key_type, typename value_type>
+    class hashed_unordered_map
+      : public hashed_container<std::tr1::unordered_map<
+                                 key_type,
+                                 hashed_value<value_type>,
+                                 class hashed_value<value_type>::hasher>
+                               >
+    {};
+#if 0
+    template<typename key_type, typename value_type>
+    class hashed_unordered_map
+      : public std::tr1::unordered_map<key_type,
+                                      hashed_value<value_type>,
+                                      class hashed_value<value_type>::hasher>
+    {
+    private:
+      typedef std::tr1::unordered_map<key_type,
+                                     hashed_value<value_type>,
+                                     class hashed_value<value_type>::hasher>
+      _base;
+
+      size_t _m_hash;
+
+      inline void set_hash ()
+      {
+       struct hashit
+       {
+         size_t &_m_hash;
+         hashit (size_t &h) : _m_hash (h) {}
+
+         inline void operator () (const typename _base::value_type &p)
+         {
+           hash_combine (_m_hash, hash_this (p.first));
+           hash_combine (_m_hash, p.second.first);
+         }
+       };
+       for_each (static_cast<_base &> (*this), hashit (_m_hash));
+      }
+
+    public:
+      friend class hashed_hasher<hashed_unordered_map>;
+      typedef hashed_hasher<hashed_unordered_map> hasher;
+
+      template<typename iterator>
+      hashed_unordered_map (iterator first, iterator last)
+       : _base (first, last), _m_hash (0)
+      {
+       set_hash ();
+      }
+
+      template<typename container>
+      hashed_unordered_map (const container &other)
+       : _base (other.begin (), other.end ()), _m_hash (0)
+      {
+       set_hash ();
+      }
+    };
+#endif
+
+    template<typename T>
+    class auto_ref
+    {
+    private:
+      T *_m_ptr;
+
+    public:
+      auto_ref (const T &other)
+       : _m_ptr (&other)
+      {}
+
+      inline operator T& () const
+      {
+       return *_m_ptr;
+      }
+
+      auto_ref (const auto_ref<T> &other)
+       : _m_ptr (other._m_ptr)
+      {}
+
+      template<typename other>
+      inline bool operator== (const auto_ref<other> &x) const
+      {
+       return *_m_ptr == static_cast<other &> (x);
+      }
+      template<typename other>
+      inline bool operator== (const other &x) const
+      {
+       return *_m_ptr == x;
+      }
+      template<typename other>
+      inline bool operator!= (const other &x) const
+      {
+       return !(*this == x);
+      }
+    };
+
+    /* A wrapped_input_iterator is like an input::const_iterator,
+       but *i returns wrapper (*i) instead; wrapper returns element
+       (or const element & or something).  */
+    template<typename input, class wrapper,
+            typename element = typename wrapper::result_type>
+    class wrapped_input_iterator : public input::const_iterator
+    {
+    private:
+      typedef typename input::const_iterator _base;
+
+      wrapper _m_wrapper;
+
+    public:
+      typedef element value_type;
+
+      inline wrapped_input_iterator ()
+       : _base ()
+      {}
+
+      template<typename arg_type>
+      inline wrapped_input_iterator (const _base &i, const arg_type &arg)
+       : _base (static_cast<_base> (i)), _m_wrapper (arg)
+      {}
+
+      inline wrapped_input_iterator (const wrapped_input_iterator &i)
+       : _base (static_cast<_base> (i)), _m_wrapper (i._m_wrapper)
+      {}
+
+      inline typename wrapper::result_type operator* () const
+      {
+       return _m_wrapper (_base::operator* ());
+      }
+
+      inline element *operator-> () const
+      {
+       return &(_m_wrapper (_base::operator* ()));
+      }
+
+      inline wrapped_input_iterator &operator++ () // prefix
+      {
+       _base::operator++ ();
+       return *this;
+      }
+      inline wrapped_input_iterator operator++ (int) // postfix
+      {
+       wrapped_input_iterator pre = *this;
+       ++*this;
+       return pre;
+      }
+      inline wrapped_input_iterator &operator-- () // prefix
+      {
+       _base::operator-- ();
+       return *this;
+      }
+      inline wrapped_input_iterator operator-- (int) // postfix
+      {
+       wrapped_input_iterator pre = *this;
+       --*this;
+       return pre;
+      }
+
+      inline const _base &base () const
+      {
+       return *this;
+      }
+
+      inline _base &base ()
+      {
+       return *this;
+      }
+
+      template<typename container = input>
+      struct copy
+      {
+       template<typename arg_type>
+       inline container operator () (const input &in,
+                                     const arg_type &arg = arg_type ())
+       {
+         return container (wrapped_input_iterator (in.begin (), arg),
+                           wrapped_input_iterator (in.end (), arg));
+       }
+      };
+    };
+
+    /* A wrapped_input_container provides begin and end methods that
+       wrap the real container's iterators with wrapped_input_iterator.  */
+    template<typename input, class wrapper,
+            typename element = typename wrapper::result_type>
+    class wrapped_input_container
+    {
+    private:
+      const input &_m_container;
+      wrapper _m_wrapper;
+
+    public:
+      typedef wrapped_input_iterator<input, wrapper, element> const_iterator;
+      typedef const_iterator iterator;
+
+      template<typename arg_type>
+      inline wrapped_input_container (const input &container,
+                                     const arg_type &arg)
+       : _m_container (container), _m_wrapper (arg)
+      {}
+
+      inline const_iterator begin () const
+      {
+       return const_iterator (_m_container.begin (), _m_wrapper);
+      }
+
+      inline const_iterator end () const
+      {
+       return const_iterator (_m_container.end (), _m_wrapper);
+      }
+
+      static inline bool ordered ()
+      {
+       return input::ordered ();
+      }
+    };
+
+    /* 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).  */
+    template<typename input, typename output, typename arg_type>
+    struct argifier
+      : public std::unary_function<typename input::const_iterator,
+                                  typename output::iterator> // not really
+    {
+      typedef typename input::const_iterator inny;
+      typedef typename output::iterator outty;
+      typedef typename input::value_type inlet;
+      typedef typename output::value_type outlet;
+
+      /* Wrapper worker passed to wrapped_input_iterator.
+        This object holds the collector pointer.  */
+      struct maker
+       : public std::unary_function<inlet, outlet>
+      {
+       const arg_type _m_arg;
+
+       inline maker (const arg_type &c)
+         : _m_arg (c)
+       {}
+
+       inline maker (const maker &m)
+         : _m_arg (m._m_arg)
+       {}
+
+       inline outlet operator () (const inlet &x) const
+       {
+         return outlet (x, _m_arg);
+       }
+      } _m_maker;
+
+      explicit inline argifier (const arg_type &c)
+       : _m_maker (c)
+      {}
+
+      typedef wrapped_input_iterator<input, maker> result_type;
+
+      inline result_type operator () (const inny &i)
+      {
+       return result_type (i, _m_maker);
+      }
+    };
+
+    template<typename input, typename output, typename arg_type>
+    static inline typename argifier<input, output, arg_type>::result_type
+    argify (const typename input::const_iterator &in, const arg_type &arg)
+    {
+      return argifier<input, output, arg_type> (arg) (in);
+    }
+
+    template<typename input, typename output, typename arg_type>
+    struct argifier2nd
+      : public std::unary_function<typename input::const_iterator,
+                                  typename output::iterator>
+    {
+      typedef typename input::const_iterator inny;
+      typedef typename output::iterator outty;
+      typedef typename input::value_type inlet;
+      typedef typename output::value_type outlet;
+
+      /* Wrapper worker passed to wrapped_input_iterator.
+        This object holds the collector pointer.  */
+      struct pair_maker
+       : public argifier<input, output, arg_type>::maker
+      {
+       typedef typename argifier<input, output, arg_type>::maker maker;
+
+       inline pair_maker (const arg_type &c) : maker (c) {}
+       inline pair_maker (const pair_maker &m) : maker (m) {}
+
+       inline outlet operator () (const inlet &x) const
+       {
+         return std::make_pair (x.first,
+                                typename outlet::second_type (x.second,
+                                                              this->_m_arg));
+       }
+      } _m_maker;
+
+      explicit inline argifier2nd (const arg_type &c)
+       : _m_maker (c)
+      {}
+
+      typedef wrapped_input_iterator<input, pair_maker> const_iterator;
+
+      inline const_iterator operator () (const inny &i)
+      {
+       return const_iterator (i, _m_maker);
+      }
+    };
+
+    template<typename input, typename output, typename arg_type>
+    static inline typename argifier2nd<input, output, arg_type>::const_iterator
+    argify2nd (const typename input::const_iterator &in, const arg_type &arg)
+    {
+      return argifier2nd<input, output, arg_type> (arg) (in);
+    }
+
+    /* A guard object is intended to be ephemeral, existing solely to be
+       destroyed in exception paths where it was not cleared explicitly.
+       In that case, it calls tracker::soiled ().
+
+       For convenience, it can be constructed from a tracker reference or
+       pointer, or default-constructed and then filled.  It's fillable by
+       calling the guard object as a function, passing it the tracker
+       reference or pointer, which it passes through on return:
+
+              guard<tracker> g;
+              use (g (t));
+              g.clear ();
+
+       This first calls T.start ().  When G goes out of scope,
+       it calls T.abort () iff G.clear () was never called.  */
+
+    template<typename tracker>
+    class guard
+    {
+    private:
+      tracker *_m_tracker;
+
+      inline void start ()
+      {
+       _m_tracker->start ();
+      }
+
+    public:
+      inline guard (tracker *t)
+       : _m_tracker (t)
+      {
+       start ();
+      }
+
+      inline guard (tracker &t)
+       : _m_tracker (&t)
+      {
+       start ();
+      }
+
+      inline guard ()
+       : _m_tracker (NULL)
+      {}
+
+      inline tracker *operator () (tracker *t)
+      {
+       _m_tracker = t;
+       start ();
+       return t;
+      }
+
+      inline tracker &operator () (tracker &t)
+      {
+       _m_tracker = &t;
+       start ();
+       return t;
+      }
+
+      inline operator tracker * () const
+      {
+       return _m_tracker;
+      }
+
+      inline operator tracker & () const
+      {
+       return *_m_tracker;
+      }
+
+      inline void clear ()
+      {
+       _m_tracker = NULL;
+      }
+
+      inline ~guard ()
+      {
+       if (unlikely (_m_tracker != NULL))
+         _m_tracker->abort ();
+      }
+    };
+
+    struct nothing
+    {
+    };
+
+    // Class instead of function so it can be a friend.
+    struct create_container
+    {
+      struct setter
+      {
+       template<typename in_iter, typename out_iter, typename arg_type>
+       inline void operator () (const out_iter &out, const in_iter &in,
+                                bool, arg_type arg) const
+       {
+         out->set (*in, arg);
+       }
+      };
+
+      template<typename container, typename input, typename arg_type,
+              typename hook_type = const setter>
+      inline create_container (container *me, const input &other,
+                              arg_type &arg, hook_type &hook = hook_type ())
+       {
+         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 ();
+             const typename input::const_iterator here = in++;
+             last = in == other.end ();
+             hook (out, here, last, arg);
+           }
+       }
+    };
+
+    template<typename T>
+    struct is : public std::equal_to<T>
+    {
+      bool operator () (const T &a, const T &b) const
+      {
+       return a.is (b);
+      }
+    };
+
+    template<typename T>
+    struct is<T *> : public std::equal_to<T *>
+    {
+      bool operator () (const T *a, const T *b) const
+      {
+       return a == b || a->is (*b);
+      }
+    };
+
+#if 0                          // unused
+    template<typename T1, typename T2>
+    struct is<std::pair<T1, T2> > : public std::equal_to<std::pair<T1, T2> >
+    {
+      bool operator () (const std::pair<T1, T2> &a,
+                       const std::pair<T1, T2> &b) const
+      {
+       return (is<T1> () (a.first, b.first)
+               && is<T2> () (a.second, b.second));
+      }
+    };
+#endif
+
+    template<typename T>
+    struct identity_set
+      : public std::tr1::unordered_set<T, typename T::hasher, is<T> >
+    {
+    };
+
+    template<typename key_type, typename mapped_type>
+    struct identity_map
+      : public std::tr1::unordered_map<key_type, mapped_type,
+                                      typename key_type::hasher,
+                                      is<key_type> >
+    {};
+
+    /* This is like an unordered_set, but the equality predicate cannot
+       be fixed statically.  Instead, each insertion call must pass in
+       the specific predicate to match against existing elements for
+       that insertion.  */
+    template<typename T, typename hasher_type = hash<T> >
+    class dynamic_equality_set
+    {
+    public:
+      typedef T value_type;
+      typedef size_t hash_type;
+      typedef std::deque<T> bucket_type;
+
+    private:
+      typedef std::tr1::unordered_map<hash_type, bucket_type> map_type;
+
+      map_type _m_map;
+      hasher_type _m_hasher;
+
+    public:
+      template<typename match_type>
+      inline const value_type *
+      add (const value_type &candidate, match_type &match)
+      {
+       bucket_type &bucket = _m_map[_m_hasher (candidate)];
+
+       for (typename bucket_type::iterator i = bucket.begin ();
+            i != bucket.end ();
+            ++i)
+         {
+           const value_type &elt = *i;
+           if (match (elt, candidate))
+             // We have a winner!
+             return &elt;
+         }
+
+       // No matches: new element.
+       bucket.push_back (candidate);
+       return &(bucket.back ());
+      }
+
+      // Unclear why you didn't just use a normal identity_set then!
+      inline const value_type *add (const value_type &candidate)
+      {
+       is<value_type> equalator;
+       return add (candidate, equalator);
+      }
+
+      template<typename reporter>
+      inline void hash_stats (std::ostream &out, const char *name,
+                             const reporter &report_collisions) const
+      {
+       size_t collisions = 0;
+       size_t empty_buckets = 0;
+       size_t total = 0;
+       size_t largest = 0;
+       for (typename map_type::const_iterator i = _m_map.begin ();
+            i != _m_map.end ();
+            ++i)
+         {
+           if (i->second.empty ())
+             ++empty_buckets;
+           else
+             {
+               size_t n = i->second.size () - 1;
+               collisions += n;
+               if (n > 0)
+                 report_collisions (i->first, i->second);
+             }
+           if (i->second.size () > largest)
+             largest = i->second.size ();
+           total += i->second.size ();
+         }
+       out << name << ": " << total << ", "
+           << collisions << " collisions, "
+           << largest << " in largest bucket";
+       if (empty_buckets > 0)
+         out << ", " << empty_buckets << " empty buckets\n";
+       else
+         out << "\n";
+      }
+    };
+
+    template<typename set_type>
+    inline void container_hash_stats (std::ostream &out, const char *name,
+                                     const set_type &set)
+    {
+      std::set<size_t> hashes;
+      for (typename set_type::const_iterator i = set.begin ();
+          i != set.end ();
+          ++i)
+       hashes.insert (hash_this (*i));
+      out << name << ": " << set.size () << ", "
+         << hashes.size () << " hashes = "
+         << (set.size () - hashes.size ()) << " collisions\n";
+    }
+
+    /* sharing_stack<T> is like std::stack<T>, but copies share list
+       tails to reduce the memory footprint.  Any non-const call to the
+       top method copies the top element so it's no longer shared.
+       So be sure to use const calls for any non-modifying access.
+       The top_const method is a short-hand for a const access to
+       a non-const container.  */
+    template<typename T>
+    class sharing_stack
+    {
+    public:
+      typedef T value_type;
+      typedef size_t size_type;
+      typedef value_type &reference;
+      typedef const value_type &const_reference;
+
+    protected:
+      class element
+      {
+      private:
+       friend class sharing_stack;
+       value_type _m_value;
+       element *_m_next;
+       unsigned int _m_count;
+
+       inline element &operator= (const element &)
+       {
+         throw std::logic_error ("cannot assign");
+       }
+
+       inline element ()
+       {
+         throw std::logic_error ("cannot default-construct");
+       }
+
+      public:
+       inline unsigned int count () const
+       {
+         return _m_count;
+       }
+
+       inline operator value_type & ()
+       {
+         return _m_value;
+       }
+
+       inline operator const value_type & () const
+       {
+         return _m_value;
+       }
+
+       inline element (const value_type &value, element *tail)
+         : _m_value (value), _m_next (tail), _m_count (1)
+       {
+         if (_m_next != NULL)
+           _m_next->acquire ();
+       }
+
+       inline element (const element &other)
+         : _m_value (other._m_value), _m_next (other._m_next), _m_count (1)
+       {
+         if (_m_next != NULL)
+           _m_next->acquire ();
+       }
+
+       inline ~element ()
+       {
+         if (_m_next != NULL)
+           _m_next->release ();
+       }
+
+       inline void acquire ()
+       {
+         assert (_m_count > 0);
+         ++_m_count;
+       }
+
+       inline void release ()
+       {
+         assert (_m_count > 0);
+         if (--_m_count == 0)
+           delete this;
+       }
+
+       inline const element *next () const
+       {
+         return _m_next;
+       }
+
+       inline bool shared () const
+       {
+         assert (_m_count > 0);
+         return _m_count > 1;
+       }
+      };
+
+      element *_m_head;
+      size_type _m_size;
+
+      inline void init (element *head, size_type n)
+      {
+       if (head == NULL)
+         assert (n == 0);
+       else
+         head->acquire ();
+       _m_head = head;
+       _m_size = n;
+      }
+
+    public:
+      inline void clear ()
+      {
+       if (_m_head == NULL)
+         assert (_m_size == 0);
+       else
+         {
+           _m_head->release ();
+           _m_head = NULL;
+           _m_size = 0;
+         }
+      }
+
+      inline bool empty () const
+      {
+       return _m_head == NULL;
+      }
+
+      inline size_type size () const
+      {
+       return _m_size;
+      }
+
+      inline void push (const value_type &value)
+      {
+       element *old = _m_head;
+       _m_head = new element (value, _m_head);
+       ++_m_size;
+       if (old != NULL)
+         old->release ();
+      }
+
+      inline void pop ()
+      {
+       --_m_size;
+       element *tail = _m_head->_m_next;
+       if (tail != NULL)
+         tail->acquire ();
+       _m_head->release ();
+       _m_head = tail;
+      }
+
+      inline const value_type &top () const
+      {
+       assert (_m_head != NULL);
+       return *_m_head;
+      }
+
+      inline const value_type &const_top () const
+      {
+       return top ();
+      }
+
+      inline value_type &top ()
+      {
+       element *prev = _m_head;
+       if (prev->shared ())
+         {
+           _m_head = new element (*prev);
+           prev->release ();
+         }
+       assert (!_m_head->shared ());
+       return *_m_head;
+      }
+
+      inline sharing_stack ()
+       : _m_head (NULL), _m_size (0)
+      {}
+
+      inline sharing_stack (const sharing_stack &other)
+      {
+       init (other._m_head, other._m_size);
+      }
+
+      inline ~sharing_stack ()
+      {
+       clear ();
+      }
+
+      inline sharing_stack &operator= (const sharing_stack &other)
+      {
+       if (&other != this)
+         {
+           clear ();
+           init (other._m_head, other._m_size);
+         }
+       return *this;
+      }
+
+      inline void swap (sharing_stack &other)
+      {
+       std::swap (_m_head, other._m_head);
+       std::swap (_m_size, other._m_size);
+      }
+
+      class const_reverse_iterator
+       : public std::iterator<std::input_iterator_tag, value_type>
+      {
+      private:
+       const element *_m_elt;
+
+       friend class sharing_stack;
+       inline const_reverse_iterator (const element *elt)
+         : _m_elt (elt)
+       {}
+
+      public:
+       inline const value_type &operator* () const
+       {
+         return *_m_elt;
+       }
+
+       inline bool operator== (const const_reverse_iterator &other) const
+       {
+         return _m_elt == other._m_elt;
+       }
+       inline bool operator!= (const const_reverse_iterator &other) const
+       {
+         return !(*this == other);
+       }
+
+       inline const_reverse_iterator &operator++ () // prefix
+       {
+         _m_elt = _m_elt->next ();
+         return *this;
+       }
+       inline const_reverse_iterator operator++ (int) // postfix
+       {
+         const const_reverse_iterator old = *this;
+         ++*this;
+         return old;
+       }
+      };
+
+      inline const_reverse_iterator rbegin () const
+      {
+       return const_reverse_iterator (_m_head);
+      }
+
+      inline const_reverse_iterator rend () const
+      {
+       return const_reverse_iterator (NULL);
+      }
+
+      template<typename other_value_type, typename pred_type>
+      inline bool equal (const sharing_stack<other_value_type> &other,
+                        pred_type &pred, size_type skip = 0) const
+      {
+       if (other.size () != size ())
+         return false;
+
+       const_reverse_iterator a = rbegin ();
+       typename sharing_stack<other_value_type>::const_reverse_iterator b
+         = other.rbegin ();
+
+       std::advance (a, skip);
+       std::advance (b, skip);
+
+       return std::equal (a, rend (), b, pred);
+      }
+
+      template<typename other_value_type>
+      inline bool operator== (const sharing_stack<other_value_type> &other)
+       const
+      {
+       equal_to<value_type, other_value_type> equalator;
+       return equal (other, equalator);
+      }
+
+      template<typename other_value_type>
+      inline bool operator!= (const sharing_stack<other_value_type> &other)
+       const
+      {
+       return !(*this == other);
+      }
+    };
+
+    // Compatible with sharing_stack, but actually a std::stack.
+    template<typename T, typename container_type = std::deque<T> >
+    struct stackish
+      : public std::stack<T, container_type>
+    {
+      inline const T &const_top () const
+      {
+       return this->top ();
+      }
+
+      inline void clear ()
+      {
+       this->c.clear ();
+      }
+
+      typedef typename container_type::const_reverse_iterator
+      const_reverse_iterator;
+
+      inline const_reverse_iterator rbegin () const
+      {
+       return this->c.rbegin ();
+      }
+
+      inline const_reverse_iterator rend () const
+      {
+       return this->c.rend ();
+      }
+
+      template<typename other_value_type, typename other_container_type,
+              typename pred_type>
+      inline bool
+      equal (const stackish<other_value_type, other_container_type> &other,
+            pred_type &pred, typename container_type::size_type skip = 0) const
+      {
+       if (other.size () != this->size ())
+         return false;
+
+       typename container_type::const_reverse_iterator a = this->rbegin ();
+       typename other_container_type::const_reverse_iterator b
+         = other.rbegin ();
+
+       std::advance (a, skip);
+       std::advance (b, skip);
+
+       return std::equal (a, this->rend (), b, pred);
+      }
+    };
+
+    /* This is a dummy you can template/syntactically use in
+       place of std::cout et al for disabled debugging spew.  */
+    struct nostream
+    {
+      inline const nostream &
+      operator<< (std::ostream &(*) (std::ostream &)) const
+      {
+       return *this;
+      }
+
+      template<typename arg>
+      inline const nostream &
+      operator<< (const arg &) const
+      {
+       return *this;
+      }
+    };
+  };
+};
+
+#endif // <elfutils/subr.hh>
diff --git a/libdw/c++/values.cc b/libdw/c++/values.cc
new file mode 100644 (file)
index 0000000..335074f
--- /dev/null
@@ -0,0 +1,710 @@
+/* -*- C++ -*- interfaces for libdw.
+   Copyright (C) 2009-2011 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   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 copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+#include <cassert>
+#include "dwarf"
+#include "dwarf_edit"
+#include "dwarf_output"
+#include "data-values.hh"
+
+extern "C"
+{
+#include "libdwP.h"
+}
+
+using namespace elfutils;
+using namespace std;
+
+#include "dwarf-knowledge.cc"
+\f
+// dwarf::attr_value disambiguation and dispatch.
+
+/* For ambiguous the forms, we need to look up the expected
+   value spaces for this attribute to disambiguate.
+*/
+dwarf::value_space
+dwarf::attr_value::what_space () const
+{
+  const uint_fast16_t version = _m_attr.cu->version;
+  unsigned int expected = expected_value_space (dwarf_whatattr (thisattr ()),
+                                               _m_tag);
+  unsigned int possible = 0;
+  switch (dwarf_whatform (thisattr ()))
+    {
+    case DW_FORM_flag:
+    case DW_FORM_flag_present:
+      return VS_flag;
+
+    case DW_FORM_addr:
+      return VS_address;
+
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      /* Location expression in DWARF 3, or target constant.  */
+      possible = VS(constant);
+      if (version >= 4)
+       break;
+      possible |= VS(location);
+      if ((expected & possible) != possible)
+       /* When both are expected, a block is a location expression.  */
+       break;
+      /* Fall through.  */
+
+    case DW_FORM_exprloc:
+      return VS_location;
+
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_udata:
+    case DW_FORM_sdata:
+      /* Target constant, known DWARF constant.  */
+      possible = (VS(dwarf_constant) | VS(constant)
+                 | VS(source_file) | VS(source_line) | VS(source_column));
+      break;
+
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+      // If a constant is not expected, these can be *ptr instead in DWARF 3.
+      possible = (VS(dwarf_constant) | VS(constant)
+                 | VS(source_file) | VS(source_line) | VS(source_column));
+      if (version >= 4 || (expected & possible))
+       break;
+
+    case DW_FORM_sec_offset:
+      possible = VS(location) | VS(lineptr) | VS(macptr) | VS(rangelistptr);
+      break;
+
+    case DW_FORM_string:
+    case DW_FORM_strp:
+      /* Identifier, file name, or string.  */
+      possible = VS(identifier) | VS(source_file) | VS(string);
+      break;
+
+    case DW_FORM_ref_addr:
+    case DW_FORM_ref1:
+    case DW_FORM_ref2:
+    case DW_FORM_ref4:
+    case DW_FORM_ref8:
+    case DW_FORM_ref_udata:
+    case DW_FORM_ref_sig8:
+      return VS_reference;
+
+    default:
+      throw std::runtime_error ("XXX bad form");
+    }
+
+  if (unlikely ((expected & possible) == 0))
+    {
+      // Otherwise we don't know enough to treat it robustly.
+      throw std::runtime_error ("XXX ambiguous form in unexpected attribute");
+    }
+
+  const int first = ffs (expected & possible) - 1;
+  if (likely ((expected & possible) == (1U << first)))
+    return static_cast<value_space> (first);
+
+  throw std::runtime_error ("XXX ambiguous form");
+}
+
+static string
+hex_string (Dwarf_Word value, const char *before = "", const char *after = "")
+{
+  std::ostringstream os;
+  os << std::hex << std::showbase << before << value << after;
+  return os.str ();
+}
+
+static string
+dec_string (Dwarf_Word value, const char *before = "", const char *after = "")
+{
+  std::ostringstream os;
+  os << before << value << after;
+  return os.str ();
+}
+
+static string
+addr_string (Dwarf_Addr value)
+{
+  // XXX some hook for symbol resolver??
+  return hex_string (value);
+}
+
+static inline string
+plain_string (const char *filename)
+{
+  return string ("\"") + filename + "\"";
+}
+
+static inline string
+plain_string (const string &filename)
+{
+  return "\"" + filename + "\"";
+}
+
+template<class value_type>
+static inline string
+value_string (const value_type &value)
+{
+  switch (value.what_space ())
+    {
+    case dwarf::VS_flag:
+      return value.flag () ? "1" : "0";
+
+    case dwarf::VS_rangelistptr:
+      return value.ranges ().to_string ();
+
+    case dwarf::VS_lineptr:
+      return value.line_info ().to_string ();
+
+    case dwarf::VS_macptr:     // XXX punt for now, treat as constant
+    case dwarf::VS_constant:
+      if (value.constant_is_integer ())
+       return hex_string (value.constant ());
+      return dec_string (value.constant_block ().size (),
+                        "{block of ", " bytes}");
+
+    case dwarf::VS_dwarf_constant:
+      return value.dwarf_constant ().to_string ();
+
+    case dwarf::VS_source_line:
+      return dec_string (value.source_line ());
+
+    case dwarf::VS_source_column:
+      return dec_string (value.source_column ());
+
+    case dwarf::VS_identifier:
+      return plain_string (value.identifier ());
+
+    case dwarf::VS_string:
+      return plain_string (value.string ());
+
+    case dwarf::VS_address:
+      return addr_string (value.address ());
+
+    case dwarf::VS_reference:
+      return hex_string (value.reference ()->offset (), "[", "]");
+
+    case dwarf::VS_source_file:
+      return value.source_file ().to_string ();
+
+    case dwarf::VS_location:
+      return value.location ().to_string ();
+
+    case dwarf::VS_discr_list:
+      break;                   // XXX DW_AT_discr_list unimplemented
+    }
+
+  throw std::runtime_error ("XXX unsupported value space");
+}
+
+template<>
+string
+to_string<dwarf::attribute> (const dwarf::attribute &attr)
+{
+  return attribute_string (attr);
+}
+
+template<>
+string
+to_string<dwarf::attr_value> (const dwarf::attr_value &value)
+{
+  return value_string (value);
+}
+
+template<>
+string
+to_string<dwarf_edit::attr_value> (const dwarf_edit::attr_value &value)
+{
+  return value_string (value);
+}
+
+template<>
+string
+to_string<dwarf_output::attr_value> (const dwarf_output::attr_value &value)
+{
+  return value_string (value);
+}
+
+// A few cases are trivial.
+#define SIMPLE(type, name, form)                                       \
+  type                                                                 \
+  dwarf::attr_value::name () const                                     \
+  {                                                                    \
+    type result;                                                       \
+    xif (thisattr (), dwarf_form##form (thisattr (), &result) < 0);    \
+    return result;                                                     \
+  }
+
+SIMPLE (bool, flag, flag)
+
+// XXX check value_space is really constantish?? vs *ptr
+SIMPLE (Dwarf_Word, constant, udata)
+SIMPLE (Dwarf_Sword, signed_constant, sdata)
+
+SIMPLE (Dwarf_Addr, address, addr)
+
+const char *
+dwarf::attr_value::string () const
+{
+  const char *result = dwarf_formstring (thisattr ());
+  xif (thisattr(), result == NULL);
+  return result;
+}
+
+bool
+dwarf::attr_value::constant_is_integer () const
+{
+  switch (dwarf_whatform (thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      return false;
+
+    case DW_FORM_data1:
+    case DW_FORM_data2:
+    case DW_FORM_data4:
+    case DW_FORM_data8:
+    case DW_FORM_udata:
+    case DW_FORM_sdata:
+      return true;
+
+    default:
+      throw std::runtime_error ("XXX wrong form");
+    }
+}
+
+
+const_vector<uint8_t>
+dwarf::attr_value::constant_block () const
+{
+  Dwarf_Block block;
+
+  switch (dwarf_whatform (thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+    case DW_FORM_exprloc:
+      xif (thisattr(), dwarf_formblock (thisattr (), &block) < 0);
+      break;
+
+    case DW_FORM_data1:
+      block.length = 1;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_data2:
+      block.length = 2;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_data4:
+      block.length = 4;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_data8:
+      block.length = 8;
+      block.data = thisattr ()->valp;
+      break;
+
+    case DW_FORM_udata:
+    case DW_FORM_sdata:
+      // XXX ?
+      if ((*(const uint8_t *) thisattr ()->valp & 0x80) == 0)
+       {
+         block.length = 1;
+         block.data = thisattr ()->valp;
+         break;
+       }
+
+    default:
+      throw std::runtime_error ("XXX wrong form");
+    }
+
+  return const_vector<uint8_t> (block);
+}
+
+namespace elfutils
+{
+  template<>
+  std::string to_string (const dwarf::debug_info_entry &die)
+  {
+    return die_string (die);
+  }
+};
+\f
+// dwarf::range_list
+
+unsigned char *
+dwarf::range_list::const_iterator::formptr (int secndx, Dwarf_Attribute *attr)
+{
+  unsigned char *readptr = __libdw_formptr (attr, secndx,
+                                           DWARF_E_NO_DEBUG_RANGES,
+                                           NULL, NULL);
+  xif (attr, readptr == NULL);
+  return readptr;
+}
+
+dwarf::range_list::const_iterator
+dwarf::range_list::begin () const
+{
+  const_iterator it (IDX_debug_ranges, _m_attr.thisattr (), 0);
+  return ++it;
+}
+
+dwarf::range_list::const_iterator::const_iterator (int secndx,
+                                                  Dwarf_Attribute *attr,
+                                                  unsigned char *readptr)
+  : _m_base (-1), _m_begin (0), _m_end (0), _m_cu (attr->cu)
+  , _m_readptr (readptr)
+{
+  if (_m_readptr == NULL)
+    {
+      _m_readptr = formptr (secndx, attr);
+      xif (attr, _m_readptr == NULL);
+    }
+}
+
+static bool
+range_list_advance (int secndx,
+                   Dwarf_CU *cu,
+                   Dwarf_Addr &base,
+                   Dwarf_Addr &begin,
+                   Dwarf_Addr &end,
+                   unsigned char *&readp,
+                   unsigned char **valp)
+{
+  const Elf_Data *d = cu->dbg->sectiondata[secndx];
+  if (unlikely (d == NULL))
+    throw std::runtime_error ("XXX no ranges");
+
+  if (unlikely (readp >= (unsigned char *)d->d_buf + d->d_size))
+    throw std::runtime_error ("XXX bad readptr in ranges iterator");
+
+  unsigned char *const readendp
+    = reinterpret_cast<unsigned char *> (d->d_buf) + d->d_size;
+
+  while (true)
+    {
+      if (readendp - readp < cu->address_size * 2)
+       throw std::runtime_error ("XXX bad ranges");
+
+      if (cu->address_size == 8)
+       {
+         begin = read_8ubyte_unaligned_inc (cu->dbg, readp);
+         end = read_8ubyte_unaligned_inc (cu->dbg, readp);
+         if (begin == (uint64_t) -1l) /* Base address entry.  */
+           {
+             base = end;
+             continue;
+           }
+       }
+      else
+       {
+         begin = read_4ubyte_unaligned_inc (cu->dbg, readp);
+         end = read_4ubyte_unaligned_inc (cu->dbg, readp);
+         if (begin == (uint32_t) -1) /* Base address entry.  */
+           {
+             base = end;
+             continue;
+           }
+       }
+
+      break;
+    }
+
+  if (begin == 0 && end == 0) /* End of list entry.  */
+    readp = (unsigned char *)-1;
+  else
+    {
+      if (valp)
+       *valp = readp;
+
+      if (base == (Dwarf_Addr) -1)
+       {
+         CUDIE (cudie, cu);
+
+         /* Find the base address of the compilation unit.  It will
+            normally be specified by DW_AT_low_pc.  In DWARF-3 draft 4,
+            the base address could be overridden by DW_AT_entry_pc.  It's
+            been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc
+            for compilation units with discontinuous ranges.  */
+         Dwarf_Attribute attr_mem;
+         if (unlikely (dwarf_lowpc (&cudie, &base) != 0)
+             && dwarf_formaddr (dwarf_attr (&cudie,
+                                            DW_AT_entry_pc,
+                                            &attr_mem),
+                                &base) != 0)
+           {
+             return true;      // XXX
+           }
+       }
+    }
+
+  return false;
+}
+
+dwarf::range_list::const_iterator &
+dwarf::range_list::const_iterator::operator++ ()
+{
+  xif (_m_cu, range_list_advance (IDX_debug_ranges, _m_cu, _m_base,
+                                 _m_begin, _m_end, _m_readptr, NULL));
+  return *this;
+}
+
+
+template<typename container>
+string
+__libdw_ranges_to_string (const container &c)
+{
+  std::ostringstream os;
+
+  os << "<" << std::hex << std::showbase;
+
+  bool first = true;
+  for (typename container::const_iterator i = c.begin (); i != c.end (); ++i)
+    {
+      const typename container::value_type range = *i;
+      if (!first)
+       os << ",";
+      os << range.first << "-" << range.second;
+      first = false;
+    }
+
+  os << ">";
+
+  return os.str ();
+}
+
+string
+dwarf::range_list::to_string () const
+{
+  return __libdw_ranges_to_string (*this);
+}
+
+string
+dwarf::ranges::to_string () const
+{
+  return __libdw_ranges_to_string (*this);
+}
+
+string
+dwarf::arange_list::to_string () const
+{
+  return __libdw_ranges_to_string (*this);
+}
+
+dwarf::aranges_map
+dwarf::aranges () const
+{
+  Dwarf_Aranges *these;
+  xif (dwarf_getaranges (_m_dw, &these, NULL) < 0);
+
+  if (these == NULL)
+    return aranges_map ();
+
+  aranges_map result;
+  for (const Dwarf_Aranges_s::Dwarf_Arange_s *r = &these->info[0];
+       r < &these->info[these->naranges];
+       ++r)
+    result[compile_unit (debug_info_entry (_m_dw, r->offset))].insert
+      (arange_list::value_type (r->addr, r->addr + r->length));
+
+  return result;
+}
+\f
+// dwarf::location_attr
+
+const dwarf::location_attr
+dwarf::attr_value::location () const
+{
+  if (what_space () != VS_location)
+    throw std::runtime_error ("XXX not a location");
+
+  return location_attr (*this);
+}
+
+bool
+dwarf::location_attr::is_list () const
+{
+  if (_m_attr.thisattr ()->cu->version >= 4)
+    return dwarf_whatform (_m_attr.thisattr ()) == DW_FORM_sec_offset;
+
+  switch (dwarf_whatform (_m_attr.thisattr ()))
+    {
+    case DW_FORM_block:
+    case DW_FORM_block1:
+    case DW_FORM_block2:
+    case DW_FORM_block4:
+      return false;
+    }
+
+  return true;
+}
+
+inline void
+dwarf::location_attr::const_iterator::advance ()
+{
+  xif (_m_cu, range_list_advance (IDX_debug_loc, _m_cu,
+                                 _m_base, _m_begin, _m_end, _m_readptr,
+                                 &_m_block.data));
+  // Special values are (unsigned char *){-1, 0, 1}.
+  if (((uintptr_t)_m_readptr + 1) > 2)
+    _m_readptr += 2 + (_m_block.length
+                      = read_2ubyte_unaligned_inc (_m_cu->dbg, _m_block.data));
+  else
+    // End iterator.
+    _m_block = Dwarf_Block ();
+}
+
+dwarf::location_attr::const_iterator
+dwarf::location_attr::begin () const
+{
+  const_iterator i (_m_attr.thisattr ());
+  if (is_list ())
+    {
+      i._m_readptr = const_iterator::formptr (IDX_debug_loc,
+                                             _m_attr.thisattr ());
+      xif (_m_attr.thisattr (), i._m_readptr == NULL);
+      i.advance ();
+    }
+  else
+    {
+      xif (_m_attr.thisattr (),
+          dwarf_formblock (_m_attr.thisattr (), &i._m_block) < 0);
+      i._m_base = 0;
+      i._m_end = -1;
+      i._m_readptr = NULL;
+    }
+
+  return i;
+}
+
+dwarf::location_attr::const_iterator &
+dwarf::location_attr::const_iterator::operator++ ()
+{
+  if (unlikely (_m_readptr == (unsigned char *)-1))
+    throw std::runtime_error ("incrementing end iterator");
+
+  if (_m_readptr == NULL)
+    {
+      // Singleton, now at end.
+      _m_readptr = (unsigned char *)-1;
+      _m_block.data = NULL;
+      _m_block.length = 0;
+    }
+  else
+    // Advance to next list entry.
+    advance ();
+
+  return *this;
+}
+
+template<typename locattr>
+static string
+locattr_string (const locattr *loc)
+{
+  return (loc->is_list () ? dec_string (loc->size (), "{loclist ", " entries}")
+         : "{locexpr}");
+}
+
+string
+dwarf::location_attr::to_string () const
+{
+  return locattr_string (this);
+}
+
+string
+dwarf_data::location_attr::to_string () const
+{
+  return locattr_string (this);
+}
+\f
+// dwarf::line_info_table
+
+template<typename line_info_table>
+static inline std::string
+line_info_string (const line_info_table *table)
+{
+  return ("[" + table->lines ().to_string () + "]");
+}
+
+std::string
+dwarf::line_info_table::to_string () const
+{
+  return line_info_string (this);
+}
+
+namespace elfutils
+{
+  template<>
+  std::string
+  dwarf_edit::line_info_table::to_string () const
+  {
+    return line_info_string (this);
+  }
+
+};
+\f
+// dwarf::line_table
+
+std::string
+dwarf::line_table::to_string () const
+{
+  return dec_string (_m_lines->nlines, "{", " line entries}");
+}
+
+namespace elfutils
+{
+  template<>
+  std::string
+  dwarf_edit::line_table::to_string () const
+  {
+    return dec_string (size (), "{", " line entries}");
+  }
+};
+\f
+::Dwarf_Off
+dwarf::debug_info_entry::cost () const
+{
+  Dwarf_Die next;
+  int result = dwarf_siblingof (thisdie (), &next);
+  xif (result < 0);
+  if (result == 0)
+    return (const char *) next.addr - (const char *) _m_die.addr;
+  if (next.addr != NULL)
+    return (const char *) next.addr - (const char *) _m_die.addr + 1;
+  return _m_die.cu->end - dwarf_dieoffset (thisdie ());
+}