]> sourceware.org Git - systemtap.git/commitdiff
PR14434 Filter out partial structs/classes.
authorMark Wielaard <mjw@redhat.com>
Mon, 6 Aug 2012 18:31:20 +0000 (20:31 +0200)
committerMark Wielaard <mjw@redhat.com>
Mon, 6 Aug 2012 22:37:14 +0000 (00:37 +0200)
GCC might generate a struct/class without DW_AT_declaration,
but that only contains members which have DW_AT_declaration
set.  We aren't interested in those.  PR14434 (GCC bug #54181).
Filter them out with a new function has_only_decl_members in dwflpp.cxx.
Add new testcase testsuite/systemtap.base/partial-class-type.exp.

dwflpp.cxx
testsuite/systemtap.base/partial-class-type-heap.cxx [new file with mode: 0644]
testsuite/systemtap.base/partial-class-type-main.cxx [new file with mode: 0644]
testsuite/systemtap.base/partial-class-type.exp [new file with mode: 0644]
testsuite/systemtap.base/partial-class-type.hxx [new file with mode: 0644]

index 3fb50b2939258af1d57ba1b10f2228ab6cc216e2..ea93469f311bff13075dda535d9c8336792c92af 100644 (file)
@@ -791,6 +791,32 @@ cache_type_prefix(Dwarf_Die* type)
   return "";
 }
 
+/* GCC might generate a struct/class without DW_AT_declaration,
+   but that only contains members which have DW_AT_declaration
+   set.  We aren't interested in those.  PR14434 (GCC bug #54181).  */
+static bool
+has_only_decl_members (Dwarf_Die *die)
+{
+  Dwarf_Die child;
+  if (dwarf_child(die, &child) != 0)
+    return false; /* no members */
+
+  do
+    {
+      if (! dwarf_hasattr(&child, DW_AT_declaration))
+       return false; /* real member found.  */
+      int tag = dwarf_tag(&child);
+      if ((tag == DW_TAG_namespace
+           || tag == DW_TAG_structure_type
+           || tag == DW_TAG_class_type)
+          && ! has_only_decl_members (&child))
+       return false; /* real grand child member found.  */
+    }
+  while (dwarf_siblingof(&child, &child) == 0);
+
+  return true; /* Tried all children and grandchildren. */
+}
+
 int
 dwflpp::global_alias_caching_callback(Dwarf_Die *die, bool has_inner_types,
                                       const string& prefix, void *arg)
@@ -798,7 +824,8 @@ dwflpp::global_alias_caching_callback(Dwarf_Die *die, bool has_inner_types,
   cu_type_cache_t *cache = static_cast<cu_type_cache_t*>(arg);
   const char *name = dwarf_diename(die);
 
-  if (!name || dwarf_hasattr(die, DW_AT_declaration))
+  if (!name || dwarf_hasattr(die, DW_AT_declaration)
+      || has_only_decl_members(die))
     return DWARF_CB_OK;
 
   int tag = dwarf_tag(die);
diff --git a/testsuite/systemtap.base/partial-class-type-heap.cxx b/testsuite/systemtap.base/partial-class-type-heap.cxx
new file mode 100644 (file)
index 0000000..300319d
--- /dev/null
@@ -0,0 +1,20 @@
+#include "partial-class-type.hxx"
+
+size_t
+Heap::header_size ()
+{
+  return 42;
+}
+
+Heap::Heap()
+{
+  _size = header_size () + 32;
+  _memory = (char *) malloc (_size);
+}
+
+void*
+Heap::allocate(size_t size)
+{
+  _size += size;
+  return _memory + header_size();
+}
diff --git a/testsuite/systemtap.base/partial-class-type-main.cxx b/testsuite/systemtap.base/partial-class-type-main.cxx
new file mode 100644 (file)
index 0000000..ecee9c9
--- /dev/null
@@ -0,0 +1,12 @@
+#include "partial-class-type.hxx"
+
+int size (int resize)
+{
+  return (int)Heap::header_size() - resize;
+}
+
+int
+main (int argc, char **argv)
+{
+  return size (argc);
+}
diff --git a/testsuite/systemtap.base/partial-class-type.exp b/testsuite/systemtap.base/partial-class-type.exp
new file mode 100644 (file)
index 0000000..034a3f3
--- /dev/null
@@ -0,0 +1,33 @@
+set test "partial-class-type"
+
+# PR14434 dwflpp sometimes caches incomplete class_type
+
+proc error_handler { res message } {
+  global verbose test
+  if { $res == 0 } {
+    verbose $message 2
+    fail "$test $message"
+    return 1
+  } else {
+    pass "$test $message"
+    return 0
+  }
+}
+
+set srcpath "$srcdir/$subdir"
+set res [target_compile $srcpath/partial-class-type-heap.cxx "partial-class-type-heap.o" object "additional_flags=-g additional_flags=-O2"]
+if { [error_handler [expr {$res==""}] "partial-class-type-heap.cxx"] } { return }
+
+set res [target_compile $srcpath/partial-class-type-main.cxx "partial-class-type-main.o" object "additional_flags=-g additional_flags=-O2"]
+if { [error_handler [expr {$res==""}] "partial-class-type-main.cxx"] } { return }
+
+set res [target_compile "partial-class-type-main.o partial-class-type-heap.o" "partial-class-type" executable "additional_flags=-g additional_flags=-O2"]
+if { [error_handler [expr {$res==""}] "partial-class-type"] } { return }
+
+set script {"probe process(\"./partial-class-type\").function(\"main\") { printf(\"_size member offset: %d\\n\", &@cast(0, \"Heap\")->_size); }"}
+
+# Try compiling a couple of times, to make sure we always pick the right DIE.
+# See PR14434 for the non-determinism.
+for {set i 0} {$i < 7} {incr i} {
+  stap_compile $test-$i 1 $script -p2
+}
diff --git a/testsuite/systemtap.base/partial-class-type.hxx b/testsuite/systemtap.base/partial-class-type.hxx
new file mode 100644 (file)
index 0000000..04a2c21
--- /dev/null
@@ -0,0 +1,12 @@
+#include <malloc.h>
+
+class Heap
+{
+  private:
+    char *_memory;
+    size_t _size;
+  public:
+    Heap();
+    void* allocate  (size_t size);
+    static size_t header_size();
+};
This page took 0.036211 seconds and 5 git commands to generate.