diff options
-rw-r--r-- | libctf/ChangeLog | 41 | ||||
-rw-r--r-- | libctf/ctf-create.c | 95 | ||||
-rw-r--r-- | libctf/ctf-dedup.c | 198 | ||||
-rw-r--r-- | libctf/ctf-impl.h | 17 | ||||
-rw-r--r-- | libctf/ctf-link.c | 321 |
5 files changed, 344 insertions, 328 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog index e0d3f7b..9706919 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,46 @@ 2021-03-02 Nick Alcock <nick.alcock@oracle.com> + * ctf-impl.h (ctf_dict_t) <ctf_link_type_mapping>: No longer used + by the nondeduplicating linker. + (ctf_add_type_mapping): Removed, now static. + (ctf_type_mapping): Likewise. + (ctf_dedup_type_mapping): New. + (ctf_dedup_t) <cd_input_nums>: New. + * ctf-dedup.c (ctf_dedup_init): Populate it. + (ctf_dedup_fini): Free it again. Emphasise that this has to be + the last thing called. + (ctf_dedup): Populate it. + (ctf_dedup_populate_type_mapping): Removed. + (ctf_dedup_populate_type_mappings): Likewise. + (ctf_dedup_emit): No longer call it. No longer call + ctf_dedup_fini either. + (ctf_dedup_type_mapping): New. + * ctf-link.c (ctf_unnamed_cuname): New. + (ctf_create_per_cu): Arguments must be non-null now. + (ctf_in_member_cb_arg): Removed. + (ctf_link): No longer populate it. No longer discard the + mapping table. + (ctf_link_deduplicating_one_symtypetab): Use + ctf_dedup_type_mapping, not ctf_type_mapping. Use + ctf_unnamed_cuname. + (ctf_link_one_variable): Likewise. Pass in args individually: no + longer a ctf_variable_iter callback. + (empty_link_type_mapping): Removed. + (ctf_link_deduplicating_variables): Use ctf_variable_next, not + ctf_variable_iter. No longer pack arguments to + ctf_link_one_variable into a struct. + (ctf_link_deduplicating_per_cu): Call ctf_dedup_fini once + all link phases are done. + (ctf_link_deduplicating): Likewise. + (ctf_link_intern_extern_string): Improve comment. + (ctf_add_type_mapping): Migrate... + (ctf_type_mapping): ... these functions... + * ctf-create.c (ctf_add_type_mapping): ... here... + (ctf_type_mapping): ... and make static, for the sole use of + ctf_add_type. + +2021-03-02 Nick Alcock <nick.alcock@oracle.com> + * ctf-link.c (ctf_link_one_variable): Remove reference to "unconflicted link mode". diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index c01ab7a..d417922 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -2471,6 +2471,101 @@ membadd (const char *name, ctf_id_t type, unsigned long offset, void *arg) return 0; } +/* Record the correspondence between a source and ctf_add_type()-added + destination type: both types are translated into parent type IDs if need be, + so they relate to the actual dictionary they are in. Outside controlled + circumstances (like linking) it is probably not useful to do more than + compare these pointers, since there is nothing stopping the user closing the + source dict whenever they want to. + + Our OOM handling here is just to not do anything, because this is called deep + enough in the call stack that doing anything useful is painfully difficult: + the worst consequence if we do OOM is a bit of type duplication anyway. */ + +static void +ctf_add_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, + ctf_dict_t *dst_fp, ctf_id_t dst_type) +{ + if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent) + src_fp = src_fp->ctf_parent; + + src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type); + + if (LCTF_TYPE_ISPARENT (dst_fp, dst_type) && dst_fp->ctf_parent) + dst_fp = dst_fp->ctf_parent; + + dst_type = LCTF_TYPE_TO_INDEX(dst_fp, dst_type); + + if (dst_fp->ctf_link_type_mapping == NULL) + { + ctf_hash_fun f = ctf_hash_type_key; + ctf_hash_eq_fun e = ctf_hash_eq_type_key; + + if ((dst_fp->ctf_link_type_mapping = ctf_dynhash_create (f, e, free, + NULL)) == NULL) + return; + } + + ctf_link_type_key_t *key; + key = calloc (1, sizeof (struct ctf_link_type_key)); + if (!key) + return; + + key->cltk_fp = src_fp; + key->cltk_idx = src_type; + + /* No OOM checking needed, because if this doesn't work the worst we'll do is + add a few more duplicate types (which will probably run out of memory + anyway). */ + ctf_dynhash_insert (dst_fp->ctf_link_type_mapping, key, + (void *) (uintptr_t) dst_type); +} + +/* Look up a type mapping: return 0 if none. The DST_FP is modified to point to + the parent if need be. The ID returned is from the dst_fp's perspective. */ +static ctf_id_t +ctf_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, ctf_dict_t **dst_fp) +{ + ctf_link_type_key_t key; + ctf_dict_t *target_fp = *dst_fp; + ctf_id_t dst_type = 0; + + if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent) + src_fp = src_fp->ctf_parent; + + src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type); + key.cltk_fp = src_fp; + key.cltk_idx = src_type; + + if (target_fp->ctf_link_type_mapping) + dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping, + &key); + + if (dst_type != 0) + { + dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type, + target_fp->ctf_parent != NULL); + *dst_fp = target_fp; + return dst_type; + } + + if (target_fp->ctf_parent) + target_fp = target_fp->ctf_parent; + else + return 0; + + if (target_fp->ctf_link_type_mapping) + dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping, + &key); + + if (dst_type) + dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type, + target_fp->ctf_parent != NULL); + + *dst_fp = target_fp; + return dst_type; +} + /* The ctf_add_type routine is used to copy a type from a source CTF dictionary to a dynamic destination dictionary. This routine operates recursively by following the source type's links and embedded member types. If the diff --git a/libctf/ctf-dedup.c b/libctf/ctf-dedup.c index 001c248..50da4ac 100644 --- a/libctf/ctf-dedup.c +++ b/libctf/ctf-dedup.c @@ -1642,6 +1642,12 @@ ctf_dedup_init (ctf_dict_t *fp) 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, @@ -1661,6 +1667,8 @@ ctf_dedup_init (ctf_dict_t *fp) 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_dict_t *fp, ctf_dict_t **outputs, uint32_t noutputs) { @@ -1682,6 +1690,7 @@ ctf_dedup_fini (ctf_dict_t *fp, ctf_dict_t **outputs, uint32_t noutputs) #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); @@ -1876,12 +1885,22 @@ ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs, 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 @@ -1937,6 +1956,10 @@ ctf_dedup (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs, return -1; /* errno is set for us. */ } return 0; + + err: + ctf_dedup_fini (output, NULL, 0); + return -1; } static int @@ -3003,100 +3026,6 @@ ctf_dedup_emit_struct_members (ctf_dict_t *output, ctf_dict_t **inputs, 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_dict_t *shared, ctf_dict_t *fp, - ctf_dict_t **inputs) -{ - ctf_dedup_t *d = &shared->ctf_dedup; - ctf_dict_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_dict_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_dict_t *output, ctf_dict_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 @@ -3127,9 +3056,6 @@ ctf_dedup_emit (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs, 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) @@ -3163,6 +3089,76 @@ ctf_dedup_emit (ctf_dict_t *output, ctf_dict_t **inputs, uint32_t ninputs, } } - 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; +} diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index a6e1da5..78a41ff 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -347,6 +347,11 @@ typedef struct ctf_dedup /* A set (a hash) of hash values of conflicting types. */ ctf_dynset_t *cd_conflicting_types; + /* A hash mapping fp *'s of inputs to their input_nums. Used only by + functions outside the core ctf_dedup / ctf_dedup_emit machinery which do + not take an inputs array. */ + ctf_dynhash_t *cd_input_nums; + /* Maps type hashes to ctf_id_t's in this dictionary. Populated only at emission time, in the dictionary where emission is taking place. */ ctf_dynhash_t *cd_output_emission_hashes; @@ -455,9 +460,8 @@ struct ctf_dict ctf_dynhash_t *ctf_link_inputs; /* Inputs to this link. */ ctf_dynhash_t *ctf_link_outputs; /* Additional outputs from this link. */ - /* Map input types to output types: populated in each output dict. - Key is a ctf_link_type_key_t: value is a type ID. Used by - nondeduplicating links and ad-hoc ctf_add_type calls only. */ + /* Map input types to output types for ctf_add_type. Key is a + ctf_link_type_key_t: value is a type ID. */ ctf_dynhash_t *ctf_link_type_mapping; /* Map input CU names to output CTF dict names: populated in the top-level @@ -703,11 +707,6 @@ extern ctf_id_t ctf_add_encoded (ctf_dict_t *, uint32_t, const char *, extern ctf_id_t ctf_add_reftype (ctf_dict_t *, uint32_t, ctf_id_t, uint32_t kind); -extern void ctf_add_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, - ctf_dict_t *dst_fp, ctf_id_t dst_type); -extern ctf_id_t ctf_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, - ctf_dict_t **dst_fp); - extern int ctf_dedup_atoms_init (ctf_dict_t *); extern int ctf_dedup (ctf_dict_t *, ctf_dict_t **, uint32_t ninputs, uint32_t *parents, int cu_mapped); @@ -715,6 +714,8 @@ extern void ctf_dedup_fini (ctf_dict_t *, ctf_dict_t **, uint32_t); extern ctf_dict_t **ctf_dedup_emit (ctf_dict_t *, ctf_dict_t **, uint32_t ninputs, uint32_t *parents, uint32_t *noutputs, int cu_mapped); +extern ctf_id_t ctf_dedup_type_mapping (ctf_dict_t *fp, ctf_dict_t *src_fp, + ctf_id_t src_type); extern void ctf_decl_init (ctf_decl_t *); extern void ctf_decl_fini (ctf_decl_t *); diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index d598b78..c0b0916 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -24,118 +24,18 @@ #pragma weak ctf_open #endif -/* Type tracking machinery. */ - -/* Record the correspondence between a source and ctf_add_type()-added - destination type: both types are translated into parent type IDs if need be, - so they relate to the actual dictionary they are in. Outside controlled - circumstances (like linking) it is probably not useful to do more than - compare these pointers, since there is nothing stopping the user closing the - source dict whenever they want to. - - Our OOM handling here is just to not do anything, because this is called deep - enough in the call stack that doing anything useful is painfully difficult: - the worst consequence if we do OOM is a bit of type duplication anyway. */ - -void -ctf_add_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, - ctf_dict_t *dst_fp, ctf_id_t dst_type) -{ - if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent) - src_fp = src_fp->ctf_parent; - - src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type); - - if (LCTF_TYPE_ISPARENT (dst_fp, dst_type) && dst_fp->ctf_parent) - dst_fp = dst_fp->ctf_parent; - - dst_type = LCTF_TYPE_TO_INDEX(dst_fp, dst_type); - - if (dst_fp->ctf_link_type_mapping == NULL) - { - ctf_hash_fun f = ctf_hash_type_key; - ctf_hash_eq_fun e = ctf_hash_eq_type_key; - - if ((dst_fp->ctf_link_type_mapping = ctf_dynhash_create (f, e, free, - NULL)) == NULL) - return; - } - - ctf_link_type_key_t *key; - key = calloc (1, sizeof (struct ctf_link_type_key)); - if (!key) - return; - - key->cltk_fp = src_fp; - key->cltk_idx = src_type; - - /* No OOM checking needed, because if this doesn't work the worst we'll do is - add a few more duplicate types (which will probably run out of memory - anyway). */ - ctf_dynhash_insert (dst_fp->ctf_link_type_mapping, key, - (void *) (uintptr_t) dst_type); -} - -/* Look up a type mapping: return 0 if none. The DST_FP is modified to point to - the parent if need be. The ID returned is from the dst_fp's perspective. */ -ctf_id_t -ctf_type_mapping (ctf_dict_t *src_fp, ctf_id_t src_type, ctf_dict_t **dst_fp) -{ - ctf_link_type_key_t key; - ctf_dict_t *target_fp = *dst_fp; - ctf_id_t dst_type = 0; - - if (LCTF_TYPE_ISPARENT (src_fp, src_type) && src_fp->ctf_parent) - src_fp = src_fp->ctf_parent; - - src_type = LCTF_TYPE_TO_INDEX(src_fp, src_type); - key.cltk_fp = src_fp; - key.cltk_idx = src_type; - - if (target_fp->ctf_link_type_mapping) - dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping, - &key); - - if (dst_type != 0) - { - dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type, - target_fp->ctf_parent != NULL); - *dst_fp = target_fp; - return dst_type; - } - - if (target_fp->ctf_parent) - target_fp = target_fp->ctf_parent; - else - return 0; - - if (target_fp->ctf_link_type_mapping) - dst_type = (uintptr_t) ctf_dynhash_lookup (target_fp->ctf_link_type_mapping, - &key); - - if (dst_type) - dst_type = LCTF_INDEX_TO_TYPE (target_fp, dst_type, - target_fp->ctf_parent != NULL); - - *dst_fp = target_fp; - return dst_type; -} - -/* Linker machinery. - - CTF linking consists of adding CTF archives full of content to be merged into +/* CTF linking consists of adding CTF archives full of content to be merged into this one to the current file (which must be writable) by calling - ctf_link_add_ctf(). Once this is done, a call to ctf_link() will merge the - type tables together, generating new CTF files as needed, with this one as a - parent, to contain types from the inputs which conflict. - ctf_link_add_strtab() takes a callback which provides string/offset pairs to - be added to the external symbol table and deduplicated from all CTF string - tables in the output link; ctf_link_shuffle_syms() takes a callback which - provides symtab entries in ascending order, and shuffles the function and - data sections to match; and ctf_link_write() emits a CTF file (if there are - no conflicts requiring per-compilation-unit sub-CTF files) or CTF archives - (otherwise) and returns it, suitable for addition in the .ctf section of the - output. */ + ctf_link_add_ctf. Once this is done, a call to ctf_link will merge the type + tables together, generating new CTF files as needed, with this one as a + parent, to contain types from the inputs which conflict. ctf_link_add_strtab + takes a callback which provides string/offset pairs to be added to the + external symbol table and deduplicated from all CTF string tables in the + output link; ctf_link_shuffle_syms takes a callback which provides symtab + entries in ascending order, and shuffles the function and data sections to + match; and ctf_link_write emits a CTF file (if there are no conflicts + requiring per-compilation-unit sub-CTF files) or CTF archives (otherwise) and + returns it, suitable for addition in the .ctf section of the output. */ /* Return the name of the compilation unit this CTF dict or its parent applies to, or a non-null string otherwise: prefer the parent. Used in debugging @@ -151,6 +51,19 @@ ctf_link_input_name (ctf_dict_t *fp) return "(unnamed)"; } +/* Return the cuname of a dict, or the string "unnamed-CU" if none. */ + +static const char * +ctf_unnamed_cuname (ctf_dict_t *fp) +{ + const char *cuname = ctf_cuname (fp); + + if (!cuname) + cuname = "unnamed-CU"; + + return cuname; +} + /* The linker inputs look like this. clin_fp is used for short-circuited CU-mapped links that can entirely avoid the first link phase in some situations in favour of just passing on the contained ctf_dict_t: it is @@ -279,6 +192,7 @@ ctf_link_add_ctf (ctf_dict_t *fp, ctf_archive_t *ctf, const char *name) /* Return a per-CU output CTF dictionary suitable for the given CU, creating and interning it if need be. */ +_libctf_nonnull_((1,2)) static ctf_dict_t * ctf_create_per_cu (ctf_dict_t *fp, const char *cu_name) { @@ -429,21 +343,6 @@ ctf_link_set_memb_name_changer (ctf_dict_t *fp, fp->ctf_link_memb_name_changer_arg = arg; } -typedef struct ctf_link_in_member_cb_arg -{ - /* The shared output dictionary. */ - ctf_dict_t *out_fp; - - /* The cuname of the input file, and an fp to each dictionary in that file - in turn. */ - const char *in_cuname; - ctf_dict_t *in_fp; - - /* If true, this is the CU-mapped portion of a deduplicating link: no child - dictionaries should be created. */ - int cu_mapped; -} ctf_link_in_member_cb_arg_t; - /* Set a function which is used to filter out unwanted variables from the link. */ int ctf_link_set_variable_filter (ctf_dict_t *fp, ctf_link_variable_filter_f *filter, @@ -479,23 +378,22 @@ check_variable (const char *name, ctf_dict_t *fp, ctf_id_t type, return 0; /* Already exists. */ } -/* Link one variable in. */ +/* Link one variable named NAME of type TYPE found in IN_FP into FP. */ static int -ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_) +ctf_link_one_variable (ctf_dict_t *fp, ctf_dict_t *in_fp, const char *name, + ctf_id_t type, int cu_mapped) { - ctf_link_in_member_cb_arg_t *arg = (ctf_link_in_member_cb_arg_t *) arg_; ctf_dict_t *per_cu_out_fp; ctf_id_t dst_type = 0; - ctf_dict_t *insert_fp; ctf_dvdef_t *dvd; /* See if this variable is filtered out. */ - if (arg->out_fp->ctf_link_variable_filter) + if (fp->ctf_link_variable_filter) { - void *farg = arg->out_fp->ctf_link_variable_filter_arg; - if (arg->out_fp->ctf_link_variable_filter (arg->in_fp, name, type, farg)) + void *farg = fp->ctf_link_variable_filter_arg; + if (fp->ctf_link_variable_filter (in_fp, name, type, farg)) return 0; } @@ -503,25 +401,25 @@ ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_) to that first: if it reports a duplicate, or if the type is in a child already, add straight to the child. */ - insert_fp = arg->out_fp; + if ((dst_type = ctf_dedup_type_mapping (fp, in_fp, type)) == CTF_ERR) + return -1; /* errno is set for us. */ - dst_type = ctf_type_mapping (arg->in_fp, type, &insert_fp); if (dst_type != 0) { - if (insert_fp == arg->out_fp) - { - if (check_variable (name, insert_fp, dst_type, &dvd)) - { - /* No variable here: we can add it. */ - if (ctf_add_variable (insert_fp, name, dst_type) < 0) - return (ctf_set_errno (arg->out_fp, ctf_errno (insert_fp))); - return 0; - } + if (!ctf_assert (fp, ctf_type_isparent (fp, dst_type))) + return -1; /* errno is set for us. */ - /* Already present? Nothing to do. */ - if (dvd && dvd->dvd_type == dst_type) - return 0; + if (check_variable (name, fp, dst_type, &dvd)) + { + /* No variable here: we can add it. */ + if (ctf_add_variable (fp, name, dst_type) < 0) + return -1; /* errno is set for us. */ + return 0; } + + /* Already present? Nothing to do. */ + if (dvd && dvd->dvd_type == dst_type) + return 0; } /* Can't add to the parent due to a name clash, or because it references a @@ -529,29 +427,29 @@ ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_) be. If we can't do that, skip it. Don't add to a child if we're doing a CU-mapped link, since that has only one output. */ - if (arg->cu_mapped) + if (cu_mapped) { ctf_dprintf ("Variable %s in input file %s depends on a type %lx hidden " - "due to conflicts: skipped.\n", name, arg->in_cuname, - type); + "due to conflicts: skipped.\n", name, + ctf_unnamed_cuname (in_fp), type); return 0; } - if ((per_cu_out_fp = ctf_create_per_cu (arg->out_fp, arg->in_cuname)) == NULL) - return -1; /* Errno is set for us. */ + if ((per_cu_out_fp = ctf_create_per_cu (fp, ctf_unnamed_cuname (in_fp))) == NULL) + return -1; /* errno is set for us. */ /* If the type was not found, check for it in the child too. */ if (dst_type == 0) { - insert_fp = per_cu_out_fp; - dst_type = ctf_type_mapping (arg->in_fp, type, &insert_fp); + if ((dst_type = ctf_dedup_type_mapping (per_cu_out_fp, + in_fp, type)) == CTF_ERR) + return -1; /* errno is set for us. */ if (dst_type == 0) { - ctf_err_warn (arg->out_fp, 1, 0, - _("type %lx for variable %s in input file %s " - "not found: skipped"), type, name, - arg->in_cuname); + ctf_err_warn (fp, 1, 0, _("type %lx for variable %s in input file %s " + "not found: skipped"), type, name, + ctf_unnamed_cuname (in_fp)); /* Do not terminate the link: just skip the variable. */ return 0; } @@ -559,21 +457,10 @@ ctf_link_one_variable (const char *name, ctf_id_t type, void *arg_) if (check_variable (name, per_cu_out_fp, dst_type, &dvd)) if (ctf_add_variable (per_cu_out_fp, name, dst_type) < 0) - return (ctf_set_errno (arg->out_fp, ctf_errno (per_cu_out_fp))); + return (ctf_set_errno (fp, ctf_errno (per_cu_out_fp))); return 0; } -/* Dump the unnecessary link type mapping after one input file is processed. */ -static void -empty_link_type_mapping (void *key _libctf_unused_, void *value, - void *arg _libctf_unused_) -{ - ctf_dict_t *fp = (ctf_dict_t *) value; - - if (fp->ctf_link_type_mapping) - ctf_dynhash_empty (fp->ctf_link_type_mapping); -} - /* Lazily open a CTF archive for linking, if not already open. Returns the number of files contained within the opened archive (0 for none), @@ -925,21 +812,24 @@ static int ctf_link_deduplicating_variables (ctf_dict_t *fp, ctf_dict_t **inputs, size_t ninputs, int cu_mapped) { - ctf_link_in_member_cb_arg_t arg; size_t i; - arg.cu_mapped = cu_mapped; - arg.out_fp = fp; - for (i = 0; i < ninputs; i++) { - arg.in_fp = inputs[i]; - if (ctf_cuname (inputs[i]) != NULL) - arg.in_cuname = ctf_cuname (inputs[i]); - else - arg.in_cuname = "unnamed-CU"; - if (ctf_variable_iter (arg.in_fp, ctf_link_one_variable, &arg) < 0) - return ctf_set_errno (fp, ctf_errno (arg.in_fp)); + ctf_next_t *it = NULL; + ctf_id_t type; + const char *name; + + while ((type = ctf_variable_next (inputs[i], &it, &name)) != CTF_ERR) + { + if (ctf_link_one_variable (fp, inputs[i], name, type, cu_mapped) < 0) + { + ctf_next_destroy (it); + return -1; /* errno is set for us. */ + } + } + if (ctf_errno (inputs[i]) != ECTF_NEXT_END) + return ctf_set_errno (fp, ctf_errno (inputs[i])); } return 0; } @@ -982,40 +872,35 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input, ctf_next_t *it = NULL; const char *name; ctf_id_t type; - const char *in_file_name; - - if (ctf_cuname (input) != NULL) - in_file_name = ctf_cuname (input); - else - in_file_name = "unnamed-CU"; while ((type = ctf_symbol_next (input, &it, &name, functions)) != CTF_ERR) { ctf_id_t dst_type; ctf_dict_t *per_cu_out_fp; - ctf_dict_t *insert_fp = fp; int sym; /* Look in the parent first. */ - dst_type = ctf_type_mapping (input, type, &insert_fp); + if ((dst_type = ctf_dedup_type_mapping (fp, input, type)) == CTF_ERR) + return -1; /* errno is set for us. */ + if (dst_type != 0) { - if (insert_fp == fp) - { - sym = check_sym (fp, name, dst_type, functions); + if (!ctf_assert (fp, ctf_type_isparent (fp, dst_type))) + return -1; /* errno is set for us. */ - /* Already present: next symbol. */ - if (sym == 0) - continue; - /* Not present: add it. */ - else if (sym > 0) - { - if (ctf_add_funcobjt_sym (fp, functions, - name, dst_type) < 0) - return -1; /* errno is set for us. */ - continue; - } + sym = check_sym (fp, name, dst_type, functions); + + /* Already present: next symbol. */ + if (sym == 0) + continue; + /* Not present: add it. */ + else if (sym > 0) + { + if (ctf_add_funcobjt_sym (fp, functions, + name, dst_type) < 0) + return -1; /* errno is set for us. */ + continue; } } @@ -1028,24 +913,26 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input, { ctf_dprintf ("Symbol %s in input file %s depends on a type %lx " "hidden due to conflicts: skipped.\n", name, - in_file_name, type); + ctf_unnamed_cuname (input), type); continue; } - if ((per_cu_out_fp = ctf_create_per_cu (fp, in_file_name)) == NULL) + if ((per_cu_out_fp = ctf_create_per_cu (fp, ctf_unnamed_cuname (input))) == NULL) return -1; /* errno is set for us. */ /* If the type was not found, check for it in the child too. */ if (dst_type == 0) { - insert_fp = per_cu_out_fp; - dst_type = ctf_type_mapping (input, type, &insert_fp); + if ((dst_type = ctf_dedup_type_mapping (per_cu_out_fp, + input, type)) == CTF_ERR) + return -1; /* errno is set for us. */ if (dst_type == 0) { ctf_err_warn (fp, 1, 0, _("type %lx for symbol %s in input file %s " - "not found: skipped"), type, name, in_file_name); + "not found: skipped"), type, name, + ctf_unnamed_cuname (input)); continue; } } @@ -1068,7 +955,7 @@ ctf_link_deduplicating_one_symtypetab (ctf_dict_t *fp, ctf_dict_t *input, ctf_err_warn (fp, 0, ECTF_DUPLICATE, _("symbol %s in input file %s found conflicting " "even when trying in per-CU dict."), name, - in_file_name); + ctf_unnamed_cuname (input)); return (ctf_set_errno (fp, ECTF_DUPLICATE)); } } @@ -1258,6 +1145,8 @@ ctf_link_deduplicating_per_cu (ctf_dict_t *fp) goto err_inputs_outputs; } + ctf_dedup_fini (out, outputs, noutputs); + /* For now, we omit symbol section linking for CU-mapped links, until it is clear how to unify the symbol table across such links. (Perhaps we should emit an unconditionally indexed symtab, like the compiler @@ -1420,6 +1309,8 @@ ctf_link_deduplicating (ctf_dict_t *fp) goto err_clean_outputs; } + ctf_dedup_fini (fp, outputs, noutputs); + /* Now close all the inputs, including per-CU intermediates. */ if (ctf_link_deduplicating_close_inputs (fp, NULL, inputs, ninputs) < 0) @@ -1452,12 +1343,9 @@ ctf_link_deduplicating (ctf_dict_t *fp) int ctf_link (ctf_dict_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; fp->ctf_link_flags = flags; if (fp->ctf_link_inputs == NULL) @@ -1503,11 +1391,6 @@ ctf_link (ctf_dict_t *fp, int flags) ctf_link_deduplicating (fp); - /* Discard the now-unnecessary mapping table data from all the outputs. */ - if (fp->ctf_link_type_mapping) - ctf_dynhash_empty (fp->ctf_link_type_mapping); - ctf_dynhash_iter (fp->ctf_link_outputs, empty_link_type_mapping, NULL); - fp->ctf_flags &= ~LCTF_LINKING; if ((ctf_errno (fp) != 0) && (ctf_errno (fp) != ECTF_NOCTFDATA)) return -1; @@ -1537,8 +1420,8 @@ ctf_link_intern_extern_string (void *key _libctf_unused_, void *value, /* Repeatedly call ADD_STRING to acquire strings from the external string table, adding them to the atoms table for this CU and all subsidiary CUs. - If ctf_link() is also called, it must be called first if you want the new CTF - files ctf_link() can create to get their strings dedupped against the ELF + If ctf_link is also called, it must be called first if you want the new CTF + files ctf_link can create to get their strings dedupped against the ELF strtab properly. */ int ctf_link_add_strtab (ctf_dict_t *fp, ctf_link_strtab_string_f *add_string, |