libctf: create: DTD addition and deletion; ctf_rollback

DTD deletion changes mostly relate to the changes to the ctf_dtdef_t, but
also we no longer nede to have special handling for forwards (we can just
use ctf_type_kind_forwarded like everyone else).

Rollback no longer needs to delete things by hand (it hasn't needed to for
years): it can just call ctf_dtd_delete.

ctf_add_generic changes substantially, mostly to allow for the ctf_dtdef_t
changes.  Rather than returning a type ID it now returns the DTD it just
allocated: it can also be asked to add some prefixes, and return the first
prefix added (which may not be the first prefix in the type, because if it
is asked to add a non-root-visible type it will additionally allocate a
CTF_K_CONFLICTING prefix to encode that).

Finally, duplicate name detection is suppressed for type and decl tags.
This commit is contained in:
Nick Alcock
2025-04-24 16:11:53 +01:00
parent 05a2970ad1
commit d5bb2772c6

View File

@@ -303,28 +303,20 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
void
ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd)
{
int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
int name_kind = kind;
const char *name;
const char *name = ctf_type_name_raw (fp, dtd->dtd_type);
int name_kind = ctf_type_kind_forwarded (fp, dtd->dtd_type);
/* Repeated calls should do nothing. */
if (name_kind < 0 && ctf_errno (fp) == ECTF_BADID)
return;
ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
switch (kind)
{
case CTF_K_FORWARD:
name_kind = dtd->dtd_data.ctt_type;
break;
}
free (dtd->dtd_vlen);
dtd->dtd_vlen_alloc = 0;
if (dtd->dtd_data.ctt_name
&& (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
{
if (LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info))
ctf_dynhash_remove (ctf_name_table (fp, name_kind), name);
}
if (name != NULL && name[0] != '\0'
&& LCTF_INFO_ISROOT (fp, dtd->dtd_buf->ctt_info))
ctf_dynhash_remove (ctf_name_table (fp, name_kind), name);
free (dtd->dtd_buf);
ctf_list_delete (&fp->ctf_dtdefs, dtd);
free (dtd);
}
@@ -404,24 +396,10 @@ ctf_rollback (ctf_dict_t *fp, ctf_snapshot_id_t id)
for (dtd = ctf_list_next (&fp->ctf_dtdefs); dtd != NULL; dtd = ntd)
{
int kind;
const char *name;
ntd = ctf_list_next (dtd);
if (ctf_type_to_index (fp, dtd->dtd_type) <= id.dtd_id)
continue;
kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
if (kind == CTF_K_FORWARD)
kind = dtd->dtd_data.ctt_type;
if (dtd->dtd_data.ctt_name
&& (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL
&& LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info))
ctf_dynhash_remove (ctf_name_table (fp, kind), name);
ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t) dtd->dtd_type);
ctf_dtd_delete (fp, dtd);
}
@@ -524,12 +502,19 @@ ctf_assign_id (ctf_dict_t *fp)
return ctf_index_to_type (fp, idx);
}
/* Note: vlen is the amount of space *allocated* for the vlen. It may well not
be the amount of space used (yet): the space used is declared in per-kind
fashion in the dtd_data's info word. */
static ctf_id_t
/* Note: vbytes is the amount of space needed by the vlen, plus as many as are
needed by the PREFIXES, plus any further prefixes (e.g. for hidden types).
It is required to be the amount of space used, as recorded in the per-kind
info word. vbytes_extra is some extra space that can be allocated to reduce
realloc calls.
TYPEP is a pointer to either the actual type structure with the name in it,
or to the first prefix requested by PREFIXES, if nonzero. */
static ctf_dtdef_t *
ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
size_t vbytes, ctf_dtdef_t **rp)
int prefixes, size_t vbytes, size_t vbytes_extra,
ctf_type_t **typep)
{
ctf_dtdef_t *dtd;
ctf_id_t type;
@@ -539,71 +524,116 @@ ctf_add_generic (ctf_dict_t *fp, uint32_t flag, const char *name, int kind,
pfp = fp->ctf_parent;
if (flag != CTF_ADD_NONROOT && flag != CTF_ADD_ROOT)
return (ctf_set_typed_errno (fp, EINVAL));
{
ctf_set_errno (fp, EINVAL);
return NULL;
}
if (fp->ctf_typemax + 1 >= pfp->ctf_provtypemax)
return (ctf_set_typed_errno (fp, ECTF_FULL));
{
ctf_set_errno (fp, ECTF_FULL);
return NULL;
}
/* Prohibit addition of types in the middle of serialization. */
if (fp->ctf_flags & LCTF_NO_TYPE)
return (ctf_set_errno (fp, ECTF_NOTSERIALIZED));
{
ctf_set_errno (fp, ECTF_NOTSERIALIZED);
return NULL;
}
if (fp->ctf_flags & LCTF_NO_STR)
return (ctf_set_errno (fp, ECTF_NOPARENT));
{
ctf_set_errno (fp, ECTF_NOPARENT);
return NULL;
}
if (fp->ctf_flags & LCTF_CHILD && fp->ctf_parent == NULL)
return (ctf_set_errno (fp, ECTF_NOPARENT));
{
ctf_set_errno (fp, ECTF_NOPARENT);
return NULL;
}
/* Prohibit addition of a root-visible type that is already present
in the non-dynamic portion. */
in the non-dynamic portion. Two exceptions: type and decl tags,
whose identifier tables are unusual (duplicates are expected). */
if (flag == CTF_ADD_ROOT && name != NULL && name[0] != '\0')
if (flag == CTF_ADD_ROOT && name != NULL && name[0] != '\0'
&& kind != CTF_K_TYPE_TAG && kind != CTF_K_DECL_TAG)
{
ctf_id_t existing;
if (((existing = ctf_dynhash_lookup_type (ctf_name_table (fp, kind),
name)) > 0)
&& ctf_static_type (fp, existing))
return (ctf_set_typed_errno (fp, ECTF_RDONLY));
{
ctf_set_errno (fp, ECTF_RDONLY);
return NULL;
}
}
/* Make sure ptrtab always grows to be big enough for all types. */
if (ctf_grow_ptrtab (fp) < 0)
return CTF_ERR; /* errno is set for us. */
return NULL; /* errno is set for us. */
if ((dtd = calloc (1, sizeof (ctf_dtdef_t))) == NULL)
return (ctf_set_typed_errno (fp, EAGAIN));
dtd->dtd_vlen_alloc = vbytes;
if (vbytes > 0)
{
if ((dtd->dtd_vlen = calloc (1, vbytes)) == NULL)
goto oom;
ctf_set_typed_errno (fp, EAGAIN);
return NULL;
}
else
dtd->dtd_vlen = NULL;
dtd->dtd_buf_size = vbytes + vbytes_extra + sizeof (ctf_type_t);
dtd->dtd_vlen_size = vbytes;
/* The non-root flag is implemented via prefixes. */
if (flag == CTF_ADD_NONROOT)
dtd->dtd_buf_size += sizeof (ctf_type_t);
if (prefixes)
dtd->dtd_buf_size += (sizeof (ctf_type_t) * prefixes);
if ((dtd->dtd_buf = calloc (1, dtd->dtd_buf_size)) == NULL)
goto oom;
dtd->dtd_vlen = ((unsigned char *) dtd->dtd_buf) + dtd->dtd_buf_size
- vbytes - vbytes_extra;
dtd->dtd_data = (ctf_type_t *) (dtd->dtd_vlen - sizeof (ctf_type_t));
type = ctf_assign_id (fp);
dtd->dtd_data.ctt_name = ctf_str_add (fp, name);
/* Populate a conflicting type kind if need be. This has vlen-in-bytes filled
in if small enough to fit, to help prefix-unaware clients skip the prefix
easily, but the vlen is otherwise redundant (and not used by libctf). */
if (flag == CTF_ADD_NONROOT)
dtd->dtd_buf->ctt_info = CTF_TYPE_INFO (CTF_K_CONFLICTING, 0,
dtd->dtd_vlen_size < 65536
? dtd->dtd_vlen_size : 0);
dtd->dtd_data->ctt_name = ctf_str_add (fp, name);
dtd->dtd_type = type;
if (dtd->dtd_data.ctt_name == 0 && name != NULL && name[0] != '\0')
if (dtd->dtd_data->ctt_name == 0 && name != NULL && name[0] != '\0')
goto oom;
if (ctf_dtd_insert (fp, dtd, flag, kind) < 0)
goto err; /* errno is set for us. */
*rp = dtd;
return type;
/* Return a pointer to the first user-requested prefix, if any. i.e., don't
return a pointer to the non-root CONFLICTING header. */
if (typep)
*typep = dtd->dtd_buf + (flag == CTF_ADD_NONROOT);
fp->ctf_serialize.cs_initialized = 0;
return dtd;
oom:
ctf_set_errno (fp, EAGAIN);
err:
free (dtd->dtd_vlen);
free (dtd->dtd_buf);
free (dtd);
return CTF_ERR;
return NULL;
}
/* When encoding integer sizes, we want to convert a byte count in the range