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 (the "License").
6178479Sjb * You may not use this file except in compliance with the License.
7178479Sjb *
8178479Sjb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9178479Sjb * or http://www.opensolaris.org/os/licensing.
10178479Sjb * See the License for the specific language governing permissions
11178479Sjb * and limitations under the License.
12178479Sjb *
13178479Sjb * When distributing Covered Code, include this CDDL HEADER in each
14178479Sjb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15178479Sjb * If applicable, add the following below this CDDL HEADER, with the
16178479Sjb * fields enclosed by brackets "[]" replaced with your own identifying
17178479Sjb * information: Portions Copyright [yyyy] [name of copyright owner]
18178479Sjb *
19178479Sjb * CDDL HEADER END
20178479Sjb */
21178479Sjb
22178479Sjb/*
23178479Sjb * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24178479Sjb * Use is subject to license terms.
25178479Sjb */
26178479Sjb
27178479Sjb#pragma ident	"%Z%%M%	%I%	%E% SMI"
28178479Sjb
29178574Sjb#if defined(sun)
30178479Sjb#include <sys/sysmacros.h>
31178574Sjb#endif
32178479Sjb#include <strings.h>
33178479Sjb#include <stdlib.h>
34178574Sjb#if defined(sun)
35178479Sjb#include <alloca.h>
36178574Sjb#endif
37178479Sjb#include <assert.h>
38178479Sjb#include <errno.h>
39178479Sjb#include <ctype.h>
40178574Sjb#if defined(sun)
41178479Sjb#include <sys/procfs_isa.h>
42178574Sjb#endif
43178479Sjb#include <limits.h>
44178479Sjb
45178479Sjb#include <dt_ident.h>
46178479Sjb#include <dt_parser.h>
47178479Sjb#include <dt_provider.h>
48178479Sjb#include <dt_strtab.h>
49178479Sjb#include <dt_impl.h>
50178479Sjb
51178479Sjb/*
52178479Sjb * Common code for cooking an identifier that uses a typed signature list (we
53178479Sjb * use this for associative arrays and functions).  If the argument list is
54178479Sjb * of the same length and types, then return the return type.  Otherwise
55178479Sjb * print an appropriate compiler error message and abort the compile.
56178479Sjb */
57178479Sjbstatic void
58178479Sjbdt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp,
59178479Sjb    int argc, dt_node_t *args, const char *prefix, const char *suffix)
60178479Sjb{
61178479Sjb	dt_idsig_t *isp = idp->di_data;
62178479Sjb	int i, compat, mismatch, arglimit, iskey;
63178479Sjb
64178479Sjb	char n1[DT_TYPE_NAMELEN];
65178479Sjb	char n2[DT_TYPE_NAMELEN];
66178479Sjb
67178479Sjb	iskey = idp->di_kind == DT_IDENT_ARRAY || idp->di_kind == DT_IDENT_AGG;
68178479Sjb
69178479Sjb	if (isp->dis_varargs >= 0) {
70178479Sjb		mismatch = argc < isp->dis_varargs;
71178479Sjb		arglimit = isp->dis_varargs;
72178479Sjb	} else if (isp->dis_optargs >= 0) {
73178479Sjb		mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc);
74178479Sjb		arglimit = argc;
75178479Sjb	} else {
76178479Sjb		mismatch = argc != isp->dis_argc;
77178479Sjb		arglimit = isp->dis_argc;
78178479Sjb	}
79178479Sjb
80178479Sjb	if (mismatch) {
81178479Sjb		xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d %s%s"
82178479Sjb		    "passed, %s%d expected\n", prefix, idp->di_name, suffix,
83178479Sjb		    argc, iskey ? "key" : "arg", argc == 1 ? " " : "s ",
84178479Sjb		    isp->dis_optargs >= 0 ? "at least " : "",
85178479Sjb		    isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit);
86178479Sjb	}
87178479Sjb
88178479Sjb	for (i = 0; i < arglimit; i++, args = args->dn_list) {
89178479Sjb		if (isp->dis_args[i].dn_ctfp != NULL)
90178479Sjb			compat = dt_node_is_argcompat(&isp->dis_args[i], args);
91178479Sjb		else
92178479Sjb			compat = 1; /* "@" matches any type */
93178479Sjb
94178479Sjb		if (!compat) {
95178479Sjb			xyerror(D_PROTO_ARG,
96178479Sjb			    "%s%s%s %s #%d is incompatible with "
97178479Sjb			    "prototype:\n\tprototype: %s\n\t%9s: %s\n",
98178479Sjb			    prefix, idp->di_name, suffix,
99178479Sjb			    iskey ? "key" : "argument", i + 1,
100178479Sjb			    dt_node_type_name(&isp->dis_args[i], n1,
101178479Sjb			    sizeof (n1)),
102178479Sjb			    iskey ? "key" : "argument",
103178479Sjb			    dt_node_type_name(args, n2, sizeof (n2)));
104178479Sjb		}
105178479Sjb	}
106178479Sjb
107178479Sjb	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
108178479Sjb}
109178479Sjb
110178479Sjb/*
111178479Sjb * Cook an associative array identifier.  If this is the first time we are
112178479Sjb * cooking this array, create its signature based on the argument list.
113178479Sjb * Otherwise validate the argument list against the existing signature.
114178479Sjb */
115178479Sjbstatic void
116178479Sjbdt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
117178479Sjb{
118178479Sjb	if (idp->di_data == NULL) {
119178479Sjb		dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t));
120178479Sjb		char n[DT_TYPE_NAMELEN];
121178479Sjb		int i;
122178479Sjb
123178479Sjb		if (isp == NULL)
124178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
125178479Sjb
126178479Sjb		isp->dis_varargs = -1;
127178479Sjb		isp->dis_optargs = -1;
128178479Sjb		isp->dis_argc = argc;
129178479Sjb		isp->dis_args = NULL;
130178479Sjb		isp->dis_auxinfo = 0;
131178479Sjb
132178479Sjb		if (argc != 0 && (isp->dis_args = calloc(argc,
133178479Sjb		    sizeof (dt_node_t))) == NULL) {
134178479Sjb			idp->di_data = NULL;
135178479Sjb			free(isp);
136178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
137178479Sjb		}
138178479Sjb
139178479Sjb		/*
140178479Sjb		 * If this identifier has not been explicitly declared earlier,
141178479Sjb		 * set the identifier's base type to be our special type <DYN>.
142178479Sjb		 * If this ident is an aggregation, it will remain as is.  If
143178479Sjb		 * this ident is an associative array, it will be reassigned
144178479Sjb		 * based on the result type of the first assignment statement.
145178479Sjb		 */
146178479Sjb		if (!(idp->di_flags & DT_IDFLG_DECL)) {
147178479Sjb			idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl);
148178479Sjb			idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl);
149178479Sjb		}
150178479Sjb
151178479Sjb		for (i = 0; i < argc; i++, args = args->dn_list) {
152178479Sjb			if (dt_node_is_dynamic(args) || dt_node_is_void(args)) {
153178479Sjb				xyerror(D_KEY_TYPE, "%s expression may not be "
154178479Sjb				    "used as %s index: key #%d\n",
155178479Sjb				    dt_node_type_name(args, n, sizeof (n)),
156178479Sjb				    dt_idkind_name(idp->di_kind), i + 1);
157178479Sjb			}
158178479Sjb
159178479Sjb			dt_node_type_propagate(args, &isp->dis_args[i]);
160178479Sjb			isp->dis_args[i].dn_list = &isp->dis_args[i + 1];
161178479Sjb		}
162178479Sjb
163178479Sjb		if (argc != 0)
164178479Sjb			isp->dis_args[argc - 1].dn_list = NULL;
165178479Sjb
166178479Sjb		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
167178479Sjb
168178479Sjb	} else {
169178479Sjb		dt_idcook_sign(dnp, idp, argc, args,
170178479Sjb		    idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]");
171178479Sjb	}
172178479Sjb}
173178479Sjb
174178479Sjb/*
175178479Sjb * Cook a function call.  If this is the first time we are cooking this
176178479Sjb * identifier, create its type signature based on predefined prototype stored
177178479Sjb * in di_iarg.  We then validate the argument list against this signature.
178178479Sjb */
179178479Sjbstatic void
180178479Sjbdt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
181178479Sjb{
182178479Sjb	if (idp->di_data == NULL) {
183178479Sjb		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
184178479Sjb		dtrace_typeinfo_t dtt;
185178479Sjb		dt_idsig_t *isp;
186178479Sjb		char *s, *p1, *p2;
187178479Sjb		int i = 0;
188178479Sjb
189178479Sjb		assert(idp->di_iarg != NULL);
190178479Sjb		s = alloca(strlen(idp->di_iarg) + 1);
191178479Sjb		(void) strcpy(s, idp->di_iarg);
192178479Sjb
193178479Sjb		if ((p2 = strrchr(s, ')')) != NULL)
194178479Sjb			*p2 = '\0'; /* mark end of parameter list string */
195178479Sjb
196178479Sjb		if ((p1 = strchr(s, '(')) != NULL)
197178479Sjb			*p1++ = '\0'; /* mark end of return type string */
198178479Sjb
199178479Sjb		if (p1 == NULL || p2 == NULL) {
200178479Sjb			xyerror(D_UNKNOWN, "internal error: malformed entry "
201178479Sjb			    "for built-in function %s\n", idp->di_name);
202178479Sjb		}
203178479Sjb
204178479Sjb		for (p2 = p1; *p2 != '\0'; p2++) {
205178479Sjb			if (!isspace(*p2)) {
206178479Sjb				i++;
207178479Sjb				break;
208178479Sjb			}
209178479Sjb		}
210178479Sjb
211178479Sjb		for (p2 = strchr(p2, ','); p2++ != NULL; i++)
212178479Sjb			p2 = strchr(p2, ',');
213178479Sjb
214178479Sjb		/*
215178479Sjb		 * We first allocate a new ident signature structure with the
216178479Sjb		 * appropriate number of argument entries, and then look up
217178479Sjb		 * the return type and store its CTF data in di_ctfp/type.
218178479Sjb		 */
219178479Sjb		if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL)
220178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
221178479Sjb
222178479Sjb		isp->dis_varargs = -1;
223178479Sjb		isp->dis_optargs = -1;
224178479Sjb		isp->dis_argc = i;
225178479Sjb		isp->dis_args = NULL;
226178479Sjb		isp->dis_auxinfo = 0;
227178479Sjb
228178479Sjb		if (i != 0 && (isp->dis_args = calloc(i,
229178479Sjb		    sizeof (dt_node_t))) == NULL) {
230178479Sjb			idp->di_data = NULL;
231178479Sjb			free(isp);
232178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
233178479Sjb		}
234178479Sjb
235178479Sjb		if (dt_type_lookup(s, &dtt) == -1) {
236178479Sjb			xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):"
237178479Sjb			    " %s\n", idp->di_name, s,
238178479Sjb			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
239178479Sjb		}
240178479Sjb
241178479Sjb		if (idp->di_kind == DT_IDENT_AGGFUNC) {
242178479Sjb			idp->di_ctfp = DT_DYN_CTFP(dtp);
243178479Sjb			idp->di_type = DT_DYN_TYPE(dtp);
244178479Sjb		} else {
245178479Sjb			idp->di_ctfp = dtt.dtt_ctfp;
246178479Sjb			idp->di_type = dtt.dtt_type;
247178479Sjb		}
248178479Sjb
249178479Sjb		/*
250178479Sjb		 * For each comma-delimited parameter in the prototype string,
251178479Sjb		 * we look up the corresponding type and store its CTF data in
252178479Sjb		 * the corresponding location in dis_args[].  We also recognize
253178479Sjb		 * the special type string "@" to indicate that the specified
254178479Sjb		 * parameter may be a D expression of *any* type (represented
255178479Sjb		 * as a dis_args[] element with ctfp = NULL, type == CTF_ERR).
256178479Sjb		 * If a varargs "..." is present, we record the argument index
257178479Sjb		 * in dis_varargs for the benefit of dt_idcook_sign(), above.
258178479Sjb		 * If the type of an argument is enclosed in square brackets
259178479Sjb		 * (e.g. "[int]"), the argument is considered optional:  the
260178479Sjb		 * argument may be absent, but if it is present, it must be of
261178479Sjb		 * the specified type.  Note that varargs may not optional,
262178479Sjb		 * optional arguments may not follow varargs, and non-optional
263178479Sjb		 * arguments may not follow optional arguments.
264178479Sjb		 */
265178479Sjb		for (i = 0; i < isp->dis_argc; i++, p1 = p2) {
266178479Sjb			while (isspace(*p1))
267178479Sjb				p1++; /* skip leading whitespace */
268178479Sjb
269178479Sjb			if ((p2 = strchr(p1, ',')) == NULL)
270178479Sjb				p2 = p1 + strlen(p1);
271178479Sjb			else
272178479Sjb				*p2++ = '\0';
273178479Sjb
274178479Sjb			if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) {
275178479Sjb				isp->dis_args[i].dn_ctfp = NULL;
276178479Sjb				isp->dis_args[i].dn_type = CTF_ERR;
277178479Sjb				if (*p1 == '.')
278178479Sjb					isp->dis_varargs = i;
279178479Sjb				continue;
280178479Sjb			}
281178479Sjb
282178479Sjb			if (*p1 == '[' && p1[strlen(p1) - 1] == ']') {
283178479Sjb				if (isp->dis_varargs != -1) {
284178479Sjb					xyerror(D_UNKNOWN, "optional arg#%d "
285178479Sjb					    "may not follow variable arg#%d\n",
286178479Sjb					    i + 1, isp->dis_varargs + 1);
287178479Sjb				}
288178479Sjb
289178479Sjb				if (isp->dis_optargs == -1)
290178479Sjb					isp->dis_optargs = i;
291178479Sjb
292178479Sjb				p1[strlen(p1) - 1] = '\0';
293178479Sjb				p1++;
294178479Sjb			} else if (isp->dis_optargs != -1) {
295178479Sjb				xyerror(D_UNKNOWN, "required arg#%d may not "
296178479Sjb				    "follow optional arg#%d\n", i + 1,
297178479Sjb				    isp->dis_optargs + 1);
298178479Sjb			}
299178479Sjb
300178479Sjb			if (dt_type_lookup(p1, &dtt) == -1) {
301178479Sjb				xyerror(D_UNKNOWN, "failed to resolve type of "
302178479Sjb				    "%s arg#%d (%s): %s\n", idp->di_name, i + 1,
303178479Sjb				    p1, dtrace_errmsg(dtp, dtrace_errno(dtp)));
304178479Sjb			}
305178479Sjb
306178479Sjb			dt_node_type_assign(&isp->dis_args[i],
307178479Sjb			    dtt.dtt_ctfp, dtt.dtt_type);
308178479Sjb		}
309178479Sjb	}
310178479Sjb
311178479Sjb	dt_idcook_sign(dnp, idp, argc, args, "", "( )");
312178479Sjb}
313178479Sjb
314178479Sjb/*
315178479Sjb * Cook a reference to the dynamically typed args[] array.  We verify that the
316178479Sjb * reference is using a single integer constant, and then construct a new ident
317178479Sjb * representing the appropriate type or translation specifically for this node.
318178479Sjb */
319178479Sjbstatic void
320178479Sjbdt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
321178479Sjb{
322178479Sjb	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
323178479Sjb	dt_probe_t *prp = yypcb->pcb_probe;
324178479Sjb
325178479Sjb	dt_node_t tag, *nnp, *xnp;
326178479Sjb	dt_xlator_t *dxp;
327178479Sjb	dt_ident_t *xidp;
328178479Sjb
329178479Sjb	char n1[DT_TYPE_NAMELEN];
330178479Sjb	char n2[DT_TYPE_NAMELEN];
331178479Sjb
332178479Sjb	if (argc != 1) {
333178479Sjb		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
334178479Sjb		    "passed, 1 expected\n", idp->di_name, argc,
335178479Sjb		    argc == 1 ? " " : "s ");
336178479Sjb	}
337178479Sjb
338178479Sjb	if (ap->dn_kind != DT_NODE_INT) {
339178479Sjb		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
340178479Sjb		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
341178479Sjb		    idp->di_name, "integer constant",
342178479Sjb		    dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1)));
343178479Sjb	}
344178479Sjb
345178479Sjb	if (yypcb->pcb_pdesc == NULL) {
346178479Sjb		xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside "
347178479Sjb		    "of a probe clause\n", idp->di_name);
348178479Sjb	}
349178479Sjb
350178479Sjb	if (prp == NULL) {
351178479Sjb		xyerror(D_ARGS_MULTI,
352178479Sjb		    "%s[ ] may not be referenced because probe description %s "
353178479Sjb		    "matches an unstable set of probes\n", idp->di_name,
354178479Sjb		    dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1)));
355178479Sjb	}
356178479Sjb
357178479Sjb	if (ap->dn_value >= prp->pr_argc) {
358178479Sjb		xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n",
359178479Sjb		    (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc,
360178479Sjb		    n1, sizeof (n1)), idp->di_name);
361178479Sjb	}
362178479Sjb
363178479Sjb	/*
364178479Sjb	 * Look up the native and translated argument types for the probe.
365178479Sjb	 * If no translation is needed, these will be the same underlying node.
366178479Sjb	 * If translation is needed, look up the appropriate translator.  Once
367178479Sjb	 * we have the appropriate node, create a new dt_ident_t for this node,
368178479Sjb	 * assign it the appropriate attributes, and set the type of 'dnp'.
369178479Sjb	 */
370178479Sjb	xnp = prp->pr_xargv[ap->dn_value];
371178479Sjb	nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]];
372178479Sjb
373178479Sjb	if (xnp->dn_type == CTF_ERR) {
374178479Sjb		xyerror(D_ARGS_TYPE, "failed to resolve translated type for "
375178479Sjb		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
376178479Sjb	}
377178479Sjb
378178479Sjb	if (nnp->dn_type == CTF_ERR) {
379178479Sjb		xyerror(D_ARGS_TYPE, "failed to resolve native type for "
380178479Sjb		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
381178479Sjb	}
382178479Sjb
383178479Sjb	if (dtp->dt_xlatemode == DT_XL_STATIC && (
384178479Sjb	    nnp == xnp || dt_node_is_argcompat(nnp, xnp))) {
385178479Sjb		dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind,
386178479Sjb		    idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
387178479Sjb		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);
388178479Sjb
389178479Sjb		if (dnp->dn_ident == NULL)
390178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
391178479Sjb
392178479Sjb		dt_node_type_assign(dnp,
393178479Sjb		    prp->pr_argv[ap->dn_value].dtt_ctfp,
394178479Sjb		    prp->pr_argv[ap->dn_value].dtt_type);
395178479Sjb
396178479Sjb	} else if ((dxp = dt_xlator_lookup(dtp,
397178479Sjb	    nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
398178479Sjb	    dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag),
399178479Sjb	    xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) {
400178479Sjb
401178479Sjb		xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type);
402178479Sjb
403178479Sjb		dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind,
404178479Sjb		    xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
405178479Sjb		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);
406178479Sjb
407178479Sjb		if (dnp->dn_ident == NULL)
408178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
409178479Sjb
410178479Sjb		if (dt_xlator_dynamic(dxp))
411178479Sjb			dxp->dx_arg = (int)ap->dn_value;
412178479Sjb
413178479Sjb		/*
414178479Sjb		 * Propagate relevant members from the translator's internal
415178479Sjb		 * dt_ident_t.  This code must be kept in sync with the state
416178479Sjb		 * that is initialized for idents in dt_xlator_create().
417178479Sjb		 */
418178479Sjb		dnp->dn_ident->di_data = xidp->di_data;
419178479Sjb		dnp->dn_ident->di_ctfp = xidp->di_ctfp;
420178479Sjb		dnp->dn_ident->di_type = xidp->di_type;
421178479Sjb
422178479Sjb		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
423178479Sjb
424178479Sjb	} else {
425178479Sjb		xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
426178479Sjb		    "is not defined\n", idp->di_name, (longlong_t)ap->dn_value,
427178479Sjb		    dt_node_type_name(nnp, n1, sizeof (n1)),
428178479Sjb		    dt_node_type_name(xnp, n2, sizeof (n2)));
429178479Sjb	}
430178479Sjb
431178479Sjb	assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN);
432178479Sjb	assert(dnp->dn_ident->di_id == idp->di_id);
433178479Sjb}
434178479Sjb
435178479Sjbstatic void
436178479Sjbdt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
437178479Sjb{
438178479Sjb	dtrace_typeinfo_t dtt;
439178479Sjb	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
440178479Sjb	char n[DT_TYPE_NAMELEN];
441178479Sjb
442178479Sjb	if (argc != 1) {
443178479Sjb		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
444178479Sjb		    "passed, 1 expected\n", idp->di_name,
445178479Sjb		    argc, argc == 1 ? " " : "s ");
446178479Sjb	}
447178479Sjb
448178479Sjb	if (ap->dn_kind != DT_NODE_INT) {
449178479Sjb		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
450178479Sjb		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
451178479Sjb		    idp->di_name, "integer constant",
452178479Sjb		    dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n)));
453178479Sjb	}
454178479Sjb
455178479Sjb	if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) {
456178479Sjb		xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n",
457178479Sjb		    (longlong_t)ap->dn_value, idp->di_name);
458178479Sjb	}
459178479Sjb
460178479Sjb	if (dt_type_lookup("uint64_t", &dtt) == -1) {
461178479Sjb		xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n",
462178479Sjb		    idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp)));
463178479Sjb	}
464178479Sjb
465178479Sjb	idp->di_ctfp = dtt.dtt_ctfp;
466178479Sjb	idp->di_type = dtt.dtt_type;
467178479Sjb
468178479Sjb	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
469178479Sjb}
470178479Sjb
471178479Sjb/*ARGSUSED*/
472178479Sjbstatic void
473178479Sjbdt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
474178479Sjb{
475178479Sjb	if (idp->di_type == CTF_ERR) {
476178479Sjb		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
477178479Sjb		dtrace_typeinfo_t dtt;
478178479Sjb
479178479Sjb		if (dt_type_lookup(idp->di_iarg, &dtt) == -1) {
480178479Sjb			xyerror(D_UNKNOWN,
481178479Sjb			    "failed to resolve type %s for identifier %s: %s\n",
482178479Sjb			    (const char *)idp->di_iarg, idp->di_name,
483178479Sjb			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
484178479Sjb		}
485178479Sjb
486178479Sjb		idp->di_ctfp = dtt.dtt_ctfp;
487178479Sjb		idp->di_type = dtt.dtt_type;
488178479Sjb	}
489178479Sjb
490178479Sjb	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
491178479Sjb}
492178479Sjb
493178479Sjb/*ARGSUSED*/
494178479Sjbstatic void
495178479Sjbdt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
496178479Sjb{
497178479Sjb	if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR)
498178479Sjb		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
499178479Sjb}
500178479Sjb
501178479Sjbstatic void
502178479Sjbdt_idcook_inline(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
503178479Sjb{
504178479Sjb	if (idp->di_kind == DT_IDENT_ARRAY)
505178479Sjb		dt_idcook_assc(dnp, idp, argc, args);
506178479Sjb	else
507178479Sjb		dt_idcook_thaw(dnp, idp, argc, args);
508178479Sjb}
509178479Sjb
510178479Sjbstatic void
511178479Sjbdt_iddtor_sign(dt_ident_t *idp)
512178479Sjb{
513178479Sjb	if (idp->di_data != NULL)
514178479Sjb		free(((dt_idsig_t *)idp->di_data)->dis_args);
515178479Sjb	free(idp->di_data);
516178479Sjb}
517178479Sjb
518178479Sjbstatic void
519178479Sjbdt_iddtor_free(dt_ident_t *idp)
520178479Sjb{
521178479Sjb	free(idp->di_data);
522178479Sjb}
523178479Sjb
524178479Sjbstatic void
525178479Sjbdt_iddtor_inline(dt_ident_t *idp)
526178479Sjb{
527178479Sjb	dt_idnode_t *inp = idp->di_iarg;
528178479Sjb
529178479Sjb	if (inp != NULL) {
530178479Sjb		dt_node_link_free(&inp->din_list);
531178479Sjb
532178479Sjb		if (inp->din_hash != NULL)
533178479Sjb			dt_idhash_destroy(inp->din_hash);
534178479Sjb
535178479Sjb		free(inp->din_argv);
536178479Sjb		free(inp);
537178479Sjb	}
538178479Sjb
539178479Sjb	if (idp->di_kind == DT_IDENT_ARRAY)
540178479Sjb		dt_iddtor_sign(idp);
541178479Sjb	else
542178479Sjb		dt_iddtor_free(idp);
543178479Sjb}
544178479Sjb
545178479Sjb/*ARGSUSED*/
546178479Sjbstatic void
547178479Sjbdt_iddtor_none(dt_ident_t *idp)
548178479Sjb{
549178479Sjb	/* do nothing */
550178479Sjb}
551178479Sjb
552178479Sjbstatic void
553178479Sjbdt_iddtor_probe(dt_ident_t *idp)
554178479Sjb{
555178479Sjb	if (idp->di_data != NULL)
556178479Sjb		dt_probe_destroy(idp->di_data);
557178479Sjb}
558178479Sjb
559178479Sjbstatic size_t
560178479Sjbdt_idsize_type(dt_ident_t *idp)
561178479Sjb{
562178479Sjb	return (ctf_type_size(idp->di_ctfp, idp->di_type));
563178479Sjb}
564178479Sjb
565178479Sjb/*ARGSUSED*/
566178479Sjbstatic size_t
567178479Sjbdt_idsize_none(dt_ident_t *idp)
568178479Sjb{
569178479Sjb	return (0);
570178479Sjb}
571178479Sjb
572178479Sjbconst dt_idops_t dt_idops_assc = {
573178479Sjb	dt_idcook_assc,
574178479Sjb	dt_iddtor_sign,
575178479Sjb	dt_idsize_none,
576178479Sjb};
577178479Sjb
578178479Sjbconst dt_idops_t dt_idops_func = {
579178479Sjb	dt_idcook_func,
580178479Sjb	dt_iddtor_sign,
581178479Sjb	dt_idsize_none,
582178479Sjb};
583178479Sjb
584178479Sjbconst dt_idops_t dt_idops_args = {
585178479Sjb	dt_idcook_args,
586178479Sjb	dt_iddtor_none,
587178479Sjb	dt_idsize_none,
588178479Sjb};
589178479Sjb
590178479Sjbconst dt_idops_t dt_idops_regs = {
591178479Sjb	dt_idcook_regs,
592178479Sjb	dt_iddtor_free,
593178479Sjb	dt_idsize_none,
594178479Sjb};
595178479Sjb
596178479Sjbconst dt_idops_t dt_idops_type = {
597178479Sjb	dt_idcook_type,
598178479Sjb	dt_iddtor_free,
599178479Sjb	dt_idsize_type,
600178479Sjb};
601178479Sjb
602178479Sjbconst dt_idops_t dt_idops_thaw = {
603178479Sjb	dt_idcook_thaw,
604178479Sjb	dt_iddtor_free,
605178479Sjb	dt_idsize_type,
606178479Sjb};
607178479Sjb
608178479Sjbconst dt_idops_t dt_idops_inline = {
609178479Sjb	dt_idcook_inline,
610178479Sjb	dt_iddtor_inline,
611178479Sjb	dt_idsize_type,
612178479Sjb};
613178479Sjb
614178479Sjbconst dt_idops_t dt_idops_probe = {
615178479Sjb	dt_idcook_thaw,
616178479Sjb	dt_iddtor_probe,
617178479Sjb	dt_idsize_none,
618178479Sjb};
619178479Sjb
620178479Sjbstatic void
621178479Sjbdt_idhash_populate(dt_idhash_t *dhp)
622178479Sjb{
623178479Sjb	const dt_ident_t *idp = dhp->dh_tmpl;
624178479Sjb
625178479Sjb	dhp->dh_tmpl = NULL; /* clear dh_tmpl first to avoid recursion */
626178479Sjb	dt_dprintf("populating %s idhash from %p\n", dhp->dh_name, (void *)idp);
627178479Sjb
628178479Sjb	for (; idp->di_name != NULL; idp++) {
629178479Sjb		if (dt_idhash_insert(dhp, idp->di_name,
630178479Sjb		    idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr,
631178479Sjb		    idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw,
632178479Sjb		    idp->di_iarg, 0) == NULL)
633178479Sjb			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
634178479Sjb	}
635178479Sjb}
636178479Sjb
637178479Sjbdt_idhash_t *
638178479Sjbdt_idhash_create(const char *name, const dt_ident_t *tmpl,
639178479Sjb    uint_t min, uint_t max)
640178479Sjb{
641178479Sjb	dt_idhash_t *dhp;
642178479Sjb	size_t size;
643178479Sjb
644178479Sjb	assert(min <= max);
645178479Sjb
646178479Sjb	size = sizeof (dt_idhash_t) +
647178479Sjb	    sizeof (dt_ident_t *) * (_dtrace_strbuckets - 1);
648178479Sjb
649178479Sjb	if ((dhp = malloc(size)) == NULL)
650178479Sjb		return (NULL);
651178479Sjb
652178479Sjb	bzero(dhp, size);
653178479Sjb	dhp->dh_name = name;
654178479Sjb	dhp->dh_tmpl = tmpl;
655178479Sjb	dhp->dh_nextid = min;
656178479Sjb	dhp->dh_minid = min;
657178479Sjb	dhp->dh_maxid = max;
658178479Sjb	dhp->dh_hashsz = _dtrace_strbuckets;
659178479Sjb
660178479Sjb	return (dhp);
661178479Sjb}
662178479Sjb
663178479Sjb/*
664178479Sjb * Destroy an entire identifier hash.  This must be done using two passes with
665178479Sjb * an inlined version of dt_ident_destroy() to avoid referencing freed memory.
666178479Sjb * In the first pass di_dtor() is called for all identifiers; then the second
667178479Sjb * pass frees the actual dt_ident_t's.  These must be done separately because
668178479Sjb * a di_dtor() may operate on data structures which contain references to other
669178479Sjb * identifiers inside of this hash itself (e.g. a global inline definition
670178479Sjb * which contains a parse tree that refers to another global variable).
671178479Sjb */
672178479Sjbvoid
673178479Sjbdt_idhash_destroy(dt_idhash_t *dhp)
674178479Sjb{
675178479Sjb	dt_ident_t *idp, *next;
676178479Sjb	ulong_t i;
677178479Sjb
678178479Sjb	for (i = 0; i < dhp->dh_hashsz; i++) {
679178479Sjb		for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) {
680178479Sjb			next = idp->di_next;
681178479Sjb			idp->di_ops->di_dtor(idp);
682178479Sjb		}
683178479Sjb	}
684178479Sjb
685178479Sjb	for (i = 0; i < dhp->dh_hashsz; i++) {
686178479Sjb		for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) {
687178479Sjb			next = idp->di_next;
688178479Sjb			free(idp->di_name);
689178479Sjb			free(idp);
690178479Sjb		}
691178479Sjb	}
692178479Sjb
693178479Sjb	free(dhp);
694178479Sjb}
695178479Sjb
696178479Sjbvoid
697178479Sjbdt_idhash_update(dt_idhash_t *dhp)
698178479Sjb{
699178479Sjb	uint_t nextid = dhp->dh_minid;
700178479Sjb	dt_ident_t *idp;
701178479Sjb	ulong_t i;
702178479Sjb
703178479Sjb	for (i = 0; i < dhp->dh_hashsz; i++) {
704178479Sjb		for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next) {
705178479Sjb			/*
706178479Sjb			 * Right now we're hard coding which types need to be
707178479Sjb			 * reset, but ideally this would be done dynamically.
708178479Sjb			 */
709178479Sjb			if (idp->di_kind == DT_IDENT_ARRAY ||
710178479Sjb			    idp->di_kind == DT_IDENT_SCALAR ||
711178479Sjb			    idp->di_kind == DT_IDENT_AGG)
712178479Sjb				nextid = MAX(nextid, idp->di_id + 1);
713178479Sjb		}
714178479Sjb	}
715178479Sjb
716178479Sjb	dhp->dh_nextid = nextid;
717178479Sjb}
718178479Sjb
719178479Sjbdt_ident_t *
720178479Sjbdt_idhash_lookup(dt_idhash_t *dhp, const char *name)
721178479Sjb{
722178479Sjb	size_t len;
723178479Sjb	ulong_t h = dt_strtab_hash(name, &len) % dhp->dh_hashsz;
724178479Sjb	dt_ident_t *idp;
725178479Sjb
726178479Sjb	if (dhp->dh_tmpl != NULL)
727178479Sjb		dt_idhash_populate(dhp); /* fill hash w/ initial population */
728178479Sjb
729178479Sjb	for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) {
730178479Sjb		if (strcmp(idp->di_name, name) == 0)
731178479Sjb			return (idp);
732178479Sjb	}
733178479Sjb
734178479Sjb	return (NULL);
735178479Sjb}
736178479Sjb
737178479Sjbint
738178479Sjbdt_idhash_nextid(dt_idhash_t *dhp, uint_t *p)
739178479Sjb{
740178479Sjb	if (dhp->dh_nextid >= dhp->dh_maxid)
741178479Sjb		return (-1); /* no more id's are free to allocate */
742178479Sjb
743178479Sjb	*p = dhp->dh_nextid++;
744178479Sjb	return (0);
745178479Sjb}
746178479Sjb
747178479Sjbulong_t
748178479Sjbdt_idhash_size(const dt_idhash_t *dhp)
749178479Sjb{
750178479Sjb	return (dhp->dh_nelems);
751178479Sjb}
752178479Sjb
753178479Sjbconst char *
754178479Sjbdt_idhash_name(const dt_idhash_t *dhp)
755178479Sjb{
756178479Sjb	return (dhp->dh_name);
757178479Sjb}
758178479Sjb
759178479Sjbdt_ident_t *
760178479Sjbdt_idhash_insert(dt_idhash_t *dhp, const char *name, ushort_t kind,
761178479Sjb    ushort_t flags, uint_t id, dtrace_attribute_t attr, uint_t vers,
762178479Sjb    const dt_idops_t *ops, void *iarg, ulong_t gen)
763178479Sjb{
764178479Sjb	dt_ident_t *idp;
765178479Sjb	ulong_t h;
766178479Sjb
767178479Sjb	if (dhp->dh_tmpl != NULL)
768178479Sjb		dt_idhash_populate(dhp); /* fill hash w/ initial population */
769178479Sjb
770178479Sjb	idp = dt_ident_create(name, kind, flags, id,
771178479Sjb	    attr, vers, ops, iarg, gen);
772178479Sjb
773178479Sjb	if (idp == NULL)
774178479Sjb		return (NULL);
775178479Sjb
776178479Sjb	h = dt_strtab_hash(name, NULL) % dhp->dh_hashsz;
777178479Sjb	idp->di_next = dhp->dh_hash[h];
778178479Sjb
779178479Sjb	dhp->dh_hash[h] = idp;
780178479Sjb	dhp->dh_nelems++;
781178479Sjb
782178479Sjb	if (dhp->dh_defer != NULL)
783178479Sjb		dhp->dh_defer(dhp, idp);
784178479Sjb
785178479Sjb	return (idp);
786178479Sjb}
787178479Sjb
788178479Sjbvoid
789178479Sjbdt_idhash_xinsert(dt_idhash_t *dhp, dt_ident_t *idp)
790178479Sjb{
791178479Sjb	ulong_t h;
792178479Sjb
793178479Sjb	if (dhp->dh_tmpl != NULL)
794178479Sjb		dt_idhash_populate(dhp); /* fill hash w/ initial population */
795178479Sjb
796178479Sjb	h = dt_strtab_hash(idp->di_name, NULL) % dhp->dh_hashsz;
797178479Sjb	idp->di_next = dhp->dh_hash[h];
798178479Sjb	idp->di_flags &= ~DT_IDFLG_ORPHAN;
799178479Sjb
800178479Sjb	dhp->dh_hash[h] = idp;
801178479Sjb	dhp->dh_nelems++;
802178479Sjb
803178479Sjb	if (dhp->dh_defer != NULL)
804178479Sjb		dhp->dh_defer(dhp, idp);
805178479Sjb}
806178479Sjb
807178479Sjbvoid
808178479Sjbdt_idhash_delete(dt_idhash_t *dhp, dt_ident_t *key)
809178479Sjb{
810178479Sjb	size_t len;
811178479Sjb	ulong_t h = dt_strtab_hash(key->di_name, &len) % dhp->dh_hashsz;
812178479Sjb	dt_ident_t **pp = &dhp->dh_hash[h];
813178479Sjb	dt_ident_t *idp;
814178479Sjb
815178479Sjb	for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) {
816178479Sjb		if (idp == key)
817178479Sjb			break;
818178479Sjb		else
819178479Sjb			pp = &idp->di_next;
820178479Sjb	}
821178479Sjb
822178479Sjb	assert(idp == key);
823178479Sjb	*pp = idp->di_next;
824178479Sjb
825178479Sjb	assert(dhp->dh_nelems != 0);
826178479Sjb	dhp->dh_nelems--;
827178479Sjb
828178479Sjb	if (!(idp->di_flags & DT_IDFLG_ORPHAN))
829178479Sjb		dt_ident_destroy(idp);
830178479Sjb}
831178479Sjb
832178479Sjbstatic int
833178479Sjbdt_idhash_comp(const void *lp, const void *rp)
834178479Sjb{
835178479Sjb	const dt_ident_t *lhs = *((const dt_ident_t **)lp);
836178479Sjb	const dt_ident_t *rhs = *((const dt_ident_t **)rp);
837178479Sjb
838178479Sjb	if (lhs->di_id != rhs->di_id)
839178479Sjb		return ((int)(lhs->di_id - rhs->di_id));
840178479Sjb	else
841178479Sjb		return (strcmp(lhs->di_name, rhs->di_name));
842178479Sjb}
843178479Sjb
844178479Sjbint
845178479Sjbdt_idhash_iter(dt_idhash_t *dhp, dt_idhash_f *func, void *data)
846178479Sjb{
847178479Sjb	dt_ident_t **ids;
848178479Sjb	dt_ident_t *idp;
849178479Sjb	ulong_t i, j, n;
850178479Sjb	int rv;
851178479Sjb
852178479Sjb	if (dhp->dh_tmpl != NULL)
853178479Sjb		dt_idhash_populate(dhp); /* fill hash w/ initial population */
854178479Sjb
855178479Sjb	n = dhp->dh_nelems;
856178479Sjb	ids = alloca(sizeof (dt_ident_t *) * n);
857178479Sjb
858178479Sjb	for (i = 0, j = 0; i < dhp->dh_hashsz; i++) {
859178479Sjb		for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next)
860178479Sjb			ids[j++] = idp;
861178479Sjb	}
862178479Sjb
863178479Sjb	qsort(ids, dhp->dh_nelems, sizeof (dt_ident_t *), dt_idhash_comp);
864178479Sjb
865178479Sjb	for (i = 0; i < n; i++) {
866178479Sjb		if ((rv = func(dhp, ids[i], data)) != 0)
867178479Sjb			return (rv);
868178479Sjb	}
869178479Sjb
870178479Sjb	return (0);
871178479Sjb}
872178479Sjb
873178479Sjbdt_ident_t *
874178479Sjbdt_idstack_lookup(dt_idstack_t *sp, const char *name)
875178479Sjb{
876178479Sjb	dt_idhash_t *dhp;
877178479Sjb	dt_ident_t *idp;
878178479Sjb
879178479Sjb	for (dhp = dt_list_prev(&sp->dids_list);
880178479Sjb	    dhp != NULL; dhp = dt_list_prev(dhp)) {
881178479Sjb		if ((idp = dt_idhash_lookup(dhp, name)) != NULL)
882178479Sjb			return (idp);
883178479Sjb	}
884178479Sjb
885178479Sjb	return (NULL);
886178479Sjb}
887178479Sjb
888178479Sjbvoid
889178479Sjbdt_idstack_push(dt_idstack_t *sp, dt_idhash_t *dhp)
890178479Sjb{
891178479Sjb	dt_list_append(&sp->dids_list, dhp);
892178479Sjb}
893178479Sjb
894178479Sjbvoid
895178479Sjbdt_idstack_pop(dt_idstack_t *sp, dt_idhash_t *dhp)
896178479Sjb{
897178479Sjb	assert(dt_list_prev(&sp->dids_list) == dhp);
898178479Sjb	dt_list_delete(&sp->dids_list, dhp);
899178479Sjb}
900178479Sjb
901178479Sjbdt_ident_t *
902178479Sjbdt_ident_create(const char *name, ushort_t kind, ushort_t flags, uint_t id,
903178479Sjb    dtrace_attribute_t attr, uint_t vers,
904178479Sjb    const dt_idops_t *ops, void *iarg, ulong_t gen)
905178479Sjb{
906178479Sjb	dt_ident_t *idp;
907178479Sjb	char *s = NULL;
908178479Sjb
909178479Sjb	if ((name != NULL && (s = strdup(name)) == NULL) ||
910178479Sjb	    (idp = malloc(sizeof (dt_ident_t))) == NULL) {
911178479Sjb		free(s);
912178479Sjb		return (NULL);
913178479Sjb	}
914178479Sjb
915178479Sjb	idp->di_name = s;
916178479Sjb	idp->di_kind = kind;
917178479Sjb	idp->di_flags = flags;
918178479Sjb	idp->di_id = id;
919178479Sjb	idp->di_attr = attr;
920178479Sjb	idp->di_vers = vers;
921178479Sjb	idp->di_ops = ops;
922178479Sjb	idp->di_iarg = iarg;
923178479Sjb	idp->di_data = NULL;
924178479Sjb	idp->di_ctfp = NULL;
925178479Sjb	idp->di_type = CTF_ERR;
926178479Sjb	idp->di_next = NULL;
927178479Sjb	idp->di_gen = gen;
928178479Sjb	idp->di_lineno = yylineno;
929178479Sjb
930178479Sjb	return (idp);
931178479Sjb}
932178479Sjb
933178479Sjb/*
934178479Sjb * Destroy an individual identifier.  This code must be kept in sync with the
935178479Sjb * dt_idhash_destroy() function below, which separates out the call to di_dtor.
936178479Sjb */
937178479Sjbvoid
938178479Sjbdt_ident_destroy(dt_ident_t *idp)
939178479Sjb{
940178479Sjb	idp->di_ops->di_dtor(idp);
941178479Sjb	free(idp->di_name);
942178479Sjb	free(idp);
943178479Sjb}
944178479Sjb
945178479Sjbvoid
946178479Sjbdt_ident_morph(dt_ident_t *idp, ushort_t kind,
947178479Sjb    const dt_idops_t *ops, void *iarg)
948178479Sjb{
949178479Sjb	idp->di_ops->di_dtor(idp);
950178479Sjb	idp->di_kind = kind;
951178479Sjb	idp->di_ops = ops;
952178479Sjb	idp->di_iarg = iarg;
953178479Sjb	idp->di_data = NULL;
954178479Sjb}
955178479Sjb
956178479Sjbdtrace_attribute_t
957178479Sjbdt_ident_cook(dt_node_t *dnp, dt_ident_t *idp, dt_node_t **pargp)
958178479Sjb{
959178479Sjb	dtrace_attribute_t attr;
960178479Sjb	dt_node_t *args, *argp;
961178479Sjb	int argc = 0;
962178479Sjb
963178479Sjb	attr = dt_node_list_cook(pargp, DT_IDFLG_REF);
964178479Sjb	args = pargp ? *pargp : NULL;
965178479Sjb
966178479Sjb	for (argp = args; argp != NULL; argp = argp->dn_list)
967178479Sjb		argc++;
968178479Sjb
969178479Sjb	idp->di_ops->di_cook(dnp, idp, argc, args);
970178479Sjb
971178479Sjb	if (idp->di_flags & DT_IDFLG_USER)
972178479Sjb		dnp->dn_flags |= DT_NF_USERLAND;
973178479Sjb
974178479Sjb	return (dt_attr_min(attr, idp->di_attr));
975178479Sjb}
976178479Sjb
977178479Sjbvoid
978178479Sjbdt_ident_type_assign(dt_ident_t *idp, ctf_file_t *fp, ctf_id_t type)
979178479Sjb{
980178479Sjb	idp->di_ctfp = fp;
981178479Sjb	idp->di_type = type;
982178479Sjb}
983178479Sjb
984178479Sjbdt_ident_t *
985178479Sjbdt_ident_resolve(dt_ident_t *idp)
986178479Sjb{
987178479Sjb	while (idp->di_flags & DT_IDFLG_INLINE) {
988178479Sjb		const dt_node_t *dnp = ((dt_idnode_t *)idp->di_iarg)->din_root;
989178479Sjb
990178479Sjb		if (dnp == NULL)
991178479Sjb			break; /* can't resolve any further yet */
992178479Sjb
993178479Sjb		switch (dnp->dn_kind) {
994178479Sjb		case DT_NODE_VAR:
995178479Sjb		case DT_NODE_SYM:
996178479Sjb		case DT_NODE_FUNC:
997178479Sjb		case DT_NODE_AGG:
998178479Sjb		case DT_NODE_INLINE:
999178479Sjb		case DT_NODE_PROBE:
1000178479Sjb			idp = dnp->dn_ident;
1001178479Sjb			continue;
1002178479Sjb		}
1003178479Sjb
1004178479Sjb		if (dt_node_is_dynamic(dnp))
1005178479Sjb			idp = dnp->dn_ident;
1006178479Sjb		else
1007178479Sjb			break;
1008178479Sjb	}
1009178479Sjb
1010178479Sjb	return (idp);
1011178479Sjb}
1012178479Sjb
1013178479Sjbsize_t
1014178479Sjbdt_ident_size(dt_ident_t *idp)
1015178479Sjb{
1016178479Sjb	idp = dt_ident_resolve(idp);
1017178479Sjb	return (idp->di_ops->di_size(idp));
1018178479Sjb}
1019178479Sjb
1020178479Sjbint
1021178479Sjbdt_ident_unref(const dt_ident_t *idp)
1022178479Sjb{
1023178479Sjb	return (idp->di_gen == yypcb->pcb_hdl->dt_gen &&
1024178479Sjb	    (idp->di_flags & (DT_IDFLG_REF|DT_IDFLG_MOD|DT_IDFLG_DECL)) == 0);
1025178479Sjb}
1026178479Sjb
1027178479Sjbconst char *
1028178479Sjbdt_idkind_name(uint_t kind)
1029178479Sjb{
1030178479Sjb	switch (kind) {
1031178479Sjb	case DT_IDENT_ARRAY:	return ("associative array");
1032178479Sjb	case DT_IDENT_SCALAR:	return ("scalar");
1033178479Sjb	case DT_IDENT_PTR:	return ("pointer");
1034178479Sjb	case DT_IDENT_FUNC:	return ("function");
1035178479Sjb	case DT_IDENT_AGG:	return ("aggregation");
1036178479Sjb	case DT_IDENT_AGGFUNC:	return ("aggregating function");
1037178479Sjb	case DT_IDENT_ACTFUNC:	return ("tracing function");
1038178479Sjb	case DT_IDENT_XLSOU:	return ("translated data");
1039178479Sjb	case DT_IDENT_XLPTR:	return ("pointer to translated data");
1040178479Sjb	case DT_IDENT_SYMBOL:	return ("external symbol reference");
1041178479Sjb	case DT_IDENT_ENUM:	return ("enumerator");
1042178479Sjb	case DT_IDENT_PRAGAT:	return ("#pragma attributes");
1043178479Sjb	case DT_IDENT_PRAGBN:	return ("#pragma binding");
1044178479Sjb	case DT_IDENT_PROBE:	return ("probe definition");
1045178479Sjb	default:		return ("<?>");
1046178479Sjb	}
1047178479Sjb}
1048