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