]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: adjust foreign-endian byteswapping for v4
authorNick Alcock <nick.alcock@oracle.com>
Thu, 24 Apr 2025 13:27:48 +0000 (14:27 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:41 +0000 (18:07 +0100)
Split into a separate commit because it's not yet really tested.

Callers not yet adjusted.

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

index 456d9d75967b2e5963596efcdf27698fb99c70d7..df84911e99558f5ad1d1c3c5dd69b1200802dda2 100644 (file)
@@ -787,8 +787,9 @@ extern struct ctf_archive *ctf_arc_open_internal (const char *, int *);
 extern void ctf_arc_close_internal (struct ctf_archive *);
 extern const ctf_preamble_t *ctf_arc_bufpreamble (const ctf_sect_t *);
 extern void *ctf_set_open_errno (int *, int);
-extern void ctf_flip_header (ctf_header_t *);
-extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *, int);
+extern int ctf_flip_header (void *, int, int);
+extern int ctf_flip (ctf_dict_t *, ctf_header_t *, unsigned char *,
+                    int is_btf, int to_foreign);
 
 extern int ctf_import_unref (ctf_dict_t *fp, ctf_dict_t *pfp);
 
index 61dbdd55d03b6095bfe75d8d480175aac883a5fc..a4b1827955567cd10cc9dbc285784e1e1e68e561 100644 (file)
@@ -1027,39 +1027,71 @@ init_static_types_names_internal (ctf_dict_t *fp, ctf_header_t *cth,
 
 /* Flip the endianness of the CTF header.  */
 
-void
-ctf_flip_header (ctf_header_t *cth)
+int
+ctf_flip_header (void *cthp, int is_btf, int ctf_version)
 {
-  swap_thing (cth->cth_preamble.ctp_magic);
-  swap_thing (cth->cth_preamble.ctp_version);
-  swap_thing (cth->cth_preamble.ctp_flags);
-  swap_thing (cth->cth_parlabel);
-  swap_thing (cth->cth_parname);
-  swap_thing (cth->cth_cuname);
-  swap_thing (cth->cth_parent_strlen);
-  swap_thing (cth->cth_objtoff);
-  swap_thing (cth->cth_funcoff);
-  swap_thing (cth->cth_objtidxoff);
-  swap_thing (cth->cth_funcidxoff);
-  swap_thing (cth->cth_varoff);
-  swap_thing (cth->cth_typeoff);
-  swap_thing (cth->cth_stroff);
-  swap_thing (cth->cth_strlen);
-}
+  ctf_header_t *cth = (ctf_header_t *) cthp;
 
-/* Flip the endianness of the label section, an array of ctf_lblent_t.  */
+  if (is_btf)
+    {
+      ctf_btf_header_t *bth = (ctf_btf_header_t *) cthp;
+
+      swap_thing (bth->bth_preamble.btf_magic);
+      swap_thing (bth->bth_preamble.btf_version);
+      swap_thing (bth->bth_preamble.btf_flags);
+      swap_thing (bth->bth_hdr_len);
+      swap_thing (bth->bth_type_off);
+      swap_thing (bth->bth_type_len);
+      swap_thing (bth->bth_str_off);
+      swap_thing (bth->bth_str_len);
+
+      /* Raw BTF?  */
+      if (ctf_version == 1)
+       return 0;
+    }
+  else
+    {
+#if 0
+      ctf_header_v2_t *h2p = (ctf_header_v2_t *) cthp;
+      ctf_header_v3_t *h3p = (ctf_header_v3_t *) cthp;
+#endif
 
-static void
-flip_lbls (void *start, size_t len)
-{
-  ctf_lblent_t *lbl = start;
-  ssize_t i;
+      /* Non-BTF-compatible: old CTF release.  */
+      switch (ctf_version) {
+      case CTF_VERSION_1:
+      case CTF_VERSION_1_UPGRADED_3:
+      case CTF_VERSION_2:
+       ctf_err_warn (NULL, 0, ECTF_INTERNAL, "Implementation of backward-compatible CTF reading still underway\n");
+       return -ECTF_INTERNAL;
+/*     ctf_flip_header_v2 (h2p); */
+      break;
+      case CTF_VERSION_3:
+       ctf_err_warn (NULL, 0, ECTF_INTERNAL, "Implementation of backward-compatible CTF reading still underway\n");
+       return -ECTF_INTERNAL;
 
-  for (i = len / sizeof (struct ctf_lblent); i > 0; lbl++, i--)
-    {
-      swap_thing (lbl->ctl_label);
-      swap_thing (lbl->ctl_type);
+/*     ctf_flip_header_v3 (h3p); */
+      }
+      return 0;
     }
+
+  /* CTFv4.  */
+
+  swap_thing (cth->cth_preamble.ctp_magic_version);
+  swap_thing (cth->cth_preamble.ctp_flags);
+  swap_thing (cth->cth_cu_name);
+  swap_thing (cth->cth_parent_name);
+  swap_thing (cth->cth_parent_strlen);
+  swap_thing (cth->cth_parent_ntypes);
+  swap_thing (cth->cth_objt_off);
+  swap_thing (cth->cth_objt_len);
+  swap_thing (cth->cth_func_off);
+  swap_thing (cth->cth_func_len);
+  swap_thing (cth->cth_objtidx_off);
+  swap_thing (cth->cth_objtidx_len);
+  swap_thing (cth->cth_funcidx_off);
+  swap_thing (cth->cth_funcidx_len);
+
+  return 0;
 }
 
 /* Flip the endianness of the data-object or function sections or their indexes,
@@ -1075,23 +1107,8 @@ flip_objts (void *start, size_t len)
       swap_thing (*obj);
 }
 
-/* Flip the endianness of the variable section, an array of ctf_varent_t.  */
-
-static void
-flip_vars (void *start, size_t len)
-{
-  ctf_varent_t *var = start;
-  ssize_t i;
-
-  for (i = len / sizeof (struct ctf_varent); i > 0; var++, i--)
-    {
-      swap_thing (var->ctv_name);
-      swap_thing (var->ctv_type);
-    }
-}
-
-/* Flip the endianness of the type section, a tagged array of ctf_type or
-   ctf_stype followed by variable data.  */
+/* Flip the endianness of the type section, a tagged array of ctf_type followed
+   by variable data (which may itself be a ctf_type for prefixed kinds).  */
 
 static int
 flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
@@ -1101,45 +1118,60 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
   while ((uintptr_t) t < ((uintptr_t) start) + len)
     {
       uint32_t kind;
-      size_t size;
+      uint32_t raw_kind;
       uint32_t vlen;
       size_t vbytes;
+      ctf_type_t *tprefixed;
 
       if (to_foreign)
        {
-         kind = CTF_V2_INFO_KIND (t->ctt_info);
-         size = t->ctt_size;
-         vlen = CTF_V2_INFO_VLEN (t->ctt_info);
-         vbytes = get_vbytes_v2 (fp, kind, size, vlen);
+         kind = LCTF_KIND (fp, t);
+         raw_kind = LCTF_INFO_UNPREFIXED_KIND (fp, t->ctt_info);
+         vlen = LCTF_VLEN (fp, t);
+         vbytes = get_vbytes_v4 (fp, t, 0);
        }
 
       swap_thing (t->ctt_name);
       swap_thing (t->ctt_info);
       swap_thing (t->ctt_size);
 
-      if (!to_foreign)
+      /* Prefixed kind: flip the kind being prefixed too (for as many prefixes
+        as there are).  */
+      tprefixed = t;
+      while (LCTF_IS_PREFIXED_KIND (raw_kind))
        {
-         kind = CTF_V2_INFO_KIND (t->ctt_info);
-         size = t->ctt_size;
-         vlen = CTF_V2_INFO_VLEN (t->ctt_info);
-         vbytes = get_vbytes_v2 (fp, kind, size, vlen);
+         tprefixed++;
+
+         if ((uintptr_t) tprefixed > ((uintptr_t) start) + len)
+           goto overflow;
+
+         swap_thing (tprefixed->ctt_name);
+         swap_thing (tprefixed->ctt_info);
+         swap_thing (tprefixed->ctt_size);
+         raw_kind = LCTF_INFO_UNPREFIXED_KIND (fp, tprefixed->ctt_info);
        }
 
-      if (_libctf_unlikely_ (size == CTF_LSIZE_SENT))
+      if (!to_foreign)
        {
-         if (to_foreign)
-           size = CTF_TYPE_LSIZE (t);
+         kind = LCTF_KIND (fp, t);
+         raw_kind = LCTF_INFO_UNPREFIXED_KIND (fp, t->ctt_info);
+         vlen = LCTF_VLEN (fp, t);
+         vbytes = get_vbytes_v4 (fp, t, 0);
+       }
 
-         swap_thing (t->ctt_lsizehi);
-         swap_thing (t->ctt_lsizelo);
+      /* Move on to the vlen region.  */
+      raw_kind = LCTF_INFO_UNPREFIXED_KIND (fp, t->ctt_info);
+      while (LCTF_IS_PREFIXED_KIND (raw_kind))
+       {
+         t++;
+         raw_kind = LCTF_INFO_UNPREFIXED_KIND (fp, t->ctt_info);
+       }
 
-         if (!to_foreign)
-           size = CTF_TYPE_LSIZE (t);
+      if (((uintptr_t) t) + sizeof (ctf_type_t) + vbytes
+         > ((uintptr_t) start) + len)
+       goto overflow;
 
-         t = (ctf_type_t *) ((uintptr_t) t + sizeof (ctf_type_t));
-       }
-      else
-       t = (ctf_type_t *) ((uintptr_t) t + sizeof (ctf_stype_t));
+      t++;
 
       switch (kind)
        {
@@ -1150,14 +1182,17 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
        case CTF_K_VOLATILE:
        case CTF_K_CONST:
        case CTF_K_RESTRICT:
-         /* These types have no vlen data to swap.  */
+       case CTF_K_TYPE_TAG:
+       case CTF_K_BTF_FLOAT:
+       case CTF_K_FUNC_LINKAGE:
+         /* These kinds have no vlen data to swap.  */
          assert (vbytes == 0);
          break;
 
        case CTF_K_INTEGER:
        case CTF_K_FLOAT:
          {
-           /* These types have a single uint32_t.  */
+           /* These kinds have a single uint32_t.  */
 
            uint32_t *item = (uint32_t *) t;
 
@@ -1165,18 +1200,38 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
            break;
          }
 
+       case CTF_K_VAR:
+         {
+           /* This has a single ctf_linkage_t.  */
+           ctf_linkage_t *l = (ctf_linkage_t *) t;
+
+           swap_thing (l->ctl_linkage);
+           break;
+         }
+
+       case CTF_K_DECL_TAG:
+         {
+           /* This has a single ctf_decl_tag_t.  */
+           ctf_decl_tag_t *d = (ctf_decl_tag_t *) t;
+
+           swap_thing (d->cdt_component_idx);
+           break;
+         }
+
        case CTF_K_FUNCTION:
          {
-           /* This type has a bunch of uint32_ts.  */
+           /* This kind has a bunch of ctf_param_t's.  */
 
-           uint32_t *item = (uint32_t *) t;
+           ctf_param_t *p = (ctf_param_t *) t;
            ssize_t i;
 
-           for (i = vlen; i > 0; item++, i--)
-             swap_thing (*item);
+           for (i = vlen; i > 0; p++, i--)
+             {
+               swap_thing (p->cfp_name);
+               swap_thing (p->cfp_type);
+             }
            break;
          }
-
        case CTF_K_ARRAY:
          {
            /* This has a single ctf_array_t.  */
@@ -1208,33 +1263,19 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
        case CTF_K_STRUCT:
        case CTF_K_UNION:
          {
-           /* This has an array of ctf_member or ctf_lmember, depending on
-              size.  We could consider it to be a simple array of uint32_t,
-              but for safety's sake in case these structures ever acquire
+           /* This has an array of ctf_member_t: the interpretation differs in
+              prefixed types, but for the purposes of byteswapping we don't
+              care.  We could consider it to be a simple array of uint32_t, but
+              for safety's sake in case these structures ever acquire
               non-uint32_t members, do it member by member.  */
 
-           if (_libctf_unlikely_ (size >= CTF_LSTRUCT_THRESH))
-             {
-               ctf_lmember_t *lm = (ctf_lmember_t *) t;
-               ssize_t i;
-               for (i = vlen; i > 0; i--, lm++)
-                 {
-                   swap_thing (lm->ctlm_name);
-                   swap_thing (lm->ctlm_offsethi);
-                   swap_thing (lm->ctlm_type);
-                   swap_thing (lm->ctlm_offsetlo);
-                 }
-             }
-           else
+           ctf_member_t *m = (ctf_member_t *) t;
+           ssize_t i;
+           for (i = vlen; i > 0; i--, m++)
              {
-               ctf_member_t *m = (ctf_member_t *) t;
-               ssize_t i;
-               for (i = vlen; i > 0; i--, m++)
-                 {
-                   swap_thing (m->ctm_name);
-                   swap_thing (m->ctm_offset);
-                   swap_thing (m->ctm_type);
-                 }
+               swap_thing (m->ctm_name);
+               swap_thing (m->ctm_type);
+               swap_thing (m->ctm_offset);
              }
            break;
          }
@@ -1253,6 +1294,39 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
              }
            break;
          }
+
+       case CTF_K_ENUM64:
+         {
+           /* This has an array of ctf_enum64_t.  */
+
+           ctf_enum64_t *item = (ctf_enum64_t *) t;
+           ssize_t i;
+
+           for (i = vlen; i > 0; item++, i--)
+             {
+               swap_thing (item->cte_name);
+               swap_thing (item->cte_val_low);
+               swap_thing (item->cte_val_high);
+             }
+           break;
+         }
+
+       case CTF_K_DATASEC:
+         {
+           /* This has an array of ctf_var_secinfo_t.  */
+
+           ctf_var_secinfo_t *item = (ctf_var_secinfo_t *) t;
+           ssize_t i;
+
+           for (i = vlen; i > 0; item++, i--)
+             {
+               swap_thing (item->cvs_type);
+               swap_thing (item->cvs_offset);
+               swap_thing (item->cvs_size);
+             }
+           break;
+         }
+
        default:
          ctf_err_warn (fp, 0, ECTF_CORRUPT,
                        _("unhandled CTF kind in endianness conversion: %x"),
@@ -1264,29 +1338,30 @@ flip_types (ctf_dict_t *fp, void *start, size_t len, int to_foreign)
     }
 
   return 0;
+
+ overflow:
+  ctf_err_warn (fp, 0, ECTF_CORRUPT, _("overflow byteswapping CTF"));
+  return ECTF_CORRUPT;
 }
 
 /* Flip the endianness of BUF, given the offsets in the (native-endianness) CTH.
-   If TO_FOREIGN is set, flip to foreign-endianness; if not, flip away.
-
-   All of this stuff happens before the header is fully initialized, so the
-   LCTF_*() macros cannot be used yet.  Since we do not try to endian-convert v1
-   data, this is no real loss.  */
+   If TO_FOREIGN is set, flip to foreign-endianness; if not, flip away.  */
 
 int
 ctf_flip (ctf_dict_t *fp, ctf_header_t *cth, unsigned char *buf,
-         int to_foreign)
+         int is_btf, int to_foreign)
 {
-  ctf_dprintf("flipping endianness\n");
-
-  flip_lbls (buf + cth->cth_lbloff, cth->cth_objtoff - cth->cth_lbloff);
-  flip_objts (buf + cth->cth_objtoff, cth->cth_funcoff - cth->cth_objtoff);
-  flip_objts (buf + cth->cth_funcoff, cth->cth_objtidxoff - cth->cth_funcoff);
-  flip_objts (buf + cth->cth_objtidxoff, cth->cth_funcidxoff - cth->cth_objtidxoff);
-  flip_objts (buf + cth->cth_funcidxoff, cth->cth_varoff - cth->cth_funcidxoff);
-  flip_vars (buf + cth->cth_varoff, cth->cth_typeoff - cth->cth_varoff);
-  return flip_types (fp, buf + cth->cth_typeoff,
-                    cth->cth_stroff - cth->cth_typeoff, to_foreign);
+  ctf_dprintf ("Flipping endianness\n");
+
+  if (!is_btf)
+    {
+      flip_objts (buf + cth->cth_objt_off, cth->cth_objt_len);
+      flip_objts (buf + cth->cth_func_off, cth->cth_func_len);
+      flip_objts (buf + cth->cth_objtidx_off, cth->cth_objtidx_len);
+      flip_objts (buf + cth->cth_funcidx_off, cth->cth_funcidx_len);
+    }
+  return flip_types (fp, buf + cth->btf.bth_type_off, cth->btf.bth_type_len,
+                    to_foreign);
 }
 
 /* Set up the ctl hashes in a ctf_dict_t.  Called by both writable and