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


Hi there,

I think there's enough context on the list for the patch, so just a
quick recap:

- every iterator implemented in an own .cc module

- new header files libdw, libdwfl with iterator declarations, and a new
  library libdwpp (-ldwpp) that ships the code

- the iterators are in versioned namespaces.  When changes are
  introduced, new version namespace is added, in which the new
  interfaces are specified and then the old namespace is imported,
  bringing is the rest that wasn't changed.  The new namespace then gets
  imported into the top-level "elfutils" namespace, so that people can
  simply write elfutils::die_tree_iterator.  Under the hood, this
  resolves to, say, elfutils::v1::die_tree_iterator, and that's what the
  ABI-level symbol is.

  This allows us to expose the layout of the individual classes, and
  avoid the overhead of pimpl.  It also avoids the messiness of symbol
  version files.

  Select private symbols that need header-file visibility were defined
  as attribute_hidden, the rest is either visible, or stashed in
  anonymous namespaces in .cc.

- dwgrep has been ported to this and works (though this is not pushed
  yet for obvious reasons), the elfutils-internal test case has been
  extended a bit to cover more of the API.

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.

Signed-off-by: Petr Machata <pmachata@redhat.com>
---
 ChangeLog                           |   4 +
 NEWS                                |   5 +-
 libdw/ChangeLog                     |  19 +++
 libdw/Makefile.am                   |  59 ++++++++-
 libdw/c++/attr_iterator.cc          | 144 +++++++++++++++++++++
 libdw/c++/child_iterator.cc         |  98 ++++++++++++++
 libdw/c++/die_tree_iterator.cc      | 178 +++++++++++++++++++++++++
 libdw/c++/libdw                     | 251 ++++++++++++++++++++++++++++++++++++
 libdw/c++/libdwP.hh                 |  88 +++++++++++++
 libdw/c++/unit_iterator.cc          | 146 +++++++++++++++++++++
 libdwfl/ChangeLog                   |  13 ++
 libdwfl/Makefile.am                 |  33 ++++-
 libdwfl/c++/dwfl_module_iterator.cc | 128 ++++++++++++++++++
 libdwfl/c++/libdwfl                 |  78 +++++++++++
 libdwfl/c++/libdwflP.hh             |  44 +++++++
 tests/ChangeLog                     |   7 +
 tests/Makefile.am                   |  13 +-
 tests/run-test-iterators.sh         |  52 ++++++++
 tests/test-iterators.cc             |  87 +++++++++++++
 19 files changed, 1440 insertions(+), 7 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 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 65c3ef5..9633bfa 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
 2015-04-14  Petr Machata  <pmachata@redhat.com>
 
+	* NEWS: Mention <elfutils/libdw>, <elfutils/libdwfl>, and libdwpp.
+
+2015-04-14  Petr Machata  <pmachata@redhat.com>
+
 	* configure.ac (HAVE_CXX): New conditional.
 
 2015-03-13  Mark Wielaard  <mjw@redhat.com>
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 3abb382..a03d119 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2015-04-14  Petr Machata  <pmachata@redhat.com>
+
+	* c++: New directory.
+	* c++/libdw, c++/libdwP.hh: New header files.
+	* 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.
+	(MOSTLYCLEANFILES): Add libdwpp-related files.
+
 2015-04-01  Petr Machata  <pmachata@redhat.com>
 
 	* libdwP.h (DWARF_E_NOT_CUDIE): New enumerator.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 272289c..43e83b5 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,44 @@ 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): libdwpp_pic.a ../libdwfl/libdwflpp_pic.a	\
+		     libdw.so$(EXEEXT)
+	$(CXXLINK) -shared -o $@ -Wl,--soname,$@.$(VERSION),-z,defs \
+		-Wl,--enable-new-dtags,--no-undefined \
+		-Wl,--whole-archive $^ -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)
@@ -139,4 +191,5 @@ noinst_HEADERS = libdwP.h memory-access.h dwarf_abbrev_hash.h \
 
 EXTRA_DIST = libdw.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..7c4f59b
--- /dev/null
+++ b/libdw/c++/attr_iterator.cc
@@ -0,0 +1,144 @@
+/* -*-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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdw"
+#include "libdwP.hh"
+
+namespace
+{
+  struct cb_data
+  {
+    // The visited attribute.
+    Dwarf_Attribute *at;
+
+    // Whether this is second pass through the callback.
+    bool been;
+  };
+
+  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;
+  }
+}
+
+attribute_hidden
+bool
+elfutils::v1::attr_iterator::move ()
+{
+  cb_data data = {&m_at, false};
+
+  // m_offset of 1 means there are no more attributes.
+  if (m_offset != 1)
+    {
+      m_offset = dwarf_getattrs (m_die, &callback, &data, m_offset);
+      if (m_offset == -1)
+	throw_libdw ();
+    }
+
+  return data.been;
+}
+
+attribute_hidden
+elfutils::v1::attr_iterator::attr_iterator (end_it)
+  : m_die (NULL)
+{}
+
+elfutils::v1::attr_iterator::attr_iterator (Dwarf_Die *die)
+  : m_die (die)
+  , m_at ((Dwarf_Attribute) {0, 0, NULL, NULL})
+  , m_offset (0)
+{
+  // Initial move, which can turn this into an end iterator.
+  ++*this;
+}
+
+elfutils::v1::attr_iterator
+elfutils::v1::attr_iterator::end ()
+{
+  return attr_iterator (end_it ());
+}
+
+bool
+elfutils::v1::attr_iterator::operator== (attr_iterator const &that) const
+{
+  return (m_die == NULL && that.m_die == NULL)
+    || (m_die != NULL && that.m_die != NULL
+	&& m_offset == that.m_offset
+	&& m_at.code == that.m_at.code);
+}
+
+bool
+elfutils::v1::attr_iterator::operator!= (attr_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::v1::attr_iterator &
+elfutils::v1::attr_iterator::operator++ ()
+{
+  assert (m_die != NULL);
+
+  if (! move ())
+    *this = end ();
+
+  return *this;
+}
+
+elfutils::v1::attr_iterator
+elfutils::v1::attr_iterator::operator++ (int)
+{
+  attr_iterator tmp = *this;
+  ++*this;
+  return tmp;
+}
+
+Dwarf_Attribute &
+elfutils::v1::attr_iterator::operator* ()
+{
+  assert (m_die != NULL);
+  return m_at;
+}
+
+Dwarf_Attribute *
+elfutils::v1::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..63414d5
--- /dev/null
+++ b/libdw/c++/child_iterator.cc
@@ -0,0 +1,98 @@
+/* -*-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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdw"
+#include "libdwP.hh"
+
+#include <cstring>
+
+attribute_hidden
+elfutils::v1::child_iterator::child_iterator (end_it)
+{
+  m_die.addr = NULL;
+}
+
+elfutils::v1::child_iterator::child_iterator (Dwarf_Die parent)
+{
+  if (! dwpp_child (parent, m_die))
+    *this = end ();
+}
+
+elfutils::v1::child_iterator
+elfutils::v1::child_iterator::end ()
+{
+  return child_iterator (end_it ());
+}
+
+bool
+elfutils::v1::child_iterator::operator== (child_iterator const &that) const
+{
+  return m_die.addr == that.m_die.addr;
+}
+
+bool
+elfutils::v1::child_iterator::operator!= (child_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::v1::child_iterator &
+elfutils::v1::child_iterator::operator++ ()
+{
+  assert (m_die.addr != NULL);
+
+  if (! dwpp_siblingof (m_die, m_die))
+    *this = end ();
+
+  return *this;
+}
+
+elfutils::v1::child_iterator
+elfutils::v1::child_iterator::operator++ (int)
+{
+  child_iterator ret = *this;
+  ++*this;
+  return ret;
+}
+
+Dwarf_Die &
+elfutils::v1::child_iterator::operator* ()
+{
+  assert (m_die.addr != NULL);
+  return m_die;
+}
+
+Dwarf_Die *
+elfutils::v1::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..9e2cd35
--- /dev/null
+++ b/libdw/c++/die_tree_iterator.cc
@@ -0,0 +1,178 @@
+/* -*-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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+#include <algorithm>
+
+#include "libdw"
+#include "libdwP.hh"
+
+namespace
+{
+  Dwarf_Die
+  offdie (elfutils::v1::unit_iterator &cuit, Dwarf_Off offset)
+  {
+    return (dwarf_tag (&cuit->cudie) == DW_TAG_type_unit
+	    ? dwpp_offdie_types : dwpp_offdie)
+      (dwarf_cu_getdwarf (cuit->cudie.cu), offset);
+  }
+}
+
+attribute_hidden
+bool
+elfutils::v1::die_tree_iterator::move ()
+{
+  Dwarf_Die child;
+  if (dwpp_child (m_die, child))
+    {
+      m_stack.push_back (dwarf_dieoffset (&m_die));
+      m_die = child;
+      return true;
+    }
+
+  do
+    if (dwpp_siblingof (m_die, m_die))
+      return true;
+    else
+      // No sibling found.  Go a level up and retry, unless this
+      // was a sole, childless CU DIE.
+      if (! m_stack.empty ())
+	{
+	  m_die = offdie (m_cuit, m_stack.back ());
+	  m_stack.pop_back ();
+	}
+  while (! m_stack.empty ());
+
+  if (++m_cuit == elfutils::v1::unit_iterator::end ())
+    return false;
+
+  m_die = m_cuit->cudie;
+  return true;
+}
+
+attribute_hidden
+elfutils::v1::die_tree_iterator::die_tree_iterator (end_it)
+  : m_cuit (unit_iterator::end ())
+{}
+
+elfutils::v1::die_tree_iterator::die_tree_iterator (Dwarf *dw)
+  : m_cuit (unit_iterator (dw))
+{
+  if (m_cuit != unit_iterator::end ())
+    m_die = m_cuit->cudie;
+}
+
+elfutils::v1::die_tree_iterator::die_tree_iterator (unit_iterator const &cuit)
+  : m_cuit (cuit)
+{
+  if (m_cuit != unit_iterator::end ())
+    m_die = m_cuit->cudie;
+}
+
+elfutils::v1::die_tree_iterator
+elfutils::v1::die_tree_iterator::end ()
+{
+  return die_tree_iterator (end_it ());
+}
+
+bool
+elfutils::v1::die_tree_iterator::operator== (die_tree_iterator
+						const &that) const
+{
+  return m_cuit == that.m_cuit
+    && (m_cuit == unit_iterator::end () || m_die.addr == that.m_die.addr);
+}
+
+bool
+elfutils::v1::die_tree_iterator::operator!= (die_tree_iterator
+						const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::v1::die_tree_iterator &
+elfutils::v1::die_tree_iterator::operator++ ()
+{
+  assert (m_cuit != unit_iterator::end ());
+
+  if (! move ())
+    *this = end ();
+
+  return *this;
+}
+
+elfutils::v1::die_tree_iterator
+elfutils::v1::die_tree_iterator::operator++ (int)
+{
+  die_tree_iterator ret = *this;
+  ++*this;
+  return ret;
+}
+
+Dwarf_Die &
+elfutils::v1::die_tree_iterator::operator* ()
+{
+  assert (m_cuit != unit_iterator::end ());
+  return m_die;
+}
+
+Dwarf_Die *
+elfutils::v1::die_tree_iterator::operator-> ()
+{
+  return &**this;
+}
+
+elfutils::v1::die_tree_iterator
+elfutils::v1::die_tree_iterator::parent ()
+{
+  assert (m_cuit != unit_iterator::end ());
+
+  if (m_stack.empty ())
+    return end ();
+
+  die_tree_iterator ret = *this;
+  ret.m_die = offdie (m_cuit, m_stack.back ());
+  ret.m_stack.pop_back ();
+
+  return ret;
+}
+
+std::vector <Dwarf_Die>
+elfutils::v1::path_from_root (die_tree_iterator &it)
+{
+  std::vector <Dwarf_Die> ret;
+  for (die_tree_iterator end = die_tree_iterator::end ();
+       it != end; it = it.parent ())
+    ret.push_back (*it);
+  std::reverse (ret.begin (), ret.end ());
+  return ret;
+}
diff --git a/libdw/c++/libdw b/libdw/c++/libdw
new file mode 100644
index 0000000..e9bd4bb
--- /dev/null
+++ b/libdw/c++/libdw
@@ -0,0 +1,251 @@
+/* -*-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 "libdw.h"
+
+namespace elfutils
+{
+namespace v1
+{
+  // 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>
+  {
+    Dwarf *m_dw;
+    Dwarf_Off m_offset;
+    Dwarf_Off m_old_offset;
+    unit_info m_info;
+    bool m_types;
+
+    struct end_it {};
+    explicit unit_iterator (end_it);
+
+    bool move ();
+
+  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);
+
+    // 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>
+  {
+    Dwarf_Die m_die;
+
+    struct end_it {};
+    child_iterator (end_it);
+
+  public:
+    explicit child_iterator (Dwarf_Die parent);
+
+    // 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>
+  {
+    unit_iterator m_cuit;
+    // Internally, only offsets are kept on the stack.
+    std::vector <Dwarf_Off> m_stack;
+    Dwarf_Die m_die;
+
+    struct end_it {};
+    die_tree_iterator (end_it);
+
+    bool move ();
+
+  public:
+    explicit die_tree_iterator (Dwarf *dw);
+    explicit die_tree_iterator (unit_iterator const &cuit);
+
+    // 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 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 ();
+  };
+
+  // Return a list 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.
+  std::vector <Dwarf_Die> path_from_root (die_tree_iterator &it);
+
+  // An attribute iterator goes through attributes of a given DIE.
+  class attr_iterator
+    : public std::iterator <std::input_iterator_tag, Dwarf_Attribute>
+  {
+    Dwarf_Die *m_die;
+    Dwarf_Attribute m_at;
+    ptrdiff_t m_offset;
+
+    struct end_it {};
+    attr_iterator (end_it);
+
+    bool move ();
+
+  public:
+    attr_iterator (Dwarf_Die *die);
+
+    // 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-> ();
+  };
+}
+}
+
+namespace elfutils
+{
+  using namespace elfutils::v1;
+}
+
+#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..c692d16
--- /dev/null
+++ b/libdw/c++/unit_iterator.cc
@@ -0,0 +1,146 @@
+/* -*-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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <dwarf.h>
+
+#include "libdw"
+#include "libdwP.hh"
+
+attribute_hidden
+bool
+elfutils::v1::unit_iterator::move ()
+{
+  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)
+    return false;
+  else if (rc != 0)
+    {
+      m_types = true;
+      m_offset = 0;
+      m_old_offset = 0;
+      return move ();
+    }
+  else
+    {
+      m_info.cudie = (m_types ? dwpp_offdie_types : dwpp_offdie)
+	(m_dw, m_old_offset + hsize);
+      return true;
+    }
+}
+
+attribute_hidden
+elfutils::v1::unit_iterator::unit_iterator (end_it)
+  : m_dw (NULL)
+{}
+
+elfutils::v1::unit_iterator::unit_iterator (Dwarf *dw)
+  : m_dw (dw)
+  , m_offset (0)
+  , m_old_offset (0)
+  , m_types (false)
+{
+  // Initial move which may turn this into an end iterator.
+  ++*this;
+}
+
+elfutils::v1::unit_iterator::unit_iterator (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)
+{
+  // Initial move, which shouldn't change this into an end iterator,
+  // we were given a valid CU DIE!
+  bool alive = move ();
+  assert (alive);
+}
+
+elfutils::v1::unit_iterator
+elfutils::v1::unit_iterator::end ()
+{
+  return unit_iterator (end_it ());
+}
+
+bool
+elfutils::v1::unit_iterator::operator== (unit_iterator const &that) const
+{
+  return (m_dw == NULL && that.m_dw == NULL)
+    || (m_dw != NULL && that.m_dw != NULL
+	&& m_types == that.m_types
+	&& m_offset == that.m_offset);
+}
+
+bool
+elfutils::v1::unit_iterator::operator!= (unit_iterator const &that) const
+{
+  return ! (*this == that);
+}
+
+elfutils::v1::unit_iterator &
+elfutils::v1::unit_iterator::operator++ ()
+{
+  assert (m_dw != NULL);
+
+  if (! move ())
+    *this = end ();
+
+  return *this;
+}
+
+elfutils::v1::unit_iterator
+elfutils::v1::unit_iterator::operator++ (int)
+{
+  unit_iterator tmp = *this;
+  ++*this;
+  return tmp;
+}
+
+elfutils::v1::unit_info &
+elfutils::v1::unit_iterator::operator* ()
+{
+  assert (m_dw != NULL);
+  return m_info;
+}
+
+elfutils::v1::unit_info *
+elfutils::v1::unit_iterator::operator-> ()
+{
+  return &**this;
+}
diff --git a/libdwfl/ChangeLog b/libdwfl/ChangeLog
index d40dbae..652428b 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,16 @@
+2015-04-14  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..9eb9790
--- /dev/null
+++ b/libdwfl/c++/dwfl_module_iterator.cc
@@ -0,0 +1,128 @@
+/* -*-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/>.  */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "libdwfl"
+#include "libdwflP.hh"
+
+namespace
+{
+  struct cb_data
+  {
+    Dwfl_Module **m_modulep;
+  };
+
+  int
+  callback (Dwfl_Module *mod, void **, const char *,
+	    Dwarf_Addr, void *arg)
+  {
+    cb_data *d = static_cast <cb_data *> (arg);
+    *d->m_modulep = mod;
+    return DWARF_CB_ABORT;
+  }
+}
+
+attribute_hidden
+bool
+elfutils::v1::dwfl_module_iterator::move ()
+{
+  cb_data d = {&m_module};
+  m_offset = dwfl_getmodules (m_dwfl, callback, &d, m_offset);
+  if (m_offset == -1)
+    throw_libdwfl ();
+  return m_offset != 0;
+}
+
+attribute_hidden
+elfutils::v1::dwfl_module_iterator::dwfl_module_iterator (end_it)
+  : m_dwfl (NULL)
+{}
+
+elfutils::v1::dwfl_module_iterator::dwfl_module_iterator (Dwfl *dwfl)
+  : m_dwfl (dwfl)
+  , m_offset (0)
+{
+  // Initial move, which can turn this into an end iterator.
+  ++*this;
+}
+
+elfutils::v1::dwfl_module_iterator
+elfutils::v1::dwfl_module_iterator::end ()
+{
+  return dwfl_module_iterator (end_it ());
+}
+
+elfutils::v1::dwfl_module_iterator &
+elfutils::v1::dwfl_module_iterator::operator++ ()
+{
+  assert (m_dwfl != NULL);
+
+  if (! move ())
+    *this = end ();
+
+  return *this;
+}
+
+elfutils::v1::dwfl_module_iterator
+elfutils::v1::dwfl_module_iterator::operator++ (int)
+{
+  dwfl_module_iterator ret = *this;
+  ++*this;
+  return ret;
+}
+
+bool
+elfutils::v1::dwfl_module_iterator::operator== (dwfl_module_iterator
+							const &that) const
+{
+  return m_dwfl == that.m_dwfl
+    && (m_dwfl == NULL || m_offset == that.m_offset);
+}
+
+bool
+elfutils::v1::dwfl_module_iterator::operator!= (dwfl_module_iterator
+							const &that) const
+{
+  return ! (*this == that);
+}
+
+Dwfl_Module &
+elfutils::v1::dwfl_module_iterator::operator* () const
+{
+  assert (m_dwfl != NULL);
+  return *m_module;
+}
+
+Dwfl_Module *
+elfutils::v1::dwfl_module_iterator::operator-> () const
+{
+  return &**this;
+}
diff --git a/libdwfl/c++/libdwfl b/libdwfl/c++/libdwfl
new file mode 100644
index 0000000..88462fb
--- /dev/null
+++ b/libdwfl/c++/libdwfl
@@ -0,0 +1,78 @@
+/* -*-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 "libdwfl.h"
+
+namespace elfutils
+{
+namespace v1
+{
+  // 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 *>
+  {
+    Dwfl *m_dwfl;
+    ptrdiff_t m_offset;
+    Dwfl_Module *m_module;
+
+    struct end_it {};
+    explicit dwfl_module_iterator (end_it);
+
+    bool move ();
+
+  public:
+    explicit dwfl_module_iterator (Dwfl *dwfl);
+    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;
+  };
+}
+}
+
+namespace elfutils
+{
+  using namespace elfutils::v1;
+}
+
+#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 b686184..728058f 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,10 @@
+2015-04-14  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-04-01  H.J. Lu  <hjl.tools@gmail.com>
 
 	* Makefile.am (TESTS): Add run-strip-test10.sh.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 45bb74d..5c5cfbf 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -143,6 +143,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 \
@@ -293,7 +298,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
 	     run-getsrc-die.sh run-strptr.sh \
 	     testfile-x32-core.bz2 testfile-x32.bz2 \
 	     backtrace.x32.core.bz2 backtrace.x32.exec.bz2 \
-	     testfile-x32-s.bz2 testfile-x32-d.bz2 testfile-x32-debug.bz2
+	     testfile-x32-s.bz2 testfile-x32-d.bz2 testfile-x32-debug.bz2 \
+	     run-test-iterators.sh
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
@@ -337,16 +343,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
@@ -438,6 +447,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]