aboutsummaryrefslogtreecommitdiff
path: root/libctf
diff options
context:
space:
mode:
authorNick Alcock <nick.alcock@oracle.com>2025-04-25 20:49:26 +0100
committerNick Alcock <nick.alcock@oracle.com>2025-04-25 21:23:07 +0100
commit7bea1097ecb81cbd6fd95420798c979688acb33c (patch)
tree7618fb2b0c5d792d1b3ecd9e5cbaa923c50f4b1d /libctf
parentf38832b3985d6a91c5ca51d46f3e6ce468f188a0 (diff)
downloadbinutils-7bea1097ecb81cbd6fd95420798c979688acb33c.zip
binutils-7bea1097ecb81cbd6fd95420798c979688acb33c.tar.gz
binutils-7bea1097ecb81cbd6fd95420798c979688acb33c.tar.bz2
libctf: dedup: conflicting CU names and merging into the parent
The last two dedup changes are, firstly, to use ctf_add_conflicting() to arrange that conflicting types that are hidden because they are added to the same dict as the types they conflict with (e.g. conflicting types in modules) are properly marked with the CU name that the type comes from. This could of course not be done with the old non-root flag, but now that we have proper prefix types, we can record it, and consumers can find out what CU any type comes from via ctf_type_conflicting (or, for non-kernel CTF generated by GNU ld, via the ctf_cuname of the per-cu dict). Secondly, we add a new kind of CU mapping for cu-mapped (two-stage) links (as a reminder, these carry out a second stage of dedupping in which they squash specific CUs down to a named set of child dicts, fusing named inputs into particular named outputs: the kernel linker uses this to make child dicts that represent modules rather than translation units). You can now map any CU name to "" (the null string). This indicates that types that would land in the CU in question should not be emitted into any sort of per-module dict but should instead just be emitted into the shared dict, possibly being marked conflicting as they do so. The usual popcount mechanism will be used to pick the type which is left unhidden. The usual forwarding stubs you would expect to find for conflicting structs and unions will not be emitted: instead, real structs and unions will take their place. Consumers must take care when chasing parent types that point to tagged structs to make sure that there isn't a correspondingly-named struct in the child they're looking at (but this is generally a problem with type chasing in children anyway, which I have a TODO open to find some sort of solution to: this should be being done automatically, and isn't).
Diffstat (limited to 'libctf')
-rw-r--r--libctf/ctf-dedup.c21
-rw-r--r--libctf/ctf-link.c6
2 files changed, 22 insertions, 5 deletions
diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c
index 16048ab..66f9568 100644
--- a/libctf/ctf-dedup.c
+++ b/libctf/ctf-dedup.c
@@ -3263,6 +3263,7 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
int cu_mapped = *(int *)arg;
int isroot;
int is_conflicting;
+ int mark_type_conflicting = 0;
ctf_next_t *i = NULL;
ctf_id_t new_type;
@@ -3281,11 +3282,14 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
depth, hval, ctf_link_input_name (input));
/* Conflicting types go into a per-CU output dictionary, unless this is a
- CU-mapped run. The import is not refcounted, since it goes into the
- ctf_link_outputs dict of the output that is its parent. */
+ CU-mapped run or the input CU name is empty. The import is not refcounted,
+ since it goes into the ctf_link_outputs dict of the output that is its
+ parent. */
is_conflicting = ctf_dynset_exists (d->cd_conflicting_types, hval, NULL);
- if (is_conflicting && !cu_mapped)
+ if (is_conflicting && !cu_mapped
+ && (ctf_cuname (input) == NULL ||
+ strcmp (ctf_cuname (input), "") != 0))
{
ctf_dprintf ("%i: Type %s in %i/%lx is conflicted: "
"inserting into per-CU target.\n",
@@ -3340,7 +3344,10 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
name already exists and is not a forward, or if this type is hidden on the
input. */
if (cu_mapped && is_conflicting)
- isroot = 0;
+ {
+ mark_type_conflicting = 1;
+ isroot = 0;
+ }
else if (name
&& (maybe_dup = ctf_lookup_by_rawname (target, kind, name)) != 0)
{
@@ -3771,6 +3778,12 @@ ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
"target %p (%s)\n", depth, hval, input_num, type, new_type,
(void *) target, ctf_link_input_name (target));
+ /* If this type is meant to be marked conflicting in this dict rather than
+ moved into a child, mark it, and note which CU it came from. */
+ if (new_type != 0 && mark_type_conflicting)
+ if (ctf_set_conflicting (target, new_type, ctf_cuname (input)) < 0)
+ goto err_target;
+
return 0;
oom_hash:
diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c
index 1d73490..1377251 100644
--- a/libctf/ctf-link.c
+++ b/libctf/ctf-link.c
@@ -369,7 +369,11 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name)
We forcibly add a dict named TO in every case, even though it may well
wind up empty, because clients that use this facility usually expect to find
- every TO dict present, even if empty, and malfunction otherwise. */
+ every TO dict present, even if empty, and malfunction otherwise.
+
+ The TO mapping named "" is special: types in this are merged directly and
+ unconditionally into the shared parent dict, and are hidden (marked conflicting) if
+ they clash, rather than being moved into child dicts. */
int
ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to)