]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: generalize the ref system
authorNick Alcock <nick.alcock@oracle.com>
Mon, 13 Jan 2025 15:04:17 +0000 (15:04 +0000)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 28 Feb 2025 15:13:24 +0000 (15:13 +0000)
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).

libctf/ctf-create.c
libctf/ctf-impl.h
libctf/ctf-open.c
libctf/ctf-string.c
libctf/ctf-util.c

index 333b995ad8e649b1784a92753c9376086e5dbb28..ada66a85a7d87d96ed2d5df16eaded43cf93bc4e 100644 (file)
@@ -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)
     {
index 84d9d7eb4044b707a607466ebad3b2d5da220e92..217573a80fe0171d3a80f72e103a39bed7fabfdc 100644 (file)
@@ -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);
 
index 4cf18f0bced5ed6d2fea1de86cf5378720618c8e..f135cab8ffc2263c4afcc46e0d585cd560c1adae 100644 (file)
@@ -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)
index 4a26541166a75ad1be76282a573f50d621c58190..3a5c7eb1bc1bf61abd58281ab663ca519ee0d2e8 100644 (file)
@@ -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)
     {
index d4b668565a1f7a5179478baeca283941f606bd1c..c8dc6f0f567278df6aaccbb60f7e4b030fe15b1b 100644 (file)
@@ -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 *