]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
libdw: Add dwarf_peel_type. Use it in dwarf_aggregate_size.
authorMark Wielaard <mjw@redhat.com>
Mon, 6 Oct 2014 20:00:16 +0000 (22:00 +0200)
committerMark Wielaard <mjw@redhat.com>
Wed, 5 Nov 2014 13:31:33 +0000 (14:31 +0100)
Add new function dwarf_peel_type. Some type annotations in DWARF are
specified by modifier tag type wrappers instead of attributes.
For type aliases (typedef) and qualifiers (const, volatile, restrict)
tags dwarf_peel_type follows the DW_AT_type attributes till it finds
a base, user-defined, reference or pointer type DIE.

Use this new function in the backends for return type DIEs (replacing
the existing dwarf_peel_type there) and in dwarf_aggregate_size so
it can provide the sizes for qualified types too. Add a new version
and testcase for the new dwarf_aggregate_size functionality.

Signed-off-by: Mark Wielaard <mjw@redhat.com>
15 files changed:
ChangeLog
NEWS
backends/ChangeLog
backends/libebl_CPU.h
libdw/ChangeLog
libdw/Makefile.am
libdw/dwarf_aggregate_size.c
libdw/dwarf_peel_type.c [new file with mode: 0644]
libdw/libdw.h
libdw/libdw.map
libdw/libdwP.h
tests/ChangeLog
tests/Makefile.am
tests/run-aggregate-size.sh
tests/testfile-sizes3.o.bz2 [new file with mode: 0644]

index 8277932488965c905dc6b02161121ef9d8ca040e..0947608d373b01fc7d9e8ef5369ebde416cd2d21 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2014-10-06  Mark Wielaard  <mjw@redhat.com>
+
+       * NEWS: New section 0.161. Add dwarf_peel_type.
+
 2014-08-25  Mark Wielaard  <mjw@redhat.com>
 
        * configure.ac: Set version to 0.160.
diff --git a/NEWS b/NEWS
index aceb3e33eb5394ef047cee26c807ab816b93ccc9..130856eae0e8b2796ebf996d044d1947f0249f26 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,8 @@
+Version 0.161
+
+libdw: New function dwarf_peel_type. dwarf_aggregate_size now uses
+       dwarf_peel_type to also provide the sizes of qualified types.
+
 Version 0.160
 
 libdw: New functions dwarf_cu_getdwarf, dwarf_cu_die.
index a335b2075f4b29c83b4138d70bb4a4ee9664a32e..82a2bf1595fb59dfbb67dff7096710256ea3e655 100644 (file)
@@ -1,3 +1,8 @@
+2014-10-06  Mark Wielaard  <mjw@redhat.com>
+
+       * libebl_CPU.h (dwarf_peel_type): Removed.
+       (dwarf_peeled_die_type): Use libdw dwarf_peel_type.
+
 2014-07-18  Kyle McMartin  <kyle@redhat.com>
            Mark Wielaard  <mjw@redhat.com>
 
index fa0d4f2d8690bca3b5915076283509759c5c5a26..ef2b922b99edd07536b22b7d24e694f7ea43c18a 100644 (file)
@@ -53,23 +53,6 @@ extern bool (*generic_debugscn_p) (const char *) attribute_hidden;
      if (_die == NULL) return -1; \
      dwarf_tag (_die); })
 
-/* Follow typedefs and qualifiers to get to the actual type.  */
-static inline int
-dwarf_peel_type (Dwarf_Die *typediep, Dwarf_Attribute *attrp)
-{
-  int tag = DWARF_TAG_OR_RETURN (typediep);
-  while (tag == DW_TAG_typedef
-        || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
-        || tag == DW_TAG_restrict_type)
-    {
-      attrp = dwarf_attr_integrate (typediep, DW_AT_type, attrp);
-      typediep = dwarf_formref_die (attrp, typediep);
-      tag = DWARF_TAG_OR_RETURN (typediep);
-    }
-
-  return tag;
-}
-
 /* Get a type die corresponding to DIE.  Peel CV qualifiers off
    it.  */
 static inline int
@@ -84,7 +67,10 @@ dwarf_peeled_die_type (Dwarf_Die *die, Dwarf_Die *result)
   if (dwarf_formref_die (attr, result) == NULL)
     return -1;
 
-  return dwarf_peel_type (result, attr);
+  if (dwarf_peel_type (result, result) != 0)
+    return -1;
+
+  return DWARF_TAG_OR_RETURN (result);
 }
 
 #endif /* libebl_CPU.h */
index 89b2735fbc40504299b553fcb0a69d15751ac8e5..82cdd8833ed6eb70368a7f71e683ca616b7cf374 100644 (file)
@@ -1,3 +1,13 @@
+2014-10-06  Mark Wielaard  <mjw@redhat.com>
+
+       * Makefile.am (libdw_a_SOURCES): Add dwarf_peel_type.c.
+       * dwarf_aggregate_size.c (get_type): Use dwarf_peel_type.
+       (aggregate_size): Likewise. Add old and new version.
+       * dwarf_peel_type.c: New file.
+       * libdw.h (dwarf_peel_type): New function declaration.
+       * libdwP.h (dwarf_peel_type): New internal declaration.
+       * libdw.map (ELFUTILS_0.161): New section.
+
 2014-10-15  Petr Machata  <pmachata@redhat.com>
 
        * libdwP.h (struct Dwarf_Files_s.cu): Drop field.
index 2e42a3764e0d63c0624078f7f589856e54e381a1..859af4d4341774aea60b4b8521a4aa43531f4b54 100644 (file)
@@ -87,7 +87,7 @@ libdw_a_SOURCES = dwarf_begin.c dwarf_begin_elf.c dwarf_end.c dwarf_getelf.c \
                  dwarf_aggregate_size.c dwarf_getlocation_implicit_pointer.c \
                  dwarf_getlocation_die.c dwarf_getlocation_attr.c \
                  dwarf_getalt.c dwarf_setalt.c dwarf_cu_getdwarf.c \
-                 dwarf_cu_die.c
+                 dwarf_cu_die.c dwarf_peel_type.c
 
 if MAINTAINER_MODE
 BUILT_SOURCES = $(srcdir)/known-dwarf.h
index 5d23541e9b4e3bff310410675b64874d7a3cf4f4..1666e2402fc35a61306acfc95aa46bfe305d2e96 100644 (file)
 static Dwarf_Die *
 get_type (Dwarf_Die *die, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem)
 {
-  return INTUSE(dwarf_formref_die)
+  Dwarf_Die *type = INTUSE(dwarf_formref_die)
     (INTUSE(dwarf_attr_integrate) (die, DW_AT_type, attr_mem), type_mem);
+
+  if (INTUSE(dwarf_peel_type) (type, type) != 0)
+    return NULL;
+
+  return type;
 }
 
 static int
@@ -198,7 +203,6 @@ aggregate_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Die *type_mem)
 
   switch (INTUSE(dwarf_tag) (die))
     {
-    case DW_TAG_typedef:
     case DW_TAG_subrange_type:
       return aggregate_size (get_type (die, &attr_mem, type_mem),
                             size, type_mem); /* Tail call.  */
@@ -225,6 +229,12 @@ dwarf_aggregate_size (die, size)
      Dwarf_Word *size;
 {
   Dwarf_Die type_mem;
+
+  if (INTUSE (dwarf_peel_type) (die, die) != 0)
+    return -1;
+
   return aggregate_size (die, size, &type_mem);
 }
 INTDEF (dwarf_aggregate_size)
+OLD_VERSION (dwarf_aggregate_size, ELFUTILS_0.144)
+NEW_VERSION (dwarf_aggregate_size, ELFUTILS_0.161)
diff --git a/libdw/dwarf_peel_type.c b/libdw/dwarf_peel_type.c
new file mode 100644 (file)
index 0000000..a110bc5
--- /dev/null
@@ -0,0 +1,74 @@
+/* Peel type aliases and qualifier tags from a type DIE.
+   Copyright (C) 2014 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 "libdwP.h"
+#include <dwarf.h>
+#include <string.h>
+
+
+int
+dwarf_peel_type (die, result)
+     Dwarf_Die *die;
+     Dwarf_Die *result;
+{
+  int tag;
+
+  /* Ignore previous errors.  */
+  if (die == NULL)
+    return -1;
+
+  *result = *die;
+  tag = INTUSE (dwarf_tag) (result);
+  while (tag == DW_TAG_typedef
+        || tag == DW_TAG_const_type
+        || tag == DW_TAG_volatile_type
+        || tag == DW_TAG_restrict_type)
+    {
+      Dwarf_Attribute attr_mem;
+      Dwarf_Attribute *attr = INTUSE (dwarf_attr_integrate) (die, DW_AT_type,
+                                                            &attr_mem);
+      if (attr == NULL)
+       return 1;
+
+      result = INTUSE (dwarf_formref_die) (attr, result);
+      if (result == NULL)
+       return -1;
+
+      tag = INTUSE (dwarf_tag) (result);
+    }
+
+  if (tag == DW_TAG_invalid)
+    return -1;
+
+  return 0;
+}
+INTDEF(dwarf_peel_type)
index 196d54ae0c1d5bb8b0c7e08ecf2775cfd65432b4..30364ba15283a55282f9724861c91adc961690bf 100644 (file)
@@ -398,6 +398,24 @@ extern int dwarf_child (Dwarf_Die *die, Dwarf_Die *result)
 extern int dwarf_siblingof (Dwarf_Die *die, Dwarf_Die *result)
      __nonnull_attribute__ (2);
 
+/* For type aliases and qualifier type DIEs follow the DW_AT_type
+   attribute (recursively) and return the underlying type Dwarf_Die.
+   Returns 0 when RESULT contains a Dwarf_Die (possibly equal to the
+   given DIE) that isn't a type alias or qualifier type.  Returns 1
+   when RESULT contains a type alias or qualifier Dwarf_Die that
+   couldn't be peeled further (it doesn't have a DW_TAG_type
+   attribute).  Returns -1 when an error occured.
+
+   The current DWARF specification defines one type alias tag
+   (DW_TAG_typedef) and three qualifier type tags (DW_TAG_const_type,
+   DW_TAG_volatile_type, DW_TAG_restrict_type).  A future version of
+   this function might peel other alias or qualifier type tags if a
+   future DWARF version or GNU extension defines other type aliases or
+   qualifier type tags that don't modify or change the structural
+   layout of the underlying type.  */
+extern int dwarf_peel_type (Dwarf_Die *die, Dwarf_Die *result)
+    __nonnull_attribute__ (2);
+
 /* Check whether the DIE has children.  */
 extern int dwarf_haschildren (Dwarf_Die *die) __nonnull_attribute__ (1);
 
index 55bc5371a25967de247ace601f25762d70280bf7..0c0ea99711d4b4663d057bcb7652e14612bacf9b 100644 (file)
@@ -306,4 +306,14 @@ ELFUTILS_0.160 {
   global:
     dwarf_cu_getdwarf;
     dwarf_cu_die;
-} ELFUTILS_0.159;
\ No newline at end of file
+} ELFUTILS_0.159;
+
+ELFUTILS_0.161 {
+  global:
+    dwarf_peel_type;
+
+    # Replaced ELFUTILS_0.144 version.  Both versions point to the
+    # same implementation, but users of the new symbol version can
+    # presume that it uses dwarf_peel_type.
+    dwarf_aggregate_size;
+} ELFUTILS_0.160;
index c0f3741c85191c7e318eebe8f2d6eec9b8c31f8b..f0ed316ff7456d23a6ce322ebcc2c373873f185a 100644 (file)
@@ -689,6 +689,7 @@ INTDECL (dwarf_lowpc)
 INTDECL (dwarf_nextcu)
 INTDECL (dwarf_next_unit)
 INTDECL (dwarf_offdie)
+INTDECL (dwarf_peel_type)
 INTDECL (dwarf_ranges)
 INTDECL (dwarf_setalt)
 INTDECL (dwarf_siblingof)
index 6b76248821e97284234c160b5a516da17d121d78..5c06d236b08e37c95e878314640530ee7b95c3ba 100644 (file)
@@ -1,3 +1,9 @@
+2014-10-06  Mark Wielaard  <mjw@redhat.com>
+
+       * run-aggregate-size.sh: Add testfile-sizes3.o test case.
+       * testfile-sizes3.o.bz2: New test file.
+       * Makefile.am (EXTRA_DIST): Add testfile-sizes3.o.bz2.
+
 2014-10-02  Mark Wielaard  <mjw@redhat.com>
 
        * run-deleted.sh: Unset VALGRIND_CMD before running deleted.
index 1c4b2b19202174bfece28325059023ef2d64b1ec..09909d28360b2e03a8b51c5c2b96d220296f37ba 100644 (file)
@@ -275,7 +275,8 @@ EXTRA_DIST = run-arextract.sh run-arsymtest.sh \
             run-readelf-zdebug.sh testfile-debug.bz2 testfile-zdebug.bz2 \
             run-deleted.sh run-linkmap-cut.sh linkmap-cut-lib.so.bz2 \
             linkmap-cut.bz2 linkmap-cut.core.bz2 \
-            run-aggregate-size.sh testfile-sizes1.o.bz2 testfile-sizes2.o.bz2
+            run-aggregate-size.sh testfile-sizes1.o.bz2 testfile-sizes2.o.bz2 \
+            testfile-sizes3.o.bz2
 
 if USE_VALGRIND
 valgrind_cmd='valgrind -q --error-exitcode=1 --run-libc-freeres=no'
index 7d812a5f2b712c7011e65c92e217d5b0dffa65cb..42b0742b126563039cbee3bb29edc69e14153a17 100755 (executable)
 # gcc -g -c -o testfile-sizes1.o sizes.c
 # clang -g -c -o testfile-sizes2.o sizes.c
 
-testfiles testfile-sizes1.o testfile-sizes2.o
+# const char c;
+# volatile int i;
+# const volatile long l;
+#
+# void * restrict v;
+#
+# struct s
+# {
+#   const char *a;
+#   volatile int i;
+# } s;
+#
+# const char ca[16];
+# volatile int ia[32];
+# const volatile void * const volatile restrict va[64];
+# struct s sa[8];
+#
+# typedef const int foo;
+# typedef volatile foo bar;
+# foo f;
+# bar b;
+#
+# gcc -std=c99 -g -c -o testfile-sizes3.o sizes.c
+
+testfiles testfile-sizes1.o testfile-sizes2.o testfile-sizes3.o
 
 testrun_compare ${abs_builddir}/aggregate_size -e testfile-sizes1.o <<\EOF
 c size 1
@@ -64,4 +88,18 @@ va size 512
 sa size 128
 EOF
 
+testrun_compare ${abs_builddir}/aggregate_size -e testfile-sizes3.o <<\EOF
+c size 1
+i size 4
+l size 8
+v size 8
+s size 16
+ca size 16
+ia size 128
+va size 512
+sa size 128
+f size 4
+b size 4
+EOF
+
 exit 0
diff --git a/tests/testfile-sizes3.o.bz2 b/tests/testfile-sizes3.o.bz2
new file mode 100644 (file)
index 0000000..7fa6a8a
Binary files /dev/null and b/tests/testfile-sizes3.o.bz2 differ