]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: create, types: enums and enum64s; type encoding
authorNick Alcock <nick.alcock@oracle.com>
Thu, 24 Apr 2025 16:17:57 +0000 (17:17 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:42 +0000 (18:07 +0100)
This commit adapts most aspects of enum handling: querying and iteration,
enumerator querying and iteration, ctf_type_add, etc.  We have to adapt to
enum64s and to signed versus unsigned enums, to our vlen and DTD changes and
other internal API changes to handle prefix types etc, and fix the types of
things to allow for 64-bit enumerators.  We can also (finally!) get useful
info on enum size rather than being restricted to a value hardwired into
libctf.

We also adjust all the type-encoding functions for the internal API changes,
since enums are the first encodable entities we have covered.

API changes:

-typedef int ctf_enum_f (const char *name, int val, void *arg);
+typedef int ctf_enum_f (const char *name, int64_t val, void *arg);
+typedef int ctf_unsigned_enum_f (const char *name, uint64_t val, void *arg);

-extern const char *ctf_enum_name (ctf_dict_t *, ctf_id_t, int);
-extern int ctf_enum_value (ctf_dict_t *, ctf_id_t, const char *, int *);
+extern const char *ctf_enum_name (ctf_dict_t *, ctf_id_t, int64_t);
+extern int ctf_enum_value (ctf_dict_t *, ctf_id_t, const char *, int64_t *);
+extern int ctf_enum_unsigned_value (ctf_dict_t *, ctf_id_t, const char *, uint64_t *);
+
+/* Return 1 if this enum's contents are unsigned, so you can tell which of the
+   above functions to use.  */
+
+extern int ctf_enum_unsigned (ctf_dict_t *, ctf_id_t);

-/* Return all enumeration constants in a given enum type.  */
-extern int ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
+/* Return all enumeration constants in a given enum type.  The return value, and
+   VAL argument, may need to be cast to uint64_t: see ctf_enum_unsigned().  */
+extern int64_t ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
 extern const char *ctf_enum_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
-   int *);
+   int64_t *);
+
+/* enums are created signed by default.  If you want an unsigned enum,
+   use ctf_add_enum_encoded() with an encoding of 0 (CTF_INT_SIGNED and
+   everything else off).  This will not create a slice, unlike all other
+   uses of ctf_add_enum_encoded(), and the result is still representable
+   as BTF.  */
+
+extern ctf_id_t ctf_add_enum64_encoded (ctf_dict_t *, uint32_t, const char *,
+ const ctf_encoding_t *);
+extern ctf_id_t ctf_add_enum64 (ctf_dict_t *, uint32_t, const char *);

-extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int);
+extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int64_t);

The only aspects of enums that are not now handled are forwards to enums,
dumping of enums, and deduplication of enums.

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

index 762cc4895ce3d8d6ab75b2c45609352136295be4..cc56de5d92715632510cb3be63af88d0a68f580f 100644 (file)
@@ -304,13 +304,14 @@ _CTF_ERRORS
 
 typedef int ctf_visit_f (const char *name, ctf_id_t type, unsigned long offset,
                         int depth, void *arg);
-typedef int ctf_enum_f (const char *name, int val, void *arg);
 typedef int ctf_variable_f (const char *name, ctf_id_t type, 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);
+typedef int ctf_enum_f (const char *name, int64_t val, void *arg);
+typedef int ctf_unsigned_enum_f (const char *name, uint64_t val, 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);
@@ -634,7 +635,10 @@ extern ssize_t ctf_type_align (ctf_dict_t *, ctf_id_t);
 /* Return the kind of a type (CTF_K_* constant).  Slices are considered to be
    the kind they are a slice of.  Forwards to incomplete structs, etc, return
    CTF_K_FORWARD (but deduplication resolves most forwards to their concrete
-   types).  */
+   types).
+
+   CTFv4 note: forwards to enums also return CTF_K_FORWARD, even though they
+   are encoded differently.  */
 
 extern int ctf_type_kind (ctf_dict_t *, ctf_id_t);
 
@@ -683,8 +687,15 @@ extern int ctf_type_cmp (ctf_dict_t *, ctf_id_t, ctf_dict_t *, ctf_id_t);
 /* Get the name of an enumerator given its value, or vice versa.  If many
    enumerators have the same value, the first with that value is returned.  */
 
-extern const char *ctf_enum_name (ctf_dict_t *, ctf_id_t, int);
-extern int ctf_enum_value (ctf_dict_t *, ctf_id_t, const char *, int *);
+extern const char *ctf_enum_name (ctf_dict_t *, ctf_id_t, int64_t);
+extern int ctf_enum_value (ctf_dict_t *, ctf_id_t, const char *, int64_t *);
+extern int ctf_enum_unsigned_value (ctf_dict_t *, ctf_id_t, const char *, uint64_t *);
+
+/* Return 1 if this enum's contents are unsigned, so you can tell which of the
+   above functions to use.  */
+
+extern int ctf_enum_unsigned (ctf_dict_t *, ctf_id_t);
+
 /* Return nonzero if this struct or union uses bitfield encoding.  */
 
 extern int ctf_struct_bitfield (ctf_dict_t *, ctf_id_t);
@@ -711,10 +722,11 @@ extern ssize_t ctf_member_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
                                const char **name, ctf_id_t *membtype,
                                int *bit_width, int flags);
 
-/* Return all enumeration constants in a given enum type.  */
-extern int ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
+/* Return all enumeration constants in a given enum type.  The return value, and
+   VAL argument, may need to be cast to uint64_t: see ctf_enum_unsigned().  */
+extern int64_t ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
 extern const char *ctf_enum_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
-                                 int *);
+                                 int64_t *);
 
 /* Return all enumeration constants with a given name in a given dict, similar
    to ctf_lookup_enumerator above but capable of returning multiple values.
@@ -821,6 +833,16 @@ extern ctf_dict_t *ctf_create (int *);
 extern ctf_id_t ctf_add_array (ctf_dict_t *, uint32_t,
                               const ctf_arinfo_t *);
 extern ctf_id_t ctf_add_const (ctf_dict_t *, uint32_t, ctf_id_t);
+
+/* enums are created signed by default.  If you want an unsigned enum,
+   use ctf_add_enum_encoded() with an encoding of 0 (CTF_INT_SIGNED and
+   everything else off).  This will not create a slice, unlike all other
+   uses of ctf_add_enum_encoded(), and the result is still representable
+   as BTF.  */
+
+extern ctf_id_t ctf_add_enum64_encoded (ctf_dict_t *, uint32_t, const char *,
+                                       const ctf_encoding_t *);
+extern ctf_id_t ctf_add_enum64 (ctf_dict_t *, uint32_t, const char *);
 extern ctf_id_t ctf_add_enum_encoded (ctf_dict_t *, uint32_t, const char *,
                                      const ctf_encoding_t *);
 extern ctf_id_t ctf_add_enum (ctf_dict_t *, uint32_t, const char *);
@@ -866,10 +888,10 @@ extern ctf_id_t ctf_add_union_sized (ctf_dict_t *, uint32_t flag, const char *,
 extern ctf_id_t ctf_add_unknown (ctf_dict_t *, uint32_t, const char *);
 extern ctf_id_t ctf_add_volatile (ctf_dict_t *, uint32_t, ctf_id_t);
 
-/* Add an enumerator to an enum.  If the enum is non-root, so are all the
-   constants added to it by ctf_add_enumerator.  */
+/* Add an enumerator to an enum or enum64.  If the enum is non-root, so are all
+   the constants added to it by ctf_add_enumerator.  */
 
-extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int);
+extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int64_t);
 
 /* Add a member to a struct or union, either at the next available offset (with
    suitable padding for the alignment) or at a specific offset, and possibly
index 0db4870b9ceaaa3b7b29f72cbd1c4602e2508012..e75ef7702457f7f0336de378d5a43ca1d5671e9f 100644 (file)
@@ -270,6 +270,7 @@ ctf_name_table (ctf_dict_t *fp, int kind)
     case CTF_K_UNION:
       return fp->ctf_unions;
     case CTF_K_ENUM:
+    case CTF_K_ENUM64:
       return fp->ctf_enums;
     default:
       return fp->ctf_names;
@@ -658,8 +659,8 @@ ctf_add_encoded (ctf_dict_t *fp, uint32_t flag,
                 const char *name, const ctf_encoding_t *ep, uint32_t kind)
 {
   ctf_dtdef_t *dtd;
-  ctf_id_t type;
   uint32_t encoding;
+  int vlen = sizeof (uint32_t);
 
   if (ep == NULL)
     return (ctf_set_typed_errno (fp, EINVAL));
@@ -1004,49 +1005,74 @@ ctf_add_union (ctf_dict_t *fp, uint32_t flag, const char *name)
   return (ctf_add_union_sized (fp, flag, name, 0));
 }
 
-ctf_id_t
-ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
+static ctf_id_t
+ctf_add_enum_internal (ctf_dict_t *fp, uint32_t flag, const char *name,
+                      int kind, int is_signed)
 {
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
-  size_t initial_vbytes = sizeof (ctf_enum_t) * INITIAL_VLEN;
+  size_t initial_vbytes;
+  ctf_type_t *prefix;
+
+  if (!ctf_assert (fp, kind == CTF_K_ENUM || kind == CTF_K_ENUM64))
+    return -1;                 /* errno is set for us. */
+
+  if (kind == CTF_K_ENUM)
+    initial_vbytes = sizeof (ctf_enum_t) * INITIAL_VLEN;
+  else
+    initial_vbytes = sizeof (ctf_enum64_t) * INITIAL_VLEN;
 
   if (fp->ctf_flags & LCTF_NO_STR)
     return (ctf_set_errno (fp, ECTF_NOPARENT));
 
   /* Promote root-visible forwards to enums.  */
   if (name != NULL)
-    type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name);
+    type = ctf_lookup_by_rawname (fp, kind, 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_ENUM,
-                                   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, 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_ENUM, flag, 0);
-  dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
+  prefix->ctt_info = CTF_TYPE_INFO (CTF_K_BIG, 0, 0);
+  dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, is_signed, 0);
 
-  return type;
+  if (kind == CTF_K_ENUM)
+    dtd->dtd_data->ctt_size = fp->ctf_dmodel->ctd_int;
+  else
+    dtd->dtd_data->ctt_size = 8;
+
+  return dtd->dtd_type;
 }
 
 ctf_id_t
-ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
-                     const ctf_encoding_t *ep)
+ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
+{
+  return ctf_add_enum_internal (fp, flag, name, CTF_K_ENUM, 1);
+}
+
+ctf_id_t
+ctf_add_enum64 (ctf_dict_t *fp, uint32_t flag, const char *name)
+{
+  return ctf_add_enum_internal (fp, flag, name, CTF_K_ENUM64, 1);
+}
+
+static ctf_id_t
+ctf_add_enum_encoded_internal (ctf_dict_t *fp, uint32_t flag, const char *name,
+                              int kind, const ctf_encoding_t *ep)
 {
   ctf_id_t type = 0;
+  int is_signed = ((ep->cte_format & CTF_INT_SIGNED) != 0);
 
   /* First, create the enum if need be, using most of the same machinery as
      ctf_add_enum(), to ensure that we do not allow things past that are not
@@ -1059,17 +1085,41 @@ ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type != 0)
     {
       if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
-         (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
+         (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM) &&
+         (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM64))
        return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
     }
-  else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
+  else if ((type = ctf_add_enum_internal (fp, flag, name, kind, is_signed))
+          == CTF_ERR)
     return CTF_ERR;            /* errno is set for us.  */
 
+  /* If this is just changing the signedness of the enum, we don't need a
+     slice.  */
+
+  if ((ep->cte_format & ~CTF_INT_SIGNED) == 0
+      && ep->cte_bits == 0
+      && ep->cte_offset == 0)
+    return type;
+
   /* Now attach a suitable slice to it.  */
 
   return ctf_add_slice (fp, flag, type, ep);
 }
 
+ctf_id_t
+ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
+                     const ctf_encoding_t *ep)
+{
+  return ctf_add_enum_encoded_internal (fp, flag, name, CTF_K_ENUM, ep);
+}
+
+ctf_id_t
+ctf_add_enum64_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
+                       const ctf_encoding_t *ep)
+{
+  return ctf_add_enum_encoded_internal (fp, flag, name, CTF_K_ENUM64, ep);
+}
+
 ctf_id_t
 ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
                 uint32_t kind)
@@ -1095,13 +1145,19 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (type)
     return type;
 
-  if ((type = ctf_add_generic (fp, flag, name, kind, 0, &dtd)) == CTF_ERR)
+  if ((dtd = ctf_add_generic (fp, flag, name, kind, 0, 0, 0, NULL)) == NULL)
     return CTF_ERR;            /* errno is set for us.  */
 
-  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
-  dtd->dtd_data.ctt_type = kind;
+  if (kind != CTF_K_ENUM &&
+      kind != CTF_K_ENUM64)
+    {
+      dtd->dtd_data->ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, 0, 0);
+      dtd->dtd_data->ctt_type = kind;
+    }
+  else
+    dtd->dtd_data->ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, 0, 0);
 
-  return type;
+  return dtd->dtd_type;
 }
 
 ctf_id_t
@@ -1187,13 +1243,12 @@ ctf_add_restrict (ctf_dict_t *fp, uint32_t flag, ctf_id_t ref)
 
 int
 ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
-                   int value)
+                   int64_t value)
 {
   ctf_dict_t *ofp = fp;
   ctf_dtdef_t *dtd;
-  ctf_enum_t *en;
 
-  uint32_t kind, vlen, root;
+  uint32_t kind, vlen, root, en_name;
 
   if (name == NULL)
     return (ctf_set_errno (fp, EINVAL));
@@ -1213,9 +1268,9 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   if (dtd == NULL)
     return (ctf_set_errno (ofp, ECTF_BADID));
 
-  kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
-  root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
-  vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
+  kind = LCTF_KIND (fp, dtd->dtd_buf);
+  root = LCTF_INFO_ISROOT (fp, dtd->dtd_buf->ctt_info);
+  vlen = LCTF_VLEN (fp, dtd->dtd_buf);
 
   /* Enumeration constant names are only added, and only checked for duplicates,
      if the enum they are part of is a root-visible type.  */
@@ -1229,16 +1284,26 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
        return (ctf_set_errno (ofp, ctf_errno (fp)));
     }
 
-  if (kind != CTF_K_ENUM)
+  if ((kind != CTF_K_ENUM) && (kind != CTF_K_ENUM64))
     return (ctf_set_errno (ofp, ECTF_NOTENUM));
 
   if (vlen == CTF_MAX_VLEN)
     return (ctf_set_errno (ofp, ECTF_DTFULL));
 
-  if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
-    return -1;                                 /* errno is set for us.  */
+  if (kind == CTF_K_ENUM)
+    {
+      if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
+       return -1;                              /* errno is set for us.  */
+
+      dtd->dtd_vlen_size += sizeof (ctf_enum_t);
+    }
+  else
+    {
+      if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum64_t) * (vlen + 1)) < 0)
+       return -1;                              /* errno is set for us.  */
 
-  en = (ctf_enum_t *) dtd->dtd_vlen;
+      dtd->dtd_vlen_size += sizeof (ctf_enum64_t);
+    }
 
   /* Check for constant duplication within any given enum: only needed for
      non-root-visible types, since the duplicate detection above does the job
@@ -1248,15 +1313,46 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
     {
       size_t i;
 
-      for (i = 0; i < vlen; i++)
-       if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
-         return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+      if (kind == CTF_K_ENUM)
+       {
+         ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
+
+         for (i = 0; i < vlen; i++)
+           if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+             return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+       }
+      else
+       {
+         ctf_enum64_t *en = (ctf_enum64_t *) dtd->dtd_vlen;
+
+         for (i = 0; i < vlen; i++)
+           if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+             return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+
+       }
     }
 
-  en[vlen].cte_name = ctf_str_add (fp, name);
-  en[vlen].cte_value = value;
+  if (kind == CTF_K_ENUM)
+    {
+      ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
+
+      en[vlen].cte_name = ctf_str_add (fp, name);
+      en[vlen].cte_value = value;
 
-  if (en[vlen].cte_name == 0 && name != NULL && name[0] != '\0')
+      en_name = en[vlen].cte_name;
+    }
+  else
+    {
+      ctf_enum64_t *en = (ctf_enum64_t *) dtd->dtd_vlen;
+
+      en[vlen].cte_name = ctf_str_add (fp, name);
+      en[vlen].cte_val_low = ((uint64_t) value) & 0xffffffff;
+      en[vlen].cte_val_high = ((uint64_t) value) >> 32;
+
+      en_name = en[vlen].cte_name;
+    }
+
+  if (en_name == 0 && name != NULL && name[0] != '\0')
     return (ctf_set_errno (ofp, ctf_errno (fp)));
 
   /* Put the newly-added enumerator name into the name table if this type is
@@ -1265,12 +1361,12 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   if (root == CTF_ADD_ROOT)
     {
       if (ctf_dynhash_insert (fp->ctf_names,
-                             (char *) ctf_strptr (fp, en[vlen].cte_name),
+                             (char *) ctf_strptr (fp, en_name),
                              (void *) (uintptr_t) enid) < 0)
        return ctf_set_errno (fp, ENOMEM);
     }
 
-  dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
+  dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
 
   return 0;
 }
@@ -1711,10 +1807,10 @@ typedef struct ctf_bundle
 } ctf_bundle_t;
 
 static int
-enumcmp (const char *name, int value, void *arg)
+enumcmp (const char *name, int64_t value, void *arg)
 {
   ctf_bundle_t *ctb = arg;
-  int bvalue;
+  int64_t bvalue;
 
   if (ctf_enum_value (ctb->ctb_dict, ctb->ctb_type, name, &bvalue) < 0)
     {
@@ -1725,7 +1821,7 @@ enumcmp (const char *name, int value, void *arg)
   if (value != bvalue)
     {
       ctf_err_warn (ctb->ctb_dict, 1, ECTF_CONFLICT,
-                   _("conflict due to enum value change: %i versus %i"),
+                   _("conflict due to enum value change: %li versus %li"),
                    value, bvalue);
       return 1;
     }
@@ -1733,7 +1829,7 @@ enumcmp (const char *name, int value, void *arg)
 }
 
 static int
-enumadd (const char *name, int value, void *arg)
+enumadd (const char *name, int64_t value, void *arg)
 {
   ctf_bundle_t *ctb = arg;
 
@@ -2247,9 +2343,18 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
       }
 
     case CTF_K_ENUM:
+    case CTF_K_ENUM64:
       if (dst_type != CTF_ERR && kind != CTF_K_FORWARD
          && dst_kind != CTF_K_FORWARD)
        {
+         if (ctf_enum_unsigned (src_fp, src_type)
+             != ctf_enum_unsigned (dst_fp, dst_type))
+           {
+             ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+                           _("conflict for enum %s against ID %lx: member "
+                             "signedness differs"), name, dst_type);
+             return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
+           }
          if (ctf_enum_iter (src_fp, src_type, enumcmp, &dst)
              || ctf_enum_iter (dst_fp, dst_type, enumcmp, &src))
            {
@@ -2263,7 +2368,10 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type
        {
          ctf_snapshot_id_t snap = ctf_snapshot (dst_fp);
 
-         dst_type = ctf_add_enum (dst_fp, flag, name);
+         if (src_type == CTF_K_ENUM)
+           dst_type = ctf_add_enum (dst_fp, flag, name);
+         else
+           dst_type = ctf_add_enum64 (dst_fp, flag, name);
          if ((dst.ctb_type = dst_type) == CTF_ERR
              || ctf_enum_iter (src_fp, src_type, enumadd, &dst))
            {
index 4fdaa20f3d105b8a8adb983121b69b34b09a9f69..1095c8d0f0a86da770191824fc4e4fa03c9a407c 100644 (file)
@@ -484,7 +484,7 @@ ctf_id_t
 ctf_lookup_enumerator (ctf_dict_t *fp, const char *name, int64_t *enum_value)
 {
   ctf_id_t type;
-  int enum_int_value;
+  int64_t enum_int_value;
 
   if (fp->ctf_flags & LCTF_NO_STR)
     return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
@@ -561,6 +561,7 @@ ctf_lookup_enumerator_next (ctf_dict_t *fp, const char *name,
   do
     {
       const char *this_name;
+      int is_enum64 = 0;
 
       /* At end of enum? Traverse to next one, if any are left.  */
 
@@ -568,14 +569,18 @@ ctf_lookup_enumerator_next (ctf_dict_t *fp, const char *name,
        {
          const ctf_type_t *tp;
          ctf_dtdef_t *dtd;
+         int kind;
+         unsigned char *vlen;
 
+         /* It's a shame we can't use ctf_type_kind_next here, but we're
+            looking for two type kinds at once...  */
          do
-           i->ctn_type = ctf_type_next (i->cu.ctn_fp, &i->ctn_next, NULL, 1);
-         while (i->ctn_type != CTF_ERR
-                && ctf_type_kind_unsliced (i->cu.ctn_fp, i->ctn_type)
-                != CTF_K_ENUM);
+           i->i.ctn_type = ctf_type_next (i->cu.ctn_fp, &i->ctn_next, NULL, 1);
+         while (i->i.ctn_type != CTF_ERR
+                && ((kind = ctf_type_kind_unsliced (i->cu.ctn_fp, i->i.ctn_type))
+                    != CTF_K_ENUM && kind != CTF_K_ENUM64));
 
-         if (i->ctn_type == CTF_ERR)
+         if (i->i.ctn_type == CTF_ERR)
            {
              /* Conveniently, when the iterator over all types is done, so is the
                 iteration as a whole: so we can just pass all errors from the
@@ -585,30 +590,43 @@ ctf_lookup_enumerator_next (ctf_dict_t *fp, const char *name,
              return CTF_ERR;                   /* errno is set for us.  */
            }
 
-         if ((tp = ctf_lookup_by_id (&fp, i->ctn_type)) == NULL)
+         if ((tp = ctf_lookup_by_id (&fp, i->i.ctn_type, &i->ctn_tp)) == NULL)
            return CTF_ERR;                     /* errno is set for us.  */
-         i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+         i->ctn_n = LCTF_VLEN (fp, tp);
 
-         dtd = ctf_dynamic_type (fp, i->ctn_type);
-
-         if (dtd == NULL)
+         if ((dtd = ctf_dynamic_type (fp, i->i.ctn_type)) != NULL)
+           vlen = dtd->dtd_vlen;
+         else
            {
-             (void) ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment);
-             i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
-                                                 i->ctn_increment);
+             ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment);
+             vlen = (unsigned char *) ((uintptr_t) tp + i->ctn_increment);
            }
+
+         if (kind == CTF_K_ENUM)
+           i->u.ctn_en = (const ctf_enum_t *) vlen;
          else
-           i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;
+           i->u.ctn_en64 = (const ctf_enum64_t *) vlen;
        }
 
-      this_name = ctf_strptr (fp, i->u.ctn_en->cte_name);
+      if (LCTF_KIND (fp, i->ctn_tp) == CTF_K_ENUM64)
+       is_enum64 = 1;
+
+      if (is_enum64)
+         this_name = ctf_strptr (fp, i->u.ctn_en64->cte_name);
+       else
+         this_name = ctf_strptr (fp, i->u.ctn_en->cte_name);
 
       i->ctn_n--;
 
       if (strcmp (name, this_name) == 0)
        {
          if (val)
-           *val = i->u.ctn_en->cte_value;
+           {
+             if (is_enum64)
+               *val = ((uint64_t) i->u.ctn_en64->cte_val_high) << 32 | (i->u.ctn_en64->cte_val_low);
+             else
+               *val = i->u.ctn_en->cte_value;
+           }
          found = 1;
 
          /* Constant found in this enum: try the next one.  (Constant names
@@ -621,7 +639,7 @@ ctf_lookup_enumerator_next (ctf_dict_t *fp, const char *name,
     }
   while (!found);
 
-  return i->ctn_type;
+  return i->i.ctn_type;
 }
 
 typedef struct ctf_symidx_sort_arg_cb
index be421e77f83527593fb3a6db40fe8a713b123570..f30a3c2804e3dfd07d14260fb5be36c679a1f148 100644 (file)
@@ -363,12 +363,12 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
 /* Iterate over the members of an ENUM.  We pass the string name and associated
    integer value of each enum element to the specified callback function.  */
 
-int
+int64_t
 ctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
 {
   ctf_next_t *i = NULL;
   const char *name;
-  int val;
+  int64_t val;
 
   while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL)
     {
@@ -391,7 +391,7 @@ ctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
 
 const char *
 ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
-              int *val)
+              int64_t *val)
 {
   ctf_dict_t *ofp = fp;
   uint32_t kind;
@@ -407,41 +407,37 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   if (!i)
     {
       const ctf_type_t *tp;
-      ctf_dtdef_t *dtd;
+      unsigned char *en;
 
       if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
        return NULL;                    /* errno is set for us.  */
 
-      if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
-       return NULL;                    /* errno is set for us.  */
+      kind = ctf_type_kind (fp, type);
 
-      if ((i = ctf_next_create ()) == NULL)
+      if ((kind != CTF_K_ENUM) && (kind != CTF_K_ENUM64))
        {
-         ctf_set_errno (ofp, ENOMEM);
+         ctf_next_destroy (i);
+         ctf_set_errno (ofp, ECTF_NOTENUM);
          return NULL;
        }
-      i->cu.ctn_fp = ofp;
 
-      (void) ctf_get_ctt_size (fp, tp, NULL,
-                              &i->ctn_increment);
-      kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+      if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
+       return NULL;                    /* errno is set for us.  */
 
-      if (kind != CTF_K_ENUM)
+      if ((i = ctf_next_create ()) == NULL)
        {
-         ctf_next_destroy (i);
-         ctf_set_errno (ofp, ECTF_NOTENUM);
+         ctf_set_errno (ofp, ENOMEM);
          return NULL;
        }
+      i->cu.ctn_fp = ofp;
 
-      dtd = ctf_dynamic_type (fp, type);
       i->ctn_iter_fun = (void (*) (void)) ctf_enum_next;
-      i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+      en = ctf_vlen (fp, type, tp, &i->ctn_n);
 
-      if (dtd == NULL)
-       i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
-                                           i->ctn_increment);
-      else
-       i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;
+      if (kind == CTF_K_ENUM)
+       i->u.ctn_en = (const ctf_enum_t *) en;
+      else /* CTF_K_ENUM64 */
+       i->u.ctn_en64 = (const ctf_enum64_t *) en;
 
       *it = i;
     }
@@ -468,10 +464,20 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   if (i->ctn_n == 0)
     goto end_iter;
 
-  name = ctf_strptr (fp, i->u.ctn_en->cte_name);
-  if (val)
-    *val = i->u.ctn_en->cte_value;
-  i->u.ctn_en++;
+  if (ctf_type_kind (fp, type) == CTF_K_ENUM)
+    {
+      name = ctf_strptr (fp, i->u.ctn_en->cte_name);
+      if (val)
+       *val = i->u.ctn_en->cte_value;
+      i->u.ctn_en++;
+    }
+  else
+    {
+      name = ctf_strptr (fp, i->u.ctn_en64->cte_name);
+      if (val)
+       *val = ((uint64_t) i->u.ctn_en64->cte_val_high) << 32 | (i->u.ctn_en64->cte_val_low);
+      i->u.ctn_en64++;
+    }
   i->ctn_n--;
 
   return name;
@@ -936,6 +942,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
              ctf_decl_sprintf (&cd, "union %s", name);
              break;
            case CTF_K_ENUM:
+           case CTF_K_ENUM64:
              ctf_decl_sprintf (&cd, "enum %s", name);
              break;
            case CTF_K_FORWARD:
@@ -949,6 +956,7 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
                    ctf_decl_sprintf (&cd, "union %s", name);
                    break;
                  case CTF_K_ENUM:
+                 case CTF_K_ENUM64:
                    ctf_decl_sprintf (&cd, "enum %s", name);
                    break;
                  default:
@@ -1089,8 +1097,6 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
     case CTF_K_FUNCTION:
       return 0;                /* Function size is only known by symtab.  */
 
-    case CTF_K_ENUM:
-      return fp->ctf_dmodel->ctd_int;
 
     case CTF_K_ARRAY:
       /* ctf_add_array() does not directly encode the element size, but
@@ -1112,7 +1118,7 @@ ctf_type_size (ctf_dict_t *fp, ctf_id_t type)
       /* Forwards do not have a meaningful size.  */
       return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
 
-    default: /* including slices of enums, etc */
+    default: /* including enums of all kinds, slices, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
     }
 }
@@ -1227,14 +1233,11 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type)
        return align;
       }
 
-    case CTF_K_ENUM:
-      return fp->ctf_dmodel->ctd_int;
-
     case CTF_K_FORWARD:
       /* Forwards do not have a meaningful alignment.  */
       return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
 
-    default:  /* including slices of enums, etc */
+    default:  /* including enums of all kinds, slices, etc */
       return (ctf_get_ctt_size (fp, tp, NULL, NULL));
     }
 }
@@ -1416,8 +1419,8 @@ ctf_type_encoding (ctf_dict_t *fp, ctf_id_t type, ctf_encoding_t *ep)
       ep->cte_bits = CTF_FP_BITS (data);
       break;
     case CTF_K_ENUM:
-      /* v3 only: we must guess at the underlying integral format.  */
-      ep->cte_format = CTF_INT_SIGNED;
+    case CTF_K_ENUM64:
+      ep->cte_format = CTF_INFO_KFLAG (suffix->ctt_info) ? CTF_INT_SIGNED : 0;
       ep->cte_offset = 0;
       ep->cte_bits = 0;
       break;
@@ -1527,8 +1530,8 @@ ctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype,
     same_names = (strcmp (ctf_strptr (lfp, ltp->ctt_name),
                          ctf_strptr (rfp, rtp->ctt_name)) == 0);
 
-  if (((lkind == CTF_K_ENUM) && (rkind == CTF_K_INTEGER)) ||
-      ((rkind == CTF_K_ENUM) && (lkind == CTF_K_INTEGER)))
+  if ((((lkind == CTF_K_ENUM) || (lkind == CTF_K_ENUM64)) && (rkind == CTF_K_INTEGER)) ||
+      (((rkind == CTF_K_ENUM) || (lkind == CTF_K_ENUM64)) && (lkind == CTF_K_INTEGER)))
     return 1;
 
   if (lkind != rkind)
@@ -1556,6 +1559,7 @@ ctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype,
     case CTF_K_UNION:
       return (same_names && (ctf_type_size (lfp, ltype)
                             == ctf_type_size (rfp, rtype)));
+    case CTF_K_ENUM64:
     case CTF_K_ENUM:
       {
        int lencoded, rencoded;
@@ -1715,14 +1719,13 @@ ctf_array_info (ctf_dict_t *fp, ctf_id_t type, ctf_arinfo_t *arp)
    matching name can be found.  Otherwise NULL is returned.  */
 
 const char *
-ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
+ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int64_t value)
 {
   ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
-  const ctf_enum_t *ep;
-  const ctf_dtdef_t *dtd;
-  ssize_t increment;
-  uint32_t n;
+  unsigned char *vlen;
+  int kind;
+  size_t n;
 
   if (fp->ctf_flags & LCTF_NO_STR)
     {
@@ -1733,26 +1736,39 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
   if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
     return NULL;               /* errno is set for us.  */
 
-  if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+  if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
     return NULL;               /* errno is set for us.  */
 
-  if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+  kind = LCTF_KIND (fp, tp);
+  if (kind != CTF_K_ENUM && kind != CTF_K_ENUM64)
     {
       ctf_set_errno (ofp, ECTF_NOTENUM);
       return NULL;
     }
 
-  ctf_get_ctt_size (fp, tp, NULL, &increment);
+  vlen = ctf_vlen (fp, type, tp, &n);
 
-  if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-    ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
-  else
-    ep = (const ctf_enum_t *) dtd->dtd_vlen;
+  if (kind == CTF_K_ENUM)
+    {
+      const ctf_enum_t *ep = (const ctf_enum_t *) vlen;
 
-  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+      for (; n != 0; n--, ep++)
+       {
+         if (ep->cte_value == value)
+           return (ctf_strptr (fp, ep->cte_name));
+       }
+    }
+  else
     {
-      if (ep->cte_value == value)
-       return (ctf_strptr (fp, ep->cte_name));
+      const ctf_enum64_t *ep = (const ctf_enum64_t *) vlen;
+
+      for (; n != 0; n--, ep++)
+       {
+         int64_t this_value = ((uint64_t) ep->cte_val_high << 32) | (ep->cte_val_low);
+
+         if (this_value == value)
+           return (ctf_strptr (fp, ep->cte_name));
+       }
     }
 
   ctf_set_errno (ofp, ECTF_NOENUMNAM);
@@ -1763,14 +1779,13 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
    matching name can be found.  Otherwise CTF_ERR is returned.  */
 
 int
-ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
+ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int64_t *valp)
 {
   ctf_dict_t *ofp = fp;
   const ctf_type_t *tp;
-  const ctf_enum_t *ep;
-  const ctf_dtdef_t *dtd;
-  ssize_t increment;
-  uint32_t n;
+  unsigned char *vlen;
+  int kind;
+  size_t n;
 
   if (fp->ctf_flags & LCTF_NO_STR)
     return (ctf_set_errno (fp, ECTF_NOPARENT));
@@ -1778,32 +1793,78 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
   if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
     return -1;                 /* errno is set for us.  */
 
-  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.  */
 
-  if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+  kind = LCTF_KIND (fp, tp);
+  if (kind != CTF_K_ENUM && kind != CTF_K_ENUM64)
     return ctf_set_errno (ofp, ECTF_NOTENUM);
 
-  ctf_get_ctt_size (fp, tp, NULL, &increment);
+  vlen = ctf_vlen (fp, type, tp, &n);
 
-  if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
-    ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
-  else
-    ep = (const ctf_enum_t *) dtd->dtd_vlen;
+  if (kind == CTF_K_ENUM)
+    {
+      const ctf_enum_t *ep = (const ctf_enum_t *) vlen;
 
-  for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+      for (; n != 0; n--, ep++)
+       {
+         if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+           {
+             if (valp != NULL)
+               *valp = ep->cte_value;
+             return 0;
+           }
+       }
+    }
+  else
     {
-      if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+      const ctf_enum64_t *ep = (const ctf_enum64_t *) vlen;
+
+      for (; n != 0; n--, ep++)
        {
-         if (valp != NULL)
-           *valp = ep->cte_value;
-         return 0;
+         if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+           {
+             if (valp != NULL)
+               *valp = ((uint64_t) ep->cte_val_high << 32) | ep->cte_val_low;
+             return 0;
+           }
        }
     }
 
   return ctf_set_errno (ofp, ECTF_NOENUMNAM);
 }
 
+/* Like ctf_enum_value, but returns an unsigned int64_t instead.  */
+int
+ctf_enum_unsigned_value (ctf_dict_t *fp, ctf_id_t type, const char *name, uint64_t *valp)
+{
+  int ret;
+  int64_t retval;
+
+  ret = ctf_enum_value (fp, type, name, &retval);
+  *valp = (uint64_t) retval;
+  return ret;
+}
+
+/* Determine whether an enum's values are signed.  */
+int
+ctf_enum_unsigned (ctf_dict_t *fp, ctf_id_t type)
+{
+  int kind;
+  const ctf_type_t *tp;                /* The suffixed kind, if prefixed */
+
+  if ((kind = ctf_type_kind (fp, type)) < 0)
+    return -1;                 /* errno is set for us.  */
+
+  if (kind != CTF_K_ENUM && kind != CTF_K_ENUM64)
+    return (ctf_set_errno (fp, ECTF_NOTENUM));
+
+  if (ctf_lookup_by_id (&fp, type, &tp) == NULL)
+    return -1;                 /* errno is set for us.  */
+
+  return !CTF_INFO_KFLAG (tp->ctt_info);
+}
+
 /* Return nonzero if this struct or union uses bitfield encoding.  */
 int
 ctf_struct_bitfield (ctf_dict_t * fp, ctf_id_t type)
index a94b2fe08694540a026192fbac62aa6968bdee1f..107a52783d464e98216ddd032dd7200810d3fe1a 100644 (file)
@@ -90,7 +90,8 @@ LIBCTF_2.0 {
 
        ctf_enum_name;
        ctf_enum_value;
-
+       ctf_enum_unsigned_value;
+       ctf_enum_unsigned;
        ctf_lookup_enumerator;
        ctf_lookup_enumerator_next;
        ctf_arc_lookup_enumerator_next;
@@ -112,6 +113,8 @@ LIBCTF_2.0 {
        ctf_add_const;
        ctf_add_enum;
        ctf_add_enum_encoded;
+       ctf_add_enum64;
+       ctf_add_enum64_encoded;
        ctf_add_float;
        ctf_add_forward;
        ctf_add_function;