dt_xlator.c revision 303975
129415Sjmg/*
2119853Scg * CDDL HEADER START
339899Sluigi *
429415Sjmg * The contents of this file are subject to the terms of the
529415Sjmg * Common Development and Distribution License, Version 1.0 only
629415Sjmg * (the "License").  You may not use this file except in compliance
729415Sjmg * with the License.
850723Scg *
950723Scg * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1029415Sjmg * or http://www.opensolaris.org/os/licensing.
1129415Sjmg * See the License for the specific language governing permissions
1230869Sjmg * and limitations under the License.
1330869Sjmg *
1430869Sjmg * When distributing Covered Code, include this CDDL HEADER in each
1530869Sjmg * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1650723Scg * If applicable, add the following below this CDDL HEADER, with the
1750723Scg * fields enclosed by brackets "[]" replaced with your own identifying
1830869Sjmg * information: Portions Copyright [yyyy] [name of copyright owner]
1950723Scg *
2050723Scg * CDDL HEADER END
2150723Scg */
2250723Scg/*
2350723Scg * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
2450723Scg * Use is subject to license terms.
2550723Scg */
2650723Scg/*
2750723Scg * Copyright (c) 2013 by Delphix. All rights reserved.
2850723Scg * Copyright (c) 2013 Joyent, Inc. All rights reserved.
2950723Scg */
3029415Sjmg
3129415Sjmg#include <strings.h>
3253465Scg#include <assert.h>
3329415Sjmg
3453465Scg#include <dt_xlator.h>
3553553Stanimura#include <dt_parser.h>
3629415Sjmg#include <dt_grammar.h>
37110499Snyan#include <dt_module.h>
38110499Snyan#include <dt_impl.h>
3970134Scg
4070134Scg/*
4182180Scg * Create a member node corresponding to one of the output members of a dynamic
4282180Scg * translator.  We set the member's dn_membexpr to a DT_NODE_XLATOR node that
4367803Scg * has dn_op set to DT_TOK_XLATE and refers back to the translator itself.  The
4455706Scg * code generator will then use this as the indicator for dynamic translation.
4555254Scg */
4667803Scg/*ARGSUSED*/
4750723Scgstatic int
4850723Scgdt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
4964881Scg{
5050723Scg	dt_xlator_t *dxp = arg;
5174763Scg	dtrace_hdl_t *dtp = dxp->dx_hdl;
5229415Sjmg	dt_node_t *enp, *mnp;
5367803Scg
5464881Scg	if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
5550723Scg		return (dt_set_errno(dtp, EDT_NOMEM));
5664881Scg
5750723Scg	enp->dn_link = dxp->dx_nodes;
5874763Scg	dxp->dx_nodes = enp;
5929415Sjmg
6064881Scg	if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
6164881Scg		return (dt_set_errno(dtp, EDT_NOMEM));
6264881Scg
6364881Scg	mnp->dn_link = dxp->dx_nodes;
6464881Scg	dxp->dx_nodes = mnp;
6564881Scg
6654462Scg	/*
6774763Scg	 * For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
6854462Scg	 * xlator refers back to the translator and whose dn_xmember refers to
6950723Scg	 * the current member.  These refs will be used by dt_cg.c and dt_as.c.
7029415Sjmg	 */
7150723Scg	enp->dn_op = DT_TOK_XLATE;
7250723Scg	enp->dn_xlator = dxp;
7374763Scg	enp->dn_xmember = mnp;
7474763Scg	dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE);
7567803Scg
7667803Scg	/*
7750723Scg	 * For the member itself, we use a DT_NODE_MEMBER as usual with the
7829415Sjmg	 * appropriate name, output type, and member expression set to 'enp'.
7950723Scg	 */
8050723Scg	if (dxp->dx_members != NULL) {
8150723Scg		assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
8254462Scg		enp->dn_link->dn_list = mnp;
8354462Scg	} else
8465644Scg		dxp->dx_members = mnp;
8555706Scg
8629415Sjmg	mnp->dn_membname = strdup(name);
8784111Scg	mnp->dn_membexpr = enp;
8850723Scg	dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE);
8950723Scg
9070291Scg	if (mnp->dn_membname == NULL)
9150723Scg		return (dt_set_errno(dtp, EDT_NOMEM));
9274763Scg
9350723Scg	return (0);
9450723Scg}
9584111Scg
9674763Scgdt_xlator_t *
9774763Scgdt_xlator_create(dtrace_hdl_t *dtp,
9850723Scg    const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst,
9950723Scg    const char *name, dt_node_t *members, dt_node_t *nodes)
10050723Scg{
10167803Scg	dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t));
10250723Scg	dtrace_typeinfo_t ptr = *dst;
10350723Scg	dt_xlator_t **map;
10450723Scg	dt_node_t *dnp;
10550723Scg	uint_t kind;
10654462Scg
10729415Sjmg	if (dxp == NULL)
10850723Scg		return (NULL);
10984111Scg
11050723Scg	dxp->dx_hdl = dtp;
11129415Sjmg	dxp->dx_id = dtp->dt_xlatorid++;
11250723Scg	dxp->dx_gen = dtp->dt_gen;
11329415Sjmg	dxp->dx_arg = -1;
11450723Scg
11550723Scg	if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) {
11650723Scg		dt_free(dtp, dxp);
11750723Scg		return (NULL);
11829415Sjmg	}
11929415Sjmg
12084111Scg	dt_list_append(&dtp->dt_xlators, dxp);
12184111Scg	bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id);
12284111Scg	dt_free(dtp, dtp->dt_xlatormap);
12384111Scg	dtp->dt_xlatormap = map;
12484111Scg	dtp->dt_xlatormap[dxp->dx_id] = dxp;
12584111Scg
12684111Scg	if (dt_type_pointer(&ptr) == -1) {
127129180Struckman		ptr.dtt_ctfp = NULL;
128129180Struckman		ptr.dtt_type = CTF_ERR;
129129180Struckman	}
130129180Struckman
131129180Struckman	dxp->dx_ident = dt_ident_create(name ? name : "T",
132129180Struckman	    DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0,
13384111Scg	    _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
13484111Scg
13584111Scg	if (dxp->dx_ident == NULL)
13684111Scg		goto err; /* no memory for identifier */
13784111Scg
13829415Sjmg	dxp->dx_ident->di_ctfp = src->dtt_ctfp;
13950723Scg	dxp->dx_ident->di_type = src->dtt_type;
14029415Sjmg
14167803Scg	/*
14250723Scg	 * If an input parameter name is given, this is a static translator
14329415Sjmg	 * definition: create an idhash and identifier for the parameter.
14450723Scg	 */
14550723Scg	if (name != NULL) {
14650723Scg		dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0);
147108064Ssemenu
14829415Sjmg		if (dxp->dx_locals == NULL)
14929415Sjmg			goto err; /* no memory for identifier hash */
15029415Sjmg
15150723Scg		dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident);
15229415Sjmg	}
15350723Scg
15450723Scg	dxp->dx_souid.di_name = "translator";
15529415Sjmg	dxp->dx_souid.di_kind = DT_IDENT_XLSOU;
15650723Scg	dxp->dx_souid.di_flags = DT_IDFLG_REF;
15750723Scg	dxp->dx_souid.di_id = dxp->dx_id;
15850723Scg	dxp->dx_souid.di_attr = _dtrace_defattr;
15950723Scg	dxp->dx_souid.di_ops = &dt_idops_thaw;
16029415Sjmg	dxp->dx_souid.di_data = dxp;
16129415Sjmg	dxp->dx_souid.di_ctfp = dst->dtt_ctfp;
16250723Scg	dxp->dx_souid.di_type = dst->dtt_type;
16350723Scg	dxp->dx_souid.di_gen = dtp->dt_gen;
16429415Sjmg
16550723Scg	dxp->dx_ptrid.di_name = "translator";
16629415Sjmg	dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR;
16750723Scg	dxp->dx_ptrid.di_flags = DT_IDFLG_REF;
16870134Scg	dxp->dx_ptrid.di_id = dxp->dx_id;
16970134Scg	dxp->dx_ptrid.di_attr = _dtrace_defattr;
17070134Scg	dxp->dx_ptrid.di_ops = &dt_idops_thaw;
17170134Scg	dxp->dx_ptrid.di_data = dxp;
17270134Scg	dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp;
17350723Scg	dxp->dx_ptrid.di_type = ptr.dtt_type;
17450723Scg	dxp->dx_ptrid.di_gen = dtp->dt_gen;
17579116Sgreen
17683366Sjulian	/*
17774797Scg	 * If a deferred pragma is pending on the keyword "translator", run all
17879090Sgreen	 * the deferred pragmas on dx_souid and then copy results to dx_ptrid.
17950723Scg	 * See the code in dt_pragma.c for details on deferred ident pragmas.
18050723Scg	 */
18129415Sjmg	if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL &&
18250723Scg	    dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) {
18350723Scg		dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid);
18450723Scg		dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr;
18550723Scg		dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers;
18650723Scg	}
18750723Scg
18850723Scg	dxp->dx_src_ctfp = src->dtt_ctfp;
18950723Scg	dxp->dx_src_type = src->dtt_type;
19029415Sjmg	dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type);
19167803Scg
19250723Scg	dxp->dx_dst_ctfp = dst->dtt_ctfp;
19350723Scg	dxp->dx_dst_type = dst->dtt_type;
19450723Scg	dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type);
19550723Scg
19650723Scg	kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base);
19750723Scg	assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
19850723Scg
19950723Scg	/*
20050723Scg	 * If no input parameter is given, we're making a dynamic translator:
20150723Scg	 * create member nodes for every member of the output type.  Otherwise
20267803Scg	 * retain the member and allocation node lists presented by the parser.
20329415Sjmg	 */
20450723Scg	if (name == NULL) {
20550723Scg		if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base,
20650723Scg		    dt_xlator_create_member, dxp) != 0)
20784111Scg			goto err;
20884111Scg	} else {
20950723Scg		dxp->dx_members = members;
21050723Scg		dxp->dx_nodes = nodes;
21150723Scg	}
21284111Scg
21384111Scg	/*
21450723Scg	 * Assign member IDs to each member and allocate space for DIFOs
21584111Scg	 * if and when this translator is eventually compiled.
21684111Scg	 */
21784111Scg	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
21884111Scg		dnp->dn_membxlator = dxp;
21984111Scg		dnp->dn_membid = dxp->dx_nmembers++;
22084111Scg	}
22184111Scg
22284111Scg	dxp->dx_membdif = dt_zalloc(dtp,
22384111Scg	    sizeof (dtrace_difo_t *) * dxp->dx_nmembers);
22450723Scg
22529415Sjmg	if (dxp->dx_membdif == NULL) {
22650723Scg		dxp->dx_nmembers = 0;
22750723Scg		goto err;
22850723Scg	}
22950723Scg
23050723Scg	return (dxp);
23150723Scg
23250723Scgerr:
23374763Scg	dt_xlator_destroy(dtp, dxp);
23450723Scg	return (NULL);
23550723Scg}
23650723Scg
23750723Scgvoid
23874763Scgdt_xlator_destroy(dtrace_hdl_t *dtp, dt_xlator_t *dxp)
23950723Scg{
24031361Sjmg	uint_t i;
24150723Scg
24250723Scg	dt_node_link_free(&dxp->dx_nodes);
24350723Scg
24450723Scg	if (dxp->dx_locals != NULL)
24529415Sjmg		dt_idhash_destroy(dxp->dx_locals);
24674763Scg	else if (dxp->dx_ident != NULL)
24750723Scg		dt_ident_destroy(dxp->dx_ident);
24850723Scg
24950723Scg	for (i = 0; i < dxp->dx_nmembers; i++)
25050723Scg		dt_difo_free(dtp, dxp->dx_membdif[i]);
25174763Scg
25229415Sjmg	dt_free(dtp, dxp->dx_membdif);
25350723Scg	dt_list_delete(&dtp->dt_xlators, dxp);
25450723Scg	dt_free(dtp, dxp);
25529415Sjmg}
25650723Scg
25750723Scgdt_xlator_t *
25850723Scgdt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
25950723Scg{
26029415Sjmg	ctf_file_t *src_ctfp = src->dn_ctfp;
26150723Scg	ctf_id_t src_type = src->dn_type;
26250723Scg	ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);
26350723Scg
26450723Scg	ctf_file_t *dst_ctfp = dst->dn_ctfp;
26550723Scg	ctf_id_t dst_type = dst->dn_type;
26650723Scg	ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
26750723Scg	uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);
26850723Scg
26929415Sjmg	int ptr = dst_kind == CTF_K_POINTER;
27050723Scg	dtrace_typeinfo_t src_dtt, dst_dtt;
27150723Scg	dt_node_t xn = { 0 };
27229415Sjmg	dt_xlator_t *dxp = NULL;
27374763Scg
27474763Scg	if (src_base == CTF_ERR || dst_base == CTF_ERR)
275129180Struckman		return (NULL); /* fail if these are unresolvable types */
27650723Scg
27750723Scg	/*
27850723Scg	 * Translators are always defined using a struct or union type, so if
27974763Scg	 * we are attempting to translate to type "T *", we internally look
28074763Scg	 * for a translation to type "T" by following the pointer reference.
28150723Scg	 */
28289774Sscottl	if (ptr) {
28350723Scg		dst_type = ctf_type_reference(dst_ctfp, dst_type);
28450723Scg		dst_base = ctf_type_resolve(dst_ctfp, dst_type);
28550723Scg		dst_kind = ctf_type_kind(dst_ctfp, dst_base);
28629415Sjmg	}
28729415Sjmg
28867803Scg	if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
28967803Scg		return (NULL); /* fail if the output isn't a struct or union */
29067803Scg
29167803Scg	/*
29267803Scg	 * In order to find a matching translator, we iterate over the set of
29367803Scg	 * available translators in three passes.  First, we look for a
29467803Scg	 * translation from the exact source type to the resolved destination.
29567803Scg	 * Second, we look for a translation from the resolved source type to
29667803Scg	 * the resolved destination.  Third, we look for a translation from a
29767803Scg	 * compatible source type (using the same rules as parameter formals)
29867803Scg	 * to the resolved destination.  If all passes fail, return NULL.
29967803Scg	 */
30067803Scg	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
30167803Scg	    dxp = dt_list_next(dxp)) {
30267803Scg		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
30367803Scg		    src_ctfp, src_type) &&
30467803Scg		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
30567803Scg		    dst_ctfp, dst_base))
30667803Scg			goto out;
30767803Scg	}
30867803Scg
309100953Ssobomax	if (flags & DT_XLATE_EXACT)
31067803Scg		goto out; /* skip remaining passes if exact match required */
31167803Scg
31267803Scg	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
31374763Scg	    dxp = dt_list_next(dxp)) {
31467803Scg		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
31567803Scg		    src_ctfp, src_type) &&
31667803Scg		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
31767803Scg		    dst_ctfp, dst_base))
31867803Scg			goto out;
319100953Ssobomax	}
32067803Scg
32167803Scg	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
32267803Scg	    dxp = dt_list_next(dxp)) {
323100953Ssobomax		dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type,
32467803Scg		    B_FALSE);
32567803Scg		if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
32667803Scg		    dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
32767803Scg			goto out;
32867803Scg	}
32967803Scg
33067803Scgout:
33167803Scg	if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
33267803Scg		return (NULL);	/* no translation available to pointer type */
33367803Scg
334130472Sjosef	if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
335130472Sjosef	    dtp->dt_xlatemode == DT_XL_STATIC)
336130472Sjosef		return (dxp);	/* we succeeded or not allowed to extern */
337130472Sjosef
338130472Sjosef	/*
339130472Sjosef	 * If we get here, then we didn't find an existing translator, but the
340130472Sjosef	 * caller and xlatemode permit us to create an extern to a dynamic one.
341130472Sjosef	 */
342130472Sjosef	src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
343130472Sjosef	src_dtt.dtt_ctfp = src_ctfp;
344130472Sjosef	src_dtt.dtt_type = src_type;
345130472Sjosef
346130472Sjosef	dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name;
34774763Scg	dst_dtt.dtt_ctfp = dst_ctfp;
34867803Scg	dst_dtt.dtt_type = dst_type;
34967803Scg
35067803Scg	return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
35167803Scg}
35267803Scg
35367803Scgdt_xlator_t *
35467803Scgdt_xlator_lookup_id(dtrace_hdl_t *dtp, id_t id)
35567803Scg{
356130472Sjosef	assert(id >= 0 && id < dtp->dt_xlatorid);
357130472Sjosef	return (dtp->dt_xlatormap[id]);
35867803Scg}
35967803Scg
36067803Scgdt_ident_t *
36168376Scgdt_xlator_ident(dt_xlator_t *dxp, ctf_file_t *ctfp, ctf_id_t type)
36267803Scg{
36367803Scg	if (ctf_type_kind(ctfp, ctf_type_resolve(ctfp, type)) == CTF_K_POINTER)
36467803Scg		return (&dxp->dx_ptrid);
36567803Scg	else
36667803Scg		return (&dxp->dx_souid);
36767803Scg}
36867803Scg
36967803Scgdt_node_t *
37067803Scgdt_xlator_member(dt_xlator_t *dxp, const char *name)
37167803Scg{
37274763Scg	dt_node_t *dnp;
37367803Scg
37467803Scg	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
37567803Scg		if (strcmp(dnp->dn_membname, name) == 0)
37667803Scg			return (dnp);
37767803Scg	}
37867803Scg
37967803Scg	return (NULL);
38067803Scg}
38167803Scg
38267803Scgint
38367803Scgdt_xlator_dynamic(const dt_xlator_t *dxp)
38467803Scg{
38567803Scg	return (dxp->dx_locals == NULL);
38667803Scg}
38767803Scg