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