]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: open, types: ctf_import for BTF
authorNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 16:59:31 +0000 (17:59 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Fri, 25 Apr 2025 17:07:44 +0000 (18:07 +0100)
ctf_import needs a bunch of fixes to work with pure BTF dicts -- and, for
that matter, importing newly-created parent dicts that have never been
written out, which may have a bunch of nonprovisional types (if types were
added to it before any imports were done) or may not (if at least one
ctf_import into it was done before any types were added).

So we adjust things so that the values that are checked against are the
nonprovisional-types values: the header revisions actually changed the name
of cth_parent_typemax to cth_parent_ntypes to make this clearer, so catch up
with that.  In the parent, we have to use ctf_idmax, not ctf_typemax.

One thing we must prohibit is that you cannot add a bunch of types to a
child and then import a parent into it: the type IDs will all be wrong
and the string offsets more so.  This was partly prohibited: prohibit it
entirely (excepting only that the not-actually-written-out void type
we might add to new BTF dicts does not influence this check).

Since BTF children don't have a cth_parent_ntypes or a cth_parent_strlen, we
cannot check this stuff, but just set them and hope.

libctf/ctf-open.c
libctf/ctf-types.c

index 6cf525b9659a57f6f9786bf9c2a859ddd76ee5bf..b58c0c4030c7b36125e9d5457919642dee9611a3 100644 (file)
@@ -2641,20 +2641,30 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed)
      number of types.  (Provisional types excepted: they go at the top of the
      type ID space, and will not overlap any child types.)  */
 
-  if (pfp->ctf_idmax != fp->ctf_header->cth_parent_typemax)
+  if (pfp->ctf_idmax != fp->ctf_header->cth_parent_ntypes)
     {
-      if (fp->ctf_header->cth_parent_typemax != 0)
+      if (fp->ctf_header->cth_parent_ntypes != 0)
        {
          ctf_err_warn (fp, 0, ECTF_WRONGPARENT,
                        _("ctf_import: incorrect parent dict: %u types expected, %u found"),
-                       fp->ctf_header->cth_parent_typemax, pfp->ctf_idmax);
+                       fp->ctf_header->cth_parent_ntypes, pfp->ctf_idmax);
          return (ctf_set_errno (fp, ECTF_WRONGPARENT));
        }
-      else if (fp->ctf_header->cth_parent_typemax == 0)
+      else if (fp->ctf_opened_btf)
+       {
+         /* A pure BTF dict does not track the number of types in the parent:
+            just update and hope.  */
+
+         fp->ctf_header->cth_parent_ntypes = pfp->ctf_idmax;
+       }
+      else if (fp->ctf_header->cth_parent_ntypes == 0)
        {
          /* If we are importing into a parent dict, the child dict had better
             be empty.  Set its starting type ID, which need not be zero: the
-            parent can already have types.  */
+            parent can already have types.  We assign typemax rather than
+            idmax because when this is a new dict we want the types to count
+            up from the number of types currently in the parent, not the number
+            in the parent when it was opened.  */
 
          if (fp->ctf_typemax != 0)
            {
@@ -2663,17 +2673,23 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed)
                            fp->ctf_typemax);
              return (ctf_set_errno (fp, EINVAL));
            }
-         fp->ctf_header->cth_parent_typemax = pfp->ctf_typemax;
+         fp->ctf_header->cth_parent_ntypes = pfp->ctf_typemax;
        }
     }
 
-  /* We might in time be able to lift this restriction, but it is unlikely to be
-     something anyone would want to do, so let's not bother for now.  */
+  /* No importing dicts with provisional strings in (except for the void one
+     added to all new dicts).  We might in time be able to lift this
+     restriction, but it is unlikely to be something anyone would want to do, so
+     let's not bother for now.  If we have a system-created void type, it might
+     have instantiated a new string.  */
 
-  if (ctf_dynhash_elements (fp->ctf_prov_strtab) != 0)
+  if ((fp->ctf_void_type == NULL
+       && ctf_dynhash_elements (fp->ctf_prov_strtab) != 0)
+      || (fp->ctf_void_type != NULL
+         && ctf_dynhash_elements (fp->ctf_prov_strtab) > 1))
     {
       ctf_err_warn (fp, 0, EINVAL,
-                   _("ctf_import: child dict already has %zi bytes of strings, cannot import"),
+                   _("ctf_import: child dict already has %zi strings, cannot import"),
                    ctf_dynhash_elements (fp->ctf_prov_strtab));
       return (ctf_set_errno (fp, EINVAL));
     }
@@ -2694,8 +2710,16 @@ ctf_import_internal (ctf_dict_t *fp, ctf_dict_t *pfp, int unreffed)
   fp->ctf_parent_unreffed = unreffed;
   fp->ctf_parent = pfp;
 
+  /* BTF dicts don't have any parent strlen in the header, but we need to know
+     it to dereference strings.  */
+
+  if (fp->ctf_opened_btf)
+    fp->ctf_header->cth_parent_strlen = pfp->ctf_str[CTF_STRTAB_0].cts_len;
+
   /* If this is a dict that hasn't previously allowed string lookups,
-     we can allow them now, and finish initialization.  */
+     we can allow them now, and finish initialization.  (This requires us to
+     figure out whether the buffer contains pure BTF or not: we can do that by
+     checking the CTF-specific magic number in the header we read in.)  */
 
   fp->ctf_flags |= LCTF_CHILD;
   fp->ctf_flags &= ~LCTF_NO_STR;
index 4ff32c2f847d9bfbedc481b837d59981e174f8b9..19d63bf6172efbf66503e3a6f4e2b1532c126010 100644 (file)
@@ -40,7 +40,7 @@ ctf_type_isparent (const ctf_dict_t *fp, ctf_id_t id)
      have been added.  Simple range check.  */
 
   if (!fp->ctf_parent)
-    return (fp->ctf_header->cth_parent_typemax >= id);
+    return (fp->ctf_header->cth_parent_ntypes >= id);
 
   /* Types in the parent's idmax range (which encompasses its stypes range) are
      in the parent.  */
@@ -76,16 +76,16 @@ ctf_type_to_index_internal (const ctf_dict_t *fp, ctf_id_t type)
 {
   uint32_t idx = type;
 
-  assert (((fp->ctf_flags & LCTF_CHILD) && (type > fp->ctf_header->cth_parent_typemax)) ||
+  assert (((fp->ctf_flags & LCTF_CHILD) && (type > fp->ctf_header->cth_parent_ntypes)) ||
          (!(fp->ctf_flags & LCTF_CHILD)));
 
   if (fp->ctf_flags & LCTF_CHILD)
     {
       /* Non-dynamic type in parent: no index permitted.  */
 
-      assert (type > fp->ctf_header->cth_parent_typemax);
+      assert (type > fp->ctf_header->cth_parent_ntypes);
 
-      idx -= fp->ctf_header->cth_parent_typemax;
+      idx -= fp->ctf_header->cth_parent_ntypes;
     }
 
   if (idx <= fp->ctf_stypes)
@@ -130,7 +130,7 @@ ctf_id_t
 ctf_index_to_type (const ctf_dict_t *fp, uint32_t idx)
 {
   if (fp->ctf_flags & LCTF_CHILD)
-    return idx + fp->ctf_header->cth_parent_typemax;
+    return idx + fp->ctf_header->cth_parent_ntypes;
 
   if (idx <= (fp->ctf_typemax - fp->ctf_nprovtypes))
     return idx;