Yet another fix to the DWARF method "static-ness" detection heuristic

* include/abg-fwd.h (is_pointer, is_qualified_type): Declare new
	functions.
	* src/abg-ir.cc (is_pointer, is_qualified_type): Implement these
	new functions.
	* src/abg-dwarf-reader.cc (finish_member_function_reading):
	Sometimes, the this pointer of a non-static method can point to a
	*qualified* version of its containing type.  I am seeing that when
	comparing libstdc++.so from RHEL 6.5 and RHEL 7.  Take that in
	account when trying to detect that the first parameter of a member
	function is the this pointer, and thus detect that the function is
	a non static member function.
	* tests/data/test-read-dwarf/test8-qualified-this-pointer.so.abi:
	New test input.
	* tests/data/test-read-dwarf/test8-qualified-this-pointer.so: New
	test input.
	* tests/data/test-read-dwarf/test8-qualified-this-pointer.cc:
	Source code of new test input.
	* tests/test-read-dwarf.cc: Update copyright year.
	(in_out_spec): Add the new test inputs to this array, so that this
	test harness runs on them.
	* tests/Makefile.am: Add the new test inputs to the source
	distribution.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2014-10-16 23:32:08 +02:00
parent 06db1895ff
commit 70cb9ba1ae
8 changed files with 104 additions and 13 deletions

View File

@ -194,6 +194,12 @@ is_class_type(const shared_ptr<type_base>);
shared_ptr<class_decl>
is_class_type(const shared_ptr<decl_base>);
shared_ptr<pointer_type_def>
is_pointer(const shared_ptr<type_base>);
shared_ptr<qualified_type_def>
is_qualified_type(const shared_ptr<type_base>);
shared_ptr<class_decl>
look_through_decl_only_class(shared_ptr<class_decl>);

View File

@ -4908,12 +4908,11 @@ finish_member_function_reading(Dwarf_Die* die,
die_access_specifier(die, access);
bool is_static = false;
{
// Let's see if the first parameter has the same class
// type as the current class has a DW_AT_artificial
// attribute flag set. We are not looking at
// DW_AT_object_pointer (for DWARF 3) because it
// wasn't being emitted in GCC 4_4, which was already
// DWARF 3.
// Let's see if the first parameter is a pointer to an instance of
// the same class type as the current class and has a
// DW_AT_artificial attribute flag set. We are not looking at
// DW_AT_object_pointer (for DWARF 3) because it wasn't being
// emitted in GCC 4_4, which was already DWARF 3.
function_decl::parameter_sptr first_parm;
if (!f->get_parameters().empty())
first_parm = f->get_parameters()[0];
@ -4921,13 +4920,20 @@ finish_member_function_reading(Dwarf_Die* die,
bool is_artificial =
first_parm && first_parm->get_artificial();;
pointer_type_def_sptr this_ptr_type;
type_base_sptr other_klass;
if (is_artificial)
this_ptr_type =
dynamic_pointer_cast<pointer_type_def>
(first_parm->get_type());
if (this_ptr_type && (get_pretty_representation
(this_ptr_type->get_pointed_to_type())
== klass->get_pretty_representation()))
this_ptr_type = is_pointer(first_parm->get_type());
if (this_ptr_type)
other_klass = this_ptr_type->get_pointed_to_type();
// Sometimes, other_klass can be qualified; e.g, volatile. In
// that case, let's get the unqualified version of other_klass.
if (qualified_type_def_sptr q = is_qualified_type(other_klass))
other_klass = q->get_underlying_type();
if (other_klass
&& (ir::get_type_declaration(other_klass)->get_qualified_name()
== klass->get_qualified_name()))
;
else
is_static = true;

View File

@ -3033,6 +3033,26 @@ class_decl_sptr
is_class_type(const decl_base_sptr d)
{return is_class_type(is_type(d));}
/// Test whether a type is a pointer_type_def.
///
/// @param t the type to test.
///
/// @return the @ref pointer_type_def_sptr if @p t is a
/// pointer_type_def, null otherwise.
pointer_type_def_sptr
is_pointer(const type_base_sptr t)
{return dynamic_pointer_cast<pointer_type_def>(t);}
/// Test whether a type is a qualified_type_def.
///
/// @param t the type to test.
///
/// @return the @ref qualified_type_def_sptr if @p t is a
/// qualified_type_def, null otherwise.
qualified_type_def_sptr
is_qualified_type(const type_base_sptr t)
{return dynamic_pointer_cast<qualified_type_def>(t);}
/// If a class is a decl-only class, get its definition. Otherwise,
/// just return the initial class.
///

View File

@ -232,12 +232,22 @@ tests/data/test-read-dwarf/test2.so \
tests/data/test-read-dwarf/test2.so.abi \
tests/data/test-read-dwarf/test3.c \
tests/data/test-read-dwarf/test3.so \
tests/data/test-read-dwarf/test3.so.abi \
tests/data/test-read-dwarf/test4.c \
tests/data/test-read-dwarf/test4.so \
tests/data/test-read-dwarf/test4.so.abi \
tests/data/test-read-dwarf/test5.cc \
tests/data/test-read-dwarf/test5.so \
tests/data/test-read-dwarf/test5.so.abi \
tests/data/test-read-dwarf/test6.cc \
tests/data/test-read-dwarf/test6.so \
tests/data/test-read-dwarf/test6.so.abi \
tests/data/test-read-dwarf/test7.cc \
tests/data/test-read-dwarf/test7.so \
tests/data/test-read-dwarf/test7.so.abi \
tests/data/test-read-dwarf/test8-qualified-this-pointer.cc \
tests/data/test-read-dwarf/test8-qualified-this-pointer.so \
tests/data/test-read-dwarf/test8-qualified-this-pointer.so.abi \
\
data/test-diff-filter/test0-v0.cc \
data/test-diff-filter/test0-v1.cc \

View File

@ -0,0 +1,15 @@
struct S
{
int i;
S()
: i(0)
{}
int
foo() const;
};
int
S::foo() const
{return i;}

Binary file not shown.

View File

@ -0,0 +1,29 @@
<abi-corpus path='data/test-read-dwarf/test8-qualified-this-pointer.so'>
<elf-function-symbols>
<elf-symbol name='_ZNK1S3fooEv' type='func-type' binding='global-binding' is-defined='yes'/>
<elf-symbol name='_fini' type='func-type' binding='global-binding' is-defined='yes'/>
<elf-symbol name='_init' type='func-type' binding='global-binding' is-defined='yes'/>
</elf-function-symbols>
<abi-instr version='1.0' address-size='64' path='test8-qualified-this-pointer.cc'>
<class-decl name='S' size-in-bits='32' is-struct='yes' visibility='default' filepath='/home/dodji/git/libabigail/master/tests/data/test-read-dwarf/test8-qualified-this-pointer.cc' line='1' column='1' id='type-id-1'>
<data-member access='public' layout-offset-in-bits='0'>
<var-decl name='i' type-id='type-id-2' visibility='default' filepath='/home/dodji/git/libabigail/master/tests/data/test-read-dwarf/test8-qualified-this-pointer.cc' line='3' column='1'/>
</data-member>
<member-function access='public' constructor='yes'>
<function-decl name='S' filepath='/home/dodji/git/libabigail/master/tests/data/test-read-dwarf/test8-qualified-this-pointer.cc' line='5' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64'>
<parameter type-id='type-id-3' is-artificial='yes'/>
</function-decl>
</member-function>
<member-function access='public'>
<function-decl name='foo' mangled-name='_ZNK1S3fooEv' filepath='/home/dodji/git/libabigail/master/tests/data/test-read-dwarf/test8-qualified-this-pointer.cc' line='10' column='1' visibility='default' binding='global' size-in-bits='64' alignment-in-bits='64' elf-symbol-id='_ZNK1S3fooEv'>
<parameter type-id='type-id-4' is-artificial='yes'/>
<return type-id='type-id-2'/>
</function-decl>
</member-function>
</class-decl>
<type-decl name='int' size-in-bits='32' alignment-in-bits='32' id='type-id-2'/>
<pointer-type-def type-id='type-id-1' size-in-bits='64' alignment-in-bits='64' id='type-id-3'/>
<qualified-type-def type-id='type-id-1' const='yes' id='type-id-5'/>
<pointer-type-def type-id='type-id-5' size-in-bits='64' alignment-in-bits='64' id='type-id-4'/>
</abi-instr>
</abi-corpus>

View File

@ -1,6 +1,6 @@
// -*- Mode: C++ -*-
//
// Copyright (C) 2013 Red Hat, Inc.
// Copyright (C) 2013-2014 Red Hat, Inc.
//
// This file is part of the GNU Application Binary Interface Generic
// Analysis and Instrumentation Library (libabigail). This library is
@ -90,6 +90,11 @@ InOutSpec in_out_specs[] =
"data/test-read-dwarf/test7.so.abi",
"output/test-read-dwarf/test7.so.abi"
},
{
"data/test-read-dwarf/test8-qualified-this-pointer.so",
"data/test-read-dwarf/test8-qualified-this-pointer.so.abi",
"output/test-read-dwarf/test8-qualified-this-pointer.so.abi"
},
// This should be the last entry.
{NULL, NULL, NULL}
};