forked from Imagelibrary/binutils-gdb
libctf: generalize the ref system
Despite the removal of the separate movable ref list, the ref system as a whole is more than complex enough to be worth generalizing now that we are adding different kinds of ref. Refs now are lists of uint32_t * which can be updated through the pointer for all entries in the list and moved to new sites for all pointers in a given range: they are no longer references to string offsets in particular and can be references to other uint32_t-sized things instead (note that ctf_id_t is a typedef to a uint32_t). ctf-string.c has been adjusted accordingly (the adjustments are tiny, more or less just turning a bunch of references to atom into &atom->csa_refs).
This commit is contained in:
@@ -146,6 +146,136 @@ ctf_str_append_noerr (char *s, const char *append)
|
||||
return new_s;
|
||||
}
|
||||
|
||||
/* Initialize the ref system. */
|
||||
int
|
||||
ctf_init_refs (ctf_dict_t *fp)
|
||||
{
|
||||
fp->ctf_movable_refs = ctf_dynhash_create (ctf_hash_integer,
|
||||
ctf_hash_eq_integer,
|
||||
NULL, NULL);
|
||||
if (!fp->ctf_movable_refs)
|
||||
return -ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
/* Destroy the ref system. */
|
||||
void
|
||||
ctf_free_refs (ctf_dict_t *fp)
|
||||
{
|
||||
ctf_dynhash_destroy (fp->ctf_movable_refs);
|
||||
}
|
||||
|
||||
/* Allocate a ref and bind it into a ref list. Does not actually
|
||||
initialize anything through the ref: the caller must do that. */
|
||||
|
||||
ctf_ref_t *
|
||||
ctf_create_ref (ctf_dict_t *fp, ctf_list_t *reflist, uint32_t *ref, int movable)
|
||||
{
|
||||
ctf_ref_t *aref;
|
||||
|
||||
aref = malloc (sizeof (struct ctf_ref));
|
||||
|
||||
if (!aref)
|
||||
return NULL;
|
||||
|
||||
aref->cre_ref = ref;
|
||||
|
||||
/* Movable refs get a backpointer to them in ctf_movable_refs: they can be
|
||||
moved later in batches via a call to ctf_move_refs. */
|
||||
|
||||
if (movable)
|
||||
{
|
||||
if (ctf_dynhash_insert (fp->ctf_movable_refs, ref, aref) < 0)
|
||||
{
|
||||
free (aref);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ctf_list_append (reflist, aref);
|
||||
|
||||
return aref;
|
||||
}
|
||||
|
||||
/* Note that refs have moved from (SRC, LEN) to DEST. We use the movable
|
||||
refs backpointer for this, because it is done an amortized-constant
|
||||
number of times during structure member and enumerand addition, and if we
|
||||
did a linear search this would turn such addition into an O(n^2)
|
||||
operation. */
|
||||
int
|
||||
ctf_move_refs (ctf_dict_t *fp, void *src, size_t len, void *dest)
|
||||
{
|
||||
uintptr_t p;
|
||||
|
||||
if (src == dest)
|
||||
return 0;
|
||||
|
||||
for (p = (uintptr_t) src; p - (uintptr_t) src < len; p++)
|
||||
{
|
||||
ctf_ref_t *ref;
|
||||
|
||||
if ((ref = ctf_dynhash_lookup (fp->ctf_movable_refs,
|
||||
(ctf_ref_t *) p)) != NULL)
|
||||
{
|
||||
int out_of_memory;
|
||||
|
||||
ref->cre_ref = (uint32_t *) (((uintptr_t) ref->cre_ref +
|
||||
(uintptr_t) dest - (uintptr_t) src));
|
||||
ctf_dynhash_remove (fp->ctf_movable_refs, (ctf_ref_t *) p);
|
||||
out_of_memory = ctf_dynhash_insert (fp->ctf_movable_refs,
|
||||
ref->cre_ref, ref);
|
||||
assert (out_of_memory == 0);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a single ref. */
|
||||
void
|
||||
ctf_remove_ref (ctf_dict_t *fp, ctf_list_t *reflist, uint32_t *ref)
|
||||
{
|
||||
ctf_ref_t *aref, *anext;
|
||||
|
||||
for (aref = ctf_list_next (reflist); aref != NULL; aref = anext)
|
||||
{
|
||||
anext = ctf_list_next (aref);
|
||||
if (aref->cre_ref == ref)
|
||||
{
|
||||
ctf_list_delete (reflist, aref);
|
||||
ctf_dynhash_remove (fp->ctf_movable_refs, ref);
|
||||
free (aref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Remove all refs to a given entity. */
|
||||
void
|
||||
ctf_purge_ref_list (ctf_dict_t *fp, ctf_list_t *reflist)
|
||||
{
|
||||
ctf_ref_t *ref, *next;
|
||||
|
||||
for (ref = ctf_list_next (reflist); ref != NULL; ref = next)
|
||||
{
|
||||
next = ctf_list_next (ref);
|
||||
ctf_list_delete (reflist, ref);
|
||||
ctf_dynhash_remove (fp->ctf_movable_refs, ref);
|
||||
free (ref);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Update a list of refs to the specified value. */
|
||||
void
|
||||
ctf_update_refs (ctf_list_t *reflist, uint32_t value)
|
||||
{
|
||||
ctf_ref_t *ref;
|
||||
|
||||
for (ref = ctf_list_next (reflist); ref != NULL;
|
||||
ref = ctf_list_next (ref))
|
||||
*(ref->cre_ref) = value;
|
||||
}
|
||||
|
||||
/* Create a ctf_next_t. */
|
||||
|
||||
ctf_next_t *
|
||||
|
||||
Reference in New Issue
Block a user