From: Nick Alcock Date: Mon, 13 Jan 2025 15:04:17 +0000 (+0000) Subject: libctf: generalize the ref system X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9835747b21aa065804d3bdcf37a5dbb88ac46992;p=thirdparty%2Fbinutils-gdb.git 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). --- diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index 333b995ad8e..ada66a85a7d 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -1118,7 +1118,7 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name, /* Remove refs in the old vlen region and reapply them. */ - ctf_str_move_refs (fp, old_vlen, sizeof (ctf_enum_t) * vlen, dtd->dtd_vlen); + ctf_move_refs (fp, old_vlen, sizeof (ctf_enum_t) * vlen, dtd->dtd_vlen); /* Check for constant duplication within any given enum: only needed for non-root-visible types, since the duplicate detection above does the job @@ -1209,7 +1209,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, /* Remove refs in the old vlen region and reapply them. */ - ctf_str_move_refs (fp, old_vlen, sizeof (ctf_lmember_t) * vlen, dtd->dtd_vlen); + ctf_move_refs (fp, old_vlen, sizeof (ctf_lmember_t) * vlen, dtd->dtd_vlen); if (name != NULL) { diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 84d9d7eb404..217573a80fe 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -228,13 +228,13 @@ typedef struct ctf_str_atom int csa_flags; /* CTF_STR_ATOM_* flags. */ } ctf_str_atom_t; -/* The refs of a single string in the atoms table. */ +/* A single ref. */ -typedef struct ctf_str_atom_ref +typedef struct ctf_ref { - ctf_list_t caf_list; /* List forward/back pointers. */ - uint32_t *caf_ref; /* A single ref to this string. */ -} ctf_str_atom_ref_t; + ctf_list_t cre_list; /* List forward/back pointers. */ + uint32_t *cre_ref; /* A single ref to this string. */ +} ctf_ref_t; /* A single linker-provided symbol, during symbol addition, possibly before we have been given external strtab refs. */ @@ -392,7 +392,7 @@ struct ctf_dict ctf_strs_t ctf_str[2]; /* Array of string table base and bounds. */ ctf_strs_writable_t *ctf_dynstrtab; /* Dynamically allocated string table, if any. */ ctf_dynhash_t *ctf_str_atoms; /* Hash table of ctf_str_atoms_t. */ - ctf_dynhash_t *ctf_str_movable_refs; /* Hash table of void * -> ctf_str_atom_ref_movable_t. */ + ctf_dynhash_t *ctf_movable_refs; /* Hash table of void * -> ctf_ref_t. */ uint32_t ctf_str_prov_offset; /* Latest provisional offset assigned so far. */ unsigned char *ctf_base; /* CTF file pointer. */ unsigned char *ctf_dynbase; /* Freeable CTF file pointer. */ @@ -765,13 +765,21 @@ extern uint32_t ctf_str_add_no_dedup_ref (ctf_dict_t *, const char *, uint32_t *ref); extern uint32_t ctf_str_add_movable_ref (ctf_dict_t *, const char *, uint32_t *ref); -extern int ctf_str_move_refs (ctf_dict_t *fp, void *src, size_t len, void *dest); extern int ctf_str_add_external (ctf_dict_t *, const char *, uint32_t offset); extern void ctf_str_remove_ref (ctf_dict_t *, const char *, uint32_t *ref); extern void ctf_str_purge_refs (ctf_dict_t *fp); extern void ctf_str_rollback (ctf_dict_t *, ctf_snapshot_id_t); extern const ctf_strs_writable_t *ctf_str_write_strtab (ctf_dict_t *); +extern int ctf_init_refs (ctf_dict_t *); +extern void ctf_free_refs (ctf_dict_t *); +extern ctf_ref_t *ctf_create_ref (ctf_dict_t *, ctf_list_t *, uint32_t *ref, + int movable); +extern void ctf_remove_ref (ctf_dict_t *fp, ctf_list_t *, uint32_t *ref); +extern int ctf_move_refs (ctf_dict_t *fp, void *src, size_t len, void *dest); +extern void ctf_purge_ref_list (ctf_dict_t *, ctf_list_t *); +extern void ctf_update_refs (ctf_list_t *, uint32_t value); + extern int ctf_preserialize (ctf_dict_t *fp); extern void ctf_depreserialize (ctf_dict_t *fp); diff --git a/libctf/ctf-open.c b/libctf/ctf-open.c index 4cf18f0bced..f135cab8ffc 100644 --- a/libctf/ctf-open.c +++ b/libctf/ctf-open.c @@ -1798,7 +1798,7 @@ ctf_bufopen (const ctf_sect_t *ctfsect, const ctf_sect_t *symsect, fp->ctf_str[CTF_STRTAB_0].cts_strs = (const char *) fp->ctf_buf + hp->cth_stroff; fp->ctf_str[CTF_STRTAB_0].cts_len = hp->cth_strlen; - if (ctf_str_create_atoms (fp) < 0) + if (ctf_init_refs (fp) < 0 || ctf_str_create_atoms (fp) < 0) { err = ENOMEM; goto bad; @@ -2032,6 +2032,7 @@ ctf_dict_close (ctf_dict_t *fp) ctf_dynhash_destroy (fp->ctf_link_out_cu_mapping); ctf_str_free_atoms (fp); + ctf_free_refs (fp); free (fp->ctf_tmp_typeslice); if (fp->ctf_data.cts_name != _CTF_NULLSTR) diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c index 4a26541166a..3a5c7eb1bc1 100644 --- a/libctf/ctf-string.c +++ b/libctf/ctf-string.c @@ -154,21 +154,6 @@ ctf_strptr_validate (ctf_dict_t *fp, uint32_t name) return str; } -/* Remove all refs to a given atom. */ -static void -ctf_str_purge_atom_refs (ctf_dict_t *fp, ctf_str_atom_t *atom) -{ - ctf_str_atom_ref_t *ref, *next; - - for (ref = ctf_list_next (&atom->csa_refs); ref != NULL; ref = next) - { - next = ctf_list_next (ref); - ctf_list_delete (&atom->csa_refs, ref); - ctf_dynhash_remove (fp->ctf_str_movable_refs, ref); - free (ref); - } -} - /* Free an atom. */ static void ctf_str_free_atom (void *a, void *fp_) @@ -176,7 +161,7 @@ ctf_str_free_atom (void *a, void *fp_) ctf_str_atom_t *atom = a; ctf_dict_t *fp = fp_; - ctf_str_purge_atom_refs (fp, atom); + ctf_purge_ref_list (fp, &atom->csa_refs); if (atom->csa_flags & CTF_STR_ATOM_FREEABLE) free (atom->csa_str); @@ -212,12 +197,6 @@ ctf_str_create_atoms (ctf_dict_t *fp) if (!fp->ctf_prov_strtab) goto oom_prov_strtab; - fp->ctf_str_movable_refs = ctf_dynhash_create (ctf_hash_integer, - ctf_hash_eq_integer, - NULL, NULL); - if (!fp->ctf_str_movable_refs) - goto oom_movable_refs; - errno = 0; ctf_str_add (fp, ""); if (errno == ENOMEM) @@ -252,9 +231,6 @@ ctf_str_create_atoms (ctf_dict_t *fp) return 0; oom_str_add: - ctf_dynhash_destroy (fp->ctf_str_movable_refs); - fp->ctf_str_movable_refs = NULL; - oom_movable_refs: ctf_dynhash_destroy (fp->ctf_prov_strtab); fp->ctf_prov_strtab = NULL; oom_prov_strtab: @@ -269,7 +245,6 @@ ctf_str_free_atoms (ctf_dict_t *fp) { ctf_dynhash_destroy (fp->ctf_prov_strtab); ctf_dynhash_destroy (fp->ctf_str_atoms); - ctf_dynhash_destroy (fp->ctf_str_movable_refs); if (fp->ctf_dynstrtab) { free (fp->ctf_dynstrtab->cts_strs); @@ -283,37 +258,6 @@ ctf_str_free_atoms (ctf_dict_t *fp) #define CTF_STR_COPY 0x8 #define CTF_STR_NO_DEDUP 0x10 -/* Allocate a ref and bind it into a ref list. */ - -static ctf_str_atom_ref_t * -aref_create (ctf_dict_t *fp, ctf_str_atom_t *atom, uint32_t *ref, int flags) -{ - ctf_str_atom_ref_t *aref; - - aref = malloc (sizeof (struct ctf_str_atom_ref)); - - if (!aref) - return NULL; - - aref->caf_ref = ref; - - /* Movable refs get a backpointer to them in ctf_str_movable_refs: they can be - moved later in batches via a call to ctf_str_move_refs. */ - - if (flags & CTF_STR_MOVABLE) - { - if (ctf_dynhash_insert (fp->ctf_str_movable_refs, ref, aref) < 0) - { - free (aref); - return NULL; - } - } - - ctf_list_append (&atom->csa_refs, aref); - - return aref; -} - /* Add a string to the atoms table, copying the passed-in string if necessary. Return the atom added. Return NULL only when out of memory (and do not touch the passed-in string in that case). @@ -357,7 +301,8 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str, if (flags & CTF_STR_ADD_REF) { - if (!aref_create (fp, atom, ref, flags)) + if (!ctf_create_ref (fp, &atom->csa_refs, ref, + flags & CTF_STR_MOVABLE)) { ctf_set_errno (fp, ENOMEM); return NULL; @@ -429,7 +374,7 @@ ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str, if (flags & CTF_STR_ADD_REF) { - if (!aref_create (fp, atom, ref, flags)) + if (!ctf_create_ref (fp, &atom->csa_refs, ref, flags & CTF_STR_MOVABLE)) goto oom; } } @@ -559,62 +504,17 @@ ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset) return 1; } -/* 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_str_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_str_atom_ref_t *ref; - - if ((ref = ctf_dynhash_lookup (fp->ctf_str_movable_refs, - (ctf_str_atom_ref_t *) p)) != NULL) - { - int out_of_memory; - - ref->caf_ref = (uint32_t *) (((uintptr_t) ref->caf_ref + - (uintptr_t) dest - (uintptr_t) src)); - ctf_dynhash_remove (fp->ctf_str_movable_refs, - (ctf_str_atom_ref_t *) p); - out_of_memory = ctf_dynhash_insert (fp->ctf_str_movable_refs, - ref->caf_ref, ref); - assert (out_of_memory == 0); - } - } - - return 0; -} - -/* Remove a single ref. */ +/* Remove a single ref to a string. */ void ctf_str_remove_ref (ctf_dict_t *fp, const char *str, uint32_t *ref) { - ctf_str_atom_ref_t *aref, *anext; ctf_str_atom_t *atom = NULL; atom = ctf_dynhash_lookup (fp->ctf_str_atoms, str); if (!atom) return; - for (aref = ctf_list_next (&atom->csa_refs); aref != NULL; aref = anext) - { - anext = ctf_list_next (aref); - if (aref->caf_ref == ref) - { - ctf_list_delete (&atom->csa_refs, aref); - ctf_dynhash_remove (fp->ctf_str_movable_refs, ref); - free (aref); - } - } + ctf_remove_ref (fp, &atom->csa_refs, ref); } /* A ctf_dynhash_iter_remove() callback that removes atoms later than a given @@ -638,7 +538,7 @@ ctf_str_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id) ctf_dynhash_iter_remove (fp->ctf_str_atoms, ctf_str_rollback_atom, &id); } -/* An adaptor around ctf_purge_atom_refs. */ +/* An adaptor around ctf_purge_ref_list. */ static void ctf_str_purge_one_atom_refs (void *key _libctf_unused_, void *value, void *arg) @@ -646,7 +546,7 @@ ctf_str_purge_one_atom_refs (void *key _libctf_unused_, void *value, ctf_str_atom_t *atom = (ctf_str_atom_t *) value; ctf_dict_t *fp = (ctf_dict_t *) arg; - ctf_str_purge_atom_refs (fp, atom); + ctf_purge_ref_list (fp, &atom->csa_refs); } /* Remove all the recorded refs from the atoms table. */ @@ -656,17 +556,6 @@ ctf_str_purge_refs (ctf_dict_t *fp) ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_purge_one_atom_refs, fp); } -/* Update a list of refs to the specified value. */ -static void -ctf_str_update_refs (ctf_str_atom_t *refs, uint32_t value) -{ - ctf_str_atom_ref_t *ref; - - for (ref = ctf_list_next (&refs->csa_refs); ref != NULL; - ref = ctf_list_next (ref)) - *(ref->caf_ref) = value; -} - /* Sort the strtab. */ static int ctf_str_sort_strtab (const void *a, const void *b) @@ -893,7 +782,7 @@ ctf_str_write_strtab (ctf_dict_t *fp) offset = atom->csa_offset + fp->ctf_header->cth_parent_strlen; } - ctf_str_update_refs (atom, offset); + ctf_update_refs (&atom->csa_refs, offset); } if (err != ECTF_NEXT_END) { diff --git a/libctf/ctf-util.c b/libctf/ctf-util.c index d4b668565a1..c8dc6f0f567 100644 --- a/libctf/ctf-util.c +++ b/libctf/ctf-util.c @@ -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 *