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