From: Mark Wielaard Date: Mon, 6 Aug 2012 18:31:20 +0000 (+0200) Subject: PR14434 Filter out partial structs/classes. X-Git-Tag: release-2.0~207 X-Git-Url: https://sourceware.org/git/?a=commitdiff_plain;h=87eeec9407f8afa5af1037600272eebf0561e1d1;p=systemtap.git PR14434 Filter out partial structs/classes. 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. --- diff --git a/dwflpp.cxx b/dwflpp.cxx index 3fb50b293..ea93469f3 100644 --- a/dwflpp.cxx +++ b/dwflpp.cxx @@ -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(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 index 000000000..300319df6 --- /dev/null +++ b/testsuite/systemtap.base/partial-class-type-heap.cxx @@ -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 index 000000000..ecee9c9c9 --- /dev/null +++ b/testsuite/systemtap.base/partial-class-type-main.cxx @@ -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 index 000000000..034a3f379 --- /dev/null +++ b/testsuite/systemtap.base/partial-class-type.exp @@ -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 index 000000000..04a2c2166 --- /dev/null +++ b/testsuite/systemtap.base/partial-class-type.hxx @@ -0,0 +1,12 @@ +#include + +class Heap +{ + private: + char *_memory; + size_t _size; + public: + Heap(); + void* allocate (size_t size); + static size_t header_size(); +};