binutils-gdb/libctf/testsuite/config/default.exp
Nick Alcock 6bd2318f32 libctf: fix linking together multiple objects derived from the same source
Right now, if you compile the same .c input repeatedly with CTF enabled
and different compilation flags, then arrange to link all of these
together, then things misbehave in various ways.  libctf may conflate
either inputs (if the .o files have the same name, say if they are
stored in different .a archives), or per-CU outputs when conflicting
types are found: the latter can lead to entirely spurious errors when
it tries to produce multiple per-CU outputs with the same name
(discarding all but the last, but then looking for types in the earlier
ones which have just been thrown away).

Fixing this is multi-pronged.  Both inputs and outputs need to be
differentiated in the hashtables libctf keeps them in: inputs with the
same cuname and filename need to be considered distinct as long as they
have different associated CTF dicts, and per-CU outputs need to be
considered distinct as long as they have different associated input
dicts.  Right now there is nothing tying the two together other than the
CU name: fix this by introducing a new field in the ctf_dict_t named
ctf_link_in_out, which (for input dicts) points to the associated per-CU
output dict (if any), and for output dicts points to the associated
input dict.  At creation time the name used is completely arbitrary:
it's only important that it be distinct if CTF dicts are distinct.  So,
when a clash is found, adjust the CU name by sticking the number of
elements in the input on the end.  At output time, the CU name will
appear in the linked object, so it matters a little more that it look
slightly less ugly: in conflicting cases, append an incrementing
integer, starting at 0.

This naming scheme is not very helpful, but it's hard to see what else
we can do.  The input .o name may be the same.  The input .a name is not
even visible to ctf_link, and even *that* might be the same, because
.a's can contain many members with the same name, all of which
participate in the link.  All we really know is that the two have
distinct dictionaries with distinct types in them, and at least this way
they are all represented, any any symbols, variables etc referring to
those types are accurately stored.

(As a side-effect this also fixes a use-after-free and double-free when
errors are found during variable or symbol emission.)

Use the opportunity to prevent a couple of sources of problems, to wit
changing the active CU mappings when a link has already been done
(no effect on ld, which doesn't use CU mappings at all), and causing
multiple consecutive ctf_link's to have the same net effect as just
doing the last one (no effect on ld, which only ever does one
ctf_link) rather than having the links be a sort of half-incremental
not-really-intended mess.

libctf/ChangeLog:

	PR libctf/29242
	* ctf-impl.h (struct ctf_dict) [ctf_link_in_out]: New.
	* ctf-dedup.c (ctf_dedup_emit_type): Set it.
	* ctf-link.c (ctf_link_add_ctf_internal): Set the input
	CU name uniquely when clashes are found.
	(ctf_link_add): Document what repeated additions do.
	(ctf_new_per_cu_name): New, come up with a consistent
	name for a new per-CU dict.
	(ctf_link_deduplicating): Use it.
	(ctf_create_per_cu): Use it, and ctf_link_in_out, and set
	ctf_link_in_out properly.  Don't overwrite per-CU dicts with
	per-CU dicts relating to different inputs.
	(ctf_link_add_cu_mapping): Prevent per-CU mappings being set up
	if we already have per-CU outputs.
	(ctf_link_one_variable): Adjust ctf_link_per_cu call.
	(ctf_link_deduplicating_one_symtypetab): Likewise.
	(ctf_link_empty_outputs): New, delete all the ctf_link_outputs
	and blank out ctf_link_in_out on the corresponding inputs.
	(ctf_link): Clarify the effect of multiple ctf_link calls.
	Empty ctf_link_outputs if it already exists rather than
	having the old output leak into the new link.  Fix a variable
	name.
	* testsuite/config/default.exp (AR): Add.
	(OBJDUMP): Likewise.
	* testsuite/libctf-regression/libctf-repeat-cu.exp: New test.
	* testsuite/libctf-regression/libctf-repeat-cu*: Main program,
	library, and expected results for the test.
2022-06-21 19:27:15 +01:00

68 lines
2.1 KiB
Plaintext

# Basic expect script for libctf lookup tests
# Copyright (C) 1993-2022 Free Software Foundation, Inc.
#
# This file is part of the GNU Binutils.
#
# This file is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
# MA 02110-1301, USA.
#
# Written by Jeffrey Wheat (cassidy@cygnus.com)
#
if ![info exists ld] then {
set ld [findfile $base_dir/../ld/ld-new $base_dir/../ld/ld-new [transform ld]]
}
if ![info exists as] then {
set as [findfile $base_dir/../gas/as-new $base_dir/../gas/as-new [transform as]]
}
remote_exec host "mkdir -p tmpdir"
# Make symlinks from tmpdir/libctf to the linker and assembler in the
# build tree, so that we can use a -B option to gcc to force it to use
# the newly built linker and assembler.
if {![file isdirectory tmpdir/libctf]} then {
catch "exec mkdir tmpdir/libctf" status
catch "exec ln -s ../../../ld/ld-new tmpdir/libctf/ld" status
catch "exec ln -s ld tmpdir/libctf/collect-ld" status
catch "exec ln -s ../../../gas/as-new tmpdir/libctf/as" status
}
set gcc_B_opt "-B[pwd]/tmpdir/libctf/"
set ld_L_opt ""
if {![info exists CC]} {
set CC gcc
}
if {![info exists CFLAGS]} {
set CFLAGS "-g -O2"
}
if {![info exists CC_FOR_TARGET]} {
set CC_FOR_TARGET [find_gcc]
}
if {![info exists CFLAGS_FOR_TARGET]} {
set CFLAGS_FOR_TARGET $CFLAGS
}
if ![info exists AR] then {
set AR [findfile $base_dir/../binutils/ar]
}
if {![info exists OBJDUMP]} {
set OBJDUMP [findfile $base_dir/../binutils/objdump]
}
# load the utility procedures
load_lib ctf-lib.exp