From: Nick Alcock Date: Thu, 24 Apr 2025 14:43:57 +0000 (+0100) Subject: libctf: types: struct/union member querying and iteration X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=64b65a0a34347c21d30fa44ada3dfcf646a6423f;p=thirdparty%2Fbinutils-gdb.git libctf: types: struct/union member querying and iteration This commit revises ctf_member_next, ctf_member_iter, ctf_member_count, and ctf_member_info for the new CTFv4 world. This also pulls in a bunch of infrastructure used by most of the type querying functions, and fundamental changes to the way DTD records are represented in libctf (ctf-create not yet adjusted). Other type querying functions affected by changes in struct representation are also changed. There are some API changes here: new bit-width fields in ctf_member_f, ctf_membinfo_t and ctf_member_next, and a fix to the type of the offset in ctf_member_f, ctf_membinfo_t and and ctf_member_count. (ctf_member_next got the offset type right already.) ctf_member_f also gets a new ctf_dict_t arg so that you can actually use the member type it passes in without having to package up and pass in the dict type yourself (a frequent need). This change is later echoed in most of the rest of the *_f typedefs. 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 int ctf_member_f (const char *name, ctf_id_t membtype, - unsigned long offset, 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); 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); -int ctf_member_count (ctf_dict_t *, ctf_id_t); +ssize_t ctf_member_count (ctf_dict_t *, ctf_id_t); The DTD changes are that where before the ctf_dtdef_t had a dtd_data which was the ctf_type_t type node for a type, and a separate dtd_vlen which was the vlen buffer which (in the final serialized representation) would directly follow that type, now it has one single buffer, dtd_buf, which consists of a stream of one or more ctf_type_t nodes, followed by a vlen, as it will appear in the final serialized form. This buffer has internal pointers into it: dtd_data is a pointer to the last ctf_type_t in the stream (the true type node, after all prefixes), and dtd_vlen is a pointer to the vlen (precisely one ctf_type_t after the dtd_data). This representation is nice because it means there is even less distinction between a dynamic type added by ctf_add_*() and a static one read directly out of a dict: you can traverse the entire type without caring where it came from, simplifying most of the type querying functions. (There are a few more things in there which will be useful mostly when adding new types: their uses will be seen later.) Two new nontrivial functions exist (one of which is annoyingly tangled up in the diff, sorry about that): ctf_find_prefix, which hunts down a given prefix (if it exists) among the possibly many that may exist on a type (so you can ask it to find the CTF_K_BIG prefix for a type if it exists, and it'll return you a pointer to its ctf_type_t record), and ctf_vlen, which you hand a type ID and its ctf_type_t *, and it gives you back a pointer to its vlen and tells you how long it is. (This is one of only two places left in ctf-types.c which cares whether a type is dynamic or not. The other has yet to be added). Almost every function in ctf-types.c will end up calling ctf_lookup_by_id and ctf_vlen in turn. ctf_next_t has changed significantly: the ctn_type member is split in two so that we can tell whether a given iterator works using types or indexes, and we gain the ability to iterate over enum64s, DTDs themselves, and datasecs (most of this will only be used in later commits). The old internal function ctf_struct_member, which handled the distinction between ctf_member_t and ctf_lmember_t, is gone. Instead we have new code that handles the different representation of bitfield versus non-bitfield structs and unions, and more code to handle the different representation of CTF_K_BIG structs and unions (their offsets are the distance from the last offset, rather than the distance from the start of the structure). --- 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. */ - if ((i = ctf_next_create ()) == NULL) - return ctf_set_errno (ofp, ENOMEM); - i->cu.ctn_fp = ofp; - i->ctn_tp = tp; - - 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) - { - ctf_next_destroy (i); - return (ctf_set_errno (ofp, ECTF_NOTSOU)); - } + 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); + if ((i = ctf_next_create ()) == NULL) + return ctf_set_errno (ofp, ENOMEM); + + i->ctn_tp = tp; + i->cu.ctn_fp = ofp; + i->u.ctn_dtd = ctf_dynamic_type (fp, type); - 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; - - ctf_get_ctt_size (fp, tp, &size, &increment); + uint32_t i = 0; + size_t n; - 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 (CTF_INFO_KFLAG (suffix->ctt_info)) + { + 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.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)) + && (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)) { - mip->ctm_offset += (unsigned long) CTF_LMEM_OFFSET (&memb); + 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; } }