From fdb4c2e02e6600b51f38a60cd70882887007cbdf Mon Sep 17 00:00:00 2001 From: Nick Alcock Date: Tue, 7 Nov 2023 21:11:18 +0000 Subject: libctf: adding CU mappings should be idempotent When CTF finds conflicting types, it usually shoves each definition into a CTF dictionary named after the compilation unit. The intent of the obscure "cu-mapped link" feature is to allow you to implement custom linkers that shove the definitions into other, more coarse-grained units (say, one per kernel module, even if a module consists of more than one compilation unit): conflicting types within one of these larger components are hidden from name lookup so you can only look up (an arbitrary one of) them by name, but can still be found by chasing type graph links and are still fully deduplicated. You do this by calling ctf_link_add_cu_mapping (fp, "CU name", "bigger lump name"), repeatedly, with different "CU name"s: the ctf_link() following that will put all conflicting types found in "CU name"s sharing a "bigger lump name" into a child dict in an archive member named "bigger lump name". So it's clear enough what happens if you call it repeatedly with the same "bigger lump name" more than once, because that's the whole point of it: but what if you call it with the same "CU name" repeatedly? ctf_link_add_cu_mapping (fp, "CU name", "bigger lump name"); ctf_link_add_cu_mapping (fp, "CU name", "other name"); This is meant to be the same as just doing the second of these, as if the first was never called. Alas, this isn't what happens, and what you get is instead a bit of an inconsistent mess: more or less, the first takes precedence, which is the exact opposite of what we wanted. Fix this to work the right way round. (I plan to add support for CU-mapped links to GNU ld, mainly so that we can properly *test* this machinery.) libctf/ChangeLog: * ctf-link.c (ctf_create_per_cu): Note the behaviour of repeatedly adding FROMs. (ctf_link_add_cu_mapping): Implement that behavour. --- libctf/ctf-link.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'libctf') diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index 27d11c9..ac33062 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -361,7 +361,8 @@ ctf_create_per_cu (ctf_dict_t *fp, ctf_dict_t *input, const char *cu_name) /* Add a mapping directing that the CU named FROM should have its conflicting/non-duplicate types (depending on link mode) go into a dict - named TO. Many FROMs can share a TO. + named TO. Many FROMs can share a TO, but adding the same FROM with + a different TO will replace the old mapping. 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 @@ -371,7 +372,7 @@ int ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to) { int err; - char *f = NULL, *t = NULL; + char *f = NULL, *t = NULL, *existing; ctf_dynhash_t *one_out; /* Mappings cannot be set up if per-CU output dicts already exist. */ @@ -393,6 +394,19 @@ ctf_link_add_cu_mapping (ctf_dict_t *fp, const char *from, const char *to) if (fp->ctf_link_out_cu_mapping == NULL) goto oom; + /* If this FROM already exists, remove the mapping from both the FROM->TO + and the TO->FROM lists: the user wants to change it. */ + + if ((existing = ctf_dynhash_lookup (fp->ctf_link_in_cu_mapping, from)) != NULL) + { + one_out = ctf_dynhash_lookup (fp->ctf_link_out_cu_mapping, existing); + if (!ctf_assert (fp, one_out)) + return -1; /* errno is set for us. */ + + ctf_dynhash_remove (one_out, from); + ctf_dynhash_remove (fp->ctf_link_in_cu_mapping, from); + } + f = strdup (from); t = strdup (to); if (!f || !t) -- cgit v1.1