16ff6d951SJohn Birrell /* 26ff6d951SJohn Birrell * CDDL HEADER START 36ff6d951SJohn Birrell * 46ff6d951SJohn Birrell * The contents of this file are subject to the terms of the 56ff6d951SJohn Birrell * Common Development and Distribution License (the "License"). 66ff6d951SJohn Birrell * You may not use this file except in compliance with the License. 76ff6d951SJohn Birrell * 86ff6d951SJohn Birrell * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96ff6d951SJohn Birrell * or http://www.opensolaris.org/os/licensing. 106ff6d951SJohn Birrell * See the License for the specific language governing permissions 116ff6d951SJohn Birrell * and limitations under the License. 126ff6d951SJohn Birrell * 136ff6d951SJohn Birrell * When distributing Covered Code, include this CDDL HEADER in each 146ff6d951SJohn Birrell * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156ff6d951SJohn Birrell * If applicable, add the following below this CDDL HEADER, with the 166ff6d951SJohn Birrell * fields enclosed by brackets "[]" replaced with your own identifying 176ff6d951SJohn Birrell * information: Portions Copyright [yyyy] [name of copyright owner] 186ff6d951SJohn Birrell * 196ff6d951SJohn Birrell * CDDL HEADER END 206ff6d951SJohn Birrell */ 216ff6d951SJohn Birrell 226ff6d951SJohn Birrell /* 236ff6d951SJohn Birrell * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 246ff6d951SJohn Birrell * Use is subject to license terms. 258e648814SRui Paulo * Copyright (c) 2013 by Delphix. All rights reserved. 268e648814SRui Paulo * Copyright (c) 2013 Joyent, Inc. All rights reserved. 276ff6d951SJohn Birrell */ 286ff6d951SJohn Birrell 296ff6d951SJohn Birrell #pragma ident "%Z%%M% %I% %E% SMI" 306ff6d951SJohn Birrell 31bc96366cSSteven Hartland #ifdef illumos 326ff6d951SJohn Birrell #include <sys/sysmacros.h> 332c981f99SJohn Birrell #endif 346ff6d951SJohn Birrell #include <strings.h> 356ff6d951SJohn Birrell #include <stdlib.h> 36bc96366cSSteven Hartland #ifdef illumos 376ff6d951SJohn Birrell #include <alloca.h> 382c981f99SJohn Birrell #endif 396ff6d951SJohn Birrell #include <assert.h> 406ff6d951SJohn Birrell #include <errno.h> 416ff6d951SJohn Birrell #include <ctype.h> 42bc96366cSSteven Hartland #ifdef illumos 436ff6d951SJohn Birrell #include <sys/procfs_isa.h> 442c981f99SJohn Birrell #endif 456ff6d951SJohn Birrell #include <limits.h> 466ff6d951SJohn Birrell 476ff6d951SJohn Birrell #include <dt_ident.h> 486ff6d951SJohn Birrell #include <dt_parser.h> 496ff6d951SJohn Birrell #include <dt_provider.h> 506ff6d951SJohn Birrell #include <dt_strtab.h> 516ff6d951SJohn Birrell #include <dt_impl.h> 526ff6d951SJohn Birrell 536ff6d951SJohn Birrell /* 546ff6d951SJohn Birrell * Common code for cooking an identifier that uses a typed signature list (we 556ff6d951SJohn Birrell * use this for associative arrays and functions). If the argument list is 566ff6d951SJohn Birrell * of the same length and types, then return the return type. Otherwise 576ff6d951SJohn Birrell * print an appropriate compiler error message and abort the compile. 586ff6d951SJohn Birrell */ 596ff6d951SJohn Birrell static void 606ff6d951SJohn Birrell dt_idcook_sign(dt_node_t *dnp, dt_ident_t *idp, 616ff6d951SJohn Birrell int argc, dt_node_t *args, const char *prefix, const char *suffix) 626ff6d951SJohn Birrell { 636ff6d951SJohn Birrell dt_idsig_t *isp = idp->di_data; 646ff6d951SJohn Birrell int i, compat, mismatch, arglimit, iskey; 656ff6d951SJohn Birrell 666ff6d951SJohn Birrell char n1[DT_TYPE_NAMELEN]; 676ff6d951SJohn Birrell char n2[DT_TYPE_NAMELEN]; 686ff6d951SJohn Birrell 696ff6d951SJohn Birrell iskey = idp->di_kind == DT_IDENT_ARRAY || idp->di_kind == DT_IDENT_AGG; 706ff6d951SJohn Birrell 716ff6d951SJohn Birrell if (isp->dis_varargs >= 0) { 726ff6d951SJohn Birrell mismatch = argc < isp->dis_varargs; 736ff6d951SJohn Birrell arglimit = isp->dis_varargs; 746ff6d951SJohn Birrell } else if (isp->dis_optargs >= 0) { 756ff6d951SJohn Birrell mismatch = (argc < isp->dis_optargs || argc > isp->dis_argc); 766ff6d951SJohn Birrell arglimit = argc; 776ff6d951SJohn Birrell } else { 786ff6d951SJohn Birrell mismatch = argc != isp->dis_argc; 796ff6d951SJohn Birrell arglimit = isp->dis_argc; 806ff6d951SJohn Birrell } 816ff6d951SJohn Birrell 826ff6d951SJohn Birrell if (mismatch) { 836ff6d951SJohn Birrell xyerror(D_PROTO_LEN, "%s%s%s prototype mismatch: %d %s%s" 846ff6d951SJohn Birrell "passed, %s%d expected\n", prefix, idp->di_name, suffix, 856ff6d951SJohn Birrell argc, iskey ? "key" : "arg", argc == 1 ? " " : "s ", 866ff6d951SJohn Birrell isp->dis_optargs >= 0 ? "at least " : "", 876ff6d951SJohn Birrell isp->dis_optargs >= 0 ? isp->dis_optargs : arglimit); 886ff6d951SJohn Birrell } 896ff6d951SJohn Birrell 906ff6d951SJohn Birrell for (i = 0; i < arglimit; i++, args = args->dn_list) { 916ff6d951SJohn Birrell if (isp->dis_args[i].dn_ctfp != NULL) 926ff6d951SJohn Birrell compat = dt_node_is_argcompat(&isp->dis_args[i], args); 936ff6d951SJohn Birrell else 946ff6d951SJohn Birrell compat = 1; /* "@" matches any type */ 956ff6d951SJohn Birrell 966ff6d951SJohn Birrell if (!compat) { 976ff6d951SJohn Birrell xyerror(D_PROTO_ARG, 986ff6d951SJohn Birrell "%s%s%s %s #%d is incompatible with " 996ff6d951SJohn Birrell "prototype:\n\tprototype: %s\n\t%9s: %s\n", 1006ff6d951SJohn Birrell prefix, idp->di_name, suffix, 1016ff6d951SJohn Birrell iskey ? "key" : "argument", i + 1, 1026ff6d951SJohn Birrell dt_node_type_name(&isp->dis_args[i], n1, 1036ff6d951SJohn Birrell sizeof (n1)), 1046ff6d951SJohn Birrell iskey ? "key" : "argument", 1056ff6d951SJohn Birrell dt_node_type_name(args, n2, sizeof (n2))); 1066ff6d951SJohn Birrell } 1076ff6d951SJohn Birrell } 1086ff6d951SJohn Birrell 1098e648814SRui Paulo dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); 1106ff6d951SJohn Birrell } 1116ff6d951SJohn Birrell 1126ff6d951SJohn Birrell /* 1136ff6d951SJohn Birrell * Cook an associative array identifier. If this is the first time we are 1146ff6d951SJohn Birrell * cooking this array, create its signature based on the argument list. 1156ff6d951SJohn Birrell * Otherwise validate the argument list against the existing signature. 1166ff6d951SJohn Birrell */ 1176ff6d951SJohn Birrell static void 1186ff6d951SJohn Birrell dt_idcook_assc(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) 1196ff6d951SJohn Birrell { 1206ff6d951SJohn Birrell if (idp->di_data == NULL) { 1216ff6d951SJohn Birrell dt_idsig_t *isp = idp->di_data = malloc(sizeof (dt_idsig_t)); 1226ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN]; 1236ff6d951SJohn Birrell int i; 1246ff6d951SJohn Birrell 1256ff6d951SJohn Birrell if (isp == NULL) 1266ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1276ff6d951SJohn Birrell 1286ff6d951SJohn Birrell isp->dis_varargs = -1; 1296ff6d951SJohn Birrell isp->dis_optargs = -1; 1306ff6d951SJohn Birrell isp->dis_argc = argc; 1316ff6d951SJohn Birrell isp->dis_args = NULL; 1326ff6d951SJohn Birrell isp->dis_auxinfo = 0; 1336ff6d951SJohn Birrell 1346ff6d951SJohn Birrell if (argc != 0 && (isp->dis_args = calloc(argc, 1356ff6d951SJohn Birrell sizeof (dt_node_t))) == NULL) { 1366ff6d951SJohn Birrell idp->di_data = NULL; 1376ff6d951SJohn Birrell free(isp); 1386ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 1396ff6d951SJohn Birrell } 1406ff6d951SJohn Birrell 1416ff6d951SJohn Birrell /* 1426ff6d951SJohn Birrell * If this identifier has not been explicitly declared earlier, 1436ff6d951SJohn Birrell * set the identifier's base type to be our special type <DYN>. 1446ff6d951SJohn Birrell * If this ident is an aggregation, it will remain as is. If 1456ff6d951SJohn Birrell * this ident is an associative array, it will be reassigned 1466ff6d951SJohn Birrell * based on the result type of the first assignment statement. 1476ff6d951SJohn Birrell */ 1486ff6d951SJohn Birrell if (!(idp->di_flags & DT_IDFLG_DECL)) { 1496ff6d951SJohn Birrell idp->di_ctfp = DT_DYN_CTFP(yypcb->pcb_hdl); 1506ff6d951SJohn Birrell idp->di_type = DT_DYN_TYPE(yypcb->pcb_hdl); 1516ff6d951SJohn Birrell } 1526ff6d951SJohn Birrell 1536ff6d951SJohn Birrell for (i = 0; i < argc; i++, args = args->dn_list) { 1546ff6d951SJohn Birrell if (dt_node_is_dynamic(args) || dt_node_is_void(args)) { 1556ff6d951SJohn Birrell xyerror(D_KEY_TYPE, "%s expression may not be " 1566ff6d951SJohn Birrell "used as %s index: key #%d\n", 1576ff6d951SJohn Birrell dt_node_type_name(args, n, sizeof (n)), 1586ff6d951SJohn Birrell dt_idkind_name(idp->di_kind), i + 1); 1596ff6d951SJohn Birrell } 1606ff6d951SJohn Birrell 1616ff6d951SJohn Birrell dt_node_type_propagate(args, &isp->dis_args[i]); 1626ff6d951SJohn Birrell isp->dis_args[i].dn_list = &isp->dis_args[i + 1]; 1636ff6d951SJohn Birrell } 1646ff6d951SJohn Birrell 1656ff6d951SJohn Birrell if (argc != 0) 1666ff6d951SJohn Birrell isp->dis_args[argc - 1].dn_list = NULL; 1676ff6d951SJohn Birrell 1688e648814SRui Paulo dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); 1696ff6d951SJohn Birrell 1706ff6d951SJohn Birrell } else { 1716ff6d951SJohn Birrell dt_idcook_sign(dnp, idp, argc, args, 1726ff6d951SJohn Birrell idp->di_kind == DT_IDENT_AGG ? "@" : "", "[ ]"); 1736ff6d951SJohn Birrell } 1746ff6d951SJohn Birrell } 1756ff6d951SJohn Birrell 1766ff6d951SJohn Birrell /* 1776ff6d951SJohn Birrell * Cook a function call. If this is the first time we are cooking this 1786ff6d951SJohn Birrell * identifier, create its type signature based on predefined prototype stored 1796ff6d951SJohn Birrell * in di_iarg. We then validate the argument list against this signature. 1806ff6d951SJohn Birrell */ 1816ff6d951SJohn Birrell static void 1826ff6d951SJohn Birrell dt_idcook_func(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) 1836ff6d951SJohn Birrell { 1846ff6d951SJohn Birrell if (idp->di_data == NULL) { 1856ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 1866ff6d951SJohn Birrell dtrace_typeinfo_t dtt; 1876ff6d951SJohn Birrell dt_idsig_t *isp; 1886ff6d951SJohn Birrell char *s, *p1, *p2; 1896ff6d951SJohn Birrell int i = 0; 1906ff6d951SJohn Birrell 1916ff6d951SJohn Birrell assert(idp->di_iarg != NULL); 1926ff6d951SJohn Birrell s = alloca(strlen(idp->di_iarg) + 1); 1936ff6d951SJohn Birrell (void) strcpy(s, idp->di_iarg); 1946ff6d951SJohn Birrell 1956ff6d951SJohn Birrell if ((p2 = strrchr(s, ')')) != NULL) 1966ff6d951SJohn Birrell *p2 = '\0'; /* mark end of parameter list string */ 1976ff6d951SJohn Birrell 1986ff6d951SJohn Birrell if ((p1 = strchr(s, '(')) != NULL) 1996ff6d951SJohn Birrell *p1++ = '\0'; /* mark end of return type string */ 2006ff6d951SJohn Birrell 2016ff6d951SJohn Birrell if (p1 == NULL || p2 == NULL) { 2026ff6d951SJohn Birrell xyerror(D_UNKNOWN, "internal error: malformed entry " 2036ff6d951SJohn Birrell "for built-in function %s\n", idp->di_name); 2046ff6d951SJohn Birrell } 2056ff6d951SJohn Birrell 2066ff6d951SJohn Birrell for (p2 = p1; *p2 != '\0'; p2++) { 2076ff6d951SJohn Birrell if (!isspace(*p2)) { 2086ff6d951SJohn Birrell i++; 2096ff6d951SJohn Birrell break; 2106ff6d951SJohn Birrell } 2116ff6d951SJohn Birrell } 2126ff6d951SJohn Birrell 213a877965fSDomagoj Stolfa for (p2 = strchr(p2, ','); p2 != NULL; i++) { 214a877965fSDomagoj Stolfa p2++; 2156ff6d951SJohn Birrell p2 = strchr(p2, ','); 216a877965fSDomagoj Stolfa } 2176ff6d951SJohn Birrell 2186ff6d951SJohn Birrell /* 2196ff6d951SJohn Birrell * We first allocate a new ident signature structure with the 2206ff6d951SJohn Birrell * appropriate number of argument entries, and then look up 2216ff6d951SJohn Birrell * the return type and store its CTF data in di_ctfp/type. 2226ff6d951SJohn Birrell */ 2236ff6d951SJohn Birrell if ((isp = idp->di_data = malloc(sizeof (dt_idsig_t))) == NULL) 2246ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 2256ff6d951SJohn Birrell 2266ff6d951SJohn Birrell isp->dis_varargs = -1; 2276ff6d951SJohn Birrell isp->dis_optargs = -1; 2286ff6d951SJohn Birrell isp->dis_argc = i; 2296ff6d951SJohn Birrell isp->dis_args = NULL; 2306ff6d951SJohn Birrell isp->dis_auxinfo = 0; 2316ff6d951SJohn Birrell 2326ff6d951SJohn Birrell if (i != 0 && (isp->dis_args = calloc(i, 2336ff6d951SJohn Birrell sizeof (dt_node_t))) == NULL) { 2346ff6d951SJohn Birrell idp->di_data = NULL; 2356ff6d951SJohn Birrell free(isp); 2366ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 2376ff6d951SJohn Birrell } 2386ff6d951SJohn Birrell 2396ff6d951SJohn Birrell if (dt_type_lookup(s, &dtt) == -1) { 2406ff6d951SJohn Birrell xyerror(D_UNKNOWN, "failed to resolve type of %s (%s):" 2416ff6d951SJohn Birrell " %s\n", idp->di_name, s, 2426ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))); 2436ff6d951SJohn Birrell } 2446ff6d951SJohn Birrell 2456ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_AGGFUNC) { 2466ff6d951SJohn Birrell idp->di_ctfp = DT_DYN_CTFP(dtp); 2476ff6d951SJohn Birrell idp->di_type = DT_DYN_TYPE(dtp); 2486ff6d951SJohn Birrell } else { 2496ff6d951SJohn Birrell idp->di_ctfp = dtt.dtt_ctfp; 2506ff6d951SJohn Birrell idp->di_type = dtt.dtt_type; 2516ff6d951SJohn Birrell } 2526ff6d951SJohn Birrell 2536ff6d951SJohn Birrell /* 2546ff6d951SJohn Birrell * For each comma-delimited parameter in the prototype string, 2556ff6d951SJohn Birrell * we look up the corresponding type and store its CTF data in 2566ff6d951SJohn Birrell * the corresponding location in dis_args[]. We also recognize 2576ff6d951SJohn Birrell * the special type string "@" to indicate that the specified 2586ff6d951SJohn Birrell * parameter may be a D expression of *any* type (represented 2596ff6d951SJohn Birrell * as a dis_args[] element with ctfp = NULL, type == CTF_ERR). 2606ff6d951SJohn Birrell * If a varargs "..." is present, we record the argument index 2616ff6d951SJohn Birrell * in dis_varargs for the benefit of dt_idcook_sign(), above. 2626ff6d951SJohn Birrell * If the type of an argument is enclosed in square brackets 2636ff6d951SJohn Birrell * (e.g. "[int]"), the argument is considered optional: the 2646ff6d951SJohn Birrell * argument may be absent, but if it is present, it must be of 2656ff6d951SJohn Birrell * the specified type. Note that varargs may not optional, 2666ff6d951SJohn Birrell * optional arguments may not follow varargs, and non-optional 2676ff6d951SJohn Birrell * arguments may not follow optional arguments. 2686ff6d951SJohn Birrell */ 2696ff6d951SJohn Birrell for (i = 0; i < isp->dis_argc; i++, p1 = p2) { 2706ff6d951SJohn Birrell while (isspace(*p1)) 2716ff6d951SJohn Birrell p1++; /* skip leading whitespace */ 2726ff6d951SJohn Birrell 2736ff6d951SJohn Birrell if ((p2 = strchr(p1, ',')) == NULL) 2746ff6d951SJohn Birrell p2 = p1 + strlen(p1); 2756ff6d951SJohn Birrell else 2766ff6d951SJohn Birrell *p2++ = '\0'; 2776ff6d951SJohn Birrell 2786ff6d951SJohn Birrell if (strcmp(p1, "@") == 0 || strcmp(p1, "...") == 0) { 2796ff6d951SJohn Birrell isp->dis_args[i].dn_ctfp = NULL; 2806ff6d951SJohn Birrell isp->dis_args[i].dn_type = CTF_ERR; 2816ff6d951SJohn Birrell if (*p1 == '.') 2826ff6d951SJohn Birrell isp->dis_varargs = i; 2836ff6d951SJohn Birrell continue; 2846ff6d951SJohn Birrell } 2856ff6d951SJohn Birrell 2866ff6d951SJohn Birrell if (*p1 == '[' && p1[strlen(p1) - 1] == ']') { 2876ff6d951SJohn Birrell if (isp->dis_varargs != -1) { 2886ff6d951SJohn Birrell xyerror(D_UNKNOWN, "optional arg#%d " 2896ff6d951SJohn Birrell "may not follow variable arg#%d\n", 2906ff6d951SJohn Birrell i + 1, isp->dis_varargs + 1); 2916ff6d951SJohn Birrell } 2926ff6d951SJohn Birrell 2936ff6d951SJohn Birrell if (isp->dis_optargs == -1) 2946ff6d951SJohn Birrell isp->dis_optargs = i; 2956ff6d951SJohn Birrell 2966ff6d951SJohn Birrell p1[strlen(p1) - 1] = '\0'; 2976ff6d951SJohn Birrell p1++; 2986ff6d951SJohn Birrell } else if (isp->dis_optargs != -1) { 2996ff6d951SJohn Birrell xyerror(D_UNKNOWN, "required arg#%d may not " 3006ff6d951SJohn Birrell "follow optional arg#%d\n", i + 1, 3016ff6d951SJohn Birrell isp->dis_optargs + 1); 3026ff6d951SJohn Birrell } 3036ff6d951SJohn Birrell 3046ff6d951SJohn Birrell if (dt_type_lookup(p1, &dtt) == -1) { 3056ff6d951SJohn Birrell xyerror(D_UNKNOWN, "failed to resolve type of " 3066ff6d951SJohn Birrell "%s arg#%d (%s): %s\n", idp->di_name, i + 1, 3076ff6d951SJohn Birrell p1, dtrace_errmsg(dtp, dtrace_errno(dtp))); 3086ff6d951SJohn Birrell } 3096ff6d951SJohn Birrell 3106ff6d951SJohn Birrell dt_node_type_assign(&isp->dis_args[i], 3118e648814SRui Paulo dtt.dtt_ctfp, dtt.dtt_type, B_FALSE); 3126ff6d951SJohn Birrell } 3136ff6d951SJohn Birrell } 3146ff6d951SJohn Birrell 3156ff6d951SJohn Birrell dt_idcook_sign(dnp, idp, argc, args, "", "( )"); 3166ff6d951SJohn Birrell } 3176ff6d951SJohn Birrell 3186ff6d951SJohn Birrell /* 3196ff6d951SJohn Birrell * Cook a reference to the dynamically typed args[] array. We verify that the 3206ff6d951SJohn Birrell * reference is using a single integer constant, and then construct a new ident 3216ff6d951SJohn Birrell * representing the appropriate type or translation specifically for this node. 3226ff6d951SJohn Birrell */ 3236ff6d951SJohn Birrell static void 3246ff6d951SJohn Birrell dt_idcook_args(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) 3256ff6d951SJohn Birrell { 3266ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 3276ff6d951SJohn Birrell dt_probe_t *prp = yypcb->pcb_probe; 3286ff6d951SJohn Birrell 3296ff6d951SJohn Birrell dt_node_t tag, *nnp, *xnp; 3306ff6d951SJohn Birrell dt_xlator_t *dxp; 3316ff6d951SJohn Birrell dt_ident_t *xidp; 3326ff6d951SJohn Birrell 3336ff6d951SJohn Birrell char n1[DT_TYPE_NAMELEN]; 3346ff6d951SJohn Birrell char n2[DT_TYPE_NAMELEN]; 3356ff6d951SJohn Birrell 3366ff6d951SJohn Birrell if (argc != 1) { 3376ff6d951SJohn Birrell xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s" 3386ff6d951SJohn Birrell "passed, 1 expected\n", idp->di_name, argc, 3396ff6d951SJohn Birrell argc == 1 ? " " : "s "); 3406ff6d951SJohn Birrell } 3416ff6d951SJohn Birrell 3426ff6d951SJohn Birrell if (ap->dn_kind != DT_NODE_INT) { 3436ff6d951SJohn Birrell xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with " 3446ff6d951SJohn Birrell "prototype:\n\tprototype: %s\n\t argument: %s\n", 3456ff6d951SJohn Birrell idp->di_name, "integer constant", 3466ff6d951SJohn Birrell dt_type_name(ap->dn_ctfp, ap->dn_type, n1, sizeof (n1))); 3476ff6d951SJohn Birrell } 3486ff6d951SJohn Birrell 3496ff6d951SJohn Birrell if (yypcb->pcb_pdesc == NULL) { 3506ff6d951SJohn Birrell xyerror(D_ARGS_NONE, "%s[ ] may not be referenced outside " 3516ff6d951SJohn Birrell "of a probe clause\n", idp->di_name); 3526ff6d951SJohn Birrell } 3536ff6d951SJohn Birrell 3546ff6d951SJohn Birrell if (prp == NULL) { 3556ff6d951SJohn Birrell xyerror(D_ARGS_MULTI, 3566ff6d951SJohn Birrell "%s[ ] may not be referenced because probe description %s " 3576ff6d951SJohn Birrell "matches an unstable set of probes\n", idp->di_name, 3586ff6d951SJohn Birrell dtrace_desc2str(yypcb->pcb_pdesc, n1, sizeof (n1))); 3596ff6d951SJohn Birrell } 3606ff6d951SJohn Birrell 3616ff6d951SJohn Birrell if (ap->dn_value >= prp->pr_argc) { 3626ff6d951SJohn Birrell xyerror(D_ARGS_IDX, "index %lld is out of range for %s %s[ ]\n", 3636ff6d951SJohn Birrell (longlong_t)ap->dn_value, dtrace_desc2str(yypcb->pcb_pdesc, 3646ff6d951SJohn Birrell n1, sizeof (n1)), idp->di_name); 3656ff6d951SJohn Birrell } 3666ff6d951SJohn Birrell 3676ff6d951SJohn Birrell /* 3686ff6d951SJohn Birrell * Look up the native and translated argument types for the probe. 3696ff6d951SJohn Birrell * If no translation is needed, these will be the same underlying node. 3706ff6d951SJohn Birrell * If translation is needed, look up the appropriate translator. Once 3716ff6d951SJohn Birrell * we have the appropriate node, create a new dt_ident_t for this node, 3726ff6d951SJohn Birrell * assign it the appropriate attributes, and set the type of 'dnp'. 3736ff6d951SJohn Birrell */ 3746ff6d951SJohn Birrell xnp = prp->pr_xargv[ap->dn_value]; 3756ff6d951SJohn Birrell nnp = prp->pr_nargv[prp->pr_mapping[ap->dn_value]]; 3766ff6d951SJohn Birrell 3776ff6d951SJohn Birrell if (xnp->dn_type == CTF_ERR) { 3786ff6d951SJohn Birrell xyerror(D_ARGS_TYPE, "failed to resolve translated type for " 3796ff6d951SJohn Birrell "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value); 3806ff6d951SJohn Birrell } 3816ff6d951SJohn Birrell 3826ff6d951SJohn Birrell if (nnp->dn_type == CTF_ERR) { 3836ff6d951SJohn Birrell xyerror(D_ARGS_TYPE, "failed to resolve native type for " 3846ff6d951SJohn Birrell "%s[%lld]\n", idp->di_name, (longlong_t)ap->dn_value); 3856ff6d951SJohn Birrell } 3866ff6d951SJohn Birrell 3876ff6d951SJohn Birrell if (dtp->dt_xlatemode == DT_XL_STATIC && ( 3886ff6d951SJohn Birrell nnp == xnp || dt_node_is_argcompat(nnp, xnp))) { 3896ff6d951SJohn Birrell dnp->dn_ident = dt_ident_create(idp->di_name, idp->di_kind, 3906ff6d951SJohn Birrell idp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr, 3916ff6d951SJohn Birrell idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen); 3926ff6d951SJohn Birrell 3936ff6d951SJohn Birrell if (dnp->dn_ident == NULL) 3946ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 3956ff6d951SJohn Birrell 3966ff6d951SJohn Birrell dt_node_type_assign(dnp, 3976ff6d951SJohn Birrell prp->pr_argv[ap->dn_value].dtt_ctfp, 3988e648814SRui Paulo prp->pr_argv[ap->dn_value].dtt_type, 3998e648814SRui Paulo prp->pr_argv[ap->dn_value].dtt_flags & DTT_FL_USER ? 4008e648814SRui Paulo B_TRUE : B_FALSE); 4016ff6d951SJohn Birrell 4026ff6d951SJohn Birrell } else if ((dxp = dt_xlator_lookup(dtp, 4036ff6d951SJohn Birrell nnp, xnp, DT_XLATE_FUZZY)) != NULL || ( 4046ff6d951SJohn Birrell dxp = dt_xlator_lookup(dtp, dt_probe_tag(prp, ap->dn_value, &tag), 4056ff6d951SJohn Birrell xnp, DT_XLATE_EXACT | DT_XLATE_EXTERN)) != NULL) { 4066ff6d951SJohn Birrell 4076ff6d951SJohn Birrell xidp = dt_xlator_ident(dxp, xnp->dn_ctfp, xnp->dn_type); 4086ff6d951SJohn Birrell 4096ff6d951SJohn Birrell dnp->dn_ident = dt_ident_create(idp->di_name, xidp->di_kind, 4106ff6d951SJohn Birrell xidp->di_flags | DT_IDFLG_ORPHAN, idp->di_id, idp->di_attr, 4116ff6d951SJohn Birrell idp->di_vers, idp->di_ops, idp->di_iarg, idp->di_gen); 4126ff6d951SJohn Birrell 4136ff6d951SJohn Birrell if (dnp->dn_ident == NULL) 4146ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 4156ff6d951SJohn Birrell 4166ff6d951SJohn Birrell if (dt_xlator_dynamic(dxp)) 4176ff6d951SJohn Birrell dxp->dx_arg = (int)ap->dn_value; 4186ff6d951SJohn Birrell 4196ff6d951SJohn Birrell /* 4206ff6d951SJohn Birrell * Propagate relevant members from the translator's internal 4216ff6d951SJohn Birrell * dt_ident_t. This code must be kept in sync with the state 4226ff6d951SJohn Birrell * that is initialized for idents in dt_xlator_create(). 4236ff6d951SJohn Birrell */ 4246ff6d951SJohn Birrell dnp->dn_ident->di_data = xidp->di_data; 4256ff6d951SJohn Birrell dnp->dn_ident->di_ctfp = xidp->di_ctfp; 4266ff6d951SJohn Birrell dnp->dn_ident->di_type = xidp->di_type; 4276ff6d951SJohn Birrell 4288e648814SRui Paulo dt_node_type_assign(dnp, DT_DYN_CTFP(dtp), DT_DYN_TYPE(dtp), 4298e648814SRui Paulo B_FALSE); 4306ff6d951SJohn Birrell 4316ff6d951SJohn Birrell } else { 4326ff6d951SJohn Birrell xyerror(D_ARGS_XLATOR, "translator for %s[%lld] from %s to %s " 4336ff6d951SJohn Birrell "is not defined\n", idp->di_name, (longlong_t)ap->dn_value, 4346ff6d951SJohn Birrell dt_node_type_name(nnp, n1, sizeof (n1)), 4356ff6d951SJohn Birrell dt_node_type_name(xnp, n2, sizeof (n2))); 4366ff6d951SJohn Birrell } 4376ff6d951SJohn Birrell 4386ff6d951SJohn Birrell assert(dnp->dn_ident->di_flags & DT_IDFLG_ORPHAN); 4396ff6d951SJohn Birrell assert(dnp->dn_ident->di_id == idp->di_id); 4406ff6d951SJohn Birrell } 4416ff6d951SJohn Birrell 4426ff6d951SJohn Birrell static void 4436ff6d951SJohn Birrell dt_idcook_regs(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *ap) 4446ff6d951SJohn Birrell { 4456ff6d951SJohn Birrell dtrace_typeinfo_t dtt; 4466ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 4476ff6d951SJohn Birrell char n[DT_TYPE_NAMELEN]; 4486ff6d951SJohn Birrell 4496ff6d951SJohn Birrell if (argc != 1) { 4506ff6d951SJohn Birrell xyerror(D_PROTO_LEN, "%s[ ] prototype mismatch: %d arg%s" 4516ff6d951SJohn Birrell "passed, 1 expected\n", idp->di_name, 4526ff6d951SJohn Birrell argc, argc == 1 ? " " : "s "); 4536ff6d951SJohn Birrell } 4546ff6d951SJohn Birrell 4556ff6d951SJohn Birrell if (ap->dn_kind != DT_NODE_INT) { 4566ff6d951SJohn Birrell xyerror(D_PROTO_ARG, "%s[ ] argument #1 is incompatible with " 4576ff6d951SJohn Birrell "prototype:\n\tprototype: %s\n\t argument: %s\n", 4586ff6d951SJohn Birrell idp->di_name, "integer constant", 4596ff6d951SJohn Birrell dt_type_name(ap->dn_ctfp, ap->dn_type, n, sizeof (n))); 4606ff6d951SJohn Birrell } 4616ff6d951SJohn Birrell 4626ff6d951SJohn Birrell if ((ap->dn_flags & DT_NF_SIGNED) && (int64_t)ap->dn_value < 0) { 4636ff6d951SJohn Birrell xyerror(D_REGS_IDX, "index %lld is out of range for array %s\n", 4646ff6d951SJohn Birrell (longlong_t)ap->dn_value, idp->di_name); 4656ff6d951SJohn Birrell } 4666ff6d951SJohn Birrell 4676ff6d951SJohn Birrell if (dt_type_lookup("uint64_t", &dtt) == -1) { 4686ff6d951SJohn Birrell xyerror(D_UNKNOWN, "failed to resolve type of %s: %s\n", 4696ff6d951SJohn Birrell idp->di_name, dtrace_errmsg(dtp, dtrace_errno(dtp))); 4706ff6d951SJohn Birrell } 4716ff6d951SJohn Birrell 4726ff6d951SJohn Birrell idp->di_ctfp = dtt.dtt_ctfp; 4736ff6d951SJohn Birrell idp->di_type = dtt.dtt_type; 4746ff6d951SJohn Birrell 4758e648814SRui Paulo dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); 4766ff6d951SJohn Birrell } 4776ff6d951SJohn Birrell 4786ff6d951SJohn Birrell /*ARGSUSED*/ 4796ff6d951SJohn Birrell static void 4806ff6d951SJohn Birrell dt_idcook_type(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) 4816ff6d951SJohn Birrell { 4826ff6d951SJohn Birrell if (idp->di_type == CTF_ERR) { 4836ff6d951SJohn Birrell dtrace_hdl_t *dtp = yypcb->pcb_hdl; 4846ff6d951SJohn Birrell dtrace_typeinfo_t dtt; 4856ff6d951SJohn Birrell 4866ff6d951SJohn Birrell if (dt_type_lookup(idp->di_iarg, &dtt) == -1) { 4876ff6d951SJohn Birrell xyerror(D_UNKNOWN, 4886ff6d951SJohn Birrell "failed to resolve type %s for identifier %s: %s\n", 4896ff6d951SJohn Birrell (const char *)idp->di_iarg, idp->di_name, 4906ff6d951SJohn Birrell dtrace_errmsg(dtp, dtrace_errno(dtp))); 4916ff6d951SJohn Birrell } 4926ff6d951SJohn Birrell 4936ff6d951SJohn Birrell idp->di_ctfp = dtt.dtt_ctfp; 4946ff6d951SJohn Birrell idp->di_type = dtt.dtt_type; 4956ff6d951SJohn Birrell } 4966ff6d951SJohn Birrell 4978e648814SRui Paulo dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); 4986ff6d951SJohn Birrell } 4996ff6d951SJohn Birrell 5006ff6d951SJohn Birrell /*ARGSUSED*/ 5016ff6d951SJohn Birrell static void 5026ff6d951SJohn Birrell dt_idcook_thaw(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) 5036ff6d951SJohn Birrell { 5046ff6d951SJohn Birrell if (idp->di_ctfp != NULL && idp->di_type != CTF_ERR) 5058e648814SRui Paulo dt_node_type_assign(dnp, idp->di_ctfp, idp->di_type, B_FALSE); 5066ff6d951SJohn Birrell } 5076ff6d951SJohn Birrell 5086ff6d951SJohn Birrell static void 5096ff6d951SJohn Birrell dt_idcook_inline(dt_node_t *dnp, dt_ident_t *idp, int argc, dt_node_t *args) 5106ff6d951SJohn Birrell { 5116ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_ARRAY) 5126ff6d951SJohn Birrell dt_idcook_assc(dnp, idp, argc, args); 5136ff6d951SJohn Birrell else 5146ff6d951SJohn Birrell dt_idcook_thaw(dnp, idp, argc, args); 5156ff6d951SJohn Birrell } 5166ff6d951SJohn Birrell 5176ff6d951SJohn Birrell static void 5186ff6d951SJohn Birrell dt_iddtor_sign(dt_ident_t *idp) 5196ff6d951SJohn Birrell { 5206ff6d951SJohn Birrell if (idp->di_data != NULL) 5216ff6d951SJohn Birrell free(((dt_idsig_t *)idp->di_data)->dis_args); 5226ff6d951SJohn Birrell free(idp->di_data); 5236ff6d951SJohn Birrell } 5246ff6d951SJohn Birrell 5256ff6d951SJohn Birrell static void 5266ff6d951SJohn Birrell dt_iddtor_free(dt_ident_t *idp) 5276ff6d951SJohn Birrell { 5286ff6d951SJohn Birrell free(idp->di_data); 5296ff6d951SJohn Birrell } 5306ff6d951SJohn Birrell 5316ff6d951SJohn Birrell static void 5326ff6d951SJohn Birrell dt_iddtor_inline(dt_ident_t *idp) 5336ff6d951SJohn Birrell { 5346ff6d951SJohn Birrell dt_idnode_t *inp = idp->di_iarg; 5356ff6d951SJohn Birrell 5366ff6d951SJohn Birrell if (inp != NULL) { 5376ff6d951SJohn Birrell dt_node_link_free(&inp->din_list); 5386ff6d951SJohn Birrell 5396ff6d951SJohn Birrell if (inp->din_hash != NULL) 5406ff6d951SJohn Birrell dt_idhash_destroy(inp->din_hash); 5416ff6d951SJohn Birrell 5426ff6d951SJohn Birrell free(inp->din_argv); 5436ff6d951SJohn Birrell free(inp); 5446ff6d951SJohn Birrell } 5456ff6d951SJohn Birrell 5466ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_ARRAY) 5476ff6d951SJohn Birrell dt_iddtor_sign(idp); 5486ff6d951SJohn Birrell else 5496ff6d951SJohn Birrell dt_iddtor_free(idp); 5506ff6d951SJohn Birrell } 5516ff6d951SJohn Birrell 5526ff6d951SJohn Birrell /*ARGSUSED*/ 5536ff6d951SJohn Birrell static void 5546ff6d951SJohn Birrell dt_iddtor_none(dt_ident_t *idp) 5556ff6d951SJohn Birrell { 5566ff6d951SJohn Birrell /* do nothing */ 5576ff6d951SJohn Birrell } 5586ff6d951SJohn Birrell 5596ff6d951SJohn Birrell static void 5606ff6d951SJohn Birrell dt_iddtor_probe(dt_ident_t *idp) 5616ff6d951SJohn Birrell { 5626ff6d951SJohn Birrell if (idp->di_data != NULL) 5636ff6d951SJohn Birrell dt_probe_destroy(idp->di_data); 5646ff6d951SJohn Birrell } 5656ff6d951SJohn Birrell 5666ff6d951SJohn Birrell static size_t 5676ff6d951SJohn Birrell dt_idsize_type(dt_ident_t *idp) 5686ff6d951SJohn Birrell { 5696ff6d951SJohn Birrell return (ctf_type_size(idp->di_ctfp, idp->di_type)); 5706ff6d951SJohn Birrell } 5716ff6d951SJohn Birrell 5726ff6d951SJohn Birrell /*ARGSUSED*/ 5736ff6d951SJohn Birrell static size_t 5746ff6d951SJohn Birrell dt_idsize_none(dt_ident_t *idp) 5756ff6d951SJohn Birrell { 5766ff6d951SJohn Birrell return (0); 5776ff6d951SJohn Birrell } 5786ff6d951SJohn Birrell 5796ff6d951SJohn Birrell const dt_idops_t dt_idops_assc = { 580*61c4ac2dSMark Johnston .di_cook = dt_idcook_assc, 581*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_sign, 582*61c4ac2dSMark Johnston .di_size = dt_idsize_none, 5836ff6d951SJohn Birrell }; 5846ff6d951SJohn Birrell 5856ff6d951SJohn Birrell const dt_idops_t dt_idops_func = { 586*61c4ac2dSMark Johnston .di_cook = dt_idcook_func, 587*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_sign, 588*61c4ac2dSMark Johnston .di_size = dt_idsize_none, 5896ff6d951SJohn Birrell }; 5906ff6d951SJohn Birrell 5916ff6d951SJohn Birrell const dt_idops_t dt_idops_args = { 592*61c4ac2dSMark Johnston .di_cook = dt_idcook_args, 593*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_none, 594*61c4ac2dSMark Johnston .di_size = dt_idsize_none, 5956ff6d951SJohn Birrell }; 5966ff6d951SJohn Birrell 5976ff6d951SJohn Birrell const dt_idops_t dt_idops_regs = { 598*61c4ac2dSMark Johnston .di_cook = dt_idcook_regs, 599*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_free, 600*61c4ac2dSMark Johnston .di_size = dt_idsize_none, 6016ff6d951SJohn Birrell }; 6026ff6d951SJohn Birrell 6036ff6d951SJohn Birrell const dt_idops_t dt_idops_type = { 604*61c4ac2dSMark Johnston .di_cook = dt_idcook_type, 605*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_free, 606*61c4ac2dSMark Johnston .di_size = dt_idsize_type, 6076ff6d951SJohn Birrell }; 6086ff6d951SJohn Birrell 6096ff6d951SJohn Birrell const dt_idops_t dt_idops_thaw = { 610*61c4ac2dSMark Johnston .di_cook = dt_idcook_thaw, 611*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_free, 612*61c4ac2dSMark Johnston .di_size = dt_idsize_type, 6136ff6d951SJohn Birrell }; 6146ff6d951SJohn Birrell 6156ff6d951SJohn Birrell const dt_idops_t dt_idops_inline = { 616*61c4ac2dSMark Johnston .di_cook = dt_idcook_inline, 617*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_inline, 618*61c4ac2dSMark Johnston .di_size = dt_idsize_type, 6196ff6d951SJohn Birrell }; 6206ff6d951SJohn Birrell 6216ff6d951SJohn Birrell const dt_idops_t dt_idops_probe = { 622*61c4ac2dSMark Johnston .di_cook = dt_idcook_thaw, 623*61c4ac2dSMark Johnston .di_dtor = dt_iddtor_probe, 624*61c4ac2dSMark Johnston .di_size = dt_idsize_none, 6256ff6d951SJohn Birrell }; 6266ff6d951SJohn Birrell 6276ff6d951SJohn Birrell static void 6286ff6d951SJohn Birrell dt_idhash_populate(dt_idhash_t *dhp) 6296ff6d951SJohn Birrell { 6306ff6d951SJohn Birrell const dt_ident_t *idp = dhp->dh_tmpl; 6316ff6d951SJohn Birrell 6326ff6d951SJohn Birrell dhp->dh_tmpl = NULL; /* clear dh_tmpl first to avoid recursion */ 6336ff6d951SJohn Birrell dt_dprintf("populating %s idhash from %p\n", dhp->dh_name, (void *)idp); 6346ff6d951SJohn Birrell 6356ff6d951SJohn Birrell for (; idp->di_name != NULL; idp++) { 6366ff6d951SJohn Birrell if (dt_idhash_insert(dhp, idp->di_name, 6376ff6d951SJohn Birrell idp->di_kind, idp->di_flags, idp->di_id, idp->di_attr, 6386ff6d951SJohn Birrell idp->di_vers, idp->di_ops ? idp->di_ops : &dt_idops_thaw, 6396ff6d951SJohn Birrell idp->di_iarg, 0) == NULL) 6406ff6d951SJohn Birrell longjmp(yypcb->pcb_jmpbuf, EDT_NOMEM); 6416ff6d951SJohn Birrell } 6426ff6d951SJohn Birrell } 6436ff6d951SJohn Birrell 6446ff6d951SJohn Birrell dt_idhash_t * 6456ff6d951SJohn Birrell dt_idhash_create(const char *name, const dt_ident_t *tmpl, 6466ff6d951SJohn Birrell uint_t min, uint_t max) 6476ff6d951SJohn Birrell { 6486ff6d951SJohn Birrell dt_idhash_t *dhp; 6496ff6d951SJohn Birrell size_t size; 6506ff6d951SJohn Birrell 6516ff6d951SJohn Birrell assert(min <= max); 6526ff6d951SJohn Birrell 6536ff6d951SJohn Birrell size = sizeof (dt_idhash_t) + 6546ff6d951SJohn Birrell sizeof (dt_ident_t *) * (_dtrace_strbuckets - 1); 6556ff6d951SJohn Birrell 6566ff6d951SJohn Birrell if ((dhp = malloc(size)) == NULL) 6576ff6d951SJohn Birrell return (NULL); 6586ff6d951SJohn Birrell 6596ff6d951SJohn Birrell bzero(dhp, size); 6606ff6d951SJohn Birrell dhp->dh_name = name; 6616ff6d951SJohn Birrell dhp->dh_tmpl = tmpl; 6626ff6d951SJohn Birrell dhp->dh_nextid = min; 6636ff6d951SJohn Birrell dhp->dh_minid = min; 6646ff6d951SJohn Birrell dhp->dh_maxid = max; 6656ff6d951SJohn Birrell dhp->dh_hashsz = _dtrace_strbuckets; 6666ff6d951SJohn Birrell 6676ff6d951SJohn Birrell return (dhp); 6686ff6d951SJohn Birrell } 6696ff6d951SJohn Birrell 6706ff6d951SJohn Birrell /* 6716ff6d951SJohn Birrell * Destroy an entire identifier hash. This must be done using two passes with 6726ff6d951SJohn Birrell * an inlined version of dt_ident_destroy() to avoid referencing freed memory. 6736ff6d951SJohn Birrell * In the first pass di_dtor() is called for all identifiers; then the second 6746ff6d951SJohn Birrell * pass frees the actual dt_ident_t's. These must be done separately because 6756ff6d951SJohn Birrell * a di_dtor() may operate on data structures which contain references to other 6766ff6d951SJohn Birrell * identifiers inside of this hash itself (e.g. a global inline definition 6776ff6d951SJohn Birrell * which contains a parse tree that refers to another global variable). 6786ff6d951SJohn Birrell */ 6796ff6d951SJohn Birrell void 6806ff6d951SJohn Birrell dt_idhash_destroy(dt_idhash_t *dhp) 6816ff6d951SJohn Birrell { 6826ff6d951SJohn Birrell dt_ident_t *idp, *next; 6836ff6d951SJohn Birrell ulong_t i; 6846ff6d951SJohn Birrell 6856ff6d951SJohn Birrell for (i = 0; i < dhp->dh_hashsz; i++) { 6866ff6d951SJohn Birrell for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) { 6876ff6d951SJohn Birrell next = idp->di_next; 6886ff6d951SJohn Birrell idp->di_ops->di_dtor(idp); 6896ff6d951SJohn Birrell } 6906ff6d951SJohn Birrell } 6916ff6d951SJohn Birrell 6926ff6d951SJohn Birrell for (i = 0; i < dhp->dh_hashsz; i++) { 6936ff6d951SJohn Birrell for (idp = dhp->dh_hash[i]; idp != NULL; idp = next) { 6946ff6d951SJohn Birrell next = idp->di_next; 6956ff6d951SJohn Birrell free(idp->di_name); 6966ff6d951SJohn Birrell free(idp); 6976ff6d951SJohn Birrell } 6986ff6d951SJohn Birrell } 6996ff6d951SJohn Birrell 7006ff6d951SJohn Birrell free(dhp); 7016ff6d951SJohn Birrell } 7026ff6d951SJohn Birrell 7036ff6d951SJohn Birrell void 7046ff6d951SJohn Birrell dt_idhash_update(dt_idhash_t *dhp) 7056ff6d951SJohn Birrell { 7066ff6d951SJohn Birrell uint_t nextid = dhp->dh_minid; 7076ff6d951SJohn Birrell dt_ident_t *idp; 7086ff6d951SJohn Birrell ulong_t i; 7096ff6d951SJohn Birrell 7106ff6d951SJohn Birrell for (i = 0; i < dhp->dh_hashsz; i++) { 7116ff6d951SJohn Birrell for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next) { 7126ff6d951SJohn Birrell /* 7136ff6d951SJohn Birrell * Right now we're hard coding which types need to be 7146ff6d951SJohn Birrell * reset, but ideally this would be done dynamically. 7156ff6d951SJohn Birrell */ 7166ff6d951SJohn Birrell if (idp->di_kind == DT_IDENT_ARRAY || 7176ff6d951SJohn Birrell idp->di_kind == DT_IDENT_SCALAR || 7186ff6d951SJohn Birrell idp->di_kind == DT_IDENT_AGG) 7196ff6d951SJohn Birrell nextid = MAX(nextid, idp->di_id + 1); 7206ff6d951SJohn Birrell } 7216ff6d951SJohn Birrell } 7226ff6d951SJohn Birrell 7236ff6d951SJohn Birrell dhp->dh_nextid = nextid; 7246ff6d951SJohn Birrell } 7256ff6d951SJohn Birrell 7266ff6d951SJohn Birrell dt_ident_t * 7276ff6d951SJohn Birrell dt_idhash_lookup(dt_idhash_t *dhp, const char *name) 7286ff6d951SJohn Birrell { 7296ff6d951SJohn Birrell size_t len; 7306ff6d951SJohn Birrell ulong_t h = dt_strtab_hash(name, &len) % dhp->dh_hashsz; 7316ff6d951SJohn Birrell dt_ident_t *idp; 7326ff6d951SJohn Birrell 7336ff6d951SJohn Birrell if (dhp->dh_tmpl != NULL) 7346ff6d951SJohn Birrell dt_idhash_populate(dhp); /* fill hash w/ initial population */ 7356ff6d951SJohn Birrell 7366ff6d951SJohn Birrell for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) { 7376ff6d951SJohn Birrell if (strcmp(idp->di_name, name) == 0) 7386ff6d951SJohn Birrell return (idp); 7396ff6d951SJohn Birrell } 7406ff6d951SJohn Birrell 7416ff6d951SJohn Birrell return (NULL); 7426ff6d951SJohn Birrell } 7436ff6d951SJohn Birrell 7446ff6d951SJohn Birrell int 7456ff6d951SJohn Birrell dt_idhash_nextid(dt_idhash_t *dhp, uint_t *p) 7466ff6d951SJohn Birrell { 7476ff6d951SJohn Birrell if (dhp->dh_nextid >= dhp->dh_maxid) 7486ff6d951SJohn Birrell return (-1); /* no more id's are free to allocate */ 7496ff6d951SJohn Birrell 7506ff6d951SJohn Birrell *p = dhp->dh_nextid++; 7516ff6d951SJohn Birrell return (0); 7526ff6d951SJohn Birrell } 7536ff6d951SJohn Birrell 7546ff6d951SJohn Birrell ulong_t 7556ff6d951SJohn Birrell dt_idhash_size(const dt_idhash_t *dhp) 7566ff6d951SJohn Birrell { 7576ff6d951SJohn Birrell return (dhp->dh_nelems); 7586ff6d951SJohn Birrell } 7596ff6d951SJohn Birrell 7606ff6d951SJohn Birrell const char * 7616ff6d951SJohn Birrell dt_idhash_name(const dt_idhash_t *dhp) 7626ff6d951SJohn Birrell { 7636ff6d951SJohn Birrell return (dhp->dh_name); 7646ff6d951SJohn Birrell } 7656ff6d951SJohn Birrell 7666ff6d951SJohn Birrell dt_ident_t * 7676ff6d951SJohn Birrell dt_idhash_insert(dt_idhash_t *dhp, const char *name, ushort_t kind, 7686ff6d951SJohn Birrell ushort_t flags, uint_t id, dtrace_attribute_t attr, uint_t vers, 7696ff6d951SJohn Birrell const dt_idops_t *ops, void *iarg, ulong_t gen) 7706ff6d951SJohn Birrell { 7716ff6d951SJohn Birrell dt_ident_t *idp; 7726ff6d951SJohn Birrell ulong_t h; 7736ff6d951SJohn Birrell 7746ff6d951SJohn Birrell if (dhp->dh_tmpl != NULL) 7756ff6d951SJohn Birrell dt_idhash_populate(dhp); /* fill hash w/ initial population */ 7766ff6d951SJohn Birrell 7776ff6d951SJohn Birrell idp = dt_ident_create(name, kind, flags, id, 7786ff6d951SJohn Birrell attr, vers, ops, iarg, gen); 7796ff6d951SJohn Birrell 7806ff6d951SJohn Birrell if (idp == NULL) 7816ff6d951SJohn Birrell return (NULL); 7826ff6d951SJohn Birrell 7836ff6d951SJohn Birrell h = dt_strtab_hash(name, NULL) % dhp->dh_hashsz; 7846ff6d951SJohn Birrell idp->di_next = dhp->dh_hash[h]; 7856ff6d951SJohn Birrell 7866ff6d951SJohn Birrell dhp->dh_hash[h] = idp; 7876ff6d951SJohn Birrell dhp->dh_nelems++; 7886ff6d951SJohn Birrell 7896ff6d951SJohn Birrell if (dhp->dh_defer != NULL) 7906ff6d951SJohn Birrell dhp->dh_defer(dhp, idp); 7916ff6d951SJohn Birrell 7926ff6d951SJohn Birrell return (idp); 7936ff6d951SJohn Birrell } 7946ff6d951SJohn Birrell 7956ff6d951SJohn Birrell void 7966ff6d951SJohn Birrell dt_idhash_xinsert(dt_idhash_t *dhp, dt_ident_t *idp) 7976ff6d951SJohn Birrell { 7986ff6d951SJohn Birrell ulong_t h; 7996ff6d951SJohn Birrell 8006ff6d951SJohn Birrell if (dhp->dh_tmpl != NULL) 8016ff6d951SJohn Birrell dt_idhash_populate(dhp); /* fill hash w/ initial population */ 8026ff6d951SJohn Birrell 8036ff6d951SJohn Birrell h = dt_strtab_hash(idp->di_name, NULL) % dhp->dh_hashsz; 8046ff6d951SJohn Birrell idp->di_next = dhp->dh_hash[h]; 8056ff6d951SJohn Birrell idp->di_flags &= ~DT_IDFLG_ORPHAN; 8066ff6d951SJohn Birrell 8076ff6d951SJohn Birrell dhp->dh_hash[h] = idp; 8086ff6d951SJohn Birrell dhp->dh_nelems++; 8096ff6d951SJohn Birrell 8106ff6d951SJohn Birrell if (dhp->dh_defer != NULL) 8116ff6d951SJohn Birrell dhp->dh_defer(dhp, idp); 8126ff6d951SJohn Birrell } 8136ff6d951SJohn Birrell 8146ff6d951SJohn Birrell void 8156ff6d951SJohn Birrell dt_idhash_delete(dt_idhash_t *dhp, dt_ident_t *key) 8166ff6d951SJohn Birrell { 8176ff6d951SJohn Birrell size_t len; 8186ff6d951SJohn Birrell ulong_t h = dt_strtab_hash(key->di_name, &len) % dhp->dh_hashsz; 8196ff6d951SJohn Birrell dt_ident_t **pp = &dhp->dh_hash[h]; 8206ff6d951SJohn Birrell dt_ident_t *idp; 8216ff6d951SJohn Birrell 8226ff6d951SJohn Birrell for (idp = dhp->dh_hash[h]; idp != NULL; idp = idp->di_next) { 8236ff6d951SJohn Birrell if (idp == key) 8246ff6d951SJohn Birrell break; 8256ff6d951SJohn Birrell else 8266ff6d951SJohn Birrell pp = &idp->di_next; 8276ff6d951SJohn Birrell } 8286ff6d951SJohn Birrell 8296ff6d951SJohn Birrell assert(idp == key); 8306ff6d951SJohn Birrell *pp = idp->di_next; 8316ff6d951SJohn Birrell 8326ff6d951SJohn Birrell assert(dhp->dh_nelems != 0); 8336ff6d951SJohn Birrell dhp->dh_nelems--; 8346ff6d951SJohn Birrell 8356ff6d951SJohn Birrell if (!(idp->di_flags & DT_IDFLG_ORPHAN)) 8366ff6d951SJohn Birrell dt_ident_destroy(idp); 8376ff6d951SJohn Birrell } 8386ff6d951SJohn Birrell 8396ff6d951SJohn Birrell static int 8406ff6d951SJohn Birrell dt_idhash_comp(const void *lp, const void *rp) 8416ff6d951SJohn Birrell { 8426ff6d951SJohn Birrell const dt_ident_t *lhs = *((const dt_ident_t **)lp); 8436ff6d951SJohn Birrell const dt_ident_t *rhs = *((const dt_ident_t **)rp); 8446ff6d951SJohn Birrell 8456ff6d951SJohn Birrell if (lhs->di_id != rhs->di_id) 8466ff6d951SJohn Birrell return ((int)(lhs->di_id - rhs->di_id)); 8476ff6d951SJohn Birrell else 8486ff6d951SJohn Birrell return (strcmp(lhs->di_name, rhs->di_name)); 8496ff6d951SJohn Birrell } 8506ff6d951SJohn Birrell 8516ff6d951SJohn Birrell int 8526ff6d951SJohn Birrell dt_idhash_iter(dt_idhash_t *dhp, dt_idhash_f *func, void *data) 8536ff6d951SJohn Birrell { 8546ff6d951SJohn Birrell dt_ident_t **ids; 8556ff6d951SJohn Birrell dt_ident_t *idp; 8566ff6d951SJohn Birrell ulong_t i, j, n; 8576ff6d951SJohn Birrell int rv; 8586ff6d951SJohn Birrell 8596ff6d951SJohn Birrell if (dhp->dh_tmpl != NULL) 8606ff6d951SJohn Birrell dt_idhash_populate(dhp); /* fill hash w/ initial population */ 8616ff6d951SJohn Birrell 8626ff6d951SJohn Birrell n = dhp->dh_nelems; 8636ff6d951SJohn Birrell ids = alloca(sizeof (dt_ident_t *) * n); 8646ff6d951SJohn Birrell 8656ff6d951SJohn Birrell for (i = 0, j = 0; i < dhp->dh_hashsz; i++) { 8666ff6d951SJohn Birrell for (idp = dhp->dh_hash[i]; idp != NULL; idp = idp->di_next) 8676ff6d951SJohn Birrell ids[j++] = idp; 8686ff6d951SJohn Birrell } 8696ff6d951SJohn Birrell 8706ff6d951SJohn Birrell qsort(ids, dhp->dh_nelems, sizeof (dt_ident_t *), dt_idhash_comp); 8716ff6d951SJohn Birrell 8726ff6d951SJohn Birrell for (i = 0; i < n; i++) { 8736ff6d951SJohn Birrell if ((rv = func(dhp, ids[i], data)) != 0) 8746ff6d951SJohn Birrell return (rv); 8756ff6d951SJohn Birrell } 8766ff6d951SJohn Birrell 8776ff6d951SJohn Birrell return (0); 8786ff6d951SJohn Birrell } 8796ff6d951SJohn Birrell 8806ff6d951SJohn Birrell dt_ident_t * 8816ff6d951SJohn Birrell dt_idstack_lookup(dt_idstack_t *sp, const char *name) 8826ff6d951SJohn Birrell { 8836ff6d951SJohn Birrell dt_idhash_t *dhp; 8846ff6d951SJohn Birrell dt_ident_t *idp; 8856ff6d951SJohn Birrell 8866ff6d951SJohn Birrell for (dhp = dt_list_prev(&sp->dids_list); 8876ff6d951SJohn Birrell dhp != NULL; dhp = dt_list_prev(dhp)) { 8886ff6d951SJohn Birrell if ((idp = dt_idhash_lookup(dhp, name)) != NULL) 8896ff6d951SJohn Birrell return (idp); 8906ff6d951SJohn Birrell } 8916ff6d951SJohn Birrell 8926ff6d951SJohn Birrell return (NULL); 8936ff6d951SJohn Birrell } 8946ff6d951SJohn Birrell 8956ff6d951SJohn Birrell void 8966ff6d951SJohn Birrell dt_idstack_push(dt_idstack_t *sp, dt_idhash_t *dhp) 8976ff6d951SJohn Birrell { 8986ff6d951SJohn Birrell dt_list_append(&sp->dids_list, dhp); 8996ff6d951SJohn Birrell } 9006ff6d951SJohn Birrell 9016ff6d951SJohn Birrell void 9026ff6d951SJohn Birrell dt_idstack_pop(dt_idstack_t *sp, dt_idhash_t *dhp) 9036ff6d951SJohn Birrell { 9046ff6d951SJohn Birrell assert(dt_list_prev(&sp->dids_list) == dhp); 9056ff6d951SJohn Birrell dt_list_delete(&sp->dids_list, dhp); 9066ff6d951SJohn Birrell } 9076ff6d951SJohn Birrell 9086ff6d951SJohn Birrell dt_ident_t * 9096ff6d951SJohn Birrell dt_ident_create(const char *name, ushort_t kind, ushort_t flags, uint_t id, 9106ff6d951SJohn Birrell dtrace_attribute_t attr, uint_t vers, 9116ff6d951SJohn Birrell const dt_idops_t *ops, void *iarg, ulong_t gen) 9126ff6d951SJohn Birrell { 9136ff6d951SJohn Birrell dt_ident_t *idp; 9146ff6d951SJohn Birrell char *s = NULL; 9156ff6d951SJohn Birrell 9166ff6d951SJohn Birrell if ((name != NULL && (s = strdup(name)) == NULL) || 9176ff6d951SJohn Birrell (idp = malloc(sizeof (dt_ident_t))) == NULL) { 9186ff6d951SJohn Birrell free(s); 9196ff6d951SJohn Birrell return (NULL); 9206ff6d951SJohn Birrell } 9216ff6d951SJohn Birrell 9226ff6d951SJohn Birrell idp->di_name = s; 9236ff6d951SJohn Birrell idp->di_kind = kind; 9246ff6d951SJohn Birrell idp->di_flags = flags; 9256ff6d951SJohn Birrell idp->di_id = id; 9266ff6d951SJohn Birrell idp->di_attr = attr; 9276ff6d951SJohn Birrell idp->di_vers = vers; 9286ff6d951SJohn Birrell idp->di_ops = ops; 9296ff6d951SJohn Birrell idp->di_iarg = iarg; 9306ff6d951SJohn Birrell idp->di_data = NULL; 9316ff6d951SJohn Birrell idp->di_ctfp = NULL; 9326ff6d951SJohn Birrell idp->di_type = CTF_ERR; 9336ff6d951SJohn Birrell idp->di_next = NULL; 9346ff6d951SJohn Birrell idp->di_gen = gen; 9356ff6d951SJohn Birrell idp->di_lineno = yylineno; 9366ff6d951SJohn Birrell 9376ff6d951SJohn Birrell return (idp); 9386ff6d951SJohn Birrell } 9396ff6d951SJohn Birrell 9406ff6d951SJohn Birrell /* 9416ff6d951SJohn Birrell * Destroy an individual identifier. This code must be kept in sync with the 9426ff6d951SJohn Birrell * dt_idhash_destroy() function below, which separates out the call to di_dtor. 9436ff6d951SJohn Birrell */ 9446ff6d951SJohn Birrell void 9456ff6d951SJohn Birrell dt_ident_destroy(dt_ident_t *idp) 9466ff6d951SJohn Birrell { 9476ff6d951SJohn Birrell idp->di_ops->di_dtor(idp); 9486ff6d951SJohn Birrell free(idp->di_name); 9496ff6d951SJohn Birrell free(idp); 9506ff6d951SJohn Birrell } 9516ff6d951SJohn Birrell 9526ff6d951SJohn Birrell void 9536ff6d951SJohn Birrell dt_ident_morph(dt_ident_t *idp, ushort_t kind, 9546ff6d951SJohn Birrell const dt_idops_t *ops, void *iarg) 9556ff6d951SJohn Birrell { 9566ff6d951SJohn Birrell idp->di_ops->di_dtor(idp); 9576ff6d951SJohn Birrell idp->di_kind = kind; 9586ff6d951SJohn Birrell idp->di_ops = ops; 9596ff6d951SJohn Birrell idp->di_iarg = iarg; 9606ff6d951SJohn Birrell idp->di_data = NULL; 9616ff6d951SJohn Birrell } 9626ff6d951SJohn Birrell 9636ff6d951SJohn Birrell dtrace_attribute_t 9646ff6d951SJohn Birrell dt_ident_cook(dt_node_t *dnp, dt_ident_t *idp, dt_node_t **pargp) 9656ff6d951SJohn Birrell { 9666ff6d951SJohn Birrell dtrace_attribute_t attr; 9676ff6d951SJohn Birrell dt_node_t *args, *argp; 9686ff6d951SJohn Birrell int argc = 0; 9696ff6d951SJohn Birrell 9706ff6d951SJohn Birrell attr = dt_node_list_cook(pargp, DT_IDFLG_REF); 9716ff6d951SJohn Birrell args = pargp ? *pargp : NULL; 9726ff6d951SJohn Birrell 9736ff6d951SJohn Birrell for (argp = args; argp != NULL; argp = argp->dn_list) 9746ff6d951SJohn Birrell argc++; 9756ff6d951SJohn Birrell 9766ff6d951SJohn Birrell idp->di_ops->di_cook(dnp, idp, argc, args); 9776ff6d951SJohn Birrell 9786ff6d951SJohn Birrell if (idp->di_flags & DT_IDFLG_USER) 9796ff6d951SJohn Birrell dnp->dn_flags |= DT_NF_USERLAND; 9806ff6d951SJohn Birrell 9816ff6d951SJohn Birrell return (dt_attr_min(attr, idp->di_attr)); 9826ff6d951SJohn Birrell } 9836ff6d951SJohn Birrell 9846ff6d951SJohn Birrell void 9856ff6d951SJohn Birrell dt_ident_type_assign(dt_ident_t *idp, ctf_file_t *fp, ctf_id_t type) 9866ff6d951SJohn Birrell { 9876ff6d951SJohn Birrell idp->di_ctfp = fp; 9886ff6d951SJohn Birrell idp->di_type = type; 9896ff6d951SJohn Birrell } 9906ff6d951SJohn Birrell 9916ff6d951SJohn Birrell dt_ident_t * 9926ff6d951SJohn Birrell dt_ident_resolve(dt_ident_t *idp) 9936ff6d951SJohn Birrell { 9946ff6d951SJohn Birrell while (idp->di_flags & DT_IDFLG_INLINE) { 9956ff6d951SJohn Birrell const dt_node_t *dnp = ((dt_idnode_t *)idp->di_iarg)->din_root; 9966ff6d951SJohn Birrell 9976ff6d951SJohn Birrell if (dnp == NULL) 9986ff6d951SJohn Birrell break; /* can't resolve any further yet */ 9996ff6d951SJohn Birrell 10006ff6d951SJohn Birrell switch (dnp->dn_kind) { 10016ff6d951SJohn Birrell case DT_NODE_VAR: 10026ff6d951SJohn Birrell case DT_NODE_SYM: 10036ff6d951SJohn Birrell case DT_NODE_FUNC: 10046ff6d951SJohn Birrell case DT_NODE_AGG: 10056ff6d951SJohn Birrell case DT_NODE_INLINE: 10066ff6d951SJohn Birrell case DT_NODE_PROBE: 10076ff6d951SJohn Birrell idp = dnp->dn_ident; 10086ff6d951SJohn Birrell continue; 10096ff6d951SJohn Birrell } 10106ff6d951SJohn Birrell 10116ff6d951SJohn Birrell if (dt_node_is_dynamic(dnp)) 10126ff6d951SJohn Birrell idp = dnp->dn_ident; 10136ff6d951SJohn Birrell else 10146ff6d951SJohn Birrell break; 10156ff6d951SJohn Birrell } 10166ff6d951SJohn Birrell 10176ff6d951SJohn Birrell return (idp); 10186ff6d951SJohn Birrell } 10196ff6d951SJohn Birrell 10206ff6d951SJohn Birrell size_t 10216ff6d951SJohn Birrell dt_ident_size(dt_ident_t *idp) 10226ff6d951SJohn Birrell { 10236ff6d951SJohn Birrell idp = dt_ident_resolve(idp); 10246ff6d951SJohn Birrell return (idp->di_ops->di_size(idp)); 10256ff6d951SJohn Birrell } 10266ff6d951SJohn Birrell 10276ff6d951SJohn Birrell int 10286ff6d951SJohn Birrell dt_ident_unref(const dt_ident_t *idp) 10296ff6d951SJohn Birrell { 10306ff6d951SJohn Birrell return (idp->di_gen == yypcb->pcb_hdl->dt_gen && 10316ff6d951SJohn Birrell (idp->di_flags & (DT_IDFLG_REF|DT_IDFLG_MOD|DT_IDFLG_DECL)) == 0); 10326ff6d951SJohn Birrell } 10336ff6d951SJohn Birrell 10346ff6d951SJohn Birrell const char * 10356ff6d951SJohn Birrell dt_idkind_name(uint_t kind) 10366ff6d951SJohn Birrell { 10376ff6d951SJohn Birrell switch (kind) { 10386ff6d951SJohn Birrell case DT_IDENT_ARRAY: return ("associative array"); 10396ff6d951SJohn Birrell case DT_IDENT_SCALAR: return ("scalar"); 10406ff6d951SJohn Birrell case DT_IDENT_PTR: return ("pointer"); 10416ff6d951SJohn Birrell case DT_IDENT_FUNC: return ("function"); 10426ff6d951SJohn Birrell case DT_IDENT_AGG: return ("aggregation"); 10436ff6d951SJohn Birrell case DT_IDENT_AGGFUNC: return ("aggregating function"); 10446ff6d951SJohn Birrell case DT_IDENT_ACTFUNC: return ("tracing function"); 10456ff6d951SJohn Birrell case DT_IDENT_XLSOU: return ("translated data"); 10466ff6d951SJohn Birrell case DT_IDENT_XLPTR: return ("pointer to translated data"); 10476ff6d951SJohn Birrell case DT_IDENT_SYMBOL: return ("external symbol reference"); 10486ff6d951SJohn Birrell case DT_IDENT_ENUM: return ("enumerator"); 10496ff6d951SJohn Birrell case DT_IDENT_PRAGAT: return ("#pragma attributes"); 10506ff6d951SJohn Birrell case DT_IDENT_PRAGBN: return ("#pragma binding"); 10516ff6d951SJohn Birrell case DT_IDENT_PROBE: return ("probe definition"); 10526ff6d951SJohn Birrell default: return ("<?>"); 10536ff6d951SJohn Birrell } 10546ff6d951SJohn Birrell } 1055