ctf_id_t ctf_add_array(ctf_file_t *fp, uint_t flag, const ctf_arinfo_t *arp) { ctf_dtdef_t *dtd; ctf_id_t type; ctf_file_t *fpd; if (arp == NULL) return (ctf_set_errno(fp, EINVAL)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && ctf_dtd_lookup(fp, arp->ctr_index) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ARRAY, flag, 0); dtd->dtd_data.ctt_size = 0; dtd->dtd_u.dtu_arr = *arp; ctf_ref_inc(fp, arp->ctr_contents); ctf_ref_inc(fp, arp->ctr_index); return (type); }
int ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) { ctf_file_t *fpd; ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) return (ctf_set_errno(fp, ECTF_BADID)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_contents) == NULL && ctf_dtd_lookup(fp, arp->ctr_contents) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); fpd = fp; if (ctf_lookup_by_id(&fpd, arp->ctr_index) == NULL && ctf_dtd_lookup(fp, arp->ctr_index) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_contents); ctf_ref_dec(fp, dtd->dtd_u.dtu_arr.ctr_index); fp->ctf_flags |= LCTF_DIRTY; dtd->dtd_u.dtu_arr = *arp; ctf_ref_inc(fp, arp->ctr_contents); ctf_ref_inc(fp, arp->ctr_index); return (0); }
/* * This removes a type from the dynamic section. This will fail if the type is * referenced by another type. Note that the CTF ID is never reused currently by * CTF. Note that if this container is a parent container then we just outright * refuse to remove the type. There currently is no notion of searching for the * ctf_dtdef_t in parent containers. If there is, then this constraint could * become finer grained. */ int ctf_delete_type(ctf_file_t *fp, ctf_id_t type) { ctf_file_t *fpd; ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); /* * We want to give as useful an errno as possible. That means that we * want to distinguish between a type which does not exist and one for * which the type is not dynamic. */ fpd = fp; if (ctf_lookup_by_id(&fpd, type) == NULL && ctf_dtd_lookup(fp, type) == NULL) return (CTF_ERR); /* errno is set for us */ if (dtd == NULL) return (ctf_set_errno(fp, ECTF_NOTDYN)); if (dtd->dtd_ref != 0 || fp->ctf_refcnt > 1) return (ctf_set_errno(fp, ECTF_REFERENCED)); ctf_dtd_delete(fp, dtd); fp->ctf_flags |= LCTF_DIRTY; return (0); }
ctf_id_t ctf_add_function(ctf_file_t *fp, uint_t flag, const ctf_funcinfo_t *ctc, const ctf_id_t *argv) { ctf_dtdef_t *dtd; ctf_id_t type; uint_t vlen; int i; ctf_id_t *vdat = NULL; ctf_file_t *fpd; if (ctc == NULL || (ctc->ctc_flags & ~CTF_FUNC_VARARG) != 0 || (ctc->ctc_argc != 0 && argv == NULL)) return (ctf_set_errno(fp, EINVAL)); vlen = ctc->ctc_argc; if (ctc->ctc_flags & CTF_FUNC_VARARG) vlen++; /* add trailing zero to indicate varargs (see below) */ if (vlen > CTF_MAX_VLEN) return (ctf_set_errno(fp, EOVERFLOW)); fpd = fp; if (ctf_lookup_by_id(&fpd, ctc->ctc_return) == NULL && ctf_dtd_lookup(fp, ctc->ctc_return) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); for (i = 0; i < ctc->ctc_argc; i++) { fpd = fp; if (ctf_lookup_by_id(&fpd, argv[i]) == NULL && ctf_dtd_lookup(fp, argv[i]) == NULL) return (ctf_set_errno(fp, ECTF_BADID)); } if (vlen != 0 && (vdat = ctf_alloc(sizeof (ctf_id_t) * vlen)) == NULL) return (ctf_set_errno(fp, EAGAIN)); if ((type = ctf_add_generic(fp, flag, NULL, &dtd)) == CTF_ERR) { ctf_free(vdat, sizeof (ctf_id_t) * vlen); return (CTF_ERR); /* errno is set for us */ } dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_FUNCTION, flag, vlen); dtd->dtd_data.ctt_type = (ushort_t)ctc->ctc_return; ctf_ref_inc(fp, ctc->ctc_return); for (i = 0; i < ctc->ctc_argc; i++) ctf_ref_inc(fp, argv[i]); bcopy(argv, vdat, sizeof (ctf_id_t) * ctc->ctc_argc); if (ctc->ctc_flags & CTF_FUNC_VARARG) vdat[vlen - 1] = 0; /* add trailing zero to indicate varargs */ dtd->dtd_u.dtu_argv = vdat; return (type); }
int ctf_add_enumerator(ctf_file_t *fp, ctf_id_t enid, const char *name, int value) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, enid); ctf_dmdef_t *dmd; uint_t kind, vlen, root; char *s; if (name == NULL) return (ctf_set_errno(fp, EINVAL)); 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_ENUM) return (ctf_set_errno(fp, ECTF_NOTENUM)); if (vlen == CTF_MAX_VLEN) return (ctf_set_errno(fp, ECTF_DTFULL)); for (dmd = ctf_list_next(&dtd->dtd_u.dtu_members); dmd != NULL; dmd = ctf_list_next(dmd)) { if (strcmp(dmd->dmd_name, name) == 0) return (ctf_set_errno(fp, ECTF_DUPMEMBER)); } if ((dmd = ctf_alloc(sizeof (ctf_dmdef_t))) == NULL) return (ctf_set_errno(fp, EAGAIN)); if ((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 = CTF_ERR; dmd->dmd_offset = 0; dmd->dmd_value = value; dtd->dtd_data.ctt_info = CTF_TYPE_INFO(kind, root, vlen + 1); ctf_list_append(&dtd->dtd_u.dtu_members, dmd); fp->ctf_dtstrlen += strlen(s) + 1; fp->ctf_flags |= LCTF_DIRTY; return (0); }
/* * Only types of dyanmic CTF containers contain reference counts. These * containers are marked RD/WR. Because of that we basically make this a no-op * for compatability with non-dynamic CTF sections. This is also a no-op for * types which are not dynamic types. It is the responsibility of the caller to * make sure it is a valid type. We help that caller out on debug builds. * * Note that the reference counts are not maintained for types that are not * within this container. In other words if we have a type in a parent, that * will not have its reference count increased. On the flip side, the parent * will not be allowed to remove dynamic types if it has children. */ static void ctf_ref_inc(ctf_file_t *fp, ctf_id_t tid) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); if (dtd == NULL) return; if (!(fp->ctf_flags & LCTF_RDWR)) return; dtd->dtd_ref++; }
/* * Just as with ctf_ref_inc, this is a no-op on non-writeable containers and the * caller should ensure that this is already a valid type. */ static void ctf_ref_dec(ctf_file_t *fp, ctf_id_t tid) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, tid); if (dtd == NULL) return; if (!(fp->ctf_flags & LCTF_RDWR)) return; ASSERT(dtd->dtd_ref >= 1); dtd->dtd_ref--; }
int ctf_set_array(ctf_file_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) { ctf_dtdef_t *dtd = ctf_dtd_lookup(fp, type); if (!(fp->ctf_flags & LCTF_RDWR)) return (ctf_set_errno(fp, ECTF_RDONLY)); if (dtd == NULL || CTF_INFO_KIND(dtd->dtd_data.ctt_info) != CTF_K_ARRAY) return (ctf_set_errno(fp, ECTF_BADID)); fp->ctf_flags |= LCTF_DIRTY; dtd->dtd_u.dtu_arr = *arp; return (0); }
ctf_id_t ctf_add_typedef(ctf_file_t *fp, uint_t flag, const char *name, ctf_id_t ref) { ctf_dtdef_t *dtd; ctf_id_t type; ctf_file_t *fpd; fpd = fp; if (ref == CTF_ERR || (ctf_lookup_by_id(&fpd, ref) == NULL && ctf_dtd_lookup(fp, ref) == NULL)) return (ctf_set_errno(fp, EINVAL)); if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_TYPEDEF, flag, 0); dtd->dtd_data.ctt_type = (ushort_t)ref; ctf_ref_inc(fp, ref); return (type); }
ctf_id_t ctf_add_enum(ctf_file_t *fp, uint_t flag, const char *name) { ctf_hash_t *hp = &fp->ctf_enums; ctf_helem_t *hep = NULL; ctf_dtdef_t *dtd; ctf_id_t type; if (name != NULL) hep = ctf_hash_lookup(hp, fp, name, strlen(name)); if (hep != NULL && ctf_type_kind(fp, hep->h_type) == CTF_K_FORWARD) dtd = ctf_dtd_lookup(fp, type = hep->h_type); else if ((type = ctf_add_generic(fp, flag, name, &dtd)) == CTF_ERR) return (CTF_ERR); /* errno is set for us */ dtd->dtd_data.ctt_info = CTF_TYPE_INFO(CTF_K_ENUM, flag, 0); dtd->dtd_data.ctt_size = fp->ctf_dmodel->ctd_int; return (type); }
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); }