From: Nick Alcock Date: Sat, 13 Jul 2019 20:31:26 +0000 (+0100) Subject: libctf: map from old to corresponding newly-added types in ctf_add_type X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=886453cbbc86ba63d8ab1264e9684a7698243eeb;p=binutils-gdb.git libctf: map from old to corresponding newly-added types in ctf_add_type This lets you call ctf_type_mapping (dest_fp, src_fp, src_type_id) and get told what type ID the corresponding type has in the target ctf_file_t. This works even if it was added by a recursive call, and because it is stored in the target ctf_file_t it works even if we had to add one type to multiple ctf_file_t's as part of conflicting type handling. We empty out this mapping after every archive is linked: because it maps input to output fps, and we only visit each input fp once, its contents are rendered entirely useless every time the source fp changes. v3: add several missing mapping additions. Add ctf_dynhash_empty, and empty after every input archive. v5: fix tabdamage. libctf/ * ctf-impl.h (ctf_file_t): New field ctf_link_type_mapping. (struct ctf_link_type_mapping_key): New. (ctf_hash_type_mapping_key): Likewise. (ctf_hash_eq_type_mapping_key): Likewise. (ctf_add_type_mapping): Likewise. (ctf_type_mapping): Likewise. (ctf_dynhash_empty): Likewise. * ctf-open.c (ctf_file_close): Update accordingly. * ctf-create.c (ctf_update): Likewise. (ctf_add_type): Populate the mapping. * ctf-hash.c (ctf_hash_type_mapping_key): Hash a type mapping key. (ctf_hash_eq_type_mapping_key): Check the key for equality. (ctf_dynhash_insert): Fix comment typo. (ctf_dynhash_empty): New. * ctf-link.c (ctf_add_type_mapping): New. (ctf_type_mapping): Likewise. (empty_link_type_mapping): New. (ctf_link_one_input_archive): Call it. --- diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 959a038b877..7dc32b89ce3 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,3 +1,24 @@ +2019-07-13 Nick Alcock + + * ctf-impl.h (ctf_file_t): New field ctf_link_type_mapping. + (struct ctf_link_type_mapping_key): New. + (ctf_hash_type_mapping_key): Likewise. + (ctf_hash_eq_type_mapping_key): Likewise. + (ctf_add_type_mapping): Likewise. + (ctf_type_mapping): Likewise. + (ctf_dynhash_empty): Likewise. + * ctf-open.c (ctf_file_close): Update accordingly. + * ctf-create.c (ctf_update): Likewise. + (ctf_add_type): Populate the mapping. + * ctf-hash.c (ctf_hash_type_mapping_key): Hash a type mapping key. + (ctf_hash_eq_type_mapping_key): Check the key for equality. + (ctf_dynhash_insert): Fix comment typo. + (ctf_dynhash_empty): New. + * ctf-link.c (ctf_add_type_mapping): New. + (ctf_type_mapping): Likewise. + (empty_link_type_mapping): New. + (ctf_link_one_input_archive): Call it. + 2019-07-13 Nick Alcock * ctf-link.c: New file, linking of the string and type sections. diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index fc37d6a40f8..90e45f340b1 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -473,6 +473,7 @@ ctf_update (ctf_file_t *fp) nfp->ctf_link_inputs = fp->ctf_link_inputs; nfp->ctf_link_outputs = fp->ctf_link_outputs; nfp->ctf_syn_ext_strtab = fp->ctf_syn_ext_strtab; + nfp->ctf_link_type_mapping = fp->ctf_link_type_mapping; nfp->ctf_snapshot_lu = fp->ctf_snapshots; @@ -485,6 +486,7 @@ ctf_update (ctf_file_t *fp) fp->ctf_link_inputs = NULL; fp->ctf_link_outputs = NULL; fp->ctf_syn_ext_strtab = NULL; + fp->ctf_link_type_mapping = NULL; fp->ctf_dvhash = NULL; memset (&fp->ctf_dvdefs, 0, sizeof (ctf_list_t)); @@ -1557,6 +1559,7 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) ctf_funcinfo_t ctc; ctf_hash_t *hp; + ctf_id_t orig_src_type = src_type; if (!(dst_fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno (dst_fp, ECTF_RDONLY)); @@ -1640,7 +1643,10 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) if (memcmp (&src_en, &dst_en, sizeof (ctf_encoding_t)) == 0) { if (kind != CTF_K_SLICE) - return dst_type; + { + ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type); + return dst_type; + } } else { @@ -1679,7 +1685,10 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) int match; /* Do the encodings match? */ if (kind != CTF_K_INTEGER && kind != CTF_K_FLOAT && kind != CTF_K_SLICE) - return dtd->dtd_type; + { + ctf_add_type_mapping (src_fp, src_type, dst_fp, dtd->dtd_type); + return dtd->dtd_type; + } sroot = (flag & CTF_ADD_ROOT); droot = (LCTF_INFO_ISROOT (dst_fp, @@ -1698,7 +1707,10 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) if (match && sroot == droot) { if (kind != CTF_K_SLICE) - return dtd->dtd_type; + { + ctf_add_type_mapping (src_fp, src_type, dst_fp, dtd->dtd_type); + return dtd->dtd_type; + } } else if (!match && sroot && droot) { @@ -1939,6 +1951,8 @@ ctf_add_type (ctf_file_t *dst_fp, ctf_file_t *src_fp, ctf_id_t src_type) return (ctf_set_errno (dst_fp, ECTF_CORRUPT)); } + if (dst_type != CTF_ERR) + ctf_add_type_mapping (src_fp, orig_src_type, dst_fp, dst_type); return dst_type; } diff --git a/libctf/ctf-hash.c b/libctf/ctf-hash.c index 3512d22a347..c6233eb6767 100644 --- a/libctf/ctf-hash.c +++ b/libctf/ctf-hash.c @@ -82,6 +82,28 @@ ctf_hash_eq_string (const void *a, const void *b) return !strcmp((const char *) hep_a->key, (const char *) hep_b->key); } +/* Hash a type_mapping_key. */ +unsigned int +ctf_hash_type_mapping_key (const void *ptr) +{ + ctf_helem_t *hep = (ctf_helem_t *) ptr; + ctf_link_type_mapping_key_t *k = (ctf_link_type_mapping_key_t *) hep->key; + + return htab_hash_pointer (k->cltm_fp) + 59 * htab_hash_pointer ((void *) k->cltm_idx); +} + +int +ctf_hash_eq_type_mapping_key (const void *a, const void *b) +{ + ctf_helem_t *hep_a = (ctf_helem_t *) a; + ctf_helem_t *hep_b = (ctf_helem_t *) b; + ctf_link_type_mapping_key_t *key_a = (ctf_link_type_mapping_key_t *) hep_a->key; + ctf_link_type_mapping_key_t *key_b = (ctf_link_type_mapping_key_t *) hep_b->key; + + return (key_a->cltm_fp == key_b->cltm_fp) + && (key_a->cltm_idx == key_b->cltm_idx); +} + /* The dynhash, used for hashes whose size is not known at creation time. */ /* Free a single ctf_helem. */ @@ -164,7 +186,7 @@ ctf_dynhash_insert (ctf_dynhash_t *hp, void *key, void *value) return errno; /* We need to keep the key_free and value_free around in each item because the - del function has no visiblity into the hash as a whole, only into the + del function has no visibility into the hash as a whole, only into the individual items. */ slot->key_free = hp->key_free; @@ -180,6 +202,12 @@ ctf_dynhash_remove (ctf_dynhash_t *hp, const void *key) htab_remove_elt (hp->htab, &hep); } +void +ctf_dynhash_empty (ctf_dynhash_t *hp) +{ + htab_empty (hp->htab); +} + void * ctf_dynhash_lookup (ctf_dynhash_t *hp, const void *key) { diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 9fb58f59715..c5225549298 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -204,6 +204,17 @@ typedef struct ctf_str_atom_ref uint32_t *caf_ref; /* A single ref to this string. */ } ctf_str_atom_ref_t; +/* The structure used as the key in a ctf_link_type_mapping, which lets the + linker machinery determine which type IDs on the input side of a link map to + which types on the output side. (The value is a ctf_id_t: another + index, not a type.) */ + +typedef struct ctf_link_type_mapping_key +{ + ctf_file_t *cltm_fp; + ctf_id_t cltm_idx; +} ctf_link_type_mapping_key_t; + /* The ctf_file is the structure used to represent a CTF container to library clients, who see it only as an opaque pointer. Modifications can therefore be made freely to this structure without regard to client versioning. The @@ -269,6 +280,7 @@ struct ctf_file ctf_archive_t *ctf_archive; /* Archive this ctf_file_t came from. */ ctf_dynhash_t *ctf_link_inputs; /* Inputs to this link. */ ctf_dynhash_t *ctf_link_outputs; /* Additional outputs from this link. */ + ctf_dynhash_t *ctf_link_type_mapping; /* Map input types to output types. */ char *ctf_tmp_typeslice; /* Storage for slicing up type names. */ size_t ctf_tmp_typeslicelen; /* Size of the typeslice. */ void *ctf_specific; /* Data for ctf_get/setspecific(). */ @@ -328,10 +340,12 @@ extern const ctf_type_t *ctf_lookup_by_id (ctf_file_t **, ctf_id_t); typedef unsigned int (*ctf_hash_fun) (const void *ptr); extern unsigned int ctf_hash_integer (const void *ptr); extern unsigned int ctf_hash_string (const void *ptr); +extern unsigned int ctf_hash_type_mapping_key (const void *ptr); typedef int (*ctf_hash_eq_fun) (const void *, const void *); extern int ctf_hash_eq_integer (const void *, const void *); extern int ctf_hash_eq_string (const void *, const void *); +extern int ctf_hash_eq_type_mapping_key (const void *, const void *); typedef void (*ctf_hash_free_fun) (void *); @@ -349,6 +363,7 @@ extern ctf_dynhash_t *ctf_dynhash_create (ctf_hash_fun, ctf_hash_eq_fun, ctf_hash_free_fun, ctf_hash_free_fun); extern int ctf_dynhash_insert (ctf_dynhash_t *, void *, void *); extern void ctf_dynhash_remove (ctf_dynhash_t *, const void *); +extern void ctf_dynhash_empty (ctf_dynhash_t *); extern void *ctf_dynhash_lookup (ctf_dynhash_t *, const void *); extern void ctf_dynhash_destroy (ctf_dynhash_t *); extern void ctf_dynhash_iter (ctf_dynhash_t *, ctf_hash_iter_f, void *); @@ -371,6 +386,11 @@ extern int ctf_dvd_insert (ctf_file_t *, ctf_dvdef_t *); extern void ctf_dvd_delete (ctf_file_t *, ctf_dvdef_t *); extern ctf_dvdef_t *ctf_dvd_lookup (const ctf_file_t *, const char *); +extern void ctf_add_type_mapping (ctf_file_t *src_fp, ctf_id_t src_type, + ctf_file_t *dst_fp, ctf_id_t dst_type); +extern ctf_id_t ctf_type_mapping (ctf_file_t *src_fp, ctf_id_t src_type, + ctf_file_t **dst_fp); + extern void ctf_decl_init (ctf_decl_t *); extern void ctf_decl_fini (ctf_decl_t *); extern void ctf_decl_push (ctf_decl_t *, ctf_file_t *, ctf_id_t); diff --git a/libctf/ctf-link.c b/libctf/ctf-link.c index 8f18a492716..e10edf2eb41 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -20,6 +20,104 @@ #include #include +/* 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 container 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 container 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_file_t *src_fp, ctf_id_t src_type, + ctf_file_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); + + /* This dynhash is a bit tricky: it has a multivalued (structural) key, so we + need to use the sized-hash machinery to generate key hashing and equality + functions. */ + + if (dst_fp->ctf_link_type_mapping == NULL) + { + ctf_hash_fun f = ctf_hash_type_mapping_key; + ctf_hash_eq_fun e = ctf_hash_eq_type_mapping_key; + + if ((dst_fp->ctf_link_type_mapping = ctf_dynhash_create (f, e, free, + NULL)) == NULL) + return; + } + + ctf_link_type_mapping_key_t *key; + key = calloc (1, sizeof (struct ctf_link_type_mapping_key)); + if (!key) + return; + + key->cltm_fp = src_fp; + key->cltm_idx = src_type; + + 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_file_t *src_fp, ctf_id_t src_type, ctf_file_t **dst_fp) +{ + ctf_link_type_mapping_key_t key; + ctf_file_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.cltm_fp = src_fp; + key.cltm_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 @@ -229,6 +327,17 @@ ctf_link_one_input_archive_member (ctf_file_t *in_fp, const char *name, void *ar 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_file_t *fp = (ctf_file_t *) value; + + if (fp->ctf_link_type_mapping) + ctf_dynhash_empty (fp->ctf_link_type_mapping); +} + /* Link one input file's types into the output file. */ static void ctf_link_one_input_archive (void *key, void *value, void *arg_) @@ -267,6 +376,11 @@ ctf_link_one_input_archive (void *key, void *value, void *arg_) ctf_set_errno (arg->out_fp, 0); } ctf_file_close (arg->main_input_fp); + + /* Discard the now-unnecessary mapping table data. */ + if (arg->out_fp->ctf_link_type_mapping) + ctf_dynhash_empty (arg->out_fp->ctf_link_type_mapping); + ctf_dynhash_iter (arg->out_fp->ctf_link_outputs, empty_link_type_mapping, NULL); } /* Merge types and variable sections in all files added to the link diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 3bc102a37d1..600fe8fcae3 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -1627,6 +1627,7 @@ ctf_file_close (ctf_file_t *fp) ctf_dynhash_destroy (fp->ctf_syn_ext_strtab); ctf_dynhash_destroy (fp->ctf_link_inputs); ctf_dynhash_destroy (fp->ctf_link_outputs); + ctf_dynhash_destroy (fp->ctf_link_type_mapping); ctf_free (fp->ctf_sxlate); ctf_free (fp->ctf_txlate);