summaryrefslogtreecommitdiff
path: root/libdw
diff options
context:
space:
mode:
authorMark Wielaard <mark@klomp.org>2018-01-30 12:05:57 +0100
committerMark Wielaard <mark@klomp.org>2018-02-21 17:10:23 +0100
commit79f0e623dcde4b042bb72f636a2211d67d5c0ade (patch)
treef685cd3b857302046bc8576c0d23e89938175dbf /libdw
parent532ab1edd81474b907c4763c417e961d813729ea (diff)
downloadelfutils-79f0e623dcde4b042bb72f636a2211d67d5c0ade.tar.gz
libdw: Add new dwarf_get_units function to iterate over all units.
The dwarf_nextcu and dwarf_next_unit functions provide information to construct the offset to construct the associated CU DIE using dwarf_offdie or dwarf_offdie_types. This requires the user to know beforehand where to DIE data is stored (in the .debug_info or .debug_types section). For type units one also needs to use the type offset to create the actual type DIE. In DWARF5 DIEs can come from even more data locations. And there are also skeleton units which require the user to find the associated split compile unit DIE (which would come from a different file). The new dwarf_get_units function simplifies iterating over the units in a DWARF file. It doesn't require the user to know where the DIE data is stored, it will automagically iterate over all know data sources (sections) returning the Dwarf_CU and the associated Dwarf_Die if requested. If the user requests to know the associated "subdie" it will also be resolved. This implementation returns the correct subdie for type units. A future version will also handle skeleton units and return the associated skeleton DIE and split unit DIE. readelf has been adapted to use the new iterator and print the new DWARF5 unit header information (which it gets through dwarf_cu_die). The new interface hides which section exactly to iterate on (by design). readelf works around that by "cheating". It sets up a Dwarf_CU so that it gets the data from the right section, using the (normally) internal data structure. Signed-off-by: Mark Wielaard <mark@klomp.org>
Diffstat (limited to 'libdw')
-rw-r--r--libdw/ChangeLog7
-rw-r--r--libdw/Makefile.am2
-rw-r--r--libdw/dwarf_get_units.c112
-rw-r--r--libdw/libdw.h15
-rw-r--r--libdw/libdw.map1
5 files changed, 136 insertions, 1 deletions
diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index d0ceec17..caa9f1d5 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2018-01-30 Mark Wielaard <mark@klomp.org>
+
+ * Makefile.am (libdw_a_SOURCES): Add dwarf_get_units.c.
+ * dwarf_get_units.c: New file.
+ * libdw.h (dwarf_get_units): New function declaration.
+ * libdw.map (ELFUTILS_0.170): Add dwarf_get_units.
+
2018-01-29 Mark Wielaard <mark@klomp.org>
* dwarf.h (DW_UT_*): Add DWARF Unit Header Types.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index b1da4406..8848f141 100644
--- a/libdw/Makefile.am
+++ b/libdw/Makefile.am
@@ -90,7 +90,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
dwarf_getlocation_die.c dwarf_getlocation_attr.c \
dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
dwarf_cu_die.c dwarf_peel_type.c dwarf_default_lower_bound.c \
- dwarf_die_addr_die.c
+ dwarf_die_addr_die.c dwarf_get_units.c
if MAINTAINER_MODE
BUILT_SOURCES = $(srcdir)/known-dwarf.h
diff --git a/libdw/dwarf_get_units.c b/libdw/dwarf_get_units.c
new file mode 100644
index 00000000..19ff5de1
--- /dev/null
+++ b/libdw/dwarf_get_units.c
@@ -0,0 +1,112 @@
+/* Iterate through the CU units for a given Dwarf.
+ Copyright (C) 2016, 2017 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 <string.h>
+
+#include "libdwP.h"
+
+int
+dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie)
+{
+ Dwarf_Off off;
+ bool v4type;
+ if (cu == NULL)
+ {
+ off = 0;
+ v4type = false;
+ }
+ else
+ {
+ off = cu->end;
+ v4type = cu->sec_idx != IDX_debug_info;
+
+ /* Make sure we got a real (not fake) CU. */
+ if (cu->sec_idx != IDX_debug_info && cu->sec_idx != IDX_debug_types)
+ {
+ __libdw_seterrno (DWARF_E_INVALID_OFFSET);
+ return -1;
+ }
+
+ /* Do we have to switch to the other section, or are we at the end? */
+ if (! v4type)
+ {
+ if (off >= cu->dbg->sectiondata[IDX_debug_info]->d_size)
+ {
+ if (cu->dbg->sectiondata[IDX_debug_types] == NULL)
+ return 1;
+
+ off = 0;
+ v4type = true;
+ }
+ }
+ else
+ if (off >= cu->dbg->sectiondata[IDX_debug_types]->d_size)
+ return 1;
+ }
+
+ *next_cu = __libdw_findcu (dwarf, off, v4type);
+ if (*next_cu == NULL)
+ return -1;
+
+ Dwarf_CU *next = (*next_cu);
+
+ if (version != NULL)
+ *version = next->version;
+
+ if (unit_type != NULL)
+ *unit_type = next->unit_type;
+
+ if (cudie != NULL)
+ {
+ if (next->version >= 2 && next->version <= 5
+ && next->unit_type >= DW_UT_compile
+ && next->unit_type <= DW_UT_split_type)
+ *cudie = CUDIE (next);
+ else
+ memset (cudie, '\0', sizeof (Dwarf_Die));
+ }
+
+ if (subdie != NULL)
+ {
+ if (next->version >= 2 && next->version <= 5
+ && (next->unit_type == DW_UT_type
+ || next->unit_type == DW_UT_split_type))
+ *subdie = SUBDIE(next);
+ else
+ memset (subdie, '\0', sizeof (Dwarf_Die));
+ }
+
+ return 0;
+}
diff --git a/libdw/libdw.h b/libdw/libdw.h
index d85d2859..acc38916 100644
--- a/libdw/libdw.h
+++ b/libdw/libdw.h
@@ -289,6 +289,21 @@ extern int dwarf_next_unit (Dwarf *dwarf, Dwarf_Off off, Dwarf_Off *next_off,
__nonnull_attribute__ (3);
+/* Gets the next Dwarf_CU (unit), version, unit type and if available
+ the CU DIE and sub (type) DIE of the unit. Returns 0 on success,
+ -1 on error or 1 if there are no more units. To start iterating
+ provide NULL for CU. If version < 5 the unit type is set from the
+ CU DIE if available (DW_UT_compile for DW_TAG_compile_unit,
+ DW_UT_type for DW_TAG_type_unit or DW_UT_partial for
+ DW_TAG_partial_unit), otherwise it is set to zero. If unavailable
+ (the version or unit type is unknown) the CU DIE is cleared.
+ Likewise ff the sub DIE isn't isn't available (the unit type is not
+ DW_UT_type or DW_UT_split_type) the sub DIE tag is cleared. */
+extern int dwarf_get_units (Dwarf *dwarf, Dwarf_CU *cu, Dwarf_CU **next_cu,
+ Dwarf_Half *version, uint8_t *unit_type,
+ Dwarf_Die *cudie, Dwarf_Die *subdie)
+ __nonnull_attribute__ (3);
+
/* Decode one DWARF CFI entry (CIE or FDE) from the raw section data.
The E_IDENT from the originating ELF file indicates the address
size and byte order used in the CFI section contained in DATA;
diff --git a/libdw/libdw.map b/libdw/libdw.map
index cdc63ce2..8d12e892 100644
--- a/libdw/libdw.map
+++ b/libdw/libdw.map
@@ -348,4 +348,5 @@ ELFUTILS_0.170 {
ELFUTILS_0.171 {
global:
dwarf_die_addr_die;
+ dwarf_get_units;
} ELFUTILS_0.170;