diff options
| author | Petr Machata <[email protected]> | 2015-04-03 10:11:34 +0200 |
|---|---|---|
| committer | Petr Machata <[email protected]> | 2015-04-14 16:35:10 +0200 |
| commit | 205c1b156380e060ae49ef0cd1b108744286efd5 (patch) | |
| tree | 20819fc6751902bf98f5fc88a022cbce5178bdc8 | |
| parent | 00cbd21384d3a77637200496c9c3bfb4c54f7a4a (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-- | ChangeLog | 4 | ||||
| -rw-r--r-- | NEWS | 5 | ||||
| -rw-r--r-- | libdw/ChangeLog | 19 | ||||
| -rw-r--r-- | libdw/Makefile.am | 59 | ||||
| -rw-r--r-- | libdw/c++/attr_iterator.cc | 144 | ||||
| -rw-r--r-- | libdw/c++/child_iterator.cc | 98 | ||||
| -rw-r--r-- | libdw/c++/die_tree_iterator.cc | 178 | ||||
| -rw-r--r-- | libdw/c++/libdw | 251 | ||||
| -rw-r--r-- | libdw/c++/libdwP.hh | 88 | ||||
| -rw-r--r-- | libdw/c++/unit_iterator.cc | 146 | ||||
| -rw-r--r-- | libdwfl/ChangeLog | 13 | ||||
| -rw-r--r-- | libdwfl/Makefile.am | 33 | ||||
| -rw-r--r-- | libdwfl/c++/dwfl_module_iterator.cc | 128 | ||||
| -rw-r--r-- | libdwfl/c++/libdwfl | 78 | ||||
| -rw-r--r-- | libdwfl/c++/libdwflP.hh | 44 | ||||
| -rw-r--r-- | tests/ChangeLog | 7 | ||||
| -rw-r--r-- | tests/Makefile.am | 13 | ||||
| -rwxr-xr-x | tests/run-test-iterators.sh | 52 | ||||
| -rw-r--r-- | tests/test-iterators.cc | 87 |
19 files changed, 1440 insertions, 7 deletions
@@ -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]> @@ -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); +} |
