_CTF_ITEM (ECTF_HASPARENT, "Cannot ctf_import: dict already has a parent.") \
_CTF_ITEM (ECTF_WRONGPARENT, "Cannot ctf_import: incorrect parent provided.") \
_CTF_ITEM (ECTF_NOTSERIALIZED, "CTF dict must be serialized first.") \
+ _CTF_ITEM (ECTF_BADCOMPONENT, "Declaration tag component_idx is invalid.") \
_CTF_ITEM (ECTF_NOTBITSOU, "Type is not a bitfield-capable struct or union.") \
_CTF_ITEM (ECTF_DESCENDING, "Structure offsets may not descend.") \
_CTF_ITEM (ECTF_LINKAGE, "Invalid linkage.") \
_CTF_ITEM (ECTF_LINKKIND, "Only functions and variables have linkage.") \
+ _CTF_ITEM (ECTF_NEVERTAG, "Cannot call this function with a tag kind.") \
_CTF_ITEM (ECTF_NOTDATASEC, "This function requires a datasec.") \
_CTF_ITEM (ECTF_NOTVAR, "This function requires a variable.") \
_CTF_ITEM (ECTF_NODATASEC, "Variable not found in datasec.") \
+ _CTF_ITEM (ECTF_NOTDECLTAG, "This function requires a decl tag.") \
+ _CTF_ITEM (ECTF_NOTTAG, "This function requires a type or decl tag.") \
#define ECTF_BASE 1000 /* Base value for libctf errnos. */
extern ctf_id_t ctf_variable_datasec (ctf_dict_t *fp, ctf_id_t var);
+/* Type and decl tags. */
+
+/* Return the type ID of the type to which a given type tag is attached, or of
+ the type of the declaration to which a decl tag is attached (so a decl tag on
+ a function parameter would return the type ID of the parameter's type). */
+
+extern ctf_id_t ctf_tag (ctf_dict_t *, ctf_id_t tag);
+
+/* Return the component ID and declaration to which a decl tag is attached.
+ -1 means "whole type". */
+
+extern ctf_id_t ctf_decl_tag (ctf_dict_t *, ctf_id_t decl_tag,
+ int64_t *component_idx);
+
/* Iterators. */
/* ctf_member_next is a _next-style iterator that can additionally traverse into
extern ctf_id_t ctf_datasec_var_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
size_t *size, size_t *offset);
+/* Iterate over all tags with the given TAG, returning the ID of each tag. */
+extern ctf_id_t ctf_tag_next (ctf_dict_t *, const char *tag, ctf_next_t **);
+
/* ctf_archive_iter and ctf_archive_next open each member dict for you,
automatically importing any parent dict as usual: ctf_archive_iter closes the
dict on return from ctf_archive_member_f, but for ctf_archive_next the caller
ctf_id_t);
extern ctf_id_t ctf_add_restrict (ctf_dict_t *, uint32_t, ctf_id_t);
+/* Add type and decl tags to whole types or (for decl tags) specific
+ components of types (parameter count for functions, member count for structs
+ and unions). */
+extern ctf_id_t ctf_add_type_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *);
+extern ctf_id_t ctf_add_decl_type_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *);
+extern ctf_id_t ctf_add_decl_tag (ctf_dict_t *, uint32_t, ctf_id_t, const char *,
+ int component_idx);
+
/* Struct and union addition. Straight addition uses possibly-confusing rules
to guess the final size of the struct/union given its members: to explicitly
state the size of the struct or union (to report compiler-generated padding,
case CTF_K_ENUM:
case CTF_K_ENUM64:
return fp->ctf_enums;
+ case CTF_K_TYPE_TAG:
+ case CTF_K_DECL_TAG:
+ return fp->ctf_tags;
case CTF_K_DATASEC:
return fp->ctf_datasecs;
default:
}
}
+int
+ctf_insert_type_decl_tag (ctf_dict_t *fp, ctf_id_t type, const char *name,
+ int kind)
+{
+ ctf_dynset_t *types;
+ ctf_dynhash_t *h = ctf_name_table (fp, kind);
+ int err;
+
+ if ((types = ctf_dynhash_lookup (h, name)) == NULL)
+ {
+ types = ctf_dynset_create (htab_hash_pointer, htab_eq_pointer, NULL);
+
+ if (!types)
+ return (ctf_set_errno (fp, ENOMEM));
+
+ err = ctf_dynhash_cinsert (h, name, types);
+ if (err != 0)
+ {
+ err *= -1;
+ return (ctf_set_errno (fp, err));
+ }
+ }
+
+ if ((err = ctf_dynset_insert (types, (void *) (uintptr_t) type)) != 0)
+ {
+ err *= -1;
+ return (ctf_set_errno (fp, err));
+ }
+ return 0;
+}
+
int
ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind)
{
dtd) < 0)
return ctf_set_errno (fp, ENOMEM);
- if (flag == CTF_ADD_ROOT && dtd->dtd_data.ctt_name
- && (name = ctf_strraw (fp, dtd->dtd_data.ctt_name)) != NULL)
+ if (flag == CTF_ADD_ROOT && dtd->dtd_data->ctt_name
+ && (name = ctf_strraw (fp, dtd->dtd_data->ctt_name)) != NULL)
{
- if (ctf_dynhash_insert (ctf_name_table (fp, kind),
- (char *) name, (void *) (uintptr_t)
- dtd->dtd_type) < 0)
+ /* Type and decl tags have unusual name tables, since their names are not
+ unique. */
+
+ if (kind != CTF_K_TYPE_TAG && kind != CTF_K_DECL_TAG)
{
- ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
- dtd->dtd_type);
- return ctf_set_errno (fp, ENOMEM);
+ if (ctf_dynhash_insert (ctf_name_table (fp, kind),
+ (char *) name, (void *) (uintptr_t)
+ dtd->dtd_type) < 0)
+ {
+ ctf_dynhash_remove (fp->ctf_dthash, (void *) (uintptr_t)
+ dtd->dtd_type);
+ return ctf_set_errno (fp, ENOMEM);
+ }
}
+ else if (ctf_insert_type_decl_tag (fp, dtd->dtd_type, name, kind) < 0)
+ return -1; /* errno is set for us. */
}
ctf_list_append (&fp->ctf_dtdefs, dtd);
return 0;
return 0;
}
+/* Add a type or decl tag applying to some whole type, or to some
+ component of a type. Component -1 is a whole type. */
+
+static ctf_id_t
+ctf_add_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag,
+ int is_decl, int32_t component_idx)
+{
+ ctf_dtdef_t *dtd;
+ size_t vlen_size = 0;
+ int kind = is_decl ? CTF_K_DECL_TAG : CTF_K_TYPE_TAG;
+ int ref_kind = ctf_type_kind (fp, type);
+
+ if (component_idx < -1)
+ return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+
+ if (is_decl)
+ {
+ vlen_size = sizeof (ctf_decl_tag_t);
+
+ /* Whole-type declarations. */
+
+ if (component_idx == 0)
+ {
+ switch (ref_kind)
+ {
+ case CTF_K_TYPEDEF:
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ case CTF_K_VAR:
+ /* TODO: support addition and querying on CTF_K_FUNCTION too, chasing back
+ to relevant CTF_K_FUNC_LINKAGEs. */
+ case CTF_K_FUNC_LINKAGE:
+ break;
+ default:
+ return (ctf_set_typed_errno (fp, ECTF_BADID));
+ }
+ }
+ }
+ else if (component_idx != -1)
+ {
+ ctf_id_t func_type;
+
+ /* Within-type declarations. */
+
+ switch (ref_kind)
+ {
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+
+ if (component_idx >= ctf_member_count (fp, type))
+ return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+ break;
+
+ case CTF_K_FUNC_LINKAGE:
+ if ((func_type = ctf_type_reference (fp, type)) == CTF_ERR)
+ return (ctf_set_typed_errno (fp, ECTF_BADID));
+ /* FALLTHRU */
+
+ case CTF_K_FUNCTION:
+ {
+ ctf_funcinfo_t fi;
+
+ if (ctf_func_type_info (fp, func_type, &fi) < 0)
+ return -1; /* errno is set for us. */
+
+ if ((size_t) component_idx >= fi.ctc_argc)
+ return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+
+ break;
+ }
+ default:
+ return (ctf_set_typed_errno (fp, ECTF_BADCOMPONENT));
+ }
+ }
+
+ if (tag == NULL || tag[0] == '\0')
+ return (ctf_set_typed_errno (fp, ECTF_NONAME));
+
+ if ((dtd = ctf_add_generic (fp, flag, tag, kind, 0, vlen_size,
+ 0, NULL)) == NULL)
+ return CTF_ERR; /* errno is set for us. */
+
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, flag, 0);
+ dtd->dtd_data->ctt_type = (uint32_t) type;
+
+ if (is_decl)
+ {
+ ctf_decl_tag_t *vlen = (ctf_decl_tag_t *) dtd->dtd_vlen;
+ vlen->cdt_component_idx = component_idx;
+ }
+
+ return dtd->dtd_type;
+}
+
+/* Create a type tag. */
+
+ctf_id_t
+ctf_add_type_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag)
+{
+ return ctf_add_tag (fp, flag, type, tag, 0, -1);
+}
+
+/* Create a decl tag applied to an entire type. */
+
+ctf_id_t
+ctf_add_decl_type_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag)
+{
+ return ctf_add_tag (fp, flag, type, tag, 1, -1);
+}
+
+/* Create a decl tag applied to one element of a type.
+ component_idx must be >= 0. */
+ctf_id_t
+ctf_add_decl_tag (ctf_dict_t *fp, uint32_t flag, ctf_id_t type, const char *tag,
+ int component_idx)
+{
+ return ctf_add_tag (fp, flag, type, tag, 1, component_idx);
+}
+
ctf_id_t
ctf_add_function (ctf_dict_t *fp, uint32_t flag,
const ctf_funcinfo_t *ctc, const ctf_id_t *argv,
prec = CTF_PREC_POINTER;
break;
+ case CTF_K_DECL_TAG:
case CTF_K_VAR:
ctf_decl_push (cd, fp, suffix->ctt_type);
prec = CTF_PREC_BASE; /* UPTODO probably wrong */
extern int ctf_add_funcobjt_sym_forced (ctf_dict_t *, int is_function,
const char *, ctf_id_t);
+extern int ctf_insert_type_decl_tag (ctf_dict_t *, ctf_id_t, const char *,
+ int kind);
extern int ctf_track_enumerator (ctf_dict_t *, ctf_id_t, const char *);
extern int ctf_dedup_atoms_init (ctf_dict_t *);
return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
}
+/* Iterate over all tags with the given TAG, returning the ID of each tag. */
+
+ctf_id_t
+ctf_tag_next (ctf_dict_t *fp, const char *tag, ctf_next_t **it)
+{
+ ctf_next_t *i = *it;
+ int err;
+ void *type;
+
+ if (!i)
+ {
+ if ((i = ctf_next_create ()) == NULL)
+ return (ctf_set_typed_errno (fp, ENOMEM));
+ i->cu.ctn_fp = fp;
+ i->ctn_iter_fun = (void (*) (void)) ctf_tag_next;
+
+ i->cu.ctn_s = ctf_dynhash_lookup (fp->ctf_tags, tag);
+
+ *it = i;
+ }
+
+ if ((void (*) (void)) ctf_tag_next != i->ctn_iter_fun)
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFUN));
+
+ if (fp != i->cu.ctn_fp)
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_WRONGFP));
+
+ err = ctf_dynset_next (i->cu.ctn_s, &i->ctn_next, &type);
+ if (err != 0 && err != ECTF_NEXT_END)
+ return ctf_set_typed_errno (fp, err);
+
+ if (err == 0)
+ return (ctf_id_t) (uintptr_t) type;
+
+ ctf_next_destroy (i);
+ *it = NULL;
+ return (ctf_set_typed_errno (fp, ECTF_NEXT_END));
+}
+
/* Follow a given type through the graph for TYPEDEF, VOLATILE, CONST, and
RESTRICT nodes until we reach a "base" type node. This is useful when
we want to follow a type ID to a node that has members or a size. To guard
case CTF_K_ENUM64:
ctf_decl_sprintf (&cd, "enum %s", name);
break;
+ case CTF_K_TYPE_TAG:
+ ctf_decl_sprintf (&cd, "%s", name);
+ break;
+ /* UPTODO: decl tags... I guess we print them when we print the
+ associated variable, somehow? For now, just this... */
+ case CTF_K_DECL_TAG:
+ ctf_decl_sprintf (&cd, "btf_decl_tag (\"%s\")", name);
+ break;
case CTF_K_FUNC_LINKAGE:
case CTF_K_VAR:
{
case CTF_K_VOLATILE:
case CTF_K_CONST:
case CTF_K_RESTRICT:
+ case CTF_K_TYPE_TAG:
+ case CTF_K_DECL_TAG:
case CTF_K_FUNCTION:
case CTF_K_FUNC_LINKAGE:
case CTF_K_VAR:
}
}
+/* Return the component ID and declaration to which a decl tag is attached. */
+
+ctf_id_t
+ctf_decl_tag (ctf_dict_t *fp, ctf_id_t decl_tag, int64_t *component_idx)
+{
+ ctf_dict_t *ofp = fp;
+ const ctf_type_t *tp, *suffix;
+ unsigned char *vlen;
+ ctf_decl_tag_t *cdt;
+
+ if ((tp = ctf_lookup_by_id (&fp, decl_tag, &suffix)) == NULL)
+ return CTF_ERR; /* errno is set for us. */
+
+ if (LCTF_KIND (fp, tp) != CTF_K_DECL_TAG)
+ return (ctf_set_typed_errno (ofp, ECTF_NOTDECLTAG));
+
+ vlen = ctf_vlen (fp, decl_tag, tp, NULL);
+ cdt = (ctf_decl_tag_t *) vlen;
+
+ *component_idx = cdt->cdt_component_idx;
+
+ return suffix->ctt_type;
+}
+
+/* Return the type ID of the type to which a given type tag is attached, or of
+ the type of the declaration to which a decl tag is attached (so a decl tag on
+ a function parameter would return the type ID of the parameter's type). */
+
+ctf_id_t
+ctf_tag (ctf_dict_t *fp, ctf_id_t tag)
+{
+ int kind = ctf_type_kind (fp, tag);
+ int64_t component_idx;
+ ctf_id_t ref;
+
+ if (kind != CTF_K_TYPE_TAG && kind != CTF_K_DECL_TAG)
+ return (ctf_set_typed_errno (fp, ECTF_NOTTAG));
+
+ if ((ref = ctf_type_reference (fp, tag)) == CTF_ERR)
+ return CTF_ERR; /* errno is set for us. */
+
+ if (kind == CTF_K_TYPE_TAG)
+ return ref;
+
+ if (ctf_decl_tag (fp, tag, &component_idx) == CTF_ERR)
+ return CTF_ERR; /* errno is set for us. */
+
+ if (component_idx == -1)
+ return ref;
+
+ /* See ctf_add_tag. */
+
+ switch (ctf_type_kind (fp, ref))
+ {
+ case CTF_K_STRUCT:
+ case CTF_K_UNION:
+ {
+ ctf_next_t *i = NULL;
+ int64_t j = 0;
+ ctf_id_t type;
+
+ while (ctf_member_next (fp, ref, &i, NULL, &type, NULL, 0) >= 0)
+ {
+ if (j++ == component_idx)
+ {
+ ctf_next_destroy (i);
+ return type;
+ }
+ }
+ if (ctf_errno (fp) != ECTF_NEXT_END)
+ {
+ ctf_next_destroy (i);
+ return CTF_ERR; /* errno is set for us. */
+ }
+ }
+ break;
+ case CTF_K_FUNC_LINKAGE:
+ case CTF_K_FUNCTION:
+ {
+ ctf_funcinfo_t fi;
+ ctf_id_t *args;
+ ctf_id_t argtype;
+
+ if (ctf_func_type_info (fp, ref, &fi) < 0)
+ return CTF_ERR; /* errno is set for us. */
+
+ if (component_idx + 1 > (ssize_t) fi.ctc_argc)
+ break;
+
+ if ((args = malloc ((component_idx + 1) * sizeof (ctf_id_t))) == NULL)
+ return (ctf_set_typed_errno (fp, ENOMEM));
+
+ if (ctf_func_type_args (fp, ref, component_idx + 1, args))
+ {
+ free (args);
+ return CTF_ERR; /* errno is set for us. */
+ }
+ argtype = args[component_idx];
+ free (args);
+ return argtype;
+ }
+
+ default:
+ return CTF_ERR; /* errno is set for us. */
+ }
+
+ ctf_err_warn (fp, 0, ECTF_NOTREF, _("decl tag %lx refers to type %lx, "
+ "component %" PRIi64 ", which does not exist"),
+ tag, (long) ref, component_idx);
+
+ return (ctf_set_typed_errno (fp, ECTF_NOTREF));
+}
+
/* Find a pointer to type by looking in fp->ctf_ptrtab and fp->ctf_pptrtab. If
we can't find a pointer to the given type, see if we can compute a pointer to
the type resulting from resolving the type down to its base type and use that
ctf_type_visit;
ctf_type_cmp;
ctf_type_compat;
+ ctf_tag;
+ ctf_decl_tag;
ctf_member_info;
ctf_member_next;
ctf_variable_next;
ctf_datasec_iter;
ctf_datasec_next;
+ ctf_tag_next;
ctf_next_create;
ctf_next_destroy;
ctf_add_array;
ctf_add_const;
+ ctf_add_decl_tag;
+ ctf_add_decl_type_tag;
ctf_add_enum;
ctf_add_enum_encoded;
ctf_add_enum64;
ctf_add_pointer;
ctf_add_type;
ctf_add_typedef;
+ ctf_add_type_tag;
ctf_add_restrict;
ctf_add_section_variable;
ctf_add_slice;