]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: adapt core dictops for v4 and prefix types
authorNick Alcock <nick.alcock@oracle.com>
Thu, 24 Apr 2025 12:50:38 +0000 (13:50 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:41 +0000 (18:07 +0100)
The heart of libctf's reading code is the ctf_dictops_t and the functions it
provides for reading various things no matter what the CTF version in use:
these are called via LCTF_*() macros that translate into calls into the
dictops.

The introduction of prefix types in v4 requires changes here: in particular,
we want the ability to get the type kind of whatever ctf_type_t we are
looking at (the 'unprefixed' kind), as well as the ability to get the type
kind taking prefixes into account: and more generally we want the ability
to both look at a given prefix and look at the type as a whole.  So several
ctf_dictops_t entries are added for this (ctfo_get_prefixed_kind,
ctfo_get_prefixed_vlen).

This means API changes (no callers yet adjusted, it'll happen as we go),
because the existing macros were mostly called with e.g. a ctt_info value
and returned a type kind, while now we need to be called with the actual
ctf_type_t itself, so we can possibly walk beyond it to find the real type
record.  ctfo_get_vbytes needs adjusting for this.

We also add names to most of the ctf_type_t parameters, because suddenly we
can have up to three of them: one relating to the first entry in the type
record (which may be a prefix, usually called 'prefix'), one relating to the
true type record (which may be a suffix, so usually called 'suffix'), and
one possibly relating to some intermediate record if we have multiple
prefixes (usually called 'tp').

There is one horrible special case in here: the vlen of the new
CTF_K_FUNC_LINKAGE kind (equivalent to BTF_KIND_FUNC) is always zero: it
reuses the vlen field to encode the linkage (!).  BTF is rife with ugly
hacks like this.

libctf/ctf-impl.h
libctf/ctf-open.c

index 4b9518b54382edf4433aa8cacec1d917201ed28a..6a6ed8eda7ad0b6ee3e3455df627058051562983 100644 (file)
@@ -133,11 +133,13 @@ typedef struct ctf_lookup
 typedef struct ctf_dictops
 {
   uint32_t (*ctfo_get_kind) (uint32_t);
+  uint32_t (*ctfo_get_prefixed_kind) (const ctf_type_t *tp);
   uint32_t (*ctfo_get_root) (uint32_t);
   uint32_t (*ctfo_get_vlen) (uint32_t);
-  ssize_t (*ctfo_get_ctt_size) (const ctf_dict_t *, const ctf_type_t *,
+  uint32_t (*ctfo_get_prefixed_vlen) (const ctf_type_t *tp);
+  ssize_t (*ctfo_get_ctt_size) (const ctf_dict_t *, const ctf_type_t *tp,
                                ssize_t *, ssize_t *);
-  ssize_t (*ctfo_get_vbytes) (ctf_dict_t *, unsigned short, ssize_t, size_t);
+  ssize_t (*ctfo_get_vbytes) (ctf_dict_t *, const ctf_type_t *, ssize_t);
 } ctf_dictops_t;
 
 typedef struct ctf_list
@@ -593,11 +595,24 @@ extern ctf_id_t ctf_index_to_type (const ctf_dict_t *, uint32_t);
    &(ctf_dtd_lookup (fp, ctf_index_to_type (fp, i))->dtd_data) :       \
    (ctf_type_t *)((uintptr_t)(fp)->ctf_buf + (fp)->ctf_txlate[(i)]))
 
-#define LCTF_INFO_KIND(fp, info)       ((fp)->ctf_dictops->ctfo_get_kind(info))
+/* The non *INFO variants of these macros acquire the relevant info from the
+   suffixed type, if the type is prefixed.  (Internally to libctf, all types
+   that may ever take a prefix are prefixed until they are written out, so that
+   nothing special needs to be done to handle them should their size later
+   expand past the limit where prefixing is needed.)  */
+
+#define LCTF_INFO_UNPREFIXED_KIND(fp, info) ((fp)->ctf_dictops->ctfo_get_kind(info))
+#define LCTF_KIND(fp, tp)              ((fp)->ctf_dictops->ctfo_get_prefixed_kind(tp))
 #define LCTF_INFO_ISROOT(fp, info)     ((fp)->ctf_dictops->ctfo_get_root(info))
-#define LCTF_INFO_VLEN(fp, info)       ((fp)->ctf_dictops->ctfo_get_vlen(info))
-#define LCTF_VBYTES(fp, kind, size, vlen) \
-  ((fp)->ctf_dictops->ctfo_get_vbytes(fp, kind, size, vlen))
+#define LCTF_VLEN(fp, tp)              ((fp)->ctf_dictops->ctfo_get_prefixed_vlen(tp))
+#define LCTF_INFO_UNPREFIXED_VLEN(fp, info)    ((fp)->ctf_dictops->ctfo_get_vlen(info))
+#define LCTF_VBYTES(fp, tp, size) \
+  ((fp)->ctf_dictops->ctfo_get_vbytes (fp, tp, size))
+
+#define LCTF_IS_PREFIXED_KIND(kind) (kind == CTF_K_BIG || kind == CTF_K_CONFLICTING)
+#define LCTF_IS_PREFIXED_INFO(info)                    \
+  ((CTF_INFO_KIND ((info)) == CTF_K_BIG)               \
+   || (CTF_INFO_KIND ((info)) == CTF_K_CONFLICTING))
 
 #define LCTF_CHILD             0x0001  /* CTF dict is a child.  */
 #define LCTF_LINKING           0x0002  /* CTF link is underway: respect ctf_link_flags.  */
@@ -807,6 +822,9 @@ extern ctf_link_sym_t *ctf_elf32_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *ds
 extern ctf_link_sym_t *ctf_elf64_to_link_sym (ctf_dict_t *fp, ctf_link_sym_t *dst,
                                              const Elf64_Sym *src, uint32_t symidx);
 
+ssize_t get_ctt_size_v2_unconverted (const ctf_dict_t *, const ctf_type_t *,
+                                    ssize_t *sizep, ssize_t *incrementp);
+
 /* Variables, all underscore-prepended. */
 
 extern const char _CTF_SECTION[];      /* name of CTF ELF section */
index fb8a752ca53044b2fb699747696b864b10045aef..b17dae6bdbdc07af2a7bb06e12d5038fc479fd8f 100644 (file)
@@ -43,10 +43,16 @@ get_kind_v1 (uint32_t info)
   return (CTF_V1_INFO_KIND (info));
 }
 
+static uint32_t
+get_prefixed_kind_v1 (const ctf_type_t *tp)
+{
+  return (CTF_V1_INFO_KIND (tp->ctt_info));
+}
+
 static uint32_t
 get_root_v1 (uint32_t info)
 {
-  return (CTF_V1_INFO_ISROOT (info));
+  return !!(CTF_V1_INFO_ISROOT (info));
 }
 
 static uint32_t
@@ -55,16 +61,28 @@ get_vlen_v1 (uint32_t info)
   return (CTF_V1_INFO_VLEN (info));
 }
 
+static uint32_t
+get_prefixed_vlen_v1 (const ctf_type_t *tp)
+{
+  return (CTF_V1_INFO_VLEN (tp->ctt_info));
+}
+
 static uint32_t
 get_kind_v2 (uint32_t info)
 {
   return (CTF_V2_INFO_KIND (info));
 }
 
+static uint32_t
+get_prefixed_kind_v2 (const ctf_type_t *tp)
+{
+  return (CTF_V2_INFO_KIND (tp->ctt_info));
+}
+
 static uint32_t
 get_root_v2 (uint32_t info)
 {
-  return (CTF_V2_INFO_ISROOT (info));
+  return !!(CTF_V2_INFO_ISROOT (info));
 }
 
 static uint32_t
@@ -73,12 +91,72 @@ get_vlen_v2 (uint32_t info)
   return (CTF_V2_INFO_VLEN (info));
 }
 
+static uint32_t
+get_prefixed_vlen_v2 (const ctf_type_t *tp)
+{
+  return (CTF_V2_INFO_VLEN (tp->ctt_info));
+}
+
+static uint32_t
+get_kind_v4 (uint32_t info)
+{
+  return (CTF_INFO_KIND (info));
+}
+
+static uint32_t
+get_prefixed_kind_v4 (const ctf_type_t *tp)
+{
+  /* Resolve away as many prefixes as exist.  */
+
+  while (LCTF_IS_PREFIXED_INFO (tp->ctt_info))
+    tp++;
+
+  return CTF_INFO_KIND (tp->ctt_info);
+}
+
+static uint32_t
+get_root_v4 (uint32_t info)
+{
+  return (CTF_INFO_KIND (info) != CTF_K_CONFLICTING);
+}
+
+static uint32_t
+get_vlen_v4 (uint32_t info)
+{
+  return (CTF_INFO_VLEN (info));
+}
+
+static uint32_t
+get_prefixed_vlen_v4 (const ctf_type_t *tp)
+{
+  const ctf_type_t *suffix;
+
+  /* Resolve away non-BIG prefixes (which have no affect on vlen).  */
+
+  while (LCTF_IS_PREFIXED_INFO (tp->ctt_info)
+        && CTF_INFO_KIND (tp->ctt_info) != CTF_K_BIG)
+    tp++;
+
+  if (!LCTF_IS_PREFIXED_INFO (tp->ctt_info))
+    return (CTF_INFO_VLEN (tp->ctt_info));
+
+  suffix = tp + 1;
+
+  /* Special case: CTF_K_FUNC_LINKAGE reuses the vlen field for the linkage: its
+     vlen is always zero.  */
+  if (CTF_INFO_KIND (suffix->ctt_info) == CTF_K_FUNC_LINKAGE)
+    return 0;
+
+  /* CTF_K_BIG.  */
+  return (CTF_INFO_VLEN (tp->ctt_info) << 16 | CTF_INFO_VLEN (suffix->ctt_info));
+}
+
 static inline ssize_t
-get_ctt_size_common (const ctf_dict_t *fp _libctf_unused_,
-                    const ctf_type_t *tp _libctf_unused_,
-                    ssize_t *sizep, ssize_t *incrementp, size_t lsize,
-                    size_t csize, size_t ctf_type_size,
-                    size_t ctf_stype_size, size_t ctf_lsize_sent)
+get_ctt_size_old (const ctf_dict_t *fp _libctf_unused_,
+                 const ctf_type_t *tp _libctf_unused_,
+                 ssize_t *sizep, ssize_t *incrementp, size_t lsize,
+                 size_t csize, size_t ctf_type_size,
+                 size_t ctf_stype_size, size_t ctf_lsize_sent)
 {
   ssize_t size, increment;
 
@@ -107,56 +185,91 @@ get_ctt_size_v1 (const ctf_dict_t *fp, const ctf_type_t *tp,
 {
   ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp;
 
-  return (get_ctt_size_common (fp, tp, sizep, incrementp,
-                              CTF_TYPE_LSIZE (t1p), t1p->ctt_size,
-                              sizeof (ctf_type_v1_t), sizeof (ctf_stype_v1_t),
-                              CTF_LSIZE_SENT_V1));
+  return (get_ctt_size_old (fp, tp, sizep, incrementp,
+                           CTF_V3_TYPE_LSIZE (t1p), t1p->ctt_size,
+                           sizeof (ctf_type_v1_t), sizeof (ctf_stype_v1_t),
+                           CTF_LSIZE_SENT_V1));
 }
 
 /* Return the size that a v1 will be once it is converted to v2.  */
 
-static ssize_t
+ssize_t
 get_ctt_size_v2_unconverted (const ctf_dict_t *fp, const ctf_type_t *tp,
                             ssize_t *sizep, ssize_t *incrementp)
 {
   ctf_type_v1_t *t1p = (ctf_type_v1_t *) tp;
 
-  return (get_ctt_size_common (fp, tp, sizep, incrementp,
-                              CTF_TYPE_LSIZE (t1p), t1p->ctt_size,
-                              sizeof (ctf_type_t), sizeof (ctf_stype_t),
-                              CTF_LSIZE_SENT));
+  return (get_ctt_size_old (fp, tp, sizep, incrementp,
+                           CTF_V3_TYPE_LSIZE (t1p), t1p->ctt_size,
+                           sizeof (ctf_type_v2_t), sizeof (ctf_stype_v2_t),
+                           CTF_LSIZE_SENT));
 }
 
 static ssize_t
 get_ctt_size_v2 (const ctf_dict_t *fp, const ctf_type_t *tp,
                 ssize_t *sizep, ssize_t *incrementp)
 {
-  return (get_ctt_size_common (fp, tp, sizep, incrementp,
-                              CTF_TYPE_LSIZE (tp), tp->ctt_size,
-                              sizeof (ctf_type_t), sizeof (ctf_stype_t),
-                              CTF_LSIZE_SENT));
+  ctf_type_v2_t *t2p = (ctf_type_v2_t *) tp;
+
+  return (get_ctt_size_old (fp, tp, sizep, incrementp,
+                           CTF_V3_TYPE_LSIZE (t2p), t2p->ctt_size,
+                           sizeof (ctf_type_v2_t), sizeof (ctf_stype_v2_t),
+                           CTF_LSIZE_SENT));
+}
+
+static ssize_t
+get_ctt_size_v4 (const ctf_dict_t *fp _libctf_unused_, const ctf_type_t *tp,
+                ssize_t *sizep, ssize_t *incrementp)
+{
+  ssize_t size = 0;
+
+  /* Figure out how many prefixes there are, and adjust the size appropriately
+     if we pass a BIG.  */
+
+  if (incrementp)
+    *incrementp = 0;
+
+  while (LCTF_IS_PREFIXED_INFO (tp->ctt_info))
+    {
+      if (CTF_INFO_KIND (tp->ctt_info) == CTF_K_BIG)
+       size = ((ssize_t) tp->ctt_size) << 32;
+
+      if (incrementp)
+       *incrementp += sizeof (ctf_type_t);
+
+      tp++;
+    }
+
+  if (incrementp)
+    *incrementp += sizeof (ctf_type_t);
+
+  size |= tp->ctt_size;
+
+  if (sizep)
+    *sizep = size;
+
+  return size;
 }
 
 static ssize_t
-get_vbytes_common (ctf_dict_t *fp, unsigned short kind,
-                  ssize_t size _libctf_unused_, size_t vlen)
+get_vbytes_old (ctf_dict_t *fp, unsigned short kind, size_t vlen)
 {
   switch (kind)
     {
-    case CTF_K_INTEGER:
-    case CTF_K_FLOAT:
+    case CTF_V3_K_INTEGER:
+    case CTF_V3_K_FLOAT:
       return (sizeof (uint32_t));
-    case CTF_K_SLICE:
+    case CTF_V3_K_SLICE:
       return (sizeof (ctf_slice_t));
-    case CTF_K_ENUM:
+    case CTF_V3_K_ENUM:
       return (sizeof (ctf_enum_t) * vlen);
-    case CTF_K_FORWARD:
-    case CTF_K_UNKNOWN:
-    case CTF_K_POINTER:
-    case CTF_K_TYPEDEF:
-    case CTF_K_VOLATILE:
-    case CTF_K_CONST:
-    case CTF_K_RESTRICT:
+    case CTF_V3_K_FORWARD:
+    case CTF_V3_K_UNKNOWN:
+    case CTF_V3_K_POINTER:
+    case CTF_V3_K_TYPEDEF:
+    case CTF_V3_K_VOLATILE:
+    case CTF_V3_K_CONST:
+    case CTF_V3_K_RESTRICT:
       return 0;
     default:
       ctf_set_errno (fp, ECTF_CORRUPT);
@@ -166,57 +279,124 @@ get_vbytes_common (ctf_dict_t *fp, unsigned short kind,
 }
 
 static ssize_t
-get_vbytes_v1 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen)
+get_vbytes_v1 (ctf_dict_t *fp, const ctf_type_t *tp, ssize_t size)
 {
+  unsigned short kind = CTF_V1_INFO_KIND (tp->ctt_info);
+  size_t vlen = CTF_V1_INFO_VLEN (tp->ctt_info);
+
   switch (kind)
     {
-    case CTF_K_ARRAY:
+    case CTF_V3_K_ARRAY:
       return (sizeof (ctf_array_v1_t));
-    case CTF_K_FUNCTION:
+    case CTF_V3_K_FUNCTION:
       return (sizeof (unsigned short) * (vlen + (vlen & 1)));
-    case CTF_K_STRUCT:
-    case CTF_K_UNION:
+    case CTF_V3_K_STRUCT:
+    case CTF_V3_K_UNION:
       if (size < CTF_LSTRUCT_THRESH_V1)
        return (sizeof (ctf_member_v1_t) * vlen);
       else
        return (sizeof (ctf_lmember_v1_t) * vlen);
     }
 
-  return (get_vbytes_common (fp, kind, size, vlen));
+  return (get_vbytes_old (fp, kind, vlen));
 }
 
 static ssize_t
-get_vbytes_v2 (ctf_dict_t *fp, unsigned short kind, ssize_t size, size_t vlen)
+get_vbytes_v2 (ctf_dict_t *fp, const ctf_type_t *tp, ssize_t size)
 {
+  unsigned short kind = CTF_V2_INFO_KIND (tp->ctt_info);
+  size_t vlen = CTF_V2_INFO_VLEN (tp->ctt_info);
+
   switch (kind)
     {
-    case CTF_K_ARRAY:
+    case CTF_V3_K_ARRAY:
       return (sizeof (ctf_array_t));
-    case CTF_K_FUNCTION:
+    case CTF_V3_K_FUNCTION:
       return (sizeof (uint32_t) * (vlen + (vlen & 1)));
-    case CTF_K_STRUCT:
-    case CTF_K_UNION:
+    case CTF_V3_K_STRUCT:
+    case CTF_V3_K_UNION:
       if (size < CTF_LSTRUCT_THRESH)
-       return (sizeof (ctf_member_t) * vlen);
+       return (sizeof (ctf_member_v2_t) * vlen);
       else
-       return (sizeof (ctf_lmember_t) * vlen);
+       return (sizeof (ctf_lmember_v2_t) * vlen);
     }
 
-  return (get_vbytes_common (fp, kind, size, vlen));
+  return (get_vbytes_old (fp, kind, vlen));
+}
+
+static ssize_t
+get_vbytes_v4 (ctf_dict_t *fp, const ctf_type_t *tp,
+              ssize_t size _libctf_unused_)
+{
+  unsigned short kind = LCTF_KIND (fp, tp);
+  ssize_t vlen = LCTF_VLEN (fp, tp);
+
+  switch (kind)
+    {
+    case CTF_K_INTEGER:
+    case CTF_K_FLOAT:
+      return (sizeof (uint32_t));
+    case CTF_K_SLICE:
+      return (sizeof (ctf_slice_t));
+    case CTF_K_ENUM:
+      return (sizeof (ctf_enum_t) * vlen);
+    case CTF_K_ENUM64:
+      return (sizeof (ctf_enum64_t) * vlen);
+    case CTF_K_ARRAY:
+      return (sizeof (ctf_array_t));
+    case CTF_K_STRUCT:
+    case CTF_K_UNION:
+      return (sizeof (ctf_member_t) * vlen);
+    case CTF_K_FUNCTION:
+      return (sizeof (ctf_param_t) * vlen);
+    case CTF_K_VAR:
+      return (sizeof (ctf_linkage_t));
+    case CTF_K_DATASEC:
+      return (sizeof (ctf_var_secinfo_t) * vlen);
+    case CTF_K_DECL_TAG:
+      return (sizeof (ctf_decl_tag_t));
+    case CTF_K_TYPE_TAG:
+    case CTF_K_FORWARD:
+    case CTF_K_UNKNOWN:
+    case CTF_K_POINTER:
+    case CTF_K_TYPEDEF:
+    case CTF_K_VOLATILE:
+    case CTF_K_CONST:
+    case CTF_K_RESTRICT:
+    case CTF_K_FUNC_LINKAGE:
+    case CTF_K_BTF_FLOAT:
+      return 0;
+    /* These should have been resolved away by LCTF_KIND.
+       If this somehow didn't work, fail.  */
+    case CTF_K_BIG:
+    case CTF_K_CONFLICTING:
+      ctf_set_errno (fp, ECTF_INTERNAL);
+      ctf_err_warn (fp, 0, 0, _("internal error: prefixed kind seen in get_vbytes_v4: %x"), kind);
+      return -1;
+    default:
+      ctf_set_errno (fp, ECTF_CORRUPT);
+      ctf_err_warn (fp, 0, 0, _("detected invalid CTF kind: %x"), kind);
+      return -1;
+    }
 }
 
 static const ctf_dictops_t ctf_dictops[] = {
-  {NULL, NULL, NULL, NULL, NULL},
+  {NULL, NULL, NULL, NULL, NULL, NULL, NULL},
   /* CTF_VERSION_1 */
-  {get_kind_v1, get_root_v1, get_vlen_v1, get_ctt_size_v1, get_vbytes_v1},
+  {get_kind_v1, get_prefixed_kind_v1, get_root_v1, get_vlen_v1,
+   get_prefixed_vlen_v1, get_ctt_size_v1, get_vbytes_v1},
   /* CTF_VERSION_1_UPGRADED_3 */
-  {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
+  {get_kind_v2, get_prefixed_kind_v2, get_root_v2, get_vlen_v2,
+   get_prefixed_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
   /* CTF_VERSION_2 */
-  {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
+  {get_kind_v2, get_prefixed_kind_v2, get_root_v2, get_vlen_v2,
+   get_prefixed_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
   /* CTF_VERSION_3, identical to 2: only new type kinds */
-  {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
-  /* UPTODO: CTF_VERSION_4, identical to 3 at present (but not for long) */
-  {get_kind_v2, get_root_v2, get_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
+  {get_kind_v2, get_prefixed_kind_v2, get_root_v2, get_vlen_v2,
+   get_prefixed_vlen_v2, get_ctt_size_v2, get_vbytes_v2},
+  /* CTF_VERSION_4, always BTF-compatible.  */
+  {get_kind_v4, get_prefixed_kind_v4, get_root_v4, get_vlen_v4,
+   get_prefixed_vlen_v4, get_ctt_size_v4, get_vbytes_v4},
 };
 
 /* Initialize the symtab translation table as appropriate for its indexing