Пример #1
0
/*ARGSUSED*/
static int
dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
{
	dt_xlator_t *dxp = arg;
	dtrace_hdl_t *dtp = dxp->dx_hdl;
	dt_node_t *enp, *mnp;

	if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
		return (dt_set_errno(dtp, EDT_NOMEM));

	enp->dn_link = dxp->dx_nodes;
	dxp->dx_nodes = enp;

	if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
		return (dt_set_errno(dtp, EDT_NOMEM));

	mnp->dn_link = dxp->dx_nodes;
	dxp->dx_nodes = mnp;

	/*
	 * For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
	 * xlator refers back to the translator and whose dn_xmember refers to
	 * the current member.  These refs will be used by dt_cg.c and dt_as.c.
	 */
	enp->dn_op = DT_TOK_XLATE;
	enp->dn_xlator = dxp;
	enp->dn_xmember = mnp;
	dt_node_type_assign(enp, dxp->dx_dst_ctfp, type);

	/*
	 * For the member itself, we use a DT_NODE_MEMBER as usual with the
	 * appropriate name, output type, and member expression set to 'enp'.
	 */
	if (dxp->dx_members != NULL) {
		assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
		enp->dn_link->dn_list = mnp;
	} else
		dxp->dx_members = mnp;

	mnp->dn_membname = strdup(name);
	mnp->dn_membexpr = enp;
	dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type);

	if (mnp->dn_membname == NULL)
		return (dt_set_errno(dtp, EDT_NOMEM));

	return (0);
}
Пример #2
0
static void
dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
{
	dtrace_typeinfo_t dtt;
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	char n[DT_TYPE_NAMELEN];

	if (argc != 1) {
		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
		    "passed, 1 expected\n", idp->di_name,
		    argc, argc == 1 ? " " : "s ");
	}

	if (ap->dn_kind != DT_NODE_INT) {
		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
		    idp->di_name, "integer constant",
		    dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n)));
	}

	if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) {
		xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n",
		    (longlong_t)ap->dn_value, idp->di_name);
	}

	if (dt_type_lookup("uint64_t", &dtt) == -1) {
		xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n",
		    idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp)));
	}

	idp->di_ctfp = dtt.dtt_ctfp;
	idp->di_type = dtt.dtt_type;

	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Пример #3
0
/*
 * Cook an associative array identifier.  If this is the first time we are
 * cooking this array, create its signature based on the argument list.
 * Otherwise validate the argument list against the existing signature.
 */
static void
dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_data == NULL) {
		dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t));
		char n[DT_TYPE_NAMELEN];
		int i;

		if (isp == NULL)
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

		isp->dis_varargs = -1;
		isp->dis_optargs = -1;
		isp->dis_argc = argc;
		isp->dis_args = NULL;
		isp->dis_auxinfo = 0;

		if (argc != 0 && (isp->dis_args = calloc(argc,
		    sizeof (dt_node_t))) == NULL) {
			idp->di_data = NULL;
			free(isp);
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
		}

		/*
		 * If this identifier has not been explicitly declared earlier,
		 * set the identifier's base type to be our special type <DYN>.
		 * If this ident is an aggregation, it will remain as is.  If
		 * this ident is an associative array, it will be reassigned
		 * based on the result type of the first assignment statement.
		 */
		if (!(idp->di_flags & DT_IDFLG_DECL)) {
			idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl);
			idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl);
		}

		for (i = 0; i < argc; i++, args = args->dn_list) {
			if (dt_node_is_dynamic(args) || dt_node_is_void(args)) {
				xyerror(D_KEY_TYPE, "%s expression may not be "
				    "used as %s index: key #%d\n",
				    dt_node_type_name(args, n, sizeof (n)),
				    dt_idkind_name(idp->di_kind), i + 1);
			}

			dt_node_type_propagate(args, &isp->dis_args[i]);
			isp->dis_args[i].dn_list = &isp->dis_args[i + 1];
		}

		if (argc != 0)
			isp->dis_args[argc - 1].dn_list = NULL;

		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);

	} else {
		dt_idcook_sign(dnp, idp, argc, args,
		    idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]");
	}
}
Пример #4
0
/*
 * Common code for cooking an identifier that uses a typed signature list (we
 * use this for associative arrays and functions).  If the argument list is
 * of the same length and types, then return the return type.  Otherwise
 * print an appropriate compiler error message and abort the compile.
 */
static void
dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp,
    int argc, dt_node_t *args, const char *prefix, const char *suffix)
{
	dt_idsig_t *isp = idp->di_data;
	int i, compat, mismatch, arglimit, iskey;

	char n1[DT_TYPE_NAMELEN];
	char n2[DT_TYPE_NAMELEN];

	iskey = idp->di_kind == DT_IDENT_ARRAY || idp->di_kind == DT_IDENT_AGG;

	if (isp->dis_varargs >= 0) {
		mismatch = argc < isp->dis_varargs;
		arglimit = isp->dis_varargs;
	} else if (isp->dis_optargs >= 0) {
		mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc);
		arglimit = argc;
	} else {
		mismatch = argc != isp->dis_argc;
		arglimit = isp->dis_argc;
	}

	if (mismatch) {
		xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d %s%s"
		    "passed, %s%d expected\n", prefix, idp->di_name, suffix,
		    argc, iskey ? "key" : "arg", argc == 1 ? " " : "s ",
		    isp->dis_optargs >= 0 ? "at least " : "",
		    isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit);
	}

	for (i = 0; i < arglimit; i++, args = args->dn_list) {
		if (isp->dis_args[i].dn_ctfp != NULL)
			compat = dt_node_is_argcompat(&isp->dis_args[i], args);
		else
			compat = 1; /* "@" matches any type */

		if (!compat) {
			xyerror(D_PROTO_ARG,
			    "%s%s%s %s #%d is incompatible with "
			    "prototype:\n\tprototype: %s\n\t%9s: %s\n",
			    prefix, idp->di_name, suffix,
			    iskey ? "key" : "argument", i + 1,
			    dt_node_type_name(&isp->dis_args[i], n1,
			    sizeof (n1)),
			    iskey ? "key" : "argument",
			    dt_node_type_name(args, n2, sizeof (n2)));
		}
	}

	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Пример #5
0
/*ARGSUSED*/
static int
dt_copyvar(dt_idhash_t *dhp, dt_ident_t *idp, void *data)
{
	dt_pcb_t *pcb = data;
	dtrace_difv_t *dvp;
	ssize_t stroff;
	dt_node_t dn;
	RT_NOREF1(dhp);

	if (!(idp->di_flags & (DT_IDFLG_DIFR | DT_IDFLG_DIFW)))
		return (0); /* omit variable from vartab */

	dvp = &pcb->pcb_difo->dtdo_vartab[pcb->pcb_asvidx++];
	stroff = dt_strtab_insert(pcb->pcb_strtab, idp->di_name);

	if (stroff == -1L)
		longjmp(pcb->pcb_jmpbuf, EDT_NOMEM);
	if (stroff > DIF_STROFF_MAX)
		longjmp(pcb->pcb_jmpbuf, EDT_STR2BIG);

	dvp->dtdv_name = (uint_t)stroff;
	dvp->dtdv_id = idp->di_id;
	dvp->dtdv_flags = 0;

	dvp->dtdv_kind = (idp->di_kind == DT_IDENT_ARRAY) ?
	    DIFV_KIND_ARRAY : DIFV_KIND_SCALAR;

	if (idp->di_flags & DT_IDFLG_LOCAL)
		dvp->dtdv_scope = DIFV_SCOPE_LOCAL;
	else if (idp->di_flags & DT_IDFLG_TLS)
		dvp->dtdv_scope = DIFV_SCOPE_THREAD;
	else
		dvp->dtdv_scope = DIFV_SCOPE_GLOBAL;

	if (idp->di_flags & DT_IDFLG_DIFR)
		dvp->dtdv_flags |= DIFV_F_REF;
	if (idp->di_flags & DT_IDFLG_DIFW)
		dvp->dtdv_flags |= DIFV_F_MOD;

	bzero(&dn, sizeof (dn));
	dt_node_type_assign(&dn, idp->di_ctfp, idp->di_type);
	dt_node_diftype(pcb->pcb_hdl, &dn, &dvp->dtdv_type);

	idp->di_flags &= ~(DT_IDFLG_DIFR | DT_IDFLG_DIFW);
	return (0);
}
Пример #6
0
/*ARGSUSED*/
static void
dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_type == CTF_ERR) {
		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
		dtrace_typeinfo_t dtt;

		if (dt_type_lookup(idp->di_iarg, &dtt) == -1) {
			xyerror(D_UNKNOWN,
			    "failed to resolve type %s for identifier %s: %s\n",
			    (const char *)idp->di_iarg, idp->di_name,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
		}

		idp->di_ctfp = dtt.dtt_ctfp;
		idp->di_type = dtt.dtt_type;
	}

	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Пример #7
0
/*
 * Lookup the dynamic translator type tag for the specified probe argument and
 * assign the type to the specified node.  If the type is not yet defined, add
 * it to the "D" module's type container as a typedef for an unknown type.
 */
dt_node_t *
dt_probe_tag(dt_probe_t *prp, uint_t argn, dt_node_t *dnp)
{
	dtrace_hdl_t *dtp = prp->pr_pvp->pv_hdl;
	dtrace_typeinfo_t dtt;
	size_t len;
	char *tag;

	len = snprintf(NULL, 0, "__dtrace_%s___%s_arg%u",
	    prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);

	tag = alloca(len + 1);

	(void) snprintf(tag, len + 1, "__dtrace_%s___%s_arg%u",
	    prp->pr_pvp->pv_desc.dtvd_name, prp->pr_name, argn);

	if (dtrace_lookup_by_type(dtp, DTRACE_OBJ_DDEFS, tag, &dtt) != 0) {
		dtt.dtt_object = DTRACE_OBJ_DDEFS;
		dtt.dtt_ctfp = DT_DYN_CTFP(dtp);
		dtt.dtt_type = ctf_add_typedef(DT_DYN_CTFP(dtp),
		    CTF_ADD_ROOT, tag, DT_DYN_TYPE(dtp));

		if (dtt.dtt_type == CTF_ERR ||
		    ctf_update(dtt.dtt_ctfp) == CTF_ERR) {
			xyerror(D_UNKNOWN, "cannot define type %s: %s\n",
			    tag, ctf_errmsg(ctf_errno(dtt.dtt_ctfp)));
		}
	}

	bzero(dnp, sizeof (dt_node_t));
	dnp->dn_kind = DT_NODE_TYPE;

	dt_node_type_assign(dnp, dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
	dt_node_attr_assign(dnp, _dtrace_defattr);

	return (dnp);
}
Пример #8
0
/*
 * If a probe was discovered from the kernel, ask dtrace(7D) for a description
 * of each of its arguments, including native and translated types.
 */
static dt_probe_t *
dt_probe_discover(dt_provider_t *pvp, const dtrace_probedesc_t *pdp)
{
	dtrace_hdl_t *dtp = pvp->pv_hdl;
	char *name = dt_probe_key(pdp, alloca(dt_probe_keylen(pdp)));

	dt_node_t *xargs, *nargs;
	dt_ident_t *idp;
	dt_probe_t *prp;

	dtrace_typeinfo_t dtt;
	int i, nc, xc;

	int adc = _dtrace_argmax;
	dtrace_argdesc_t *adv = alloca(sizeof (dtrace_argdesc_t) * adc);
	dtrace_argdesc_t *adp = adv;

	assert(strcmp(pvp->pv_desc.dtvd_name, pdp->dtpd_provider) == 0);
	assert(pdp->dtpd_id != DTRACE_IDNONE);

	dt_dprintf("discovering probe %s:%s id=%d\n",
	    pvp->pv_desc.dtvd_name, name, pdp->dtpd_id);

	for (nc = -1, i = 0; i < adc; i++, adp++) {
		bzero(adp, sizeof (dtrace_argdesc_t));
		adp->dtargd_ndx = i;
		adp->dtargd_id = pdp->dtpd_id;

		if (dt_ioctl(dtp, DTRACEIOC_PROBEARG, adp) != 0) {
			(void) dt_set_errno(dtp, errno);
			return (NULL);
		}

		if (adp->dtargd_ndx == DTRACE_ARGNONE)
			break; /* all argument descs have been retrieved */

		nc = MAX(nc, adp->dtargd_mapping);
	}

	xc = i;
	nc++;

	/*
	 * The pid provider believes in giving the kernel a break. No reason to
	 * give the kernel all the ctf containers that we're keeping ourselves
	 * just to get it back from it. So if we're coming from a pid provider
	 * probe and the kernel gave us no argument information we'll get some
	 * here. If for some crazy reason the kernel knows about our userland
	 * types then we just ignore this.
	 */
	if (xc == 0 && nc == 0 &&
	    strncmp(pvp->pv_desc.dtvd_name, "pid", 3) == 0) {
		nc = adc;
		dt_pid_get_types(dtp, pdp, adv, &nc);
		xc = nc;
	}

	/*
	 * Now that we have discovered the number of native and translated
	 * arguments from the argument descriptions, allocate a new probe ident
	 * and corresponding dt_probe_t and hash it into the provider.
	 */
	xargs = dt_probe_alloc_args(pvp, xc);
	nargs = dt_probe_alloc_args(pvp, nc);

	if ((xc != 0 && xargs == NULL) || (nc != 0 && nargs == NULL))
		return (NULL); /* dt_errno is set for us */

	idp = dt_ident_create(name, DT_IDENT_PROBE,
	    DT_IDFLG_ORPHAN, pdp->dtpd_id, _dtrace_defattr, 0,
	    &dt_idops_probe, NULL, dtp->dt_gen);

	if (idp == NULL) {
		(void) dt_set_errno(dtp, EDT_NOMEM);
		return (NULL);
	}

	if ((prp = dt_probe_create(dtp, idp, 2,
	    nargs, nc, xargs, xc)) == NULL) {
		dt_ident_destroy(idp);
		return (NULL);
	}

	dt_probe_declare(pvp, prp);

	/*
	 * Once our new dt_probe_t is fully constructed, iterate over the
	 * cached argument descriptions and assign types to prp->pr_nargv[]
	 * and prp->pr_xargv[] and assign mappings to prp->pr_mapping[].
	 */
	for (adp = adv, i = 0; i < xc; i++, adp++) {
		if (dtrace_type_strcompile(dtp,
		    adp->dtargd_native, &dtt) != 0) {
			dt_dprintf("failed to resolve input type %s "
			    "for %s:%s arg #%d: %s\n", adp->dtargd_native,
			    pvp->pv_desc.dtvd_name, name, i + 1,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));

			dtt.dtt_object = NULL;
			dtt.dtt_ctfp = NULL;
			dtt.dtt_type = CTF_ERR;
		} else {
			dt_node_type_assign(prp->pr_nargv[adp->dtargd_mapping],
			    dtt.dtt_ctfp, dtt.dtt_type,
			    dtt.dtt_flags & DTT_FL_USER ? B_TRUE : B_FALSE);
		}

		if (dtt.dtt_type != CTF_ERR && (adp->dtargd_xlate[0] == '\0' ||
		    strcmp(adp->dtargd_native, adp->dtargd_xlate) == 0)) {
			dt_node_type_propagate(prp->pr_nargv[
			    adp->dtargd_mapping], prp->pr_xargv[i]);
		} else if (dtrace_type_strcompile(dtp,
		    adp->dtargd_xlate, &dtt) != 0) {
			dt_dprintf("failed to resolve output type %s "
			    "for %s:%s arg #%d: %s\n", adp->dtargd_xlate,
			    pvp->pv_desc.dtvd_name, name, i + 1,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));

			dtt.dtt_object = NULL;
			dtt.dtt_ctfp = NULL;
			dtt.dtt_type = CTF_ERR;
		} else {
			dt_node_type_assign(prp->pr_xargv[i],
			    dtt.dtt_ctfp, dtt.dtt_type, B_FALSE);
		}

		prp->pr_mapping[i] = adp->dtargd_mapping;
		prp->pr_argv[i] = dtt;
	}

	return (prp);
}
Пример #9
0
dt_xlator_t *
dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
{
	ctf_file_t *src_ctfp = src->dn_ctfp;
	ctf_id_t src_type = src->dn_type;
	ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);

	ctf_file_t *dst_ctfp = dst->dn_ctfp;
	ctf_id_t dst_type = dst->dn_type;
	ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
	uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);

	int ptr = dst_kind == CTF_K_POINTER;
	dtrace_typeinfo_t src_dtt, dst_dtt;
	dt_node_t xn = { 0 };
	dt_xlator_t *dxp = NULL;

	if (src_base == CTF_ERR || dst_base == CTF_ERR)
		return (NULL); /* fail if these are unresolvable types */

	/*
	 * Translators are always defined using a struct or union type, so if
	 * we are attempting to translate to type "T *", we internally look
	 * for a translation to type "T" by following the pointer reference.
	 */
	if (ptr) {
		dst_type = ctf_type_reference(dst_ctfp, dst_type);
		dst_base = ctf_type_resolve(dst_ctfp, dst_type);
		dst_kind = ctf_type_kind(dst_ctfp, dst_base);
	}

	if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
		return (NULL); /* fail if the output isn't a struct or union */

	/*
	 * In order to find a matching translator, we iterate over the set of
	 * available translators in three passes.  First, we look for a
	 * translation from the exact source type to the resolved destination.
	 * Second, we look for a translation from the resolved source type to
	 * the resolved destination.  Third, we look for a translation from a
	 * compatible source type (using the same rules as parameter formals)
	 * to the resolved destination.  If all passes fail, return NULL.
	 */
	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
	    dxp = dt_list_next(dxp)) {
		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
		    src_ctfp, src_type) &&
		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
		    dst_ctfp, dst_base))
			goto out;
	}

	if (flags & DT_XLATE_EXACT)
		goto out; /* skip remaining passes if exact match required */

	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
	    dxp = dt_list_next(dxp)) {
		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
		    src_ctfp, src_type) &&
		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
		    dst_ctfp, dst_base))
			goto out;
	}

	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
	    dxp = dt_list_next(dxp)) {
		dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type);
		if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
		    dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
			goto out;
	}

out:
	if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
		return (NULL);	/* no translation available to pointer type */

	if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
	    dtp->dt_xlatemode == DT_XL_STATIC)
		return (dxp);	/* we succeeded or not allowed to extern */

	/*
	 * If we get here, then we didn't find an existing translator, but the
	 * caller and xlatemode permit us to create an extern to a dynamic one.
	 */
	src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
	src_dtt.dtt_ctfp = src_ctfp;
	src_dtt.dtt_type = src_type;

	dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name;
	dst_dtt.dtt_ctfp = dst_ctfp;
	dst_dtt.dtt_type = dst_type;

	return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
}
Пример #10
0
/*ARGSUSED*/
static void
dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR)
		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
}
Пример #11
0
/*
 * Cook a reference to the dynamically typed args[] array.  We verify that the
 * reference is using a single integer constant, and then construct a new ident
 * representing the appropriate type or translation specifically for this node.
 */
static void
dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
{
	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
	dt_probe_t *prp = yypcb->pcb_probe;

	dt_node_t tag, *nnp, *xnp;
	dt_xlator_t *dxp;
	dt_ident_t *xidp;

	char n1[DT_TYPE_NAMELEN];
	char n2[DT_TYPE_NAMELEN];

	if (argc != 1) {
		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
		    "passed, 1 expected\n", idp->di_name, argc,
		    argc == 1 ? " " : "s ");
	}

	if (ap->dn_kind != DT_NODE_INT) {
		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
		    idp->di_name, "integer constant",
		    dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1)));
	}

	if (yypcb->pcb_pdesc == NULL) {
		xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside "
		    "of a probe clause\n", idp->di_name);
	}

	if (prp == NULL) {
		xyerror(D_ARGS_MULTI,
		    "%s[ ] may not be referenced because probe description %s "
		    "matches an unstable set of probes\n", idp->di_name,
		    dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1)));
	}

	if (ap->dn_value >= prp->pr_argc) {
		xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n",
		    (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc,
		    n1, sizeof (n1)), idp->di_name);
	}

	/*
	 * Look up the native and translated argument types for the probe.
	 * If no translation is needed, these will be the same underlying node.
	 * If translation is needed, look up the appropriate translator.  Once
	 * we have the appropriate node, create a new dt_ident_t for this node,
	 * assign it the appropriate attributes, and set the type of 'dnp'.
	 */
	xnp = prp->pr_xargv[ap->dn_value];
	nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]];

	if (xnp->dn_type == CTF_ERR) {
		xyerror(D_ARGS_TYPE, "failed to resolve translated type for "
		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
	}

	if (nnp->dn_type == CTF_ERR) {
		xyerror(D_ARGS_TYPE, "failed to resolve native type for "
		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
	}

	if (dtp->dt_xlatemode == DT_XL_STATIC && (
	    nnp == xnp || dt_node_is_argcompat(nnp, xnp))) {
		dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind,
		    idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);

		if (dnp->dn_ident == NULL)
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

		dt_node_type_assign(dnp,
		    prp->pr_argv[ap->dn_value].dtt_ctfp,
		    prp->pr_argv[ap->dn_value].dtt_type);

	} else if ((dxp = dt_xlator_lookup(dtp,
	    nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
	    dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag),
	    xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) {

		xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type);

		dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind,
		    xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);

		if (dnp->dn_ident == NULL)
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

		if (dt_xlator_dynamic(dxp))
			dxp->dx_arg = (int)ap->dn_value;

		/*
		 * Propagate relevant members from the translator's internal
		 * dt_ident_t.  This code must be kept in sync with the state
		 * that is initialized for idents in dt_xlator_create().
		 */
		dnp->dn_ident->di_data = xidp->di_data;
		dnp->dn_ident->di_ctfp = xidp->di_ctfp;
		dnp->dn_ident->di_type = xidp->di_type;

		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));

	} else {
		xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
		    "is not defined\n", idp->di_name, (longlong_t)ap->dn_value,
		    dt_node_type_name(nnp, n1, sizeof (n1)),
		    dt_node_type_name(xnp, n2, sizeof (n2)));
	}

	assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN);
	assert(dnp->dn_ident->di_id == idp->di_id);
}
Пример #12
0
/*
 * Cook a function call.  If this is the first time we are cooking this
 * identifier, create its type signature based on predefined prototype stored
 * in di_iarg.  We then validate the argument list against this signature.
 */
static void
dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
{
	if (idp->di_data == NULL) {
		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
		dtrace_typeinfo_t dtt;
		dt_idsig_t *isp;
		char *s, *p1, *p2;
		int i = 0;

		assert(idp->di_iarg != NULL);
		s = alloca(strlen(idp->di_iarg) + 1);
		(void) strcpy(s, idp->di_iarg);

		if ((p2 = strrchr(s, ')')) != NULL)
			*p2 = '\0'; /* mark end of parameter list string */

		if ((p1 = strchr(s, '(')) != NULL)
			*p1++ = '\0'; /* mark end of return type string */

		if (p1 == NULL || p2 == NULL) {
			xyerror(D_UNKNOWN, "internal error: malformed entry "
			    "for built-in function %s\n", idp->di_name);
		}

		for (p2 = p1; *p2 != '\0'; p2++) {
			if (!isspace(*p2)) {
				i++;
				break;
			}
		}

		for (p2 = strchr(p2, ','); p2++ != NULL; i++)
			p2 = strchr(p2, ',');

		/*
		 * We first allocate a new ident signature structure with the
		 * appropriate number of argument entries, and then look up
		 * the return type and store its CTF data in di_ctfp/type.
		 */
		if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL)
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);

		isp->dis_varargs = -1;
		isp->dis_optargs = -1;
		isp->dis_argc = i;
		isp->dis_args = NULL;
		isp->dis_auxinfo = 0;

		if (i != 0 && (isp->dis_args = calloc(i,
		    sizeof (dt_node_t))) == NULL) {
			idp->di_data = NULL;
			free(isp);
			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
		}

		if (dt_type_lookup(s, &dtt) == -1) {
			xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):"
			    " %s\n", idp->di_name, s,
			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
		}

		if (idp->di_kind == DT_IDENT_AGGFUNC) {
			idp->di_ctfp = DT_DYN_CTFP(dtp);
			idp->di_type = DT_DYN_TYPE(dtp);
		} else {
			idp->di_ctfp = dtt.dtt_ctfp;
			idp->di_type = dtt.dtt_type;
		}

		/*
		 * For each comma-delimited parameter in the prototype string,
		 * we look up the corresponding type and store its CTF data in
		 * the corresponding location in dis_args[].  We also recognize
		 * the special type string "@" to indicate that the specified
		 * parameter may be a D expression of *any* type (represented
		 * as a dis_args[] element with ctfp = NULL, type == CTF_ERR).
		 * If a varargs "..." is present, we record the argument index
		 * in dis_varargs for the benefit of dt_idcook_sign(), above.
		 * If the type of an argument is enclosed in square brackets
		 * (e.g. "[int]"), the argument is considered optional:  the
		 * argument may be absent, but if it is present, it must be of
		 * the specified type.  Note that varargs may not optional,
		 * optional arguments may not follow varargs, and non-optional
		 * arguments may not follow optional arguments.
		 */
		for (i = 0; i < isp->dis_argc; i++, p1 = p2) {
			while (isspace(*p1))
				p1++; /* skip leading whitespace */

			if ((p2 = strchr(p1, ',')) == NULL)
				p2 = p1 + strlen(p1);
			else
				*p2++ = '\0';

			if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) {
				isp->dis_args[i].dn_ctfp = NULL;
				isp->dis_args[i].dn_type = CTF_ERR;
				if (*p1 == '.')
					isp->dis_varargs = i;
				continue;
			}

			if (*p1 == '[' && p1[strlen(p1) - 1] == ']') {
				if (isp->dis_varargs != -1) {
					xyerror(D_UNKNOWN, "optional arg#%d "
					    "may not follow variable arg#%d\n",
					    i + 1, isp->dis_varargs + 1);
				}

				if (isp->dis_optargs == -1)
					isp->dis_optargs = i;

				p1[strlen(p1) - 1] = '\0';
				p1++;
			} else if (isp->dis_optargs != -1) {
				xyerror(D_UNKNOWN, "required arg#%d may not "
				    "follow optional arg#%d\n", i + 1,
				    isp->dis_optargs + 1);
			}

			if (dt_type_lookup(p1, &dtt) == -1) {
				xyerror(D_UNKNOWN, "failed to resolve type of "
				    "%s arg#%d (%s): %s\n", idp->di_name, i + 1,
				    p1, dtrace_errmsg(dtp, dtrace_errno(dtp)));
			}

			dt_node_type_assign(&isp->dis_args[i],
			    dtt.dtt_ctfp, dtt.dtt_type);
		}
	}

	dt_idcook_sign(dnp, idp, argc, args, "", "( )");
}