/* * Resolve the type down to a base type node, and then return the alignment * needed for the type storage in bytes. */ ssize_t ctf_type_align(ctf_file_t *fp, ctf_id_t type) { const ctf_type_t *tp; ctf_arinfo_t r; 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) return (-1); /* errno is set for us */ switch (LCTF_INFO_KIND(fp, tp->ctt_info)) { case CTF_K_POINTER: case CTF_K_FUNCTION: return (fp->ctf_dmodel->ctd_pointer); case CTF_K_ARRAY: if (ctf_array_info(fp, type, &r) == CTF_ERR) return (-1); /* errno is set for us */ return (ctf_type_align(fp, r.ctr_contents)); case CTF_K_STRUCT: case CTF_K_UNION: { uint_t n = LCTF_INFO_VLEN(fp, tp->ctt_info); ssize_t size, increment; size_t align = 0; const void *vmp; (void) ctf_get_ctt_size(fp, tp, &size, &increment); vmp = (uchar_t *)tp + increment; if (LCTF_INFO_KIND(fp, tp->ctt_info) == CTF_K_STRUCT) n = MIN(n, 1); /* only use first member for structs */ if (fp->ctf_version == CTF_VERSION_1 || size < CTF_LSTRUCT_THRESH) { const ctf_member_t *mp = vmp; for (; n != 0; n--, mp++) { ssize_t am = ctf_type_align(fp, mp->ctm_type); align = MAX(align, am); } } else { const ctf_lmember_t *lmp = vmp; for (; n != 0; n--, lmp++) { ssize_t am = ctf_type_align(fp, lmp->ctlm_type); align = MAX(align, am); } } return (align); } case CTF_K_ENUM: return (fp->ctf_dmodel->ctd_int); default: return (ctf_get_ctt_size(fp, tp, NULL, NULL)); } }
int ctf_add_member(ctf_file_t *fp, ctf_id_t souid, const char *name, ctf_id_t type) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, souid); ctf_dmdef_t *dmd; ssize_t msize, malign, ssize; uint_t kind, vlen, root; char *s = NULL; if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (dtd == NULL) return (ctf_set_errno(fp, ECTF_BADID)); kind = CTF_INFO_KIND(dtd->dtd_data.ctt_info); root = CTF_INFO_ISROOT(dtd->dtd_data.ctt_info); vlen = CTF_INFO_VLEN(dtd->dtd_data.ctt_info); if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) return (ctf_set_errno(fp, ECTF_NOTSOU)); if (vlen == CTF_MAX_VLEN) return (ctf_set_errno(fp, ECTF_DTFULL)); 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_DUPMEMBER)); } } if ((msize = ctf_type_size(fp, type)) == CTF_ERR || (malign = ctf_type_align(fp, type)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) return (ctf_set_errno(fp, EAGAIN)); if (name != NULL && (s = ctf_strdup(name)) == NULL) { ctf_free(dmd, sizeof (ctf_dmdef_t)); return (ctf_set_errno(fp, EAGAIN)); } dmd->dmd_name = s; dmd->dmd_type = type; dmd->dmd_value = -1; if (kind == CTF_K_STRUCT && vlen != 0) { 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_encoding_t linfo; ssize_t lsize; if (ctf_type_encoding(fp, ltype, &linfo) != CTF_ERR) off += linfo.cte_bits; else if ((lsize = ctf_type_size(fp, ltype)) != CTF_ERR) off += lsize * NBBY; /* * Round up the offset of the end of the last member to the * next byte boundary, convert 'off' to bytes, and then round * it up again to the next multiple of the alignment required * by the new member. Finally, convert back to bits and store * the result in dmd_offset. Technically we could do more * efficient packing if the new member is a bit-field, but * we're the "compiler" and ANSI says we can do as we choose. */ off = roundup(off, NBBY) / NBBY; off = roundup(off, MAX(malign, 1)); dmd->dmd_offset = off * NBBY; ssize = off + msize; } else { dmd->dmd_offset = 0; ssize = ctf_get_ctt_size(fp, &dtd->dtd_data, NULL, NULL); ssize = MAX(ssize, msize); } if (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 = (ushort_t)ssize; dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); ctf_list_append(&dtd->dtd_u.dtu_members, dmd); if (s != NULL) fp->ctf_dtstrlen += strlen(s) + 1; ctf_ref_inc(fp, type); fp->ctf_flags |= LCTF_DIRTY; return (0); }