This is the mail archive of the elfutils-devel@sourceware.org mailing list for the elfutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 2/2] Add C++ iterators


Hello,

as requested by Mark, I made the iterator interfaces ABI stable, so that
they can be safely used on API boundaries of third-party libraries.
This patch should also include all the other points that we talked about
(from the top of my head: returning reference from operator++, dropping
of offset member function, change from cu_iterator to unit_iterator),
except for exceptions, which are still std::runtime_error.

This adds a new library, libdwpp, which implements these interfaces.
The interfaces themselves are fully pimpl'd.  Actual class layout
etc. is fully internal detail--on the outside we publish one pointer
field.  Due to this, the iterators are more heavyweight, involving a
dynamic allocation for each instance, and PLT call for each operation,
but on the other hand, virtually no ABI breakage is possible.

Symbols are versioned.  This ties us closely to the GCC ABI, but I think
everybody uses Itanium ABI these days anyway.  This also means that if
there should be a change in behavior that would constitute an ABI
breakage, it can be mitigated the same way as with C symbols.

I hid many symbols as well.  Namely the private constructors are not
exported at all, and I have also hidden the not-in-charge constructor
and destructor variants, because those should only come into play when
the iterators are inherited from, which they are not designed for.

The test case was extended to at least use each of the iterators, albeit
in somewhat limited manner.  dwgrep, when adapted, builds and passes
test suite fine as well.

Thanks,
Petr

--- 8< ---------------------------------------------------------------

- Add unit_iterator, child_iterator, die_tree_iterator and
  attr_iterator for libdw, and dwfl_module_iterator for libdwfl.

- The code is shipped in a new library called libdwpp with versioned
  symbols.

Signed-off-by: Petr Machata <pmachata@redhat.com>
---
 ChangeLog                           |   4 +
 NEWS                                |   5 +-
 libdw/ChangeLog                     |  21 ++++
 libdw/Makefile.am                   |  62 ++++++++-
 libdw/c++/attr_iterator.cc          | 172 +++++++++++++++++++++++++
 libdw/c++/child_iterator.cc         | 143 +++++++++++++++++++++
 libdw/c++/die_tree_iterator.cc      | 213 +++++++++++++++++++++++++++++++
 libdw/c++/libdw                     | 245 ++++++++++++++++++++++++++++++++++++
 libdw/c++/libdwP.hh                 |  88 +++++++++++++
 libdw/c++/unit_iterator.cc          | 204 ++++++++++++++++++++++++++++++
 libdw/libdwpp.map                   | 199 +++++++++++++++++++++++++++++
 libdwfl/ChangeLog                   |  13 ++
 libdwfl/Makefile.am                 |  33 ++++-
 libdwfl/c++/dwfl_module_iterator.cc | 154 +++++++++++++++++++++++
 libdwfl/c++/libdwfl                 |  70 +++++++++++
 libdwfl/c++/libdwflP.hh             |  44 +++++++
 tests/ChangeLog                     |   7 ++
 tests/Makefile.am                   |  12 +-
 tests/run-test-iterators.sh         |  52 ++++++++
 tests/test-iterators.cc             |  87 +++++++++++++
 20 files changed, 1820 insertions(+), 8 deletions(-)
 create mode 100644 libdw/c++/attr_iterator.cc
 create mode 100644 libdw/c++/child_iterator.cc
 create mode 100644 libdw/c++/die_tree_iterator.cc
 create mode 100644 libdw/c++/libdw
 create mode 100644 libdw/c++/libdwP.hh
 create mode 100644 libdw/c++/unit_iterator.cc
 create mode 100644 libdw/libdwpp.map
 create mode 100644 libdwfl/c++/dwfl_module_iterator.cc
 create mode 100644 libdwfl/c++/libdwfl
 create mode 100644 libdwfl/c++/libdwflP.hh
 create mode 100755 tests/run-test-iterators.sh
 create mode 100644 tests/test-iterators.cc

diff --git a/ChangeLog b/ChangeLog
index 6c6f216..99c2450 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2015-04-03  Petr Machata  <pmachata@redhat.com>
+
+	* NEWS: Mention <elfutils/libdw>, <elfutils/libdwfl>, and libdwpp.
+
 2015-03-18  Petr Machata  <pmachata@redhat.com>
 
 	* configure.ac (HAVE_CXX): New conditional.
diff --git a/NEWS b/NEWS
index 60aa995..02f8691 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,9 @@
 Version 0.162
 
-libdw: Install new header elfutils/known-dwarf.h.
+libdw: Install new headers elfutils/known-dwarf.h, elfutils/libdw.
+libdwfl: Install new header elfutils/libdwfl.
+libdwpp: New library, contains the code for <elfutils/libdw> and
+         <elfutils/libdwfl> C++ interfaces.
 
 Version 0.161
 
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 4fb4763..30bb80c 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -7,6 +7,27 @@
 	of white-listing valid tags.
 	* dwarf_getsrclines.c (dwarf_getsrclines.c): Likewise.
 
+2015-03-17  Petr Machata  <pmachata@redhat.com>
+
+	* c++: New directory.
+	* c++/libdw, c++/libdwP.hh: New header files.
+	* libdwpp.map: New version script file.
+	* c++/attr_iterator.cc, c++/child_iterator.cc: New files.
+	* c++/die_tree_iterator.cc, c++/unit_iterator.cc: Likewise.
+	* Makefile.am (AUTOMAKE_OPTIONS): New variable.
+	[HAVE_CXX] (lib_LIBRARIES): Add libdwpp.a.
+	[HAVE_CXX] (noinst_LIBRARIES): Add libdwpp_pic.a.
+	[HAVE_CXX] (pkginclude_HEADERS): Add c++/libdw.
+	[HAVE_CXX] (libdwpp_a_SOURCES, libdwpp_so_SOURCES): New variables.
+	[HAVE_CXX] (libdwpp_pic_a_SOURCES, am_libdwpp_pic_a_OBJECTS): Likewise.
+	[HAVE_CXX] (libdwpp.so$(EXEEXT)): New rule.
+	(INSTALL_DEPS): New variable, contains libdwpp.so if HAVE_CXX.
+	(install): Depend on $(INSTALL_DEPS).
+	[HAVE_CXX] (install): Install libdwpp.so et.al.
+	[HAVE_CXX] (uninstall): Uninstall them.
+	(EXTRA_DIST): Add libdwpp.map.
+	(MOSTLYCLEANFILES): Add libdwpp-related files.
+
 2015-03-18  Petr Machata  <pmachata@redhat.com>
 
 	* Makefile.am (pkginclude_HEADERS): Add known-dwarf.h.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 272289c..8f43e76 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -1,6 +1,6 @@
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2002-2010, 2012, 2014 Red Hat, Inc.
+## Copyright (C) 2002-2010, 2012, 2014, 2015 Red Hat, Inc.
 ## This file is part of elfutils.
 ##
 ## This file is free software; you can redistribute it and/or modify
@@ -34,12 +34,26 @@ endif
 AM_CPPFLAGS += -I$(srcdir)/../libelf
 VERSION = 1
 
+# For c++/ subdir.
+AUTOMAKE_OPTIONS = subdir-objects
+
 lib_LIBRARIES = libdw.a
+if HAVE_CXX
+lib_LIBRARIES += libdwpp.a
+endif
+
 noinst_LIBRARIES = libdw_pic.a
+if HAVE_CXX
+noinst_LIBRARIES += libdwpp_pic.a
+endif
+
 noinst_PROGRAMS = $(noinst_LIBRARIES:_pic.a=.so)
 
 include_HEADERS = dwarf.h
 pkginclude_HEADERS = libdw.h known-dwarf.h
+if HAVE_CXX
+pkginclude_HEADERS += c++/libdw
+endif
 
 libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
 		  dwarf_getpubnames.c dwarf_getabbrev.c dwarf_tag.c \
@@ -91,6 +105,11 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
 		  dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
 		  dwarf_cu_die.c dwarf_peel_type.c
 
+if HAVE_CXX
+libdwpp_a_SOURCES = c++/unit_iterator.cc c++/die_tree_iterator.cc	\
+		    c++/child_iterator.cc c++/attr_iterator.cc
+endif
+
 if MAINTAINER_MODE
 BUILT_SOURCES = $(srcdir)/known-dwarf.h
 MAINTAINERCLEANFILES = $(srcdir)/known-dwarf.h
@@ -102,6 +121,11 @@ endif
 libdw_pic_a_SOURCES =
 am_libdw_pic_a_OBJECTS = $(libdw_a_SOURCES:.c=.os)
 
+if HAVE_CXX
+libdwpp_pic_a_SOURCES =
+am_libdwpp_pic_a_OBJECTS = $(libdwpp_a_SOURCES:.cc=.os)
+endif
+
 libdw_so_SOURCES =
 libdw.so$(EXEEXT): $(srcdir)/libdw.map libdw_pic.a ../libdwelf/libdwelf_pic.a \
 	  ../libdwfl/libdwfl_pic.a ../libebl/libebl.a \
@@ -116,16 +140,45 @@ libdw.so$(EXEEXT): $(srcdir)/libdw.map libdw_pic.a ../libdwelf/libdwelf_pic.a \
 	@$(textrel_check)
 	ln -fs $@ $@.$(VERSION)
 
-install: install-am libdw.so
+if HAVE_CXX
+libdwpp_so_SOURCES =
+libdwpp.so$(EXEEXT): $(srcdir)/libdwpp.map libdwpp_pic.a ../libdwfl/libdwflpp_pic.a \
+		     libdw.so$(EXEEXT)
+	$(CXXLINK) -shared -o $@ -Wl,--soname,$@.$(VERSION),-z,defs \
+		-Wl,--enable-new-dtags \
+		-Wl,--version-script,$<,--no-undefined \
+		-Wl,--whole-archive $(filter-out $<,$^) -Wl,--no-whole-archive\
+		libdw.so$(EXEEXT)
+	@$(textrel_check)
+	ln -fs $@ $@.$(VERSION)
+endif
+
+if HAVE_CXX
+INSTALL_DEPS = libdwpp.so
+else
+INSTALL_DEPS =
+endif
+
+install: install-am libdw.so $(INSTALL_DEPS)
 	$(mkinstalldirs) $(DESTDIR)$(libdir)
 	$(INSTALL_PROGRAM) libdw.so $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
 	ln -fs libdw-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdw.so.$(VERSION)
 	ln -fs libdw.so.$(VERSION) $(DESTDIR)$(libdir)/libdw.so
+if HAVE_CXX
+	$(INSTALL_PROGRAM) libdwpp.so $(DESTDIR)$(libdir)/libdwpp-$(PACKAGE_VERSION).so
+	ln -fs libdwpp-$(PACKAGE_VERSION).so $(DESTDIR)$(libdir)/libdwpp.so.$(VERSION)
+	ln -fs libdwpp.so.$(VERSION) $(DESTDIR)$(libdir)/libdwpp.so
+endif
 
 uninstall: uninstall-am
 	rm -f $(DESTDIR)$(libdir)/libdw-$(PACKAGE_VERSION).so
 	rm -f $(DESTDIR)$(libdir)/libdw.so.$(VERSION)
 	rm -f $(DESTDIR)$(libdir)/libdw.so
+if HAVE_CXX
+	rm -f $(DESTDIR)$(libdir)/libdwpp-$(PACKAGE_VERSION).so
+	rm -f $(DESTDIR)$(libdir)/libdwpp.so.$(VERSION)
+	rm -f $(DESTDIR)$(libdir)/libdwpp.so
+endif
 	rmdir --ignore-fail-on-non-empty $(DESTDIR)$(includedir)/elfutils
 
 libdwfl_objects = $(shell $(AR) t ../libdwfl/libdwfl.a)
@@ -137,6 +190,7 @@ libdw_a_LIBADD += $(addprefix ../libdwelf/,$(libdwelf_objects))
 noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \
 		 dwarf_sig8_hash.h cfi.h encoded-value.h
 
-EXTRA_DIST = libdw.map
+EXTRA_DIST = libdw.map libdwpp.map
 
-MOSTLYCLEANFILES = $(am_libdw_pic_a_OBJECTS) libdw.so.$(VERSION)
+MOSTLYCLEANFILES = $(am_libdw_pic_a_OBJECTS) libdw.so.$(VERSION) \
+	$(am_libdwpp_pic_a_OBJECTS) libdwpp.so.$(VERSION)
diff --git a/libdw/c++/attr_iterator.cc b/libdw/c++/attr_iterator.cc
new file mode 100644
index 0000000..ade1b53
--- /dev/null
+++ b/libdw/c++/attr_iterator.cc
@@ -0,0 +1,172 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdw"
+#include "libdwP.hh"
+
+struct elfutils::attr_iterator::pimpl
+{
+  Dwarf_Die *m_die;
+  Dwarf_Attribute m_at;
+  ptrdiff_t m_offset;
+
+  struct cb_data
+  {
+    // The visited attribute.
+    Dwarf_Attribute *at;
+
+    // Whether this is second pass through the callback.
+    bool been;
+  };
+
+  static int
+  callback (Dwarf_Attribute *at, void *data)
+  {
+    cb_data *d = static_cast <cb_data *> (data);
+    if (d->been)
+      return DWARF_CB_ABORT;
+
+    *d->at = *at;
+    d->been = true;
+
+    // Do a second iteration to find the next offset.
+    return DWARF_CB_OK;
+  }
+
+  void
+  move ()
+  {
+    // If m_offset is already 1, we are done iterating.
+    if (m_offset == 1)
+      {
+	*this = pimpl ((ptrdiff_t) 1);
+	return;
+      }
+
+    cb_data data = {&m_at, false};
+    m_offset = dwarf_getattrs (m_die, &callback, &data, m_offset);
+    if (m_offset == -1)
+      throw_libdw ();
+  }
+
+  pimpl (ptrdiff_t offset)
+    : m_die (NULL)
+    , m_at ((Dwarf_Attribute) {0, 0, NULL, NULL})
+    , m_offset (offset)
+  {}
+
+  pimpl (Dwarf_Die *die)
+    : m_die (die)
+    , m_at ((Dwarf_Attribute) {0, 0, NULL, NULL})
+    , m_offset (0)
+  {
+    move ();
+  }
+
+  bool
+  operator== (pimpl const &other) const
+  {
+    return m_offset == other.m_offset
+      && m_at.code == other.m_at.code;
+  }
+};
+
+elfutils::attr_iterator::attr_iterator (ptrdiff_t offset)
+  : m_pimpl (new pimpl (offset))
+{}
+
+elfutils::attr_iterator::attr_iterator (Dwarf_Die *die)
+  : m_pimpl (new pimpl (die))
+{}
+
+elfutils::attr_iterator::attr_iterator (attr_iterator const &that)
+  : m_pimpl (new pimpl (*that.m_pimpl))
+{}
+
+elfutils::attr_iterator::~attr_iterator ()
+{
+  delete m_pimpl;
+}
+
+elfutils::attr_iterator &
+elfutils::attr_iterator::operator= (attr_iterator const &that)
+{
+  if (this != &that)
+    {
+      pimpl *npimpl = new pimpl (*that.m_pimpl);
+      delete m_pimpl;
+      m_pimpl = npimpl;
+    }
+
+  return *this;
+}
+
+elfutils::attr_iterator
+elfutils::attr_iterator::end ()
+{
+  return attr_iterator ((ptrdiff_t) 1);
+}
+
+bool
+elfutils::attr_iterator::operator== (attr_iterator const &that) const
+{
+  return *m_pimpl == *that.m_pimpl;
+}
+
+bool
+elfutils::attr_iterator::operator!= (attr_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::attr_iterator &
+elfutils::attr_iterator::operator++ ()
+{
+  m_pimpl->move ();
+  return *this;
+}
+
+elfutils::attr_iterator
+elfutils::attr_iterator::operator++ (int)
+{
+  attr_iterator tmp = *this;
+  ++*this;
+  return tmp;
+}
+
+Dwarf_Attribute &
+elfutils::attr_iterator::operator* ()
+{
+  return m_pimpl->m_at;
+}
+
+Dwarf_Attribute *
+elfutils::attr_iterator::operator-> ()
+{
+  return &**this;
+}
diff --git a/libdw/c++/child_iterator.cc b/libdw/c++/child_iterator.cc
new file mode 100644
index 0000000..e4dbff8
--- /dev/null
+++ b/libdw/c++/child_iterator.cc
@@ -0,0 +1,143 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdw"
+#include "libdwP.hh"
+
+#include <cstring>
+
+struct elfutils::child_iterator::pimpl
+{
+  Dwarf_Die m_die;
+
+  // Create pimpl for end-iterator.
+  pimpl ()
+  {
+    std::memset (&m_die, 0, sizeof m_die);
+    m_die.addr = (void *) -1;
+  }
+
+  explicit pimpl (Dwarf_Die parent)
+  {
+    if (! dwpp_child (parent, m_die))
+      *this = pimpl ();
+  }
+
+  pimpl (pimpl const &that)
+    : m_die (that.m_die)
+  {}
+
+  bool
+  operator== (pimpl const &that) const
+  {
+    return m_die.addr == that.m_die.addr;
+  }
+
+  void
+  move ()
+  {
+    assert (! (*this == pimpl ()));
+    if (! dwpp_siblingof (m_die, m_die))
+      *this = pimpl ();
+  }
+};
+
+elfutils::child_iterator::child_iterator ()
+  : m_pimpl (new pimpl ())
+{}
+
+elfutils::child_iterator::child_iterator (Dwarf_Die parent)
+  : m_pimpl (new pimpl (parent))
+{}
+
+elfutils::child_iterator::child_iterator (child_iterator const &that)
+  : m_pimpl (new pimpl (*that.m_pimpl))
+{}
+
+elfutils::child_iterator::~child_iterator ()
+{
+  delete m_pimpl;
+}
+
+elfutils::child_iterator &
+elfutils::child_iterator::operator= (child_iterator const &that)
+{
+  if (this != &that)
+    {
+      pimpl *npimpl = new pimpl (*that.m_pimpl);
+      delete m_pimpl;
+      m_pimpl = npimpl;
+    }
+
+  return *this;
+}
+
+elfutils::child_iterator
+elfutils::child_iterator::end ()
+{
+  return child_iterator ();
+}
+
+bool
+elfutils::child_iterator::operator== (child_iterator const &that) const
+{
+  return *m_pimpl == *that.m_pimpl;
+}
+
+bool
+elfutils::child_iterator::operator!= (child_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::child_iterator &
+elfutils::child_iterator::operator++ ()
+{
+  m_pimpl->move ();
+  return *this;
+}
+
+elfutils::child_iterator
+elfutils::child_iterator::operator++ (int)
+{
+  child_iterator ret = *this;
+  ++*this;
+  return ret;
+}
+
+Dwarf_Die &
+elfutils::child_iterator::operator* ()
+{
+  return m_pimpl->m_die;
+}
+
+Dwarf_Die *
+elfutils::child_iterator::operator-> ()
+{
+  return &**this;
+}
diff --git a/libdw/c++/die_tree_iterator.cc b/libdw/c++/die_tree_iterator.cc
new file mode 100644
index 0000000..11b1bf6
--- /dev/null
+++ b/libdw/c++/die_tree_iterator.cc
@@ -0,0 +1,213 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <dwarf.h>
+#include <algorithm>
+
+#include "libdw"
+#include "libdwP.hh"
+
+namespace
+{
+  Dwarf *
+  getdw (elfutils::unit_iterator &cuit)
+  {
+    return dwarf_cu_getdwarf (cuit->cudie.cu);
+  }
+}
+
+struct elfutils::die_tree_iterator::pimpl
+{
+  unit_iterator m_cuit;
+  // Internally, only offsets are kept on the stack.
+  std::vector <Dwarf_Off> m_stack;
+  Dwarf_Die m_die;
+
+  pimpl (Dwarf_Off)
+    : m_cuit (unit_iterator::end ())
+  {}
+
+  explicit pimpl (Dwarf *dw)
+    : m_cuit (unit_iterator (dw))
+    , m_die (m_cuit->cudie)
+  {}
+
+  explicit pimpl (unit_iterator const &cuit)
+    : m_cuit (cuit)
+    , m_die (m_cuit->cudie)
+  {}
+
+  pimpl (pimpl const &that)
+    : m_cuit (that.m_cuit)
+    , m_stack (that.m_stack)
+    , m_die (that.m_die)
+  {}
+
+  bool
+  operator== (pimpl const &that) const
+  {
+    return m_cuit == that.m_cuit
+      && m_stack == that.m_stack
+      // xxx fishy.  What if other is end()?
+      && (m_cuit == unit_iterator::end ()
+	  || m_die.addr == that.m_die.addr);
+  }
+
+  void
+  move ()
+  {
+    Dwarf_Die child;
+    if (dwpp_child (m_die, child))
+      {
+	m_stack.push_back (dwarf_dieoffset (&m_die));
+	m_die = child;
+	return;
+      }
+
+    do
+      if (dwpp_siblingof (m_die, m_die))
+	return;
+      else
+	// No sibling found.  Go a level up and retry, unless this
+	// was a sole, childless CU DIE.
+	if (! m_stack.empty ())
+	  {
+	    m_die = (dwarf_tag (&m_cuit->cudie) == DW_TAG_type_unit
+		     ? dwpp_offdie_types : dwpp_offdie)
+	      (getdw (m_cuit), m_stack.back ());
+	    m_stack.pop_back ();
+	  }
+    while (! m_stack.empty ());
+
+    m_die = (++m_cuit)->cudie;
+  }
+};
+
+elfutils::die_tree_iterator::die_tree_iterator (Dwarf_Off off)
+  : m_pimpl (new pimpl (off))
+{}
+
+elfutils::die_tree_iterator::die_tree_iterator (Dwarf *dw)
+  : m_pimpl (new pimpl (dw))
+{}
+
+elfutils::die_tree_iterator::die_tree_iterator (unit_iterator const &cuit)
+  : m_pimpl (new pimpl (cuit))
+{}
+
+elfutils::die_tree_iterator::die_tree_iterator (die_tree_iterator const &that)
+  : m_pimpl (new pimpl (*that.m_pimpl))
+{}
+
+elfutils::die_tree_iterator::~die_tree_iterator ()
+{
+  delete m_pimpl;
+}
+
+elfutils::die_tree_iterator &
+elfutils::die_tree_iterator::operator= (die_tree_iterator const &that)
+{
+  if (this != &that)
+    {
+      pimpl *npimpl = new pimpl (*that.m_pimpl);
+      delete m_pimpl;
+      m_pimpl = npimpl;
+    }
+  return *this;
+}
+
+elfutils::die_tree_iterator
+elfutils::die_tree_iterator::end ()
+{
+  return die_tree_iterator ((Dwarf_Off) -1);
+}
+
+bool
+elfutils::die_tree_iterator::operator== (die_tree_iterator const &that) const
+{
+  return *m_pimpl == *that.m_pimpl;
+}
+
+bool
+elfutils::die_tree_iterator::operator!= (die_tree_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::die_tree_iterator &
+elfutils::die_tree_iterator::operator++ ()
+{
+  m_pimpl->move ();
+  return *this;
+}
+
+elfutils::die_tree_iterator
+elfutils::die_tree_iterator::operator++ (int)
+{
+  die_tree_iterator ret = *this;
+  ++*this;
+  return ret;
+}
+
+Dwarf_Die &
+elfutils::die_tree_iterator::operator* ()
+{
+  return m_pimpl->m_die;
+}
+
+Dwarf_Die *
+elfutils::die_tree_iterator::operator-> ()
+{
+  return &**this;
+}
+
+elfutils::die_tree_iterator::stack_type
+elfutils::die_tree_iterator::stack () const
+{
+  stack_type ret;
+  for (die_tree_iterator it = *this; it != end (); it = it.parent ())
+    ret.push_back (*it);
+  std::reverse (ret.begin (), ret.end ());
+  return ret;
+}
+
+elfutils::die_tree_iterator
+elfutils::die_tree_iterator::parent ()
+{
+  assert (*this != end ());
+  if (m_pimpl->m_stack.empty ())
+    return end ();
+
+  die_tree_iterator ret = *this;
+  ret.m_pimpl->m_die = (dwarf_tag (&m_pimpl->m_cuit->cudie) == DW_TAG_type_unit
+			? dwpp_offdie_types : dwpp_offdie)
+    (getdw (m_pimpl->m_cuit), m_pimpl->m_stack.back ());
+  ret.m_pimpl->m_stack.pop_back ();
+
+  return ret;
+}
diff --git a/libdw/c++/libdw b/libdw/c++/libdw
new file mode 100644
index 0000000..0b01b2d
--- /dev/null
+++ b/libdw/c++/libdw
@@ -0,0 +1,245 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBDW_CPP
+#define _LIBDW_CPP	1
+
+#include <vector>
+#include <iterator>
+
+#include <elfutils/libdw.h>
+
+namespace elfutils
+{
+  // The iterators presented here have operators * and -> as non-const
+  // member functions.  The reason is that the libdw interfaces do not
+  // take, say, Dwarf_Die const *, but Dwarf_Die *, and therefore
+  // returning a const reference of some sort would not be useful.  We
+  // don't want to give out copies either, as that adds unnecessary
+  // overhead.  And we simply don't care much if anyone does end up
+  // changing the internal copy of the current CU, DIE, or whatever.
+
+
+  // An iterator that goes over compile units (full or partial) in a
+  // given DWARF file.  The type that it points to (yields on
+  // dereference) is CU_INFO (see below).
+  //
+  // Example usage:
+  // {
+  //   std::vector <Dwarf_Off> v
+  //   for (elfutils::cu_iterator jt (dw);
+  //        jt != elfutils::cu_iterator::end (); ++jt)
+  //     v.push_back (dwarf_dieoffset (&jt->cudie));
+  // }
+  class unit_iterator;
+
+  // Helper structure with data about each compile unit.
+  struct unit_info
+  {
+    Dwarf_Die cudie;
+    Dwarf_Off abbrev_offset;
+    uint64_t type_signature; // Valid for DW_TAG_type_unit
+    Dwarf_Half version;
+    uint8_t address_size;
+    uint8_t offset_size;
+  };
+
+  class unit_iterator
+    : public std::iterator <std::input_iterator_tag, unit_info>
+  {
+    struct pimpl;
+    pimpl *m_pimpl;
+
+    explicit unit_iterator (Dwarf_Off off, bool types);
+
+  public:
+    // Construct a unit iterator that will iterate through all units
+    // in DW.
+    explicit unit_iterator (Dwarf *dw);
+
+    // Construct a unit iterator for DW such that it points to a
+    // compile (or other type of) unit represented by CUDIE.
+    unit_iterator (Dwarf *dw, Dwarf_Die cudie);
+
+    unit_iterator (unit_iterator const &that);
+    ~unit_iterator ();
+    unit_iterator &operator= (unit_iterator const &that);
+
+    // Return a unit_iterator pointing one after the last actual CU.
+    static unit_iterator end ();
+
+    bool operator== (unit_iterator const &that) const;
+    bool operator!= (unit_iterator const &that) const;
+
+    unit_iterator &operator++ ();
+    unit_iterator operator++ (int);
+
+    // N.B. see top of the file for explanation of non-constness of
+    // operators * and ->.
+
+    unit_info &operator* ();
+    unit_info *operator-> ();
+  };
+
+
+  // An iterator that goes through children of a given DIE.
+  // Example usage:
+  // {
+  //    size_t nchildren = std::distance (elfutils::child_iterator (type_die),
+  //                                      elfutils::child_iterator::end ());
+  // }
+
+  class child_iterator
+    : public std::iterator <std::input_iterator_tag, Dwarf_Die>
+  {
+    struct pimpl;
+    pimpl *m_pimpl;
+
+    child_iterator ();
+
+  public:
+    explicit child_iterator (Dwarf_Die parent);
+    child_iterator (child_iterator const &that);
+    ~child_iterator ();
+    child_iterator &operator= (child_iterator const &that);
+
+    // Return a child_iterator pointing one after the last actual
+    // child.
+    static child_iterator end ();
+
+    bool operator== (child_iterator const &that) const;
+    bool operator!= (child_iterator const &that) const;
+
+    child_iterator &operator++ ();
+    child_iterator operator++ (int);
+
+    // N.B. see top of the file for explanation of non-constness of
+    // operators * and ->.
+    Dwarf_Die &operator* ();
+    Dwarf_Die *operator-> ();
+  };
+
+
+  // Tree flattening iterator.  It pre-order iterates all DIEs in
+  // given DWARF file, optionally starting from a given CU iterator.
+  // It keeps track of path from CU root to the current DIE, and that
+  // can be requested through stack() member function.
+  //
+  // Example usage:
+  // {
+  //   for (elfutils::die_tree_iterator it (dw);
+  //        it != elfutils::die_tree_iterator::end (); ++it)
+  //     {
+  //       typedef elfutils::die_tree_iterator::stack_type stack_type;
+  //       stack_type const &stack = it.stack ();
+  //       for (stack_type::const_iterator jt = stack.begin ();
+  //            jt != stack.end (); ++jt)
+  //         ...;
+  //     }
+  // }
+  class die_tree_iterator
+    : public std::iterator <std::input_iterator_tag, Dwarf_Die>
+  {
+    struct pimpl;
+    pimpl *m_pimpl;
+
+    die_tree_iterator (Dwarf_Off);
+
+  public:
+    typedef std::vector <Dwarf_Die> stack_type;
+
+    explicit die_tree_iterator (Dwarf *dw);
+    explicit die_tree_iterator (unit_iterator const &cuit);
+
+    die_tree_iterator (die_tree_iterator const &that);
+    ~die_tree_iterator ();
+    die_tree_iterator &operator= (die_tree_iterator const &that);
+
+    // Return a die_tree_iterator pointing one after the last actual
+    // DIE.
+    static die_tree_iterator end ();
+
+    bool operator== (die_tree_iterator const &that) const;
+    bool operator!= (die_tree_iterator const &that) const;
+
+    die_tree_iterator &operator++ ();
+    die_tree_iterator operator++ (int);
+
+    // N.B. see top of the file for explanation of non-constness of
+    // operators * and ->.
+
+    Dwarf_Die &operator* ();
+    Dwarf_Die *operator-> ();
+
+    // Return a stack of DIE's representing the path from CU DIE to
+    // the current DIE (both ends inclusive).  The first element of
+    // the returned stack is the CU DIE, the last one the current DIE.
+    stack_type stack () const;
+
+    // Return a die_tree_iterator referencing a parent of a DIE that
+    // this iterator points at.  Returns an end iterator if there is
+    // no parent.  Technically a const, but can't be one due to
+    // dwarf_tag call inside.
+    die_tree_iterator parent ();
+  };
+
+
+  // An attribute iterator goes through attributes of a given DIE.
+  class attr_iterator
+    : public std::iterator <std::input_iterator_tag, Dwarf_Attribute>
+  {
+    struct pimpl;
+    pimpl *m_pimpl;
+
+    attr_iterator (ptrdiff_t offset);
+
+  public:
+    attr_iterator (Dwarf_Die *die);
+    attr_iterator (attr_iterator const &that);
+    ~attr_iterator ();
+    attr_iterator &operator= (attr_iterator const &that);
+
+    // Return an attr_iterator pointing one after the last actual
+    // attribute.
+    static attr_iterator end ();
+
+    bool operator== (attr_iterator const &that) const;
+    bool operator!= (attr_iterator const &that) const;
+
+    attr_iterator &operator++ ();
+    attr_iterator operator++ (int);
+
+    // N.B. see top of the file for explanation of non-constness of
+    // operators * and ->.
+
+    Dwarf_Attribute &operator* ();
+    Dwarf_Attribute *operator-> ();
+  };
+}
+
+#endif
diff --git a/libdw/c++/libdwP.hh b/libdw/c++/libdwP.hh
new file mode 100644
index 0000000..cb6a145
--- /dev/null
+++ b/libdw/c++/libdwP.hh
@@ -0,0 +1,88 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _CPP_LIBDWP_H
+#define _CPP_LIBDWP_H 1
+
+#include <stdexcept>
+#include <cassert>
+#include <cstdlib>
+
+inline void
+throw_libdw (int dwerr = 0)
+{
+  if (dwerr == 0)
+    dwerr = dwarf_errno ();
+  assert (dwerr != 0);
+  throw std::runtime_error (dwarf_errmsg (dwerr));
+}
+
+inline bool
+dwpp_child (Dwarf_Die &die, Dwarf_Die &result)
+{
+  int ret = dwarf_child (&die, &result);
+  if (ret < 0)
+    throw_libdw ();
+  return ret == 0;
+}
+
+inline bool
+dwpp_siblingof (Dwarf_Die &die, Dwarf_Die &result)
+{
+  switch (dwarf_siblingof (&die, &result))
+    {
+    case -1:
+      throw_libdw ();
+    case 0:
+      return true;
+    case 1:
+      return false;
+    default:
+      std::abort ();
+    }
+}
+
+inline Dwarf_Die
+dwpp_offdie (Dwarf *dbg, Dwarf_Off offset)
+{
+  Dwarf_Die result;
+  if (dwarf_offdie (dbg, offset, &result) == NULL)
+    throw_libdw ();
+  return result;
+}
+
+inline Dwarf_Die
+dwpp_offdie_types (Dwarf *dbg, Dwarf_Off offset)
+{
+  Dwarf_Die result;
+  if (dwarf_offdie_types (dbg, offset, &result) == NULL)
+    throw_libdw ();
+  return result;
+}
+
+#endif
diff --git a/libdw/c++/unit_iterator.cc b/libdw/c++/unit_iterator.cc
new file mode 100644
index 0000000..f49b363
--- /dev/null
+++ b/libdw/c++/unit_iterator.cc
@@ -0,0 +1,204 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include <dwarf.h>
+
+#include "libdw"
+#include "libdwP.hh"
+
+struct elfutils::unit_iterator::pimpl
+{
+  Dwarf *m_dw;
+  Dwarf_Off m_offset;
+  Dwarf_Off m_old_offset;
+  unit_info m_info;
+  bool m_types;
+
+  bool
+  is_end ()
+  {
+    return m_offset == (Dwarf_Off) -1 && m_types;
+  }
+
+  void
+  move ()
+  {
+    assert (! is_end ());
+    m_old_offset = m_offset;
+    size_t hsize;
+    int rc = dwarf_next_unit (m_dw, m_offset, &m_offset, &hsize,
+			      &m_info.version, &m_info.abbrev_offset,
+			      &m_info.address_size, &m_info.offset_size,
+			      m_types ? &m_info.type_signature : NULL, NULL);
+    if (rc < 0)
+      throw_libdw ();
+
+    if (rc != 0 && m_types)
+      done ();
+    else if (rc != 0)
+      {
+	m_types = true;
+	m_offset = 0;
+	m_old_offset = 0;
+	move ();
+      }
+    else
+      m_info.cudie = (m_types ? dwpp_offdie_types : dwpp_offdie)
+	(m_dw, m_old_offset + hsize);
+  }
+
+  void
+  done ()
+  {
+    *this = *end ().m_pimpl;
+    assert (is_end ());
+  }
+
+  pimpl (Dwarf_Off off, bool types)
+    : m_dw (NULL)
+    , m_offset (off)
+    , m_old_offset (0)
+    , m_types (types)
+  {}
+
+  explicit pimpl (Dwarf *dw)
+    : m_dw (dw)
+    , m_offset (0)
+    , m_old_offset (0)
+    , m_types (false)
+  {
+    move ();
+  }
+
+  // Construct a CU iterator for DW such that it points to a compile
+  // unit represented by CUDIE.
+  pimpl (Dwarf *dw, Dwarf_Die cudie)
+    : m_dw (dw)
+    , m_offset (dwarf_dieoffset (&cudie) - dwarf_cuoffset (&cudie))
+    , m_old_offset (0)
+    , m_types (dwarf_tag (&cudie) == DW_TAG_type_unit)
+  {
+    move ();
+  }
+
+  bool
+  operator== (pimpl const &that) const
+  {
+    return m_types == that.m_types && m_offset == that.m_offset;
+  }
+
+  unit_info &
+  deref ()
+  {
+    return m_info;
+  }
+};
+
+elfutils::unit_iterator::unit_iterator (Dwarf_Off off, bool types)
+  : m_pimpl (new pimpl (off, types))
+{
+}
+
+elfutils::unit_iterator::unit_iterator (Dwarf *dw)
+  : m_pimpl (new pimpl (dw))
+{
+}
+
+elfutils::unit_iterator::unit_iterator (Dwarf *dw, Dwarf_Die cudie)
+  : m_pimpl (new pimpl (dw, cudie))
+{
+}
+
+elfutils::unit_iterator::unit_iterator (unit_iterator const &that)
+  : m_pimpl (new pimpl (*that.m_pimpl))
+{
+}
+
+elfutils::unit_iterator::~unit_iterator ()
+{
+  delete m_pimpl;
+}
+
+elfutils::unit_iterator &
+elfutils::unit_iterator::operator= (unit_iterator const &that)
+{
+  if (this != &that)
+    {
+      pimpl *npimpl = new pimpl (*that.m_pimpl);
+      delete m_pimpl;
+      m_pimpl = npimpl;
+    }
+  return *this;
+}
+
+elfutils::unit_iterator
+elfutils::unit_iterator::end ()
+{
+  unit_iterator ret ((Dwarf_Off) -1, true);
+  assert (ret.m_pimpl->is_end ());
+  return ret;
+}
+
+bool
+elfutils::unit_iterator::operator== (unit_iterator const &that) const
+{
+  return *m_pimpl == *that.m_pimpl;
+}
+
+bool
+elfutils::unit_iterator::operator!= (unit_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::unit_iterator &
+elfutils::unit_iterator::operator++ ()
+{
+  m_pimpl->move ();
+  return *this;
+}
+
+elfutils::unit_iterator
+elfutils::unit_iterator::operator++ (int)
+{
+  unit_iterator tmp = *this;
+  ++*this;
+  return tmp;
+}
+
+elfutils::unit_info &
+elfutils::unit_iterator::operator* ()
+{
+  return m_pimpl->deref ();
+}
+
+elfutils::unit_info *
+elfutils::unit_iterator::operator-> ()
+{
+  return &**this;
+}
diff --git a/libdw/libdwpp.map b/libdw/libdwpp.map
new file mode 100644
index 0000000..7d85575
--- /dev/null
+++ b/libdw/libdwpp.map
@@ -0,0 +1,199 @@
+ELFUTILS_0 { };
+
+ELFUTILS_0.162 {
+  global:
+
+    # ### elfutils::die_tree_iterator ###
+
+    # die_tree_iterator(Dwarf*)
+    _ZN8elfutils17die_tree_iteratorC1EP5Dwarf;
+
+    # die_tree_iterator(elfutils::die_tree_iterator const&)
+    _ZN8elfutils17die_tree_iteratorC1ERKS0_;
+
+    # die_tree_iterator(elfutils::unit_iterator const&)
+    _ZN8elfutils17die_tree_iteratorC1ERKNS_13unit_iteratorE;
+
+    # ~die_tree_iterator()
+    _ZN8elfutils17die_tree_iteratorD1Ev;
+
+    # operator=(elfutils::die_tree_iterator const&)
+    _ZN8elfutils17die_tree_iteratoraSERKS0_;
+
+    # parent()
+    _ZN8elfutils17die_tree_iterator6parentEv;
+
+    # stack() const
+    _ZNK8elfutils17die_tree_iterator5stackEv;
+
+    # end()
+    _ZN8elfutils17die_tree_iterator3endEv;
+
+    # operator->()
+    _ZN8elfutils17die_tree_iteratorptEv;
+
+    # operator*()
+    _ZN8elfutils17die_tree_iteratordeEv;
+
+    # operator++()
+    _ZN8elfutils17die_tree_iteratorppEv;
+
+    # operator++(int)
+    _ZN8elfutils17die_tree_iteratorppEi;
+
+    # operator==(elfutils::die_tree_iterator const&) const
+    _ZNK8elfutils17die_tree_iteratoreqERKS0_;
+
+    # operator!=(elfutils::die_tree_iterator const&) const
+    _ZNK8elfutils17die_tree_iteratorneERKS0_;
+
+
+    # ### elfutils::unit_iterator ###
+
+    # unit_iterator(Dwarf*)
+    _ZN8elfutils13unit_iteratorC1EP5Dwarf;
+
+    # unit_iterator(Dwarf*, Dwarf_Die)
+    _ZN8elfutils13unit_iteratorC1EP5Dwarf9Dwarf_Die;
+
+    # unit_iterator(elfutils::unit_iterator const&)
+    _ZN8elfutils13unit_iteratorC1ERKS0_;
+
+    # ~unit_iterator()
+    _ZN8elfutils13unit_iteratorD1Ev;
+
+    # operator=(elfutils::unit_iterator const&)
+    _ZN8elfutils13unit_iteratoraSERKS0_;
+
+    # end()
+    _ZN8elfutils13unit_iterator3endEv;
+
+    # operator->()
+    _ZN8elfutils13unit_iteratorptEv;
+
+    # operator*()
+    _ZN8elfutils13unit_iteratordeEv;
+
+    # operator++()
+    _ZN8elfutils13unit_iteratorppEv;
+
+    # operator++(int)
+    _ZN8elfutils13unit_iteratorppEi;
+
+    # operator==(elfutils::unit_iterator const&) const
+    _ZNK8elfutils13unit_iteratoreqERKS0_;
+
+    # operator!=(elfutils::unit_iterator const&) const
+    _ZNK8elfutils13unit_iteratorneERKS0_;
+
+
+    # ### elfutils::child_iterator ###
+
+    # child_iterator(elfutils::child_iterator const&)
+    _ZN8elfutils14child_iteratorC1ERKS0_;
+
+    # child_iterator(Dwarf_Die)
+    _ZN8elfutils14child_iteratorC1E9Dwarf_Die;
+
+    # ~child_iterator()
+    _ZN8elfutils14child_iteratorD1Ev;
+
+    # operator=(elfutils::child_iterator const&)
+    _ZN8elfutils14child_iteratoraSERKS0_;
+
+    # end()
+    _ZN8elfutils14child_iterator3endEv;
+
+    # operator==(elfutils::child_iterator const&) const
+    _ZNK8elfutils14child_iteratoreqERKS0_;
+
+    # operator!=(elfutils::child_iterator const&) const
+    _ZNK8elfutils14child_iteratorneERKS0_;
+
+    # operator*()
+    _ZN8elfutils14child_iteratordeEv;
+
+    # operator->()
+    _ZN8elfutils14child_iteratorptEv;
+
+    # operator++()
+    _ZN8elfutils14child_iteratorppEv;
+
+    # operator++(int)
+    _ZN8elfutils14child_iteratorppEi;
+
+
+    # ### elfutils::attr_iterator ###
+
+    # attr_iterator(Dwarf_Die*)
+    _ZN8elfutils13attr_iteratorC1EP9Dwarf_Die;
+
+    # attr_iterator(elfutils::attr_iterator const&)
+    _ZN8elfutils13attr_iteratorC1ERKS0_;
+
+    # ~attr_iterator()
+    _ZN8elfutils13attr_iteratorD1Ev;
+
+    # operator=(elfutils::attr_iterator const&)
+    _ZN8elfutils13attr_iteratoraSERKS0_;
+
+    # end()
+    _ZN8elfutils13attr_iterator3endEv;
+
+    # operator++()
+    _ZN8elfutils13attr_iteratorppEv;
+
+    # operator++(int)
+    _ZN8elfutils13attr_iteratorppEi;
+
+    # operator*()
+    _ZN8elfutils13attr_iteratordeEv;
+
+    # operator->()
+    _ZN8elfutils13attr_iteratorptEv;
+
+    # operator==(elfutils::attr_iterator const&) const
+    _ZNK8elfutils13attr_iteratoreqERKS0_;
+
+    # operator!=(elfutils::attr_iterator const&) const
+    _ZNK8elfutils13attr_iteratorneERKS0_;
+
+
+    # ### elfutils::dwfl_module_iterator ###
+
+    # dwfl_module_iterator(Dwfl*)
+    _ZN8elfutils20dwfl_module_iteratorC1EP4Dwfl;
+
+    # dwfl_module_iterator(elfutils::dwfl_module_iterator const&)
+    _ZN8elfutils20dwfl_module_iteratorC1ERKS0_;
+
+    # ~dwfl_module_iterator()
+    _ZN8elfutils20dwfl_module_iteratorD1Ev;
+
+    # operator=(elfutils::dwfl_module_iterator const&)
+    _ZN8elfutils20dwfl_module_iteratoraSERKS0_;
+
+    # end()
+    _ZN8elfutils20dwfl_module_iterator3endEv;
+
+    # operator++()
+    _ZN8elfutils20dwfl_module_iteratorppEv;
+
+    # operator++(int)
+    _ZN8elfutils20dwfl_module_iteratorppEi;
+
+    # operator*() const
+    _ZNK8elfutils20dwfl_module_iteratordeEv;
+
+    # operator->() const
+    _ZNK8elfutils20dwfl_module_iteratorptEv;
+
+    # operator==(elfutils::dwfl_module_iterator const&) const
+    _ZNK8elfutils20dwfl_module_iteratoreqERKS0_;
+
+    # operator!=(elfutils::dwfl_module_iterator const&) const
+    _ZNK8elfutils20dwfl_module_iteratorneERKS0_;
+
+  local:
+    *;
+} ELFUTILS_0;
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index d40dbae..b5cfdb9 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,16 @@
+2015-03-17  Petr Machata  <pmachata@redhat.com>
+
+	* c++: New directory.
+	* c++/libdwfl, c++/libdwflP.hh: New header files.
+	* Makefile.am (AUTOMAKE_OPTIONS): New variable.
+	[HAVE_CXX] (pkginclude_HEADERS): Add c++/libdwfl.
+	[HAVE_CXX] (noinst_LIBRARIES): Add libdwflpp.a, libdwflpp_pic.a.
+	[HAVE_CXX] (libdwflpp_a_SOURCES, libdwflpp, libdwpp): New variables.
+	[HAVE_CXX] (libdwflpp_pic_a_SOURCES): Likewise.
+	[HAVE_CXX] (am_libdwflpp_pic_a_OBJECTS): Likewise.
+	(noinst_HEADERS): Add c++/libdwflP.hh.
+	[HAVE_CXX] (CLEANFILES): Add $(am_libdwflpp_pic_a_OBJECTS).
+
 2015-01-26  Mark Wielaard  <mjw@redhat.com>
 
 	* dwfl_module_getdwarf.c (find_symtab): Explicitly clear symdata,
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 72c980b..21e1844 100644
--- a/libdwfl/Makefile.am
+++ b/libdwfl/Makefile.am
@@ -2,7 +2,7 @@
 ##
 ## Process this file with automake to create Makefile.in
 ##
-## Copyright (C) 2005-2010, 2013 Red Hat, Inc.
+## Copyright (C) 2005-2010, 2013, 2015 Red Hat, Inc.
 ## This file is part of elfutils.
 ##
 ## This file is free software; you can redistribute it and/or modify
@@ -34,10 +34,23 @@ AM_CPPFLAGS += -I$(srcdir) -I$(srcdir)/../libelf -I$(srcdir)/../libebl \
 	   -I$(srcdir)/../libdw -I$(srcdir)/../libdwelf
 VERSION = 1
 
+# For c++/ subdir.
+AUTOMAKE_OPTIONS = subdir-objects
+
 noinst_LIBRARIES = libdwfl.a
+if HAVE_CXX
+noinst_LIBRARIES += libdwflpp.a
+endif
+
 noinst_LIBRARIES += libdwfl_pic.a
+if HAVE_CXX
+noinst_LIBRARIES += libdwflpp_pic.a
+endif
 
 pkginclude_HEADERS = libdwfl.h
+if HAVE_CXX
+pkginclude_HEADERS += c++/libdwfl
+endif
 
 libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
 		    dwfl_module.c dwfl_report_elf.c relocate.c \
@@ -70,6 +83,10 @@ libdwfl_a_SOURCES = dwfl_begin.c dwfl_end.c dwfl_error.c dwfl_version.c \
 		    dwfl_frame.c frame_unwind.c dwfl_frame_pc.c \
 		    linux-pid-attach.c linux-core-attach.c dwfl_frame_regs.c
 
+if HAVE_CXX
+libdwflpp_a_SOURCES = c++/dwfl_module_iterator.cc
+endif
+
 if ZLIB
 libdwfl_a_SOURCES += gzip.c
 endif
@@ -82,6 +99,10 @@ endif
 
 libdwfl = $(libdw)
 libdw = ../libdw/libdw.so
+if HAVE_CXX
+libdwflpp = $(libdwpp)
+libdwpp = ../libdw/libdwpp.so
+endif
 libelf = ../libelf/libelf.so
 libebl = ../libebl/libebl.a
 libeu = ../lib/libeu.a
@@ -89,6 +110,14 @@ libeu = ../lib/libeu.a
 libdwfl_pic_a_SOURCES =
 am_libdwfl_pic_a_OBJECTS = $(libdwfl_a_SOURCES:.c=.os)
 
-noinst_HEADERS = libdwflP.h
+if HAVE_CXX
+libdwflpp_pic_a_SOURCES =
+am_libdwflpp_pic_a_OBJECTS = $(libdwflpp_a_SOURCES:.cc=.os)
+endif
+
+noinst_HEADERS = libdwflP.h c++/libdwflP.hh
 
 CLEANFILES += $(am_libdwfl_pic_a_OBJECTS)
+if HAVE_CXX
+CLEANFILES += $(am_libdwflpp_pic_a_OBJECTS)
+endif
diff --git a/libdwfl/c++/dwfl_module_iterator.cc b/libdwfl/c++/dwfl_module_iterator.cc
new file mode 100644
index 0000000..26f96fe
--- /dev/null
+++ b/libdwfl/c++/dwfl_module_iterator.cc
@@ -0,0 +1,154 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#include "libdwfl"
+#include "libdwflP.hh"
+
+struct elfutils::dwfl_module_iterator::pimpl
+{
+  Dwfl *m_dwfl;
+  ptrdiff_t m_offset;
+  Dwfl_Module *m_module;
+
+  static int
+  module_cb (Dwfl_Module *mod, void **, const char *,
+	     Dwarf_Addr, void *arg)
+  {
+    pimpl *self = static_cast <pimpl *> (arg);
+    self->m_module = mod;
+    return DWARF_CB_ABORT;
+  }
+
+  void
+  move ()
+  {
+    m_offset = dwfl_getmodules (m_dwfl, module_cb, this, m_offset);
+    if (m_offset == -1)
+      throw_libdwfl ();
+  }
+
+  explicit pimpl (ptrdiff_t off)
+    : m_dwfl (NULL)
+    , m_offset (off)
+  {}
+
+  explicit pimpl (Dwfl *dwfl)
+    : m_dwfl (dwfl)
+    , m_offset (0)
+  {
+    move ();
+  }
+
+  pimpl (pimpl const &that)
+    : m_dwfl (that.m_dwfl)
+    , m_offset (that.m_offset)
+    , m_module (that.m_module)
+  {}
+
+  bool
+  operator== (pimpl const &that) const
+  {
+    assert (m_dwfl == NULL || that.m_dwfl == NULL || m_dwfl == that.m_dwfl);
+    return m_offset == that.m_offset;
+  }
+};
+
+elfutils::dwfl_module_iterator::dwfl_module_iterator (ptrdiff_t off)
+  : m_pimpl (new pimpl (off))
+{}
+
+elfutils::dwfl_module_iterator::dwfl_module_iterator (Dwfl *dwfl)
+  : m_pimpl (new pimpl (dwfl))
+{}
+
+elfutils::dwfl_module_iterator::dwfl_module_iterator (dwfl_module_iterator const &that)
+  : m_pimpl (new pimpl (*that.m_pimpl))
+{}
+
+elfutils::dwfl_module_iterator::~dwfl_module_iterator ()
+{
+  delete m_pimpl;
+}
+
+elfutils::dwfl_module_iterator &
+elfutils::dwfl_module_iterator::operator= (dwfl_module_iterator const &that)
+{
+  if (this != &that)
+    {
+      pimpl *npimpl = new pimpl (*that.m_pimpl);
+      delete m_pimpl;
+      m_pimpl = npimpl;
+    }
+
+  return *this;
+}
+
+elfutils::dwfl_module_iterator
+elfutils::dwfl_module_iterator::end ()
+{
+  return dwfl_module_iterator ((ptrdiff_t) 0);
+}
+
+elfutils::dwfl_module_iterator &
+elfutils::dwfl_module_iterator::operator++ ()
+{
+  m_pimpl->move ();
+  return *this;
+}
+
+elfutils::dwfl_module_iterator
+elfutils::dwfl_module_iterator::operator++ (int)
+{
+  dwfl_module_iterator ret = *this;
+  ++*this;
+  return ret;
+}
+
+Dwfl_Module &
+elfutils::dwfl_module_iterator::operator* () const
+{
+  return *m_pimpl->m_module;
+}
+
+Dwfl_Module *
+elfutils::dwfl_module_iterator::operator-> () const
+{
+  return &**this;
+}
+
+bool
+elfutils::dwfl_module_iterator::operator== (dwfl_module_iterator const &that) const
+{
+  return *m_pimpl == *that.m_pimpl;
+}
+
+bool
+elfutils::dwfl_module_iterator::operator!= (dwfl_module_iterator const &that) const
+{
+  return ! (*this == that);
+}
diff --git a/libdwfl/c++/libdwfl b/libdwfl/c++/libdwfl
new file mode 100644
index 0000000..42eb584
--- /dev/null
+++ b/libdwfl/c++/libdwfl
@@ -0,0 +1,70 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _LIBDWFL_CPP
+#define _LIBDWFL_CPP	1
+
+#include <iterator>
+#include <elfutils/libdwfl.h>
+
+namespace elfutils
+{
+  // Given a Dwfl, iterates through its Dwfl_Module's.
+  //
+  // Example usage:
+  // std::vector <Dwfl_Module *> mods (elfutils::dwfl_module_iterator (dwfl),
+  //				       elfutils::dwfl_module_iterator::end ());
+
+  class dwfl_module_iterator
+    : public std::iterator <std::input_iterator_tag, Dwfl_Module *>
+  {
+    struct pimpl;
+    pimpl *m_pimpl;
+
+    explicit dwfl_module_iterator (ptrdiff_t off);
+
+  public:
+    explicit dwfl_module_iterator (Dwfl *dwfl);
+    dwfl_module_iterator (dwfl_module_iterator const &that);
+    ~dwfl_module_iterator ();
+    dwfl_module_iterator &operator= (dwfl_module_iterator const &that);
+
+    static dwfl_module_iterator end ();
+
+    dwfl_module_iterator &operator++ ();
+    dwfl_module_iterator operator++ (int);
+
+    Dwfl_Module &operator* () const;
+    Dwfl_Module *operator-> () const;
+
+    bool operator== (dwfl_module_iterator const &that) const;
+    bool operator!= (dwfl_module_iterator const &that) const;
+  };
+}
+
+#endif
diff --git a/libdwfl/c++/libdwflP.hh b/libdwfl/c++/libdwflP.hh
new file mode 100644
index 0000000..c3f2792
--- /dev/null
+++ b/libdwfl/c++/libdwflP.hh
@@ -0,0 +1,44 @@
+/* -*-c++-*-
+   Copyright (C) 2009, 2010, 2011, 2012, 2014, 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of either
+
+     * the GNU Lesser General Public License as published by the Free
+       Software Foundation; either version 3 of the License, or (at
+       your option) any later version
+
+   or
+
+     * the GNU General Public License as published by the Free
+       Software Foundation; either version 2 of the License, or (at
+       your option) any later version
+
+   or both in parallel, as here.
+
+   elfutils is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received copies of the GNU General Public License and
+   the GNU Lesser General Public License along with this program.  If
+   not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef _CPP_LIBDWFLP_H
+#define _CPP_LIBDWFLP_H 1
+
+#include <stdexcept>
+#include <cassert>
+
+static inline void
+throw_libdwfl (int dwflerr = 0)
+{
+  if (dwflerr == 0)
+    dwflerr = dwfl_errno ();
+  assert (dwflerr != 0);
+  throw std::runtime_error (dwfl_errmsg (dwflerr));
+}
+
+#endif
diff --git a/tests/ChangeLog b/tests/ChangeLog
index a029645..f50da48 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,5 +1,12 @@
 2015-03-18  Petr Machata  <pmachata@redhat.com>
 
+	* test-iterators.cc, run-test-iterators.sh: New files.
+	* Makefile.am (check_PROGRAMS) [HAVE_CXX]: Add test-iterators.
+	(TESTS) [HAVE_CXX]: Add run-test-iterators.sh.
+	(libdwpp): New variable.
+
+2015-03-18  Petr Machata  <pmachata@redhat.com>
+
 	* addrcfi.c (op_name): Adjust uses of know-dwarf.h macros to match
 	the API changes.
 	* allregs.c (dwarf_encoding_string): Likewise.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 9e8bc02..abe6da7 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -141,6 +141,11 @@ check_PROGRAMS += $(asm_TESTS)
 TESTS += $(asm_TESTS)
 endif
 
+if HAVE_CXX
+check_PROGRAMS += test-iterators
+TESTS += run-test-iterators.sh
+endif
+
 EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     run-show-die-info.sh run-get-files.sh run-get-lines.sh \
 	     run-get-pubnames.sh run-get-aranges.sh \
@@ -286,7 +291,7 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     testfile-sizes3.o.bz2 \
 	     run-readelf-A.sh testfileppc32attrs.o.bz2 \
 	     testfile-debug-types.bz2 \
-	     run-getsrc-die.sh run-strptr.sh
+	     run-getsrc-die.sh run-strptr.sh run-test-iterators.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
@@ -330,16 +335,19 @@ endif !STANDALONE
 
 if STANDALONE
 libdw = -ldw
+libdwpp = -ldwpp
 libelf = -lelf
 libasm = -lasm
 libebl = -lebl
 else !STANDALONE
 if BUILD_STATIC
 libdw = ../libdw/libdw.a $(zip_LIBS) $(libelf) $(libebl) -ldl
+libdwpp = ../libdw/libdwpp.a $(libdw)
 libelf = ../libelf/libelf.a
 libasm = ../libasm/libasm.a
 else
 libdw = ../libdw/libdw.so
+libdwpp = ../libdw/libdwpp.so
 libelf = ../libelf/libelf.so
 libasm = ../libasm/libasm.so
 endif
@@ -431,6 +439,8 @@ getsrc_die_LDADD = $(libdw) $(libelf)
 strptr_LDADD = $(libelf)
 newdata_LDADD = $(libelf)
 elfstrtab_LDADD = $(libelf)
+test_iterators_SOURCES = test-iterators.cc
+test_iterators_LDADD = $(libdw) $(libdwpp)
 
 if GCOV
 check: check-am coverage
diff --git a/tests/run-test-iterators.sh b/tests/run-test-iterators.sh
new file mode 100755
index 0000000..6942570
--- /dev/null
+++ b/tests/run-test-iterators.sh
@@ -0,0 +1,52 @@
+#! /bin/sh
+# Copyright (C) 2015 Red Hat, Inc.
+# This file is part of elfutils.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+. $srcdir/test-subr.sh
+
+testfiles testfile39 testfile-debug-types
+
+testrun_compare ${abs_top_builddir}/tests/test-iterators testfile39 <<\EOF
+0xb
+0x9e
+0x135
+0x1c8
+0 7
+0 7
+0 7
+0 7
+EOF
+
+testrun_compare ${abs_top_builddir}/tests/test-iterators testfile-debug-types <<\EOF
+0xb
+0x17
+0x5a
+4 6
+0 9
+0 3
+0 6
+0 6
+2 3
+1 4
+0 2
+0 5
+1 3
+2 4
+0 3
+0 5
+EOF
+
+exit 0
diff --git a/tests/test-iterators.cc b/tests/test-iterators.cc
new file mode 100644
index 0000000..987bc6a
--- /dev/null
+++ b/tests/test-iterators.cc
@@ -0,0 +1,87 @@
+/* Copyright (C) 2015 Red Hat, Inc.
+   This file is part of elfutils.
+
+   This file is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   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 this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+#include <iostream>
+#include <cassert>
+#include <stdexcept>
+
+#include "../libdw/c++/libdw"
+#include "../libdwfl/c++/libdwfl"
+#include "../libdw/c++/libdwP.hh"
+#include "../libdwfl/c++/libdwflP.hh"
+
+int
+main (int, char *argv[])
+{
+  int fd = open (argv[1], O_RDONLY);
+  if (fd < 0)
+    throw std::runtime_error (strerror (errno));
+
+  const static Dwfl_Callbacks callbacks =
+    {
+      .find_elf = dwfl_build_id_find_elf,
+      .find_debuginfo = dwfl_standard_find_debuginfo,
+      .section_address = dwfl_offline_section_address,
+      .debuginfo_path = NULL,
+    };
+
+  Dwfl *dwfl = dwfl_begin (&callbacks);
+  if (dwfl == NULL)
+    throw_libdwfl ();
+
+  dwfl_report_begin (dwfl);
+  if (dwfl_report_offline (dwfl, argv[1], argv[1], fd) == NULL)
+    throw_libdwfl ();
+  dwfl_report_end (dwfl, NULL, NULL);
+
+  for (elfutils::dwfl_module_iterator modit (dwfl);
+       modit != elfutils::dwfl_module_iterator::end (); ++modit)
+    {
+      Dwarf_Off bias;
+      Dwarf *dw = dwfl_module_getdwarf (&*modit, &bias);
+      std::vector <std::pair <elfutils::unit_iterator, Dwarf_Die> > cudies;
+      for (elfutils::unit_iterator it (dw); it != elfutils::unit_iterator::end (); ++it)
+	cudies.push_back (std::make_pair (it, it->cudie));
+
+      for (size_t i = 0; i < cudies.size (); ++i)
+	{
+	  elfutils::unit_iterator jt (dw, cudies[i].second);
+	  std::cerr << std::hex << std::showbase
+		    << dwarf_dieoffset (&jt->cudie) << std::endl;
+	  for (size_t j = i; jt != elfutils::unit_iterator::end (); ++jt, ++j)
+	    assert (jt == cudies[j].first);
+	}
+
+      assert (elfutils::die_tree_iterator (elfutils::unit_iterator::end ())
+	      == elfutils::die_tree_iterator::end ());
+
+      for (elfutils::die_tree_iterator it (dw);
+	   it != elfutils::die_tree_iterator::end (); ++it)
+	std::cerr << std::dec
+		  << std::distance (elfutils::child_iterator (*it),
+				    elfutils::child_iterator::end ()) << ' '
+		  << std::distance (elfutils::attr_iterator (&*it),
+				    elfutils::attr_iterator::end ())
+		  << std::endl;
+    }
+
+  dwfl_end (dwfl);
+}
-- 
2.1.0


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]