[PATCH] libdw: Parse new DWARF5 units and CU DIEs.

2018-01-30 Thread Mark Wielaard
Parse DWARF5 units, add the unit_type to the Dwarf_CU and generalize some
code calculating the header length and getting at the first DIE of a unit.
Unit headers can have different sizes depending on the unit type.

Signed-off-by: Mark Wielaard 
---
 libdw/ChangeLog|  36 ++
 libdw/dwarf.h  |  16 ++-
 libdw/dwarf_cu_die.c   |  12 +-
 libdw/dwarf_formref_die.c  |  45 ---
 libdw/dwarf_getaranges.c   |  16 +--
 libdw/dwarf_getlocation_die.c  |   2 +-
 libdw/dwarf_getlocation_implicit_pointer.c |   2 +-
 libdw/dwarf_nextcu.c   | 191 ++---
 libdw/libdwP.h | 113 ++---
 libdw/libdw_findcu.c   |  67 ++
 libdwfl/ChangeLog  |   7 ++
 libdwfl/cu.c   |  14 +--
 12 files changed, 394 insertions(+), 127 deletions(-)

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 37edcd7..58c882b 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,39 @@
+2018-01-29  Mark Wielaard  
+
+   * dwarf.h (DW_UT_*): Add DWARF Unit Header Types.
+   * dwarf_cu_die.c (dwarf_cu_die): Rename arguments. type_signaturep
+   is now called unit_idp. type_offsetp is now called subdie_offsetp.
+   * dwarf_formref_die.c (dwarf_formref_die): Scan both .debug_info
+   and .debug_types sections for type units when type signature ref
+   not found.
+   * dwarf_getaranges.c (dwarf_getaranges): Use __libdw_findcu and
+   __libdw_first_die_off_from_cu instead of trying by hand.
+   * dwarf_getlocation_die.c (dwarf_getlocation_die): Use ISV4TU
+   instead of checking type_offset by hand.
+   * dwarf_getlocation_implicit_pointer.c
+   (dwarf_getlocation_implicit_pointer): Likewise.
+   * dwarf_nextcu.c (dwarf_next_unit): Call __libdw_next_unit.
+   (__libdw_next_unit): New function based on dwarf_next_unit with
+   DWARF5 header support.
+   * libdwP.h (struct Dwarf_CU): Renamed type_offset to subdie_offset
+   and type_sig8 to unit_id8.
+   (ISV4TU): New macro to determine whether a CU is a version 4 type
+   unit (which comes from the .debug_types section).
+   (DIE_OFFSET_FROM_CU_OFFSET): Replaced macro by real function...
+   (__libdw_first_die_from_cu_start): ... that also handles DWARF5
+   unit headers.
+   (__libdw_first_die_off_from_cu): New function that calls the above
+   using the CU fields.
+   (CUDIE): Use __libdw_first_die_off_from_cu.
+   (SUBDIE): New macro that provides the DIE for a CU using the
+   subdie_offset.
+   (__libdw_next_unit): New internal function declaration.
+   * libdw_findcu.c (__libdw_intern_next_unit): Use __libdw_next_unit.
+   Accept DWARF version 5 headers. Setup unit_type.
+   (__libdw_findcu): Rename debug_types argument to v4_debug_types
+   argument (to indicate that we are looking in the .debug_types
+   section). Support finding the exact offset (unit header start).
+
 2018-01-25  Mark Wielaard  
 
* Makefile.am (libdw_a_SOURCES): Add dwarf_die_addr_die.c.
diff --git a/libdw/dwarf.h b/libdw/dwarf.h
index 8edf719..bf81694 100644
--- a/libdw/dwarf.h
+++ b/libdw/dwarf.h
@@ -1,5 +1,5 @@
 /* This file defines standard DWARF types, structures, and macros.
-   Copyright (C) 2000-2011, 2014, 2016, 2017 Red Hat, Inc.
+   Copyright (C) 2000-2011, 2014, 2016, 2017, 2018 Red Hat, Inc.
This file is part of elfutils.
 
This file is free software; you can redistribute it and/or modify
@@ -29,6 +29,20 @@
 #ifndef _DWARF_H
 #define_DWARF_H 1
 
+/* DWARF Unit Header Types.  */
+enum
+  {
+DW_UT_compile = 0x01,
+DW_UT_type = 0x02,
+DW_UT_partial = 0x03,
+DW_UT_skeleton = 0x04,
+DW_UT_split_compile = 0x05,
+DW_UT_split_type = 0x06,
+
+DW_UT_lo_user = 0x80,
+DW_UT_hi_user = 0xff
+  };
+
 /* DWARF tags.  */
 enum
   {
diff --git a/libdw/dwarf_cu_die.c b/libdw/dwarf_cu_die.c
index 194da58..7594e7d 100644
--- a/libdw/dwarf_cu_die.c
+++ b/libdw/dwarf_cu_die.c
@@ -37,8 +37,8 @@
 Dwarf_Die *
 dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half *versionp,
  Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep,
- uint8_t *offset_sizep, uint64_t *type_signaturep,
- Dwarf_Off *type_offsetp)
+ uint8_t *offset_sizep, uint64_t *unit_idp,
+ Dwarf_Off *subdie_offsetp)
 {
   if (cu == NULL)
 return NULL;
@@ -53,10 +53,10 @@ dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half 
*versionp,
 *address_sizep = cu->address_size;
   if (offset_sizep != NULL)
 *offset_sizep = cu->offset_size;
-  if (type_signaturep != NULL)
-*type_signaturep = cu->type_sig8;
-  if (type_offsetp != NULL)
-*type_offsetp = cu->type_offset;
+  if (unit_idp != NULL)
+*unit_idp = cu->unit_id8;
+  if (subdie_

[PATCH] libdw: Add new dwarf_get_units function to iterate over all units.

2018-01-30 Thread Mark Wielaard
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 
---
 libdw/ChangeLog |   7 +++
 libdw/Makefile.am   |   2 +-
 libdw/dwarf_get_units.c | 112 ++
 libdw/libdw.h   |  15 ++
 libdw/libdw.map |   1 +
 src/ChangeLog   |   7 +++
 src/readelf.c   | 140 
 7 files changed, 248 insertions(+), 36 deletions(-)
 create mode 100644 libdw/dwarf_get_units.c

diff --git a/libdw/ChangeLog b/libdw/ChangeLog
index 58c882b..8e3bbef 100644
--- a/libdw/ChangeLog
+++ b/libdw/ChangeLog
@@ -1,3 +1,10 @@
+2018-01-30  Mark Wielaard  
+
+   * 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  
 
* dwarf.h (DW_UT_*): Add DWARF Unit Header Types.
diff --git a/libdw/Makefile.am b/libdw/Makefile.am
index b1da440..8848f14 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 000..19ff5de
--- /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 .  */
+
+
+#ifdef HAVE_CONFIG_H
+# include 
+#endif
+
+#include 
+
+#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 ot