diff options
-rw-r--r-- | libctf/ChangeLog | 21 | ||||
-rw-r--r-- | libctf/ctf-create.c | 20 | ||||
-rw-r--r-- | libctf/ctf-hash.c | 30 | ||||
-rw-r--r-- | libctf/ctf-impl.h | 20 | ||||
-rw-r--r-- | libctf/ctf-link.c | 114 | ||||
-rw-r--r-- | libctf/ctf-open.c | 1 |
6 files changed, 202 insertions, 4 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog index 959a038..7dc32b8 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,26 @@ 2019-07-13 Nick Alcock <nick.alcock@oracle.com> + * 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 <nick.alcock@oracle.com> + * ctf-link.c: New file, linking of the string and type sections. * Makefile.am (libctf_a_SOURCES): Add it. * Makefile.in: Regenerate. diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index fc37d6a..90e45f3 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 3512d22..c6233eb 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 9fb58f5..c522554 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 8f18a49..e10edf2 100644 --- a/libctf/ctf-link.c +++ b/libctf/ctf-link.c @@ -20,6 +20,104 @@ #include <ctf-impl.h> #include <string.h> +/* 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 3bc102a..600fe8f 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); |