10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
70Sstevel@tonic-gate * with the License.
80Sstevel@tonic-gate *
90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate * See the License for the specific language governing permissions
120Sstevel@tonic-gate * and limitations under the License.
130Sstevel@tonic-gate *
140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate *
200Sstevel@tonic-gate * CDDL HEADER END
210Sstevel@tonic-gate */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
240Sstevel@tonic-gate * Use is subject to license terms.
250Sstevel@tonic-gate */
260Sstevel@tonic-gate
270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
280Sstevel@tonic-gate
290Sstevel@tonic-gate #include <strings.h>
30*265Smws #include <assert.h>
310Sstevel@tonic-gate
320Sstevel@tonic-gate #include <dt_xlator.h>
33*265Smws #include <dt_parser.h>
34*265Smws #include <dt_grammar.h>
35*265Smws #include <dt_module.h>
360Sstevel@tonic-gate #include <dt_impl.h>
370Sstevel@tonic-gate
38*265Smws /*
39*265Smws * Create a member node corresponding to one of the output members of a dynamic
40*265Smws * translator. We set the member's dn_membexpr to a DT_NODE_XLATOR node that
41*265Smws * has dn_op set to DT_TOK_XLATE and refers back to the translator itself. The
42*265Smws * code generator will then use this as the indicator for dynamic translation.
43*265Smws */
44*265Smws /*ARGSUSED*/
45*265Smws static int
dt_xlator_create_member(const char * name,ctf_id_t type,ulong_t off,void * arg)46*265Smws dt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
47*265Smws {
48*265Smws dt_xlator_t *dxp = arg;
49*265Smws dtrace_hdl_t *dtp = dxp->dx_hdl;
50*265Smws dt_node_t *enp, *mnp;
51*265Smws
52*265Smws if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
53*265Smws return (dt_set_errno(dtp, EDT_NOMEM));
54*265Smws
55*265Smws enp->dn_link = dxp->dx_nodes;
56*265Smws dxp->dx_nodes = enp;
57*265Smws
58*265Smws if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
59*265Smws return (dt_set_errno(dtp, EDT_NOMEM));
60*265Smws
61*265Smws mnp->dn_link = dxp->dx_nodes;
62*265Smws dxp->dx_nodes = mnp;
63*265Smws
64*265Smws /*
65*265Smws * For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
66*265Smws * xlator refers back to the translator and whose dn_xmember refers to
67*265Smws * the current member. These refs will be used by dt_cg.c and dt_as.c.
68*265Smws */
69*265Smws enp->dn_op = DT_TOK_XLATE;
70*265Smws enp->dn_xlator = dxp;
71*265Smws enp->dn_xmember = mnp;
72*265Smws dt_node_type_assign(enp, dxp->dx_dst_ctfp, type);
73*265Smws
74*265Smws /*
75*265Smws * For the member itself, we use a DT_NODE_MEMBER as usual with the
76*265Smws * appropriate name, output type, and member expression set to 'enp'.
77*265Smws */
78*265Smws if (dxp->dx_members != NULL) {
79*265Smws assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
80*265Smws enp->dn_link->dn_list = mnp;
81*265Smws } else
82*265Smws dxp->dx_members = mnp;
83*265Smws
84*265Smws mnp->dn_membname = strdup(name);
85*265Smws mnp->dn_membexpr = enp;
86*265Smws dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type);
87*265Smws
88*265Smws if (mnp->dn_membname == NULL)
89*265Smws return (dt_set_errno(dtp, EDT_NOMEM));
90*265Smws
91*265Smws return (0);
92*265Smws }
93*265Smws
940Sstevel@tonic-gate dt_xlator_t *
dt_xlator_create(dtrace_hdl_t * dtp,const dtrace_typeinfo_t * src,const dtrace_typeinfo_t * dst,const char * name,dt_node_t * members,dt_node_t * nodes)950Sstevel@tonic-gate dt_xlator_create(dtrace_hdl_t *dtp,
960Sstevel@tonic-gate const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst,
970Sstevel@tonic-gate const char *name, dt_node_t *members, dt_node_t *nodes)
980Sstevel@tonic-gate {
99*265Smws dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t));
1000Sstevel@tonic-gate dtrace_typeinfo_t ptr = *dst;
101*265Smws dt_xlator_t **map;
102*265Smws dt_node_t *dnp;
103*265Smws uint_t kind;
1040Sstevel@tonic-gate
1050Sstevel@tonic-gate if (dxp == NULL)
1060Sstevel@tonic-gate return (NULL);
1070Sstevel@tonic-gate
108*265Smws dxp->dx_hdl = dtp;
109*265Smws dxp->dx_id = dtp->dt_xlatorid++;
110*265Smws dxp->dx_gen = dtp->dt_gen;
111*265Smws dxp->dx_arg = -1;
112*265Smws
113*265Smws if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) {
114*265Smws dt_free(dtp, dxp);
115*265Smws return (NULL);
116*265Smws }
117*265Smws
118*265Smws dt_list_append(&dtp->dt_xlators, dxp);
119*265Smws bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id);
120*265Smws dt_free(dtp, dtp->dt_xlatormap);
121*265Smws dtp->dt_xlatormap = map;
122*265Smws dtp->dt_xlatormap[dxp->dx_id] = dxp;
123*265Smws
1240Sstevel@tonic-gate if (dt_type_pointer(&ptr) == -1) {
1250Sstevel@tonic-gate ptr.dtt_ctfp = NULL;
1260Sstevel@tonic-gate ptr.dtt_type = CTF_ERR;
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate
129*265Smws dxp->dx_ident = dt_ident_create(name ? name : "T",
130*265Smws DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0,
131*265Smws _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
1320Sstevel@tonic-gate
1330Sstevel@tonic-gate if (dxp->dx_ident == NULL)
1340Sstevel@tonic-gate goto err; /* no memory for identifier */
1350Sstevel@tonic-gate
1360Sstevel@tonic-gate dxp->dx_ident->di_ctfp = src->dtt_ctfp;
1370Sstevel@tonic-gate dxp->dx_ident->di_type = src->dtt_type;
1380Sstevel@tonic-gate
139*265Smws /*
140*265Smws * If an input parameter name is given, this is a static translator
141*265Smws * definition: create an idhash and identifier for the parameter.
142*265Smws */
143*265Smws if (name != NULL) {
144*265Smws dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0);
145*265Smws
146*265Smws if (dxp->dx_locals == NULL)
147*265Smws goto err; /* no memory for identifier hash */
148*265Smws
149*265Smws dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident);
150*265Smws }
151*265Smws
1520Sstevel@tonic-gate dxp->dx_souid.di_name = "translator";
1530Sstevel@tonic-gate dxp->dx_souid.di_kind = DT_IDENT_XLSOU;
1540Sstevel@tonic-gate dxp->dx_souid.di_flags = DT_IDFLG_REF;
155*265Smws dxp->dx_souid.di_id = dxp->dx_id;
1560Sstevel@tonic-gate dxp->dx_souid.di_attr = _dtrace_defattr;
1570Sstevel@tonic-gate dxp->dx_souid.di_ops = &dt_idops_thaw;
1580Sstevel@tonic-gate dxp->dx_souid.di_data = dxp;
1590Sstevel@tonic-gate dxp->dx_souid.di_ctfp = dst->dtt_ctfp;
1600Sstevel@tonic-gate dxp->dx_souid.di_type = dst->dtt_type;
1610Sstevel@tonic-gate dxp->dx_souid.di_gen = dtp->dt_gen;
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate dxp->dx_ptrid.di_name = "translator";
1640Sstevel@tonic-gate dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR;
1650Sstevel@tonic-gate dxp->dx_ptrid.di_flags = DT_IDFLG_REF;
166*265Smws dxp->dx_ptrid.di_id = dxp->dx_id;
1670Sstevel@tonic-gate dxp->dx_ptrid.di_attr = _dtrace_defattr;
1680Sstevel@tonic-gate dxp->dx_ptrid.di_ops = &dt_idops_thaw;
1690Sstevel@tonic-gate dxp->dx_ptrid.di_data = dxp;
1700Sstevel@tonic-gate dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp;
1710Sstevel@tonic-gate dxp->dx_ptrid.di_type = ptr.dtt_type;
1720Sstevel@tonic-gate dxp->dx_ptrid.di_gen = dtp->dt_gen;
1730Sstevel@tonic-gate
1740Sstevel@tonic-gate /*
1750Sstevel@tonic-gate * If a deferred pragma is pending on the keyword "translator", run all
1760Sstevel@tonic-gate * the deferred pragmas on dx_souid and then copy results to dx_ptrid.
1770Sstevel@tonic-gate * See the code in dt_pragma.c for details on deferred ident pragmas.
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL &&
1800Sstevel@tonic-gate dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) {
1810Sstevel@tonic-gate dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid);
1820Sstevel@tonic-gate dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr;
1830Sstevel@tonic-gate dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers;
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate
1860Sstevel@tonic-gate dxp->dx_src_ctfp = src->dtt_ctfp;
1870Sstevel@tonic-gate dxp->dx_src_type = src->dtt_type;
1880Sstevel@tonic-gate dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type);
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate dxp->dx_dst_ctfp = dst->dtt_ctfp;
1910Sstevel@tonic-gate dxp->dx_dst_type = dst->dtt_type;
1920Sstevel@tonic-gate dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type);
1930Sstevel@tonic-gate
194*265Smws kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base);
195*265Smws assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
196*265Smws
197*265Smws /*
198*265Smws * If no input parameter is given, we're making a dynamic translator:
199*265Smws * create member nodes for every member of the output type. Otherwise
200*265Smws * retain the member and allocation node lists presented by the parser.
201*265Smws */
202*265Smws if (name == NULL) {
203*265Smws if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base,
204*265Smws dt_xlator_create_member, dxp) != 0)
205*265Smws goto err;
206*265Smws } else {
207*265Smws dxp->dx_members = members;
208*265Smws dxp->dx_nodes = nodes;
209*265Smws }
210*265Smws
211*265Smws /*
212*265Smws * Assign member IDs to each member and allocate space for DIFOs
213*265Smws * if and when this translator is eventually compiled.
214*265Smws */
215*265Smws for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
216*265Smws dnp->dn_membxlator = dxp;
217*265Smws dnp->dn_membid = dxp->dx_nmembers++;
218*265Smws }
219*265Smws
220*265Smws dxp->dx_membdif = dt_zalloc(dtp,
221*265Smws sizeof (dtrace_difo_t *) * dxp->dx_nmembers);
222*265Smws
223*265Smws if (dxp->dx_membdif == NULL) {
224*265Smws dxp->dx_nmembers = 0;
225*265Smws goto err;
226*265Smws }
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate return (dxp);
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate err:
2310Sstevel@tonic-gate dt_xlator_destroy(dtp, dxp);
2320Sstevel@tonic-gate return (NULL);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate void
dt_xlator_destroy(dtrace_hdl_t * dtp,dt_xlator_t * dxp)2360Sstevel@tonic-gate dt_xlator_destroy(dtrace_hdl_t *dtp, dt_xlator_t *dxp)
2370Sstevel@tonic-gate {
238*265Smws uint_t i;
239*265Smws
2400Sstevel@tonic-gate dt_node_link_free(&dxp->dx_nodes);
241*265Smws
242*265Smws if (dxp->dx_locals != NULL)
243*265Smws dt_idhash_destroy(dxp->dx_locals);
244*265Smws else if (dxp->dx_ident != NULL)
245*265Smws dt_ident_destroy(dxp->dx_ident);
246*265Smws
247*265Smws for (i = 0; i < dxp->dx_nmembers; i++)
248*265Smws dt_difo_free(dtp, dxp->dx_membdif[i]);
249*265Smws
250*265Smws dt_free(dtp, dxp->dx_membdif);
2510Sstevel@tonic-gate dt_list_delete(&dtp->dt_xlators, dxp);
252*265Smws dt_free(dtp, dxp);
2530Sstevel@tonic-gate }
2540Sstevel@tonic-gate
2550Sstevel@tonic-gate dt_xlator_t *
dt_xlator_lookup(dtrace_hdl_t * dtp,dt_node_t * src,dt_node_t * dst,int flags)256*265Smws dt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate ctf_file_t *src_ctfp = src->dn_ctfp;
2590Sstevel@tonic-gate ctf_id_t src_type = src->dn_type;
2600Sstevel@tonic-gate ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);
2610Sstevel@tonic-gate
2620Sstevel@tonic-gate ctf_file_t *dst_ctfp = dst->dn_ctfp;
2630Sstevel@tonic-gate ctf_id_t dst_type = dst->dn_type;
2640Sstevel@tonic-gate ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
265*265Smws uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);
2660Sstevel@tonic-gate
267*265Smws int ptr = dst_kind == CTF_K_POINTER;
268*265Smws dtrace_typeinfo_t src_dtt, dst_dtt;
2690Sstevel@tonic-gate dt_node_t xn = { 0 };
270*265Smws dt_xlator_t *dxp = NULL;
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate if (src_base == CTF_ERR || dst_base == CTF_ERR)
2730Sstevel@tonic-gate return (NULL); /* fail if these are unresolvable types */
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate * Translators are always defined using a struct or union type, so if
2770Sstevel@tonic-gate * we are attempting to translate to type "T *", we internally look
2780Sstevel@tonic-gate * for a translation to type "T" by following the pointer reference.
2790Sstevel@tonic-gate */
2800Sstevel@tonic-gate if (ptr) {
2810Sstevel@tonic-gate dst_type = ctf_type_reference(dst_ctfp, dst_type);
2820Sstevel@tonic-gate dst_base = ctf_type_resolve(dst_ctfp, dst_type);
283*265Smws dst_kind = ctf_type_kind(dst_ctfp, dst_base);
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate
286*265Smws if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
287*265Smws return (NULL); /* fail if the output isn't a struct or union */
288*265Smws
2890Sstevel@tonic-gate /*
2900Sstevel@tonic-gate * In order to find a matching translator, we iterate over the set of
2910Sstevel@tonic-gate * available translators in three passes. First, we look for a
2920Sstevel@tonic-gate * translation from the exact source type to the resolved destination.
2930Sstevel@tonic-gate * Second, we look for a translation from the resolved source type to
2940Sstevel@tonic-gate * the resolved destination. Third, we look for a translation from a
2950Sstevel@tonic-gate * compatible source type (using the same rules as parameter formals)
2960Sstevel@tonic-gate * to the resolved destination. If all passes fail, return NULL.
2970Sstevel@tonic-gate */
2980Sstevel@tonic-gate for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
2990Sstevel@tonic-gate dxp = dt_list_next(dxp)) {
3000Sstevel@tonic-gate if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
3010Sstevel@tonic-gate src_ctfp, src_type) &&
3020Sstevel@tonic-gate ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
3030Sstevel@tonic-gate dst_ctfp, dst_base))
3040Sstevel@tonic-gate goto out;
3050Sstevel@tonic-gate }
3060Sstevel@tonic-gate
307*265Smws if (flags & DT_XLATE_EXACT)
3080Sstevel@tonic-gate goto out; /* skip remaining passes if exact match required */
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
3110Sstevel@tonic-gate dxp = dt_list_next(dxp)) {
3120Sstevel@tonic-gate if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
3130Sstevel@tonic-gate src_ctfp, src_type) &&
3140Sstevel@tonic-gate ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
3150Sstevel@tonic-gate dst_ctfp, dst_base))
3160Sstevel@tonic-gate goto out;
3170Sstevel@tonic-gate }
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
3200Sstevel@tonic-gate dxp = dt_list_next(dxp)) {
3210Sstevel@tonic-gate dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type);
3220Sstevel@tonic-gate if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
3230Sstevel@tonic-gate dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
3240Sstevel@tonic-gate goto out;
3250Sstevel@tonic-gate }
3260Sstevel@tonic-gate
3270Sstevel@tonic-gate out:
3280Sstevel@tonic-gate if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
329*265Smws return (NULL); /* no translation available to pointer type */
330*265Smws
331*265Smws if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
332*265Smws dtp->dt_xlatemode == DT_XL_STATIC)
333*265Smws return (dxp); /* we succeeded or not allowed to extern */
3340Sstevel@tonic-gate
335*265Smws /*
336*265Smws * If we get here, then we didn't find an existing translator, but the
337*265Smws * caller and xlatemode permit us to create an extern to a dynamic one.
338*265Smws */
339*265Smws src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
340*265Smws src_dtt.dtt_ctfp = src_ctfp;
341*265Smws src_dtt.dtt_type = src_type;
342*265Smws
343*265Smws dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name;
344*265Smws dst_dtt.dtt_ctfp = dst_ctfp;
345*265Smws dst_dtt.dtt_type = dst_type;
346*265Smws
347*265Smws return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
348*265Smws }
349*265Smws
350*265Smws dt_xlator_t *
dt_xlator_lookup_id(dtrace_hdl_t * dtp,id_t id)351*265Smws dt_xlator_lookup_id(dtrace_hdl_t *dtp, id_t id)
352*265Smws {
353*265Smws assert(id >= 0 && id < dtp->dt_xlatorid);
354*265Smws return (dtp->dt_xlatormap[id]);
3550Sstevel@tonic-gate }
3560Sstevel@tonic-gate
3570Sstevel@tonic-gate dt_ident_t *
dt_xlator_ident(dt_xlator_t * dxp,ctf_file_t * ctfp,ctf_id_t type)3580Sstevel@tonic-gate dt_xlator_ident(dt_xlator_t *dxp, ctf_file_t *ctfp, ctf_id_t type)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate if (ctf_type_kind(ctfp, ctf_type_resolve(ctfp, type)) == CTF_K_POINTER)
3610Sstevel@tonic-gate return (&dxp->dx_ptrid);
3620Sstevel@tonic-gate else
3630Sstevel@tonic-gate return (&dxp->dx_souid);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
3660Sstevel@tonic-gate dt_node_t *
dt_xlator_member(dt_xlator_t * dxp,const char * name)3670Sstevel@tonic-gate dt_xlator_member(dt_xlator_t *dxp, const char *name)
3680Sstevel@tonic-gate {
3690Sstevel@tonic-gate dt_node_t *dnp;
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
3720Sstevel@tonic-gate if (strcmp(dnp->dn_membname, name) == 0)
3730Sstevel@tonic-gate return (dnp);
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate
3760Sstevel@tonic-gate return (NULL);
3770Sstevel@tonic-gate }
378*265Smws
379*265Smws int
dt_xlator_dynamic(const dt_xlator_t * dxp)380*265Smws dt_xlator_dynamic(const dt_xlator_t *dxp)
381*265Smws {
382*265Smws return (dxp->dx_locals == NULL);
383*265Smws }
384