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
dt_xlator_create_member(const char * name,ctf_id_t type,ulong_t off,void * arg)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 *
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)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
dt_xlator_destroy(dtrace_hdl_t * dtp,dt_xlator_t * dxp)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 *
dt_xlator_lookup(dtrace_hdl_t * dtp,dt_node_t * src,dt_node_t * dst,int flags)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 *
dt_xlator_lookup_id(dtrace_hdl_t * dtp,id_t id)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 *
dt_xlator_ident(dt_xlator_t * dxp,ctf_file_t * ctfp,ctf_id_t type)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 *
dt_xlator_member(dt_xlator_t * dxp,const char * name)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
dt_xlator_dynamic(const dt_xlator_t * dxp)383 dt_xlator_dynamic(const dt_xlator_t *dxp)
384 {
385           return (dxp->dx_locals == NULL);
386 }
387