dwarf-reader, ir: Add member fns to exported corpus fns after c14n

There are cases where a member function C::f has a defined & exported
ELF symbol in a translation unit TU-2, whereas it has no associated
symbol in another translation unit TU-1.

The class C from TU-1 and the class C from TU-2 have the same
canonical type because they are equivalent.  Now, suppose it's C from
TU-2 that is the canonical type; that means the canonical type of C
from TU-1 is C from TU-2.

Today, the only types that are emitted in an ABIXML file are canonical
types.  So if we want the C::f which has a publicly defined & exported
elf symbol to be emitted in the ABIXML file, then the C::f that is
defined & exported in the ABI corpus should be the C::f from the
canonical class type C i.e, the C::f from TU-2.

In other words, the exported C::f should be the member function of the
canonical type class C.

That means that determining which C::f to export in the ABI corpus
should be done *after* type canonicalization.

Today however, determining which C::f to export is done during the
construction of the IR, in the DWARF reader.  That leads to
cases where the exported C::f is the one that has no defined &
exported ELF symbol.  As virtual member functions (in particular) are
involved in class type comparison, that could lead to spurious type
changes left and right.  Oops.

This patch implements the export of member functions after type
canonicalization in the DWARF reader.  Note that CTF and BTF readers
are not impacted as they only support the C language which doesn't
have member functions.

	* src/abg-dwarf-reader.cc
	(reader::fixup_functions_with_no_symbols): Do not export the
	virtual member function here.
	(build_ir_node_from_die): For DW_TAG_subprogram DIEs, likewise.
	* src/abg-ir.cc (maybe_adjust_canonical_type): Walk the member
	functions of the canonical type and export them in the ABI corpus
	if they have a defined and exported elf symbol.
	* tests/data/test-read-dwarf/test9-pr18818-clang.so.abi: Adjust.

Signed-off-by: Dodji Seketeli <dodji@redhat.com>
This commit is contained in:
Dodji Seketeli 2024-02-27 16:45:28 +01:00
parent bdce453d8c
commit 202820ea7a
3 changed files with 45 additions and 16 deletions

View File

@ -4552,12 +4552,7 @@ public:
ABG_ASSERT(is_member_function(i->second));
ABG_ASSERT(get_member_function_is_virtual(i->second));
i->second->set_symbol(sym);
// The function_decl now has an associated (public) ELF symbol so
// it ought to be advertised as being public.
i->second->set_is_in_public_symbol_table(true);
// Add the function to the set of exported decls of the
// current corpus.
maybe_add_fn_to_exported_decls(i->second.get());
if (do_log())
cerr << "fixed up '"
<< i->second->get_pretty_representation()
@ -16016,7 +16011,13 @@ build_ir_node_from_die(reader& rdr,
if (fn)
{
rdr.maybe_add_fn_to_exported_decls(fn.get());
if (!is_member_function(fn)
|| !get_member_function_is_virtual(fn))
// Virtual member functions are added to the set of
// functions exported by the current ABI corpus *after*
// the canonicalization of their parent type. So let's
// not do it here.
rdr.maybe_add_fn_to_exported_decls(fn.get());
rdr.associate_die_to_decl(die, fn, where_offset,
/*associate_by_repr=*/false);
maybe_canonicalize_type(fn->get_type(), rdr);

View File

@ -15649,18 +15649,15 @@ static void
maybe_adjust_canonical_type(const type_base_sptr& canonical,
const type_base_sptr& type)
{
if (!canonical
// If 'type' is *NOT* a newly canonicalized type ...
|| type->get_naked_canonical_type()
// ... or if 'type' is it's own canonical type, then get out.
|| type.get() == canonical.get())
if (type->get_naked_canonical_type())
return;
class_decl_sptr canonical_class = is_class_type(canonical);
if (class_decl_sptr cl = is_class_type(type))
{
class_decl_sptr canonical_class = is_class_type(canonical);
if (canonical_class)
if (canonical_class
&& canonical_class.get() != cl.get())
{
// Set symbols of member functions that might be missing
// theirs.
@ -15695,6 +15692,37 @@ maybe_adjust_canonical_type(const type_base_sptr& canonical,
}
}
// Make sure the virtual member functions with exported symbols are
// all added to the set of exported functions of the corpus.
// If we are looking at a non-canonicalized class (for instance, a
// decl-only class that has virtual member functoins), let's pretend
// it does have a canonical class so that we can perform the
// necessary virtual member function adjustments
if (class_decl_sptr cl = is_class_type(type))
if (is_non_canonicalized_type(cl))
{
ABG_ASSERT(!canonical_class);
canonical_class = cl;
}
if (canonical_class)
{
if (auto abi_corpus = canonical_class->get_corpus())
{
for (auto& fn : canonical_class->get_member_functions())
{
if (elf_symbol_sptr sym = fn->get_symbol())
if (sym->is_defined() && sym->is_public())
{
fn->set_is_in_public_symbol_table(true);
auto b = abi_corpus->get_exported_decls_builder();
b->maybe_add_fn_to_exported_fns(fn.get());
}
}
}
}
// If an artificial function type equals a non-artfificial one in
// the system, then the canonical type of both should be deemed
// non-artificial. This is important because only non-artificial

View File

@ -4810,7 +4810,7 @@
</function-decl>
</member-function>
<member-function access='public' destructor='yes' vtable-offset='0'>
<function-decl name='~system_error' mangled-name='_ZN5boost6system12system_errorD2Ev' filepath='src/third_party/boost-1.56.0/boost/system/system_error.hpp' line='47' column='1' visibility='default' binding='global' size-in-bits='64'>
<function-decl name='~system_error' mangled-name='_ZN5boost6system12system_errorD2Ev' filepath='src/third_party/boost-1.56.0/boost/system/system_error.hpp' line='47' column='1' visibility='default' binding='global' size-in-bits='64' elf-symbol-id='_ZN5boost6system12system_errorD2Ev'>
<parameter type-id='type-id-206' is-artificial='yes'/>
<return type-id='type-id-118'/>
</function-decl>