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.
This commit is contained in:
Nick Alcock 2019-07-13 21:31:26 +01:00
parent 72c83edd92
commit 886453cbbc
6 changed files with 202 additions and 4 deletions

View File

@ -1,3 +1,24 @@
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.

View File

@ -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;
}

View File

@ -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)
{

View File

@ -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);

View File

@ -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

View File

@ -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);