]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf, types: ctf_type_kind_{iter,next} et al
authorNick Alcock <nick.alcock@oracle.com>
Thu, 24 Apr 2025 17:00:32 +0000 (18:00 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:43 +0000 (18:07 +0100)
These new functions let you iterate over types by kind, letting you get all
variables, all enums, all datasecs, etc.  (This is amenable to future
optimization, and some is expected shortly.)

We also add new iternal functions ctf_type_kind_{forwarded_,unsliced_,}tp
which are like the corresponding non-_tp functions except that they
take a ctf_type_t rather than a type ID: doing this allows the deduplicator
to use these nearly-public functions more.  The public ctf_type_kind*
functions are reimplemented in terms of these.

This machinery is the principal place where the magic encoding of forwards
is encoded.

include/ctf-api.h
libctf/ctf-impl.h
libctf/ctf-types.c
libctf/libctf.ver

index ac8965fef066a695b9a3a7fc108718820c1ebd74..079c4cf8784256ffe304d955ada96daa9cc2291e 100644 (file)
@@ -310,8 +310,6 @@ _CTF_ERRORS
 
 typedef int ctf_visit_f (const char *name, ctf_id_t type, unsigned long offset,
                         int depth, void *arg);
-typedef int ctf_type_f (ctf_id_t type, void *arg);
-typedef int ctf_type_all_f (ctf_id_t type, int flag, void *arg);
                         void *arg);
 typedef int ctf_member_f (ctf_dict_t *, const char *name, ctf_id_t membtype,
                          size_t offset, int bit_width, void *arg);
@@ -321,6 +319,9 @@ typedef int ctf_variable_f (ctf_dict_t *, const char *name, ctf_id_t type,
                            void *arg);
 typedef int ctf_datasec_var_f (ctf_dict_t *fp, ctf_id_t type, size_t offset,
                               size_t datasec_size, void *arg);
+typedef int ctf_type_f (ctf_dict_t *, ctf_id_t type, void *arg);
+typedef int ctf_type_all_f (ctf_dict_t *, ctf_id_t type, int flag, void *arg);
+typedef int ctf_type_kind_f (ctf_dict_t *, ctf_id_t type, int kind, void *arg);
 typedef int ctf_archive_member_f (ctf_dict_t *fp, const char *name, void *arg);
 typedef int ctf_archive_raw_member_f (const char *name, const void *content,
                                      size_t len, void *arg);
@@ -793,8 +794,10 @@ extern ctf_id_t ctf_arc_lookup_enumerator_next (ctf_archive_t *, const char *nam
 
 extern int ctf_type_iter (ctf_dict_t *, ctf_type_f *, void *);
 extern int ctf_type_iter_all (ctf_dict_t *, ctf_type_all_f *, void *);
+extern int ctf_type_kind_iter (ctf_dict_t *, int kind, ctf_type_kind_f *, void *);
 extern ctf_id_t ctf_type_next (ctf_dict_t *, ctf_next_t **,
                               int *flag, int want_hidden);
+extern ctf_id_t ctf_type_kind_next (ctf_dict_t *, ctf_next_t **, int kind);
 
 extern int ctf_variable_iter (ctf_dict_t *, ctf_variable_f *, void *);
 extern ctf_id_t ctf_variable_next (ctf_dict_t *, ctf_next_t **,
index 49f677b0d65f3f5c5065f27dfa47bc1c8c7cd12c..f0422c05970c6d7ee852b67c5c75c0ee1d7b391e 100644 (file)
@@ -811,6 +811,9 @@ extern char *ctf_str_append_noerr (char *, const char *);
 extern ctf_id_t ctf_type_resolve_unsliced (ctf_dict_t *, ctf_id_t);
 extern ctf_id_t ctf_type_resolve_nonrepresentable (ctf_dict_t *, ctf_id_t, int allow_zero);
 extern int ctf_type_kind_unsliced (ctf_dict_t *, ctf_id_t);
+extern int ctf_type_kind_unsliced_tp (ctf_dict_t *, const ctf_type_t *);
+extern int ctf_type_kind_tp (ctf_dict_t *, const ctf_type_t *);
+extern int ctf_type_kind_forwarded_tp (ctf_dict_t *, const ctf_type_t *);
 extern ssize_t ctf_type_align_natural (ctf_dict_t *fp, ctf_id_t prev_type,
                                       ctf_id_t type, ssize_t bit_offset);
 extern ctf_var_secinfo_t *ctf_datasec_entry (ctf_dict_t *, ctf_id_t,
index 94ecdbeadf6ff924edb2a158e8b8807648756ccc..bb2d652248cec674aab84237446e87eeb7ce8e66 100644 (file)
@@ -489,8 +489,8 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   return NULL;
 }
 
-/* Iterate over every root (user-visible) type in the given CTF dict.
-   We pass the type ID of each type to the specified callback function.
+/* Iterate over every root (user-visible) type in the given CTF dict.  We pass
+   the type ID of each type to the specified callback function.
 
    Does not traverse parent types: you have to do that explicitly.  This is by
    design, to avoid traversing them more than once if traversing many children
@@ -505,7 +505,7 @@ ctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg)
   while ((type = ctf_type_next (fp, &i, NULL, 0)) != CTF_ERR)
     {
       int rc;
-      if ((rc = func (type, arg)) != 0)
+      if ((rc = func (fp, type, arg)) != 0)
        {
          ctf_next_destroy (i);
          return rc;
@@ -517,12 +517,12 @@ ctf_type_iter (ctf_dict_t *fp, ctf_type_f *func, void *arg)
   return 0;
 }
 
-/* Iterate over every type in the given CTF dict, user-visible or not.
-   We pass the type ID of each type to the specified callback function.
+/* Iterate over every type in the given CTF dict, user-visible or not.  We pass
+   the type ID of each type to the specified callback function.
 
    Does not traverse parent types: you have to do that explicitly.  This is by
    design, to avoid traversing them more than once if traversing many children
-   of a single parent.  */
+  of a single parent.  */
 
 int
 ctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg)
@@ -534,7 +534,42 @@ ctf_type_iter_all (ctf_dict_t *fp, ctf_type_all_f *func, void *arg)
   while ((type = ctf_type_next (fp, &i, &flag, 1)) != CTF_ERR)
     {
       int rc;
-      if ((rc = func (type, flag, arg)) != 0)
+      if ((rc = func (fp, type, flag, arg)) != 0)
+       {
+         ctf_next_destroy (i);
+         return rc;
+       }
+    }
+  if (ctf_errno (fp) != ECTF_NEXT_END)
+    return -1;                                 /* errno is set for us.  */
+
+  return 0;
+}
+
+/* Iterate over every type of the given kind in the given CTF dict.
+   We pass the type ID of each type to the specified callback function.
+
+   Types returned may be prefixed (but this is normally invisible): you can also
+   specifically traverse prefixed types by asking for CTF_K_BIG or CTF_K_HIDDEN.
+   In this case, the kind of the type returned will be different (the kind
+   prefixed).  Using CTF_K_BIG may have unexpected results if types have been
+   added to this dict since it was opened, since types are only 'unbiggened'
+   upon being written out.
+
+   Does not traverse parent types: you have to do that explicitly.  This is by
+   design, to avoid traversing them more than once if traversing many children
+   of a single parent.  */
+
+int
+ctf_type_kind_iter (ctf_dict_t *fp, int kind, ctf_type_kind_f *func, void *arg)
+{
+  ctf_next_t *i = NULL;
+  ctf_id_t type;
+
+  while ((type = ctf_type_kind_next (fp, &i, kind)) != CTF_ERR)
+    {
+      int rc;
+      if ((rc = func (fp, type, kind, arg)) != 0)
        {
          ctf_next_destroy (i);
          return rc;
@@ -565,7 +600,7 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
        return ctf_set_typed_errno (fp, ENOMEM);
 
       i->cu.ctn_fp = fp;
-      i->ctn_type = 1;
+      i->i.ctn_idx = 1;
       i->ctn_iter_fun = (void (*) (void)) ctf_type_next;
       *it = i;
     }
@@ -576,19 +611,78 @@ ctf_type_next (ctf_dict_t *fp, ctf_next_t **it, int *flag, int want_hidden)
   if (fp != i->cu.ctn_fp)
     return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
 
-  while (i->ctn_type <= fp->ctf_typemax)
+  while (i->i.ctn_idx <= fp->ctf_typemax)
     {
-      const ctf_type_t *tp = LCTF_INDEX_TO_TYPEPTR (fp, i->ctn_type);
+      const ctf_type_t *tp;
+
+      if (i->i.ctn_idx > fp->ctf_stypes)
+       tp = ctf_dtd_lookup (fp, ctf_index_to_type (fp, i->i.ctn_idx))->dtd_data;
+      else
+       tp = fp->ctf_txlate[i->i.ctn_idx];
 
       if ((!want_hidden) && (!LCTF_INFO_ISROOT (fp, tp->ctt_info)))
        {
-         i->ctn_type++;
+         i->i.ctn_idx++;
          continue;
        }
 
       if (flag)
        *flag = LCTF_INFO_ISROOT (fp, tp->ctt_info);
-      return ctf_index_to_type (fp, i->ctn_type++);
+      return ctf_index_to_type (fp, i->i.ctn_idx++);
+    }
+  ctf_next_destroy (i);
+  *it = NULL;
+  return ctf_set_typed_errno (fp, ECTF_NEXT_END);
+}
+
+/* UPTODO optimize this */
+
+/* Iterate over every type of a given kind in the given CTF dict, returning each
+   type ID in turn.  Returns CTF_ERR on end of iteration or error.  you can also
+   specifically traverse prefixed types by asking for CTF_K_BIG or CTF_K_HIDDEN.
+   In this case, the kind of the type returned will be different (the kind
+   prefixed).  Using CTF_K_BIG may have unexpected results if types have been
+   added to this dict since it was opened, since types are only 'unbiggened'
+   upon being written out.
+
+   Does not traverse parent types: you have to do that explicitly.  This is by
+   design, to avoid traversing them more than once if traversing many children
+   of a single parent.  */
+
+ctf_id_t
+ctf_type_kind_next (ctf_dict_t *fp, ctf_next_t **it, int kind)
+{
+  ctf_next_t *i = *it;
+
+  if (!i)
+    {
+      if ((i = ctf_next_create ()) == NULL)
+       return ctf_set_typed_errno (fp, ENOMEM);
+
+      i->cu.ctn_fp = fp;
+      i->i.ctn_idx = 1;
+      i->ctn_iter_fun = (void (*) (void)) ctf_type_kind_next;
+      *it = i;
+    }
+
+  if ((void (*) (void)) ctf_type_kind_next != i->ctn_iter_fun)
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
+
+  if (fp != i->cu.ctn_fp)
+    return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
+
+  while (i->i.ctn_idx <= fp->ctf_typemax)
+    {
+      ctf_id_t type = ctf_index_to_type (fp, i->i.ctn_idx);
+
+      if (ctf_type_kind (i->cu.ctn_fp, type) != kind)
+       {
+         i->i.ctn_idx++;
+         continue;
+       }
+
+      i->i.ctn_idx++;
+      return type;
     }
   ctf_next_destroy (i);
   *it = NULL;
@@ -1339,17 +1433,84 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
     }
 }
 
-/* Return the kind (CTF_K_* constant) for the specified type ID.  */
+/* Return the kind (CTF_K_* constant) for the specified type pointer.
+   Internal use only.
+
+   Pretend that all forwards are of type CTF_K_FORWARD, for ease of
+   use and compatibility.  */
+
+int
+ctf_type_kind_unsliced_tp (ctf_dict_t *fp, const ctf_type_t *tp)
+{
+  if (LCTF_KIND (fp, tp) == CTF_K_ENUM
+      && LCTF_VLEN (fp, tp) == 0)
+    return CTF_K_FORWARD;
+
+  return (LCTF_KIND (fp, tp));
+}
+
+/* Return the kind (CTF_K_* constant) for the specified type pointer.
+   Slices are considered to be of the same kind as the type sliced.  */
+
+int
+ctf_type_kind_tp (ctf_dict_t *fp, const ctf_type_t *tp)
+{
+  int kind;
+
+  if ((kind = ctf_type_kind_unsliced_tp (fp, tp)) < 0)
+    return -1;                 /* errno is set for us.  */
+
+  if (kind == CTF_K_SLICE)
+    {
+      const ctf_slice_t *sp;
+      ssize_t increment;
+
+      ctf_get_ctt_size (fp, tp, NULL, &increment);
+      sp = (const ctf_slice_t *) tp + increment;
+
+      kind = ctf_type_kind_unsliced (fp, sp->cts_type);
+    }
+
+  return kind;
+}
+
+/* Return the kind of this type pointer, except, for forwards, return the kind
+   of thing this is a forward to.  */
+int
+ctf_type_kind_forwarded_tp (ctf_dict_t *fp, const ctf_type_t *tp)
+{
+  int kind;
+
+  if ((kind = ctf_type_kind_tp (fp, tp)) < 0)
+    return -1;                 /* errno is set for us.  */
+
+  /* Covers forwards to enums, too.  */
+  if (kind != CTF_K_FORWARD)
+    return kind;
+
+  while (LCTF_IS_PREFIXED_INFO (tp->ctt_info))
+    tp++;
+
+  if (CTF_INFO_KFLAG (tp->ctt_info))
+    return CTF_K_UNION;
+  else
+    return CTF_K_STRUCT;
+}
+
+/* Return the kind (CTF_K_* constant) for the specified type ID.
+
+   Pretend that all forwards are of type CTF_K_FORWARD, for ease of
+   use and compatibility.  */
 
 int
 ctf_type_kind_unsliced (ctf_dict_t *fp, ctf_id_t type)
 {
   const ctf_type_t *tp;
 
-  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+  if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
     return -1;                 /* errno is set for us.  */
 
-  return (LCTF_INFO_KIND (fp, tp->ctt_info));
+  return (ctf_type_kind_unsliced_tp (fp, tp));
 }
 
 /* Return the kind (CTF_K_* constant) for the specified type ID.
@@ -1366,7 +1527,7 @@ ctf_type_kind (ctf_dict_t *fp, ctf_id_t type)
   if (kind == CTF_K_SLICE)
     {
       if ((type = ctf_type_reference (fp, type)) == CTF_ERR)
-       return -1;
+       return -1;              /* errno is set for us.  */
       kind = ctf_type_kind_unsliced (fp, type);
     }
 
@@ -1378,19 +1539,17 @@ ctf_type_kind (ctf_dict_t *fp, ctf_id_t type)
 int
 ctf_type_kind_forwarded (ctf_dict_t *fp, ctf_id_t type)
 {
-  int kind;
-  const ctf_type_t *tp;
+  int ret;
+  ctf_dict_t *ofp = fp;
+  const ctf_type_t *tp, *suffix;
 
-  if ((kind = ctf_type_kind (fp, type)) < 0)
+  if ((tp = ctf_lookup_by_id (&fp, type, &suffix)) == NULL)
     return -1;                 /* errno is set for us.  */
 
-  if (kind != CTF_K_FORWARD)
-    return kind;
+  if ((ret = ctf_type_kind_forwarded_tp (fp, tp)) < 0)
+    return (ctf_set_errno (ofp, ctf_errno (fp)));
 
-  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-    return -1;                 /* errno is set for us.  */
-
-  return tp->ctt_type;
+  return ret;
 }
 
 /* If the type is one that directly references another type (such as POINTER),
index 421bf40945b424c7a71d18aa3620ca6f7c81e5b2..605faa3e0e66da3869d94666a8e26c5b52ffc209 100644 (file)
@@ -102,6 +102,8 @@ LIBCTF_2.0 {
        ctf_type_iter;
        ctf_type_next;
        ctf_type_iter_all;
+       ctf_type_kind_iter;
+       ctf_type_kind_next;
        ctf_variable_iter;
        ctf_variable_next;
        ctf_datasec_iter;