]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
libctf: add mechanism to prohibit most operations without a strtab
authorNick Alcock <nick.alcock@oracle.com>
Mon, 15 Jul 2024 19:43:51 +0000 (20:43 +0100)
committerNick Alcock <nick.alcock@oracle.com>
Thu, 30 Oct 2025 14:17:51 +0000 (14:17 +0000)
We are about to add machinery that deduplicates a child dict's strtab
against its parent.  Obviously if you open such a dict but do not import its
parent, all strtab lookups must fail: so add an LCTF_NO_STR flag that is set
in that window and make most operations fail if it's not set.  (Two more
that will be set in future commits are serialization and string lookup
itself.)

Notably, not all symbol lookup is impossible in this window: you can still
look up by symbol index, as long as this dict is not using an indexed
strtypetab (which obviously requires string lookups to get the symbol name).

include/
* ctf-api.h (_CTF_ERRORS) [ECTF_HASPARENT]: New.
        [ECTF_WRONGPARENT]: Likewise.
(ECTF_NERR): Update.
        Update comments to note the new limitations on ctf_import et al.

libctf/
* ctf-impl.h (LCTF_NO_STR): New.
* ctf-create.c (ctf_rollback): Error out when LCTF_NO_STR.
(ctf_add_generic): Likewise.
(ctf_add_struct_sized): Likewise.
(ctf_add_union_sized): Likewise.
(ctf_add_enum): Likewise.
(ctf_add_forward): Likewise.
(ctf_add_unknown): Likewise.
(ctf_add_enumerator): Likewise.
(ctf_add_member_offset): Likewise.
(ctf_add_variable): Likewise.
(ctf_add_funcobjt_sym_forced): Likewise.
(ctf_add_type): Likewise (on either dict).
* ctf-dump.c (ctf_dump): Likewise.
* ctf-lookup.c (ctf_lookup_by_name): Likewise.
(ctf_lookup_variable): Likewise. Likewise.
(ctf_lookup_enumerator): Likewise.
(ctf_lookup_enumerator_next): Likewise.
(ctf_symbol_next): Likewise.
(ctf_lookup_by_sym_or_name): Likewise, if doing indexed lookups.
* ctf-types.c (ctf_member_next): Likewise.
(ctf_enum_next): Likewise.
(ctf_type_aname): Likewise.
(ctf_type_name_raw): Likewise.
(ctf_type_compat): Likewise, for either dict.
(ctf_member_info): Likewise.
(ctf_enum_name): Likewise.
(ctf_enum_value): Likewise.
(ctf_type_rvisit): Likewise.
(ctf_variable_next): Note that we don't need to test LCTF_NO_STR.

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

index ed01a885392574c416b601c57dc832d6e346416b..07a652987b5f5d78beff55af2a6b1d536b504685 100644 (file)
@@ -246,7 +246,9 @@ typedef struct ctf_snapshot_id
   _CTF_ITEM (ECTF_NONAME, "Type name must not be empty.") \
   _CTF_ITEM (ECTF_BADFLAG, "Invalid CTF dict flag specified.") \
   _CTF_ITEM (ECTF_CTFVERS_NO_SERIALIZE, "CTFv1 dicts are too old to serialize.") \
-  _CTF_ITEM (ECTF_UNSTABLE, "Attempt to write unstable file format version: set I_KNOW_LIBCTF_IS_UNSTABLE in the environment.")
+  _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.")
 
 #define        ECTF_BASE       1000    /* Base value for libctf errnos.  */
 
@@ -259,7 +261,7 @@ _CTF_ERRORS
 #undef _CTF_FIRST
   };
 
-#define ECTF_NERR (ECTF_UNSTABLE - ECTF_BASE + 1) /* Count of CTF errors.  */
+#define ECTF_NERR (ECTF_WRONGPARENT - ECTF_BASE + 1) /* Count of CTF errors.  */
 
 /* The CTF data model is inferred to be the caller's data model or the data
    model of the given object, unless ctf_setmodel is explicitly called.  */
@@ -461,7 +463,11 @@ extern void ctf_dict_close (ctf_dict_t *);
    contain the name of their originating compilation unit and the name of
    their parent.  Dicts opened from CTF archives have this relationship set
    up already, but if opening via raw low-level calls, you need to figure
-   out which dict is the parent and set it on the child via ctf_import(). */
+   out which dict is the parent and set it on the child via ctf_import().
+
+   Almost all operations other than ctf_import and ctf_close do not work on
+   child dicts that have not yet had ctf_import called on them; in particular,
+   name lookups and type lookup in general are broken, as is type addition.  */
 
 extern const char *ctf_cuname (ctf_dict_t *);
 extern ctf_dict_t *ctf_parent_dict (ctf_dict_t *);
index 5820830f0868eddad47182271773de4f855a2efa..7c2a73708e60a7a8dd30d63289aa3892a0fcb73f 100644 (file)
@@ -364,6 +364,9 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
   ctf_dtdef_t *dtd, *ntd;
   ctf_dvdef_t *dvd, *nvd;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if (id.snapshot_id < fp->ctf_stypes)
     return (ctf_set_errno (fp, ECTF_RDONLY));
 
@@ -431,6 +434,9 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
   if (LCTF_INDEX_TO_TYPE (fp, fp->ctf_typemax, 1) == (CTF_MAX_PTYPE - 1))
     return (ctf_set_typed_errno (fp, ECTF_FULL));
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   /* Prohibit addition of a root-visible type that is already present
      in the non-dynamic portion. */
 
@@ -787,6 +793,9 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
   size_t initial_vlen = 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 structs.  */
   if (name != NULL && flag == CTF_ADD_ROOT)
     type = ctf_lookup_by_rawname (fp, CTF_K_STRUCT, name);
@@ -831,6 +840,9 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name,
   ctf_id_t type = 0;
   size_t initial_vlen = 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 && flag == CTF_ADD_ROOT)
     type = ctf_lookup_by_rawname (fp, CTF_K_UNION, name);
@@ -874,6 +886,9 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
   ctf_id_t type = 0;
   size_t initial_vlen = sizeof (ctf_enum_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 && flag == CTF_ADD_ROOT)
     type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name);
@@ -943,6 +958,9 @@ ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
   if (name == NULL || name[0] == '\0')
     return (ctf_set_typed_errno (fp, ECTF_NONAME));
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   /* If the type is already defined or exists as a forward tag, just return
      the ctf_id_t of the existing definition.  Since this changes nothing,
      it's safe to do even on the read-only portion of the dict.  */
@@ -967,6 +985,9 @@ ctf_add_unknown (ctf_dict_t *fp, uint32_t flag, const char *name)
   ctf_dtdef_t *dtd;
   ctf_id_t type = 0;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   /* If a type is already defined with this name, error (if not CTF_K_UNKNOWN)
      or just return it.  */
 
@@ -1063,6 +1084,9 @@ ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
   if (enid < fp->ctf_stypes)
     return (ctf_set_errno (ofp, ECTF_RDONLY));
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if (dtd == NULL)
     return (ctf_set_errno (ofp, ECTF_BADID));
 
@@ -1148,6 +1172,9 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
   unsigned char *old_vlen;
   ctf_lmember_t *memb;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, souid))
     {
       /* Adding a child type to a parent, even via the child, is prohibited.
@@ -1380,6 +1407,9 @@ ctf_add_variable_forced (ctf_dict_t *fp, const char *name, ctf_id_t ref)
 int
 ctf_add_variable (ctf_dict_t *fp, const char *name, ctf_id_t ref)
 {
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if (ctf_lookup_variable_here (fp, name) != CTF_ERR)
     return (ctf_set_errno (fp, ECTF_DUPLICATE));
 
@@ -1400,6 +1430,9 @@ ctf_add_funcobjt_sym_forced (ctf_dict_t *fp, int is_function, const char *name,
   char *dupname;
   ctf_dynhash_t *h = is_function ? fp->ctf_funchash : fp->ctf_objthash;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if (ctf_lookup_by_id (&tmp, id) == NULL)
     return -1;                         /* errno is set for us.  */
 
@@ -2068,6 +2101,9 @@ ctf_add_type (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type)
 {
   ctf_id_t id;
 
+  if ((src_fp->ctf_flags & LCTF_NO_STR) || (dst_fp->ctf_flags & LCTF_NO_STR))
+    return (ctf_set_errno (dst_fp, ECTF_NOPARENT));
+
   if (!src_fp->ctf_add_processing)
     src_fp->ctf_add_processing = ctf_dynhash_create (ctf_hash_integer,
                                                     ctf_hash_eq_integer,
index a47dc2ad1c2c038b37c238fc11a6245144f7ff25..22408fb6038430098191fb5f7e29ba952c0b697d 100644 (file)
@@ -706,6 +706,12 @@ ctf_dump (ctf_dict_t *fp, ctf_dump_state_t **statep, ctf_sect_names_t sect,
   char *line;
   ctf_dump_state_t *state = NULL;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    {
+      ctf_set_errno (fp, ECTF_NOPARENT);
+      return NULL;
+    }
+
   if (*statep == NULL)
     {
       /* Data collection.  Transforming a call-at-a-time iterator into a
index 8370a84ac37ef484dc177e3af8cb28a7279fe9c0..2a17afacbb66fd182b2266efb16b917d66e6f046 100644 (file)
@@ -610,8 +610,10 @@ struct ctf_next
 #define LCTF_VBYTES(fp, kind, size, vlen) \
   ((fp)->ctf_dictops->ctfo_get_vbytes(fp, kind, size, vlen))
 
-#define LCTF_CHILD     0x0001  /* CTF dict is a child.  */
+#define LCTF_CHILD             0x0001  /* CTF dict is a child.  */
+#define LCTF_LINKING           0x0002  /* CTF link is underway: respect ctf_link_flags.  */
 #define LCTF_STRICT_NO_DUP_ENUMERATORS 0x0004 /* Duplicate enums prohibited.  */
+#define LCTF_NO_STR            0x0008  /* No string lookup possible yet.  */
 #define LCTF_NO_SERIALIZE      0x0010  /* Serialization of this dict prohibited.  */
 
 extern ctf_dynhash_t *ctf_name_table (ctf_dict_t *, int);
index af35be0167113d727dd4f50d534bbec386a081ee..c3ffeb05b791c4dfb1cf55f6a3ed321d757c4bd0 100644 (file)
@@ -319,6 +319,9 @@ ctf_lookup_by_name_internal (ctf_dict_t *fp, ctf_dict_t *child,
 ctf_id_t
 ctf_lookup_by_name (ctf_dict_t *fp, const char *name)
 {
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
   return ctf_lookup_by_name_internal (fp, NULL, name);
 }
 
@@ -398,6 +401,9 @@ ctf_lookup_variable (ctf_dict_t *fp, const char *name)
 {
   ctf_id_t type;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
   if ((type = ctf_lookup_variable_here (fp, name)) == CTF_ERR)
     {
       if (ctf_errno (fp) == ECTF_NOTYPEDAT && fp->ctf_parent != NULL)
@@ -426,6 +432,9 @@ ctf_lookup_enumerator (ctf_dict_t *fp, const char *name, int64_t *enum_value)
   ctf_id_t type;
   int enum_int_value;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
   if (ctf_dynset_lookup (fp->ctf_conflicting_enums, name))
     return (ctf_set_typed_errno (fp, ECTF_DUPLICATE));
 
@@ -467,6 +476,9 @@ ctf_lookup_enumerator_next (ctf_dict_t *fp, const char *name,
   ctf_next_t *i = *it;
   int found = 0;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
   /* We use ctf_type_next() to iterate across all types, but then traverse each
      enumerator found by hand: traversing enumerators is very easy, and it would
      probably be more confusing to use two nested iterators than to do it this
@@ -836,6 +848,9 @@ ctf_symbol_next (ctf_dict_t *fp, ctf_next_t **it, const char **name,
   ctf_next_t *i = *it;
   int err;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
   if (!i)
     {
       if ((i = ctf_next_create ()) == NULL)
@@ -1201,15 +1216,22 @@ ctf_lookup_by_sym_or_name (ctf_dict_t *fp, unsigned long symidx,
   if (symname == NULL && symidx >= fp->ctf_nsyms)
     goto try_parent;
 
-  /* Try an indexed lookup.  */
+  /* Try an indexed lookup.  We can only do indexed lookups if we have a string
+     table.  */
 
   if (fp->ctf_objtidx_names && is_function != 1)
     {
+      if (fp->ctf_flags & LCTF_NO_STR)
+       return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
       if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 0)) == CTF_ERR)
        return CTF_ERR;                         /* errno is set for us.  */
     }
   if (type == 0 && fp->ctf_funcidx_names && is_function != 0)
     {
+      if (fp->ctf_flags & LCTF_NO_STR)
+       return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
+
       if ((type = ctf_try_lookup_indexed (fp, symidx, symname, 1)) == CTF_ERR)
        return CTF_ERR;                         /* errno is set for us.  */
     }
index d08d4542dc197936043e0086c983a8addbc577e6..427c31e2c3ce91f740c50c7f4423ede53786fdee 100644 (file)
@@ -105,6 +105,9 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   uint32_t max_vlen;
   ctf_next_t *i = *it;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if (!i)
     {
       const ctf_type_t *tp;
@@ -285,6 +288,12 @@ ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
   const char *name;
   ctf_next_t *i = *it;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    {
+      ctf_set_errno (fp, ECTF_NOPARENT);
+      return NULL;
+    }
+
   if (!i)
     {
       const ctf_type_t *tp;
@@ -505,6 +514,9 @@ ctf_variable_next (ctf_dict_t *fp, ctf_next_t **it, const char **name)
   ctf_next_t *i = *it;
   ctf_id_t id;
 
+  /* (No need for a LCTF_NO_STR check: checking for a missing parent covers more
+     cases, and we need to do that anyway.)  */
+
   if ((fp->ctf_flags & LCTF_CHILD) && (fp->ctf_parent == NULL))
     return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
 
@@ -670,6 +682,12 @@ ctf_type_aname (ctf_dict_t *fp, ctf_id_t type)
   if (fp == NULL && type == CTF_ERR)
     return NULL;       /* Simplify caller code by permitting CTF_ERR.  */
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    {
+      ctf_set_errno (fp, ECTF_NOPARENT);
+      return NULL;
+    }
+
   ctf_decl_init (&cd);
   ctf_decl_push (&cd, fp, type);
 
@@ -888,6 +906,12 @@ ctf_type_name_raw (ctf_dict_t *fp, ctf_id_t type)
 {
   const ctf_type_t *tp;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    {
+      ctf_set_errno (fp, ECTF_NOPARENT);
+      return NULL;
+    }
+
   if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
     return NULL;               /* errno is set for us.  */
 
@@ -1289,6 +1313,12 @@ ctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype,
   uint32_t lkind, rkind;
   int same_names = 0;
 
+  if (lfp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (lfp, ECTF_NOPARENT));
+
+  if (rfp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (rfp, ECTF_NOPARENT));
+
   if (ctf_type_cmp (lfp, ltype, rfp, rtype) == 0)
     return 1;
 
@@ -1389,6 +1419,9 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name,
   ssize_t size, increment, vbytes;
   uint32_t kind, n, i = 0;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR)
     return -1;                 /* errno is set for us.  */
 
@@ -1495,6 +1528,12 @@ ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
   ssize_t increment;
   uint32_t n;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    {
+      ctf_set_errno (fp, ECTF_NOPARENT);
+      return NULL;
+    }
+
   if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
     return NULL;               /* errno is set for us.  */
 
@@ -1537,6 +1576,9 @@ ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
   ssize_t increment;
   uint32_t n;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
     return -1;                 /* errno is set for us.  */
 
@@ -1663,6 +1705,9 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func,
   int nonrepresentable = 0;
   int rc;
 
+  if (fp->ctf_flags & LCTF_NO_STR)
+    return (ctf_set_errno (fp, ECTF_NOPARENT));
+
   if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) {
     if (ctf_errno (fp) != ECTF_NONREPRESENTABLE)
       return -1;               /* errno is set for us.  */