diff options
-rw-r--r-- | libctf/ChangeLog | 40 | ||||
-rw-r--r-- | libctf/ctf-create.c | 260 | ||||
-rw-r--r-- | libctf/ctf-impl.h | 14 | ||||
-rw-r--r-- | libctf/ctf-serialize.c | 117 | ||||
-rw-r--r-- | libctf/ctf-types.c | 298 | ||||
-rw-r--r-- | libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c | 1 | ||||
-rw-r--r-- | libctf/testsuite/libctf-regression/type-add-unnamed-struct.c | 2 | ||||
-rw-r--r-- | libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk | 1 |
8 files changed, 323 insertions, 410 deletions
diff --git a/libctf/ChangeLog b/libctf/ChangeLog index fa333d5..7874a77 100644 --- a/libctf/ChangeLog +++ b/libctf/ChangeLog @@ -1,5 +1,45 @@ 2021-03-18 Nick Alcock <nick.alcock@oracle.com> + * ctf-impl.h (ctf_dtdef_t) <dtu_members>: Remove. + <dtd_u>: Likewise. + (ctf_dmdef_t): Remove. + (struct ctf_next) <u.ctn_dmd>: Remove. + * ctf-create.c (INITIAL_VLEN): New, more-or-less arbitrary initial + vlen size. + (ctf_add_enum): Use it. + (ctf_dtd_delete): Do not free the (removed) dmd; remove string + refs from the vlen on struct deletion. + (ctf_add_struct_sized): Populate the vlen: do it by hand if + promoting forwards. Always populate the full-size + lsizehi/lsizelo members. + (ctf_add_union_sized): Likewise. + (ctf_add_member_offset): Set up the vlen rather than the dmd. + Expand it as needed, repointing string refs via + ctf_str_move_pending. Add the member names as pending strings. + Always populate the full-size lsizehi/lsizelo members. + (membadd): Remove, folding back into... + (ctf_add_type_internal): ... here, adding via an ordinary + ctf_add_struct_sized and _next iteration rather than doing + everything by hand. + * ctf-serialize.c (ctf_copy_smembers): Remove this... + (ctf_copy_lmembers): ... and this... + (ctf_emit_type_sect): ... folding into here. Figure out if a + ctf_stype_t is needed here, not in ctf_add_*_sized. + (ctf_type_sect_size): Figure out the ctf_stype_t stuff the same + way here. + * ctf-types.c (ctf_member_next): Remove the dmd path and always + use the vlen. Force large-structure usage for dynamic types. + (ctf_type_align): Likewise. + (ctf_member_info): Likewise. + (ctf_type_rvisit): Likewise. + * testsuite/libctf-regression/type-add-unnamed-struct-ctf.c: Add a + self-referential type to this test. + * testsuite/libctf-regression/type-add-unnamed-struct.c: Adjusted + accordingly. + * testsuite/libctf-regression/type-add-unnamed-struct.lk: Likewise. + +2021-03-18 Nick Alcock <nick.alcock@oracle.com> + * ctf-impl.h (ctf_dtdef_t) <dtd_vlen_alloc>: New. (ctf_str_move_pending): Declare. * ctf-string.c (ctf_str_add_ref_internal): Fix error return. diff --git a/libctf/ctf-create.c b/libctf/ctf-create.c index 3218e3e..e87b91e 100644 --- a/libctf/ctf-create.c +++ b/libctf/ctf-create.c @@ -30,6 +30,12 @@ #define roundup(x, y) ((((x) + ((y) - 1)) / (y)) * (y)) #endif +/* The initial size of a dynamic type's vlen in members. Arbitrary: the bigger + this is, the less allocation needs to be done for small structure + initialization, and the more memory is wasted for small structures during CTF + construction. No effect on generated CTF or ctf_open()ed CTF. */ +#define INITIAL_VLEN 16 + /* Make sure the ptrtab has enough space for at least one more type. We start with 4KiB of ptrtab, enough for a thousand types, then grow it 25% @@ -244,7 +250,6 @@ ctf_dtd_insert (ctf_dict_t *fp, ctf_dtdef_t *dtd, int flag, int kind) void ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd) { - ctf_dmdef_t *dmd, *nmd; int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); size_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); int name_kind = kind; @@ -256,14 +261,14 @@ ctf_dtd_delete (ctf_dict_t *fp, ctf_dtdef_t *dtd) { case CTF_K_STRUCT: case CTF_K_UNION: - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = nmd) - { - if (dmd->dmd_name != NULL) - free (dmd->dmd_name); - nmd = ctf_list_next (dmd); - free (dmd); - } + { + ctf_lmember_t *memb = (ctf_lmember_t *) dtd->dtd_vlen; + size_t i; + + for (i = 0; i < vlen; i++) + ctf_str_remove_ref (fp, ctf_strraw (fp, memb[i].ctlm_name), + &memb[i].ctlm_name); + } break; case CTF_K_ENUM: { @@ -797,6 +802,7 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name, { ctf_dtdef_t *dtd; ctf_id_t type = 0; + size_t initial_vlen = sizeof (ctf_lmember_t) * INITIAL_VLEN; /* Promote root-visible forwards to structs. */ if (name != NULL) @@ -805,19 +811,21 @@ ctf_add_struct_sized (ctf_dict_t *fp, uint32_t flag, const char *name, 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, - 0, &dtd)) == CTF_ERR) + initial_vlen, &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us. */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_STRUCT, flag, 0); - - if (size > CTF_MAX_SIZE) + /* Forwards won't have any vlen yet. */ + if (dtd->dtd_vlen_alloc == 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); + if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL) + return (ctf_set_errno (fp, ENOMEM)); + dtd->dtd_vlen_alloc = initial_vlen; } - else - dtd->dtd_data.ctt_size = (uint32_t) size; + + 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; } @@ -834,6 +842,7 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name, { ctf_dtdef_t *dtd; ctf_id_t type = 0; + size_t initial_vlen = sizeof (ctf_lmember_t) * INITIAL_VLEN; /* Promote root-visible forwards to unions. */ if (name != NULL) @@ -842,19 +851,21 @@ ctf_add_union_sized (ctf_dict_t *fp, uint32_t flag, const char *name, 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, - 0, &dtd)) == CTF_ERR) + initial_vlen, &dtd)) == CTF_ERR) return CTF_ERR; /* errno is set for us */ - dtd->dtd_data.ctt_info = CTF_TYPE_INFO (CTF_K_UNION, flag, 0); - - if (size > CTF_MAX_SIZE) + /* Forwards won't have any vlen yet. */ + if (dtd->dtd_vlen_alloc == 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); + if ((dtd->dtd_vlen = calloc (1, initial_vlen)) == NULL) + return (ctf_set_errno (fp, ENOMEM)); + dtd->dtd_vlen_alloc = initial_vlen; } - else - dtd->dtd_data.ctt_size = (uint32_t) size; + + 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; } @@ -870,7 +881,7 @@ ctf_add_enum (ctf_dict_t *fp, uint32_t flag, const char *name) { ctf_dtdef_t *dtd; ctf_id_t type = 0; - size_t initial_vlen = sizeof (ctf_enum_t) * 16; + size_t initial_vlen = sizeof (ctf_enum_t) * INITIAL_VLEN; /* Promote root-visible forwards to enums. */ if (name != NULL) @@ -1066,12 +1077,13 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, ctf_id_t type, unsigned long bit_offset) { ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid); - ctf_dmdef_t *dmd; ssize_t msize, malign, ssize; uint32_t kind, vlen, root; - char *s = NULL; + size_t i; int is_incomplete = 0; + unsigned char *old_vlen; + ctf_lmember_t *memb; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno (fp, ECTF_RDONLY)); @@ -1092,14 +1104,26 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, if (vlen == CTF_MAX_VLEN) return (ctf_set_errno (fp, ECTF_DTFULL)); + old_vlen = dtd->dtd_vlen; + if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0) + return -1; /* errno is set for us. */ + memb = (ctf_lmember_t *) dtd->dtd_vlen; + + if (dtd->dtd_vlen != old_vlen) + { + ptrdiff_t move = (signed char *) dtd->dtd_vlen - (signed char *) old_vlen; + + /* Remove pending refs in the old vlen region and reapply them. */ + + for (i = 0; i < vlen; i++) + ctf_str_move_pending (fp, &memb[i].ctlm_name, move); + } + if (name != NULL) { - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = ctf_list_next (dmd)) - { - if (dmd->dmd_name != NULL && strcmp (dmd->dmd_name, name) == 0) - return (ctf_set_errno (fp, ECTF_DUPLICATE)); - } + for (i = 0; i < vlen; i++) + if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0) + return (ctf_set_errno (fp, ECTF_DUPLICATE)); } if ((msize = ctf_type_size (fp, type)) < 0 || @@ -1124,18 +1148,10 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, return -1; /* errno is set for us. */ } - if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL) - return (ctf_set_errno (fp, EAGAIN)); - - if (name != NULL && (s = strdup (name)) == NULL) - { - free (dmd); - return (ctf_set_errno (fp, EAGAIN)); - } - - dmd->dmd_name = s; - dmd->dmd_type = type; - dmd->dmd_value = -1; + memb[vlen].ctlm_name = ctf_str_add_pending (fp, name, &memb[vlen].ctlm_name); + memb[vlen].ctlm_type = type; + if (memb[vlen].ctlm_name == 0 && name != NULL && name[0] != '\0') + return -1; /* errno is set for us. */ if (kind == CTF_K_STRUCT && vlen != 0) { @@ -1143,9 +1159,8 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, { /* Natural alignment. */ - ctf_dmdef_t *lmd = ctf_list_prev (&dtd->dtd_u.dtu_members); - ctf_id_t ltype = ctf_type_resolve (fp, lmd->dmd_type); - size_t off = lmd->dmd_offset; + ctf_id_t ltype = ctf_type_resolve (fp, memb[vlen - 1].ctlm_type); + size_t off = CTF_LMEM_OFFSET(&memb[vlen - 1]); ctf_encoding_t linfo; ssize_t lsize; @@ -1155,10 +1170,7 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, cannot insert right after such a member without explicit offset specification, because its alignment and size is not known. */ if (ltype == CTF_ERR) - { - free (dmd); - return -1; /* errno is set for us. */ - } + return -1; /* errno is set for us. */ if (is_incomplete) { @@ -1176,14 +1188,15 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, off += lsize * CHAR_BIT; else if (lsize == -1 && ctf_errno (fp) == ECTF_INCOMPLETE) { + const char *lname = ctf_strraw (fp, memb[vlen - 1].ctlm_name); + ctf_err_warn (fp, 1, ECTF_INCOMPLETE, _("ctf_add_member_offset: cannot add member %s of " "type %lx to struct %lx without specifying " "explicit offset after member %s of type %lx, " "which is an incomplete type\n"), name ? name : _("(unnamed member)"), type, souid, - lmd->dmd_name ? lmd->dmd_name - : _("(unnamed member)"), ltype); + lname ? lname : _("(unnamed member)"), ltype); return -1; /* errno is set for us. */ } @@ -1198,36 +1211,32 @@ ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, off = roundup (off, CHAR_BIT) / CHAR_BIT; off = roundup (off, MAX (malign, 1)); - dmd->dmd_offset = off * CHAR_BIT; + memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (off * CHAR_BIT); + memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (off * CHAR_BIT); ssize = off + msize; } else { /* Specified offset in bits. */ - dmd->dmd_offset = bit_offset; + memb[vlen].ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (bit_offset); + memb[vlen].ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (bit_offset); ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL); ssize = MAX (ssize, ((signed) bit_offset / CHAR_BIT) + msize); } } else { - dmd->dmd_offset = 0; + memb[vlen].ctlm_offsethi = 0; + memb[vlen].ctlm_offsetlo = 0; ssize = ctf_get_ctt_size (fp, &dtd->dtd_data, NULL, NULL); ssize = MAX (ssize, msize); } - if ((size_t) ssize > CTF_MAX_SIZE) - { - dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; - dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize); - dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize); - } - else - dtd->dtd_data.ctt_size = (uint32_t) ssize; - + dtd->dtd_data.ctt_size = CTF_LSIZE_SENT; + dtd->dtd_data.ctt_lsizehi = CTF_SIZE_TO_LSIZE_HI (ssize); + dtd->dtd_data.ctt_lsizelo = CTF_SIZE_TO_LSIZE_LO (ssize); dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1); - ctf_list_append (&dtd->dtd_u.dtu_members, dmd); fp->ctf_flags |= LCTF_DIRTY; return 0; @@ -1411,41 +1420,6 @@ membcmp (const char *name, ctf_id_t type _libctf_unused_, unsigned long offset, return 0; } -static int -membadd (const char *name, ctf_id_t type, unsigned long offset, void *arg) -{ - ctf_bundle_t *ctb = arg; - ctf_dmdef_t *dmd; - char *s = NULL; - - if ((dmd = malloc (sizeof (ctf_dmdef_t))) == NULL) - return (ctf_set_errno (ctb->ctb_dict, EAGAIN)); - - /* Unnamed members in non-dynamic dicts have a name of "", while dynamic dicts - use NULL. Adapt. */ - - if (name[0] == 0) - name = NULL; - - if (name != NULL && (s = strdup (name)) == NULL) - { - free (dmd); - return (ctf_set_errno (ctb->ctb_dict, EAGAIN)); - } - - /* For now, dmd_type is copied as the src_fp's type; it is reset to an - equivalent dst_fp type by a final loop in ctf_add_type(), below. */ - dmd->dmd_name = s; - dmd->dmd_type = type; - dmd->dmd_offset = offset; - dmd->dmd_value = -1; - - ctf_list_append (&ctb->ctb_dtd->dtd_u.dtu_members, dmd); - - ctb->ctb_dict->ctf_flags |= LCTF_DIRTY; - return 0; -} - /* Record the correspondence between a source and ctf_add_type()-added destination type: both types are translated into parent type IDs if need be, so they relate to the actual dictionary they are in. Outside controlled @@ -1828,11 +1802,10 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type case CTF_K_STRUCT: case CTF_K_UNION: { - ctf_dmdef_t *dmd; - int errs = 0; - size_t size; - ssize_t ssize; - ctf_dtdef_t *dtd; + ctf_next_t *i = NULL; + ssize_t offset; + const char *membname; + ctf_id_t src_membtype; /* Technically to match a struct or union we need to check both ways (src members vs. dst, dst members vs. src) but we make @@ -1867,67 +1840,44 @@ ctf_add_type_internal (ctf_dict_t *dst_fp, ctf_dict_t *src_fp, ctf_id_t src_type break; } - /* Unlike the other cases, copying structs and unions is done - manually so as to avoid repeated lookups in ctf_add_member - and to ensure the exact same member offsets as in src_type. */ - - dst_type = ctf_add_generic (dst_fp, flag, name, kind, 0, &dtd); + dst_type = ctf_add_struct_sized (dst_fp, flag, name, + ctf_type_size (src_fp, src_type)); if (dst_type == CTF_ERR) return CTF_ERR; /* errno is set for us. */ - dst.ctb_type = dst_type; - dst.ctb_dtd = dtd; - /* Pre-emptively add this struct to the type mapping so that structures that refer to themselves work. */ ctf_add_type_mapping (src_fp, src_type, dst_fp, dst_type); - if (ctf_member_iter (src_fp, src_type, membadd, &dst) != 0) - errs++; /* Increment errs and fail at bottom of case. */ - - if ((ssize = ctf_type_size (src_fp, src_type)) < 0) - return CTF_ERR; /* errno is set for us. */ - - size = (size_t) ssize; - if (size > CTF_MAX_SIZE) - { - 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); - } - else - dtd->dtd_data.ctt_size = (uint32_t) size; - - dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, flag, vlen); - - /* Make a final pass through the members changing each dmd_type (a - src_fp type) to an equivalent type in dst_fp. We pass through all - members, leaving any that fail set to CTF_ERR, unless they fail - because they are marking a member of type not representable in this - version of CTF, in which case we just want to silently omit them: - no consumer can do anything with them anyway. */ - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = ctf_list_next (dmd)) + while ((offset = ctf_member_next (src_fp, src_type, &i, &membname, + &src_membtype, 0)) >= 0) { ctf_dict_t *dst = dst_fp; - ctf_id_t memb_type; + ctf_id_t dst_membtype = ctf_type_mapping (src_fp, src_membtype, &dst); - memb_type = ctf_type_mapping (src_fp, dmd->dmd_type, &dst); - if (memb_type == 0) + if (dst_membtype == 0) { - if ((dmd->dmd_type = - ctf_add_type_internal (dst_fp, src_fp, dmd->dmd_type, - proc_tracking_fp)) == CTF_ERR) + dst_membtype = ctf_add_type_internal (dst_fp, src_fp, + src_membtype, + proc_tracking_fp); + if (dst_membtype == CTF_ERR) { if (ctf_errno (dst_fp) != ECTF_NONREPRESENTABLE) - errs++; + { + ctf_next_destroy (i); + break; + } } } - else - dmd->dmd_type = memb_type; - } - if (errs) + if (ctf_add_member_offset (dst_fp, dst_type, membname, + dst_membtype, offset) < 0) + { + ctf_next_destroy (i); + break; + } + } + if (ctf_errno (src_fp) != ECTF_NEXT_END) return CTF_ERR; /* errno is set for us. */ break; } diff --git a/libctf/ctf-impl.h b/libctf/ctf-impl.h index 9a82d95..87dd03b 100644 --- a/libctf/ctf-impl.h +++ b/libctf/ctf-impl.h @@ -179,15 +179,6 @@ typedef struct ctf_decl int cd_enomem; /* Nonzero if OOM during printing. */ } ctf_decl_t; -typedef struct ctf_dmdef -{ - ctf_list_t dmd_list; /* List forward/back pointers. */ - char *dmd_name; /* Name of this member. */ - ctf_id_t dmd_type; /* Type of this member (for sou). */ - unsigned long dmd_offset; /* Offset of this member in bits (for sou). */ - int dmd_value; /* Value of this member (for enum). */ -} ctf_dmdef_t; - typedef struct ctf_dtdef { ctf_list_t dtd_list; /* List forward/back pointers. */ @@ -195,10 +186,6 @@ typedef struct ctf_dtdef ctf_type_t dtd_data; /* Type node, including name. */ size_t dtd_vlen_alloc; /* Total vlen space allocated. */ unsigned char *dtd_vlen; /* Variable-length data for this type. */ - union - { - ctf_list_t dtu_members; /* struct, union, or enum */ - } dtd_u; } ctf_dtdef_t; typedef struct ctf_dvdef @@ -557,7 +544,6 @@ struct ctf_next { const ctf_member_t *ctn_mp; const ctf_lmember_t *ctn_lmp; - const ctf_dmdef_t *ctn_dmd; const ctf_enum_t *ctn_en; const ctf_dvdef_t *ctn_dvd; ctf_next_hkv_t *ctn_sorted_hkv; diff --git a/libctf/ctf-serialize.c b/libctf/ctf-serialize.c index 5d94f44..0811b7b 100644 --- a/libctf/ctf-serialize.c +++ b/libctf/ctf-serialize.c @@ -719,57 +719,6 @@ symerr: /* Type section. */ -static unsigned char * -ctf_copy_smembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) -{ - ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - ctf_member_t ctm; - - for (; dmd != NULL; dmd = ctf_list_next (dmd)) - { - ctf_member_t *copied; - - ctm.ctm_name = 0; - ctm.ctm_type = (uint32_t) dmd->dmd_type; - ctm.ctm_offset = (uint32_t) dmd->dmd_offset; - - memcpy (t, &ctm, sizeof (ctm)); - copied = (ctf_member_t *) t; - if (dmd->dmd_name) - ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctm_name); - - t += sizeof (ctm); - } - - return t; -} - -static unsigned char * -ctf_copy_lmembers (ctf_dict_t *fp, ctf_dtdef_t *dtd, unsigned char *t) -{ - ctf_dmdef_t *dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - ctf_lmember_t ctlm; - - for (; dmd != NULL; dmd = ctf_list_next (dmd)) - { - ctf_lmember_t *copied; - - ctlm.ctlm_name = 0; - ctlm.ctlm_type = (uint32_t) dmd->dmd_type; - ctlm.ctlm_offsethi = CTF_OFFSET_TO_LMEMHI (dmd->dmd_offset); - ctlm.ctlm_offsetlo = CTF_OFFSET_TO_LMEMLO (dmd->dmd_offset); - - memcpy (t, &ctlm, sizeof (ctlm)); - copied = (ctf_lmember_t *) t; - if (dmd->dmd_name) - ctf_str_add_ref (fp, dmd->dmd_name, &copied->ctlm_name); - - t += sizeof (ctlm); - } - - return t; -} - /* Iterate through the dynamic type definition list and compute the size of the CTF type section. */ @@ -784,8 +733,20 @@ ctf_type_sect_size (ctf_dict_t *fp) { uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); + size_t type_ctt_size = dtd->dtd_data.ctt_size; + + /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t + if possible. */ + + if (kind == CTF_K_STRUCT || kind == CTF_K_UNION) + { + size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data); + + if (lsize <= CTF_MAX_SIZE) + type_ctt_size = lsize; + } - if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) + if (type_ctt_size != CTF_LSIZE_SENT) type_size += sizeof (ctf_stype_t); else type_size += sizeof (ctf_type_t); @@ -807,7 +768,7 @@ ctf_type_sect_size (ctf_dict_t *fp) break; case CTF_K_STRUCT: case CTF_K_UNION: - if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) + if (type_ctt_size < CTF_LSTRUCT_THRESH) type_size += sizeof (ctf_member_t) * vlen; else type_size += sizeof (ctf_lmember_t) * vlen; @@ -836,13 +797,24 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr) { uint32_t kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); uint32_t vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); - + size_t type_ctt_size = dtd->dtd_data.ctt_size; size_t len; ctf_stype_t *copied; const char *name; size_t i; - if (dtd->dtd_data.ctt_size != CTF_LSIZE_SENT) + /* Shrink ctf_type_t-using types from a ctf_type_t to a ctf_stype_t + if possible. */ + + if (kind == CTF_K_STRUCT || kind == CTF_K_UNION) + { + size_t lsize = CTF_TYPE_LSIZE (&dtd->dtd_data); + + if (lsize <= CTF_MAX_SIZE) + type_ctt_size = lsize; + } + + if (type_ctt_size != CTF_LSIZE_SENT) len = sizeof (ctf_stype_t); else len = sizeof (ctf_type_t); @@ -855,6 +827,7 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr) ctf_str_add_ref (fp, name, &copied->ctt_name); ctf_str_add_ref (fp, name, &dtd->dtd_data.ctt_name); } + copied->ctt_size = type_ctt_size; t += len; switch (kind) @@ -880,12 +853,40 @@ ctf_emit_type_sect (ctf_dict_t *fp, unsigned char **tptr) t += sizeof (uint32_t) * (vlen + (vlen & 1)); break; + /* These need to be copied across element by element, depending on + their ctt_size. */ case CTF_K_STRUCT: case CTF_K_UNION: - if (dtd->dtd_data.ctt_size < CTF_LSTRUCT_THRESH) - t = ctf_copy_smembers (fp, dtd, t); + { + ctf_lmember_t *dtd_vlen = (ctf_lmember_t *) dtd->dtd_vlen; + ctf_lmember_t *t_lvlen = (ctf_lmember_t *) t; + ctf_member_t *t_vlen = (ctf_member_t *) t; + + for (i = 0; i < vlen; i++) + { + const char *name = ctf_strraw (fp, dtd_vlen[i].ctlm_name); + + ctf_str_add_ref (fp, name, &dtd_vlen[i].ctlm_name); + + if (type_ctt_size < CTF_LSTRUCT_THRESH) + { + t_vlen[i].ctm_name = dtd_vlen[i].ctlm_name; + t_vlen[i].ctm_type = dtd_vlen[i].ctlm_type; + t_vlen[i].ctm_offset = CTF_LMEM_OFFSET (&dtd_vlen[i]); + ctf_str_add_ref (fp, name, &t_vlen[i].ctm_name); + } + else + { + t_lvlen[i] = dtd_vlen[i]; + ctf_str_add_ref (fp, name, &t_lvlen[i].ctlm_name); + } + } + } + + if (type_ctt_size < CTF_LSTRUCT_THRESH) + t += sizeof (ctf_member_t) * vlen; else - t = ctf_copy_lmembers (fp, dtd, t); + t += sizeof (ctf_lmember_t) * vlen; break; case CTF_K_ENUM: diff --git a/libctf/ctf-types.c b/libctf/ctf-types.c index 49264eb..df7673e 100644 --- a/libctf/ctf-types.c +++ b/libctf/ctf-types.c @@ -101,24 +101,17 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, dtd = ctf_dynamic_type (fp, type); i->ctn_iter_fun = (void (*) (void)) ctf_member_next; - - /* We depend below on the RDWR state indicating whether the DTD-related - fields or the DMD-related fields have been initialized. */ - - assert ((dtd && (fp->ctf_flags & LCTF_RDWR)) - || (!dtd && (!(fp->ctf_flags & LCTF_RDWR)))); + i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); if (dtd == NULL) { - i->ctn_n = LCTF_INFO_VLEN (fp, tp->ctt_info); - if (i->ctn_size < CTF_LSTRUCT_THRESH) i->u.ctn_mp = (const ctf_member_t *) ((uintptr_t) tp + increment); else i->u.ctn_lmp = (const ctf_lmember_t *) ((uintptr_t) tp + increment); } else - i->u.ctn_dmd = ctf_list_next (&dtd->dtd_u.dtu_members); + i->u.ctn_lmp = (const ctf_lmember_t *) dtd->dtd_vlen; *it = i; } @@ -141,71 +134,46 @@ ctf_member_next (ctf_dict_t *fp, ctf_id_t type, ctf_next_t **it, retry: if (!i->ctn_type) { - if (!(fp->ctf_flags & LCTF_RDWR)) - { - if (i->ctn_n == 0) - goto end_iter; - - if (i->ctn_size < CTF_LSTRUCT_THRESH) - { - const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name); - - if (name) - *name = membname; - if (membtype) - *membtype = i->u.ctn_mp->ctm_type; - offset = i->u.ctn_mp->ctm_offset; - - if (membname[0] == 0 - && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT - || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION)) - i->ctn_type = i->u.ctn_mp->ctm_type; + if (i->ctn_n == 0) + goto end_iter; - i->u.ctn_mp++; - } - else - { - const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name); + /* Dynamic structures in read-write dicts always use lmembers. */ + if (i->ctn_size < CTF_LSTRUCT_THRESH + && !(fp->ctf_flags & LCTF_RDWR)) + { + const char *membname = ctf_strptr (fp, i->u.ctn_mp->ctm_name); - if (name) - *name = membname; - if (membtype) - *membtype = i->u.ctn_lmp->ctlm_type; - offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp); + if (name) + *name = membname; + if (membtype) + *membtype = i->u.ctn_mp->ctm_type; + offset = i->u.ctn_mp->ctm_offset; - if (membname[0] == 0 - && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT - || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION)) - i->ctn_type = i->u.ctn_lmp->ctlm_type; + if (membname[0] == 0 + && (ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, i->u.ctn_mp->ctm_type) == CTF_K_UNION)) + i->ctn_type = i->u.ctn_mp->ctm_type; - i->u.ctn_lmp++; - } - i->ctn_n--; + i->u.ctn_mp++; } else { - if (i->u.ctn_dmd == NULL) - goto end_iter; - /* The dmd contains a NULL for unnamed dynamic members. Don't inflict - this on our callers. */ + const char *membname = ctf_strptr (fp, i->u.ctn_lmp->ctlm_name); + if (name) - { - if (i->u.ctn_dmd->dmd_name) - *name = i->u.ctn_dmd->dmd_name; - else - *name = ""; - } + *name = membname; if (membtype) - *membtype = i->u.ctn_dmd->dmd_type; - offset = i->u.ctn_dmd->dmd_offset; + *membtype = i->u.ctn_lmp->ctlm_type; + offset = (unsigned long) CTF_LMEM_OFFSET (i->u.ctn_lmp); - if (i->u.ctn_dmd->dmd_name == NULL - && (ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_STRUCT - || ctf_type_kind (fp, i->u.ctn_dmd->dmd_type) == CTF_K_UNION)) - i->ctn_type = i->u.ctn_dmd->dmd_type; + if (membname[0] == 0 + && (ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, i->u.ctn_lmp->ctlm_type) == CTF_K_UNION)) + i->ctn_type = i->u.ctn_lmp->ctlm_type; - i->u.ctn_dmd = ctf_list_next (i->u.ctn_dmd); + i->u.ctn_lmp++; } + i->ctn_n--; /* The callers might want automatic recursive sub-struct traversal. */ if (!(flags & CTF_MN_RECURSE)) @@ -996,53 +964,44 @@ ctf_type_align (ctf_dict_t *fp, ctf_id_t type) case CTF_K_UNION: { size_t align = 0; + int dynamic = 0; ctf_dtdef_t *dtd; - if ((dtd = ctf_dynamic_type (ofp, type)) == NULL) - { - uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info); - ssize_t size, increment; - const void *vmp; + if ((dtd = ctf_dynamic_type (ofp, type)) != NULL) + dynamic = 1; - (void) ctf_get_ctt_size (fp, tp, &size, &increment); - vmp = (unsigned char *) tp + increment; + uint32_t n = LCTF_INFO_VLEN (fp, tp->ctt_info); + ssize_t size, increment; + const void *vmp; - if (kind == CTF_K_STRUCT) - n = MIN (n, 1); /* Only use first member for structs. */ + (void) ctf_get_ctt_size (fp, tp, &size, &increment); - if (size < CTF_LSTRUCT_THRESH) - { - const ctf_member_t *mp = vmp; - for (; n != 0; n--, mp++) - { - ssize_t am = ctf_type_align (ofp, mp->ctm_type); - align = MAX (align, (size_t) am); - } - } - else + if (!dynamic) + vmp = (unsigned char *) tp + increment; + else + vmp = dtd->dtd_vlen; + + if (kind == CTF_K_STRUCT) + n = MIN (n, 1); /* Only use first member for structs. */ + + if (size < CTF_LSTRUCT_THRESH && !dynamic) + { + const ctf_member_t *mp = vmp; + for (; n != 0; n--, mp++) { - const ctf_lmember_t *lmp = vmp; - for (; n != 0; n--, lmp++) - { - ssize_t am = ctf_type_align (ofp, lmp->ctlm_type); - align = MAX (align, (size_t) am); - } + ssize_t am = ctf_type_align (ofp, mp->ctm_type); + align = MAX (align, (size_t) am); } } else { - ctf_dmdef_t *dmd; - - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = ctf_list_next (dmd)) - { - ssize_t am = ctf_type_align (ofp, dmd->dmd_type); - align = MAX (align, (size_t) am); - if (kind == CTF_K_STRUCT) - break; - } + const ctf_lmember_t *lmp = vmp; + for (; n != 0; n--, lmp++) + { + ssize_t am = ctf_type_align (ofp, lmp->ctlm_type); + align = MAX (align, (size_t) am); + } } - return align; } @@ -1390,8 +1349,10 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, ctf_dict_t *ofp = fp; const ctf_type_t *tp; ctf_dtdef_t *dtd; + const void *vmp; ssize_t size, increment; uint32_t kind, n; + int dynamic = 0; if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) return -1; /* errno is set for us. */ @@ -1405,73 +1366,54 @@ ctf_member_info (ctf_dict_t *fp, ctf_id_t type, const char *name, if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno (ofp, ECTF_NOTSOU)); - if ((dtd = ctf_dynamic_type (fp, type)) == NULL) - { - if (size < CTF_LSTRUCT_THRESH) - { - const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + - increment); + if ((dtd = ctf_dynamic_type (ofp, type)) != NULL) + dynamic = 1; - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) - { - const char *membname = ctf_strptr (fp, mp->ctm_name); + if (!dynamic) + vmp = (unsigned char *) tp + increment; + else + vmp = dtd->dtd_vlen; - if (membname[0] == 0 - && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT - || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION) - && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0)) - return 0; + if (size < CTF_LSTRUCT_THRESH && !dynamic) + { + const ctf_member_t *mp = vmp; - if (strcmp (membname, name) == 0) - { - mip->ctm_type = mp->ctm_type; - mip->ctm_offset = mp->ctm_offset; - return 0; - } - } - } - else + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - increment); + const char *membname = ctf_strptr (fp, mp->ctm_name); - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) - { - const char *membname = ctf_strptr (fp, lmp->ctlm_name); - - if (membname[0] == 0 - && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT - || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION) - && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0)) - return 0; + if (membname[0] == 0 + && (ctf_type_kind (fp, mp->ctm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, mp->ctm_type) == CTF_K_UNION) + && (ctf_member_info (fp, mp->ctm_type, name, mip) == 0)) + return 0; - if (strcmp (membname, name) == 0) - { - mip->ctm_type = lmp->ctlm_type; - mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp); - return 0; - } + if (strcmp (membname, name) == 0) + { + mip->ctm_type = mp->ctm_type; + mip->ctm_offset = mp->ctm_offset; + return 0; } } } else { - ctf_dmdef_t *dmd; + const ctf_lmember_t *lmp = vmp; - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = ctf_list_next (dmd)) + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) { - if (dmd->dmd_name == NULL - && (ctf_type_kind (fp, dmd->dmd_type) == CTF_K_STRUCT - || ctf_type_kind (fp, dmd->dmd_type) == CTF_K_UNION) - && (ctf_member_info (fp, dmd->dmd_type, name, mip) == 0)) + const char *membname = ctf_strptr (fp, lmp->ctlm_name); + + if (membname[0] == 0 + && (ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_STRUCT + || ctf_type_kind (fp, lmp->ctlm_type) == CTF_K_UNION) + && (ctf_member_info (fp, lmp->ctlm_type, name, mip) == 0)) return 0; - if (dmd->dmd_name != NULL - && strcmp (dmd->dmd_name, name) == 0) + if (strcmp (membname, name) == 0) { - mip->ctm_type = dmd->dmd_type; - mip->ctm_offset = dmd->dmd_offset; + mip->ctm_type = lmp->ctlm_type; + mip->ctm_offset = (unsigned long) CTF_LMEM_OFFSET (lmp); return 0; } } @@ -1688,8 +1630,10 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func, ctf_id_t otype = type; const ctf_type_t *tp; const ctf_dtdef_t *dtd; + const void *vmp; ssize_t size, increment; uint32_t kind, n; + int dynamic = 0; int rc; if ((type = ctf_type_resolve (fp, type)) == CTF_ERR) @@ -1708,48 +1652,38 @@ ctf_type_rvisit (ctf_dict_t *fp, ctf_id_t type, ctf_visit_f *func, (void) ctf_get_ctt_size (fp, tp, &size, &increment); - if ((dtd = ctf_dynamic_type (fp, type)) == NULL) + if ((dtd = ctf_dynamic_type (fp, type)) != NULL) + dynamic = 1; + + if (!dynamic) + vmp = (unsigned char *) tp + increment; + else + vmp = dtd->dtd_vlen; + + if (size < CTF_LSTRUCT_THRESH && !dynamic) { - if (size < CTF_LSTRUCT_THRESH) - { - const ctf_member_t *mp = (const ctf_member_t *) ((uintptr_t) tp + - increment); + const ctf_member_t *mp = vmp; - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) - { - if ((rc = ctf_type_rvisit (fp, mp->ctm_type, - func, arg, ctf_strptr (fp, - mp->ctm_name), - offset + mp->ctm_offset, - depth + 1)) != 0) - return rc; - } - } - else + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, mp++) { - const ctf_lmember_t *lmp = (const ctf_lmember_t *) ((uintptr_t) tp + - increment); - - for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) - { - if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type, - func, arg, ctf_strptr (fp, - lmp->ctlm_name), - offset + (unsigned long) CTF_LMEM_OFFSET (lmp), - depth + 1)) != 0) - return rc; - } + if ((rc = ctf_type_rvisit (fp, mp->ctm_type, + func, arg, ctf_strptr (fp, + mp->ctm_name), + offset + mp->ctm_offset, + depth + 1)) != 0) + return rc; } } else { - ctf_dmdef_t *dmd; + const ctf_lmember_t *lmp = vmp; - for (dmd = ctf_list_next (&dtd->dtd_u.dtu_members); - dmd != NULL; dmd = ctf_list_next (dmd)) + for (n = LCTF_INFO_VLEN (fp, tp->ctt_info); n != 0; n--, lmp++) { - if ((rc = ctf_type_rvisit (fp, dmd->dmd_type, func, arg, - dmd->dmd_name, dmd->dmd_offset, + if ((rc = ctf_type_rvisit (fp, lmp->ctlm_type, + func, arg, ctf_strptr (fp, + lmp->ctlm_name), + offset + (unsigned long) CTF_LMEM_OFFSET (lmp), depth + 1)) != 0) return rc; } diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c b/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c index d319aaf..a1573a7 100644 --- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c +++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct-ctf.c @@ -12,6 +12,7 @@ struct foo struct { int baz; + struct foo *foo; }; }; }; diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c index 43c3934..16ff094 100644 --- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c +++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.c @@ -13,7 +13,7 @@ main (int argc, char *argv[]) ctf_id_t newtype; const char *memb; ctf_membinfo_t mi; - const char *membs[] = { "bar", "baz", NULL }; + const char *membs[] = { "bar", "baz", "foo", NULL }; const char **walk; int err; diff --git a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk index caa8934..b818a24 100644 --- a/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk +++ b/libctf/testsuite/libctf-regression/type-add-unnamed-struct.lk @@ -1,3 +1,4 @@ # source: type-add-unnamed-struct-ctf.c Looked up bar, type [0-9a-f]*, offset [0-9a-f]* Looked up baz, type [0-9a-f]*, offset [0-9a-f]* +Looked up foo, type [0-9a-f]*, offset [0-9a-f]* |