diff --git a/include/ctf-api.h b/include/ctf-api.h index a771de234f9..2b58a4dd92d 100644 --- a/include/ctf-api.h +++ b/include/ctf-api.h @@ -144,10 +144,15 @@ typedef struct ctf_encoding uint32_t cte_bits; /* Size of storage in bits. */ } ctf_encoding_t; +/* "Not bitfield" here really means "not recorded as a bitfield in the + structure". ctf_type_encoding() may reveal that the base type or an + intervening slice has bitfield encoding nonetheless. */ + typedef struct ctf_membinfo { ctf_id_t ctm_type; /* Type of struct or union member. */ - unsigned long ctm_offset; /* Offset of member in bits. */ + size_t ctm_offset; /* Offset of member in bits. */ + int ctm_bit_width; /* Width of member in bits: -1: not bitfield */ } ctf_membinfo_t; typedef struct ctf_arinfo @@ -296,13 +301,13 @@ _CTF_ERRORS typedef int ctf_visit_f (const char *name, ctf_id_t type, unsigned long offset, int depth, void *arg); -typedef int ctf_member_f (const char *name, ctf_id_t membtype, - unsigned long offset, 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_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); @@ -679,7 +684,7 @@ extern int ctf_array_info (ctf_dict_t *, ctf_id_t, ctf_arinfo_t *); extern int ctf_member_info (ctf_dict_t *, ctf_id_t, const char *, ctf_membinfo_t *); -extern int ctf_member_count (ctf_dict_t *, ctf_id_t); +extern ssize_t ctf_member_count (ctf_dict_t *, ctf_id_t); /* Iterators. */ @@ -690,7 +695,7 @@ extern int ctf_member_count (ctf_dict_t *, ctf_id_t); extern int ctf_member_iter (ctf_dict_t *, ctf_id_t, ctf_member_f *, void *); extern ssize_t ctf_member_next (ctf_dict_t *, ctf_id_t, ctf_next_t **, const char **name, ctf_id_t *membtype, - int flags); + 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 *); diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 5bbfdf68d7d..95168ca7677 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -182,9 +182,15 @@ typedef struct ctf_dtdef ctf_id_t dtd_type; /* Type identifier for this definition. */ ctf_id_t dtd_final_type; /* Final (nonprovisional) id, if nonzero. */ ctf_list_t dtd_refs; /* Refs to this DTD's dtd_type: see below. */ - ctf_type_t dtd_data; /* Type node, including name. */ - size_t dtd_vlen_alloc; /* Total vlen space allocated (vbytes). */ - unsigned char *dtd_vlen; /* Variable-length data for this type. */ + ctf_type_t *dtd_buf; /* Type nodes plus variable-length data for + this type. */ + size_t dtd_buf_size; /* Length of dtd_buf in bytes. */ + ctf_type_t *dtd_data; /* True type node, including name (pointer into + dtd_buf). */ + unsigned char *dtd_vlen; /* Actual vlen data (pointer into dtd_buf). */ + size_t dtd_vlen_size; /* Total vlen space so far (vbytes). */ + uint64_t dtd_last_offset; /* Offset of the last struct field. */ + int dtd_flags; /* Some of the DTD_F_ flags. */ } ctf_dtdef_t; typedef struct ctf_dvdef @@ -549,11 +555,15 @@ typedef struct ctf_next_hkv struct ctf_next { void (*ctn_iter_fun) (void); - ctf_id_t ctn_type; + union + { + ctf_id_t ctn_type; + ctf_id_t ctn_idx; + } i; size_t ctn_size; ssize_t ctn_increment; const ctf_type_t *ctn_tp; - uint32_t ctn_n; + size_t ctn_n; /* Some iterators contain other iterators, in addition to their other state. We allow for inner and outer iterators, for two-layer nested loops @@ -563,13 +573,14 @@ struct ctf_next /* We can save space on this side of things by noting that a type is either dynamic or not, as a whole, and a given iterator can only iterate over one - kind of thing at once: so we can overlap the DTD and non-DTD members, and - the structure, variable and enum members, etc. */ + kind of thing at once: so we can overlap the DTD and non-DTD members, the + structure and enum members, etc. */ union { - unsigned char *ctn_vlen; + const ctf_dtdef_t *ctn_dtd; const ctf_enum_t *ctn_en; - const ctf_dvdef_t *ctn_dvd; + const ctf_enum64_t *ctn_en64; + const ctf_var_secinfo_t *ctn_datasec; ctf_next_hkv_t *ctn_sorted_hkv; void **ctn_hash_slot; } u; @@ -633,6 +644,8 @@ extern ctf_dynhash_t *ctf_name_table (ctf_dict_t *, int); extern ctf_id_t ctf_lookup_variable_here (ctf_dict_t *fp, const char *name); extern const ctf_type_t *ctf_lookup_by_id (ctf_dict_t **, ctf_id_t, const ctf_type_t **suffix); +extern const ctf_type_t *ctf_find_prefix (ctf_dict_t *, const ctf_type_t *, + int kind); extern ctf_id_t ctf_lookup_by_sym_or_name (ctf_dict_t *, unsigned long symidx, const char *symname, int try_parent, int is_function); diff --git a/libctf/ctf-lookup.c b/libctf/ctf-lookup.c index ac874fca200..dcc189f0bde 100644 --- a/libctf/ctf-lookup.c +++ b/libctf/ctf-lookup.c @@ -426,6 +426,22 @@ ctf_lookup_by_id (ctf_dict_t **fpp, ctf_id_t type, const ctf_type_t **suffix) } } +/* Find a given prefix in some type, if any. */ +const ctf_type_t * +ctf_find_prefix (ctf_dict_t *fp, const ctf_type_t *tp, int kind) +{ + uint32_t kind_ = kind; + + while (LCTF_IS_PREFIXED_INFO (tp->ctt_info) + && CTF_INFO_KIND (tp->ctt_info) != kind_) + tp++; + + if (LCTF_INFO_UNPREFIXED_KIND (fp, tp->ctt_info) != kind_) + return NULL; + + return tp; +} + typedef struct ctf_lookup_idx_key { ctf_dict_t *clik_fp; diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index 6a3dff3e4ca..6b8ff8659d8 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -134,34 +134,28 @@ ctf_index_to_type (const ctf_dict_t *fp, uint32_t idx) return fp->ctf_provtypemax + (fp->ctf_typemax - idx); } -/* Expand a structure element into the passed-in ctf_lmember_t. */ +/* Figure out the vlen and optionally vlen length for some type. */ -static int -ctf_struct_member (ctf_dict_t *fp, ctf_lmember_t *dst, const ctf_type_t *tp, - unsigned char *vlen, size_t vbytes, size_t n) +static unsigned char * +ctf_vlen (ctf_dict_t *fp, ctf_id_t type, const ctf_type_t *tp, size_t *vlen_len) { - if (!ctf_assert (fp, n < LCTF_INFO_VLEN (fp, tp->ctt_info))) - return -1; /* errno is set for us. */ + ctf_dtdef_t *dtd; - /* Already large. */ - if (tp->ctt_size == CTF_LSIZE_SENT) + if ((dtd = ctf_dynamic_type (fp, type)) != NULL) { - ctf_lmember_t *lmp = (ctf_lmember_t *) vlen; - - if (!ctf_assert (fp, (n + 1) * sizeof (ctf_lmember_t) <= vbytes)) - return -1; /* errno is set for us. */ - - memcpy (dst, &lmp[n], sizeof (ctf_lmember_t)); + if (vlen_len) + *vlen_len = LCTF_VLEN (fp, dtd->dtd_buf); + return dtd->dtd_vlen; } else { - ctf_member_t *mp = (ctf_member_t *) vlen; - dst->ctlm_name = mp[n].ctm_name; - dst->ctlm_type = mp[n].ctm_type; - dst->ctlm_offsetlo = mp[n].ctm_offset; - dst->ctlm_offsethi = 0; + ssize_t size, increment; + + ctf_get_ctt_size (fp, tp, &size, &increment); + if (vlen_len) + *vlen_len = LCTF_VLEN (fp, tp); + return (unsigned char *) tp + increment; } - return 0; } /* Iterate over the members of a STRUCT or UNION. We pass the name, member @@ -172,13 +166,15 @@ ctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) { ctf_next_t *i = NULL; ssize_t offset; + int bit_width; const char *name; ctf_id_t membtype; - while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, 0)) >= 0) + while ((offset = ctf_member_next (fp, type, &i, &name, &membtype, + &bit_width, 0)) >= 0) { int rc; - if ((rc = func (name, membtype, offset, arg)) != 0) + if ((rc = func (fp, name, membtype, offset, bit_width, arg)) != 0) { ctf_next_destroy (i); return rc; @@ -196,13 +192,16 @@ ctf_member_iter (ctf_dict_t *fp, ctf_id_t type, ctf_member_f *func, void *arg) ssize_t ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, - const char **name, ctf_id_t *membtype, int flags) + const char **name, ctf_id_t *membtype, + int *bit_width, int flags) { ctf_dict_t *ofp = fp; uint32_t kind; ssize_t offset; - uint32_t max_vlen; + size_t nmemb; + unsigned char *vlen; ctf_next_t *i = *it; + const ctf_type_t *prefix, *tp; if (fp->ctf_flags & LCTF_NO_STR) return (ctf_set_errno (fp, ECTF_NOPARENT)); @@ -210,42 +209,25 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, if (!i) { const ctf_type_t *tp; - ctf_dtdef_t *dtd; - ssize_t size; - ssize_t increment; if ((type = ctf_type_resolve (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. */ + kind = LCTF_KIND (fp, tp); + + if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) + return (ctf_set_errno (ofp, ECTF_NOTSOU)); + if ((i = ctf_next_create ()) == NULL) return ctf_set_errno (ofp, ENOMEM); - i->cu.ctn_fp = ofp; + i->ctn_tp = tp; + i->cu.ctn_fp = ofp; + i->u.ctn_dtd = ctf_dynamic_type (fp, type); - ctf_get_ctt_size (fp, tp, &size, &increment); - kind = LCTF_INFO_KIND (fp, tp->ctt_info); - - if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) - { - ctf_next_destroy (i); - return (ctf_set_errno (ofp, ECTF_NOTSOU)); - } - - if ((dtd = ctf_dynamic_type (fp, type)) != NULL) - { - i->u.ctn_vlen = dtd->dtd_vlen; - i->ctn_size = dtd->dtd_vlen_alloc; - } - else - { - unsigned long vlen = LCTF_INFO_VLEN (fp, tp->ctt_info); - - i->u.ctn_vlen = (unsigned char *) tp + increment; - i->ctn_size = LCTF_VBYTES (fp, kind, size, vlen);; - } i->ctn_iter_fun = (void (*) (void)) ctf_member_next; i->ctn_n = 0; *it = i; @@ -261,7 +243,20 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, if ((fp = ctf_get_dict (ofp, type)) == NULL) return (ctf_set_errno (ofp, ECTF_NOPARENT)); - max_vlen = LCTF_INFO_VLEN (fp, i->ctn_tp->ctt_info); + vlen = ctf_vlen (fp, type, i->ctn_tp, &nmemb); + + /* Reset the tp on every iteration if this is a dynamic type: adding members + can move it, and hunt down any CTF_K_BIG prefix. */ + + if (i->u.ctn_dtd) + i->ctn_tp = i->u.ctn_dtd->dtd_buf; + + if ((prefix = ctf_find_prefix (fp, i->ctn_tp, CTF_K_BIG)) == NULL) + prefix = i->ctn_tp; + tp = prefix; + + while (LCTF_IS_PREFIXED_KIND (LCTF_INFO_UNPREFIXED_KIND (fp, tp->ctt_info))) + tp++; /* When we hit an unnamed struct/union member, we set ctn_type to indicate that we are inside one, then return the unnamed member: on the next call, @@ -269,46 +264,69 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, the sub-struct until it later turns out that that iteration has ended. */ retry: - if (!i->ctn_type) + if (!i->i.ctn_type) { - ctf_lmember_t memb; + ctf_member_t *memb = (ctf_member_t *) vlen; const char *membname; - if (i->ctn_n == max_vlen) + if (i->ctn_n >= nmemb) goto end_iter; - if (ctf_struct_member (fp, &memb, i->ctn_tp, i->u.ctn_vlen, i->ctn_size, - i->ctn_n) < 0) - return (ctf_set_errno (ofp, ctf_errno (fp))); + membname = ctf_strptr (fp, memb[i->ctn_n].ctm_name); - membname = ctf_strptr (fp, memb.ctlm_name); + /* Skip nameless padding types. */ + if (membname[0] == 0 && memb[i->ctn_n].ctm_type == 0) + { + i->ctn_n++; + goto retry; + } if (name) *name = membname; if (membtype) - *membtype = memb.ctlm_type; - offset = (unsigned long) CTF_LMEM_OFFSET (&memb); + *membtype = memb[i->ctn_n].ctm_type; + if (bit_width) + { + if (CTF_INFO_KFLAG (tp->ctt_info)) + *bit_width = CTF_MEMBER_BIT_SIZE (memb[i->ctn_n].ctm_offset); + else + *bit_width = 0; + } + + if (CTF_INFO_KFLAG (tp->ctt_info)) + offset = CTF_MEMBER_BIT_OFFSET (memb[i->ctn_n].ctm_offset); + else + offset = memb[i->ctn_n].ctm_offset; + + /* CTF_K_BIG offsets are gap sizes: convert to offset-from-start. + Keep track of the offset-so-far in ctn_size. */ + + if (prefix != tp) + { + i->ctn_size += offset; + offset = i->ctn_size; + } if (membname[0] == 0 - && (ctf_type_kind (fp, memb.ctlm_type) == CTF_K_STRUCT - || ctf_type_kind (fp, memb.ctlm_type) == CTF_K_UNION)) - i->ctn_type = memb.ctlm_type; + && (ctf_type_kind (fp, memb[i->ctn_n].ctm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, memb[i->ctn_n].ctm_type) == CTF_K_UNION)) + i->i.ctn_type = memb[i->ctn_n].ctm_type; i->ctn_n++; /* The callers might want automatic recursive sub-struct traversal. */ if (!(flags & CTF_MN_RECURSE)) - i->ctn_type = 0; + i->i.ctn_type = 0; /* Sub-struct traversal starting? Take note of the offset of this member, for later boosting of sub-struct members' offsets. */ - if (i->ctn_type) + if (i->i.ctn_type) i->ctn_increment = offset; } /* Traversing a sub-struct? Just return it, with the offset adjusted. */ else { - ssize_t ret = ctf_member_next (fp, i->ctn_type, &i->ctn_next, name, - membtype, flags); + ssize_t ret = ctf_member_next (fp, i->i.ctn_type, &i->ctn_next, name, + membtype, bit_width, flags); if (ret >= 0) return ret + i->ctn_increment; @@ -317,7 +335,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, { ctf_next_destroy (i); *it = NULL; - i->ctn_type = 0; + i->i.ctn_type = 0; ctf_set_errno (ofp, ctf_errno (fp)); return ret; } @@ -325,7 +343,7 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, if (!ctf_assert (fp, (i->ctn_next == NULL))) return (ctf_set_errno (ofp, ctf_errno (fp))); - i->ctn_type = 0; + i->i.ctn_type = 0; /* This sub-struct has ended: on to the next real member. */ goto retry; } @@ -1113,35 +1131,20 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type) case CTF_K_UNION: { size_t align = 0; - ctf_dtdef_t *dtd; unsigned char *vlen; - uint32_t i = 0, n = LCTF_INFO_VLEN (fp, tp->ctt_info); - ssize_t size, increment, vbytes; + uint32_t i = 0; + size_t n; - ctf_get_ctt_size (fp, tp, &size, &increment); - - if ((dtd = ctf_dynamic_type (fp, type)) != NULL) - { - vlen = dtd->dtd_vlen; - vbytes = dtd->dtd_vlen_alloc; - } - else - { - vlen = (unsigned char *) tp + increment; - vbytes = LCTF_VBYTES (fp, kind, size, n); - } + vlen = ctf_vlen (fp, type, tp, &n); if (kind == CTF_K_STRUCT) n = MIN (n, 1); /* Only use first member for structs. */ for (; n != 0; n--, i++) { - ctf_lmember_t memb; + ctf_member_t *memb = (ctf_member_t *) vlen; - if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0) - return -1; /* errno is set for us. */ - - ssize_t am = ctf_type_align (ofp, memb.ctlm_type); + ssize_t am = ctf_type_align (ofp, memb[i].ctm_type); align = MAX (align, (size_t) am); } return align; @@ -1497,7 +1500,7 @@ ctf_type_compat (ctf_dict_t *lfp, ctf_id_t ltype, /* Return the number of members in a STRUCT or UNION, or the number of enumerators in an ENUM. The count does not include unnamed sub-members. */ -int +ssize_t ctf_member_count (ctf_dict_t *fp, ctf_id_t type) { ctf_dict_t *ofp = fp; @@ -1507,15 +1510,15 @@ ctf_member_count (ctf_dict_t *fp, ctf_id_t type) if ((type = ctf_type_resolve (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. */ - kind = LCTF_INFO_KIND (fp, tp->ctt_info); + kind = LCTF_KIND (fp, tp); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION && kind != CTF_K_ENUM) return (ctf_set_errno (ofp, ECTF_NOTSUE)); - return LCTF_INFO_VLEN (fp, tp->ctt_info); + return LCTF_VLEN (fp, tp); } /* Return the type and offset for a given member of a STRUCT or UNION. */ @@ -1525,11 +1528,12 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, ctf_membinfo_t *mip) { ctf_dict_t *ofp = fp; - const ctf_type_t *tp; - ctf_dtdef_t *dtd; + const ctf_type_t *tp, *suffix; + int big = 0; + size_t total_offset = 0; unsigned char *vlen; - ssize_t size, increment, vbytes; - uint32_t kind, n, i = 0; + uint32_t kind, i = 0; + size_t n; if (fp->ctf_flags & LCTF_NO_STR) return (ctf_set_errno (fp, ECTF_NOPARENT)); @@ -1537,50 +1541,61 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, if ((type = ctf_type_resolve (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, &suffix)) == NULL) return -1; /* errno is set for us. */ - ctf_get_ctt_size (fp, tp, &size, &increment); - kind = LCTF_INFO_KIND (fp, tp->ctt_info); + kind = LCTF_KIND (fp, tp); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno (ofp, ECTF_NOTSOU)); - n = LCTF_INFO_VLEN (fp, tp->ctt_info); - if ((dtd = ctf_dynamic_type (fp, type)) != NULL) - { - vlen = dtd->dtd_vlen; - vbytes = dtd->dtd_vlen_alloc; - } - else - { - vlen = (unsigned char *) tp + increment; - vbytes = LCTF_VBYTES (fp, kind, size, n); - } + vlen = ctf_vlen (fp, type, tp, &n); + + big = (ctf_find_prefix (fp, tp, CTF_K_BIG) != NULL); for (; n != 0; n--, i++) { - ctf_lmember_t memb; + ctf_member_t *memb = (ctf_member_t *) vlen; const char *membname; + size_t offset; + int bit_width = 0; - if (ctf_struct_member (fp, &memb, tp, vlen, vbytes, i) < 0) - return (ctf_set_errno (ofp, ctf_errno (fp))); + membname = ctf_strptr (fp, memb->ctm_name); - membname = ctf_strptr (fp, memb.ctlm_name); - - if (membname[0] == 0 - && (ctf_type_kind (fp, memb.ctlm_type) == CTF_K_STRUCT - || ctf_type_kind (fp, memb.ctlm_type) == CTF_K_UNION) - && (ctf_member_info (fp, memb.ctlm_type, name, mip) == 0)) + if (CTF_INFO_KFLAG (suffix->ctt_info)) { - mip->ctm_offset += (unsigned long) CTF_LMEM_OFFSET (&memb); + offset = CTF_MEMBER_BIT_OFFSET (memb->ctm_offset); + bit_width = CTF_MEMBER_BIT_SIZE (memb->ctm_offset); + } + else + offset = memb->ctm_offset; + + total_offset += offset; + + /* Unnamed struct/union member. */ + if (membname[0] == 0 + && (ctf_type_kind (fp, memb->ctm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, memb->ctm_type) == CTF_K_UNION) + && (ctf_member_info (fp, memb->ctm_type, name, mip) == 0)) + { + if (!big) + mip->ctm_offset += total_offset; + else + mip->ctm_offset += offset; + return 0; } + /* Ordinary member. */ if (strcmp (membname, name) == 0) { - mip->ctm_type = memb.ctlm_type; - mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (&memb); + mip->ctm_type = memb->ctm_type; + if (big) + mip->ctm_offset = total_offset + memb->ctm_offset; + else + mip->ctm_offset = memb->ctm_offset; + mip->ctm_bit_width = bit_width; + return 0; } }