ctf_dtdef_t *
ctf_dtd_lookup (const ctf_dict_t *fp, ctf_id_t type)
{
+ if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type))
+ fp = fp->ctf_parent;
+
return (ctf_dtdef_t *)
ctf_dynhash_lookup (fp->ctf_dthash, (void *) (uintptr_t) type);
}
int
ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp)
{
+ ctf_dict_t *ofp = fp;
ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
ctf_array_t *vlen;
+ if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type))
+ fp = fp->ctf_parent;
+
+ if (!(ofp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno (ofp, ECTF_RDONLY));
+
if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (fp, ECTF_RDONLY));
+ return (ctf_set_errno (ofp, ECTF_RDONLY));
if (dtd == NULL
|| LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY)
- return (ctf_set_errno (fp, ECTF_BADID));
+ return (ctf_set_errno (ofp, ECTF_BADID));
vlen = (ctf_array_t *) dtd->dtd_vlen;
fp->ctf_flags |= LCTF_DIRTY;
ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
int value)
{
+ ctf_dict_t *ofp = fp;
ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid);
unsigned char *old_vlen;
ctf_enum_t *en;
if (name == NULL)
return (ctf_set_errno (fp, EINVAL));
+ if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, enid))
+ fp = fp->ctf_parent;
+
+ if (!(ofp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno (ofp, ECTF_RDONLY));
+
if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (fp, ECTF_RDONLY));
+ return (ctf_set_errno (ofp, ECTF_RDONLY));
if (dtd == NULL)
- return (ctf_set_errno (fp, ECTF_BADID));
+ return (ctf_set_errno (ofp, ECTF_BADID));
kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info);
vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
if (kind != CTF_K_ENUM)
- return (ctf_set_errno (fp, ECTF_NOTENUM));
+ return (ctf_set_errno (ofp, ECTF_NOTENUM));
if (vlen == CTF_MAX_VLEN)
- return (ctf_set_errno (fp, ECTF_DTFULL));
+ return (ctf_set_errno (ofp, ECTF_DTFULL));
old_vlen = dtd->dtd_vlen;
if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
for (i = 0; i < vlen; i++)
if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
- return (ctf_set_errno (fp, ECTF_DUPLICATE));
+ return (ctf_set_errno (ofp, ECTF_DUPLICATE));
en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name);
en[i].cte_value = value;
if (en[i].cte_name == 0 && name != NULL && name[0] != '\0')
- return -1; /* errno is set for us. */
+ return (ctf_set_errno (ofp, ctf_errno (fp)));
dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name,
ctf_id_t type, unsigned long bit_offset)
{
+ ctf_dict_t *ofp = fp;
ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid);
ssize_t msize, malign, ssize;
unsigned char *old_vlen;
ctf_lmember_t *memb;
+ if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, souid))
+ {
+ /* Adding a child type to a parent, even via the child, is prohibited.
+ Otherwise, climb to the parent and do all work there. */
+
+ if (LCTF_TYPE_ISCHILD (fp, type))
+ return (ctf_set_errno (ofp, ECTF_BADID));
+
+ fp = fp->ctf_parent;
+ }
+
+ if (!(ofp->ctf_flags & LCTF_RDWR))
+ return (ctf_set_errno (ofp, ECTF_RDONLY));
+
if (!(fp->ctf_flags & LCTF_RDWR))
- return (ctf_set_errno (fp, ECTF_RDONLY));
+ return (ctf_set_errno (ofp, ECTF_RDONLY));
if (dtd == NULL)
- return (ctf_set_errno (fp, ECTF_BADID));
+ return (ctf_set_errno (ofp, ECTF_BADID));
if (name != NULL && name[0] == '\0')
name = NULL;
vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info);
if (kind != CTF_K_STRUCT && kind != CTF_K_UNION)
- return (ctf_set_errno (fp, ECTF_NOTSOU));
+ return (ctf_set_errno (ofp, ECTF_NOTSOU));
if (vlen == CTF_MAX_VLEN)
- return (ctf_set_errno (fp, ECTF_DTFULL));
+ return (ctf_set_errno (ofp, ECTF_DTFULL));
old_vlen = dtd->dtd_vlen;
if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0)
- return -1; /* errno is set for us. */
+ return (ctf_set_errno (ofp, ctf_errno (fp)));
memb = (ctf_lmember_t *) dtd->dtd_vlen;
if (dtd->dtd_vlen != old_vlen)
{
for (i = 0; i < vlen; i++)
if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0)
- return (ctf_set_errno (fp, ECTF_DUPLICATE));
+ return (ctf_set_errno (ofp, ECTF_DUPLICATE));
}
if ((msize = ctf_type_size (fp, type)) < 0 ||
if (is_incomplete)
{
- ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+ ctf_err_warn (ofp, 1, ECTF_INCOMPLETE,
_("ctf_add_member_offset: cannot add member %s of "
"incomplete type %lx to struct %lx without "
"specifying explicit offset\n"),
name ? name : _("(unnamed member)"), type, souid);
- return (ctf_set_errno (fp, ECTF_INCOMPLETE));
+ return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
}
if (ctf_type_encoding (fp, ltype, &linfo) == 0)
{
const char *lname = ctf_strraw (fp, memb[vlen - 1].ctlm_name);
- ctf_err_warn (fp, 1, ECTF_INCOMPLETE,
+ ctf_err_warn (ofp, 1, ECTF_INCOMPLETE,
_("ctf_add_member_offset: cannot add member %s of "
"type %lx to struct %lx without specifying "
"explicit offset after member %s of type %lx, "
"which is an incomplete type\n"),
name ? name : _("(unnamed member)"), type, souid,
lname ? lname : _("(unnamed member)"), ltype);
- return -1; /* errno is set for us. */
+ return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
}
/* Round up the offset of the end of the last member to
const ctf_encoding_t encoding)
{
ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type);
- int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+ int kind;
int otype = type;
+ if (dtd == NULL)
+ return (ctf_set_errno (fp, ECTF_BADID));
+
+ kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info);
+
if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM))
return (ctf_set_errno (fp, ECTF_NOTINTFP));
--- /dev/null
+/* Make sure we do various things right that involve DTD lookups of parents
+ from the perspective of children. */
+
+#include <ctf-api.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum crash_method { ADD_STRUCT, ADD_UNION, ADD_MEMBER_OFFSET, ADD_MEMBER_ENCODED, ADD_ENUM, ADD_ENUMERATOR, SET_ARRAY };
+
+void
+dtd_crash (enum crash_method method, int parent_bigger)
+{
+ ctf_dict_t *pfp, *cfp;
+ ctf_encoding_t e = { CTF_INT_SIGNED, 0, sizeof (long) };
+ ctf_id_t ptype, ftype, stype, foo;
+ int forward_kind = CTF_K_STRUCT;
+ size_t i;
+ int err;
+
+ /* Maybe make the relevant type IDs in the parent much bigger than those
+ in the child, or maybe vice versa. */
+
+ if ((pfp = ctf_create (&err)) == NULL)
+ goto create_err;
+
+ if (parent_bigger)
+ {
+ if ((foo = ctf_add_integer (pfp, CTF_ADD_NONROOT, "blah", &e)) == CTF_ERR)
+ goto create_parent;
+
+ for (i = 0; i < 4096; i++)
+ if (ctf_add_pointer (pfp, CTF_ADD_NONROOT, foo) == CTF_ERR)
+ goto create_parent;
+ }
+
+ if ((ptype = ctf_add_integer (pfp, CTF_ADD_NONROOT, "int", &e)) == CTF_ERR)
+ goto create_parent;
+
+ /* Add a forward to a struct, union, or enum (depending on the method) in
+ the parent, so we can try to replace it in the child and see what
+ happens. (Most of them are structs, or it doesn't matter, as for
+ SET_ARRAY; so we do that by default.) */
+
+ switch (method)
+ {
+ case ADD_UNION:
+ forward_kind = CTF_K_UNION;
+ break;
+ case ADD_ENUM:
+ case ADD_ENUMERATOR:
+ forward_kind = CTF_K_ENUM;
+ break;
+ /* Placate clang. */
+ default:
+ break;
+ }
+
+ if ((ftype = ctf_add_forward (pfp, CTF_ADD_ROOT, "foo", forward_kind)) == CTF_ERR)
+ goto create_parent;
+
+ if ((cfp = ctf_create (&err)) == NULL)
+ goto create_err;
+
+ if (ctf_import (cfp, pfp) < 0)
+ goto create_child;
+
+ if (!parent_bigger)
+ {
+ if ((foo = ctf_add_integer (pfp, CTF_ADD_NONROOT, "blah", &e)) == CTF_ERR)
+ goto create_parent;
+
+ for (i = 0; i < 4096; i++)
+ if (ctf_add_pointer (pfp, CTF_ADD_NONROOT, foo) == CTF_ERR)
+ goto create_parent;
+ }
+
+ switch (method)
+ {
+ /* These try to replace a forward, and should not do so if we're
+ adding in the child and it's in the parent. */
+ case ADD_STRUCT:
+ if ((stype = ctf_add_struct_sized (cfp, CTF_ADD_ROOT, "foo", 1024)) == CTF_ERR)
+ goto create_child;
+ if (stype == ftype)
+ fprintf (stderr, "Forward-promotion spotted!\n");
+ break;
+
+ case ADD_UNION:
+ if ((stype = ctf_add_union_sized (cfp, CTF_ADD_ROOT, "foo", 1024)) == CTF_ERR)
+ goto create_child;
+ if (stype == ftype)
+ fprintf (stderr, "Forward-promotion spotted!\n");
+ break;
+
+ case ADD_ENUM:
+ if ((stype = ctf_add_enum (cfp, CTF_ADD_ROOT, "foo")) == CTF_ERR)
+ goto create_child;
+ if (stype == ftype)
+ fprintf (stderr, "Forward-promotion spotted!\n");
+ break;
+
+ /* These try to look up the struct/union/enum we're adding to: make
+ sure this works from the perspective of the child if the type is in
+ the parent. Also make sure that addition of child types to parent
+ types this way is prohibited, and that addition of parent types to
+ parent types is allowed. */
+ case ADD_MEMBER_OFFSET:
+ {
+ ctf_id_t ctype;
+
+ if ((stype = ctf_add_struct (pfp, CTF_ADD_ROOT, "bar")) == CTF_ERR)
+ goto create_child;
+
+ if ((ctype = ctf_add_integer (cfp, CTF_ADD_NONROOT, "xyzzy", &e)) == CTF_ERR)
+ goto create_child;
+
+ if (ctf_add_member_offset (cfp, stype, "member", ptype, 5) == CTF_ERR)
+ goto create_child;
+
+ if (ctf_add_member_offset (cfp, stype, "xyzzy", ctype, 4) != CTF_ERR)
+ fprintf (stderr, "Addition of child type to parent via child unexpectedly succeeded\n");
+ else if (ctf_errno (cfp) == 0)
+ fprintf (stderr, "got error from ctype addition to parent struct, but no error found on child\n");
+
+ break;
+ }
+
+ case ADD_ENUMERATOR:
+ if ((stype = ctf_add_enum (pfp, CTF_ADD_ROOT, "bar")) == CTF_ERR)
+ goto create_parent;
+
+ if (ctf_add_enumerator (cfp, stype, "FOO", 0) == CTF_ERR)
+ goto create_child;
+ break;
+
+ /* This tries to look up the member type we're adding, and goes wrong
+ if the struct is in the child and the member type is in the parent. */
+ case ADD_MEMBER_ENCODED:
+ if ((stype = ctf_add_struct (cfp, CTF_ADD_ROOT, "foo")) == CTF_ERR)
+ goto create_child;
+
+ if (ctf_add_member_encoded (cfp, stype, "cmember", ptype, 5, e) == CTF_ERR)
+ goto create_child;
+ break;
+
+ /* This tries to look up the array we're resetting the state of. */
+ case SET_ARRAY:
+ {
+ ctf_arinfo_t ar;
+
+ ar.ctr_contents = ptype;
+ ar.ctr_index = ptype;
+ ar.ctr_nelems = 5;
+
+ if ((stype = ctf_add_array (pfp, CTF_ADD_ROOT, &ar)) == CTF_ERR)
+ goto create_child;
+
+ if (ctf_set_array (cfp, stype, &ar) == CTF_ERR)
+ goto create_child;
+ break;
+ }
+ }
+
+ ctf_dict_close (cfp);
+ ctf_dict_close (pfp);
+
+ return;
+
+ create_err:
+ fprintf (stderr, "Creation failed: %s\n", ctf_errmsg (err));
+ exit (1);
+ create_parent:
+ fprintf (stderr, "Cannot create parent type: %s\n", ctf_errmsg (ctf_errno (pfp)));
+ exit (1);
+ create_child:
+ fprintf (stderr, "Cannot create child type: %s\n", ctf_errmsg (ctf_errno (cfp)));
+ exit (1);
+}