summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPetr Machata <[email protected]>2015-04-03 10:11:34 +0200
committerPetr Machata <[email protected]>2015-04-14 16:35:10 +0200
commit205c1b156380e060ae49ef0cd1b108744286efd5 (patch)
tree20819fc6751902bf98f5fc88a022cbce5178bdc8
parent00cbd21384d3a77637200496c9c3bfb4c54f7a4a (diff)
Add C++ iterators
- 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 <[email protected]>
-rw-r--r--ChangeLog4
-rw-r--r--NEWS5
-rw-r--r--libdw/ChangeLog19
-rw-r--r--libdw/Makefile.am59
-rw-r--r--libdw/c++/attr_iterator.cc144
-rw-r--r--libdw/c++/child_iterator.cc98
-rw-r--r--libdw/c++/die_tree_iterator.cc178
-rw-r--r--libdw/c++/libdw251
-rw-r--r--libdw/c++/libdwP.hh88
-rw-r--r--libdw/c++/unit_iterator.cc146
-rw-r--r--libdwfl/ChangeLog13
-rw-r--r--libdwfl/Makefile.am33
-rw-r--r--libdwfl/c++/dwfl_module_iterator.cc128
-rw-r--r--libdwfl/c++/libdwfl78
-rw-r--r--libdwfl/c++/libdwflP.hh44
-rw-r--r--tests/ChangeLog7
-rw-r--r--tests/Makefile.am13
-rwxr-xr-xtests/run-test-iterators.sh52
-rw-r--r--tests/test-iterators.cc87
19 files changed, 1440 insertions, 7 deletions
diff --git a/ChangeLog b/ChangeLog
index 65c3ef5a..9633bfa9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2015-04-14 Petr Machata <[email protected]>
+ * NEWS: Mention <elfutils/libdw>, <elfutils/libdwfl>, and libdwpp.
+
+2015-04-14 Petr Machata <[email protected]>
+
* configure.ac (HAVE_CXX): New conditional.
2015-03-13 Mark Wielaard <[email protected]>
diff --git a/NEWS b/NEWS
index 60aa995d..02f8691e 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 3abb3828..a03d119f 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,22 @@
+2015-04-14 Petr Machata <[email protected]>
+
+ * 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 <[email protected]>
* libdwP.h (DWARF_E_NOT_CUDIE): New enumerator.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index 272289c4..43e83b58 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 00000000..7c4f59b7
--- /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 00000000..63414d56
--- /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 00000000..9e2cd35d
--- /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 00000000..e9bd4bb2
--- /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 00000000..cb6a145d
--- /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 00000000..c692d168
--- /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 d40dbae3..652428bf 100644
--- a/libdwfl/ChangeLog
+++ b/libdwfl/ChangeLog
@@ -1,3 +1,16 @@
+2015-04-14 Petr Machata <[email protected]>
+
+ * 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 <[email protected]>
* dwfl_module_getdwarf.c (find_symtab): Explicitly clear symdata,
diff --git a/libdwfl/Makefile.am b/libdwfl/Makefile.am
index 72c980bf..21e1844b 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 00000000..9eb97902
--- /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 00000000..88462fbb
--- /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 00000000..c3f2792b
--- /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 b6861849..728058f4 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,10 @@
+2015-04-14 Petr Machata <[email protected]>
+
+ * 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 <[email protected]>
* Makefile.am (TESTS): Add run-strip-test10.sh.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 45bb74df..5c5cfbfd 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 00000000..69425704
--- /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 00000000..987bc6af
--- /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);
+}