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