X-Git-Url: https://repo.jachan.dev/binutils.git/blobdiff_plain/b3adc24a0713411ab38a21dc894dd40dbc5c8f4f..HEAD:/libctf/ctf-string.c diff --git a/libctf/ctf-string.c b/libctf/ctf-string.c index 583679defb..936307cf6e 100644 --- a/libctf/ctf-string.c +++ b/libctf/ctf-string.c @@ -1,5 +1,5 @@ /* CTF string table management. - Copyright (C) 2019-2020 Free Software Foundation, Inc. + Copyright (C) 2019-2022 Free Software Foundation, Inc. This file is part of libctf. @@ -19,11 +19,12 @@ #include #include +#include /* Convert an encoded CTF string name into a pointer to a C string, using an explicit internal strtab rather than the fp-based one. */ const char * -ctf_strraw_explicit (ctf_file_t *fp, uint32_t name, ctf_strs_t *strtab) +ctf_strraw_explicit (ctf_dict_t *fp, uint32_t name, ctf_strs_t *strtab) { ctf_strs_t *ctsp = &fp->ctf_str[CTF_NAME_STID (name)]; @@ -58,7 +59,7 @@ ctf_strraw_explicit (ctf_file_t *fp, uint32_t name, ctf_strs_t *strtab) /* Convert an encoded CTF string name into a pointer to a C string by looking up the appropriate string table buffer and then adding the offset. */ const char * -ctf_strraw (ctf_file_t *fp, uint32_t name) +ctf_strraw (ctf_dict_t *fp, uint32_t name) { return ctf_strraw_explicit (fp, name, NULL); } @@ -66,7 +67,7 @@ ctf_strraw (ctf_file_t *fp, uint32_t name) /* Return a guaranteed-non-NULL pointer to the string with the given CTF name. */ const char * -ctf_strptr (ctf_file_t *fp, uint32_t name) +ctf_strptr (ctf_dict_t *fp, uint32_t name) { const char *s = ctf_strraw (fp, name); return (s != NULL ? s : "(?)"); @@ -99,11 +100,11 @@ ctf_str_free_atom (void *a) /* Create the atoms table. There is always at least one atom in it, the null string. */ int -ctf_str_create_atoms (ctf_file_t *fp) +ctf_str_create_atoms (ctf_dict_t *fp) { fp->ctf_str_atoms = ctf_dynhash_create (ctf_hash_string, ctf_hash_eq_string, free, ctf_str_free_atom); - if (fp->ctf_str_atoms == NULL) + if (!fp->ctf_str_atoms) return -ENOMEM; if (!fp->ctf_prov_strtab) @@ -113,6 +114,13 @@ ctf_str_create_atoms (ctf_file_t *fp) if (!fp->ctf_prov_strtab) goto oom_prov_strtab; + if (!fp->ctf_str_pending_ref) + fp->ctf_str_pending_ref = ctf_dynset_create (htab_hash_pointer, + htab_eq_pointer, + NULL); + if (!fp->ctf_str_pending_ref) + goto oom_str_pending_ref; + errno = 0; ctf_str_add (fp, ""); if (errno == ENOMEM) @@ -123,6 +131,9 @@ ctf_str_create_atoms (ctf_file_t *fp) oom_str_add: ctf_dynhash_destroy (fp->ctf_prov_strtab); fp->ctf_prov_strtab = NULL; + oom_str_pending_ref: + ctf_dynset_destroy (fp->ctf_str_pending_ref); + fp->ctf_str_pending_ref = NULL; oom_prov_strtab: ctf_dynhash_destroy (fp->ctf_str_atoms); fp->ctf_str_atoms = NULL; @@ -131,20 +142,25 @@ ctf_str_create_atoms (ctf_file_t *fp) /* Destroy the atoms table. */ void -ctf_str_free_atoms (ctf_file_t *fp) +ctf_str_free_atoms (ctf_dict_t *fp) { ctf_dynhash_destroy (fp->ctf_prov_strtab); ctf_dynhash_destroy (fp->ctf_str_atoms); + ctf_dynset_destroy (fp->ctf_str_pending_ref); } +#define CTF_STR_ADD_REF 0x1 +#define CTF_STR_MAKE_PROVISIONAL 0x2 +#define CTF_STR_PENDING_REF 0x4 + /* Add a string to the atoms table, copying the passed-in string. Return the atom added. Return NULL only when out of memory (and do not touch the passed-in string in that case). Possibly augment the ref list with the passed-in ref. Possibly add a provisional entry for this string to the provisional strtab. */ static ctf_str_atom_t * -ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, - int add_ref, int make_provisional, uint32_t *ref) +ctf_str_add_ref_internal (ctf_dict_t *fp, const char *str, + int flags, uint32_t *ref) { char *newstr = NULL; ctf_str_atom_t *atom = NULL; @@ -152,7 +168,7 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, atom = ctf_dynhash_lookup (fp->ctf_str_atoms, str); - if (add_ref) + if (flags & CTF_STR_ADD_REF) { if ((aref = malloc (sizeof (struct ctf_str_atom_ref))) == NULL) return NULL; @@ -161,8 +177,9 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, if (atom) { - if (add_ref) + if (flags & CTF_STR_ADD_REF) { + ctf_dynset_remove (fp->ctf_str_pending_ref, (void *) ref); ctf_list_append (&atom->csa_refs, aref); fp->ctf_str_num_refs++; } @@ -182,7 +199,7 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, atom->csa_str = newstr; atom->csa_snapshot_id = fp->ctf_snapshots; - if (make_provisional) + if (flags & CTF_STR_MAKE_PROVISIONAL) { atom->csa_offset = fp->ctf_str_prov_offset; @@ -193,8 +210,14 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, fp->ctf_str_prov_offset += strlen (atom->csa_str) + 1; } - if (add_ref) + if (flags & CTF_STR_PENDING_REF) { + if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) ref) < 0) + goto oom; + } + else if (flags & CTF_STR_ADD_REF) + { + ctf_dynset_remove (fp->ctf_str_pending_ref, (void *) ref); ctf_list_append (&atom->csa_refs, aref); fp->ctf_str_num_refs++; } @@ -206,6 +229,7 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, free (atom); free (aref); free (newstr); + ctf_set_errno (fp, ENOMEM); return NULL; } @@ -215,13 +239,14 @@ ctf_str_add_ref_internal (ctf_file_t *fp, const char *str, provisional offset is assigned to should be added as a ref using ctf_str_add_ref() as well.) */ uint32_t -ctf_str_add (ctf_file_t *fp, const char *str) +ctf_str_add (ctf_dict_t *fp, const char *str) { ctf_str_atom_t *atom; + if (!str) - return 0; + str = ""; - atom = ctf_str_add_ref_internal (fp, str, FALSE, TRUE, 0); + atom = ctf_str_add_ref_internal (fp, str, CTF_STR_MAKE_PROVISIONAL, 0); if (!atom) return 0; @@ -232,39 +257,97 @@ ctf_str_add (ctf_file_t *fp, const char *str) passed-in ref, whether or not the string is already present. There is no attempt to deduplicate the refs list (but duplicates are harmless). */ uint32_t -ctf_str_add_ref (ctf_file_t *fp, const char *str, uint32_t *ref) +ctf_str_add_ref (ctf_dict_t *fp, const char *str, uint32_t *ref) { ctf_str_atom_t *atom; + if (!str) + str = ""; + + atom = ctf_str_add_ref_internal (fp, str, CTF_STR_ADD_REF + | CTF_STR_MAKE_PROVISIONAL, ref); + if (!atom) return 0; - atom = ctf_str_add_ref_internal (fp, str, TRUE, TRUE, ref); + return atom->csa_offset; +} + +/* Like ctf_str_add_ref(), but notes that this memory location must be added as + a ref by a later serialization phase, rather than adding it itself. */ +uint32_t +ctf_str_add_pending (ctf_dict_t *fp, const char *str, uint32_t *ref) +{ + ctf_str_atom_t *atom; + + if (!str) + str = ""; + + atom = ctf_str_add_ref_internal (fp, str, CTF_STR_PENDING_REF + | CTF_STR_MAKE_PROVISIONAL, ref); if (!atom) return 0; return atom->csa_offset; } +/* Note that a pending ref now located at NEW_REF has moved by BYTES bytes. */ +int +ctf_str_move_pending (ctf_dict_t *fp, uint32_t *new_ref, ptrdiff_t bytes) +{ + if (bytes == 0) + return 0; + + if (ctf_dynset_insert (fp->ctf_str_pending_ref, (void *) new_ref) < 0) + return (ctf_set_errno (fp, ENOMEM)); + + ctf_dynset_remove (fp->ctf_str_pending_ref, + (void *) ((signed char *) new_ref - bytes)); + return 0; +} + /* Add an external strtab reference at OFFSET. Returns zero if the addition failed, nonzero otherwise. */ int -ctf_str_add_external (ctf_file_t *fp, const char *str, uint32_t offset) +ctf_str_add_external (ctf_dict_t *fp, const char *str, uint32_t offset) { ctf_str_atom_t *atom; + if (!str) - return 0; + str = ""; - atom = ctf_str_add_ref_internal (fp, str, FALSE, FALSE, 0); + atom = ctf_str_add_ref_internal (fp, str, 0, 0); if (!atom) return 0; atom->csa_external_offset = CTF_SET_STID (offset, CTF_STRTAB_1); + + if (!fp->ctf_syn_ext_strtab) + fp->ctf_syn_ext_strtab = ctf_dynhash_create (ctf_hash_integer, + ctf_hash_eq_integer, + NULL, NULL); + if (!fp->ctf_syn_ext_strtab) + { + ctf_set_errno (fp, ENOMEM); + return 0; + } + + if (ctf_dynhash_insert (fp->ctf_syn_ext_strtab, + (void *) (uintptr_t) + atom->csa_external_offset, + (void *) atom->csa_str) < 0) + { + /* No need to bother freeing the syn_ext_strtab: it will get freed at + ctf_str_write_strtab time if unreferenced. */ + ctf_set_errno (fp, ENOMEM); + return 0; + } + return 1; } /* Remove a single ref. */ void -ctf_str_remove_ref (ctf_file_t *fp, const char *str, uint32_t *ref) +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; @@ -282,22 +365,27 @@ ctf_str_remove_ref (ctf_file_t *fp, const char *str, uint32_t *ref) free (aref); } } + + ctf_dynset_remove (fp->ctf_str_pending_ref, (void *) ref); } /* A ctf_dynhash_iter_remove() callback that removes atoms later than a given - snapshot ID. */ + snapshot ID. External atoms are never removed, because they came from the + linker string table and are still present even if you roll back type + additions. */ static int ctf_str_rollback_atom (void *key _libctf_unused_, void *value, void *arg) { ctf_str_atom_t *atom = (ctf_str_atom_t *) value; ctf_snapshot_id_t *id = (ctf_snapshot_id_t *) arg; - return (atom->csa_snapshot_id > id->snapshot_id); + return (atom->csa_snapshot_id > id->snapshot_id) + && (atom->csa_external_offset == 0); } -/* Roll back, deleting all atoms created after a particular ID. */ +/* Roll back, deleting all (internal) atoms created after a particular ID. */ void -ctf_str_rollback (ctf_file_t *fp, ctf_snapshot_id_t id) +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); } @@ -313,7 +401,7 @@ ctf_str_purge_one_atom_refs (void *key _libctf_unused_, void *value, /* Remove all the recorded refs from the atoms table. */ void -ctf_str_purge_refs (ctf_file_t *fp) +ctf_str_purge_refs (ctf_dict_t *fp) { if (fp->ctf_str_num_refs > 0) ctf_dynhash_iter (fp->ctf_str_atoms, ctf_str_purge_one_atom_refs, NULL); @@ -410,7 +498,7 @@ ctf_str_sort_strtab (const void *a, const void *b) external strtab offsets to names, so we can look them up with ctf_strptr(). Only external strtab offsets with references are added. */ ctf_strs_writable_t -ctf_str_write_strtab (ctf_file_t *fp) +ctf_str_write_strtab (ctf_dict_t *fp) { ctf_strs_writable_t strtab; ctf_str_atom_t *nullstr; @@ -427,7 +515,7 @@ ctf_str_write_strtab (ctf_file_t *fp) nullstr = ctf_dynhash_lookup (fp->ctf_str_atoms, ""); if (!nullstr) { - ctf_dprintf ("Internal error: null string not found in strtab.\n"); + ctf_err_warn (fp, 0, ECTF_INTERNAL, _("null string not found in strtab")); strtab.cts_strs = NULL; return strtab; } @@ -455,32 +543,15 @@ ctf_str_write_strtab (ctf_file_t *fp) if ((strtab.cts_strs = malloc (strtab.cts_len)) == NULL) goto oom_sorttab; - if (!fp->ctf_syn_ext_strtab) - fp->ctf_syn_ext_strtab = ctf_dynhash_create (ctf_hash_integer, - ctf_hash_eq_integer, - NULL, NULL); - if (!fp->ctf_syn_ext_strtab) - goto oom_strtab; - /* Update all refs: also update the strtab appropriately. */ for (i = 0; i < s.strtab_count; i++) { if (sorttab[i]->csa_external_offset) { - /* External strtab entry: populate the synthetic external strtab. - - This is safe because you cannot ctf_rollback to before the point - when a ctf_update is done, and the strtab is written at ctf_update - time. So any atoms we reference here are sure to stick around - until ctf_file_close. */ + /* External strtab entry. */ any_external = 1; ctf_str_update_refs (sorttab[i], sorttab[i]->csa_external_offset); - if (ctf_dynhash_insert (fp->ctf_syn_ext_strtab, - (void *) (uintptr_t) - sorttab[i]->csa_external_offset, - (void *) sorttab[i]->csa_str) < 0) - goto oom_strtab; sorttab[i]->csa_offset = sorttab[i]->csa_external_offset; } else @@ -510,9 +581,6 @@ ctf_str_write_strtab (ctf_file_t *fp) fp->ctf_str_prov_offset = strtab.cts_len + 1; return strtab; - oom_strtab: - free (strtab.cts_strs); - strtab.cts_strs = NULL; oom_sorttab: free (sorttab); oom: