/* CTF type deduplication.
- Copyright (C) 2019 Free Software Foundation, Inc.
+ Copyright (C) 2019-2022 Free Software Foundation, Inc.
This file is part of libctf.
*global type ID* or 'GID', a pair of an array offset and a ctf_id_t. Since
both are already 32 bits or less or can easily be constrained to that range,
we can pack them both into a single 64-bit hash word for easy lookups, which
- would be much more annoying to do with a ctf_file_t * and a ctf_id_t. (On
+ would be much more annoying to do with a ctf_dict_t * and a ctf_id_t. (On
32-bit platforms, we must do that anyway, since pointers, and thus hash keys
and values, are only 32 bits wide). We track which inputs are parents of
which other inputs so that we can correctly recognize that types we have
approach, but with a smaller key, this is all we can do. */
static void *
-id_to_packed_id (ctf_file_t *fp, int input_num, ctf_id_t type)
+id_to_packed_id (ctf_dict_t *fp, int input_num, ctf_id_t type)
{
const void *lookup;
ctf_type_id_key_t *dynkey = NULL;
ctf_type_id_key_t key = { input_num, type };
- if (!ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_file_t,
+ if (!ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_dict_t,
&key, &lookup, NULL))
{
if ((dynkey = malloc (sizeof (ctf_type_id_key_t))) == NULL)
goto oom;
memcpy (dynkey, &key, sizeof (ctf_type_id_key_t));
- if (ctf_dynhash_insert (fp->ctf_dedup.cd_id_to_file_t, dynkey, NULL) < 0)
+ if (ctf_dynhash_insert (fp->ctf_dedup.cd_id_to_dict_t, dynkey, NULL) < 0)
goto oom;
- ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_file_t,
+ ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_id_to_dict_t,
dynkey, &lookup, NULL);
}
/* We use a raw assert() here because there isn't really a way to get any sort
if ((element = ctf_dynhash_lookup (set, key)) == NULL)
{
if ((element = ctf_dynset_create (htab_hash_string,
- ctf_dynset_eq_string,
+ htab_eq_string,
NULL)) == NULL)
return NULL;
/* Initialize the dedup atoms table. */
int
-ctf_dedup_atoms_init (ctf_file_t *fp)
+ctf_dedup_atoms_init (ctf_dict_t *fp)
{
if (fp->ctf_dedup_atoms)
return 0;
if (!fp->ctf_dedup_atoms_alloc)
{
if ((fp->ctf_dedup_atoms_alloc
- = ctf_dynset_create (htab_hash_string, ctf_dynset_eq_string,
+ = ctf_dynset_create (htab_hash_string, htab_eq_string,
free)) == NULL)
return ctf_set_errno (fp, ENOMEM);
}
/* Intern things in the dedup atoms table. */
static const char *
-intern (ctf_file_t *fp, char *atom)
+intern (ctf_dict_t *fp, char *atom)
{
const void *foo;
while allowing for the four C namespaces (normal, struct, union, enum).
Return a new dynamically-allocated string. */
static const char *
-ctf_decorate_type_name (ctf_file_t *fp, const char *name, int kind)
+ctf_decorate_type_name (ctf_dict_t *fp, const char *name, int kind)
{
ctf_dedup_t *d = &fp->ctf_dedup;
const char *ret;
}
static const char *
-ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
- ctf_file_t **inputs, uint32_t *parents,
+ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
+ ctf_dict_t **inputs, uint32_t *parents,
int input_num, ctf_id_t type, int flags,
unsigned long depth,
- int (*populate_fun) (ctf_file_t *fp,
- ctf_file_t *input,
- ctf_file_t **inputs,
+ int (*populate_fun) (ctf_dict_t *fp,
+ ctf_dict_t *input,
+ ctf_dict_t **inputs,
int input_num,
ctf_id_t type,
void *id,
Only called for forwards or forwardable types with names, when the link mode
is CTF_LINK_SHARE_DUPLICATED. */
static int
-ctf_dedup_record_origin (ctf_file_t *fp, int input_num, const char *decorated,
+ctf_dedup_record_origin (ctf_dict_t *fp, int input_num, const char *decorated,
void *id)
{
ctf_dedup_t *d = &fp->ctf_dedup;
calls, recursively). */
static const char *
-ctf_dedup_rhash_type (ctf_file_t *fp, ctf_file_t *input, ctf_file_t **inputs,
+ctf_dedup_rhash_type (ctf_dict_t *fp, ctf_dict_t *input, ctf_dict_t **inputs,
uint32_t *parents, int input_num, ctf_id_t type,
void *type_id, const ctf_type_t *tp, const char *name,
const char *decorated, int kind, int flags,
unsigned long depth,
- int (*populate_fun) (ctf_file_t *fp,
- ctf_file_t *input,
- ctf_file_t **inputs,
+ int (*populate_fun) (ctf_dict_t *fp,
+ ctf_dict_t *input,
+ ctf_dict_t **inputs,
int input_num,
ctf_id_t type,
void *id,
char hashbuf[CTF_SHA1_SIZE];
const char *hval = NULL;
const char *whaterr;
- int err;
+ int err = 0;
const char *citer = NULL;
ctf_dynset_t *citers = NULL;
whaterr = N_("error updating citers"); \
if (!citers) \
if ((citers = ctf_dynset_create (htab_hash_string, \
- ctf_dynset_eq_string, \
- NULL)) == NULL) \
+ htab_eq_string, \
+ NULL)) == NULL) \
goto oom; \
if (ctf_dynset_cinsert (citers, hval) < 0) \
goto oom; \
- } while (0)
+ } \
+ while (0)
/* If this is a named struct or union or a forward to one, and this is a child
traversal, treat this type as if it were a forward -- do not recurse to
&& ctf_dedup_record_origin (fp, input_num, decorated, type_id) < 0)
return NULL; /* errno is set for us. */
+#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
+ ctf_dprintf ("%lu: hashing thing with ID %i/%lx (kind %i): %s.\n",
+ depth, input_num, type, kind, name ? name : "");
+#endif
+
+ /* Some type kinds don't have names: the API provides no way to set the name,
+ so the type the deduplicator outputs will be nameless even if the input
+ somehow has a name, and the name should not be mixed into the hash. */
+
+ switch (kind)
+ {
+ case CTF_K_POINTER:
+ case CTF_K_ARRAY:
+ case CTF_K_FUNCTION:
+ case CTF_K_VOLATILE:
+ case CTF_K_CONST:
+ case CTF_K_RESTRICT:
+ case CTF_K_SLICE:
+ name = NULL;
+ }
+
/* Mix in invariant stuff, transforming the type kind if needed. Note that
the vlen is *not* hashed in: the actual variable-length info is hashed in
instead, piecewise. The vlen is not part of the type, only the
*other types in the same TU* with the same name: so two types can easily
have distinct nonroot flags, yet be exactly the same type.*/
-#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
- ctf_dprintf ("%lu: hashing thing with ID %i/%lx (kind %i): %s.\n",
- depth, input_num, type, kind, name ? name : "");
-#endif
-
ctf_sha1_init (&hash);
if (name)
ctf_dedup_sha1_add (&hash, name, strlen (name) + 1, "name", depth);
if (ctf_type_encoding (input, type, &ep) < 0)
{
whaterr = N_("error getting encoding");
- goto err;
+ goto input_err;
}
ctf_dedup_sha1_add (&hash, &ep, sizeof (ctf_encoding_t), "encoding",
depth);
citer = hval;
if ((dtd = ctf_dynamic_type (input, type)) != NULL)
- slice = &dtd->dtd_u.dtu_slice;
+ slice = (ctf_slice_t *) dtd->dtd_vlen;
else
slice = (ctf_slice_t *) ((uintptr_t) tp + increment);
if (ctf_array_info (input, type, &ar) < 0)
{
whaterr = N_("error getting array info");
- goto err;
+ goto input_err;
}
if ((hval = ctf_dedup_hash_type (fp, input, inputs, parents, input_num,
if (ctf_func_type_info (input, type, &fi) < 0)
{
whaterr = N_("error getting func type info");
- goto err;
+ goto input_err;
}
if ((hval = ctf_dedup_hash_type (fp, input, inputs, parents, input_num,
if ((args = calloc (fi.ctc_argc, sizeof (ctf_id_t))) == NULL)
{
+ err = ENOMEM;
whaterr = N_("error doing memory allocation");
goto err;
}
{
free (args);
whaterr = N_("error getting func arg type");
- goto err;
+ goto input_err;
}
for (j = 0; j < fi.ctc_argc; j++)
{
if (ctf_errno (input) != ECTF_NEXT_END)
{
whaterr = N_("error doing enum member iteration");
- goto err;
+ goto input_err;
}
break;
}
ctf_dedup_sha1_add (&hash, &size, sizeof (ssize_t), "struct size",
depth);
- while ((offset = ctf_member_next (input, type, &i, &mname,
- &membtype)) >= 0)
+ while ((offset = ctf_member_next (input, type, &i, &mname, &membtype,
+ 0)) >= 0)
{
if (mname == NULL)
mname = "";
if (ctf_errno (input) != ECTF_NEXT_END)
{
whaterr = N_("error doing struct/union member iteration");
- goto err;
+ goto input_err;
}
break;
}
iterr:
ctf_next_destroy (i);
+ input_err:
+ err = ctf_errno (input);
err:
ctf_sha1_fini (&hash, NULL);
- ctf_err_warn (fp, 0, 0, _("%s (%i): %s: during type hashing for type %lx, "
- "kind %i"), ctf_link_input_name (input),
+ ctf_err_warn (fp, 0, err, _("%s (%i): %s: during type hashing for type %lx, "
+ "kind %i"), ctf_link_input_name (input),
input_num, gettext (whaterr), type, kind);
return NULL;
oom:
Returns a hash value (an atom), or NULL on error. */
static const char *
-ctf_dedup_hash_type (ctf_file_t *fp, ctf_file_t *input,
- ctf_file_t **inputs, uint32_t *parents,
+ctf_dedup_hash_type (ctf_dict_t *fp, ctf_dict_t *input,
+ ctf_dict_t **inputs, uint32_t *parents,
int input_num, ctf_id_t type, int flags,
unsigned long depth,
- int (*populate_fun) (ctf_file_t *fp,
- ctf_file_t *input,
- ctf_file_t **inputs,
+ int (*populate_fun) (ctf_dict_t *fp,
+ ctf_dict_t *input,
+ ctf_dict_t **inputs,
int input_num,
ctf_id_t type,
void *id,
if (tp->ctt_name == 0 || !name || name[0] == '\0')
name = NULL;
- /* Treat the unknown kind just like the unimplemented type. */
- if (kind == CTF_K_UNKNOWN)
- return "00000000000000000000";
-
/* Decorate the name appropriately for the namespace it appears in: forwards
appear in the namespace of their referent. */
cd_output_first_tu mapping. */
static int
-ctf_dedup_populate_mappings (ctf_file_t *fp, ctf_file_t *input _libctf_unused_,
- ctf_file_t **inputs _libctf_unused_,
+ctf_dedup_populate_mappings (ctf_dict_t *fp, ctf_dict_t *input _libctf_unused_,
+ ctf_dict_t **inputs _libctf_unused_,
int input_num _libctf_unused_,
ctf_id_t type _libctf_unused_, void *id,
const char *decorated_name,
while ((err = ctf_dynset_cnext (type_ids, &i, &one_id)) == 0)
{
- ctf_file_t *foo = inputs[CTF_DEDUP_GID_TO_INPUT (one_id)];
+ ctf_dict_t *foo = inputs[CTF_DEDUP_GID_TO_INPUT (one_id)];
ctf_id_t bar = CTF_DEDUP_GID_TO_TYPE (one_id);
if (ctf_type_kind_unsliced (foo, bar) != orig_kind)
{
ctf_dedup_maybe_synthesize_forward.) */
static int
-ctf_dedup_mark_conflicting_hash (ctf_file_t *fp, const char *hval)
+ctf_dedup_mark_conflicting_hash (ctf_dict_t *fp, const char *hval)
{
ctf_dedup_t *d = &fp->ctf_dedup;
ctf_next_t *i = NULL;
/* Look up a type kind from the output mapping, given a type hash value. */
static int
-ctf_dedup_hash_kind (ctf_file_t *fp, ctf_file_t **inputs, const char *hash)
+ctf_dedup_hash_kind (ctf_dict_t *fp, ctf_dict_t **inputs, const char *hash)
{
ctf_dedup_t *d = &fp->ctf_dedup;
void *id;
/* Used to keep a count of types: i.e. distinct type hash values. */
typedef struct ctf_dedup_type_counter
{
- ctf_file_t *fp;
- ctf_file_t **inputs;
+ ctf_dict_t *fp;
+ ctf_dict_t **inputs;
int num_non_forwards;
} ctf_dedup_type_counter_t;
/* Detect name ambiguity and mark ambiguous names as conflicting, other than the
most common. */
static int
-ctf_dedup_detect_name_ambiguity (ctf_file_t *fp, ctf_file_t **inputs)
+ctf_dedup_detect_name_ambiguity (ctf_dict_t *fp, ctf_dict_t **inputs)
{
ctf_dedup_t *d = &fp->ctf_dedup;
ctf_next_t *i = NULL;
the most-popular type on insertion, and we want conflicting structs
et al to have all forwards left intact, so the user is notified
that this type is conflicting. TODO: improve this in future by
- setting such forwards non-root-visible.) */
+ setting such forwards non-root-visible.)
+
+ If multiple distinct types are "most common", pick the one that
+ appears first on the link line, and within that, the one with the
+ lowest type ID. (See sort_output_mapping.) */
const void *key;
const void *count;
const char *hval;
long max_hcount = -1;
+ void *max_gid = NULL;
const char *max_hval = NULL;
if (ctf_dynhash_elements (name_counts) <= 1)
while ((err = ctf_dynhash_cnext (name_counts, &j, &key, &count)) == 0)
{
hval = (const char *) key;
+
if ((long int) (uintptr_t) count > max_hcount)
{
max_hcount = (long int) (uintptr_t) count;
max_hval = hval;
+ max_gid = ctf_dynhash_lookup (d->cd_output_first_gid, hval);
+ }
+ else if ((long int) (uintptr_t) count == max_hcount)
+ {
+ void *gid = ctf_dynhash_lookup (d->cd_output_first_gid, hval);
+
+ if (CTF_DEDUP_GID_TO_INPUT(gid) < CTF_DEDUP_GID_TO_INPUT(max_gid)
+ || (CTF_DEDUP_GID_TO_INPUT(gid) == CTF_DEDUP_GID_TO_INPUT(max_gid)
+ && CTF_DEDUP_GID_TO_TYPE(gid) < CTF_DEDUP_GID_TO_TYPE(max_gid)))
+ {
+ max_hval = hval;
+ max_gid = ctf_dynhash_lookup (d->cd_output_first_gid, hval);
+ }
}
}
if (err != ECTF_NEXT_END)
/* Initialize the deduplication machinery. */
static int
-ctf_dedup_init (ctf_file_t *fp)
+ctf_dedup_init (ctf_dict_t *fp)
{
ctf_dedup_t *d = &fp->ctf_dedup;
size_t i;
goto oom;
#if IDS_NEED_ALLOCATION
- if ((d->cd_id_to_file_t = ctf_dynhash_create (ctf_hash_type_id_key,
+ if ((d->cd_id_to_dict_t = ctf_dynhash_create (ctf_hash_type_id_key,
ctf_hash_eq_type_id_key,
free, NULL)) == NULL)
goto oom;
goto oom;
#endif
+ if ((d->cd_input_nums
+ = ctf_dynhash_create (ctf_hash_integer,
+ ctf_hash_eq_integer,
+ NULL, NULL)) == NULL)
+ goto oom;
+
if ((d->cd_emission_struct_members
= ctf_dynhash_create (ctf_hash_integer,
ctf_hash_eq_integer,
if ((d->cd_conflicting_types
= ctf_dynset_create (htab_hash_string,
- ctf_dynset_eq_string, NULL)) == NULL)
+ htab_eq_string, NULL)) == NULL)
goto oom;
return 0;
return ctf_set_errno (fp, ENOMEM);
}
+/* No ctf_dedup calls are allowed after this call other than starting a new
+ deduplication via ctf_dedup (not even ctf_dedup_type_mapping lookups). */
void
-ctf_dedup_fini (ctf_file_t *fp, ctf_file_t **outputs, uint32_t noutputs)
+ctf_dedup_fini (ctf_dict_t *fp, ctf_dict_t **outputs, uint32_t noutputs)
{
ctf_dedup_t *d = &fp->ctf_dedup;
size_t i;
/* ctf_dedup_atoms is kept across links. */
#if IDS_NEED_ALLOCATION
- ctf_dynhash_destroy (d->cd_id_to_file_t);
+ ctf_dynhash_destroy (d->cd_id_to_dict_t);
#endif
for (i = 0; i < 4; i++)
ctf_dynhash_destroy (d->cd_decorated_names[i]);
#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
ctf_dynhash_destroy (d->cd_output_mapping_guard);
#endif
+ ctf_dynhash_destroy (d->cd_input_nums);
ctf_dynhash_destroy (d->cd_emission_struct_members);
ctf_dynset_destroy (d->cd_conflicting_types);
ctf_dedup_t *od = &outputs[i]->ctf_dedup;
ctf_dynhash_destroy (od->cd_output_emission_hashes);
ctf_dynhash_destroy (od->cd_output_emission_conflicted_forwards);
- ctf_file_close (od->cd_output);
+ ctf_dict_close (od->cd_output);
}
}
memset (d, 0, sizeof (ctf_dedup_t));
/* Return 1 if this type is cited by multiple input dictionaries. */
static int
-ctf_dedup_multiple_input_dicts (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_multiple_input_dicts (ctf_dict_t *output, ctf_dict_t **inputs,
const char *hval)
{
ctf_dedup_t *d = &output->ctf_dedup;
ctf_dynset_t *type_ids;
ctf_next_t *i = NULL;
void *id;
- ctf_file_t *found = NULL, *relative_found = NULL;
+ ctf_dict_t *found = NULL, *relative_found = NULL;
const char *type_id;
- ctf_file_t *input_fp;
+ ctf_dict_t *input_fp;
ctf_id_t input_id;
const char *name;
const char *decorated;
while ((err = ctf_dynset_next (type_ids, &i, &id)) == 0)
{
- ctf_file_t *fp = inputs[CTF_DEDUP_GID_TO_INPUT (id)];
+ ctf_dict_t *fp = inputs[CTF_DEDUP_GID_TO_INPUT (id)];
if (fp == found || fp == relative_found)
continue;
name = ctf_type_name_raw (input_fp, input_id);
if ((fwdkind == CTF_K_STRUCT || fwdkind == CTF_K_UNION)
- && name && name[0] != '\0')
+ && name[0] != '\0')
{
const void *origin;
types. Only used if the link mode is CTF_LINK_SHARE_DUPLICATED. */
static int
-ctf_dedup_conflictify_unshared (ctf_file_t *output, ctf_file_t **inputs)
+ctf_dedup_conflictify_unshared (ctf_dict_t *output, ctf_dict_t **inputs)
{
ctf_dedup_t *d = &output->ctf_dedup;
ctf_next_t *i = NULL;
const void *k;
ctf_dynset_t *to_mark = NULL;
- if ((to_mark = ctf_dynset_create (htab_hash_string, ctf_dynset_eq_string,
+ if ((to_mark = ctf_dynset_create (htab_hash_string, htab_eq_string,
NULL)) == NULL)
goto err_no;
ctf_dedup_emit afterwards to do that. */
int
-ctf_dedup (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
+ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
uint32_t *parents, int cu_mapped)
{
ctf_dedup_t *d = &output->ctf_dedup;
size_t i;
ctf_next_t *it = NULL;
- for (i = 0; i < ninputs; i++)
- ctf_dprintf ("Input %i: %s\n", (int) i, ctf_link_input_name (inputs[i]));
-
if (ctf_dedup_init (output) < 0)
return -1; /* errno is set for us. */
+ for (i = 0; i < ninputs; i++)
+ {
+ ctf_dprintf ("Input %i: %s\n", (int) i, ctf_link_input_name (inputs[i]));
+ if (ctf_dynhash_insert (d->cd_input_nums, inputs[i],
+ (void *) (uintptr_t) i) < 0)
+ {
+ ctf_set_errno (output, errno);
+ ctf_err_warn (output, 0, errno, _("ctf_dedup: cannot initialize: %s\n"),
+ ctf_errmsg (errno));
+ goto err;
+ }
+ }
+
/* Some flags do not apply when CU-mapping: this is not a duplicated link,
because there is only one output and we really don't want to end up marking
all nonconflicting but appears-only-once types as conflicting (which in the
while ((id = ctf_type_next (inputs[i], &it, NULL, 1)) != CTF_ERR)
{
- ctf_dedup_hash_type (output, inputs[i], inputs, parents,
- i, id, 0, 0, ctf_dedup_populate_mappings);
+ if (ctf_dedup_hash_type (output, inputs[i], inputs,
+ parents, i, id, 0, 0,
+ ctf_dedup_populate_mappings) == NULL)
+ goto err; /* errno is set for us. */
}
if (ctf_errno (inputs[i]) != ECTF_NEXT_END)
{
ctf_set_errno (output, ctf_errno (inputs[i]));
ctf_err_warn (output, 0, 0, _("iteration failure "
"computing type hashes"));
- return -1;
+ goto err;
}
}
ctf_dprintf ("Detecting type name ambiguity\n");
if (ctf_dedup_detect_name_ambiguity (output, inputs) < 0)
- return -1; /* errno is set for us. */
+ goto err; /* errno is set for us. */
/* If the link mode is CTF_LINK_SHARE_DUPLICATED, we change any unconflicting
types whose output mapping references only one input dict into a
{
ctf_dprintf ("Conflictifying unshared types\n");
if (ctf_dedup_conflictify_unshared (output, inputs) < 0)
- return -1; /* errno is set for us. */
+ goto err; /* errno is set for us. */
}
return 0;
+
+ err:
+ ctf_dedup_fini (output, NULL, 0);
+ return -1;
}
static int
-ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
uint32_t ninputs, uint32_t *parents,
ctf_dynset_t *already_visited,
const char *hval,
int (*visit_fun) (const char *hval,
- ctf_file_t *output,
- ctf_file_t **inputs,
+ ctf_dict_t *output,
+ ctf_dict_t **inputs,
uint32_t ninputs,
uint32_t *parents,
int already_visited,
- ctf_file_t *input,
+ ctf_dict_t *input,
ctf_id_t type,
void *id,
int depth,
/* Like ctf_dedup_rwalk_output_mapping (which see), only takes a single target
type and visits it. */
static int
-ctf_dedup_rwalk_one_output_mapping (ctf_file_t *output,
- ctf_file_t **inputs, uint32_t ninputs,
+ctf_dedup_rwalk_one_output_mapping (ctf_dict_t *output,
+ ctf_dict_t **inputs, uint32_t ninputs,
uint32_t *parents,
ctf_dynset_t *already_visited,
int visited, void *type_id,
const char *hval,
int (*visit_fun) (const char *hval,
- ctf_file_t *output,
- ctf_file_t **inputs,
+ ctf_dict_t *output,
+ ctf_dict_t **inputs,
uint32_t ninputs,
uint32_t *parents,
int already_visited,
- ctf_file_t *input,
+ ctf_dict_t *input,
ctf_id_t type,
void *id,
int depth,
void *arg, unsigned long depth)
{
ctf_dedup_t *d = &output->ctf_dedup;
- ctf_file_t *fp;
+ ctf_dict_t *fp;
int input_num;
ctf_id_t type;
int ret;
times, which is worse. */
#define CTF_TYPE_WALK(type, errlabel, errmsg) \
- do { \
- void *type_id; \
- const char *hashval; \
- int cited_type_input_num = input_num; \
+ do \
+ { \
+ void *type_id; \
+ const char *hashval; \
+ int cited_type_input_num = input_num; \
\
- if ((fp->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (fp, type))) \
- cited_type_input_num = parents[input_num]; \
+ if ((fp->ctf_flags & LCTF_CHILD) && (LCTF_TYPE_ISPARENT (fp, type))) \
+ cited_type_input_num = parents[input_num]; \
\
- type_id = CTF_DEDUP_GID (output, cited_type_input_num, type); \
+ type_id = CTF_DEDUP_GID (output, cited_type_input_num, type); \
\
- if (type == 0) \
- { \
- ctf_dprintf ("Walking: unimplemented type\n"); \
- break; \
- } \
+ if (type == 0) \
+ { \
+ ctf_dprintf ("Walking: unimplemented type\n"); \
+ break; \
+ } \
\
- ctf_dprintf ("Looking up ID %i/%lx in type hashes\n", \
- cited_type_input_num, type); \
- hashval = ctf_dynhash_lookup (d->cd_type_hashes, type_id); \
- if (!ctf_assert (output, hashval)) \
- { \
- whaterr = N_("error looking up ID in type hashes"); \
- goto errlabel; \
- } \
- ctf_dprintf ("ID %i/%lx has hash %s\n", cited_type_input_num, type, \
- hashval); \
+ ctf_dprintf ("Looking up ID %i/%lx in type hashes\n", \
+ cited_type_input_num, type); \
+ hashval = ctf_dynhash_lookup (d->cd_type_hashes, type_id); \
+ if (!ctf_assert (output, hashval)) \
+ { \
+ whaterr = N_("error looking up ID in type hashes"); \
+ goto errlabel; \
+ } \
+ ctf_dprintf ("ID %i/%lx has hash %s\n", cited_type_input_num, type, \
+ hashval); \
\
- ret = ctf_dedup_rwalk_output_mapping (output, inputs, ninputs, parents, \
- already_visited, hashval, \
- visit_fun, arg, depth); \
- if (ret < 0) \
- { \
- whaterr = errmsg; \
- goto errlabel; \
- } \
- } while (0)
+ ret = ctf_dedup_rwalk_output_mapping (output, inputs, ninputs, parents, \
+ already_visited, hashval, \
+ visit_fun, arg, depth); \
+ if (ret < 0) \
+ { \
+ whaterr = errmsg; \
+ goto errlabel; \
+ } \
+ } \
+ while (0)
switch (ctf_type_kind_unsliced (fp, type))
{
case CTF_K_UNKNOWN:
- /* Just skip things of unknown kind. */
- return 0;
case CTF_K_FORWARD:
case CTF_K_INTEGER:
case CTF_K_FLOAT:
once, but are not recursed through repeatedly: ALREADY_VISITED tracks whether
types have already been visited. */
static int
-ctf_dedup_rwalk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_rwalk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
uint32_t ninputs, uint32_t *parents,
ctf_dynset_t *already_visited,
const char *hval,
int (*visit_fun) (const char *hval,
- ctf_file_t *output,
- ctf_file_t **inputs,
+ ctf_dict_t *output,
+ ctf_dict_t **inputs,
uint32_t ninputs,
uint32_t *parents,
int already_visited,
- ctf_file_t *input,
+ ctf_dict_t *input,
ctf_id_t type,
void *id,
int depth,
typedef struct ctf_sort_om_cb_arg
{
- ctf_file_t **inputs;
+ ctf_dict_t **inputs;
uint32_t ninputs;
ctf_dedup_t *d;
} ctf_sort_om_cb_arg_t;
void *one_gid, *two_gid;
uint32_t one_ninput;
uint32_t two_ninput;
- ctf_file_t *one_fp;
- ctf_file_t *two_fp;
+ ctf_dict_t *one_fp;
+ ctf_dict_t *two_fp;
ctf_id_t one_type;
ctf_id_t two_type;
/* The public entry point to ctf_dedup_rwalk_output_mapping, above. */
static int
-ctf_dedup_walk_output_mapping (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_walk_output_mapping (ctf_dict_t *output, ctf_dict_t **inputs,
uint32_t ninputs, uint32_t *parents,
int (*visit_fun) (const char *hval,
- ctf_file_t *output,
- ctf_file_t **inputs,
+ ctf_dict_t *output,
+ ctf_dict_t **inputs,
uint32_t ninputs,
uint32_t *parents,
int already_visited,
- ctf_file_t *input,
+ ctf_dict_t *input,
ctf_id_t type,
void *id,
int depth,
void *k;
if ((already_visited = ctf_dynset_create (htab_hash_string,
- ctf_dynset_eq_string,
+ htab_eq_string,
NULL)) == NULL)
return ctf_set_errno (output, ENOMEM);
conflicted per-TU type ID in INPUT with hash HVAL. Return its CTF ID, or 0
if none was needed. */
static ctf_id_t
-ctf_dedup_maybe_synthesize_forward (ctf_file_t *output, ctf_file_t *target,
- ctf_file_t *input, ctf_id_t id,
+ctf_dedup_maybe_synthesize_forward (ctf_dict_t *output, ctf_dict_t *target,
+ ctf_dict_t *input, ctf_id_t id,
const char *hval)
{
ctf_dedup_t *od = &output->ctf_dedup;
ctf_dedup_t *td = &target->ctf_dedup;
int kind;
int fwdkind;
- const char *name;
+ const char *name = ctf_type_name_raw (input, id);
const char *decorated;
void *v;
ctf_id_t emitted_forward;
if (!ctf_dynset_exists (od->cd_conflicting_types, hval, NULL)
|| target->ctf_flags & LCTF_CHILD
- || !ctf_type_name_raw (input, id)
+ || name[0] == '\0'
|| (((kind = ctf_type_kind_unsliced (input, id)) != CTF_K_STRUCT
&& kind != CTF_K_UNION && kind != CTF_K_FORWARD)))
return 0;
fwdkind = ctf_type_kind_forwarded (input, id);
- name = ctf_type_name_raw (input, id);
ctf_dprintf ("Using synthetic forward for conflicted struct/union with "
"hval %s\n", hval);
make usability a bit better. */
static ctf_id_t
-ctf_dedup_id_to_target (ctf_file_t *output, ctf_file_t *target,
- ctf_file_t **inputs, uint32_t ninputs,
- uint32_t *parents, ctf_file_t *input, int input_num,
+ctf_dedup_id_to_target (ctf_dict_t *output, ctf_dict_t *target,
+ ctf_dict_t **inputs, uint32_t ninputs,
+ uint32_t *parents, ctf_dict_t *input, int input_num,
ctf_id_t id)
{
ctf_dedup_t *od = &output->ctf_dedup;
ctf_dedup_t *td = &target->ctf_dedup;
- ctf_file_t *err_fp = input;
+ ctf_dict_t *err_fp = input;
const char *hval;
void *target_id;
ctf_id_t emitted_forward;
have already been emitted. (This type itself may also have been emitted.)
If the ARG is 1, this is a CU-mapped deduplication round mapping many
- ctf_file_t's into precisely one: conflicting types should be marked
+ ctf_dict_t's into precisely one: conflicting types should be marked
non-root-visible. If the ARG is 0, conflicting types go into per-CU
dictionaries stored in the input's ctf_dedup.cd_output: otherwise, everything
is emitted directly into the output. No struct/union members are emitted.
data object section, backtrace section etc). */
static int
-ctf_dedup_emit_type (const char *hval, ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_emit_type (const char *hval, ctf_dict_t *output, ctf_dict_t **inputs,
uint32_t ninputs, uint32_t *parents, int already_visited,
- ctf_file_t *input, ctf_id_t type, void *id, int depth,
+ ctf_dict_t *input, ctf_id_t type, void *id, int depth,
void *arg)
{
ctf_dedup_t *d = &output->ctf_dedup;
int kind = ctf_type_kind_unsliced (input, type);
const char *name;
- ctf_file_t *target = output;
- ctf_file_t *real_input;
+ ctf_dict_t *target = output;
+ ctf_dict_t *real_input;
const ctf_type_t *tp;
int input_num = CTF_DEDUP_GID_TO_INPUT (id);
int output_num = (uint32_t) -1; /* 'shared' */
ctf_parent_name_set (target, _CTF_SECTION);
input->ctf_dedup.cd_output = target;
+ input->ctf_link_in_out = target;
+ target->ctf_link_in_out = input;
}
output_num = input_num;
}
switch (kind)
{
case CTF_K_UNKNOWN:
- /* These are types that CTF cannot encode, marked as such by the compile.
- We intentionally do not re-emit these. */
- new_type = 0;
+ /* These are types that CTF cannot encode, marked as such by the
+ compiler. */
+ errtype = _("unknown type");
+ if ((new_type = ctf_add_unknown (target, isroot, name)) == CTF_ERR)
+ goto err_target;
break;
case CTF_K_FORWARD:
/* This will do nothing if the type to which this forwards already exists,
id, out_id);
/* Record the need to emit the members of this structure later. */
if (ctf_dynhash_insert (d->cd_emission_struct_members, id, out_id) < 0)
- goto err_target;
+ {
+ ctf_set_errno (target, errno);
+ goto err_target;
+ }
break;
}
default:
point. */
static int
-ctf_dedup_emit_struct_members (ctf_file_t *output, ctf_file_t **inputs,
+ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs,
uint32_t ninputs, uint32_t *parents)
{
ctf_dedup_t *d = &output->ctf_dedup;
ctf_next_t *i = NULL;
void *input_id, *target_id;
int err;
- ctf_file_t *err_fp, *input_fp;
+ ctf_dict_t *err_fp, *input_fp;
int input_num;
ctf_id_t err_type;
&input_id, &target_id)) == 0)
{
ctf_next_t *j = NULL;
- ctf_file_t *target;
+ ctf_dict_t *target;
uint32_t target_num;
ctf_id_t input_type, target_type;
ssize_t offset;
target_type = CTF_DEDUP_GID_TO_TYPE (target_id);
while ((offset = ctf_member_next (input_fp, input_type, &j, &name,
- &membtype)) >= 0)
+ &membtype, 0)) >= 0)
{
err_fp = target;
err_type = target_type;
return ctf_set_errno (output, err);
}
-/* Populate the type mapping used by the types in one FP (which must be an input
- dict containing a non-null cd_output resulting from a ctf_dedup_emit_type
- walk). */
-static int
-ctf_dedup_populate_type_mapping (ctf_file_t *shared, ctf_file_t *fp,
- ctf_file_t **inputs)
-{
- ctf_dedup_t *d = &shared->ctf_dedup;
- ctf_file_t *output = fp->ctf_dedup.cd_output;
- const void *k, *v;
- ctf_next_t *i = NULL;
- int err;
-
- /* The shared dict (the output) stores its types in the fp itself, not in a
- separate cd_output dict. */
- if (shared == fp)
- output = fp;
-
- /* There may be no types to emit at all, or all the types in this TU may be
- shared. */
- if (!output || !output->ctf_dedup.cd_output_emission_hashes)
- return 0;
-
- while ((err = ctf_dynhash_cnext (output->ctf_dedup.cd_output_emission_hashes,
- &i, &k, &v)) == 0)
- {
- const char *hval = (const char *) k;
- ctf_id_t id_out = (ctf_id_t) (uintptr_t) v;
- ctf_next_t *j = NULL;
- ctf_dynset_t *type_ids;
- const void *id;
-
- type_ids = ctf_dynhash_lookup (d->cd_output_mapping, hval);
- if (!ctf_assert (shared, type_ids))
- return -1;
-#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
- ctf_dprintf ("Traversing emission hash: hval %s\n", hval);
-#endif
-
- while ((err = ctf_dynset_cnext (type_ids, &j, &id)) == 0)
- {
- ctf_file_t *input = inputs[CTF_DEDUP_GID_TO_INPUT (id)];
- ctf_id_t id_in = CTF_DEDUP_GID_TO_TYPE (id);
-
-#ifdef ENABLE_LIBCTF_HASH_DEBUGGING
- ctf_dprintf ("Adding mapping from %i/%lx to %lx\n",
- CTF_DEDUP_GID_TO_INPUT (id), id_in, id_out);
-#endif
- ctf_add_type_mapping (input, id_in, output, id_out);
- }
- if (err != ECTF_NEXT_END)
- {
- ctf_next_destroy (i);
- goto err;
- }
- }
- if (err != ECTF_NEXT_END)
- goto err;
-
- return 0;
-
- err:
- ctf_err_warn (shared, 0, err, _("iteration error populating the type mapping"));
- return ctf_set_errno (shared, err);
-}
-
-/* Populate the type mapping machinery used by the rest of the linker,
- by ctf_add_type, etc. */
-static int
-ctf_dedup_populate_type_mappings (ctf_file_t *output, ctf_file_t **inputs,
- uint32_t ninputs)
-{
- size_t i;
-
- if (ctf_dedup_populate_type_mapping (output, output, inputs) < 0)
- {
- ctf_err_warn (output, 0, 0, _("cannot populate type mappings for shared "
- "CTF dict"));
- return -1; /* errno is set for us. */
- }
-
- for (i = 0; i < ninputs; i++)
- {
- if (ctf_dedup_populate_type_mapping (output, inputs[i], inputs) < 0)
- {
- ctf_err_warn (output, 0, ctf_errno (inputs[i]),
- _("cannot populate type mappings for per-CU CTF dict"));
- return ctf_set_errno (output, ctf_errno (inputs[i]));
- }
- }
-
- return 0;
-}
-
/* Emit deduplicated types into the outputs. The shared type repository is
OUTPUT, on which the ctf_dedup function must have already been called. The
PARENTS array contains the INPUTS index of the parent dict for every child
If CU_MAPPED is set, this is a first pass for a link with a non-empty CU
mapping: only one output will result. */
-ctf_file_t **
-ctf_dedup_emit (ctf_file_t *output, ctf_file_t **inputs, uint32_t ninputs,
+ctf_dict_t **
+ctf_dedup_emit (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs,
uint32_t *parents, uint32_t *noutputs, int cu_mapped)
{
size_t num_outputs = 1; /* Always at least one output: us. */
- ctf_file_t **outputs;
- ctf_file_t **walk;
+ ctf_dict_t **outputs;
+ ctf_dict_t **walk;
size_t i;
ctf_dprintf ("Triggering emission.\n");
if (ctf_dedup_emit_struct_members (output, inputs, ninputs, parents) < 0)
return NULL; /* errno is set for us. */
- if (ctf_dedup_populate_type_mappings (output, inputs, ninputs) < 0)
- return NULL; /* errno is set for us. */
-
for (i = 0; i < ninputs; i++)
{
if (inputs[i]->ctf_dedup.cd_output)
if (!ctf_assert (output, !cu_mapped || (cu_mapped && num_outputs == 1)))
return NULL;
- if ((outputs = calloc (num_outputs, sizeof (ctf_file_t *))) == NULL)
+ if ((outputs = calloc (num_outputs, sizeof (ctf_dict_t *))) == NULL)
{
ctf_err_warn (output, 0, ENOMEM,
_("out of memory allocating link outputs array"));
}
}
- ctf_dedup_fini (output, outputs, num_outputs);
return outputs;
}
+
+/* Determine what type SRC_FP / SRC_TYPE was emitted as in the FP, which
+ must be the shared dict or have it as a parent: return 0 if none. The SRC_FP
+ must be a past input to ctf_dedup. */
+
+ctf_id_t
+ctf_dedup_type_mapping (ctf_dict_t *fp, ctf_dict_t *src_fp, ctf_id_t src_type)
+{
+ ctf_dict_t *output = NULL;
+ ctf_dedup_t *d;
+ int input_num;
+ void *num_ptr;
+ void *type_ptr;
+ int found;
+ const char *hval;
+
+ /* It is an error (an internal error in the caller, in ctf-link.c) to call
+ this with an FP that is not a per-CU output or shared output dict, or with
+ a SRC_FP that was not passed to ctf_dedup as an input; it is an internal
+ error in ctf-dedup for the type passed not to have been hashed, though if
+ the src_fp is a child dict and the type is not a child type, it will have
+ been hashed under the GID corresponding to the parent. */
+
+ if (fp->ctf_dedup.cd_type_hashes != NULL)
+ output = fp;
+ else if (fp->ctf_parent && fp->ctf_parent->ctf_dedup.cd_type_hashes != NULL)
+ output = fp->ctf_parent;
+ else
+ {
+ ctf_set_errno (fp, ECTF_INTERNAL);
+ ctf_err_warn (fp, 0, ECTF_INTERNAL,
+ _("dict %p passed to ctf_dedup_type_mapping is not a "
+ "deduplicated output"), (void *) fp);
+ return CTF_ERR;
+ }
+
+ if (src_fp->ctf_parent && ctf_type_isparent (src_fp, src_type))
+ src_fp = src_fp->ctf_parent;
+
+ d = &output->ctf_dedup;
+
+ found = ctf_dynhash_lookup_kv (d->cd_input_nums, src_fp, NULL, &num_ptr);
+ if (!ctf_assert (output, found != 0))
+ return CTF_ERR; /* errno is set for us. */
+ input_num = (uintptr_t) num_ptr;
+
+ hval = ctf_dynhash_lookup (d->cd_type_hashes,
+ CTF_DEDUP_GID (output, input_num, src_type));
+
+ if (!ctf_assert (output, hval != NULL))
+ return CTF_ERR; /* errno is set for us. */
+
+ /* The emission hashes may be unset if this dict was created after
+ deduplication to house variables or other things that would conflict if
+ stored in the shared dict. */
+ if (fp->ctf_dedup.cd_output_emission_hashes)
+ if (ctf_dynhash_lookup_kv (fp->ctf_dedup.cd_output_emission_hashes, hval,
+ NULL, &type_ptr))
+ return (ctf_id_t) (uintptr_t) type_ptr;
+
+ if (fp->ctf_parent)
+ {
+ ctf_dict_t *pfp = fp->ctf_parent;
+ if (pfp->ctf_dedup.cd_output_emission_hashes)
+ if (ctf_dynhash_lookup_kv (pfp->ctf_dedup.cd_output_emission_hashes,
+ hval, NULL, &type_ptr))
+ return (ctf_id_t) (uintptr_t) type_ptr;
+ }
+
+ return 0;
+}