diff --git a/include/ctf-api.h b/include/ctf-api.h index b48c491303f..03711f7a213 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -250,7 +250,9 @@ typedef struct ctf_snapshot_id _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.") \ - _CTF_ITEM (ECTF_NOTSERIALIZED, "CTF dict must be serialized first.") + _CTF_ITEM (ECTF_NOTSERIALIZED, "CTF dict must be serialized first.") \ + _CTF_ITEM (ECTF_NOTBITSOU, "Type is not a bitfield-capable struct or union.") \ + _CTF_ITEM (ECTF_DESCENDING, "Structure offsets may not descend.") \ #define ECTF_BASE 1000 /* Base value for libctf errnos. */ @@ -284,6 +286,7 @@ _CTF_ERRORS #define CTF_ADD_NONROOT 0 /* Type only visible in nested scope. */ #define CTF_ADD_ROOT 1 /* Type visible at top-level scope. */ +#define CTF_ADD_STRUCT_BITFIELDS 2 /* Struct/union field-level bitfields */ /* Flags for ctf_member_next. */ @@ -842,13 +845,15 @@ extern ctf_id_t ctf_add_restrict (ctf_dict_t *, uint32_t, ctf_id_t); /* 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, - etc) use the _sized variants. */ + etc) use the _sized variants. The FLAG parameter can take the value + CTF_ADD_STRUCT_BITFIELDS, indicating that bitfields can be directly added + to this struct via ctf_add_member_bitfield. */ -extern ctf_id_t ctf_add_struct (ctf_dict_t *, uint32_t, const char *); -extern ctf_id_t ctf_add_union (ctf_dict_t *, uint32_t, const char *); -extern ctf_id_t ctf_add_struct_sized (ctf_dict_t *, uint32_t, const char *, +extern ctf_id_t ctf_add_struct (ctf_dict_t *, uint32_t flag, const char *); +extern ctf_id_t ctf_add_union (ctf_dict_t *, uint32_t flag, const char *); +extern ctf_id_t ctf_add_struct_sized (ctf_dict_t *, uint32_t flag, const char *, size_t); -extern ctf_id_t ctf_add_union_sized (ctf_dict_t *, uint32_t, const char *, +extern ctf_id_t ctf_add_union_sized (ctf_dict_t *, uint32_t flag, const char *, size_t); /* Note that CTF cannot encode a given type. This usually returns an diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index 1a5665b15bc..a0ffb878033 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -931,48 +931,58 @@ ctf_add_function (ctf_dict_t *fp, uint32_t flag, if (ctc->ctc_flags & CTF_FUNC_VARARG) vdat[vlen - 1] = 0; /* Add trailing zero to indicate varargs. */ - return type; + return dtd->dtd_type; +} + +static ctf_id_t +ctf_add_sou_sized (ctf_dict_t *fp, uint32_t flag, const char *name, + size_t size, int kind) +{ + ctf_dtdef_t *dtd; + ctf_type_t *prefix; + ctf_id_t type = 0; + uint32_t idx; + size_t initial_vbytes = sizeof (ctf_member_t) * INITIAL_VLEN; + int root_flag = flag & (~CTF_ADD_STRUCT_BITFIELDS); + + if (fp->ctf_flags & LCTF_NO_STR) + return (ctf_set_errno (fp, ECTF_NOPARENT)); + + /* Promote root-visible forwards to structs/unions. */ + if (name != NULL) + type = ctf_lookup_by_rawname (fp, kind, name); + + if (type > 0) + idx = ctf_type_to_index (fp, type); + + /* Prohibit promotion if this type was ctf_open()ed. */ + if (type > 0 && idx < 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); + + 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, root_flag, name, kind, 1, 0, + initial_vbytes, &prefix)) == NULL) + return CTF_ERR; /* errno is set for us. */ + + prefix->ctt_info = CTF_TYPE_INFO (CTF_K_BIG, 0, 0); + dtd->dtd_data->ctt_info = CTF_TYPE_INFO (kind, !!(flag & CTF_ADD_STRUCT_BITFIELDS), 0); + prefix->ctt_size = CTF_SIZE_TO_LSIZE_HI (size); + dtd->dtd_data->ctt_size = CTF_SIZE_TO_LSIZE_LO (size); + + return dtd->dtd_type; } ctf_id_t ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name, size_t size) { - ctf_dtdef_t *dtd; - ctf_id_t type = 0; - size_t initial_vbytes = 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) - type = ctf_lookup_by_rawname (fp, CTF_K_STRUCT, 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_STRUCT, - 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->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0); - dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; - dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size); - dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size); - - return type; + return ctf_add_sou_sized (fp, flag, name, size, CTF_K_STRUCT); } ctf_id_t @@ -985,41 +995,7 @@ ctf_id_t ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name, size_t size) { - ctf_dtdef_t *dtd; - ctf_id_t type = 0; - size_t initial_vbytes = 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) - type = ctf_lookup_by_rawname (fp, CTF_K_UNION, 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_UNION, - 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->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0); - dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; - dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (size); - dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (size); - - return type; + return ctf_add_sou_sized (fp, flag, name, size, CTF_K_UNION); } ctf_id_t