typedef int ctf_visit_f (const char *name, ctf_id_t type, unsigned long offset,
int depth, void *arg);
-typedef int ctf_enum_f (const char *name, int val, void *arg);
typedef int ctf_variable_f (const char *name, ctf_id_t type, void *arg);
typedef int ctf_type_f (ctf_id_t type, void *arg);
typedef int ctf_type_all_f (ctf_id_t type, int flag, void *arg);
void *arg);
typedef int ctf_member_f (ctf_dict_t *, const char *name, ctf_id_t membtype,
size_t offset, int bit_width, void *arg);
+typedef int ctf_enum_f (const char *name, int64_t val, void *arg);
+typedef int ctf_unsigned_enum_f (const char *name, uint64_t val, void *arg);
typedef int ctf_archive_member_f (ctf_dict_t *fp, const char *name, void *arg);
typedef int ctf_archive_raw_member_f (const char *name, const void *content,
size_t len, void *arg);
/* Return the kind of a type (CTF_K_* constant). Slices are considered to be
the kind they are a slice of. Forwards to incomplete structs, etc, return
CTF_K_FORWARD (but deduplication resolves most forwards to their concrete
- types). */
+ types).
+
+ CTFv4 note: forwards to enums also return CTF_K_FORWARD, even though they
+ are encoded differently. */
extern int ctf_type_kind (ctf_dict_t *, ctf_id_t);
/* Get the name of an enumerator given its value, or vice versa. If many
enumerators have the same value, the first with that value is returned. */
-extern const char *ctf_enum_name (ctf_dict_t *, ctf_id_t, int);
-extern int ctf_enum_value (ctf_dict_t *, ctf_id_t, const char *, int *);
+extern const char *ctf_enum_name (ctf_dict_t *, ctf_id_t, int64_t);
+extern int ctf_enum_value (ctf_dict_t *, ctf_id_t, const char *, int64_t *);
+extern int ctf_enum_unsigned_value (ctf_dict_t *, ctf_id_t, const char *, uint64_t *);
+
+/* Return 1 if this enum's contents are unsigned, so you can tell which of the
+ above functions to use. */
+
+extern int ctf_enum_unsigned (ctf_dict_t *, ctf_id_t);
+
/* Return nonzero if this struct or union uses bitfield encoding. */
extern int ctf_struct_bitfield (ctf_dict_t *, ctf_id_t);
const char **name, ctf_id_t *membtype,
int *bit_width, int flags);
-/* Return all enumeration constants in a given enum type. */
-extern int ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
+/* Return all enumeration constants in a given enum type. The return value, and
+ VAL argument, may need to be cast to uint64_t: see ctf_enum_unsigned(). */
+extern int64_t ctf_enum_iter (ctf_dict_t *, ctf_id_t, ctf_enum_f *, void *);
extern const char *ctf_enum_next (ctf_dict_t *, ctf_id_t, ctf_next_t **,
- int *);
+ int64_t *);
/* Return all enumeration constants with a given name in a given dict, similar
to ctf_lookup_enumerator above but capable of returning multiple values.
extern ctf_id_t ctf_add_array (ctf_dict_t *, uint32_t,
const ctf_arinfo_t *);
extern ctf_id_t ctf_add_const (ctf_dict_t *, uint32_t, ctf_id_t);
+
+/* enums are created signed by default. If you want an unsigned enum,
+ use ctf_add_enum_encoded() with an encoding of 0 (CTF_INT_SIGNED and
+ everything else off). This will not create a slice, unlike all other
+ uses of ctf_add_enum_encoded(), and the result is still representable
+ as BTF. */
+
+extern ctf_id_t ctf_add_enum64_encoded (ctf_dict_t *, uint32_t, const char *,
+ const ctf_encoding_t *);
+extern ctf_id_t ctf_add_enum64 (ctf_dict_t *, uint32_t, const char *);
extern ctf_id_t ctf_add_enum_encoded (ctf_dict_t *, uint32_t, const char *,
const ctf_encoding_t *);
extern ctf_id_t ctf_add_enum (ctf_dict_t *, uint32_t, const char *);
extern ctf_id_t ctf_add_unknown (ctf_dict_t *, uint32_t, const char *);
extern ctf_id_t ctf_add_volatile (ctf_dict_t *, uint32_t, ctf_id_t);
-/* Add an enumerator to an enum. If the enum is non-root, so are all the
- constants added to it by ctf_add_enumerator. */
+/* Add an enumerator to an enum or enum64. If the enum is non-root, so are all
+ the constants added to it by ctf_add_enumerator. */
-extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int);
+extern int ctf_add_enumerator (ctf_dict_t *, ctf_id_t, const char *, int64_t);
/* Add a member to a struct or union, either at the next available offset (with
suitable padding for the alignment) or at a specific offset, and possibly
case CTF_K_UNION:
return fp->ctf_unions;
case CTF_K_ENUM:
+ case CTF_K_ENUM64:
return fp->ctf_enums;
default:
return fp->ctf_names;
const char *name, const ctf_encoding_t *ep, uint32_t kind)
{
ctf_dtdef_t *dtd;
- ctf_id_t type;
uint32_t encoding;
+ int vlen = sizeof (uint32_t);
if (ep == NULL)
return (ctf_set_typed_errno (fp, EINVAL));
return (ctf_add_union_sized (fp, flag, name, 0));
}
-ctf_id_t
-ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
+static ctf_id_t
+ctf_add_enum_internal (ctf_dict_t *fp, uint32_t flag, const char *name,
+ int kind, int is_signed)
{
ctf_dtdef_t *dtd;
ctf_id_t type = 0;
- size_t initial_vbytes = sizeof (ctf_enum_t) * INITIAL_VLEN;
+ size_t initial_vbytes;
+ ctf_type_t *prefix;
+
+ if (!ctf_assert (fp, kind == CTF_K_ENUM || kind == CTF_K_ENUM64))
+ return -1; /* errno is set for us. */
+
+ if (kind == CTF_K_ENUM)
+ initial_vbytes = sizeof (ctf_enum_t) * INITIAL_VLEN;
+ else
+ initial_vbytes = sizeof (ctf_enum64_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)
- type = ctf_lookup_by_rawname (fp, CTF_K_ENUM, name);
+ type = ctf_lookup_by_rawname (fp, kind, name);
/* Prohibit promotion if this type was ctf_open()ed. */
if (type > 0 && type < fp->ctf_stypes)
return (ctf_set_errno (fp, ECTF_RDONLY));
if (type != 0 && ctf_type_kind (fp, type) == CTF_K_FORWARD)
- dtd = ctf_dtd_lookup (fp, type);
- else if ((type = ctf_add_generic (fp, flag, name, CTF_K_ENUM,
- initial_vbytes, &dtd)) == CTF_ERR)
- return CTF_ERR; /* errno is set for us. */
-
- /* Forwards won't have any vlen yet. */
- if (dtd->dtd_vlen_alloc == 0)
{
- if ((dtd->dtd_vlen = calloc (1, initial_vbytes)) == NULL)
- return (ctf_set_typed_errno (fp, ENOMEM));
- dtd->dtd_vlen_alloc = initial_vbytes;
+ dtd = ctf_dtd_lookup (fp, type);
+
+ if ((prefix = ctf_add_prefix (fp, dtd, initial_vbytes)) == NULL)
+ return CTF_ERR; /* errno is set for us. */
}
+ else if ((dtd = ctf_add_generic (fp, flag, name, kind, 1, 0, initial_vbytes,
+ &prefix)) == NULL)
+ return CTF_ERR; /* errno is set for us. */
- dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, flag, 0);
- dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int;
+ prefix->ctt_info = CTF_TYPE_INFO (CTF_K_BIG, 0, 0);
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, is_signed, 0);
- return type;
+ if (kind == CTF_K_ENUM)
+ dtd->dtd_data->ctt_size = fp->ctf_dmodel->ctd_int;
+ else
+ dtd->dtd_data->ctt_size = 8;
+
+ return dtd->dtd_type;
}
ctf_id_t
-ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
- const ctf_encoding_t *ep)
+ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name)
+{
+ return ctf_add_enum_internal (fp, flag, name, CTF_K_ENUM, 1);
+}
+
+ctf_id_t
+ctf_add_enum64 (ctf_dict_t *fp, uint32_t flag, const char *name)
+{
+ return ctf_add_enum_internal (fp, flag, name, CTF_K_ENUM64, 1);
+}
+
+static ctf_id_t
+ctf_add_enum_encoded_internal (ctf_dict_t *fp, uint32_t flag, const char *name,
+ int kind, const ctf_encoding_t *ep)
{
ctf_id_t type = 0;
+ int is_signed = ((ep->cte_format & CTF_INT_SIGNED) != 0);
/* First, create the enum if need be, using most of the same machinery as
ctf_add_enum(), to ensure that we do not allow things past that are not
if (type != 0)
{
if ((ctf_type_kind (fp, type) != CTF_K_FORWARD) &&
- (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM))
+ (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM) &&
+ (ctf_type_kind_unsliced (fp, type) != CTF_K_ENUM64))
return (ctf_set_typed_errno (fp, ECTF_NOTINTFP));
}
- else if ((type = ctf_add_enum (fp, flag, name)) == CTF_ERR)
+ else if ((type = ctf_add_enum_internal (fp, flag, name, kind, is_signed))
+ == CTF_ERR)
return CTF_ERR; /* errno is set for us. */
+ /* If this is just changing the signedness of the enum, we don't need a
+ slice. */
+
+ if ((ep->cte_format & ~CTF_INT_SIGNED) == 0
+ && ep->cte_bits == 0
+ && ep->cte_offset == 0)
+ return type;
+
/* Now attach a suitable slice to it. */
return ctf_add_slice (fp, flag, type, ep);
}
+ctf_id_t
+ctf_add_enum_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
+ const ctf_encoding_t *ep)
+{
+ return ctf_add_enum_encoded_internal (fp, flag, name, CTF_K_ENUM, ep);
+}
+
+ctf_id_t
+ctf_add_enum64_encoded (ctf_dict_t *fp, uint32_t flag, const char *name,
+ const ctf_encoding_t *ep)
+{
+ return ctf_add_enum_encoded_internal (fp, flag, name, CTF_K_ENUM64, ep);
+}
+
ctf_id_t
ctf_add_forward (ctf_dict_t *fp, uint32_t flag, const char *name,
uint32_t kind)
if (type)
return type;
- if ((type = ctf_add_generic (fp, flag, name, kind, 0, &dtd)) == CTF_ERR)
+ if ((dtd = ctf_add_generic (fp, flag, name, kind, 0, 0, 0, NULL)) == NULL)
return CTF_ERR; /* errno is set for us. */
- dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, flag, 0);
- dtd->dtd_data.ctt_type = kind;
+ if (kind != CTF_K_ENUM &&
+ kind != CTF_K_ENUM64)
+ {
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (CTF_K_FORWARD, 0, 0);
+ dtd->dtd_data->ctt_type = kind;
+ }
+ else
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (CTF_K_ENUM, 0, 0);
- return type;
+ return dtd->dtd_type;
}
ctf_id_t
int
ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name,
- int value)
+ int64_t value)
{
ctf_dict_t *ofp = fp;
ctf_dtdef_t *dtd;
- ctf_enum_t *en;
- uint32_t kind, vlen, root;
+ uint32_t kind, vlen, root, en_name;
if (name == NULL)
return (ctf_set_errno (fp, EINVAL));
if (dtd == NULL)
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);
+ kind = LCTF_KIND (fp, dtd->dtd_buf);
+ root = LCTF_INFO_ISROOT (fp, dtd->dtd_buf->ctt_info);
+ vlen = LCTF_VLEN (fp, dtd->dtd_buf);
/* Enumeration constant names are only added, and only checked for duplicates,
if the enum they are part of is a root-visible type. */
return (ctf_set_errno (ofp, ctf_errno (fp)));
}
- if (kind != CTF_K_ENUM)
+ if ((kind != CTF_K_ENUM) && (kind != CTF_K_ENUM64))
return (ctf_set_errno (ofp, ECTF_NOTENUM));
if (vlen == CTF_MAX_VLEN)
return (ctf_set_errno (ofp, ECTF_DTFULL));
- if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
- return -1; /* errno is set for us. */
+ if (kind == CTF_K_ENUM)
+ {
+ if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0)
+ return -1; /* errno is set for us. */
+
+ dtd->dtd_vlen_size += sizeof (ctf_enum_t);
+ }
+ else
+ {
+ if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum64_t) * (vlen + 1)) < 0)
+ return -1; /* errno is set for us. */
- en = (ctf_enum_t *) dtd->dtd_vlen;
+ dtd->dtd_vlen_size += sizeof (ctf_enum64_t);
+ }
/* Check for constant duplication within any given enum: only needed for
non-root-visible types, since the duplicate detection above does the job
{
size_t i;
- for (i = 0; i < vlen; i++)
- if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
- return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+ if (kind == CTF_K_ENUM)
+ {
+ ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
+
+ for (i = 0; i < vlen; i++)
+ if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+ return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+ }
+ else
+ {
+ ctf_enum64_t *en = (ctf_enum64_t *) dtd->dtd_vlen;
+
+ for (i = 0; i < vlen; i++)
+ if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0)
+ return (ctf_set_errno (ofp, ECTF_DUPLICATE));
+
+ }
}
- en[vlen].cte_name = ctf_str_add (fp, name);
- en[vlen].cte_value = value;
+ if (kind == CTF_K_ENUM)
+ {
+ ctf_enum_t *en = (ctf_enum_t *) dtd->dtd_vlen;
+
+ en[vlen].cte_name = ctf_str_add (fp, name);
+ en[vlen].cte_value = value;
- if (en[vlen].cte_name == 0 && name != NULL && name[0] != '\0')
+ en_name = en[vlen].cte_name;
+ }
+ else
+ {
+ ctf_enum64_t *en = (ctf_enum64_t *) dtd->dtd_vlen;
+
+ en[vlen].cte_name = ctf_str_add (fp, name);
+ en[vlen].cte_val_low = ((uint64_t) value) & 0xffffffff;
+ en[vlen].cte_val_high = ((uint64_t) value) >> 32;
+
+ en_name = en[vlen].cte_name;
+ }
+
+ if (en_name == 0 && name != NULL && name[0] != '\0')
return (ctf_set_errno (ofp, ctf_errno (fp)));
/* Put the newly-added enumerator name into the name table if this type is
if (root == CTF_ADD_ROOT)
{
if (ctf_dynhash_insert (fp->ctf_names,
- (char *) ctf_strptr (fp, en[vlen].cte_name),
+ (char *) ctf_strptr (fp, en_name),
(void *) (uintptr_t) enid) < 0)
return ctf_set_errno (fp, ENOMEM);
}
- dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
+ dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1);
return 0;
}
} ctf_bundle_t;
static int
-enumcmp (const char *name, int value, void *arg)
+enumcmp (const char *name, int64_t value, void *arg)
{
ctf_bundle_t *ctb = arg;
- int bvalue;
+ int64_t bvalue;
if (ctf_enum_value (ctb->ctb_dict, ctb->ctb_type, name, &bvalue) < 0)
{
if (value != bvalue)
{
ctf_err_warn (ctb->ctb_dict, 1, ECTF_CONFLICT,
- _("conflict due to enum value change: %i versus %i"),
+ _("conflict due to enum value change: %li versus %li"),
value, bvalue);
return 1;
}
}
static int
-enumadd (const char *name, int value, void *arg)
+enumadd (const char *name, int64_t value, void *arg)
{
ctf_bundle_t *ctb = arg;
}
case CTF_K_ENUM:
+ case CTF_K_ENUM64:
if (dst_type != CTF_ERR && kind != CTF_K_FORWARD
&& dst_kind != CTF_K_FORWARD)
{
+ if (ctf_enum_unsigned (src_fp, src_type)
+ != ctf_enum_unsigned (dst_fp, dst_type))
+ {
+ ctf_err_warn (dst_fp, 1, ECTF_CONFLICT,
+ _("conflict for enum %s against ID %lx: member "
+ "signedness differs"), name, dst_type);
+ return (ctf_set_typed_errno (dst_fp, ECTF_CONFLICT));
+ }
if (ctf_enum_iter (src_fp, src_type, enumcmp, &dst)
|| ctf_enum_iter (dst_fp, dst_type, enumcmp, &src))
{
{
ctf_snapshot_id_t snap = ctf_snapshot (dst_fp);
- dst_type = ctf_add_enum (dst_fp, flag, name);
+ if (src_type == CTF_K_ENUM)
+ dst_type = ctf_add_enum (dst_fp, flag, name);
+ else
+ dst_type = ctf_add_enum64 (dst_fp, flag, name);
if ((dst.ctb_type = dst_type) == CTF_ERR
|| ctf_enum_iter (src_fp, src_type, enumadd, &dst))
{
ctf_lookup_enumerator (ctf_dict_t *fp, const char *name, int64_t *enum_value)
{
ctf_id_t type;
- int enum_int_value;
+ int64_t enum_int_value;
if (fp->ctf_flags & LCTF_NO_STR)
return (ctf_set_typed_errno (fp, ECTF_NOPARENT));
do
{
const char *this_name;
+ int is_enum64 = 0;
/* At end of enum? Traverse to next one, if any are left. */
{
const ctf_type_t *tp;
ctf_dtdef_t *dtd;
+ int kind;
+ unsigned char *vlen;
+ /* It's a shame we can't use ctf_type_kind_next here, but we're
+ looking for two type kinds at once... */
do
- i->ctn_type = ctf_type_next (i->cu.ctn_fp, &i->ctn_next, NULL, 1);
- while (i->ctn_type != CTF_ERR
- && ctf_type_kind_unsliced (i->cu.ctn_fp, i->ctn_type)
- != CTF_K_ENUM);
+ i->i.ctn_type = ctf_type_next (i->cu.ctn_fp, &i->ctn_next, NULL, 1);
+ while (i->i.ctn_type != CTF_ERR
+ && ((kind = ctf_type_kind_unsliced (i->cu.ctn_fp, i->i.ctn_type))
+ != CTF_K_ENUM && kind != CTF_K_ENUM64));
- if (i->ctn_type == CTF_ERR)
+ if (i->i.ctn_type == CTF_ERR)
{
/* Conveniently, when the iterator over all types is done, so is the
iteration as a whole: so we can just pass all errors from the
return CTF_ERR; /* errno is set for us. */
}
- if ((tp = ctf_lookup_by_id (&fp, i->ctn_type)) == NULL)
+ if ((tp = ctf_lookup_by_id (&fp, i->i.ctn_type, &i->ctn_tp)) == NULL)
return CTF_ERR; /* errno is set for us. */
- i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+ i->ctn_n = LCTF_VLEN (fp, tp);
- dtd = ctf_dynamic_type (fp, i->ctn_type);
-
- if (dtd == NULL)
+ if ((dtd = ctf_dynamic_type (fp, i->i.ctn_type)) != NULL)
+ vlen = dtd->dtd_vlen;
+ else
{
- (void) ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment);
- i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
- i->ctn_increment);
+ ctf_get_ctt_size (fp, tp, NULL, &i->ctn_increment);
+ vlen = (unsigned char *) ((uintptr_t) tp + i->ctn_increment);
}
+
+ if (kind == CTF_K_ENUM)
+ i->u.ctn_en = (const ctf_enum_t *) vlen;
else
- i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;
+ i->u.ctn_en64 = (const ctf_enum64_t *) vlen;
}
- this_name = ctf_strptr (fp, i->u.ctn_en->cte_name);
+ if (LCTF_KIND (fp, i->ctn_tp) == CTF_K_ENUM64)
+ is_enum64 = 1;
+
+ if (is_enum64)
+ this_name = ctf_strptr (fp, i->u.ctn_en64->cte_name);
+ else
+ this_name = ctf_strptr (fp, i->u.ctn_en->cte_name);
i->ctn_n--;
if (strcmp (name, this_name) == 0)
{
if (val)
- *val = i->u.ctn_en->cte_value;
+ {
+ if (is_enum64)
+ *val = ((uint64_t) i->u.ctn_en64->cte_val_high) << 32 | (i->u.ctn_en64->cte_val_low);
+ else
+ *val = i->u.ctn_en->cte_value;
+ }
found = 1;
/* Constant found in this enum: try the next one. (Constant names
}
while (!found);
- return i->ctn_type;
+ return i->i.ctn_type;
}
typedef struct ctf_symidx_sort_arg_cb
/* Iterate over the members of an ENUM. We pass the string name and associated
integer value of each enum element to the specified callback function. */
-int
+int64_t
ctf_enum_iter (ctf_dict_t *fp, ctf_id_t type, ctf_enum_f *func, void *arg)
{
ctf_next_t *i = NULL;
const char *name;
- int val;
+ int64_t val;
while ((name = ctf_enum_next (fp, type, &i, &val)) != NULL)
{
const char *
ctf_enum_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it,
- int *val)
+ int64_t *val)
{
ctf_dict_t *ofp = fp;
uint32_t kind;
if (!i)
{
const ctf_type_t *tp;
- ctf_dtdef_t *dtd;
+ unsigned char *en;
if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
return NULL; /* errno is set for us. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
- return NULL; /* errno is set for us. */
+ kind = ctf_type_kind (fp, type);
- if ((i = ctf_next_create ()) == NULL)
+ if ((kind != CTF_K_ENUM) && (kind != CTF_K_ENUM64))
{
- ctf_set_errno (ofp, ENOMEM);
+ ctf_next_destroy (i);
+ ctf_set_errno (ofp, ECTF_NOTENUM);
return NULL;
}
- i->cu.ctn_fp = ofp;
- (void) ctf_get_ctt_size (fp, tp, NULL,
- &i->ctn_increment);
- kind = LCTF_INFO_KIND (fp, tp->ctt_info);
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
+ return NULL; /* errno is set for us. */
- if (kind != CTF_K_ENUM)
+ if ((i = ctf_next_create ()) == NULL)
{
- ctf_next_destroy (i);
- ctf_set_errno (ofp, ECTF_NOTENUM);
+ ctf_set_errno (ofp, ENOMEM);
return NULL;
}
+ i->cu.ctn_fp = ofp;
- dtd = ctf_dynamic_type (fp, type);
i->ctn_iter_fun = (void (*) (void)) ctf_enum_next;
- i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info);
+ en = ctf_vlen (fp, type, tp, &i->ctn_n);
- if (dtd == NULL)
- i->u.ctn_en = (const ctf_enum_t *) ((uintptr_t) tp +
- i->ctn_increment);
- else
- i->u.ctn_en = (const ctf_enum_t *) dtd->dtd_vlen;
+ if (kind == CTF_K_ENUM)
+ i->u.ctn_en = (const ctf_enum_t *) en;
+ else /* CTF_K_ENUM64 */
+ i->u.ctn_en64 = (const ctf_enum64_t *) en;
*it = i;
}
if (i->ctn_n == 0)
goto end_iter;
- name = ctf_strptr (fp, i->u.ctn_en->cte_name);
- if (val)
- *val = i->u.ctn_en->cte_value;
- i->u.ctn_en++;
+ if (ctf_type_kind (fp, type) == CTF_K_ENUM)
+ {
+ name = ctf_strptr (fp, i->u.ctn_en->cte_name);
+ if (val)
+ *val = i->u.ctn_en->cte_value;
+ i->u.ctn_en++;
+ }
+ else
+ {
+ name = ctf_strptr (fp, i->u.ctn_en64->cte_name);
+ if (val)
+ *val = ((uint64_t) i->u.ctn_en64->cte_val_high) << 32 | (i->u.ctn_en64->cte_val_low);
+ i->u.ctn_en64++;
+ }
i->ctn_n--;
return name;
ctf_decl_sprintf (&cd, "union %s", name);
break;
case CTF_K_ENUM:
+ case CTF_K_ENUM64:
ctf_decl_sprintf (&cd, "enum %s", name);
break;
case CTF_K_FORWARD:
ctf_decl_sprintf (&cd, "union %s", name);
break;
case CTF_K_ENUM:
+ case CTF_K_ENUM64:
ctf_decl_sprintf (&cd, "enum %s", name);
break;
default:
case CTF_K_FUNCTION:
return 0; /* Function size is only known by symtab. */
- case CTF_K_ENUM:
- return fp->ctf_dmodel->ctd_int;
case CTF_K_ARRAY:
/* ctf_add_array() does not directly encode the element size, but
/* Forwards do not have a meaningful size. */
return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
- default: /* including slices of enums, etc */
+ default: /* including enums of all kinds, slices, etc */
return (ctf_get_ctt_size (fp, tp, NULL, NULL));
}
}
return align;
}
- case CTF_K_ENUM:
- return fp->ctf_dmodel->ctd_int;
-
case CTF_K_FORWARD:
/* Forwards do not have a meaningful alignment. */
return (ctf_set_errno (ofp, ECTF_INCOMPLETE));
- default: /* including slices of enums, etc */
+ default: /* including enums of all kinds, slices, etc */
return (ctf_get_ctt_size (fp, tp, NULL, NULL));
}
}
ep->cte_bits = CTF_FP_BITS (data);
break;
case CTF_K_ENUM:
- /* v3 only: we must guess at the underlying integral format. */
- ep->cte_format = CTF_INT_SIGNED;
+ case CTF_K_ENUM64:
+ ep->cte_format = CTF_INFO_KFLAG (suffix->ctt_info) ? CTF_INT_SIGNED : 0;
ep->cte_offset = 0;
ep->cte_bits = 0;
break;
same_names = (strcmp (ctf_strptr (lfp, ltp->ctt_name),
ctf_strptr (rfp, rtp->ctt_name)) == 0);
- if (((lkind == CTF_K_ENUM) && (rkind == CTF_K_INTEGER)) ||
- ((rkind == CTF_K_ENUM) && (lkind == CTF_K_INTEGER)))
+ if ((((lkind == CTF_K_ENUM) || (lkind == CTF_K_ENUM64)) && (rkind == CTF_K_INTEGER)) ||
+ (((rkind == CTF_K_ENUM) || (lkind == CTF_K_ENUM64)) && (lkind == CTF_K_INTEGER)))
return 1;
if (lkind != rkind)
case CTF_K_UNION:
return (same_names && (ctf_type_size (lfp, ltype)
== ctf_type_size (rfp, rtype)));
+ case CTF_K_ENUM64:
case CTF_K_ENUM:
{
int lencoded, rencoded;
matching name can be found. Otherwise NULL is returned. */
const char *
-ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int value)
+ctf_enum_name (ctf_dict_t *fp, ctf_id_t type, int64_t value)
{
ctf_dict_t *ofp = fp;
const ctf_type_t *tp;
- const ctf_enum_t *ep;
- const ctf_dtdef_t *dtd;
- ssize_t increment;
- uint32_t n;
+ unsigned char *vlen;
+ int kind;
+ size_t n;
if (fp->ctf_flags & LCTF_NO_STR)
{
if ((type = ctf_type_resolve_unsliced (fp, type)) == CTF_ERR)
return NULL; /* errno is set for us. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
return NULL; /* errno is set for us. */
- if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+ kind = LCTF_KIND (fp, tp);
+ if (kind != CTF_K_ENUM && kind != CTF_K_ENUM64)
{
ctf_set_errno (ofp, ECTF_NOTENUM);
return NULL;
}
- ctf_get_ctt_size (fp, tp, NULL, &increment);
+ vlen = ctf_vlen (fp, type, tp, &n);
- if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
- ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
- else
- ep = (const ctf_enum_t *) dtd->dtd_vlen;
+ if (kind == CTF_K_ENUM)
+ {
+ const ctf_enum_t *ep = (const ctf_enum_t *) vlen;
- for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+ for (; n != 0; n--, ep++)
+ {
+ if (ep->cte_value == value)
+ return (ctf_strptr (fp, ep->cte_name));
+ }
+ }
+ else
{
- if (ep->cte_value == value)
- return (ctf_strptr (fp, ep->cte_name));
+ const ctf_enum64_t *ep = (const ctf_enum64_t *) vlen;
+
+ for (; n != 0; n--, ep++)
+ {
+ int64_t this_value = ((uint64_t) ep->cte_val_high << 32) | (ep->cte_val_low);
+
+ if (this_value == value)
+ return (ctf_strptr (fp, ep->cte_name));
+ }
}
ctf_set_errno (ofp, ECTF_NOENUMNAM);
matching name can be found. Otherwise CTF_ERR is returned. */
int
-ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int *valp)
+ctf_enum_value (ctf_dict_t *fp, ctf_id_t type, const char *name, int64_t *valp)
{
ctf_dict_t *ofp = fp;
const ctf_type_t *tp;
- const ctf_enum_t *ep;
- const ctf_dtdef_t *dtd;
- ssize_t increment;
- uint32_t n;
+ unsigned char *vlen;
+ int kind;
+ size_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. */
- if ((tp = ctf_lookup_by_id (&fp, type)) == NULL)
+ if ((tp = ctf_lookup_by_id (&fp, type, NULL)) == NULL)
return -1; /* errno is set for us. */
- if (LCTF_INFO_KIND (fp, tp->ctt_info) != CTF_K_ENUM)
+ kind = LCTF_KIND (fp, tp);
+ if (kind != CTF_K_ENUM && kind != CTF_K_ENUM64)
return ctf_set_errno (ofp, ECTF_NOTENUM);
- ctf_get_ctt_size (fp, tp, NULL, &increment);
+ vlen = ctf_vlen (fp, type, tp, &n);
- if ((dtd = ctf_dynamic_type (ofp, type)) == NULL)
- ep = (const ctf_enum_t *) ((uintptr_t) tp + increment);
- else
- ep = (const ctf_enum_t *) dtd->dtd_vlen;
+ if (kind == CTF_K_ENUM)
+ {
+ const ctf_enum_t *ep = (const ctf_enum_t *) vlen;
- for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, ep++)
+ for (; n != 0; n--, ep++)
+ {
+ if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+ {
+ if (valp != NULL)
+ *valp = ep->cte_value;
+ return 0;
+ }
+ }
+ }
+ else
{
- if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+ const ctf_enum64_t *ep = (const ctf_enum64_t *) vlen;
+
+ for (; n != 0; n--, ep++)
{
- if (valp != NULL)
- *valp = ep->cte_value;
- return 0;
+ if (strcmp (ctf_strptr (fp, ep->cte_name), name) == 0)
+ {
+ if (valp != NULL)
+ *valp = ((uint64_t) ep->cte_val_high << 32) | ep->cte_val_low;
+ return 0;
+ }
}
}
return ctf_set_errno (ofp, ECTF_NOENUMNAM);
}
+/* Like ctf_enum_value, but returns an unsigned int64_t instead. */
+int
+ctf_enum_unsigned_value (ctf_dict_t *fp, ctf_id_t type, const char *name, uint64_t *valp)
+{
+ int ret;
+ int64_t retval;
+
+ ret = ctf_enum_value (fp, type, name, &retval);
+ *valp = (uint64_t) retval;
+ return ret;
+}
+
+/* Determine whether an enum's values are signed. */
+int
+ctf_enum_unsigned (ctf_dict_t *fp, ctf_id_t type)
+{
+ int kind;
+ const ctf_type_t *tp; /* The suffixed kind, if prefixed */
+
+ if ((kind = ctf_type_kind (fp, type)) < 0)
+ return -1; /* errno is set for us. */
+
+ if (kind != CTF_K_ENUM && kind != CTF_K_ENUM64)
+ return (ctf_set_errno (fp, ECTF_NOTENUM));
+
+ if (ctf_lookup_by_id (&fp, type, &tp) == NULL)
+ return -1; /* errno is set for us. */
+
+ return !CTF_INFO_KFLAG (tp->ctt_info);
+}
+
/* Return nonzero if this struct or union uses bitfield encoding. */
int
ctf_struct_bitfield (ctf_dict_t * fp, ctf_id_t type)
ctf_enum_name;
ctf_enum_value;
-
+ ctf_enum_unsigned_value;
+ ctf_enum_unsigned;
ctf_lookup_enumerator;
ctf_lookup_enumerator_next;
ctf_arc_lookup_enumerator_next;
ctf_add_const;
ctf_add_enum;
ctf_add_enum_encoded;
+ ctf_add_enum64;
+ ctf_add_enum64_encoded;
ctf_add_float;
ctf_add_forward;
ctf_add_function;