예제 #1
0
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);
}
예제 #2
0
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);
}
예제 #3
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);
}
예제 #4
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);
}
예제 #5
0
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);
}
예제 #6
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++;
}
예제 #7
0
/*
 * 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--;
}
예제 #8
0
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);
}
예제 #9
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);
}
예제 #10
0
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);
}
예제 #11
0
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);
}