]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: create: struct/union addition
authorNick Alcock <nick.alcock@oracle.com>
Thu, 24 Apr 2025 15:28:26 +0000 (16:28 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:42 +0000 (18:07 +0100)
There's one API addition here: the existing CTF_ADD_ROOT / CTF_ADD_NONROOT
flags can have a new flag ORed with them, CTF_ADD_STRUCT_BITFIELDS,
indicating that the newly-added struct/union is capable of having bitfields
added to it via the new ctf_add_member_bitfield function (see a later
commit).

Without this, you can only add bitfields via the deprecated slice or base
type encoding representations (the former will force CTF output).

Implementation notes: structs and unions are always added with a CTF_K_BIG
prefix: if promoting from a forward, one is added.  These are elided at
serialization time if they are not needed to encode this size of struct /
this number of members.  (This means you don't have to figure out in advance
if your struct will be too big for BTF: you can just add members to it,
and libctf will figure it out and upgrade the dict as needed, or tell you
it can't if you've forbidden such things.)

We take advantage of this to merge a couple of very similar functions,
saving a bit of code.

include/ctf-api.h
libctf/ctf-create.c

index b48c491303f00646b92a7955b583e10568318414..03711f7a213de24c040e057643c84f3780b99adf 100644 (file)
@@ -250,7 +250,9 @@ typedef struct ctf_snapshot_id
   _CTF_ITEM (ECTF_UNSTABLE, "Attempt to write unstable file format version: set I_KNOW_LIBCTF_IS_UNSTABLE in the environment.") \
   _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_NOTSERIALIZED, "CTF dict must be serialized first.") \
+  _CTF_ITEM (ECTF_NOTBITSOU, "Type is not a bitfield-capable struct or union.") \
+  _CTF_ITEM (ECTF_DESCENDING, "Structure offsets may not descend.") \
 
 #define        ECTF_BASE       1000    /* Base value for libctf errnos.  */
 
@@ -284,6 +286,7 @@ _CTF_ERRORS
 
 #define        CTF_ADD_NONROOT 0       /* Type only visible in nested scope.  */
 #define        CTF_ADD_ROOT    1       /* Type visible at top-level scope.  */
+#define CTF_ADD_STRUCT_BITFIELDS 2 /* Struct/union field-level bitfields */
 
 /* Flags for ctf_member_next.  */
 
@@ -842,13 +845,15 @@ extern ctf_id_t ctf_add_restrict (ctf_dict_t *, uint32_t, ctf_id_t);
 /* 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,
-   etc) use the _sized variants.  */
+   etc) use the _sized variants.  The FLAG parameter can take the value
+   CTF_ADD_STRUCT_BITFIELDS, indicating that bitfields can be directly added
+   to this struct via ctf_add_member_bitfield.  */
 
-extern ctf_id_t ctf_add_struct (ctf_dict_t *, uint32_t, const char *);
-extern ctf_id_t ctf_add_union (ctf_dict_t *, uint32_t, const char *);
-extern ctf_id_t ctf_add_struct_sized (ctf_dict_t *, uint32_t, const char *,
+extern ctf_id_t ctf_add_struct (ctf_dict_t *, uint32_t flag, const char *);
+extern ctf_id_t ctf_add_union (ctf_dict_t *, uint32_t flag, const char *);
+extern ctf_id_t ctf_add_struct_sized (ctf_dict_t *, uint32_t flag, const char *,
                                      size_t);
-extern ctf_id_t ctf_add_union_sized (ctf_dict_t *, uint32_t, const char *,
+extern ctf_id_t ctf_add_union_sized (ctf_dict_t *, uint32_t flag, const char *,
                                     size_t);
 
 /* Note that CTF cannot encode a given type.  This usually returns an
index 1a5665b15bc992aef1bf46d459ff4b420662ed42..a0ffb8780339ae143b36387091bff5191410d3dc 100644 (file)
@@ -931,48 +931,58 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag,
   if (ctc->ctc_flags & CTF_FUNC_VARARG)
     vdat[vlen - 1] = 0;                   /* Add trailing zero to indicate varargs.  */
 
-  return type;
+  return dtd->dtd_type;
 }
 
-ctf_id_t
-ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
-                     size_t size)
+static ctf_id_t
+ctf_add_sou_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
+                  size_t size, int kind)
 {
   ctf_dtdef_t *dtd;
+  ctf_type_t *prefix;
   ctf_id_t type = 0;
-  size_t initial_vbytes = sizeof (ctf_lmember_t) * INITIAL_VLEN;
+  uint32_t idx;
+  size_t initial_vbytes = sizeof (ctf_member_t) * INITIAL_VLEN;
+  int root_flag = flag & (~CTF_ADD_STRUCT_BITFIELDS);
 
   if (fp->ctf_flags & LCTF_NO_STR)
     return (ctf_set_errno (fp, ECTF_NOPARENT));
 
-  /* Promote root-visible forwards to structs.  */
+  /* Promote root-visible forwards to structs/unions.  */
   if (name != NULL)
-    type = ctf_lookup_by_rawname (fp, CTF_K_STRUCT, name);
+    type = ctf_lookup_by_rawname (fp, kind, name);
+
+  if (type > 0)
+    idx = ctf_type_to_index (fp, type);
 
   /* Prohibit promotion if this type was ctf_open()ed.  */
-  if (type > 0 && type < fp->ctf_stypes)
+  if (type > 0 && idx < fp->ctf_stypes)
     return (ctf_set_errno (fp, ECTF_RDONLY));
 
   if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
-    dtd = ctf_dtd_lookup (fp, type);
-  else if ((type = ctf_add_generic (fp, flag, name, CTF_K_STRUCT,
-                                   initial_vbytes, &dtd)) == CTF_ERR)
-    return CTF_ERR;            /* errno is set for us.  */
-
-  /* Forwards won't have any vlen yet.  */
-  if (dtd->dtd_vlen_alloc == 0)
     {
-      if ((dtd->dtd_vlen = calloc (1, initial_vbytes)) == NULL)
-       return (ctf_set_typed_errno (fp, ENOMEM));
-      dtd->dtd_vlen_alloc = initial_vbytes;
+      dtd = ctf_dtd_lookup (fp, type);
+
+      if ((prefix = ctf_add_prefix (fp, dtd, initial_vbytes)) == NULL)
+       return CTF_ERR;                         /* errno is set for us.  */
     }
+  else if ((dtd = ctf_add_generic (fp, root_flag, name, kind, 1, 0,
+                                  initial_vbytes, &prefix)) == NULL)
+    return CTF_ERR;                            /* errno is set for us.  */
 
-  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0);
-  dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
-  dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
-  dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
+  prefix->ctt_info = CTF_TYPE_INFO (CTF_K_BIG, 0, 0);
+  dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, !!(flag & CTF_ADD_STRUCT_BITFIELDS), 0);
+  prefix->ctt_size = CTF_SIZE_TO_LSIZE_HI (size);
+  dtd->dtd_data->ctt_size = CTF_SIZE_TO_LSIZE_LO (size);
 
-  return type;
+  return dtd->dtd_type;
+}
+
+ctf_id_t
+ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
+                     size_t size)
+{
+  return ctf_add_sou_sized (fp, flag, name, size, CTF_K_STRUCT);
 }
 
 ctf_id_t
@@ -985,41 +995,7 @@ ctf_id_t
 ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
                     size_t size)
 {
-  ctf_dtdef_t *dtd;
-  ctf_id_t type = 0;
-  size_t initial_vbytes = sizeof (ctf_lmember_t) * INITIAL_VLEN;
-
-  if (fp->ctf_flags & LCTF_NO_STR)
-    return (ctf_set_errno (fp, ECTF_NOPARENT));
-
-  /* Promote root-visible forwards to unions.  */
-  if (name != NULL)
-    type = ctf_lookup_by_rawname (fp, CTF_K_UNION, name);
-
-  /* Prohibit promotion if this type was ctf_open()ed.  */
-  if (type > 0 && type < fp->ctf_stypes)
-    return (ctf_set_errno (fp, ECTF_RDONLY));
-
-  if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
-    dtd = ctf_dtd_lookup (fp, type);
-  else if ((type = ctf_add_generic (fp, flag, name, CTF_K_UNION,
-                                   initial_vbytes, &dtd)) == CTF_ERR)
-    return CTF_ERR;            /* errno is set for us.  */
-
-  /* Forwards won't have any vlen yet.  */
-  if (dtd->dtd_vlen_alloc == 0)
-    {
-      if ((dtd->dtd_vlen = calloc (1, initial_vbytes)) == NULL)
-       return (ctf_set_typed_errno (fp, ENOMEM));
-      dtd->dtd_vlen_alloc = initial_vbytes;
-    }
-
-  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0);
-  dtd->dtd_data.ctt_size = CTF_LSIZE_SENT;
-  dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size);
-  dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size);
-
-  return type;
+  return ctf_add_sou_sized (fp, flag, name, size, CTF_K_UNION);
 }
 
 ctf_id_t