libctf, link: redo cu-mapping handling

Now a bunch of stuff that doesn't apply to ld or any normal use of
libctf, piled into one commit so that it's easier to ignore.

The cu-mapping machinery associates incoming compilation unit names with
outgoing names of CTF dictionaries that should correspond to them, for
non-gdb CTF consumers that would like to group multiple TUs into a
single child dict if conflicting types are found in it (the existing use
case is one kernel module, one child CTF dict, even if the kernel module
is composed of multiple CUs).

The upcoming deduplicator needs to track not only the mapping from
incoming CU name to outgoing dict name, but the inverse mapping from
outgoing dict name to incoming CU name, so it can work over every CTF
dict we might see in the output and link into it.

So rejig the ctf-link machinery to do that.  Simultaneously (because
they are closely associated and were written at the same time), we add a
new CTF_LINK_EMPTY_CU_MAPPINGS flag to ctf_link, which tells the
ctf_link machinery to create empty child dicts for each outgoing CU
mapping even if no CUs that correspond to it exist in the link.  This is
a bit (OK, quite a lot) of a waste of space, but some existing consumers
require it.  (Nobody else should use it.)

Its value is not consecutive with existing CTF_LINK flag values because
we're about to add more flags that are conceptually closer to the
existing ones than this one is.

include/
	* ctf-api.h (CTF_LINK_EMPTY_CU_MAPPINGS): New.

libctf/
	* ctf-impl.h (ctf_file_t): Improve comments.
	<ctf_link_cu_mapping>: Split into...
	<ctf_link_in_cu_mapping>: ... this...
	<ctf_link_out_cu_mapping>: ... and this.
	* ctf-create.c (ctf_serialize): Adjust.
	* ctf-open.c (ctf_file_close): Likewise.
	* ctf-link.c (ctf_create_per_cu): Look things up in the
	in_cu_mapping instead of the cu_mapping.
	(ctf_link_add_cu_mapping): The deduplicating link will define
	what happens if many FROMs share a TO.
	(ctf_link_add_cu_mapping): Create in_cu_mapping and
	out_cu_mapping. Do not create ctf_link_outputs here any more, or
	create per-CU dicts here: they are already created when needed.
	(ctf_link_one_variable): Log a debug message if we skip a
	variable due to its type being concealed in a CU-mapped link.
	(This is probably too common a case to make into a warning.)
	(ctf_link): Create empty per-CU dicts if requested.
This commit is contained in:
Nick Alcock 2020-06-05 17:36:16 +01:00
parent e3f17159e2
commit 5f54462c6a
7 changed files with 136 additions and 33 deletions

View file

@ -296,10 +296,12 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname)
dictionary name. We prefer the filename because this is easier for likely
callers to determine. */
if (fp->ctf_link_cu_mapping)
if (fp->ctf_link_in_cu_mapping)
{
if (((ctf_name = ctf_dynhash_lookup (fp->ctf_link_cu_mapping, filename)) == NULL) &&
((ctf_name = ctf_dynhash_lookup (fp->ctf_link_cu_mapping, cuname)) == NULL))
if (((ctf_name = ctf_dynhash_lookup (fp->ctf_link_in_cu_mapping,
filename)) == NULL) &&
((ctf_name = ctf_dynhash_lookup (fp->ctf_link_in_cu_mapping,
cuname)) == NULL))
ctf_name = filename;
}
@ -339,10 +341,7 @@ ctf_create_per_cu (ctf_file_t *fp, const char *filename, const char *cuname)
/* Add a mapping directing that the CU named FROM should have its
conflicting/non-duplicate types (depending on link mode) go into a container
named TO. Many FROMs can share a TO: in this case, the effect on conflicting
types is not yet defined (but in time an auto-renaming algorithm will be
added: ugly, but there is really no right thing one can do in this
situation).
named TO. Many FROMs can share a TO.
We forcibly add a container named TO in every case, even though it may well
wind up empty, because clients that use this facility usually expect to find
@ -352,34 +351,63 @@ int
ctf_link_add_cu_mapping (ctf_file_t *fp, const char *from, const char *to)
{
int err;
char *f, *t;
char *f = NULL, *t = NULL;
ctf_dynhash_t *one_out;
if (fp->ctf_link_cu_mapping == NULL)
fp->ctf_link_cu_mapping = ctf_dynhash_create (ctf_hash_string,
ctf_hash_eq_string, free,
free);
if (fp->ctf_link_cu_mapping == NULL)
return ctf_set_errno (fp, ENOMEM);
if (fp->ctf_link_in_cu_mapping == NULL)
fp->ctf_link_in_cu_mapping = ctf_dynhash_create (ctf_hash_string,
ctf_hash_eq_string, free,
free);
if (fp->ctf_link_in_cu_mapping == NULL)
goto oom;
if (fp->ctf_link_outputs == NULL)
fp->ctf_link_outputs = ctf_dynhash_create (ctf_hash_string,
ctf_hash_eq_string, free,
(ctf_hash_free_fun)
ctf_file_close);
if (fp->ctf_link_outputs == NULL)
return ctf_set_errno (fp, ENOMEM);
if (fp->ctf_link_out_cu_mapping == NULL)
fp->ctf_link_out_cu_mapping = ctf_dynhash_create (ctf_hash_string,
ctf_hash_eq_string, free,
(ctf_hash_free_fun)
ctf_dynhash_destroy);
if (fp->ctf_link_out_cu_mapping == NULL)
goto oom;
f = strdup (from);
t = strdup (to);
if (!f || !t)
goto oom;
if (ctf_create_per_cu (fp, t, t) == NULL)
goto oom_noerrno; /* Errno is set for us. */
/* Track both in a list from FROM to TO and in a list from TO to a list of
FROM. The former is used to create TUs with the mapped-to name at need:
the latter is used in deduplicating links to pull in all input CUs
corresponding to a single output CU. */
err = ctf_dynhash_insert (fp->ctf_link_cu_mapping, f, t);
if (err)
if ((err = ctf_dynhash_insert (fp->ctf_link_in_cu_mapping, f, t)) < 0)
{
ctf_set_errno (fp, err);
goto oom_noerrno;
}
/* f and t are now owned by the in_cu_mapping: reallocate them. */
f = strdup (from);
t = strdup (to);
if (!f || !t)
goto oom;
if ((one_out = ctf_dynhash_lookup (fp->ctf_link_out_cu_mapping, t)) == NULL)
{
if ((one_out = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string,
free, NULL)) == NULL)
goto oom;
if ((err = ctf_dynhash_insert (fp->ctf_link_out_cu_mapping,
t, one_out)) < 0)
{
ctf_dynhash_destroy (one_out);
ctf_set_errno (fp, err);
goto oom_noerrno;
}
}
else
free (t);
if (ctf_dynhash_insert (one_out, f, NULL) < 0)
{
ctf_set_errno (fp, err);
goto oom_noerrno;
@ -777,6 +805,8 @@ int
ctf_link (ctf_file_t *fp, int flags)
{
ctf_link_in_member_cb_arg_t arg;
ctf_next_t *i = NULL;
int err;
memset (&arg, 0, sizeof (struct ctf_link_in_member_cb_arg));
arg.out_fp = fp;
@ -794,6 +824,33 @@ ctf_link (ctf_file_t *fp, int flags)
if (fp->ctf_link_outputs == NULL)
return ctf_set_errno (fp, ENOMEM);
/* Create empty CUs if requested. We do not currently claim that multiple
links in succession with CTF_LINK_EMPTY_CU_MAPPINGS set in some calls and
not set in others will do anything especially sensible. */
if (fp->ctf_link_out_cu_mapping && (flags & CTF_LINK_EMPTY_CU_MAPPINGS))
{
void *v;
while ((err = ctf_dynhash_next (fp->ctf_link_out_cu_mapping, &i, &v,
NULL)) == 0)
{
const char *to = (const char *) v;
if (ctf_create_per_cu (fp, to, to) == NULL)
{
ctf_next_destroy (i);
return -1; /* Errno is set for us. */
}
}
if (err != ECTF_NEXT_END)
{
ctf_err_warn (fp, 1, "Iteration error creating empty CUs: %s",
ctf_errmsg (err));
ctf_set_errno (fp, err);
return -1;
}
}
ctf_dynhash_iter (fp->ctf_link_inputs, ctf_link_one_input_archive,
&arg);