xref: /illumos-gate/usr/src/lib/libdtrace/common/dt_ident.c (revision d5dbd18d69de8954ab5ceb588e99d43fc9b21d46)
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 <sys/sysmacros.h>
30 #include <strings.h>
31 #include <stdlib.h>
32 #include <alloca.h>
33 #include <assert.h>
34 #include <errno.h>
35 #include <ctype.h>
36 #include <sys/procfs_isa.h>
37 #include <limits.h>
38 
39 #include <dt_ident.h>
40 #include <dt_parser.h>
41 #include <dt_provider.h>
42 #include <dt_strtab.h>
43 #include <dt_impl.h>
44 
45 /*
46  * Common code for cooking an identifier that uses a typed signature list (we
47  * use this for associative arrays and functions).  If the argument list is
48  * of the same length and types, then return the return type.  Otherwise
49  * print an appropriate compiler error message and abort the compile.
50  */
51 static void
52 dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp,
53     int argc, dt_node_t *args, const char *prefix, const char *suffix)
54 {
55 	dt_idsig_t *isp = idp->di_data;
56 	int i, compat, mismatch, arglimit;
57 
58 	char n1[DT_TYPE_NAMELEN];
59 	char n2[DT_TYPE_NAMELEN];
60 
61 	if (isp->dis_varargs >= 0) {
62 		mismatch = argc < isp->dis_varargs;
63 		arglimit = isp->dis_varargs;
64 	} else if (isp->dis_optargs >= 0) {
65 		mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc);
66 		arglimit = argc;
67 	} else {
68 		mismatch = argc != isp->dis_argc;
69 		arglimit = isp->dis_argc;
70 	}
71 
72 	if (mismatch) {
73 		xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d arg%s"
74 		    "passed, %s%d expected\n", prefix, idp->di_name, suffix,
75 		    argc, argc == 1 ? " " : "s ",
76 		    isp->dis_optargs >= 0 ? "at least " : "",
77 		    isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit);
78 	}
79 
80 	for (i = 0; i < arglimit; i++, args = args->dn_list) {
81 		if (isp->dis_args[i].dn_ctfp != NULL)
82 			compat = dt_node_is_argcompat(&isp->dis_args[i], args);
83 		else
84 			compat = 1; /* "@" matches any type */
85 
86 		if (!compat) {
87 			xyerror(D_PROTO_ARG,
88 			    "%s%s%s argument #%d is incompatible with "
89 			    "prototype:\n\tprototype: %s\n\t argument: %s\n",
90 			    prefix, idp->di_name, suffix, i + 1,
91 			    dt_node_type_name(&isp->dis_args[i], n1,
92 			    sizeof (n1)),
93 			    dt_node_type_name(args, n2, sizeof (n2)));
94 		}
95 	}
96 
97 	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
98 }
99 
100 /*
101  * Cook an associative array identifier.  If this is the first time we are
102  * cooking this array, create its signature based on the argument list.
103  * Otherwise validate the argument list against the existing signature.
104  */
105 static void
106 dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
107 {
108 	if (idp->di_data == NULL) {
109 		dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t));
110 		char n[DT_TYPE_NAMELEN];
111 		int i;
112 
113 		if (isp == NULL)
114 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
115 
116 		isp->dis_varargs = -1;
117 		isp->dis_optargs = -1;
118 		isp->dis_argc = argc;
119 		isp->dis_args = NULL;
120 
121 		if (argc != 0 && (isp->dis_args = calloc(argc,
122 		    sizeof (dt_node_t))) == NULL) {
123 			idp->di_data = NULL;
124 			free(isp);
125 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
126 		}
127 
128 		/*
129 		 * If this identifier has not been explicitly declared earlier,
130 		 * set the identifier's base type to be our special type <DYN>.
131 		 * If this ident is an aggregation, it will remain as is.  If
132 		 * this ident is an associative array, it will be reassigned
133 		 * based on the result type of the first assignment statement.
134 		 */
135 		if (!(idp->di_flags & DT_IDFLG_DECL)) {
136 			idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl);
137 			idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl);
138 		}
139 
140 		for (i = 0; i < argc; i++, args = args->dn_list) {
141 			if (dt_node_is_dynamic(args) || dt_node_is_void(args)) {
142 				xyerror(D_KEY_TYPE, "%s expression may not be "
143 				    "used as %s index: key #%d\n",
144 				    dt_node_type_name(args, n, sizeof (n)),
145 				    dt_idkind_name(idp->di_kind), i + 1);
146 			}
147 
148 			dt_node_type_propagate(args, &isp->dis_args[i]);
149 			isp->dis_args[i].dn_list = &isp->dis_args[i + 1];
150 		}
151 
152 		if (argc != 0)
153 			isp->dis_args[argc - 1].dn_list = NULL;
154 
155 		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
156 
157 	} else {
158 		dt_idcook_sign(dnp, idp, argc, args,
159 		    idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]");
160 	}
161 }
162 
163 /*
164  * Cook a function call.  If this is the first time we are cooking this
165  * identifier, create its type signature based on predefined prototype stored
166  * in di_iarg.  We then validate the argument list against this signature.
167  */
168 static void
169 dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
170 {
171 	if (idp->di_data == NULL) {
172 		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
173 		dtrace_typeinfo_t dtt;
174 		dt_idsig_t *isp;
175 		char *s, *p1, *p2;
176 		int i = 0;
177 
178 		assert(idp->di_iarg != NULL);
179 		s = alloca(strlen(idp->di_iarg) + 1);
180 		(void) strcpy(s, idp->di_iarg);
181 
182 		if ((p2 = strrchr(s, ')')) != NULL)
183 			*p2 = '\0'; /* mark end of parameter list string */
184 
185 		if ((p1 = strchr(s, '(')) != NULL)
186 			*p1++ = '\0'; /* mark end of return type string */
187 
188 		if (p1 == NULL || p2 == NULL) {
189 			xyerror(D_UNKNOWN, "internal error: malformed entry "
190 			    "for built-in function %s\n", idp->di_name);
191 		}
192 
193 		for (p2 = p1; *p2 != '\0'; p2++) {
194 			if (!isspace(*p2)) {
195 				i++;
196 				break;
197 			}
198 		}
199 
200 		for (p2 = strchr(p2, ','); p2++ != NULL; i++)
201 			p2 = strchr(p2, ',');
202 
203 		/*
204 		 * We first allocate a new ident signature structure with the
205 		 * appropriate number of argument entries, and then look up
206 		 * the return type and store its CTF data in di_ctfp/type.
207 		 */
208 		if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL)
209 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
210 
211 		isp->dis_varargs = -1;
212 		isp->dis_optargs = -1;
213 		isp->dis_argc = i;
214 		isp->dis_args = NULL;
215 
216 		if (i != 0 && (isp->dis_args = calloc(i,
217 		    sizeof (dt_node_t))) == NULL) {
218 			idp->di_data = NULL;
219 			free(isp);
220 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
221 		}
222 
223 		if (dt_type_lookup(s, &dtt) == -1) {
224 			xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):"
225 			    " %s\n", idp->di_name, s,
226 			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
227 		}
228 
229 		if (idp->di_kind == DT_IDENT_AGGFUNC) {
230 			idp->di_ctfp = DT_DYN_CTFP(dtp);
231 			idp->di_type = DT_DYN_TYPE(dtp);
232 		} else {
233 			idp->di_ctfp = dtt.dtt_ctfp;
234 			idp->di_type = dtt.dtt_type;
235 		}
236 
237 		/*
238 		 * For each comma-delimited parameter in the prototype string,
239 		 * we look up the corresponding type and store its CTF data in
240 		 * the corresponding location in dis_args[].  We also recognize
241 		 * the special type string "@" to indicate that the specified
242 		 * parameter may be a D expression of *any* type (represented
243 		 * as a dis_args[] element with ctfp = NULL, type == CTF_ERR).
244 		 * If a varargs "..." is present, we record the argument index
245 		 * in dis_varargs for the benefit of dt_idcook_sign(), above.
246 		 * If the type of an argument is enclosed in square brackets
247 		 * (e.g. "[int]"), the argument is considered optional:  the
248 		 * argument may be absent, but if it is present, it must be of
249 		 * the specified type.  Note that varargs may not optional,
250 		 * optional arguments may not follow varargs, and non-optional
251 		 * arguments may not follow optional arguments.
252 		 */
253 		for (i = 0; i < isp->dis_argc; i++, p1 = p2) {
254 			while (isspace(*p1))
255 				p1++; /* skip leading whitespace */
256 
257 			if ((p2 = strchr(p1, ',')) == NULL)
258 				p2 = p1 + strlen(p1);
259 			else
260 				*p2++ = '\0';
261 
262 			if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) {
263 				isp->dis_args[i].dn_ctfp = NULL;
264 				isp->dis_args[i].dn_type = CTF_ERR;
265 				if (*p1 == '.')
266 					isp->dis_varargs = i;
267 				continue;
268 			}
269 
270 			if (*p1 == '[' && p1[strlen(p1) - 1] == ']') {
271 				if (isp->dis_varargs != -1) {
272 					xyerror(D_UNKNOWN, "optional arg#%d "
273 					    "may not follow variable arg#%d\n",
274 					    i + 1, isp->dis_varargs + 1);
275 				}
276 
277 				if (isp->dis_optargs == -1)
278 					isp->dis_optargs = i;
279 
280 				p1[strlen(p1) - 1] = '\0';
281 				p1++;
282 			} else if (isp->dis_optargs != -1) {
283 				xyerror(D_UNKNOWN, "required arg#%d may not "
284 				    "follow optional arg#%d\n", i + 1,
285 				    isp->dis_optargs + 1);
286 			}
287 
288 			if (dt_type_lookup(p1, &dtt) == -1) {
289 				xyerror(D_UNKNOWN, "failed to resolve type of "
290 				    "%s arg#%d (%s): %s\n", idp->di_name, i + 1,
291 				    p1, dtrace_errmsg(dtp, dtrace_errno(dtp)));
292 			}
293 
294 			dt_node_type_assign(&isp->dis_args[i],
295 			    dtt.dtt_ctfp, dtt.dtt_type);
296 		}
297 	}
298 
299 	dt_idcook_sign(dnp, idp, argc, args, "", "( )");
300 }
301 
302 /*
303  * Cook a reference to the dynamically typed args[] array.  We verify that the
304  * reference is using a single integer constant, and then construct a new ident
305  * representing the appropriate type or translation specifically for this node.
306  */
307 static void
308 dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
309 {
310 	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
311 	dt_probe_t *prp = yypcb->pcb_probe;
312 
313 	dt_node_t tag, *nnp, *xnp;
314 	dt_xlator_t *dxp;
315 	dt_ident_t *xidp;
316 
317 	char n1[DT_TYPE_NAMELEN];
318 	char n2[DT_TYPE_NAMELEN];
319 
320 	if (argc != 1) {
321 		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
322 		    "passed, 1 expected\n", idp->di_name, argc,
323 		    argc == 1 ? " " : "s ");
324 	}
325 
326 	if (ap->dn_kind != DT_NODE_INT) {
327 		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
328 		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
329 		    idp->di_name, "integer constant",
330 		    dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1)));
331 	}
332 
333 	if (yypcb->pcb_pdesc == NULL) {
334 		xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside "
335 		    "of a probe clause\n", idp->di_name);
336 	}
337 
338 	if (prp == NULL) {
339 		xyerror(D_ARGS_MULTI,
340 		    "%s[ ] may not be referenced because probe description %s "
341 		    "matches an unstable set of probes\n", idp->di_name,
342 		    dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1)));
343 	}
344 
345 	if (ap->dn_value >= prp->pr_argc) {
346 		xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n",
347 		    (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc,
348 		    n1, sizeof (n1)), idp->di_name);
349 	}
350 
351 	/*
352 	 * Look up the native and translated argument types for the probe.
353 	 * If no translation is needed, these will be the same underlying node.
354 	 * If translation is needed, look up the appropriate translator.  Once
355 	 * we have the appropriate node, create a new dt_ident_t for this node,
356 	 * assign it the appropriate attributes, and set the type of 'dnp'.
357 	 */
358 	xnp = prp->pr_xargv[ap->dn_value];
359 	nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]];
360 
361 	if (xnp->dn_type == CTF_ERR) {
362 		xyerror(D_ARGS_TYPE, "failed to resolve translated type for "
363 		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
364 	}
365 
366 	if (nnp->dn_type == CTF_ERR) {
367 		xyerror(D_ARGS_TYPE, "failed to resolve native type for "
368 		    "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value);
369 	}
370 
371 	if (dtp->dt_xlatemode == DT_XL_STATIC && (
372 	    nnp == xnp || dt_node_is_argcompat(nnp, xnp))) {
373 		dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind,
374 		    idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
375 		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);
376 
377 		if (dnp->dn_ident == NULL)
378 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
379 
380 		dt_node_type_assign(dnp,
381 		    prp->pr_argv[ap->dn_value].dtt_ctfp,
382 		    prp->pr_argv[ap->dn_value].dtt_type);
383 
384 	} else if ((dxp = dt_xlator_lookup(dtp,
385 	    nnp, xnp, DT_XLATE_FUZZY)) != NULL || (
386 	    dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag),
387 	    xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) {
388 
389 		xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type);
390 
391 		dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind,
392 		    xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr,
393 		    idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen);
394 
395 		if (dnp->dn_ident == NULL)
396 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
397 
398 		if (dt_xlator_dynamic(dxp))
399 			dxp->dx_arg = (int)ap->dn_value;
400 
401 		/*
402 		 * Propagate relevant members from the translator's internal
403 		 * dt_ident_t.  This code must be kept in sync with the state
404 		 * that is initialized for idents in dt_xlator_create().
405 		 */
406 		dnp->dn_ident->di_data = xidp->di_data;
407 		dnp->dn_ident->di_ctfp = xidp->di_ctfp;
408 		dnp->dn_ident->di_type = xidp->di_type;
409 
410 		dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp));
411 
412 	} else {
413 		xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s "
414 		    "is not defined\n", idp->di_name, (longlong_t)ap->dn_value,
415 		    dt_node_type_name(nnp, n1, sizeof (n1)),
416 		    dt_node_type_name(xnp, n2, sizeof (n2)));
417 	}
418 
419 	assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN);
420 	assert(dnp->dn_ident->di_id == idp->di_id);
421 }
422 
423 static void
424 dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap)
425 {
426 	dtrace_typeinfo_t dtt;
427 	dtrace_hdl_t *dtp = yypcb->pcb_hdl;
428 	char n[DT_TYPE_NAMELEN];
429 
430 	if (argc != 1) {
431 		xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s"
432 		    "passed, 1 expected\n", idp->di_name,
433 		    argc, argc == 1 ? " " : "s ");
434 	}
435 
436 	if (ap->dn_kind != DT_NODE_INT) {
437 		xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with "
438 		    "prototype:\n\tprototype: %s\n\t argument: %s\n",
439 		    idp->di_name, "integer constant",
440 		    dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n)));
441 	}
442 
443 	if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) {
444 		xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n",
445 		    (longlong_t)ap->dn_value, idp->di_name);
446 	}
447 
448 	if (dt_type_lookup("uint64_t", &dtt) == -1) {
449 		xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n",
450 		    idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp)));
451 	}
452 
453 	idp->di_ctfp = dtt.dtt_ctfp;
454 	idp->di_type = dtt.dtt_type;
455 
456 	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
457 }
458 
459 /*ARGSUSED*/
460 static void
461 dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
462 {
463 	if (idp->di_type == CTF_ERR) {
464 		dtrace_hdl_t *dtp = yypcb->pcb_hdl;
465 		dtrace_typeinfo_t dtt;
466 
467 		if (dt_type_lookup(idp->di_iarg, &dtt) == -1) {
468 			xyerror(D_UNKNOWN,
469 			    "failed to resolve type %s for identifier %s: %s\n",
470 			    (const char *)idp->di_iarg, idp->di_name,
471 			    dtrace_errmsg(dtp, dtrace_errno(dtp)));
472 		}
473 
474 		idp->di_ctfp = dtt.dtt_ctfp;
475 		idp->di_type = dtt.dtt_type;
476 	}
477 
478 	dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
479 }
480 
481 /*ARGSUSED*/
482 static void
483 dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
484 {
485 	if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR)
486 		dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type);
487 }
488 
489 static void
490 dt_idcook_inline(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args)
491 {
492 	if (idp->di_kind == DT_IDENT_ARRAY)
493 		dt_idcook_assc(dnp, idp, argc, args);
494 	else
495 		dt_idcook_thaw(dnp, idp, argc, args);
496 }
497 
498 static void
499 dt_iddtor_sign(dt_ident_t *idp)
500 {
501 	if (idp->di_data != NULL)
502 		free(((dt_idsig_t *)idp->di_data)->dis_args);
503 	free(idp->di_data);
504 }
505 
506 static void
507 dt_iddtor_free(dt_ident_t *idp)
508 {
509 	free(idp->di_data);
510 }
511 
512 static void
513 dt_iddtor_inline(dt_ident_t *idp)
514 {
515 	dt_idnode_t *inp = idp->di_iarg;
516 
517 	if (inp != NULL) {
518 		dt_node_link_free(&inp->din_list);
519 
520 		if (inp->din_hash != NULL)
521 			dt_idhash_destroy(inp->din_hash);
522 
523 		free(inp->din_argv);
524 		free(inp);
525 	}
526 
527 	if (idp->di_kind == DT_IDENT_ARRAY)
528 		dt_iddtor_sign(idp);
529 	else
530 		dt_iddtor_free(idp);
531 }
532 
533 /*ARGSUSED*/
534 static void
535 dt_iddtor_none(dt_ident_t *idp)
536 {
537 	/* do nothing */
538 }
539 
540 static void
541 dt_iddtor_probe(dt_ident_t *idp)
542 {
543 	if (idp->di_data != NULL)
544 		dt_probe_destroy(idp->di_data);
545 }
546 
547 static size_t
548 dt_idsize_type(dt_ident_t *idp)
549 {
550 	return (ctf_type_size(idp->di_ctfp, idp->di_type));
551 }
552 
553 /*ARGSUSED*/
554 static size_t
555 dt_idsize_none(dt_ident_t *idp)
556 {
557 	return (0);
558 }
559 
560 const dt_idops_t dt_idops_assc = {
561 	dt_idcook_assc,
562 	dt_iddtor_sign,
563 	dt_idsize_none,
564 };
565 
566 const dt_idops_t dt_idops_func = {
567 	dt_idcook_func,
568 	dt_iddtor_sign,
569 	dt_idsize_none,
570 };
571 
572 const dt_idops_t dt_idops_args = {
573 	dt_idcook_args,
574 	dt_iddtor_none,
575 	dt_idsize_none,
576 };
577 
578 const dt_idops_t dt_idops_regs = {
579 	dt_idcook_regs,
580 	dt_iddtor_free,
581 	dt_idsize_none,
582 };
583 
584 const dt_idops_t dt_idops_type = {
585 	dt_idcook_type,
586 	dt_iddtor_free,
587 	dt_idsize_type,
588 };
589 
590 const dt_idops_t dt_idops_thaw = {
591 	dt_idcook_thaw,
592 	dt_iddtor_free,
593 	dt_idsize_type,
594 };
595 
596 const dt_idops_t dt_idops_inline = {
597 	dt_idcook_inline,
598 	dt_iddtor_inline,
599 	dt_idsize_type,
600 };
601 
602 const dt_idops_t dt_idops_probe = {
603 	dt_idcook_thaw,
604 	dt_iddtor_probe,
605 	dt_idsize_none,
606 };
607 
608 static void
609 dt_idhash_populate(dt_idhash_t *dhp)
610 {
611 	const dt_ident_t *idp = dhp->dh_tmpl;
612 
613 	dhp->dh_tmpl = NULL; /* clear dh_tmpl first to avoid recursion */
614 	dt_dprintf("populating %s idhash from %p\n", dhp->dh_name, (void *)idp);
615 
616 	for (; idp->di_name != NULL; idp++) {
617 		if (dt_idhash_insert(dhp, idp->di_name,
618 		    idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr,
619 		    idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw,
620 		    idp->di_iarg, 0) == NULL)
621 			longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM);
622 	}
623 }
624 
625 dt_idhash_t *
626 dt_idhash_create(const char *name, const dt_ident_t *tmpl,
627     uint_t min, uint_t max)
628 {
629 	dt_idhash_t *dhp;
630 	size_t size;
631 
632 	assert(min <= max);
633 
634 	size = sizeof (dt_idhash_t) +
635 	    sizeof (dt_ident_t *) * (_dtrace_strbuckets - 1);
636 
637 	if ((dhp = malloc(size)) == NULL)
638 		return (NULL);
639 
640 	bzero(dhp, size);
641 	dhp->dh_name = name;
642 	dhp->dh_tmpl = tmpl;
643 	dhp->dh_nextid = min;
644 	dhp->dh_minid = min;
645 	dhp->dh_maxid = max;
646 	dhp->dh_hashsz = _dtrace_strbuckets;
647 
648 	return (dhp);
649 }
650 
651 /*
652  * Destroy an entire identifier hash.  This must be done using two passes with
653  * an inlined version of dt_ident_destroy() to avoid referencing freed memory.
654  * In the first pass di_dtor() is called for all identifiers; then the second
655  * pass frees the actual dt_ident_t's.  These must be done separately because
656  * a di_dtor() may operate on data structures which contain references to other
657  * identifiers inside of this hash itself (e.g. a global inline definition
658  * which contains a parse tree that refers to another global variable).
659  */
660 void
661 dt_idhash_destroy(dt_idhash_t *dhp)
662 {
663 	dt_ident_t *idp, *next;
664 	ulong_t i;
665 
666 	for (i = 0; i < dhp->dh_hashsz; i++) {
667 		for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) {
668 			next = idp->di_next;
669 			idp->di_ops->di_dtor(idp);
670 		}
671 	}
672 
673 	for (i = 0; i < dhp->dh_hashsz; i++) {
674 		for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) {
675 			next = idp->di_next;
676 			free(idp->di_name);
677 			free(idp);
678 		}
679 	}
680 
681 	free(dhp);
682 }
683 
684 void
685 dt_idhash_update(dt_idhash_t *dhp)
686 {
687 	uint_t nextid = dhp->dh_minid;
688 	dt_ident_t *idp;
689 	ulong_t i;
690 
691 	for (i = 0; i < dhp->dh_hashsz; i++) {
692 		for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next) {
693 			if (idp->di_kind == DT_IDENT_ARRAY ||
694 			    idp->di_kind == DT_IDENT_SCALAR)
695 				nextid = MAX(nextid, idp->di_id + 1);
696 		}
697 	}
698 
699 	dhp->dh_nextid = nextid;
700 }
701 
702 dt_ident_t *
703 dt_idhash_lookup(dt_idhash_t *dhp, const char *name)
704 {
705 	size_t len;
706 	ulong_t h = dt_strtab_hash(name, &len) % dhp->dh_hashsz;
707 	dt_ident_t *idp;
708 
709 	if (dhp->dh_tmpl != NULL)
710 		dt_idhash_populate(dhp); /* fill hash w/ initial population */
711 
712 	for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) {
713 		if (strcmp(idp->di_name, name) == 0)
714 			return (idp);
715 	}
716 
717 	return (NULL);
718 }
719 
720 int
721 dt_idhash_nextid(dt_idhash_t *dhp, uint_t *p)
722 {
723 	if (dhp->dh_nextid >= dhp->dh_maxid)
724 		return (-1); /* no more id's are free to allocate */
725 
726 	*p = dhp->dh_nextid++;
727 	return (0);
728 }
729 
730 ulong_t
731 dt_idhash_size(const dt_idhash_t *dhp)
732 {
733 	return (dhp->dh_nelems);
734 }
735 
736 const char *
737 dt_idhash_name(const dt_idhash_t *dhp)
738 {
739 	return (dhp->dh_name);
740 }
741 
742 dt_ident_t *
743 dt_idhash_insert(dt_idhash_t *dhp, const char *name, ushort_t kind,
744     ushort_t flags, uint_t id, dtrace_attribute_t attr, uint_t vers,
745     const dt_idops_t *ops, void *iarg, ulong_t gen)
746 {
747 	dt_ident_t *idp;
748 	ulong_t h;
749 
750 	if (dhp->dh_tmpl != NULL)
751 		dt_idhash_populate(dhp); /* fill hash w/ initial population */
752 
753 	idp = dt_ident_create(name, kind, flags, id,
754 	    attr, vers, ops, iarg, gen);
755 
756 	if (idp == NULL)
757 		return (NULL);
758 
759 	h = dt_strtab_hash(name, NULL) % dhp->dh_hashsz;
760 	idp->di_next = dhp->dh_hash[h];
761 
762 	dhp->dh_hash[h] = idp;
763 	dhp->dh_nelems++;
764 
765 	if (dhp->dh_defer != NULL)
766 		dhp->dh_defer(dhp, idp);
767 
768 	return (idp);
769 }
770 
771 void
772 dt_idhash_xinsert(dt_idhash_t *dhp, dt_ident_t *idp)
773 {
774 	ulong_t h;
775 
776 	if (dhp->dh_tmpl != NULL)
777 		dt_idhash_populate(dhp); /* fill hash w/ initial population */
778 
779 	h = dt_strtab_hash(idp->di_name, NULL) % dhp->dh_hashsz;
780 	idp->di_next = dhp->dh_hash[h];
781 	idp->di_flags &= ~DT_IDFLG_ORPHAN;
782 
783 	dhp->dh_hash[h] = idp;
784 	dhp->dh_nelems++;
785 
786 	if (dhp->dh_defer != NULL)
787 		dhp->dh_defer(dhp, idp);
788 }
789 
790 void
791 dt_idhash_delete(dt_idhash_t *dhp, dt_ident_t *key)
792 {
793 	size_t len;
794 	ulong_t h = dt_strtab_hash(key->di_name, &len) % dhp->dh_hashsz;
795 	dt_ident_t **pp = &dhp->dh_hash[h];
796 	dt_ident_t *idp;
797 
798 	for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) {
799 		if (idp == key)
800 			break;
801 		else
802 			pp = &idp->di_next;
803 	}
804 
805 	assert(idp == key);
806 	*pp = idp->di_next;
807 
808 	assert(dhp->dh_nelems != 0);
809 	dhp->dh_nelems--;
810 
811 	if (!(idp->di_flags & DT_IDFLG_ORPHAN))
812 		dt_ident_destroy(idp);
813 }
814 
815 static int
816 dt_idhash_comp(const void *lp, const void *rp)
817 {
818 	const dt_ident_t *lhs = *((const dt_ident_t **)lp);
819 	const dt_ident_t *rhs = *((const dt_ident_t **)rp);
820 
821 	if (lhs->di_id != rhs->di_id)
822 		return ((int)(lhs->di_id - rhs->di_id));
823 	else
824 		return (strcmp(lhs->di_name, rhs->di_name));
825 }
826 
827 int
828 dt_idhash_iter(dt_idhash_t *dhp, dt_idhash_f *func, void *data)
829 {
830 	dt_ident_t **ids;
831 	dt_ident_t *idp;
832 	ulong_t i, j;
833 	int rv;
834 
835 	if (dhp->dh_tmpl != NULL)
836 		dt_idhash_populate(dhp); /* fill hash w/ initial population */
837 
838 	ids = alloca(sizeof (dt_ident_t *) * dhp->dh_nelems);
839 
840 	for (i = 0, j = 0; i < dhp->dh_hashsz; i++) {
841 		for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next)
842 			ids[j++] = idp;
843 	}
844 
845 	qsort(ids, dhp->dh_nelems, sizeof (dt_ident_t *), dt_idhash_comp);
846 
847 	for (i = 0; i < dhp->dh_nelems; i++) {
848 		if ((rv = func(dhp, ids[i], data)) != 0)
849 			return (rv);
850 	}
851 
852 	return (0);
853 }
854 
855 dt_ident_t *
856 dt_idstack_lookup(dt_idstack_t *sp, const char *name)
857 {
858 	dt_idhash_t *dhp;
859 	dt_ident_t *idp;
860 
861 	for (dhp = dt_list_prev(&sp->dids_list);
862 	    dhp != NULL; dhp = dt_list_prev(dhp)) {
863 		if ((idp = dt_idhash_lookup(dhp, name)) != NULL)
864 			return (idp);
865 	}
866 
867 	return (NULL);
868 }
869 
870 void
871 dt_idstack_push(dt_idstack_t *sp, dt_idhash_t *dhp)
872 {
873 	dt_list_append(&sp->dids_list, dhp);
874 }
875 
876 void
877 dt_idstack_pop(dt_idstack_t *sp, dt_idhash_t *dhp)
878 {
879 	assert(dt_list_prev(&sp->dids_list) == dhp);
880 	dt_list_delete(&sp->dids_list, dhp);
881 }
882 
883 dt_ident_t *
884 dt_ident_create(const char *name, ushort_t kind, ushort_t flags, uint_t id,
885     dtrace_attribute_t attr, uint_t vers,
886     const dt_idops_t *ops, void *iarg, ulong_t gen)
887 {
888 	dt_ident_t *idp;
889 	char *s = NULL;
890 
891 	if ((name != NULL && (s = strdup(name)) == NULL) ||
892 	    (idp = malloc(sizeof (dt_ident_t))) == NULL) {
893 		free(s);
894 		return (NULL);
895 	}
896 
897 	idp->di_name = s;
898 	idp->di_kind = kind;
899 	idp->di_flags = flags;
900 	idp->di_id = id;
901 	idp->di_attr = attr;
902 	idp->di_vers = vers;
903 	idp->di_ops = ops;
904 	idp->di_iarg = iarg;
905 	idp->di_data = NULL;
906 	idp->di_ctfp = NULL;
907 	idp->di_type = CTF_ERR;
908 	idp->di_next = NULL;
909 	idp->di_gen = gen;
910 	idp->di_lineno = yylineno;
911 
912 	return (idp);
913 }
914 
915 /*
916  * Destroy an individual identifier.  This code must be kept in sync with the
917  * dt_idhash_destroy() function below, which separates out the call to di_dtor.
918  */
919 void
920 dt_ident_destroy(dt_ident_t *idp)
921 {
922 	idp->di_ops->di_dtor(idp);
923 	free(idp->di_name);
924 	free(idp);
925 }
926 
927 void
928 dt_ident_morph(dt_ident_t *idp, ushort_t kind,
929     const dt_idops_t *ops, void *iarg)
930 {
931 	idp->di_ops->di_dtor(idp);
932 	idp->di_kind = kind;
933 	idp->di_ops = ops;
934 	idp->di_iarg = iarg;
935 	idp->di_data = NULL;
936 }
937 
938 dtrace_attribute_t
939 dt_ident_cook(dt_node_t *dnp, dt_ident_t *idp, dt_node_t **pargp)
940 {
941 	dtrace_attribute_t attr;
942 	dt_node_t *args, *argp;
943 	int argc = 0;
944 
945 	attr = dt_node_list_cook(pargp, DT_IDFLG_REF);
946 	args = pargp ? *pargp : NULL;
947 
948 	for (argp = args; argp != NULL; argp = argp->dn_list)
949 		argc++;
950 
951 	idp->di_ops->di_cook(dnp, idp, argc, args);
952 
953 	if (idp->di_flags & DT_IDFLG_USER)
954 		dnp->dn_flags |= DT_NF_USERLAND;
955 
956 	return (dt_attr_min(attr, idp->di_attr));
957 }
958 
959 void
960 dt_ident_type_assign(dt_ident_t *idp, ctf_file_t *fp, ctf_id_t type)
961 {
962 	idp->di_ctfp = fp;
963 	idp->di_type = type;
964 }
965 
966 dt_ident_t *
967 dt_ident_resolve(dt_ident_t *idp)
968 {
969 	while (idp->di_flags & DT_IDFLG_INLINE) {
970 		const dt_node_t *dnp = ((dt_idnode_t *)idp->di_iarg)->din_root;
971 
972 		if (dnp == NULL)
973 			break; /* can't resolve any further yet */
974 
975 		switch (dnp->dn_kind) {
976 		case DT_NODE_VAR:
977 		case DT_NODE_SYM:
978 		case DT_NODE_FUNC:
979 		case DT_NODE_AGG:
980 		case DT_NODE_INLINE:
981 		case DT_NODE_PROBE:
982 			idp = dnp->dn_ident;
983 			continue;
984 		}
985 
986 		if (dt_node_is_dynamic(dnp))
987 			idp = dnp->dn_ident;
988 		else
989 			break;
990 	}
991 
992 	return (idp);
993 }
994 
995 size_t
996 dt_ident_size(dt_ident_t *idp)
997 {
998 	idp = dt_ident_resolve(idp);
999 	return (idp->di_ops->di_size(idp));
1000 }
1001 
1002 int
1003 dt_ident_unref(const dt_ident_t *idp)
1004 {
1005 	return (idp->di_gen == yypcb->pcb_hdl->dt_gen &&
1006 	    (idp->di_flags & (DT_IDFLG_REF|DT_IDFLG_MOD|DT_IDFLG_DECL)) == 0);
1007 }
1008 
1009 const char *
1010 dt_idkind_name(uint_t kind)
1011 {
1012 	switch (kind) {
1013 	case DT_IDENT_ARRAY:	return ("associative array");
1014 	case DT_IDENT_SCALAR:	return ("scalar");
1015 	case DT_IDENT_PTR:	return ("pointer");
1016 	case DT_IDENT_FUNC:	return ("function");
1017 	case DT_IDENT_AGG:	return ("aggregation");
1018 	case DT_IDENT_AGGFUNC:	return ("aggregating function");
1019 	case DT_IDENT_ACTFUNC:	return ("tracing function");
1020 	case DT_IDENT_XLSOU:	return ("translated data");
1021 	case DT_IDENT_XLPTR:	return ("pointer to translated data");
1022 	case DT_IDENT_SYMBOL:	return ("external symbol reference");
1023 	case DT_IDENT_ENUM:	return ("enumerator");
1024 	case DT_IDENT_PRAGAT:	return ("#pragma attributes");
1025 	case DT_IDENT_PRAGBN:	return ("#pragma binding");
1026 	case DT_IDENT_PROBE:	return ("probe definition");
1027 	default:		return ("<?>");
1028 	}
1029 }
1030