Home | History | Annotate | Line # | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License, Version 1.0 only
      6  * (the "License").  You may not use this file except in compliance
      7  * with the License.
      8  *
      9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
     10  * or http://www.opensolaris.org/os/licensing.
     11  * See the License for the specific language governing permissions
     12  * and limitations under the License.
     13  *
     14  * When distributing Covered Code, include this CDDL HEADER in each
     15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     16  * If applicable, add the following below this CDDL HEADER, with the
     17  * fields enclosed by brackets "[]" replaced with your own identifying
     18  * information: Portions Copyright [yyyy] [name of copyright owner]
     19  *
     20  * CDDL HEADER END
     21  */
     22 /*
     23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
     24  * Use is subject to license terms.
     25  */
     26 /*
     27  * Copyright (c) 2013 by Delphix. All rights reserved.
     28  * Copyright (c) 2013 Joyent, Inc. All rights reserved.
     29  */
     30 
     31 #include <strings.h>
     32 #include <assert.h>
     33 
     34 #include <dt_xlator.h>
     35 #include <dt_parser.h>
     36 #include <dt_grammar.h>
     37 #include <dt_module.h>
     38 #include <dt_impl.h>
     39 
     40 /*
     41  * Create a member node corresponding to one of the output members of a dynamic
     42  * translator.  We set the member's dn_membexpr to a DT_NODE_XLATOR node that
     43  * has dn_op set to DT_TOK_XLATE and refers back to the translator itself.  The
     44  * code generator will then use this as the indicator for dynamic translation.
     45  */
     46 /*ARGSUSED*/
     47 static int
     48 dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
     49 {
     50 	dt_xlator_t *dxp = arg;
     51 	dtrace_hdl_t *dtp = dxp->dx_hdl;
     52 	dt_node_t *enp, *mnp;
     53 
     54 	if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
     55 		return (dt_set_errno(dtp, EDT_NOMEM));
     56 
     57 	enp->dn_link = dxp->dx_nodes;
     58 	dxp->dx_nodes = enp;
     59 
     60 	if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
     61 		return (dt_set_errno(dtp, EDT_NOMEM));
     62 
     63 	mnp->dn_link = dxp->dx_nodes;
     64 	dxp->dx_nodes = mnp;
     65 
     66 	/*
     67 	 * For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
     68 	 * xlator refers back to the translator and whose dn_xmember refers to
     69 	 * the current member.  These refs will be used by dt_cg.c and dt_as.c.
     70 	 */
     71 	enp->dn_op = DT_TOK_XLATE;
     72 	enp->dn_xlator = dxp;
     73 	enp->dn_xmember = mnp;
     74 	dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE);
     75 
     76 	/*
     77 	 * For the member itself, we use a DT_NODE_MEMBER as usual with the
     78 	 * appropriate name, output type, and member expression set to 'enp'.
     79 	 */
     80 	if (dxp->dx_members != NULL) {
     81 		assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
     82 		enp->dn_link->dn_list = mnp;
     83 	} else
     84 		dxp->dx_members = mnp;
     85 
     86 	mnp->dn_membname = strdup(name);
     87 	mnp->dn_membexpr = enp;
     88 	dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE);
     89 
     90 	if (mnp->dn_membname == NULL)
     91 		return (dt_set_errno(dtp, EDT_NOMEM));
     92 
     93 	return (0);
     94 }
     95 
     96 dt_xlator_t *
     97 dt_xlator_create(dtrace_hdl_t *dtp,
     98     const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst,
     99     const char *name, dt_node_t *members, dt_node_t *nodes)
    100 {
    101 	dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t));
    102 	dtrace_typeinfo_t ptr = *dst;
    103 	dt_xlator_t **map;
    104 	dt_node_t *dnp;
    105 	uint_t kind;
    106 
    107 	if (dxp == NULL)
    108 		return (NULL);
    109 
    110 	dxp->dx_hdl = dtp;
    111 	dxp->dx_id = dtp->dt_xlatorid++;
    112 	dxp->dx_gen = dtp->dt_gen;
    113 	dxp->dx_arg = -1;
    114 
    115 	if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) {
    116 		dt_free(dtp, dxp);
    117 		return (NULL);
    118 	}
    119 
    120 	dt_list_append(&dtp->dt_xlators, dxp);
    121 	bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id);
    122 	dt_free(dtp, dtp->dt_xlatormap);
    123 	dtp->dt_xlatormap = map;
    124 	dtp->dt_xlatormap[dxp->dx_id] = dxp;
    125 
    126 	if (dt_type_pointer(&ptr) == -1) {
    127 		ptr.dtt_ctfp = NULL;
    128 		ptr.dtt_type = CTF_ERR;
    129 	}
    130 
    131 	dxp->dx_ident = dt_ident_create(name ? name : "T",
    132 	    DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0,
    133 	    _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
    134 
    135 	if (dxp->dx_ident == NULL)
    136 		goto err; /* no memory for identifier */
    137 
    138 	dxp->dx_ident->di_ctfp = src->dtt_ctfp;
    139 	dxp->dx_ident->di_type = src->dtt_type;
    140 
    141 	/*
    142 	 * If an input parameter name is given, this is a static translator
    143 	 * definition: create an idhash and identifier for the parameter.
    144 	 */
    145 	if (name != NULL) {
    146 		dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0);
    147 
    148 		if (dxp->dx_locals == NULL)
    149 			goto err; /* no memory for identifier hash */
    150 
    151 		dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident);
    152 	}
    153 
    154 	dxp->dx_souid.di_name = "translator";
    155 	dxp->dx_souid.di_kind = DT_IDENT_XLSOU;
    156 	dxp->dx_souid.di_flags = DT_IDFLG_REF;
    157 	dxp->dx_souid.di_id = dxp->dx_id;
    158 	dxp->dx_souid.di_attr = _dtrace_defattr;
    159 	dxp->dx_souid.di_ops = &dt_idops_thaw;
    160 	dxp->dx_souid.di_data = dxp;
    161 	dxp->dx_souid.di_ctfp = dst->dtt_ctfp;
    162 	dxp->dx_souid.di_type = dst->dtt_type;
    163 	dxp->dx_souid.di_gen = dtp->dt_gen;
    164 
    165 	dxp->dx_ptrid.di_name = "translator";
    166 	dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR;
    167 	dxp->dx_ptrid.di_flags = DT_IDFLG_REF;
    168 	dxp->dx_ptrid.di_id = dxp->dx_id;
    169 	dxp->dx_ptrid.di_attr = _dtrace_defattr;
    170 	dxp->dx_ptrid.di_ops = &dt_idops_thaw;
    171 	dxp->dx_ptrid.di_data = dxp;
    172 	dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp;
    173 	dxp->dx_ptrid.di_type = ptr.dtt_type;
    174 	dxp->dx_ptrid.di_gen = dtp->dt_gen;
    175 
    176 	/*
    177 	 * If a deferred pragma is pending on the keyword "translator", run all
    178 	 * the deferred pragmas on dx_souid and then copy results to dx_ptrid.
    179 	 * See the code in dt_pragma.c for details on deferred ident pragmas.
    180 	 */
    181 	if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL &&
    182 	    dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) {
    183 		dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid);
    184 		dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr;
    185 		dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers;
    186 	}
    187 
    188 	dxp->dx_src_ctfp = src->dtt_ctfp;
    189 	dxp->dx_src_type = src->dtt_type;
    190 	dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type);
    191 
    192 	dxp->dx_dst_ctfp = dst->dtt_ctfp;
    193 	dxp->dx_dst_type = dst->dtt_type;
    194 	dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type);
    195 
    196 	kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base);
    197 	assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
    198 
    199 	/*
    200 	 * If no input parameter is given, we're making a dynamic translator:
    201 	 * create member nodes for every member of the output type.  Otherwise
    202 	 * retain the member and allocation node lists presented by the parser.
    203 	 */
    204 	if (name == NULL) {
    205 		if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base,
    206 		    dt_xlator_create_member, dxp) != 0)
    207 			goto err;
    208 	} else {
    209 		dxp->dx_members = members;
    210 		dxp->dx_nodes = nodes;
    211 	}
    212 
    213 	/*
    214 	 * Assign member IDs to each member and allocate space for DIFOs
    215 	 * if and when this translator is eventually compiled.
    216 	 */
    217 	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
    218 		dnp->dn_membxlator = dxp;
    219 		dnp->dn_membid = dxp->dx_nmembers++;
    220 	}
    221 
    222 	dxp->dx_membdif = dt_zalloc(dtp,
    223 	    sizeof (dtrace_difo_t *) * dxp->dx_nmembers);
    224 
    225 	if (dxp->dx_membdif == NULL) {
    226 		dxp->dx_nmembers = 0;
    227 		goto err;
    228 	}
    229 
    230 	return (dxp);
    231 
    232 err:
    233 	dt_xlator_destroy(dtp, dxp);
    234 	return (NULL);
    235 }
    236 
    237 void
    238 dt_xlator_destroy(dtrace_hdl_t *dtp, dt_xlator_t *dxp)
    239 {
    240 	uint_t i;
    241 
    242 	dt_node_link_free(&dxp->dx_nodes);
    243 
    244 	if (dxp->dx_locals != NULL)
    245 		dt_idhash_destroy(dxp->dx_locals);
    246 	else if (dxp->dx_ident != NULL)
    247 		dt_ident_destroy(dxp->dx_ident);
    248 
    249 	for (i = 0; i < dxp->dx_nmembers; i++)
    250 		dt_difo_free(dtp, dxp->dx_membdif[i]);
    251 
    252 	dt_free(dtp, dxp->dx_membdif);
    253 	dt_list_delete(&dtp->dt_xlators, dxp);
    254 	dt_free(dtp, dxp);
    255 }
    256 
    257 dt_xlator_t *
    258 dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
    259 {
    260 	ctf_file_t *src_ctfp = src->dn_ctfp;
    261 	ctf_id_t src_type = src->dn_type;
    262 	ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);
    263 
    264 	ctf_file_t *dst_ctfp = dst->dn_ctfp;
    265 	ctf_id_t dst_type = dst->dn_type;
    266 	ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
    267 	uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);
    268 
    269 	int ptr = dst_kind == CTF_K_POINTER;
    270 	dtrace_typeinfo_t src_dtt, dst_dtt;
    271 	dt_node_t xn = { 0 };
    272 	dt_xlator_t *dxp = NULL;
    273 
    274 	if (src_base == CTF_ERR || dst_base == CTF_ERR)
    275 		return (NULL); /* fail if these are unresolvable types */
    276 
    277 	/*
    278 	 * Translators are always defined using a struct or union type, so if
    279 	 * we are attempting to translate to type "T *", we internally look
    280 	 * for a translation to type "T" by following the pointer reference.
    281 	 */
    282 	if (ptr) {
    283 		dst_type = ctf_type_reference(dst_ctfp, dst_type);
    284 		dst_base = ctf_type_resolve(dst_ctfp, dst_type);
    285 		dst_kind = ctf_type_kind(dst_ctfp, dst_base);
    286 	}
    287 
    288 	if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
    289 		return (NULL); /* fail if the output isn't a struct or union */
    290 
    291 	/*
    292 	 * In order to find a matching translator, we iterate over the set of
    293 	 * available translators in three passes.  First, we look for a
    294 	 * translation from the exact source type to the resolved destination.
    295 	 * Second, we look for a translation from the resolved source type to
    296 	 * the resolved destination.  Third, we look for a translation from a
    297 	 * compatible source type (using the same rules as parameter formals)
    298 	 * to the resolved destination.  If all passes fail, return NULL.
    299 	 */
    300 	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
    301 	    dxp = dt_list_next(dxp)) {
    302 		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
    303 		    src_ctfp, src_type) &&
    304 		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
    305 		    dst_ctfp, dst_base))
    306 			goto out;
    307 	}
    308 
    309 	if (flags & DT_XLATE_EXACT)
    310 		goto out; /* skip remaining passes if exact match required */
    311 
    312 	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
    313 	    dxp = dt_list_next(dxp)) {
    314 		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
    315 		    src_ctfp, src_type) &&
    316 		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
    317 		    dst_ctfp, dst_base))
    318 			goto out;
    319 	}
    320 
    321 	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
    322 	    dxp = dt_list_next(dxp)) {
    323 		dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type,
    324 		    B_FALSE);
    325 		if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
    326 		    dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
    327 			goto out;
    328 	}
    329 
    330 out:
    331 	if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
    332 		return (NULL);	/* no translation available to pointer type */
    333 
    334 	if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
    335 	    dtp->dt_xlatemode == DT_XL_STATIC)
    336 		return (dxp);	/* we succeeded or not allowed to extern */
    337 
    338 	/*
    339 	 * If we get here, then we didn't find an existing translator, but the
    340 	 * caller and xlatemode permit us to create an extern to a dynamic one.
    341 	 */
    342 	src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
    343 	src_dtt.dtt_ctfp = src_ctfp;
    344 	src_dtt.dtt_type = src_type;
    345 
    346 	dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name;
    347 	dst_dtt.dtt_ctfp = dst_ctfp;
    348 	dst_dtt.dtt_type = dst_type;
    349 
    350 	return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
    351 }
    352 
    353 dt_xlator_t *
    354 dt_xlator_lookup_id(dtrace_hdl_t *dtp, id_t id)
    355 {
    356 	assert(id >= 0 && id < dtp->dt_xlatorid);
    357 	return (dtp->dt_xlatormap[id]);
    358 }
    359 
    360 dt_ident_t *
    361 dt_xlator_ident(dt_xlator_t *dxp, ctf_file_t *ctfp, ctf_id_t type)
    362 {
    363 	if (ctf_type_kind(ctfp, ctf_type_resolve(ctfp, type)) == CTF_K_POINTER)
    364 		return (&dxp->dx_ptrid);
    365 	else
    366 		return (&dxp->dx_souid);
    367 }
    368 
    369 dt_node_t *
    370 dt_xlator_member(dt_xlator_t *dxp, const char *name)
    371 {
    372 	dt_node_t *dnp;
    373 
    374 	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
    375 		if (strcmp(dnp->dn_membname, name) == 0)
    376 			return (dnp);
    377 	}
    378 
    379 	return (NULL);
    380 }
    381 
    382 int
    383 dt_xlator_dynamic(const dt_xlator_t *dxp)
    384 {
    385 	return (dxp->dx_locals == NULL);
    386 }
    387