1178479Sjb/*
2178479Sjb * CDDL HEADER START
3178479Sjb *
4178479Sjb * The contents of this file are subject to the terms of the
5178479Sjb * Common Development and Distribution License, Version 1.0 only
6178479Sjb * (the "License").  You may not use this file except in compliance
7178479Sjb * with the License.
8178479Sjb *
9178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10178479Sjb * or http://www.opensolaris.org/os/licensing.
11178479Sjb * See the License for the specific language governing permissions
12178479Sjb * and limitations under the License.
13178479Sjb *
14178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
15178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16178479Sjb * If applicable, add the following below this CDDL HEADER, with the
17178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
18178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
19178479Sjb *
20178479Sjb * CDDL HEADER END
21178479Sjb */
22178479Sjb/*
23178479Sjb * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24178479Sjb * Use is subject to license terms.
25178479Sjb */
26268578Srpaulo/*
27268578Srpaulo * Copyright (c) 2013 by Delphix. All rights reserved.
28268578Srpaulo * Copyright (c) 2013 Joyent, Inc. All rights reserved.
29268578Srpaulo */
30178479Sjb
31178479Sjb#include <strings.h>
32178479Sjb#include <assert.h>
33178479Sjb
34178479Sjb#include <dt_xlator.h>
35178479Sjb#include <dt_parser.h>
36178479Sjb#include <dt_grammar.h>
37178479Sjb#include <dt_module.h>
38178479Sjb#include <dt_impl.h>
39178479Sjb
40178479Sjb/*
41178479Sjb * Create a member node corresponding to one of the output members of a dynamic
42178479Sjb * translator.  We set the member's dn_membexpr to a DT_NODE_XLATOR node that
43178479Sjb * has dn_op set to DT_TOK_XLATE and refers back to the translator itself.  The
44178479Sjb * code generator will then use this as the indicator for dynamic translation.
45178479Sjb */
46178479Sjb/*ARGSUSED*/
47178479Sjbstatic int
48178479Sjbdt_xlator_create_member(const char *name, ctf_id_t type, ulong_t off, void *arg)
49178479Sjb{
50178479Sjb	dt_xlator_t *dxp = arg;
51178479Sjb	dtrace_hdl_t *dtp = dxp->dx_hdl;
52178479Sjb	dt_node_t *enp, *mnp;
53178479Sjb
54178479Sjb	if ((enp = dt_node_xalloc(dtp, DT_NODE_XLATOR)) == NULL)
55178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
56178479Sjb
57178479Sjb	enp->dn_link = dxp->dx_nodes;
58178479Sjb	dxp->dx_nodes = enp;
59178479Sjb
60178479Sjb	if ((mnp = dt_node_xalloc(dtp, DT_NODE_MEMBER)) == NULL)
61178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
62178479Sjb
63178479Sjb	mnp->dn_link = dxp->dx_nodes;
64178479Sjb	dxp->dx_nodes = mnp;
65178479Sjb
66178479Sjb	/*
67178479Sjb	 * For the member expression, we use a DT_NODE_XLATOR/TOK_XLATE whose
68178479Sjb	 * xlator refers back to the translator and whose dn_xmember refers to
69178479Sjb	 * the current member.  These refs will be used by dt_cg.c and dt_as.c.
70178479Sjb	 */
71178479Sjb	enp->dn_op = DT_TOK_XLATE;
72178479Sjb	enp->dn_xlator = dxp;
73178479Sjb	enp->dn_xmember = mnp;
74268578Srpaulo	dt_node_type_assign(enp, dxp->dx_dst_ctfp, type, B_FALSE);
75178479Sjb
76178479Sjb	/*
77178479Sjb	 * For the member itself, we use a DT_NODE_MEMBER as usual with the
78178479Sjb	 * appropriate name, output type, and member expression set to 'enp'.
79178479Sjb	 */
80178479Sjb	if (dxp->dx_members != NULL) {
81178479Sjb		assert(enp->dn_link->dn_kind == DT_NODE_MEMBER);
82178479Sjb		enp->dn_link->dn_list = mnp;
83178479Sjb	} else
84178479Sjb		dxp->dx_members = mnp;
85178479Sjb
86178479Sjb	mnp->dn_membname = strdup(name);
87178479Sjb	mnp->dn_membexpr = enp;
88268578Srpaulo	dt_node_type_assign(mnp, dxp->dx_dst_ctfp, type, B_FALSE);
89178479Sjb
90178479Sjb	if (mnp->dn_membname == NULL)
91178479Sjb		return (dt_set_errno(dtp, EDT_NOMEM));
92178479Sjb
93178479Sjb	return (0);
94178479Sjb}
95178479Sjb
96178479Sjbdt_xlator_t *
97178479Sjbdt_xlator_create(dtrace_hdl_t *dtp,
98178479Sjb    const dtrace_typeinfo_t *src, const dtrace_typeinfo_t *dst,
99178479Sjb    const char *name, dt_node_t *members, dt_node_t *nodes)
100178479Sjb{
101178479Sjb	dt_xlator_t *dxp = dt_zalloc(dtp, sizeof (dt_xlator_t));
102178479Sjb	dtrace_typeinfo_t ptr = *dst;
103178479Sjb	dt_xlator_t **map;
104178479Sjb	dt_node_t *dnp;
105178479Sjb	uint_t kind;
106178479Sjb
107178479Sjb	if (dxp == NULL)
108178479Sjb		return (NULL);
109178479Sjb
110178479Sjb	dxp->dx_hdl = dtp;
111178479Sjb	dxp->dx_id = dtp->dt_xlatorid++;
112178479Sjb	dxp->dx_gen = dtp->dt_gen;
113178479Sjb	dxp->dx_arg = -1;
114178479Sjb
115178479Sjb	if ((map = dt_alloc(dtp, sizeof (void *) * (dxp->dx_id + 1))) == NULL) {
116178479Sjb		dt_free(dtp, dxp);
117178479Sjb		return (NULL);
118178479Sjb	}
119178479Sjb
120178479Sjb	dt_list_append(&dtp->dt_xlators, dxp);
121178479Sjb	bcopy(dtp->dt_xlatormap, map, sizeof (void *) * dxp->dx_id);
122178479Sjb	dt_free(dtp, dtp->dt_xlatormap);
123178479Sjb	dtp->dt_xlatormap = map;
124178479Sjb	dtp->dt_xlatormap[dxp->dx_id] = dxp;
125178479Sjb
126178479Sjb	if (dt_type_pointer(&ptr) == -1) {
127178479Sjb		ptr.dtt_ctfp = NULL;
128178479Sjb		ptr.dtt_type = CTF_ERR;
129178479Sjb	}
130178479Sjb
131178479Sjb	dxp->dx_ident = dt_ident_create(name ? name : "T",
132178479Sjb	    DT_IDENT_SCALAR, DT_IDFLG_REF | DT_IDFLG_ORPHAN, 0,
133178479Sjb	    _dtrace_defattr, 0, &dt_idops_thaw, NULL, dtp->dt_gen);
134178479Sjb
135178479Sjb	if (dxp->dx_ident == NULL)
136178479Sjb		goto err; /* no memory for identifier */
137178479Sjb
138178479Sjb	dxp->dx_ident->di_ctfp = src->dtt_ctfp;
139178479Sjb	dxp->dx_ident->di_type = src->dtt_type;
140178479Sjb
141178479Sjb	/*
142178479Sjb	 * If an input parameter name is given, this is a static translator
143178479Sjb	 * definition: create an idhash and identifier for the parameter.
144178479Sjb	 */
145178479Sjb	if (name != NULL) {
146178479Sjb		dxp->dx_locals = dt_idhash_create("xlparams", NULL, 0, 0);
147178479Sjb
148178479Sjb		if (dxp->dx_locals == NULL)
149178479Sjb			goto err; /* no memory for identifier hash */
150178479Sjb
151178479Sjb		dt_idhash_xinsert(dxp->dx_locals, dxp->dx_ident);
152178479Sjb	}
153178479Sjb
154178479Sjb	dxp->dx_souid.di_name = "translator";
155178479Sjb	dxp->dx_souid.di_kind = DT_IDENT_XLSOU;
156178479Sjb	dxp->dx_souid.di_flags = DT_IDFLG_REF;
157178479Sjb	dxp->dx_souid.di_id = dxp->dx_id;
158178479Sjb	dxp->dx_souid.di_attr = _dtrace_defattr;
159178479Sjb	dxp->dx_souid.di_ops = &dt_idops_thaw;
160178479Sjb	dxp->dx_souid.di_data = dxp;
161178479Sjb	dxp->dx_souid.di_ctfp = dst->dtt_ctfp;
162178479Sjb	dxp->dx_souid.di_type = dst->dtt_type;
163178479Sjb	dxp->dx_souid.di_gen = dtp->dt_gen;
164178479Sjb
165178479Sjb	dxp->dx_ptrid.di_name = "translator";
166178479Sjb	dxp->dx_ptrid.di_kind = DT_IDENT_XLPTR;
167178479Sjb	dxp->dx_ptrid.di_flags = DT_IDFLG_REF;
168178479Sjb	dxp->dx_ptrid.di_id = dxp->dx_id;
169178479Sjb	dxp->dx_ptrid.di_attr = _dtrace_defattr;
170178479Sjb	dxp->dx_ptrid.di_ops = &dt_idops_thaw;
171178479Sjb	dxp->dx_ptrid.di_data = dxp;
172178479Sjb	dxp->dx_ptrid.di_ctfp = ptr.dtt_ctfp;
173178479Sjb	dxp->dx_ptrid.di_type = ptr.dtt_type;
174178479Sjb	dxp->dx_ptrid.di_gen = dtp->dt_gen;
175178479Sjb
176178479Sjb	/*
177178479Sjb	 * If a deferred pragma is pending on the keyword "translator", run all
178178479Sjb	 * the deferred pragmas on dx_souid and then copy results to dx_ptrid.
179178479Sjb	 * See the code in dt_pragma.c for details on deferred ident pragmas.
180178479Sjb	 */
181178479Sjb	if (dtp->dt_globals->dh_defer != NULL && yypcb->pcb_pragmas != NULL &&
182178479Sjb	    dt_idhash_lookup(yypcb->pcb_pragmas, "translator") != NULL) {
183178479Sjb		dtp->dt_globals->dh_defer(dtp->dt_globals, &dxp->dx_souid);
184178479Sjb		dxp->dx_ptrid.di_attr = dxp->dx_souid.di_attr;
185178479Sjb		dxp->dx_ptrid.di_vers = dxp->dx_souid.di_vers;
186178479Sjb	}
187178479Sjb
188178479Sjb	dxp->dx_src_ctfp = src->dtt_ctfp;
189178479Sjb	dxp->dx_src_type = src->dtt_type;
190178479Sjb	dxp->dx_src_base = ctf_type_resolve(src->dtt_ctfp, src->dtt_type);
191178479Sjb
192178479Sjb	dxp->dx_dst_ctfp = dst->dtt_ctfp;
193178479Sjb	dxp->dx_dst_type = dst->dtt_type;
194178479Sjb	dxp->dx_dst_base = ctf_type_resolve(dst->dtt_ctfp, dst->dtt_type);
195178479Sjb
196178479Sjb	kind = ctf_type_kind(dst->dtt_ctfp, dxp->dx_dst_base);
197178479Sjb	assert(kind == CTF_K_STRUCT || kind == CTF_K_UNION);
198178479Sjb
199178479Sjb	/*
200178479Sjb	 * If no input parameter is given, we're making a dynamic translator:
201178479Sjb	 * create member nodes for every member of the output type.  Otherwise
202178479Sjb	 * retain the member and allocation node lists presented by the parser.
203178479Sjb	 */
204178479Sjb	if (name == NULL) {
205178479Sjb		if (ctf_member_iter(dxp->dx_dst_ctfp, dxp->dx_dst_base,
206178479Sjb		    dt_xlator_create_member, dxp) != 0)
207178479Sjb			goto err;
208178479Sjb	} else {
209178479Sjb		dxp->dx_members = members;
210178479Sjb		dxp->dx_nodes = nodes;
211178479Sjb	}
212178479Sjb
213178479Sjb	/*
214178479Sjb	 * Assign member IDs to each member and allocate space for DIFOs
215178479Sjb	 * if and when this translator is eventually compiled.
216178479Sjb	 */
217178479Sjb	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
218178479Sjb		dnp->dn_membxlator = dxp;
219178479Sjb		dnp->dn_membid = dxp->dx_nmembers++;
220178479Sjb	}
221178479Sjb
222178479Sjb	dxp->dx_membdif = dt_zalloc(dtp,
223178479Sjb	    sizeof (dtrace_difo_t *) * dxp->dx_nmembers);
224178479Sjb
225178479Sjb	if (dxp->dx_membdif == NULL) {
226178479Sjb		dxp->dx_nmembers = 0;
227178479Sjb		goto err;
228178479Sjb	}
229178479Sjb
230178479Sjb	return (dxp);
231178479Sjb
232178479Sjberr:
233178479Sjb	dt_xlator_destroy(dtp, dxp);
234178479Sjb	return (NULL);
235178479Sjb}
236178479Sjb
237178479Sjbvoid
238178479Sjbdt_xlator_destroy(dtrace_hdl_t *dtp, dt_xlator_t *dxp)
239178479Sjb{
240178479Sjb	uint_t i;
241178479Sjb
242178479Sjb	dt_node_link_free(&dxp->dx_nodes);
243178479Sjb
244178479Sjb	if (dxp->dx_locals != NULL)
245178479Sjb		dt_idhash_destroy(dxp->dx_locals);
246178479Sjb	else if (dxp->dx_ident != NULL)
247178479Sjb		dt_ident_destroy(dxp->dx_ident);
248178479Sjb
249178479Sjb	for (i = 0; i < dxp->dx_nmembers; i++)
250178479Sjb		dt_difo_free(dtp, dxp->dx_membdif[i]);
251178479Sjb
252178479Sjb	dt_free(dtp, dxp->dx_membdif);
253178479Sjb	dt_list_delete(&dtp->dt_xlators, dxp);
254178479Sjb	dt_free(dtp, dxp);
255178479Sjb}
256178479Sjb
257178479Sjbdt_xlator_t *
258178479Sjbdt_xlator_lookup(dtrace_hdl_t *dtp, dt_node_t *src, dt_node_t *dst, int flags)
259178479Sjb{
260178479Sjb	ctf_file_t *src_ctfp = src->dn_ctfp;
261178479Sjb	ctf_id_t src_type = src->dn_type;
262178479Sjb	ctf_id_t src_base = ctf_type_resolve(src_ctfp, src_type);
263178479Sjb
264178479Sjb	ctf_file_t *dst_ctfp = dst->dn_ctfp;
265178479Sjb	ctf_id_t dst_type = dst->dn_type;
266178479Sjb	ctf_id_t dst_base = ctf_type_resolve(dst_ctfp, dst_type);
267178479Sjb	uint_t dst_kind = ctf_type_kind(dst_ctfp, dst_base);
268178479Sjb
269178479Sjb	int ptr = dst_kind == CTF_K_POINTER;
270178479Sjb	dtrace_typeinfo_t src_dtt, dst_dtt;
271178479Sjb	dt_node_t xn = { 0 };
272178479Sjb	dt_xlator_t *dxp = NULL;
273178479Sjb
274178479Sjb	if (src_base == CTF_ERR || dst_base == CTF_ERR)
275178479Sjb		return (NULL); /* fail if these are unresolvable types */
276178479Sjb
277178479Sjb	/*
278178479Sjb	 * Translators are always defined using a struct or union type, so if
279178479Sjb	 * we are attempting to translate to type "T *", we internally look
280178479Sjb	 * for a translation to type "T" by following the pointer reference.
281178479Sjb	 */
282178479Sjb	if (ptr) {
283178479Sjb		dst_type = ctf_type_reference(dst_ctfp, dst_type);
284178479Sjb		dst_base = ctf_type_resolve(dst_ctfp, dst_type);
285178479Sjb		dst_kind = ctf_type_kind(dst_ctfp, dst_base);
286178479Sjb	}
287178479Sjb
288178479Sjb	if (dst_kind != CTF_K_UNION && dst_kind != CTF_K_STRUCT)
289178479Sjb		return (NULL); /* fail if the output isn't a struct or union */
290178479Sjb
291178479Sjb	/*
292178479Sjb	 * In order to find a matching translator, we iterate over the set of
293178479Sjb	 * available translators in three passes.  First, we look for a
294178479Sjb	 * translation from the exact source type to the resolved destination.
295178479Sjb	 * Second, we look for a translation from the resolved source type to
296178479Sjb	 * the resolved destination.  Third, we look for a translation from a
297178479Sjb	 * compatible source type (using the same rules as parameter formals)
298178479Sjb	 * to the resolved destination.  If all passes fail, return NULL.
299178479Sjb	 */
300178479Sjb	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
301178479Sjb	    dxp = dt_list_next(dxp)) {
302178479Sjb		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_type,
303178479Sjb		    src_ctfp, src_type) &&
304178479Sjb		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
305178479Sjb		    dst_ctfp, dst_base))
306178479Sjb			goto out;
307178479Sjb	}
308178479Sjb
309178479Sjb	if (flags & DT_XLATE_EXACT)
310178479Sjb		goto out; /* skip remaining passes if exact match required */
311178479Sjb
312178479Sjb	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
313178479Sjb	    dxp = dt_list_next(dxp)) {
314178479Sjb		if (ctf_type_compat(dxp->dx_src_ctfp, dxp->dx_src_base,
315178479Sjb		    src_ctfp, src_type) &&
316178479Sjb		    ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
317178479Sjb		    dst_ctfp, dst_base))
318178479Sjb			goto out;
319178479Sjb	}
320178479Sjb
321178479Sjb	for (dxp = dt_list_next(&dtp->dt_xlators); dxp != NULL;
322178479Sjb	    dxp = dt_list_next(dxp)) {
323268578Srpaulo		dt_node_type_assign(&xn, dxp->dx_src_ctfp, dxp->dx_src_type,
324268578Srpaulo		    B_FALSE);
325178479Sjb		if (ctf_type_compat(dxp->dx_dst_ctfp, dxp->dx_dst_base,
326178479Sjb		    dst_ctfp, dst_base) && dt_node_is_argcompat(src, &xn))
327178479Sjb			goto out;
328178479Sjb	}
329178479Sjb
330178479Sjbout:
331178479Sjb	if (ptr && dxp != NULL && dxp->dx_ptrid.di_type == CTF_ERR)
332178479Sjb		return (NULL);	/* no translation available to pointer type */
333178479Sjb
334178479Sjb	if (dxp != NULL || !(flags & DT_XLATE_EXTERN) ||
335178479Sjb	    dtp->dt_xlatemode == DT_XL_STATIC)
336178479Sjb		return (dxp);	/* we succeeded or not allowed to extern */
337178479Sjb
338178479Sjb	/*
339178479Sjb	 * If we get here, then we didn't find an existing translator, but the
340178479Sjb	 * caller and xlatemode permit us to create an extern to a dynamic one.
341178479Sjb	 */
342178479Sjb	src_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, src_ctfp)->dm_name;
343178479Sjb	src_dtt.dtt_ctfp = src_ctfp;
344178479Sjb	src_dtt.dtt_type = src_type;
345178479Sjb
346178479Sjb	dst_dtt.dtt_object = dt_module_lookup_by_ctf(dtp, dst_ctfp)->dm_name;
347178479Sjb	dst_dtt.dtt_ctfp = dst_ctfp;
348178479Sjb	dst_dtt.dtt_type = dst_type;
349178479Sjb
350178479Sjb	return (dt_xlator_create(dtp, &src_dtt, &dst_dtt, NULL, NULL, NULL));
351178479Sjb}
352178479Sjb
353178479Sjbdt_xlator_t *
354178479Sjbdt_xlator_lookup_id(dtrace_hdl_t *dtp, id_t id)
355178479Sjb{
356178479Sjb	assert(id >= 0 && id < dtp->dt_xlatorid);
357178479Sjb	return (dtp->dt_xlatormap[id]);
358178479Sjb}
359178479Sjb
360178479Sjbdt_ident_t *
361178479Sjbdt_xlator_ident(dt_xlator_t *dxp, ctf_file_t *ctfp, ctf_id_t type)
362178479Sjb{
363178479Sjb	if (ctf_type_kind(ctfp, ctf_type_resolve(ctfp, type)) == CTF_K_POINTER)
364178479Sjb		return (&dxp->dx_ptrid);
365178479Sjb	else
366178479Sjb		return (&dxp->dx_souid);
367178479Sjb}
368178479Sjb
369178479Sjbdt_node_t *
370178479Sjbdt_xlator_member(dt_xlator_t *dxp, const char *name)
371178479Sjb{
372178479Sjb	dt_node_t *dnp;
373178479Sjb
374178479Sjb	for (dnp = dxp->dx_members; dnp != NULL; dnp = dnp->dn_list) {
375178479Sjb		if (strcmp(dnp->dn_membname, name) == 0)
376178479Sjb			return (dnp);
377178479Sjb	}
378178479Sjb
379178479Sjb	return (NULL);
380178479Sjb}
381178479Sjb
382178479Sjbint
383178479Sjbdt_xlator_dynamic(const dt_xlator_t *dxp)
384178479Sjb{
385178479Sjb	return (dxp->dx_locals == NULL);
386178479Sjb}
387