]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf, create, types: type and decl tags
authorNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 10:14:09 +0000 (11:14 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:43 +0000 (18:07 +0100)
These are a little more fiddly than previous kinds, because their
namespacing rules are odd: they have names (so presumably we want an API to
look them up by name), but the names are not unique (they don't need to be,
because they are not entities you can refer to from C), so many distinct
tags in the same TU can have the same name.  Type tags only refer to a type
ID: decl tags refer to a specific function parameter or structure member via
a zero-indexed "component index".

The name tables for these things are a hash of name to a set of type IDs;
rather different from all the other named entities in libctf.  As a
consequence, they can presently be looked up only using their own dedicated
functions, not using ctf_lookup_by_name et al.  (It's not clear if this
restriction could ever be lifted: ctf_lookup_by_name and friends return a
type ID, not a set of them.)

They are similar enough to each other that we can at least have one function
to look up both type and decl tags if you don't care about their
component_idx and only want a type ID: ctf_tag.  (And one to iterate over
them, ctf_tag_next).

(A caveat: because tags aren't widely used or generated yet, much of this is
more or less untested and/or supposition and will need testing later.)

New API, more or less the minimum needed because it's not entirely clear how
these things will be used:

+ctf_id_t ctf_tag (ctf_dict_t *, ctf_id_t tag);
+ctf_id_t ctf_decl_tag (ctf_dict_t *, ctf_id_t decl_tag,
+        int64_t *component_idx);
+ctf_id_t ctf_tag_next (ctf_dict_t *, const char *tag, ctf_next_t **);
+ctf_id_t ctf_add_type_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *);
+ctf_id_t ctf_add_decl_type_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *);
+ctf_id_t ctf_add_decl_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *,
+    int component_idx);

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

index 92b602df4f21ab706235d2f043e093b90ef5f86b..e986cadee091a61fbea8065397cff1a73e162c59 100644 (file)
@@ -253,13 +253,17 @@ typedef struct ctf_snapshot_id
   _CTF_ITEM (ECTF_HASPARENT, "Cannot ctf_import: dict already has a parent.") \
   _CTF_ITEM (ECTF_WRONGPARENT, "Cannot ctf_import: incorrect parent provided.") \
   _CTF_ITEM (ECTF_NOTSERIALIZED, "CTF dict must be serialized first.") \
+  _CTF_ITEM (ECTF_BADCOMPONENT, "Declaration tag component_idx is invalid.") \
   _CTF_ITEM (ECTF_NOTBITSOU, "Type is not a bitfield-capable struct or union.") \
   _CTF_ITEM (ECTF_DESCENDING, "Structure offsets may not descend.") \
   _CTF_ITEM (ECTF_LINKAGE, "Invalid linkage.") \
   _CTF_ITEM (ECTF_LINKKIND, "Only functions and variables have linkage.") \
+  _CTF_ITEM (ECTF_NEVERTAG, "Cannot call this function with a tag kind.") \
   _CTF_ITEM (ECTF_NOTDATASEC, "This function requires a datasec.") \
   _CTF_ITEM (ECTF_NOTVAR, "This function requires a variable.") \
   _CTF_ITEM (ECTF_NODATASEC, "Variable not found in datasec.") \
+  _CTF_ITEM (ECTF_NOTDECLTAG, "This function requires a decl tag.") \
+  _CTF_ITEM (ECTF_NOTTAG, "This function requires a type or decl tag.") \
 
 #define        ECTF_BASE       1000    /* Base value for libctf errnos.  */
 
@@ -745,6 +749,20 @@ extern ctf_id_t ctf_datasec_var_offset (ctf_dict_t *fp, ctf_id_t datasec,
 
 extern ctf_id_t ctf_variable_datasec (ctf_dict_t *fp, ctf_id_t var);
 
+/* Type and decl tags.  */
+
+/* Return the type ID of the type to which a given type tag is attached, or of
+   the type of the declaration to which a decl tag is attached (so a decl tag on
+   a function parameter would return the type ID of the parameter's type).  */
+
+extern ctf_id_t ctf_tag (ctf_dict_t *, ctf_id_t tag);
+
+/* Return the component ID and declaration to which a decl tag is attached.
+   -1 means "whole type".  */
+
+extern ctf_id_t ctf_decl_tag (ctf_dict_t *, ctf_id_t decl_tag,
+                             int64_t *component_idx);
+
 /* Iterators.  */
 
 /* ctf_member_next is a _next-style iterator that can additionally traverse into
@@ -817,6 +835,9 @@ extern int ctf_datasec_var_iter (ctf_dict_t *, ctf_id_t, ctf_datasec_var_f *,
 extern ctf_id_t ctf_datasec_var_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
                                      size_t *size, size_t *offset);
 
+/* Iterate over all tags with the given TAG, returning the ID of each tag.  */
+extern ctf_id_t ctf_tag_next (ctf_dict_t *, const char *tag, ctf_next_t **);
+
 /* ctf_archive_iter and ctf_archive_next open each member dict for you,
    automatically importing any parent dict as usual: ctf_archive_iter closes the
    dict on return from ctf_archive_member_f, but for ctf_archive_next the caller
@@ -920,6 +941,14 @@ extern ctf_id_t ctf_add_typedef (ctf_dict_t *, uint32_t, const char *,
                                 ctf_id_t);
 extern ctf_id_t ctf_add_restrict (ctf_dict_t *, uint32_t, ctf_id_t);
 
+/* Add type and decl tags to whole types or (for decl tags) specific
+   components of types (parameter count for functions, member count for structs
+   and unions).  */
+extern ctf_id_t ctf_add_type_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *);
+extern ctf_id_t ctf_add_decl_type_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *);
+extern ctf_id_t ctf_add_decl_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *,
+                                 int component_idx);
+
 /* Struct and union addition.  Straight addition uses possibly-confusing rules
    to guess the final size of the struct/union given its members: to explicitly
    state the size of the struct or union (to report compiler-generated padding,
index 25876bbd5836ef5d2d89dcc52e5277430838b9b3..6a22aca1d678b82d3443a62bfdb503e2dbeba62f 100644 (file)
@@ -272,6 +272,9 @@ ctf_name_table (ctf_dict_t *fp, int kind)
     case CTF_K_ENUM:
     case CTF_K_ENUM64:
       return fp->ctf_enums;
+    case CTF_K_TYPE_TAG:
+    case CTF_K_DECL_TAG:
+      return fp->ctf_tags;
     case CTF_K_DATASEC:
       return fp->ctf_datasecs;
     default:
@@ -279,6 +282,37 @@ ctf_name_table (ctf_dict_t *fp, int kind)
     }
 }
 
+int
+ctf_insert_type_decl_tag (ctf_dict_t *fp, ctf_id_t type, const char *name,
+                         int kind)
+{
+  ctf_dynset_t *types;
+  ctf_dynhash_t *h = ctf_name_table (fp, kind);
+  int err;
+
+  if ((types = ctf_dynhash_lookup (h, name)) == NULL)
+    {
+      types = ctf_dynset_create (htab_hash_pointer, htab_eq_pointer, NULL);
+
+      if (!types)
+       return (ctf_set_errno (fp, ENOMEM));
+
+      err = ctf_dynhash_cinsert (h, name, types);
+      if (err != 0)
+       {
+         err *= -1;
+         return (ctf_set_errno (fp, err));
+       }
+    }
+
+  if ((err = ctf_dynset_insert (types, (void *) (uintptr_t) type)) != 0)
+    {
+      err *= -1;
+      return (ctf_set_errno (fp, err));
+    }
+  return 0;
+}
+
 int
 ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
 {
@@ -287,17 +321,25 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
                          dtd) < 0)
     return ctf_set_errno (fp, ENOMEM);
 
-  if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name
-      && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
+  if (flag == CTF_ADD_ROOT && dtd->dtd_data->ctt_name
+      && (name = ctf_strraw (fp, dtd->dtd_data->ctt_name)) != NULL)
     {
-      if (ctf_dynhash_insert (ctf_name_table (fp, kind),
-                             (char *) name, (void *) (uintptr_t)
-                             dtd->dtd_type) < 0)
+      /* Type and decl tags have unusual name tables, since their names are not
+        unique.  */
+
+      if (kind != CTF_K_TYPE_TAG && kind != CTF_K_DECL_TAG)
        {
-         ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
-                             dtd->dtd_type);
-         return ctf_set_errno (fp, ENOMEM);
+         if (ctf_dynhash_insert (ctf_name_table (fp, kind),
+                                 (char *) name, (void *) (uintptr_t)
+                                 dtd->dtd_type) < 0)
+           {
+             ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
+                                 dtd->dtd_type);
+             return ctf_set_errno (fp, ENOMEM);
+           }
        }
+      else if (ctf_insert_type_decl_tag (fp, dtd->dtd_type, name, kind) < 0)
+       return -1;                      /* errno is set for us.  */
     }
   ctf_list_append (&fp->ctf_dtdefs, dtd);
   return 0;
@@ -886,6 +928,125 @@ ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
   return 0;
 }
 
+/* Add a type or decl tag applying to some whole type, or to some
+   component of a type.  Component -1 is a whole type.  */
+
+static ctf_id_t
+ctf_add_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag,
+            int is_decl, int32_t component_idx)
+{
+  ctf_dtdef_t *dtd;
+  size_t vlen_size = 0;
+  int kind = is_decl ? CTF_K_DECL_TAG : CTF_K_TYPE_TAG;
+  int ref_kind = ctf_type_kind (fp, type);
+
+  if (component_idx < -1)
+    return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+
+  if (is_decl)
+    {
+      vlen_size = sizeof (ctf_decl_tag_t);
+
+      /* Whole-type declarations.  */
+
+      if (component_idx == 0)
+       {
+         switch (ref_kind)
+           {
+           case CTF_K_TYPEDEF:
+           case CTF_K_STRUCT:
+           case CTF_K_UNION:
+           case CTF_K_VAR:
+             /* TODO: support addition and querying on CTF_K_FUNCTION too, chasing back
+                to relevant CTF_K_FUNC_LINKAGEs.  */
+           case CTF_K_FUNC_LINKAGE:
+             break;
+           default:
+             return (ctf_set_typed_errno (fp, ECTF_BADID));
+           }
+       }
+    }
+  else if (component_idx != -1)
+    {
+      ctf_id_t func_type;
+
+      /* Within-type declarations.  */
+
+      switch (ref_kind)
+       {
+       case CTF_K_STRUCT:
+       case CTF_K_UNION:
+
+         if (component_idx >= ctf_member_count (fp, type))
+           return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+         break;
+
+       case CTF_K_FUNC_LINKAGE:
+         if ((func_type = ctf_type_reference (fp, type)) == CTF_ERR)
+           return (ctf_set_typed_errno (fp, ECTF_BADID));
+         /* FALLTHRU */
+
+       case CTF_K_FUNCTION:
+         {
+           ctf_funcinfo_t fi;
+
+           if (ctf_func_type_info (fp, func_type, &fi) < 0)
+             return -1;        /* errno is set for us.  */
+
+           if ((size_t) component_idx >= fi.ctc_argc)
+             return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+
+           break;
+         }
+       default:
+         return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+       }
+    }
+
+  if (tag == NULL || tag[0] == '\0')
+    return (ctf_set_typed_errno (fp, ECTF_NONAME));
+
+  if ((dtd = ctf_add_generic (fp, flag, tag, kind, 0, vlen_size,
+                             0, NULL)) == NULL)
+    return CTF_ERR;            /* errno is set for us.  */
+
+  dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, flag, 0);
+  dtd->dtd_data->ctt_type = (uint32_t) type;
+
+  if (is_decl)
+    {
+      ctf_decl_tag_t *vlen = (ctf_decl_tag_t *) dtd->dtd_vlen;
+      vlen->cdt_component_idx = component_idx;
+    }
+
+  return dtd->dtd_type;
+}
+
+/* Create a type tag.  */
+
+ctf_id_t
+ctf_add_type_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag)
+{
+  return ctf_add_tag (fp, flag, type, tag, 0, -1);
+}
+
+/* Create a decl tag applied to an entire type.  */
+
+ctf_id_t
+ctf_add_decl_type_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag)
+{
+  return ctf_add_tag (fp, flag, type, tag, 1, -1);
+}
+
+/* Create a decl tag applied to one element of a type.
+   component_idx must be >= 0.  */
+ctf_id_t
+ctf_add_decl_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag,
+                 int component_idx)
+{
+  return ctf_add_tag (fp, flag, type, tag, 1, component_idx);
+}
+
 ctf_id_t
 ctf_add_function (ctf_dict_t *fp, uint32_t flag,
                  const ctf_funcinfo_t *ctc, const ctf_id_t *argv,
index e2b046d7325f4efe9bdb510c89ee93bf1962de75..4c1007f5a67fa71746e069a662cffb73a64208ae 100644 (file)
@@ -127,6 +127,7 @@ ctf_decl_push (ctf_decl_t *cd, ctf_dict_t *fp, ctf_id_t type)
       prec = CTF_PREC_POINTER;
       break;
 
+    case CTF_K_DECL_TAG:
     case CTF_K_VAR:
       ctf_decl_push (cd, fp, suffix->ctt_type);
       prec = CTF_PREC_BASE; /* UPTODO probably wrong */
index f0422c05970c6d7ee852b67c5c75c0ee1d7b391e..a90a672826cdf55eeb8f1108eeb4a8d447b501b5 100644 (file)
@@ -745,6 +745,8 @@ extern ctf_id_t ctf_add_reftype (ctf_dict_t *, uint32_t, ctf_id_t,
 extern int ctf_add_funcobjt_sym_forced (ctf_dict_t *, int is_function,
                                        const char *, ctf_id_t);
 
+extern int ctf_insert_type_decl_tag (ctf_dict_t *, ctf_id_t, const char *,
+                                    int kind);
 extern int ctf_track_enumerator (ctf_dict_t *, ctf_id_t, const char *);
 
 extern int ctf_dedup_atoms_init (ctf_dict_t *);
index 8f19b566313ce0204146618dfc1647a57a64ed56..dac1ec50468f2a06c692478d4a9a4d0409777054 100644 (file)
@@ -853,6 +853,45 @@ ctf_datasec_var_next (ctf_dict_t *fp, ctf_id_t datasec, ctf_next_t **it,
   return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
 }
 
+/* Iterate over all tags with the given TAG, returning the ID of each tag.  */
+
+ctf_id_t
+ctf_tag_next (ctf_dict_t *fp, const char *tag, ctf_next_t **it)
+{
+  ctf_next_t *i = *it;
+  int err;
+  void *type;
+
+  if (!i)
+    {
+      if ((i = ctf_next_create ()) == NULL)
+       return (ctf_set_typed_errno (fp, ENOMEM));
+      i->cu.ctn_fp = fp;
+      i->ctn_iter_fun = (void (*) (void)) ctf_tag_next;
+
+      i->cu.ctn_s = ctf_dynhash_lookup (fp->ctf_tags, tag);
+
+      *it = i;
+    }
+
+  if ((void (*) (void)) ctf_tag_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));
+
+  err = ctf_dynset_next (i->cu.ctn_s, &i->ctn_next, &type);
+  if (err != 0 && err != ECTF_NEXT_END)
+    return ctf_set_typed_errno (fp, err);
+
+  if (err == 0)
+    return (ctf_id_t) (uintptr_t) type;
+
+  ctf_next_destroy (i);
+  *it = NULL;
+  return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
+}
+
 /* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
    RESTRICT nodes until we reach a "base" type node.  This is useful when
    we want to follow a type ID to a node that has members or a size.  To guard
@@ -1149,6 +1188,14 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
            case CTF_K_ENUM64:
              ctf_decl_sprintf (&cd, "enum %s", name);
              break;
+           case CTF_K_TYPE_TAG:
+             ctf_decl_sprintf (&cd, "%s", name);
+             break;
+           /* UPTODO: decl tags... I guess we print them when we print the
+              associated variable, somehow?  For now, just this...  */
+           case CTF_K_DECL_TAG:
+             ctf_decl_sprintf (&cd, "btf_decl_tag (\"%s\")", name);
+             break;
            case CTF_K_FUNC_LINKAGE:
            case CTF_K_VAR:
              {
@@ -1603,6 +1650,8 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_VOLATILE:
     case CTF_K_CONST:
     case CTF_K_RESTRICT:
+    case CTF_K_TYPE_TAG:
+    case CTF_K_DECL_TAG:
     case CTF_K_FUNCTION:
     case CTF_K_FUNC_LINKAGE:
     case CTF_K_VAR:
@@ -1630,6 +1679,119 @@ ctf_type_reference (ctf_dict_t *fp, ctf_id_t type)
     }
 }
 
+/* Return the component ID and declaration to which a decl tag is attached.  */
+
+ctf_id_t
+ctf_decl_tag (ctf_dict_t *fp, ctf_id_t decl_tag, int64_t *component_idx)
+{
+  ctf_dict_t *ofp = fp;
+  const ctf_type_t *tp, *suffix;
+  unsigned char *vlen;
+  ctf_decl_tag_t *cdt;
+
+  if ((tp = ctf_lookup_by_id (&fp, decl_tag, &suffix)) == NULL)
+    return CTF_ERR;            /* errno is set for us.  */
+
+  if (LCTF_KIND (fp, tp) != CTF_K_DECL_TAG)
+    return (ctf_set_typed_errno (ofp, ECTF_NOTDECLTAG));
+
+  vlen = ctf_vlen (fp, decl_tag, tp, NULL);
+  cdt = (ctf_decl_tag_t *) vlen;
+
+  *component_idx = cdt->cdt_component_idx;
+
+  return suffix->ctt_type;
+}
+
+/* Return the type ID of the type to which a given type tag is attached, or of
+   the type of the declaration to which a decl tag is attached (so a decl tag on
+   a function parameter would return the type ID of the parameter's type).  */
+
+ctf_id_t
+ctf_tag (ctf_dict_t *fp, ctf_id_t tag)
+{
+  int kind = ctf_type_kind (fp, tag);
+  int64_t component_idx;
+  ctf_id_t ref;
+
+  if (kind != CTF_K_TYPE_TAG && kind != CTF_K_DECL_TAG)
+    return (ctf_set_typed_errno (fp, ECTF_NOTTAG));
+
+  if ((ref = ctf_type_reference (fp, tag)) == CTF_ERR)
+    return CTF_ERR;            /* errno is set for us.  */
+
+  if (kind == CTF_K_TYPE_TAG)
+    return ref;
+
+  if (ctf_decl_tag (fp, tag, &component_idx) == CTF_ERR)
+    return CTF_ERR;            /* errno is set for us.  */
+
+  if (component_idx == -1)
+    return ref;
+
+  /* See ctf_add_tag.  */
+
+  switch (ctf_type_kind (fp, ref))
+    {
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+      {
+       ctf_next_t *i = NULL;
+       int64_t j = 0;
+       ctf_id_t type;
+
+       while (ctf_member_next (fp, ref, &i, NULL, &type, NULL, 0) >= 0)
+         {
+           if (j++ == component_idx)
+             {
+               ctf_next_destroy (i);
+               return type;
+             }
+         }
+       if (ctf_errno (fp) != ECTF_NEXT_END)
+         {
+           ctf_next_destroy (i);
+           return CTF_ERR;     /* errno is set for us.  */
+         }
+      }
+      break;
+    case CTF_K_FUNC_LINKAGE:
+    case CTF_K_FUNCTION:
+      {
+       ctf_funcinfo_t fi;
+       ctf_id_t *args;
+       ctf_id_t argtype;
+
+       if (ctf_func_type_info (fp, ref, &fi) < 0)
+         return CTF_ERR;       /* errno is set for us.  */
+
+       if (component_idx + 1 > (ssize_t) fi.ctc_argc)
+         break;
+
+       if ((args = malloc ((component_idx + 1) * sizeof (ctf_id_t))) == NULL)
+         return (ctf_set_typed_errno (fp, ENOMEM));
+
+       if (ctf_func_type_args (fp, ref, component_idx + 1, args))
+         {
+           free (args);
+           return CTF_ERR;     /* errno is set for us. */
+         }
+       argtype = args[component_idx];
+       free (args);
+       return argtype;
+      }
+
+    default:
+      return CTF_ERR;          /* errno is set for us.  */
+    }
+
+  ctf_err_warn (fp, 0, ECTF_NOTREF, _("decl tag %lx refers to type %lx, "
+                                     "component %" PRIi64 ", which does not exist"),
+               tag, (long) ref, component_idx);
+
+  return (ctf_set_typed_errno (fp, ECTF_NOTREF));
+}
+
 /* Find a pointer to type by looking in fp->ctf_ptrtab and fp->ctf_pptrtab.  If
    we can't find a pointer to the given type, see if we can compute a pointer to
    the type resulting from resolving the type down to its base type and use that
index daa8375a9ed32aeae40429ec5236c8d64f3d1949..66ddb530a1b907508874a4a43c6e62c4f6108cfc 100644 (file)
@@ -84,6 +84,8 @@ LIBCTF_2.0 {
        ctf_type_visit;
        ctf_type_cmp;
        ctf_type_compat;
+       ctf_tag;
+       ctf_decl_tag;
 
        ctf_member_info;
        ctf_member_next;
@@ -111,6 +113,7 @@ LIBCTF_2.0 {
        ctf_variable_next;
        ctf_datasec_iter;
        ctf_datasec_next;
+       ctf_tag_next;
 
        ctf_next_create;
        ctf_next_destroy;
@@ -118,6 +121,8 @@ LIBCTF_2.0 {
 
        ctf_add_array;
        ctf_add_const;
+       ctf_add_decl_tag;
+       ctf_add_decl_type_tag;
        ctf_add_enum;
        ctf_add_enum_encoded;
        ctf_add_enum64;
@@ -131,6 +136,7 @@ LIBCTF_2.0 {
        ctf_add_pointer;
        ctf_add_type;
        ctf_add_typedef;
+       ctf_add_type_tag;
        ctf_add_restrict;
        ctf_add_section_variable;
        ctf_add_slice;