]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
Major revamp of dwarf_edit/dwarf_output.
authorRoland McGrath <roland@redhat.com>
Thu, 2 Jul 2009 09:11:12 +0000 (02:11 -0700)
committerRoland McGrath <roland@redhat.com>
Thu, 2 Jul 2009 09:11:12 +0000 (02:11 -0700)
21 files changed:
libdw/ChangeLog
libdw/Makefile.am
libdw/c++/data-values.hh [new file with mode: 0644]
libdw/c++/dwarf
libdw/c++/dwarf_data [new file with mode: 0644]
libdw/c++/dwarf_edit
libdw/c++/dwarf_output
libdw/c++/edit-values.cc
libdw/c++/known.cc
libdw/c++/output-values.cc [new file with mode: 0644]
libdw/c++/subr.hh
libdw/c++/values.cc
src/ChangeLog
src/dwarfcmp.cc
tests/ChangeLog
tests/Makefile.am
tests/dwarf-print.cc
tests/dwarf_edit.cc [new file with mode: 0644]
tests/print-die.hh [new file with mode: 0644]
tests/run-dwarf-attributes.sh
tests/run-dwarf_edit.sh [new file with mode: 0755]

index 28cc39a5bae7845bf0196d355fab924e926d8f9e..a269182eb4211f0a1cd0efa0c3d7246c75799d41 100644 (file)
@@ -1,3 +1,24 @@
+2009-07-02  Roland McGrath  <roland@redhat.com>
+
+       * c++/dwarf_output: Rewrite.
+       * c++/subr.hh: New helpers for dwarf_output/dwarf_data.
+
+       * c++/dwarf_edit: Much guts moved to ...
+       * c++/dwarf_data: ... here, new file.
+       * c++/known.cc: Update specializations.
+
+       * libdw/c++/edit-values.cc (what_space): Moved to ...
+       * c++/data-values.hh: ... here, new file.
+
+       * Makefile.am (noinst_HEADERS): Add it.
+
+       * c++/output-values.cc: New file.
+       * Makefile.am (libdwpp_a_SOURCES): Add it.
+       Makefile.am (pkginclude_HEADERS): Add dwarf_data, dwarf_output.
+
+       * c++/dwarf: Use to_string function overload, not to_string method.
+       * c++/values.cc: Define to_string specializations.
+
 2009-07-01  Roland McGrath  <roland@redhat.com>
 
        * c++/dwarf_tracker: Major revamp for efficiency and to handle
index b957c168d907f59aa2ce2af1979e8372e8535312..f358840c47de8e91f572f917a7a10fefc3410597 100644 (file)
@@ -48,8 +48,8 @@ endif
 
 include_HEADERS = dwarf.h
 pkginclude_HEADERS = libdw.h \
-                    c++/subr.hh \
-                    c++/dwarf c++/dwarf_edit \
+                    c++/subr.hh c++/dwarf_data \
+                    c++/dwarf c++/dwarf_edit c++/dwarf_output \
                     c++/dwarf_tracker c++/dwarf_comparator
 
 libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
@@ -94,8 +94,10 @@ libdwpp_a_SOURCES = c++/values.cc \
                    c++/exception.cc \
                    c++/known.cc \
                    c++/line_info.cc \
-                   c++/edit-values.cc
-noinst_HEADERS    = c++/dwarf-knowledge.cc
+                   c++/edit-values.cc \
+                   c++/output-values.cc
+noinst_HEADERS    = c++/dwarf-knowledge.cc \
+                   c++/data-values.hh
 
 if MAINTAINER_MODE
 BUILT_SOURCES = $(srcdir)/known-dwarf.h
diff --git a/libdw/c++/data-values.hh b/libdw/c++/data-values.hh
new file mode 100644 (file)
index 0000000..55860f5
--- /dev/null
@@ -0,0 +1,97 @@
+/* elfutils::dwarf_data common internal templates.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include "dwarf_data"
+
+#include <typeinfo>
+
+namespace elfutils
+{
+
+  template<class impl, typename v>
+  dwarf::value_space
+  dwarf_data::attr_value<impl, v>::what_space () const
+  {
+    if (typeid (*_m_value) == typeid (typename v::value_flag))
+      return dwarf::VS_flag;
+    if (typeid (*_m_value) == typeid (typename v::value_dwarf_constant))
+      return dwarf::VS_dwarf_constant;
+    if (typeid (*_m_value) == typeid (typename v::value_reference))
+      return dwarf::VS_reference;
+    if (typeid (*_m_value) == typeid (typename v::value_unit_reference))
+      return dwarf::VS_unit_reference;
+    if (typeid (*_m_value) == typeid (typename v::value_lineptr))
+      return dwarf::VS_lineptr;
+    if (typeid (*_m_value) == typeid (typename v::value_macptr))
+      return dwarf::VS_macptr;
+    if (typeid (*_m_value) == typeid (typename v::value_rangelistptr))
+      return dwarf::VS_rangelistptr;
+    if (typeid (*_m_value) == typeid (typename v::value_identifier))
+      return dwarf::VS_identifier;
+    if (typeid (*_m_value) == typeid (typename v::value_string))
+      return dwarf::VS_string;
+    if (typeid (*_m_value) == typeid (typename v::value_source_file))
+      return dwarf::VS_source_file;
+    if (typeid (*_m_value) == typeid (typename v::value_source_line))
+      return dwarf::VS_source_line;
+    if (typeid (*_m_value) == typeid (typename v::value_source_column))
+      return dwarf::VS_source_column;
+    if (typeid (*_m_value) == typeid (typename v::value_address))
+      return dwarf::VS_address;
+    if (typeid (*_m_value) == typeid (typename v::value_constant)
+       || typeid (*_m_value) == typeid (typename v::value_constant_block))
+      return dwarf::VS_constant;
+    if (typeid (*_m_value) == typeid (typename v::value_location))
+      return dwarf::VS_location;
+
+    throw std::runtime_error ("XXX impossible");
+  }
+
+
+};
index 9f2d37f1d34cccbf33357c3f3e165aaeb21bee05..311591fe6d970691d9feb2e2aa0b092af3e7487c 100644 (file)
@@ -1903,13 +1903,7 @@ namespace elfutils
        return !(*this == other);
       }
 
-      inline std::string to_string () const
-      {
-       std::string result = attributes::name (::dwarf_whatattr (thisattr ()));
-       result += "=";
-       result += second.to_string ();
-       return result;
-      }
+      inline std::string to_string () const;
     };
 
     /* This works like range_list, but is based on a debug_info_entry using
@@ -2367,15 +2361,19 @@ namespace elfutils
     return const_iterator (*this, 1);
   }
 
-  // Explicit specialization.
+  // Explicit specializations.
+  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.
   }
-
-  // Explicit specialization.
   template<>
   std::string to_string<dwarf::dwarf_enum> (const dwarf::dwarf_enum &);
   inline std::string dwarf::dwarf_enum::to_string () const
diff --git a/libdw/c++/dwarf_data b/libdw/c++/dwarf_data
new file mode 100644 (file)
index 0000000..6d03900
--- /dev/null
@@ -0,0 +1,1267 @@
+/* elfutils::dwarf_data -- internal DWARF data representations in -*- C++ -*-
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifndef _ELFUTILS_DWARF_DATA
+#define _ELFUTILS_DWARF_DATA   1
+
+#include "dwarf"
+#include <bitset>
+#include <typeinfo>
+
+/* 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:
+
+    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) {}
+
+      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);
+      }
+    };
+
+    // This describes a CU's directory table, a simple array of strings.
+    class directory_table : public std::vector<std::string>
+    {
+    private:
+      typedef std::vector<std::string> _base;
+
+    public:
+      struct hasher : public subr::container_hasher<directory_table> {};
+
+      directory_table () {}
+
+      template<typename table>
+      directory_table (const table &other)
+       : _base (other.begin (), other.end ()) {}
+
+      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);
+      }
+    };
+
+  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 ()) {}
+
+      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.  It's parameterized
+       by the directory_table and line_table representations.  */
+    template<typename directory_table, typename line_table>
+    class line_info_table
+      : private std::pair<directory_table, line_table>
+    {
+    private:
+      typedef std::pair<directory_table, line_table> _base;
+
+    public:
+      inline line_info_table () : _base () {}
+
+      template<typename table>
+      inline line_info_table (const table &other)
+       : _base (other.include_directories (), other.lines ())
+      {}
+
+      template<typename table>
+      inline line_info_table &operator= (const table &other)
+      {
+       this->first = directory_table (other.include_directories ());
+       this->second = line_table (other.lines ());
+       return *this;
+      }
+
+      inline directory_table &include_directories ()
+      {
+       return this->first;
+      }
+      inline const directory_table &include_directories () const
+      {
+       return this->first;
+      }
+      inline line_table &lines ()
+      {
+       return this->second;
+      }
+      inline const line_table &lines () const
+      {
+       return this->second;
+      }
+
+      template<typename table>
+      inline bool operator== (const table &other) const
+      {
+       return (include_directories () == other.include_directories ()
+               && 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;
+
+      inline dwarf_enum ()
+       : _base (0, 0)
+      {}
+
+    public:
+
+      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>>.
+    class range_list : public dwarf::arange_list
+    {
+    public:
+      struct hasher : public subr::container_hasher<range_list> {};
+
+      template<typename list>
+      range_list (const list &other)
+       : dwarf::arange_list (other.begin (), other.end ()) {}
+    };
+
+    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;
+    };
+
+  public:
+    struct nothing {};
+
+    template<typename impl>
+    struct value
+    {
+      struct value_dispatch
+      {
+       virtual ~value_dispatch () {}
+      };
+
+      template<typename flavor, typename input, typename arg_type>
+      static inline value_dispatch *
+      make (flavor *&result, const input &x, const arg_type &arg)
+      {
+       return result = new flavor (x, arg);
+      }
+
+      struct value_string : public value_dispatch, public std::string
+      {
+       inline value_string () {}
+
+       template<typename string, typename arg_type>
+       inline value_string (const string &s, const arg_type &arg)
+         : std::string (s)
+       {}
+
+       std::string to_string () const
+       {
+         std::string result ("\"");
+         result += *this;
+         result += "\"";
+         return result;
+       }
+      };
+
+      struct value_identifier : public value_string
+      {
+       template<typename id, typename arg_type>
+       inline value_identifier (const id &s, const arg_type &arg)
+         : value_string (s, arg)
+       {}
+      };
+
+      struct value_reference : public value_dispatch
+      {
+       typename impl::debug_info_entry::children_type::iterator ref;
+
+       template<typename arg_type>
+       inline value_reference
+       (const typename impl::debug_info_entry::children_type::iterator &i,
+        const arg_type &arg)
+         : ref (i)
+       {}
+
+       template<typename iter, typename arg_type>      // XXX dummy
+       inline value_reference (const iter &i, const arg_type &arg)
+         : ref () {}
+      };
+
+      struct value_unit_reference : public value_dispatch
+      {
+       typename impl::compile_units::iterator ref;
+
+       template<typename arg_type>
+       inline value_unit_reference
+       (const typename impl::compile_units::iterator &i,
+        const arg_type &arg)
+         : ref (i)
+       {}
+
+       template<typename iter, typename arg_type>      // XXX dummy
+       inline value_unit_reference (const iter &i, const arg_type &arg)
+         : ref ()
+       {}
+      };
+
+      struct value_flag : public value_dispatch
+      {
+       bool flag;
+
+       inline value_flag ()
+         : flag (true)
+       {}
+
+       template<typename arg_type>
+       inline value_flag (bool t, const arg_type &arg)
+         : flag (t)
+       {}
+      };
+
+      struct value_address : public value_dispatch
+      {
+       // XXX dwfl, reloc
+       ::Dwarf_Addr addr;
+
+       inline value_address ()
+         : addr (0)
+       {}
+
+       template<typename arg_type>
+       inline value_address (::Dwarf_Addr x, const arg_type &arg)
+         : 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, const arg_type &arg)
+         : 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, const arg_type &arg)
+         : impl::line_info_table (other)
+       {}
+      };
+
+      struct value_constant : public value_dispatch
+      {
+       union
+       {
+         ::Dwarf_Word word;
+         ::Dwarf_Sword sword;
+       };
+
+       inline value_constant ()
+         : word (0)
+       {}
+
+       template<typename arg_type>
+       inline value_constant (::Dwarf_Word x, const arg_type &arg)
+         : word (x)
+       {}
+      };
+
+      struct value_constant_block : public value_dispatch,
+                                   public std::vector<uint8_t>
+      {
+       inline value_constant_block () {}
+
+       template<typename block, typename arg_type>
+       inline value_constant_block (const block &b, const arg_type &arg)
+         : 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, typename arg_type>
+       inline value_dwarf_constant (const constant &other, const arg_type &arg)
+         : 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, const arg_type &arg)
+         : source_file (other)
+       {}
+      };
+
+      struct value_source_line : public value_dispatch
+      {
+       unsigned int n;
+
+       inline value_source_line ()
+         : n (0)
+       {}
+
+       template<typename arg_type>
+       inline value_source_line (unsigned int m, const arg_type &arg)
+         : n (m)
+       {}
+      };
+      typedef value_source_line value_source_column;
+
+      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, const arg_type &arg)
+         : location_attr (other)
+       {}
+      };
+    };
+
+    template<class impl, typename vw = value<impl> >
+    class attr_value
+    {
+    private:
+      typename vw::value_dispatch *_m_value;
+
+      template<typename value, typename arg_type = nothing>
+      struct init
+      {
+       inline init (attr_value *av,
+                    const value &other, const arg_type &arg = arg_type ())
+       {
+         switch (other.what_space ())
+           {
+#define _DWARF_DATA_AV_MAKE(flavor, fetch)                             \
+             case dwarf::VS_##flavor:                                  \
+               {                                                       \
+                 typename vw::value_##flavor *p;                       \
+                 av->_m_value = vw::make (p, 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 (unit_reference, unit_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;
+                 av->_m_value = vw::make (p, other.constant (), arg);
+               }
+             else
+               {
+                 typename vw::value_constant_block *p;
+                 av->_m_value = vw::make (p, other.constant_block (), arg);
+               }
+             break;
+
+           default:
+           case dwarf::VS_discr_list:
+             throw std::runtime_error ("XXX unimplemented");
+
+#undef _DWARF_DATA_AV_MAKE
+           }
+       }
+      };
+
+      template<typename flavor>
+      inline flavor &const_variant () const
+      {
+       flavor *p = dynamic_cast<flavor *> (_m_value);
+       if (p == NULL)
+         throw std::runtime_error ("wrong value type");
+       return *p;
+      }
+
+      template<typename flavor>
+      inline flavor &variant () const
+      {
+       return const_variant<flavor> ();
+      }
+
+      template<typename flavor>
+      inline flavor &variant ()
+      {
+       if (_m_value == NULL)
+         _m_value = new flavor;
+       return const_variant<flavor> ();
+      }
+
+    public:
+      attr_value (const attr_value &other)
+       : _m_value (NULL)
+      {
+       if (other._m_value != NULL)
+         init<attr_value> me (this, other);
+      }
+
+      template<typename value, typename arg_type>
+      attr_value (const value &other, const arg_type &arg)
+       : _m_value (NULL)
+      {
+       init<value, arg_type> me (this, other, arg);
+      }
+
+      inline attr_value ()
+       : _m_value (NULL)
+      {}
+
+      ~attr_value ()
+      {
+       if (_m_value != NULL)
+         delete _m_value;
+      }
+
+      inline attr_value &operator= (const attr_value &other)
+      {
+       if (_m_value != NULL)
+         {
+           delete _m_value;
+           _m_value = NULL;
+         }
+       init<attr_value> me (this, other);
+       return *this;
+      }
+      template<typename value>
+      inline attr_value &operator= (const value &other)
+      {
+       if (_m_value != NULL)
+         {
+           delete _m_value;
+           _m_value = NULL;
+         }
+       init<value> me (this, other);
+       return *this;
+      }
+
+      dwarf::value_space what_space () const;
+      inline std::string to_string () const;
+
+      inline bool &flag () const
+      {
+       return variant<typename vw::value_flag> ().flag;
+      }
+
+      // XXX dwfl, reloc
+      inline ::Dwarf_Addr &address () const
+      {
+       return variant<typename vw::value_address> ().addr;
+      }
+
+      inline typename impl::debug_info_entry::children_type::iterator
+      reference () const
+      {
+       return variant<typename vw::value_reference> ().ref;
+      }
+      inline typename impl::compile_units::iterator
+      unit_reference () const
+      {
+       return variant<typename vw::value_unit_reference> ().ref;
+      }
+
+      inline location_attr &location () const
+      {
+       return static_cast<location_attr &>
+         (variant<typename vw::value_location> ());
+      }
+
+      inline std::string &string ()
+      {
+       return static_cast<std::string &>
+         (variant<typename vw::value_string> ());
+      }
+      inline const std::string &string () const
+      {
+       return static_cast<const std::string &>
+         (variant<typename vw::value_string> ());
+      }
+      inline std::string &identifier ()
+      {
+       return string ();
+      }
+      inline const std::string &identifier () const
+      {
+       return string ();
+      }
+
+      inline const typename impl::source_file &source_file () const
+      {
+       return static_cast<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<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<typename vw::value_constant *> (_m_value) != NULL;
+      }
+
+      inline const typename impl::range_list &ranges () const
+      {
+       return static_cast<range_list &>
+         (variant<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<typename impl::line_info_table &>
+         (variant<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_unit_reference:
+             return unit_reference () == other.unit_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 arg = nothing, typename v = value<impl> >
+    class attributes_type
+      : public std::map<int, attr_value<impl, v> >
+    {
+      friend class impl::debug_info_entry;
+    private:
+      typedef std::map<int, attr_value<impl, v> > base_type;
+
+    protected:
+      inline attributes_type () {}
+
+    public: // XXX should be protected
+      template<typename input, typename arg_type>
+      inline attributes_type (const input &other, const arg_type &c)
+       : base_type (subr::argify2nd<input, attributes_type, arg_type>
+                    (other.begin (), c),
+                    subr::argify2nd<input, attributes_type, arg_type>
+                    (other.end (), 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 const bool ordered = 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
index 00698b540bc1b76c99294f1addd3c4955746b5e8..8e12c5da76a96ec300109f3e93f6b3dd26b1c481 100644 (file)
@@ -51,7 +51,8 @@
 #define _ELFUTILS_DWARF_EDIT   1
 
 #include "dwarf"
-#include <bitset>
+#include "dwarf_data"
+#include "dwarf_tracker"
 
 /* Read the comments for elfutils::dwarf first.
 
@@ -86,8 +87,18 @@ namespace elfutils
   class dwarf_edit
   {
   public:
+    typedef dwarf_data::source_file source_file;
+    typedef dwarf_data::directory_table directory_table;
+    typedef dwarf_data::line_entry<source_file> line_entry;
+    typedef dwarf_data::line_table<line_entry> line_table;
+    typedef dwarf_data::line_info_table<directory_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 compile_units;
-    class attr_value;
 
     class debug_info_entry
     {
@@ -99,38 +110,36 @@ namespace elfutils
       private:
         children_type () {}
 
-       template<typename childrens>
-       children_type (const childrens &other)
-         : std::list<debug_info_entry> (other.begin (), other.end ()) {}
+       template<typename input, typename tracker>
+       children_type (const input &other, tracker *t)
+         : std::list<debug_info_entry>
+           (subr::argify<input, children_type, tracker *> (other.begin (), t),
+            subr::argify<input, children_type, tracker *> (other.end (), t))
+       {}
 
       public:
        typedef debug_info_entry value_type;
+
+       inline debug_info_entry &add_entry (int tag)
+       {
+         push_back (debug_info_entry (tag));
+         return back ();
+       }
       };
 
-      class attributes_type : public std::map<int, attr_value>
+      class attributes_type
+       : public dwarf_data::attributes_type<dwarf_edit>
       {
        friend class debug_info_entry;
       private:
-       typedef std::map<int, attr_value> base_type;
-
-       attributes_type () {}
-
-       template<typename attrs>
-       attributes_type (const attrs &other)
-         : std::map<int, attr_value> (other.begin (), other.end ()) {}
+       typedef dwarf_data::attributes_type<dwarf_edit> base_type;
 
-      public:
-       typedef base_type::key_type key_type;
-       typedef base_type::value_type value_type;
-       typedef base_type::mapped_type mapped_type;
-
-       static const bool ordered = true;
+       inline attributes_type () {}
 
-       template<typename attrs>
-       inline operator attrs () const
-       {
-         return attrs (begin (), end ());
-       }
+       template<typename attrs, typename tracker>
+       inline attributes_type (const attrs &other, tracker *t)
+         : base_type (other, t)
+       {}
       };
 
     private:
@@ -147,11 +156,11 @@ namespace elfutils
 
       /* The template constructor lets us copy in from any class that has
         compatibly iterable containers for attributes and children.  */
-      template<typename die_type>
-      debug_info_entry (const die_type &die)
+      template<typename die_type, typename tracker>
+      debug_info_entry (const die_type &die, tracker *t)
        : _m_tag (die.tag ()),
-         _m_attributes (die.attributes ()),
-         _m_children (die.children ())
+         _m_attributes (die.attributes (), t),
+         _m_children (die.children (), t)
       {}
 
       inline int tag () const
@@ -204,6 +213,12 @@ namespace elfutils
       {
        return identity ();
       }
+
+      // Convenience entry points.
+      inline debug_info_entry &add_entry (int child_tag)
+      {
+       return children ().add_entry (child_tag);
+      }
     };
 
     typedef debug_info_entry::attributes_type::value_type attribute;
@@ -216,8 +231,9 @@ namespace elfutils
 
       // XXX should be private
     public:
-      template<typename die_type>
-      compile_unit (const die_type &die) : debug_info_entry (die)
+      template<typename die_type, typename tracker>
+      inline compile_unit (const die_type &die, tracker *t)
+       : debug_info_entry (die, t)
       {
        if (die.tag () != ::DW_TAG_compile_unit)
          throw std::invalid_argument ("not a compile_unit entry");
@@ -237,22 +253,26 @@ namespace elfutils
       typedef std::list<compile_unit> _base;
 
       // Default constructor: an empty container, no CUs.
-      inline compile_units () {}
+      inline compile_units ()
+      {}
 
       // Constructor copying CUs from input container.
-      template<typename input>
-      compile_units(const input &units)
-       : _base (units.begin (), units.end ()) {}
+      template<typename input, typename tracker>
+      inline compile_units (const input &units, tracker *t)
+       : _base (subr::argify<input, compile_units, tracker *>
+                (units.begin (), t),
+                subr::argify<input, compile_units, tracker *>
+                (units.end (), t))
+      {}
 
     public:
       typedef compile_unit value_type;
       typedef _base::iterator iterator;
       typedef _base::const_iterator const_iterator;
 
-      inline compile_unit &new_unit ()
+      inline compile_unit &add_unit ()
       {
-       compile_unit nu;
-       push_back (nu);
+       push_back (compile_unit ());
        return back ();
       }
 
@@ -268,901 +288,6 @@ namespace elfutils
       }
     };
 
-    // Same as set<pair<Dwarf_Addr, Dwarf_Addr>>.
-    class range_list : public dwarf::arange_list
-    {
-    public:
-      template<typename list>
-      range_list (const list &other)
-       : dwarf::arange_list (other.begin (), other.end ()) {}
-    };
-
-    class source_file
-    {
-    private:
-      std::string _m_name;
-      ::Dwarf_Word _m_mtime;
-      ::Dwarf_Word _m_size;
-
-    public:
-      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) {}
-
-      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);
-      }
-    };
-
-    // This describes a CU's directory table, a simple array of strings.
-    class directory_table : public std::vector<std::string>
-    {
-    private:
-      typedef std::vector<std::string> _base;
-
-    public:
-      directory_table () {}
-
-      template<typename table>
-      directory_table (const table &other)
-       : _base (other.begin (), other.end ()) {}
-
-      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);
-      }
-    };
-
-    class line_entry
-    {
-    private:
-      ::Dwarf_Addr _m_addr;    // XXX dwfl, reloc
-      source_file _m_file;
-      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 (::Dwarf_Addr addr)
-       : _m_addr (addr), _m_file (), _m_line (0), _m_column (0) {}
-
-      template<typename entry>
-      line_entry (const entry &other)
-       : _m_addr (0), _m_file (), _m_line (0), _m_column (0)
-      {
-       *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;
-      }
-      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
-
-      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);
-      }
-    };
-
-    class line_table : public std::vector<line_entry>
-    {
-    private:
-      typedef std::vector<line_entry> _base;
-
-    public:
-      typedef _base::size_type size_type;
-      typedef _base::difference_type difference_type;
-      typedef _base::value_type value_type;
-      typedef _base::iterator iterator;
-      typedef _base::const_iterator const_iterator;
-
-      line_table () {}
-
-      template<typename table>
-      line_table (const table &other) : _base (other.begin (), other.end ()) {}
-
-      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);
-      }
-
-      // Look up by matching address.
-      iterator find (::Dwarf_Addr);
-      const_iterator find (::Dwarf_Addr) const;
-    };
-
-    class line_info_table
-    {
-    private:
-      directory_table _m_dirs;
-      line_table _m_lines;
-
-    public:
-      line_info_table () : _m_dirs (), _m_lines () {}
-
-      template<typename table>
-      line_info_table (const table &other)
-       : _m_dirs (other.include_directories ()), _m_lines (other.lines ()) {}
-
-      template<typename table>
-      inline line_info_table &operator= (const table &other)
-      {
-       _m_dirs = directory_table (other.include_directories ());
-       _m_lines = line_table (other.lines ());
-       return *this;
-      }
-
-      inline directory_table &include_directories ()
-      {
-       return _m_dirs;
-      }
-      inline const directory_table &include_directories () const
-      {
-       return _m_dirs;
-      }
-      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 (include_directories () == other.include_directories ()
-               && lines () == other.lines ());
-      }
-      template<typename table>
-      inline bool operator!= (const table &other) const
-      {
-       return !(*this == other);
-      }
-    };
-
-    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;
-
-      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;
-    };
-
-    class dwarf_enum
-    {
-    private:
-      ::Dwarf_Word _m_value;
-      unsigned int _m_which;
-
-    public:
-      inline dwarf_enum (unsigned int attr, unsigned int value)
-       : _m_value (value), _m_which (attr)
-      {}
-
-      template<typename constant>
-      inline dwarf_enum (const constant &other)
-       : _m_value (static_cast<unsigned int> (other)),
-         _m_which (other.which ())
-      {}
-
-      // Return the DW_AT_* indicating which enum this value belongs to.
-      inline unsigned int which () const
-      {
-       return _m_which;
-      }
-
-      inline operator unsigned int () const
-      {
-       return _m_value;
-      }
-
-      inline dwarf_enum &operator= (const dwarf_enum& other)
-      {
-       _m_value = other._m_value;
-       _m_which = other._m_which;
-       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);
-      }
-    };
-
-  private:
-    class value_dispatch
-    {
-    public:
-      virtual ~value_dispatch () {}
-    };
-
-    struct value_string : public value_dispatch, public std::string
-    {
-      template<typename string>
-      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
-    {
-      template<typename id>
-      value_identifier (const id &s) : value_string (s) {}
-    };
-
-    struct value_reference : public value_dispatch
-    {
-      debug_info_entry::children_type::iterator ref;
-      value_reference (const debug_info_entry::children_type::iterator &i)
-       : ref (i) {}
-
-      template<typename iter>  // XXX dummy
-      value_reference (const iter &i) : ref () {}
-    };
-    struct value_unit_reference : public value_dispatch
-    {
-      compile_units::iterator ref;
-      value_unit_reference (const compile_units::iterator &i) : ref (i) {}
-
-      template<typename iter>  // XXX dummy
-      value_unit_reference (const iter &i) : ref () {}
-    };
-
-    struct value_flag : public value_dispatch
-    {
-      bool flag;
-      value_flag (bool t) : flag (t) {}
-    };
-
-    struct value_address : public value_dispatch
-    {
-      // XXX dwfl, reloc
-      ::Dwarf_Addr addr;
-      value_address (::Dwarf_Addr a) : addr (a) {}
-    };
-
-    struct value_rangelistptr : public value_dispatch, public range_list
-    {
-      template<typename list>
-      value_rangelistptr (const list &other) : range_list (other) {}
-    };
-
-    struct value_lineptr : public value_dispatch, public line_info_table
-    {
-      template<typename table>
-      value_lineptr (const table &other) : line_info_table (other) {}
-    };
-
-    struct value_constant : public value_dispatch
-    {
-      union
-      {
-       ::Dwarf_Word word;
-       ::Dwarf_Sword sword;
-      };
-      value_constant (::Dwarf_Word x) : word (x) {}
-    };
-
-    struct value_constant_block : public value_dispatch,
-                                 public std::vector<uint8_t>
-    {
-      template<typename block>
-      value_constant_block (const block &b)
-       : std::vector<uint8_t> (b.begin (), b.end ()) {}
-    };
-
-    struct value_dwarf_constant : public value_dispatch, public dwarf_enum
-    {
-      template<typename constant>
-      value_dwarf_constant (const constant &other) : dwarf_enum (other) {}
-    };
-
-    struct value_source_file : public value_dispatch, public source_file
-    {
-      template<typename file>
-      value_source_file (const file &other) : source_file (other) {}
-    };
-
-    struct value_source_line : public value_dispatch
-    {
-      unsigned int n;
-      value_source_line (unsigned int m) : n (m) {}
-    };
-    typedef value_source_line value_source_column;
-
-    struct value_macptr : public value_dispatch {};
-
-    struct value_location : public value_dispatch, public location_attr
-    {
-      template<typename loc>
-      value_location (const loc &other) : location_attr (other) {}
-    };
-
-  public:
-    class attr_value
-    {
-    private:
-      value_dispatch *_m_value;
-
-      template<typename value>
-      inline void init (const value &other)
-      {
-       switch (other.what_space ())
-         {
-         case dwarf::VS_identifier:
-           _m_value = new value_identifier (other.identifier ());
-           break;
-         case dwarf::VS_string:
-           _m_value = new value_string (other.string ());
-           break;
-         case dwarf::VS_flag:
-           _m_value = new value_flag (other.flag ());
-           break;
-         case dwarf::VS_rangelistptr:
-           _m_value = new value_rangelistptr (other.ranges ());
-           break;
-         case dwarf::VS_lineptr:
-           _m_value = new value_lineptr (other.line_info ());
-           break;
-         case dwarf::VS_address:
-           _m_value = new value_address (other.address ());
-           break;
-         case dwarf::VS_constant:
-           if (other.constant_is_integer ())
-             _m_value = new value_constant (other.constant ());
-           else
-             _m_value = new value_constant_block (other.constant_block ());
-           break;
-         case dwarf::VS_source_line:
-           _m_value = new value_source_line (other.source_line ());
-           break;
-         case dwarf::VS_source_column:
-           _m_value = new value_source_column (other.source_column ());
-           break;
-         case dwarf::VS_source_file:
-           _m_value = new value_source_file (other.source_file ());
-           break;
-         case dwarf::VS_dwarf_constant:
-           _m_value = new value_dwarf_constant (other.dwarf_constant ());
-           break;
-         case dwarf::VS_reference:
-           _m_value = new value_reference (other.reference ());
-           break;
-         case dwarf::VS_unit_reference:
-           _m_value = new value_unit_reference (other.unit_reference ());
-           break;
-         case dwarf::VS_location:
-           _m_value = new value_location (other.location ());
-           break;
-#if 0
-         case dwarf::VS_macptr:
-           _m_value = new value_macptr (other.macptr ());
-           break;
-#endif
-         default:
-         case dwarf::VS_discr_list:
-           throw std::runtime_error ("XXX unimplemented");
-         }
-      }
-
-      template<typename flavor>
-      inline flavor &variant () const
-      {
-       flavor *p = dynamic_cast<flavor *> (_m_value);
-       if (p == NULL)
-         throw std::runtime_error ("wrong value type");
-       return *p;
-      }
-
-    public:
-      attr_value (const attr_value &other) : _m_value (NULL)
-      {
-       init (other);
-      }
-      template<typename value>
-      attr_value (const value &other) : _m_value (NULL)
-      {
-       init (other);
-      }
-
-      attr_value () : _m_value (NULL) {}
-
-      ~attr_value ()
-      {
-       if (_m_value != NULL)
-         delete _m_value;
-      }
-
-      inline attr_value &operator= (const attr_value &other)
-      {
-       if (_m_value != NULL)
-         {
-           delete _m_value;
-           _m_value = NULL;
-         }
-       init (other);
-       return *this;
-      }
-      template<typename value>
-      inline attr_value &operator= (const value &other)
-      {
-       if (_m_value != NULL)
-         {
-           delete _m_value;
-           _m_value = NULL;
-         }
-       init (other);
-       return *this;
-      }
-
-      dwarf::value_space what_space () const;
-      inline std::string to_string () const;
-
-      inline bool &flag () const
-      {
-       return variant<value_flag> ().flag;
-      }
-
-      // XXX dwfl, reloc
-      inline ::Dwarf_Addr &address () const
-      {
-       return variant<value_address> ().addr;
-      }
-
-      inline debug_info_entry::children_type::iterator reference () const
-      {
-       return variant<value_reference> ().ref;
-      }
-      inline compile_units::iterator unit_reference () const
-      {
-       return variant<value_unit_reference> ().ref;
-      }
-
-      inline location_attr &location () const
-      {
-       return static_cast<location_attr &> (variant<value_location> ());
-      }
-
-      inline std::string &string () const
-      {
-       return static_cast<std::string &> (variant<value_string> ());
-      }
-      inline std::string &identifier () const
-      {
-       return string ();
-      }
-
-      inline dwarf_edit::source_file &source_file () const
-      {
-       return static_cast<dwarf_edit::source_file &>
-         (variant<value_source_file> ());
-      }
-
-      inline unsigned int &source_line () const
-      {
-       return variant<value_source_line> ().n;
-      }
-
-      inline unsigned int &source_column () const
-      {
-       return variant<value_source_column> ().n;
-      }
-
-      inline ::Dwarf_Word &constant () const
-      {
-       return variant<value_constant> ().word;
-      }
-
-      inline ::Dwarf_Sword &signed_constant () const
-      {
-       return variant<value_constant> ().sword;
-      }
-
-      inline std::vector<uint8_t> &constant_block () const
-      {
-       return static_cast<std::vector<uint8_t> &>
-         (variant<value_constant_block> ());
-      }
-
-      inline dwarf_enum &dwarf_constant () const
-      {
-       return variant<value_dwarf_constant> ();
-      }
-
-      inline bool constant_is_integer () const
-      {
-       return dynamic_cast<value_constant *> (_m_value) != NULL;
-      }
-
-      inline range_list &ranges () const
-      {
-       return static_cast<range_list &> (variant<value_rangelistptr> ());
-      }
-
-      inline line_info_table &line_info () const
-      {
-       return static_cast<line_info_table &> (variant<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_unit_reference:
-             return unit_reference () == other.unit_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);
-      }
-    };
-
   private:
     compile_units _m_units;
 
@@ -1176,13 +301,21 @@ namespace elfutils
       return _m_units;
     }
 
+    // Convenience entry point.
+    inline compile_unit &add_unit ()
+    {
+      return compile_units ().add_unit ();
+    }
+
   public:
     // Default constructor: an empty container, no CUs.
     inline dwarf_edit () {}
 
     // Constructor copying CUs from an input file (dwarf or dwarf_edit).
-    template<typename input>
-    dwarf_edit (const input &dw) : _m_units (dw.compile_units ()) {}
+    template<typename input, typename tracker>
+    dwarf_edit (const input &dw, tracker *t)
+      : _m_units (dw.compile_units (), t)
+    {}
 
     template<typename file>
     inline bool operator== (const file &other) const
@@ -1200,17 +333,7 @@ namespace elfutils
   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&);
-  inline std::string dwarf_edit::attr_value::to_string () const
-  {
-    return elfutils::to_string (*this); // Use that.
-  }
-  template<>
-  std::string to_string<dwarf_edit::dwarf_enum> (const dwarf_edit::dwarf_enum&);
-  inline std::string dwarf_edit::dwarf_enum::to_string () const
-  {
-    return elfutils::to_string (*this); // Use that.
-  }
+  std::string to_string<dwarf_edit::attr_value> (const dwarf_edit::attr_value &);
 };
 
 #endif // <elfutils/dwarf_edit>
index d4d2ee6111b513c071a11f5630620e207d54ed66..ff2621ba5ef6db7bc428f1a12c417b48aac48a8f 100644 (file)
@@ -50,7 +50,8 @@
 #ifndef _ELFUTILS_DWARF_OUTPUT
 #define _ELFUTILS_DWARF_OUTPUT 1
 
-#include "dwarf"
+#include "dwarf_edit"
+#include <functional>
 
 /* Read the comments for elfutils::dwarf first.
 
 
 namespace elfutils
 {
+  class dwarf_output_collector;
+
+#if 0
   class dwarf_output
   {
   public:
     class compile_units;
+    class debug_info_entry;
+    typedef debug_info_entry compile_unit;
+
+  private:
+    template<typename input>
+    static inline const input &
+    collect (dwarf_output_collector *c,
+            const subr::auto_ref<const input> &p)
+    {
+      return static_cast<const input &> (p);
+    }
+
+    template<typename input>
+    static inline const debug_info_entry &
+    collect (dwarf_output_collector *,
+            const typename input::debug_info_entry &);
+
+  public:
 
     // XXX later
     class attr_value : public dwarf::attr_value
@@ -79,50 +101,312 @@ namespace elfutils
 
     class debug_info_entry
     {
+      friend class dwarf_output;
+
     public:
+      typedef subr::hashed_unordered_map<int, attr_value> attributes_type;
+      typedef subr::hashed_vector<debug_info_entry> children_type;
+
+    private:
+      const int _m_tag;
+      const attributes_type _m_attributes;
+      const children_type _m_children;
+      size_t _m_hash;
 
-      class children : public std::vector<debug_info_entry>
+      /* The template constructor lets us copy in from any class that has
+        compatibly iterable containers for attributes and children.  */
+      template<typename die_type>
+      debug_info_entry (const die_type &die, dwarf_output_collector *c)
+       : _m_tag (die.tag ()),
+         _m_attributes (die.attributes ()),
+         _m_children (die.children ()),
+         _m_hash (0)
       {
-       friend class debug_info_entry;
-      private:
-        children () {}
+       subr::hash_combine (_m_hash, _m_tag);
+       subr::hash_combine (_m_hash, _m_attributes);
+       subr::hash_combine (_m_hash, _m_children);
+      }
+
+    public:
+      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.attributes () == attributes ()
+               && other.children () == children ());
+      }
+      template<typename die>
+      bool operator!= (const die &other) const
+      {
+       return !(*this == other);
+      }
+    };
+
+    typedef debug_info_entry::attributes_type::value_type attribute;
+
+  public:
+    /* 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 vector is actually mutable as a std::vector.  But note that you
+       should never remove a compile_unit, though you can reorder the
+       vector.  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
+      : public std::vector<subr::auto_ref<const debug_info_entry> >
+    {
+      friend class dwarf_output;
+    private:
+      typedef std::vector<subr::auto_ref<const debug_info_entry> > _base;
+
+      template<typename input>
+      struct make
+       : public std::binary_function<typename input::value_type,
+                                     dwarf_output_collector *,
+                                     _base::value_type>
+      {
+       _base::value_type operator () (const typename input::value_type &cu,
+                                      dwarf_output_collector *c) const
+       {
+         return _base::value_type (collect (c, cu));
+       }
+      };
+
+      // Construct empty container.
+      compile_units ()
+       : _base ()
+      {}
+
+      // Constructor copying CUs from input container.
+      template<typename input>
+      compile_units (const input &units, dwarf_output_collector *c)
+       : _base ()
+      {
+       for (typename input::const_iterator it = units.begin ();
+            it != units.end ();
+            ++it)
+         push_back (make<input> () (*it, c));
+      }
+
+    public:
+      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);
+      }
+
+      void recollect (dwarf_output_collector *c)
+      {
+       std::transform (begin (), end (), begin (),
+                       std::bind2nd (make<compile_units> (), c));
+      }
+    };
+
+  private:
+    const compile_units _m_units;
+
+  public:
+    const class compile_units &compile_units () const
+    {
+      return _m_units;
+    }
+
+  public:
+    // Constructor for an empty file, can add to its compile_units ().
+    dwarf_output ()
+      : _m_units ()
+    {}
+
+    // Constructor copying CUs from an input file (can be any of dwarf,
+    // dwarf_edit, or dwarf_output).
+    template<typename input>
+    dwarf_output (const input &dw, dwarf_output_collector *c)
+      : _m_units (dw.compile_units (), c)
+    {}
 
-       template<typename childrens>
-       children (const childrens &other)
-         : std::vector<debug_info_entry> (other.begin (), other.end ()) {}
+    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);
+    }
+  };
+
+#else  // XXX temp
+
+  class dwarf_output
+  {
+  public:
+    typedef dwarf_data::source_file source_file;
+    typedef dwarf_data::directory_table directory_table;
+    typedef dwarf_data::line_entry<source_file> line_entry;
+    typedef dwarf_data::line_table<line_entry> line_table;
+    typedef dwarf_data::line_info_table<directory_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;
+    class debug_info_entry;
+
+  protected:
+
+    template<typename input>
+    static inline const std::string &
+    collect_string (dwarf_output_collector *, const input &);
+
+    /* 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 *>::wrapped
+    collectify (const typename input::const_iterator &in,
+               dwarf_output_collector *c)
+    {
+      return subr::argifier<input, output, dwarf_output_collector *> (c) (in);
+    }
+
+    struct value_wrapper
+      : public dwarf_data::value<dwarf_output>
+    {
+      struct value_string : public value_dispatch
+      {
+       const std::string &_m_str;
+
+       template<typename string>
+       inline value_string (const string &s, dwarf_output_collector *c)
+         : _m_str (collect_string (c, s))
+       {}
+
+       inline operator const std::string & () const
+       {
+         return _m_str;
+       }
+
+       std::string to_string () const
+       {
+         std::string result ("\"");
+         result += _m_str;
+         result += "\"";
+         return result;
+       }
       };
 
-      class attributes : public std::map<int, attr_value>
+      template<typename flavor, typename input>
+      static inline value_dispatch *
+      make (flavor *&result, const input &x, const dwarf_data::nothing &)
+      {
+       throw std::logic_error ("dwarf_output cannot be default-constructed");
+      }
+
+      template<typename flavor, typename input, typename arg_type>
+      static inline value_dispatch *
+      make (flavor *&result, const input &x, const arg_type &arg)
+      {
+       return result = new flavor (x, arg);
+      }
+
+      template<typename input>
+      static inline value_dispatch *
+      make (value_string *&result, const input &x, dwarf_output_collector *c)
+      {
+       return result = new value_string (x, c);
+      }
+
+    };
+
+  public:
+
+    typedef dwarf_data::attr_value<dwarf_output, value_wrapper> attr_value;
+
+    class compile_units;
+
+    class debug_info_entry
+    {
+    public:
+
+      class children_type : public std::list<debug_info_entry>
       {
        friend class debug_info_entry;
       private:
-       attributes () {}
+        children_type () {}
 
-       template<typename attrs>
-       attributes (const attrs &other)
-         : std::map<int, attr_value> (other.begin (), other.end ()) {}
+       template<typename input>
+       inline children_type (const input &other, dwarf_output_collector *c)
+         : std::list<debug_info_entry>
+           (collectify<input, children_type> (other.begin (), c),
+            collectify<input, children_type> (other.end (), c))
+       {}
 
       public:
-       template<typename attrs>
-       inline operator attrs () const
-       {
-         return attrs (begin (), end ());
-       }
+       typedef debug_info_entry value_type;
+      };
+
+      class attributes_type
+       : public dwarf_data::attributes_type<dwarf_output,
+                                            dwarf_output_collector *,
+                                            value_wrapper>
+      {
+       friend class debug_info_entry;
+      private:
+       typedef dwarf_data::attributes_type<dwarf_output,
+                                           dwarf_output_collector *,
+                                           value_wrapper> base_type;
+
+       template<typename input>
+       inline attributes_type (const input &other, dwarf_output_collector *c)
+         : base_type (other, c)
+       {}
       };
 
     private:
       const int _m_tag;
-      const attributes _m_attributes;
-      const children _m_children;
+      attributes_type _m_attributes;
+      children_type _m_children;
 
     public:
-      /* The template constructor lets us copy in from any class that has
-        compatibly iterable containers for attributes and children.  */
-      template<typename die>
-      debug_info_entry (const die &die)
+      template<typename die_type>
+      debug_info_entry (const die_type &die, dwarf_output_collector *c)
        : _m_tag (die.tag ()),
-         _m_attributes (die.attributes ()),
-         _m_children (die.children ())
+         _m_attributes (die.attributes (), c),
+         _m_children (die.children (), c)
       {}
 
       inline int tag () const
@@ -135,20 +419,20 @@ namespace elfutils
        return !_m_children.empty ();
       }
 
-      inline class children &children ()
+      inline children_type &children ()
       {
        return _m_children;
       }
-      inline const class children &children () const
+      inline const children_type &children () const
       {
        return _m_children;
       }
 
-      inline class attributes &attributes ()
+      inline attributes_type &attributes ()
       {
        return _m_attributes;
       }
-      inline const class attributes &attributes () const
+      inline const attributes_type &attributes () const
       {
        return _m_attributes;
       }
@@ -156,7 +440,8 @@ namespace elfutils
       template<typename die>
       bool operator== (const die &other) const
       {
-       return (other.attributes () == attributes ()
+       return (other.tag () == tag ()
+               && other.attributes () == attributes ()
                && other.children () == children ());
       }
       template<typename die>
@@ -164,30 +449,70 @@ namespace elfutils
       {
        return !(*this == other);;
       }
+
+      inline ::Dwarf_Off identity () const
+      {
+       return (uintptr_t) this;
+      }
+
+      inline ::Dwarf_Off offset () const
+      {
+       return identity ();
+      }
     };
 
-    typedef debug_info_entry::attributes::value_type attribute;
+    typedef debug_info_entry::attributes_type::value_type attribute;
 
     class compile_unit : public debug_info_entry
     {
+      friend class compile_units;
+
+      // XXX should be private
+    public:
+      template<typename die_type>
+      compile_unit (const die_type &die, dwarf_output_collector *c)
+       : debug_info_entry (die, c)
+      {
+       if (die.tag () != ::DW_TAG_compile_unit)
+         throw std::invalid_argument ("not a compile_unit entry");
+      }
+
+      /* XXX doesn't help
+       public:
+       compile_unit (const compile_unit &u) : debug_info_entry (u) {}
+      */
     };
 
     // Main container anchoring all the output.
-    class compile_units : public std::vector<compile_unit>
+    class compile_units
+      : public std::list<compile_unit>
     {
       friend class dwarf_output;
     private:
+      typedef std::list<compile_unit> _base;
+
+      // Default constructor: an empty container, no CUs.
+      inline compile_units ()
+       : _base ()
+      {}
+
       // Constructor copying CUs from input container.
       template<typename input>
-      compile_units(const input &units)
-       : std::vector<compile_unit> (units.begin (), units.end ())
-      {}
+      compile_units (const input &units, dwarf_output_collector *c)
+       : _base (collectify<input, compile_units> (units.begin (), c),
+                collectify<input, compile_units> (units.end (), c))
+      {
+      }
 
     public:
+      typedef compile_unit value_type;
+      typedef _base::iterator iterator;
+      typedef _base::const_iterator const_iterator;
+
       template<typename other_children>
       bool operator== (const other_children &other) const
       {
-       return std::equal (begin (), end (), other.begin ());
+       return subr::container_equal (*this, other);
       }
       template<typename other_children>
       bool operator!= (const other_children &other) const
@@ -197,18 +522,30 @@ namespace elfutils
     };
 
   private:
-    const compile_units _m_units;
+    compile_units _m_units;
 
   public:
+    class compile_units &compile_units ()
+    {
+      return _m_units;
+    }
     const class compile_units &compile_units () const
     {
       return _m_units;
     }
 
   public:
-    // Constructor copying CUs from an input file (dwarf or dwarf_output).
+    // Constructor for an empty file, can add to its compile_units ().
+    dwarf_output ()
+      : _m_units ()
+    {}
+
+    // Constructor copying CUs from an input file (can be any of dwarf,
+    // dwarf_edit, or dwarf_output).
     template<typename input>
-    dwarf_output (const input &dw) : _m_units (dw.compile_units ()) {}
+    dwarf_output (const input &dw, dwarf_output_collector *c)
+      : _m_units (dw.compile_units (), c)
+    {}
 
     template<typename file>
     inline bool operator== (const file &other) const
@@ -221,4 +558,32 @@ namespace elfutils
       return !(*this == other);
     }
   };
-}
+
+  // Explicit specializations.
+  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&);
+
+#endif
+
+  class dwarf_output_collector
+  {
+    friend class dwarf_output;
+
+  private:
+    subr::value_set<std::string> _m_strings;
+    subr::value_set<dwarf_output::range_list> _m_ranges;
+
+  };
+
+  template<typename input>
+  inline const std::string &
+  dwarf_output::collect_string (dwarf_output_collector *c, const input &s)
+  {
+    return c->_m_strings.add (s);
+  }
+
+};
+
+#endif // <elfutils/dwarf_output>
index eb957492a9bfa0fdd9254dda58b85d0fc0d8a920..7640b4caa8ee1a0c94ea4820d3e3694493b89355 100644 (file)
 
 #include <config.h>
 #include "dwarf_edit"
-
-#include <typeinfo>
+#include "data-values.hh"
 
 using namespace elfutils;
 
-
-dwarf::value_space
-dwarf_edit::attr_value::what_space () const
-{
-  if (typeid (*_m_value) == typeid (value_flag))
-    return dwarf::VS_flag;
-  if (typeid (*_m_value) == typeid (value_dwarf_constant))
-    return dwarf::VS_dwarf_constant;
-  if (typeid (*_m_value) == typeid (value_reference))
-    return dwarf::VS_reference;
-  if (typeid (*_m_value) == typeid (value_unit_reference))
-    return dwarf::VS_unit_reference;
-  if (typeid (*_m_value) == typeid (value_lineptr))
-    return dwarf::VS_lineptr;
-  if (typeid (*_m_value) == typeid (value_macptr))
-    return dwarf::VS_macptr;
-  if (typeid (*_m_value) == typeid (value_rangelistptr))
-    return dwarf::VS_rangelistptr;
-  if (typeid (*_m_value) == typeid (value_identifier))
-    return dwarf::VS_identifier;
-  if (typeid (*_m_value) == typeid (value_string))
-    return dwarf::VS_string;
-  if (typeid (*_m_value) == typeid (value_source_file))
-    return dwarf::VS_source_file;
-  if (typeid (*_m_value) == typeid (value_source_line))
-    return dwarf::VS_source_line;
-  if (typeid (*_m_value) == typeid (value_source_column))
-    return dwarf::VS_source_column;
-  if (typeid (*_m_value) == typeid (value_address))
-    return dwarf::VS_address;
-  if (typeid (*_m_value) == typeid (value_constant)
-      || typeid (*_m_value) == typeid (value_constant_block))
-    return dwarf::VS_constant;
-  if (typeid (*_m_value) == typeid (value_location))
-    return dwarf::VS_location;
-
-  throw std::runtime_error ("XXX impossible");
-}
+template dwarf::value_space dwarf_edit::attr_value::what_space () const;
 
 template<>
 std::string
@@ -104,7 +66,7 @@ to_string<dwarf_edit::attribute> (const dwarf_edit::attribute &attr)
 }
 
 std::string
-dwarf_edit::source_file::to_string () const
+dwarf_data::source_file::to_string () const
 {
   if (likely (_m_mtime == 0) && likely (_m_size == 0))
     return "\"" + _m_name + "\"";
@@ -115,7 +77,7 @@ dwarf_edit::source_file::to_string () const
 }
 
 std::string
-dwarf_edit::location_attr::to_string () const
+dwarf_data::location_attr::to_string () const
 {
   return is_list () ? "XXX-loclist" : "XXX-expr";
 }
index 1bb84f1375183404c4ca950b34547f4721a3baba..a7788416e396a49788aa49b08da77c529495c066 100644 (file)
@@ -217,13 +217,13 @@ dwarf::dwarf_enum::name () const
 }
 
 const char *
-dwarf_edit::dwarf_enum::identifier () const
+dwarf_data::dwarf_enum::identifier () const
 {
   return enum_identifier (*this);
 }
 
 const char *
-dwarf_edit::dwarf_enum::name () const
+dwarf_data::dwarf_enum::name () const
 {
   return enum_name (*this);
 }
@@ -245,7 +245,7 @@ to_string<dwarf::dwarf_enum> (const dwarf::dwarf_enum &value)
 
 template<>
 string
-to_string<dwarf_edit::dwarf_enum> (const dwarf_edit::dwarf_enum &value)
+to_string<dwarf_data::dwarf_enum> (const dwarf_data::dwarf_enum &value)
 {
   return enum_string (value);
 }
diff --git a/libdw/c++/output-values.cc b/libdw/c++/output-values.cc
new file mode 100644 (file)
index 0000000..d50abb8
--- /dev/null
@@ -0,0 +1,68 @@
+/* elfutils::dwarf_output attribute value interfaces.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   In addition, as a special exception, Red Hat, Inc. gives You the
+   additional right to link the code of Red Hat elfutils with code licensed
+   under any Open Source Initiative certified open source license
+   (http://www.opensource.org/licenses/index.php) which requires the
+   distribution of source code with any binary distribution and to
+   distribute linked combinations of the two.  Non-GPL Code permitted under
+   this exception must only link to the code of Red Hat elfutils through
+   those well defined interfaces identified in the file named EXCEPTION
+   found in the source code files (the "Approved Interfaces").  The files
+   of Non-GPL Code may instantiate templates or use macros or inline
+   functions from the Approved Interfaces without causing the resulting
+   work to be covered by the GNU General Public License.  Only Red Hat,
+   Inc. may make changes or additions to the list of Approved Interfaces.
+   Red Hat's grant of this exception is conditioned upon your not adding
+   any new exceptions.  If you wish to add a new Approved Interface or
+   exception, please contact Red Hat.  You must obey the GNU General Public
+   License in all respects for all of the Red Hat elfutils code and other
+   code used in conjunction with Red Hat elfutils except the Non-GPL Code
+   covered by this exception.  If you modify this file, you may extend this
+   exception to your version of the file, but you are not obligated to do
+   so.  If you do not wish to provide this exception without modification,
+   you must delete this exception statement from your version and license
+   this file solely under the GPL without exception.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <config.h>
+#include "dwarf_output"
+#include "data-values.hh"
+
+#include <typeinfo>
+
+using namespace elfutils;
+
+template dwarf::value_space dwarf_output::attr_value::what_space () const;
+
+template<>
+std::string
+to_string<dwarf_output::attribute> (const dwarf_output::attribute &attr)
+{
+  std::string result = dwarf::attributes::name (attr.first);
+  result += "=";
+  result += attr.second.to_string ();
+  return result;
+}
index e11846279356188df18bee241b8da9dd3f883d62..7a799eeb82247a39707d3921049c4855cddb1f59 100644 (file)
 #include <cstring>
 #include <iostream>
 #include <sstream>
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+#include <vector>
+#include <algorithm>
+#include <utility>
 
 namespace elfutils
 {
   namespace subr
   {
+    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>
+    struct integer_hash : public std::unary_function<T, size_t>
+    {
+      inline size_t operator () (const T &x) const
+      {
+       return x;
+      }
+    };
+    template<>
+    struct hash<int> : public integer_hash<int> {};
+    template<>
+    struct hash<uint64_t> : public integer_hash<uint64_t> {};
+
+    template<typename T>
+    struct container_hasher : public std::unary_function<T, size_t>
+    {
+      struct hasher
+      {
+       size_t _m_hash;
+       inline hasher () : _m_hash (0) {}
+       inline void operator () (const typename T::value_type &x)
+       {
+         subr::hash_combine (_m_hash, hash_this (x));
+       }
+      };
+
+      inline size_t operator () (const T &x) const
+      {
+       hasher h;
+       std::for_each (x.begin (), x.end (), h);
+       return h._m_hash;
+      }
+    };
+
+    template<>
+    struct hash<std::string>
+    {
+    private:
+      struct hasher : public container_hasher<std::string>::hasher
+      {
+       inline void operator () (std::string::value_type c)
+       {
+         _m_hash = 5 * _m_hash + c;
+       }
+      };
+    public:
+      inline size_t operator () (const std::string &x) const
+      {
+       hasher h;
+       std::for_each (x.begin (), x.end (), h);
+       return h._m_hash;
+      }
+    };
+
+    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)
+      inline bool operator () (const mystring &me, const string &you) const
       {
        return you == me;
       }
@@ -30,12 +121,12 @@ namespace elfutils
     struct name_equal<const char *>
       : public std::binary_function<const char *, const char *, bool>
     {
-      bool operator () (const char *me, const char *you)
+      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)
+      inline bool operator () (const mystring &me, const char *you) const
       {
        return me == you;
       }
@@ -71,7 +162,7 @@ namespace elfutils
     template<typename t1, typename t2>
     struct equal_to : public std::binary_function<t1, t2, bool>
     {
-      inline bool operator () (const t1 &a, const t2 &b)
+      inline bool operator () (const t1 &a, const t2 &b) const
       {
        return a == b;
       }
@@ -96,7 +187,7 @@ namespace elfutils
       {}
 
       inline bool operator () (const typename t1::const_iterator &a,
-                              const typename t2::const_iterator &b)
+                              const typename t2::const_iterator &b) const
       {
        return _m_pred (*a, *b);
       }
@@ -262,6 +353,348 @@ namespace elfutils
        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));
+      }
+    };
+
+    // 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;
+
+    private:
+      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 elt_type &p)
+         {
+           subr::hash_combine (_m_hash, p.first);
+         }
+       };
+       std::for_each (_base::begin (), _base::end (), hashit (_m_hash));
+      }
+
+    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), _m_hash (0)
+      {
+       set_hash ();
+      }
+
+      template<typename other_container>
+      hashed_container (const other_container &other)
+       : _base (other.begin (), other.end ()), _m_hash (0)
+      {
+       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 ()));
+      }
+    };
+
+    // 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)
+         {
+           subr::hash_combine (_m_hash, hash_this (p.first));
+           subr::hash_combine (_m_hash, p.second.first);
+         }
+       };
+       std::for_each (_base::begin (), _base::end (), 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, typename 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 (const _base &i, wrapper &w)
+       : _base (static_cast<_base> (i)), _m_wrapper (&w)
+      {}
+
+      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* ());
+      }
+    };
+
+    /* 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>
+    {
+      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>
+      {
+       arg_type _m_arg;
+       explicit inline maker (const arg_type &c) : _m_arg (c) {}
+
+       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 subr::wrapped_input_iterator<input, maker> wrapped;
+
+      inline wrapped operator () (const inny &i)
+      {
+       return wrapped (i, _m_maker);
+      }
+    };
+
+    template<typename input, typename output, typename arg_type>
+    static inline typename argifier<input, output, arg_type>::wrapped
+    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 maker
+       : public std::unary_function<inlet, outlet>
+      {
+       arg_type _m_arg;
+       explicit inline maker (const arg_type &c) : _m_arg (c) {}
+
+       inline outlet operator () (const inlet &x) const
+       {
+         return std::make_pair (x.first,
+                                typename outlet::second_type (x.second,
+                                                              _m_arg));
+       }
+      } _m_maker;
+
+      explicit inline argifier2nd (const arg_type &c)
+       : _m_maker (c)
+      {}
+
+      typedef subr::wrapped_input_iterator<input, maker> wrapped;
+
+      inline wrapped operator () (const inny &i)
+      {
+       return wrapped (i, _m_maker);
+      }
+    };
+
+    template<typename input, typename output, typename arg_type>
+    static inline typename argifier2nd<input, output, arg_type>::wrapped
+    argify2nd (const typename input::const_iterator &in, const arg_type &arg)
+    {
+      return argifier2nd<input, output, arg_type> (arg) (in);
+    }
+
   };
 };
 
index 5e0eda23fd925892b406a5f978cd49afcc69ef47..109db05a8d0d5368472e90351230b08fa841f0ed 100644 (file)
@@ -51,6 +51,7 @@
 #include <cassert>
 #include "dwarf"
 #include "dwarf_edit"
+#include "dwarf_output"
 
 extern "C"
 {
@@ -232,6 +233,16 @@ value_string (const value_type &value)
   throw std::runtime_error ("XXX unsupported value space");
 }
 
+template<>
+string
+to_string<dwarf::attribute> (const dwarf::attribute &attr)
+{
+  std::string result = dwarf::attributes::name (attr.first);
+  result += "=";
+  result += attr.second.to_string ();
+  return result;
+}
+
 template<>
 string
 to_string<dwarf::attr_value> (const dwarf::attr_value &value)
@@ -246,6 +257,12 @@ 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)                                       \
index 190a33d7cf2f818075374081571cbc8d74282bba..e521df840e131b3d44207415b1c7822448d616e3 100644 (file)
@@ -1,3 +1,8 @@
+2009-07-02  Roland McGrath  <roland@redhat.com>
+
+       * dwarfcmp.cc (main): Update -T constructors using tracker.
+       Instantiate and test dwarf_output for -T too.
+
 2009-07-01  Roland McGrath  <roland@redhat.com>
 
        * dwarfcmp.cc (talker): Update constructor parameters.
index 4deff59dc4ecd7e6d7d93e498ab3b8f7d0fdc01c..677a5bebae85f756bb82bdae41e77d3d822d0ede 100644 (file)
@@ -47,6 +47,7 @@
 #include "c++/dwarf_edit"
 #include "c++/dwarf_comparator"
 #include "c++/dwarf_tracker"
+#include "c++/dwarf_output"
 
 using namespace elfutils;
 using namespace std;
@@ -133,8 +134,8 @@ struct talker : public dwarf_ref_tracker<dwarf1, dwarf2>
   typedef typename _base::cu2 cu2;
   typedef typename _base::die1 die1;
   typedef typename _base::die2 die2;
-  typedef typename die1::value_type::attributes_type::const_iterator attr1;
-  typedef typename die2::value_type::attributes_type::const_iterator attr2;
+  typedef typename _base::dwarf1_die::attributes_type::const_iterator attr1;
+  typedef typename _base::dwarf2_die::attributes_type::const_iterator attr2;
 
   const typename dwarf1::debug_info_entry *a_;
   const typename dwarf2::debug_info_entry *b_;
@@ -324,9 +325,28 @@ main (int argc, char *argv[])
 
       if (test_writer)
        {
-         dwarf_edit out1 (file1);
-         dwarf_edit out2 (file2);
-         test_classes (file1, file2, out1, out2, same);
+         dwarf_ref_tracker<dwarf_edit, dwarf> t1;
+         dwarf_ref_tracker<dwarf_edit, dwarf> t2;
+         dwarf_edit edit1 (file1, &t1);
+         dwarf_edit edit2 (file2, &t2);
+         test_classes (file1, file2, edit1, edit2, same);
+
+         {
+           dwarf_output_collector c1;
+           dwarf_output_collector c2;
+           dwarf_output out1 (file1, &c1);
+           dwarf_output out2 (file2, &c2);
+           test_classes (file1, file2, out1, out2, same);
+           test_classes (edit1, edit2, out1, out2, same);
+         }
+         {
+           dwarf_output_collector c1;
+           dwarf_output_collector c2;
+           dwarf_output out1 (edit1, &c1);
+           dwarf_output out2 (edit2, &c2);
+           test_classes (file1, file2, out1, out2, same);
+           test_classes (edit1, edit2, out1, out2, same);
+         }
        }
 
       result = !same;
index b988cfec07cdf4235ca1a5f214c8c03260363c9b..d7c99a187b9ce74136876877a7d0ea4dac07ca18 100644 (file)
@@ -1,3 +1,14 @@
+2009-07-02  Roland McGrath  <roland@redhat.com>
+
+       * run-dwarf_edit.sh: New file.
+       * dwarf_edit.cc: New file.
+       * Makefile.am (noinst_PROGRAMS, TESTS, EXTRA_DIST): Add them.
+       (dwarf_edit_SOURCES, dwarf_edit_LDADD): New variables.
+
+       * dwarf-print.cc (print_die): Templatify and move ...
+       * print-die.hh: ... here, new file.
+       * Makefile.am (noinst_HEADERS): New variable, add it.
+
 2009-07-01  Roland McGrath  <roland@redhat.com>
 
        * run-dwarfcmp-self.sh: Run on dwarflint too.
index ba95008852a4001a3c1fa25d9fb101af2b52030e..41cd9f3288150432b127e9999bd9e8b3f8a53b3a 100644 (file)
@@ -52,6 +52,8 @@ else
 tests_rpath = no
 endif
 
+noinst_HEADERS = print-die.hh
+
 noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  showptable update1 update2 update3 update4 test-nlist \
                  show-die-info get-files get-lines get-pubnames \
@@ -60,7 +62,8 @@ noinst_PROGRAMS = arextract arsymtest newfile saridx scnnames sectiondump \
                  find-prologues funcretval allregs rdwrmmap \
                  dwfl-bug-addr-overflow arls dwfl-bug-fd-leak \
                  dwfl-addr-sect dwfl-bug-report early-offscn \
-                 dwfl-bug-getmodules dwarf-getmacros dwarf-print
+                 dwfl-bug-getmodules dwarf-getmacros dwarf-print \
+                 dwarf_edit
 # get-ciefde
 asm_TESTS = asm-tst1 asm-tst2 asm-tst3 asm-tst4 asm-tst5 \
            asm-tst6 asm-tst7 asm-tst8 asm-tst9
@@ -87,7 +90,8 @@ TESTS = run-arextract.sh run-arsymtest.sh newfile test-nlist \
        run-dwfl-bug-offline-rel.sh run-dwfl-addr-sect.sh \
        run-disasm-x86.sh run-disasm-x86-64.sh \
        run-early-offscn.sh run-dwarf-getmacros.sh \
-       run-dwarfcmp-self.sh run-dwarflint-self.sh run-dwarf-attributes.sh
+       run-dwarfcmp-self.sh run-dwarflint-self.sh run-dwarf-attributes.sh \
+       run-dwarf_edit.sh
 # run-show-ciefde.sh
 
 if !STANDALONE
@@ -122,7 +126,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             run-dwfl-addr-sect.sh run-early-offscn.sh \
             run-dwarf-getmacros.sh \
             run-dwarfcmp-self.sh run-dwarflint-self.sh \
-            run-dwarf-attributes.sh \
+            run-dwarf-attributes.sh run-dwarf_edit.sh \
             testfile15.bz2 testfile15.debug.bz2 \
             testfile16.bz2 testfile16.debug.bz2 \
             testfile17.bz2 testfile17.debug.bz2 \
@@ -193,6 +197,9 @@ libdwpp = ../libdw/libdwpp.a $(libdw)
 dwarf_print_SOURCES = dwarf-print.cc
 dwarf_print_LDADD = $(libdwpp) $(libmudflap) -ldl
 
+dwarf_edit_SOURCES = dwarf_edit.cc
+dwarf_edit_LDADD = $(libdwpp) $(libmudflap) -ldl
+
 arextract_LDADD = $(libelf) $(libmudflap)
 arsymtest_LDADD = $(libelf) $(libmudflap)
 newfile_LDADD = $(libelf) $(libmudflap)
index d37a006a041bc18baa855152764db422c63f52c4..36b9415beed324ea15793e6faf203f2328797fe7 100644 (file)
 #include <errno.h>
 #include <error.h>
 #include <fcntl.h>
-#include <clocale>
-#include <cstdio>
-#include <libintl.h>
-#include <ostream>
-#include <iomanip>
 
 #include "c++/dwarf"
 
 using namespace elfutils;
 using namespace std;
 
+#include "print-die.hh"
+
 static Dwarf *
 open_file (const char *fname)
 {
@@ -57,75 +54,14 @@ open_file (const char *fname)
   return dw;
 }
 
-static void
-print_die (const dwarf::debug_info_entry &die,
-          unsigned int indent, unsigned int limit)
-{
-  string prefix (indent, ' ');
-  const string tag = dwarf::tags::name (die.tag ());
-
-  cout << prefix << "<" << tag << " offset=[" << die.offset () << "]";
-
-  for (dwarf::debug_info_entry::attributes_type::const_iterator i
-        = die.attributes ().begin (); i != die.attributes ().end (); ++i)
-    cout << " " << (*i).to_string ();
-
-  if (die.has_children ())
-    {
-      if (limit != 0 && indent >= limit)
-       {
-         cout << ">...\n";
-         return;
-       }
-
-      cout << ">\n";
-
-      for (dwarf::debug_info_entry::children_type::const_iterator i
-            = die.children ().begin (); i != die.children ().end (); ++i)
-       print_die (*i, indent + 1, limit);
-
-      cout << prefix << "</" << tag << ">\n";
-    }
-  else
-    cout << "/>\n";
-}
-
-static void
-process_file (const char *file, unsigned int limit)
-{
-  dwarf dw (open_file (file));
-
-  cout << file << ":\n";
-
-  for (dwarf::compile_units::const_iterator i = dw.compile_units ().begin ();
-       i != dw.compile_units ().end ();
-       ++i)
-    print_die (*i, 1, limit);
-}
-
 int
 main (int argc, char *argv[])
 {
-  /* Set locale.  */
-  (void) setlocale (LC_ALL, "");
-
-  /* Make sure the message catalog can be found.  */
-  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
-
-  /* Initialize the message catalog.  */
-  (void) textdomain (PACKAGE_TARNAME);
-
-  cout << hex << setiosflags (ios::showbase);
-
-  unsigned int depth = 0;
-  if (argc > 1 && sscanf (argv[1], "--depth=%u", &depth) == 1)
-    {
-      --argc;
-      ++argv;
-    }
+  unsigned int depth;
+  print_die_main (argc, argv, depth);
 
   for (int i = 1; i < argc; ++i)
-    process_file (argv[i], depth);
+    print_file (argv[i], dwarf (open_file (argv[i])), depth);
 
   return 0;
 }
diff --git a/tests/dwarf_edit.cc b/tests/dwarf_edit.cc
new file mode 100644 (file)
index 0000000..5510be1
--- /dev/null
@@ -0,0 +1,59 @@
+/* Test program for elfutils::dwarf_edit basics.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "c++/dwarf_edit"
+
+using namespace elfutils;
+using namespace std;
+
+#include "print-die.hh"
+
+
+int
+main (int argc, char **argv)
+{
+  unsigned int depth;
+  print_die_main (argc, argv, depth);
+
+  dwarf_edit f;
+
+  dwarf_edit::compile_unit &cu = f.add_unit ();
+
+  cu.attributes ()[DW_AT_name].source_file () = "source-file.c";
+
+  dwarf_edit::debug_info_entry &ent = cu.add_entry (DW_TAG_subprogram);
+
+  ent.attributes ()[DW_AT_name].identifier () = "foo";
+
+  ent.attributes ()[DW_AT_description] = ent.attributes ()[DW_AT_name];
+
+  print_file ("consed", f, depth);
+
+  return 0;
+}
diff --git a/tests/print-die.hh b/tests/print-die.hh
new file mode 100644 (file)
index 0000000..91d70c9
--- /dev/null
@@ -0,0 +1,117 @@
+/* Pseudo-XMLish printing for elfutils::dwarf* tests.
+   Copyright (C) 2009 Red Hat, Inc.
+   This file is part of Red Hat elfutils.
+
+   Red Hat elfutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by the
+   Free Software Foundation; version 2 of the License.
+
+   Red Hat elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Red Hat elfutils; if not, write to the Free Software Foundation,
+   Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+
+   Red Hat elfutils is an included package of the Open Invention Network.
+   An included package of the Open Invention Network is a package for which
+   Open Invention Network licensees cross-license their patents.  No patent
+   license is granted, either expressly or impliedly, by designation as an
+   included package.  Should you wish to participate in the Open Invention
+   Network licensing program, please visit www.openinventionnetwork.com
+   <http://www.openinventionnetwork.com>.  */
+
+#include <cstring>
+#include <cstdio>
+#include <clocale>
+#include <libintl.h>
+#include <ostream>
+#include <iomanip>
+
+static bool print_offset;
+
+static void
+print_die_main (int &argc, char **&argv, unsigned int &depth)
+{
+  /* Set locale.  */
+  (void) setlocale (LC_ALL, "");
+
+  /* Make sure the message catalog can be found.  */
+  (void) bindtextdomain (PACKAGE_TARNAME, LOCALEDIR);
+
+  /* Initialize the message catalog.  */
+  (void) textdomain (PACKAGE_TARNAME);
+
+  cout << hex << setiosflags (ios::showbase);
+
+  if (argc > 1 && !strcmp (argv[1], "--offsets"))
+    {
+      print_offset = true;
+      --argc;
+      ++argv;
+    }
+
+  depth = 0;
+  if (argc > 1 && sscanf (argv[1], "--depth=%u", &depth) == 1)
+    {
+      --argc;
+      ++argv;
+    }
+}
+
+template<typename file>
+static void
+print_die (const typename file::debug_info_entry &die,
+          unsigned int indent, unsigned int limit)
+{
+  string prefix (indent, ' ');
+  const string tag = dwarf::tags::name (die.tag ());
+
+  cout << prefix << "<" << tag;
+  if (print_offset)
+    cout << " offset=[" << die.offset () << "]";
+
+  for (typename file::debug_info_entry::attributes_type::const_iterator i
+        = die.attributes ().begin (); i != die.attributes ().end (); ++i)
+    cout << " " << to_string (*i);
+
+  if (die.has_children ())
+    {
+      if (limit != 0 && indent >= limit)
+       {
+         cout << ">...\n";
+         return;
+       }
+
+      cout << ">\n";
+
+      for (typename file::debug_info_entry::children_type::const_iterator i
+            = die.children ().begin (); i != die.children ().end (); ++i)
+       print_die<file> (*i, indent + 1, limit);
+
+      cout << prefix << "</" << tag << ">\n";
+    }
+  else
+    cout << "/>\n";
+}
+
+template<typename file>
+static void
+print_cu (const typename file::compile_unit &cu, const unsigned int limit)
+{
+  print_die<file> (static_cast<const typename file::debug_info_entry &> (cu),
+                  1, limit);
+}
+
+template<typename file>
+static void
+print_file (const char *name, const file &dw, const unsigned int limit)
+{
+  cout << name << ":\n";
+
+  for (typename file::compile_units::const_iterator i
+        = dw.compile_units ().begin (); i != dw.compile_units ().end (); ++i)
+    print_cu<file> (*i, limit);
+}
index 22c7289d9ce9ada1600f1bfac76acba772265334..4aa170ba73f07bde9af6aca5873088c661ab635c 100755 (executable)
@@ -27,7 +27,7 @@
 
 testfiles testfile
 
-testrun_compare ./dwarf-print --depth=1 testfile <<\EOF
+testrun_compare ./dwarf-print --offsets --depth=1 testfile <<\EOF
 testfile:
  <compile_unit offset=[0xb] stmt_list=0 high_pc=0x804845a low_pc=0x804842c name="m.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=C89>...
  <compile_unit offset=[0xca] stmt_list=0x4b high_pc=0x8048466 low_pc=0x804845c name="b.c" comp_dir="/home/drepper/gnu/new-bu/build/ttt" producer="GNU C 2.96 20000731 (Red Hat Linux 7.0)" language=C89>...
diff --git a/tests/run-dwarf_edit.sh b/tests/run-dwarf_edit.sh
new file mode 100755 (executable)
index 0000000..a7b0baf
--- /dev/null
@@ -0,0 +1,35 @@
+#! /bin/sh
+# Copyright (C) 2009 Red Hat, Inc.
+# This file is part of Red Hat elfutils.
+#
+# Red Hat elfutils is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by the
+# Free Software Foundation; version 2 of the License.
+#
+# Red Hat elfutils is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Red Hat elfutils; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
+#
+# Red Hat elfutils is an included package of the Open Invention Network.
+# An included package of the Open Invention Network is a package for which
+# Open Invention Network licensees cross-license their patents.  No patent
+# license is granted, either expressly or impliedly, by designation as an
+# included package.  Should you wish to participate in the Open Invention
+# Network licensing program, please visit www.openinventionnetwork.com
+# <http://www.openinventionnetwork.com>.
+
+. $srcdir/test-subr.sh
+
+testrun_compare ./dwarf_edit <<\EOF
+consed:
+ <compile_unit name="source-file.c">
+  <subprogram name="foo" description="foo"/>
+ </compile_unit>
+EOF
+
+exit 0