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 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * tree.c -- routines for manipulating the prop tree 26 * 27 * the actions in escparse.y call these routines to construct 28 * the parse tree. these routines, in turn, call the check_X() 29 * routines for semantic checking. 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <ctype.h> 37 #include <strings.h> 38 #include <alloca.h> 39 #include "alloc.h" 40 #include "out.h" 41 #include "stats.h" 42 #include "stable.h" 43 #include "literals.h" 44 #include "lut.h" 45 #include "esclex.h" 46 #include "tree.h" 47 #include "check.h" 48 #include "ptree.h" 49 50 static struct node *Root; 51 52 static char *Newname; 53 54 static struct stats *Faultcount; 55 static struct stats *Upsetcount; 56 static struct stats *Defectcount; 57 static struct stats *Errorcount; 58 static struct stats *Ereportcount; 59 static struct stats *SERDcount; 60 static struct stats *STATcount; 61 static struct stats *ASRUcount; 62 static struct stats *FRUcount; 63 static struct stats *Configcount; 64 static struct stats *Propcount; 65 static struct stats *Maskcount; 66 static struct stats *Nodecount; 67 static struct stats *Namecount; 68 static struct stats *Nodesize; 69 70 struct lut *Usedprops; 71 72 void 73 tree_init(void) 74 { 75 Faultcount = stats_new_counter("parser.fault", "fault decls", 1); 76 Upsetcount = stats_new_counter("parser.upset", "upset decls", 1); 77 Defectcount = stats_new_counter("parser.defect", "defect decls", 1); 78 Errorcount = stats_new_counter("parser.error", "error decls", 1); 79 Ereportcount = stats_new_counter("parser.ereport", "ereport decls", 1); 80 SERDcount = stats_new_counter("parser.SERD", "SERD engine decls", 1); 81 STATcount = stats_new_counter("parser.STAT", "STAT engine decls", 1); 82 ASRUcount = stats_new_counter("parser.ASRU", "ASRU decls", 1); 83 FRUcount = stats_new_counter("parser.FRU", "FRU decls", 1); 84 Configcount = stats_new_counter("parser.config", "config stmts", 1); 85 Propcount = stats_new_counter("parser.prop", "prop stmts", 1); 86 Maskcount = stats_new_counter("parser.mask", "mask stmts", 1); 87 Nodecount = stats_new_counter("parser.node", "nodes created", 1); 88 Namecount = stats_new_counter("parser.name", "names created", 1); 89 Nodesize = 90 stats_new_counter("parser.nodesize", "sizeof(struct node)", 1); 91 stats_counter_add(Nodesize, sizeof (struct node)); 92 } 93 94 void 95 tree_fini(void) 96 { 97 stats_delete(Faultcount); 98 stats_delete(Upsetcount); 99 stats_delete(Defectcount); 100 stats_delete(Errorcount); 101 stats_delete(Ereportcount); 102 stats_delete(SERDcount); 103 stats_delete(STATcount); 104 stats_delete(ASRUcount); 105 stats_delete(FRUcount); 106 stats_delete(Configcount); 107 stats_delete(Propcount); 108 stats_delete(Maskcount); 109 stats_delete(Nodecount); 110 stats_delete(Namecount); 111 stats_delete(Nodesize); 112 113 /* free entire parse tree */ 114 tree_free(Root); 115 116 /* free up the luts we keep for decls */ 117 lut_free(Faults, NULL, NULL); 118 Faults = NULL; 119 lut_free(Upsets, NULL, NULL); 120 Upsets = NULL; 121 lut_free(Defects, NULL, NULL); 122 Defects = NULL; 123 lut_free(Errors, NULL, NULL); 124 Errors = NULL; 125 lut_free(Ereports, NULL, NULL); 126 Ereports = NULL; 127 lut_free(Ereportenames, NULL, NULL); 128 Ereportenames = NULL; 129 lut_free(SERDs, NULL, NULL); 130 SERDs = NULL; 131 lut_free(STATs, NULL, NULL); 132 STATs = NULL; 133 lut_free(ASRUs, NULL, NULL); 134 ASRUs = NULL; 135 lut_free(FRUs, NULL, NULL); 136 FRUs = NULL; 137 lut_free(Configs, NULL, NULL); 138 Configs = NULL; 139 lut_free(Usedprops, NULL, NULL); 140 Usedprops = NULL; 141 142 Props = Lastprops = NULL; 143 Masks = Lastmasks = NULL; 144 Problems = Lastproblems = NULL; 145 146 if (Newname != NULL) { 147 FREE(Newname); 148 Newname = NULL; 149 } 150 } 151 152 /*ARGSUSED*/ 153 static int 154 nodesize(enum nodetype t, struct node *ret) 155 { 156 int size = sizeof (struct node); 157 158 switch (t) { 159 case T_NAME: 160 size += sizeof (ret->u.name) - sizeof (ret->u); 161 break; 162 163 case T_GLOBID: 164 size += sizeof (ret->u.globid) - sizeof (ret->u); 165 break; 166 167 case T_TIMEVAL: 168 case T_NUM: 169 size += sizeof (ret->u.ull) - sizeof (ret->u); 170 break; 171 172 case T_QUOTE: 173 size += sizeof (ret->u.quote) - sizeof (ret->u); 174 break; 175 176 case T_FUNC: 177 size += sizeof (ret->u.func) - sizeof (ret->u); 178 break; 179 180 case T_FAULT: 181 case T_UPSET: 182 case T_DEFECT: 183 case T_ERROR: 184 case T_EREPORT: 185 case T_ASRU: 186 case T_FRU: 187 case T_SERD: 188 case T_STAT: 189 case T_CONFIG: 190 case T_PROP: 191 case T_MASK: 192 size += sizeof (ret->u.stmt) - sizeof (ret->u); 193 break; 194 195 case T_EVENT: 196 size += sizeof (ret->u.event) - sizeof (ret->u); 197 break; 198 199 case T_ARROW: 200 size += sizeof (ret->u.arrow) - sizeof (ret->u); 201 break; 202 203 default: 204 size += sizeof (ret->u.expr) - sizeof (ret->u); 205 break; 206 } 207 return (size); 208 } 209 210 struct node * 211 newnode(enum nodetype t, const char *file, int line) 212 { 213 struct node *ret = NULL; 214 int size = nodesize(t, ret); 215 216 ret = alloc_xmalloc(size); 217 stats_counter_bump(Nodecount); 218 bzero(ret, size); 219 ret->t = t; 220 ret->file = (file == NULL) ? "<nofile>" : file; 221 ret->line = line; 222 223 return (ret); 224 } 225 226 /*ARGSUSED*/ 227 void 228 tree_free(struct node *root) 229 { 230 if (root == NULL) 231 return; 232 233 switch (root->t) { 234 case T_NAME: 235 tree_free(root->u.name.child); 236 tree_free(root->u.name.next); 237 break; 238 case T_FUNC: 239 tree_free(root->u.func.arglist); 240 break; 241 case T_AND: 242 case T_OR: 243 case T_EQ: 244 case T_NE: 245 case T_ADD: 246 case T_DIV: 247 case T_MOD: 248 case T_MUL: 249 case T_SUB: 250 case T_LT: 251 case T_LE: 252 case T_GT: 253 case T_GE: 254 case T_BITAND: 255 case T_BITOR: 256 case T_BITXOR: 257 case T_BITNOT: 258 case T_LSHIFT: 259 case T_RSHIFT: 260 case T_NVPAIR: 261 case T_ASSIGN: 262 case T_CONDIF: 263 case T_CONDELSE: 264 case T_LIST: 265 tree_free(root->u.expr.left); 266 tree_free(root->u.expr.right); 267 break; 268 case T_EVENT: 269 tree_free(root->u.event.ename); 270 tree_free(root->u.event.epname); 271 tree_free(root->u.event.eexprlist); 272 break; 273 case T_NOT: 274 tree_free(root->u.expr.left); 275 break; 276 case T_ARROW: 277 tree_free(root->u.arrow.lhs); 278 tree_free(root->u.arrow.nnp); 279 tree_free(root->u.arrow.knp); 280 tree_free(root->u.arrow.rhs); 281 break; 282 case T_PROP: 283 case T_MASK: 284 tree_free(root->u.stmt.np); 285 break; 286 case T_FAULT: 287 case T_UPSET: 288 case T_DEFECT: 289 case T_ERROR: 290 case T_EREPORT: 291 case T_ASRU: 292 case T_FRU: 293 case T_SERD: 294 case T_STAT: 295 case T_CONFIG: 296 tree_free(root->u.stmt.np); 297 if (root->u.stmt.nvpairs) 298 tree_free(root->u.stmt.nvpairs); 299 if (root->u.stmt.lutp) 300 lut_free(root->u.stmt.lutp, NULL, NULL); 301 break; 302 case T_TIMEVAL: 303 case T_NUM: 304 case T_QUOTE: 305 case T_GLOBID: 306 case T_NOTHING: 307 break; 308 default: 309 out(O_DIE, 310 "internal error: tree_free unexpected nodetype: %d", 311 root->t); 312 /*NOTREACHED*/ 313 } 314 alloc_xfree((char *)root, nodesize(root->t, root)); 315 } 316 317 static int 318 tree_treecmp(struct node *np1, struct node *np2, enum nodetype t, 319 lut_cmp cmp_func) 320 { 321 if (np1 == NULL || np2 == NULL) 322 return (0); 323 324 if (np1->t != np2->t) 325 return (1); 326 327 ASSERT(cmp_func != NULL); 328 329 if (np1->t == t) 330 return ((*cmp_func)(np1, np2)); 331 332 switch (np1->t) { 333 case T_NAME: 334 if (tree_treecmp(np1->u.name.child, np2->u.name.child, t, 335 cmp_func)) 336 return (1); 337 return (tree_treecmp(np1->u.name.next, np2->u.name.next, t, 338 cmp_func)); 339 /*NOTREACHED*/ 340 break; 341 case T_FUNC: 342 return (tree_treecmp(np1->u.func.arglist, np2->u.func.arglist, 343 t, cmp_func)); 344 /*NOTREACHED*/ 345 break; 346 case T_AND: 347 case T_OR: 348 case T_EQ: 349 case T_NE: 350 case T_ADD: 351 case T_DIV: 352 case T_MOD: 353 case T_MUL: 354 case T_SUB: 355 case T_LT: 356 case T_LE: 357 case T_GT: 358 case T_GE: 359 case T_BITAND: 360 case T_BITOR: 361 case T_BITXOR: 362 case T_BITNOT: 363 case T_LSHIFT: 364 case T_RSHIFT: 365 case T_NVPAIR: 366 case T_ASSIGN: 367 case T_CONDIF: 368 case T_CONDELSE: 369 case T_LIST: 370 if (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t, 371 cmp_func)) 372 return (1); 373 return (tree_treecmp(np1->u.expr.right, np2->u.expr.right, t, 374 cmp_func)); 375 /*NOTREACHED*/ 376 break; 377 case T_EVENT: 378 if (tree_treecmp(np1->u.event.ename, np2->u.event.ename, t, 379 cmp_func)) 380 return (1); 381 if (tree_treecmp(np1->u.event.epname, np2->u.event.epname, t, 382 cmp_func)) 383 return (1); 384 return (tree_treecmp(np1->u.event.eexprlist, 385 np2->u.event.eexprlist, t, cmp_func)); 386 /*NOTREACHED*/ 387 break; 388 case T_NOT: 389 return (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t, 390 cmp_func)); 391 /*NOTREACHED*/ 392 break; 393 case T_ARROW: 394 if (tree_treecmp(np1->u.arrow.lhs, np2->u.arrow.lhs, t, 395 cmp_func)) 396 return (1); 397 if (tree_treecmp(np1->u.arrow.nnp, np2->u.arrow.nnp, t, 398 cmp_func)) 399 return (1); 400 if (tree_treecmp(np1->u.arrow.knp, np2->u.arrow.knp, t, 401 cmp_func)) 402 return (1); 403 return (tree_treecmp(np1->u.arrow.rhs, np2->u.arrow.rhs, t, 404 cmp_func)); 405 /*NOTREACHED*/ 406 break; 407 case T_PROP: 408 case T_MASK: 409 return (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, 410 cmp_func)); 411 /*NOTREACHED*/ 412 break; 413 case T_FAULT: 414 case T_UPSET: 415 case T_DEFECT: 416 case T_ERROR: 417 case T_EREPORT: 418 case T_ASRU: 419 case T_FRU: 420 case T_SERD: 421 case T_STAT: 422 if (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func)) 423 return (1); 424 return (tree_treecmp(np1->u.stmt.nvpairs, np2->u.stmt.nvpairs, 425 t, cmp_func)); 426 /*NOTREACHED*/ 427 break; 428 case T_TIMEVAL: 429 case T_NUM: 430 case T_QUOTE: 431 case T_GLOBID: 432 case T_NOTHING: 433 break; 434 default: 435 out(O_DIE, 436 "internal error: tree_treecmp unexpected nodetype: %d", 437 np1->t); 438 /*NOTREACHED*/ 439 break; 440 } 441 442 return (0); 443 } 444 445 struct node * 446 tree_root(struct node *np) 447 { 448 if (np) 449 Root = np; 450 return (Root); 451 } 452 453 struct node * 454 tree_nothing(void) 455 { 456 return (newnode(T_NOTHING, L_nofile, 0)); 457 } 458 459 struct node * 460 tree_expr(enum nodetype t, struct node *left, struct node *right) 461 { 462 struct node *ret; 463 464 ASSERTinfo(left != NULL || right != NULL, ptree_nodetype2str(t)); 465 466 ret = newnode(t, 467 (left) ? left->file : right->file, 468 (left) ? left->line : right->line); 469 470 ret->u.expr.left = left; 471 ret->u.expr.right = right; 472 473 check_expr(ret); 474 475 return (ret); 476 } 477 478 /* 479 * ename_compress -- convert event class name in to more space-efficient form 480 * 481 * this routine is called after the parser has completed an "ename", which 482 * is that part of an event that contains the class name (like ereport.x.y.z). 483 * after this routine gets done with the ename, two things are true: 484 * 1. the ename uses only a single struct node 485 * 2. ename->u.name.s contains the *complete* class name, dots and all, 486 * entered into the string table. 487 * 488 * so in addition to saving space by using fewer struct nodes, this routine 489 * allows consumers of the fault tree to assume the ename is a single 490 * string, rather than a linked list of strings. 491 */ 492 static struct node * 493 ename_compress(struct node *ename) 494 { 495 char *buf; 496 char *cp; 497 int len = 0; 498 struct node *np; 499 500 if (ename == NULL) 501 return (ename); 502 503 ASSERT(ename->t == T_NAME); 504 505 if (ename->u.name.next == NULL) 506 return (ename); /* no compression to be applied here */ 507 508 for (np = ename; np != NULL; np = np->u.name.next) { 509 ASSERT(np->t == T_NAME); 510 len++; /* room for '.' and final '\0' */ 511 len += strlen(np->u.name.s); 512 } 513 cp = buf = alloca(len); 514 for (np = ename; np != NULL; np = np->u.name.next) { 515 ASSERT(np->t == T_NAME); 516 if (np != ename) 517 *cp++ = '.'; 518 (void) strcpy(cp, np->u.name.s); 519 cp += strlen(cp); 520 } 521 522 ename->u.name.s = stable(buf); 523 tree_free(ename->u.name.next); 524 ename->u.name.next = NULL; 525 ename->u.name.last = ename; 526 return (ename); 527 } 528 529 struct node * 530 tree_event(struct node *ename, struct node *epname, struct node *eexprlist) 531 { 532 struct node *ret; 533 534 ASSERT(ename != NULL); 535 536 ret = newnode(T_EVENT, ename->file, ename->line); 537 538 ret->u.event.ename = ename_compress(ename); 539 ret->u.event.epname = epname; 540 ret->u.event.eexprlist = eexprlist; 541 542 check_event(ret); 543 544 return (ret); 545 } 546 547 struct node * 548 tree_name(const char *s, enum itertype it, const char *file, int line) 549 { 550 struct node *ret = newnode(T_NAME, file, line); 551 552 ASSERT(s != NULL); 553 554 stats_counter_bump(Namecount); 555 ret->u.name.t = N_UNSPEC; 556 ret->u.name.s = stable(s); 557 ret->u.name.it = it; 558 ret->u.name.last = ret; 559 560 if (it == IT_ENAME) { 561 /* PHASE2, possible optimization: convert to table driven */ 562 if (s == L_fault) 563 ret->u.name.t = N_FAULT; 564 else if (s == L_upset) 565 ret->u.name.t = N_UPSET; 566 else if (s == L_defect) 567 ret->u.name.t = N_DEFECT; 568 else if (s == L_error) 569 ret->u.name.t = N_ERROR; 570 else if (s == L_ereport) 571 ret->u.name.t = N_EREPORT; 572 else if (s == L_serd) 573 ret->u.name.t = N_SERD; 574 else if (s == L_stat) 575 ret->u.name.t = N_STAT; 576 else 577 outfl(O_ERR, file, line, "unknown class: %s", s); 578 } 579 return (ret); 580 } 581 582 struct node * 583 tree_iname(const char *s, const char *file, int line) 584 { 585 struct node *ret; 586 char *ss; 587 char *ptr; 588 589 ASSERT(s != NULL && *s != '\0'); 590 591 ss = STRDUP(s); 592 593 ptr = &ss[strlen(ss) - 1]; 594 if (!isdigit(*ptr)) { 595 outfl(O_ERR, file, line, 596 "instanced name expected (i.e. \"x0/y1\")"); 597 FREE(ss); 598 return (tree_name(s, IT_NONE, file, line)); 599 } 600 while (ptr > ss && isdigit(*(ptr - 1))) 601 ptr--; 602 603 ret = newnode(T_NAME, file, line); 604 stats_counter_bump(Namecount); 605 ret->u.name.child = tree_num(ptr, file, line); 606 *ptr = '\0'; 607 ret->u.name.t = N_UNSPEC; 608 ret->u.name.s = stable(ss); 609 ret->u.name.it = IT_NONE; 610 ret->u.name.last = ret; 611 FREE(ss); 612 613 return (ret); 614 } 615 616 struct node * 617 tree_globid(const char *s, const char *file, int line) 618 { 619 struct node *ret = newnode(T_GLOBID, file, line); 620 621 ASSERT(s != NULL); 622 623 ret->u.globid.s = stable(s); 624 625 return (ret); 626 } 627 628 struct node * 629 tree_name_append(struct node *np1, struct node *np2) 630 { 631 ASSERT(np1 != NULL && np2 != NULL); 632 633 if (np1->t != T_NAME) 634 outfl(O_DIE, np1->file, np1->line, 635 "tree_name_append: internal error (np1 type %d)", np1->t); 636 if (np2->t != T_NAME) 637 outfl(O_DIE, np2->file, np2->line, 638 "tree_name_append: internal error (np2 type %d)", np2->t); 639 640 ASSERT(np1->u.name.last != NULL); 641 642 np1->u.name.last->u.name.next = np2; 643 np1->u.name.last = np2; 644 return (np1); 645 } 646 647 /* 648 * tree_name_repairdash -- repair a class name that contained a dash 649 * 650 * this routine is called by the parser when a dash is encountered 651 * in a class name. the event protocol allows the dashes but our 652 * lexer considers them a separate token (arithmetic minus). an extra 653 * rule in the parser catches this case and calls this routine to fixup 654 * the last component of the class name (so far) by constructing the 655 * new stable entry for a name including the dash. 656 */ 657 struct node * 658 tree_name_repairdash(struct node *np, const char *s) 659 { 660 int len; 661 char *buf; 662 663 ASSERT(np != NULL && s != NULL); 664 665 if (np->t != T_NAME) 666 outfl(O_DIE, np->file, np->line, 667 "tree_name_repairdash: internal error (np type %d)", 668 np->t); 669 670 ASSERT(np->u.name.last != NULL); 671 672 len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1; 673 buf = MALLOC(len); 674 (void) snprintf(buf, len, "%s-%s", np->u.name.last->u.name.s, s); 675 np->u.name.last->u.name.s = stable(buf); 676 FREE(buf); 677 return (np); 678 } 679 680 struct node * 681 tree_name_repairdash2(const char *s, struct node *np) 682 { 683 int len; 684 char *buf; 685 686 ASSERT(np != NULL && s != NULL); 687 688 if (np->t != T_NAME) 689 outfl(O_DIE, np->file, np->line, 690 "tree_name_repairdash: internal error (np type %d)", 691 np->t); 692 693 ASSERT(np->u.name.last != NULL); 694 695 len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1; 696 buf = MALLOC(len); 697 (void) snprintf(buf, len, "%s-%s", s, np->u.name.last->u.name.s); 698 np->u.name.last->u.name.s = stable(buf); 699 FREE(buf); 700 return (np); 701 } 702 703 struct node * 704 tree_name_iterator(struct node *np1, struct node *np2) 705 { 706 ASSERT(np1 != NULL); 707 ASSERT(np2 != NULL); 708 ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t)); 709 710 np1->u.name.child = np2; 711 712 check_name_iterator(np1); 713 714 return (np1); 715 } 716 717 struct node * 718 tree_timeval(const char *s, const char *suffix, const char *file, int line) 719 { 720 struct node *ret = newnode(T_TIMEVAL, file, line); 721 const unsigned long long *ullp; 722 723 ASSERT(s != NULL); 724 ASSERT(suffix != NULL); 725 726 if ((ullp = lex_s2ullp_lut_lookup(Timesuffixlut, suffix)) == NULL) { 727 outfl(O_ERR, file, line, 728 "unrecognized number suffix: %s", suffix); 729 /* still construct a valid timeval node so parsing continues */ 730 ret->u.ull = 1; 731 } else { 732 ret->u.ull = (unsigned long long)strtoul(s, NULL, 0) * *ullp; 733 } 734 735 return (ret); 736 } 737 738 struct node * 739 tree_num(const char *s, const char *file, int line) 740 { 741 struct node *ret = newnode(T_NUM, file, line); 742 743 ret->u.ull = (unsigned long long)strtoul(s, NULL, 0); 744 return (ret); 745 } 746 747 struct node * 748 tree_quote(const char *s, const char *file, int line) 749 { 750 struct node *ret = newnode(T_QUOTE, file, line); 751 752 ret->u.quote.s = stable(s); 753 return (ret); 754 } 755 756 struct node * 757 tree_func(const char *s, struct node *np, const char *file, int line) 758 { 759 struct node *ret = newnode(T_FUNC, file, line); 760 const char *ptr; 761 762 ret->u.func.s = s; 763 ret->u.func.arglist = np; 764 765 check_func(ret); 766 767 /* 768 * keep track of the properties we're interested in so we can ignore the 769 * rest 770 */ 771 if (strcmp(s, L_confprop) == 0 || strcmp(s, L_confprop_defined) == 0) { 772 ptr = stable(np->u.expr.right->u.quote.s); 773 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 774 } else if (strcmp(s, L_is_connected) == 0) { 775 ptr = stable("connected"); 776 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 777 ptr = stable("CONNECTED"); 778 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 779 } else if (strcmp(s, L_is_type) == 0) { 780 ptr = stable("type"); 781 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 782 ptr = stable("TYPE"); 783 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 784 } else if (strcmp(s, L_is_on) == 0) { 785 ptr = stable("on"); 786 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 787 ptr = stable("ON"); 788 Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); 789 } 790 791 return (ret); 792 } 793 794 /* 795 * given a list from a prop or mask statement or a function argument, 796 * convert all iterators to explicit iterators by inventing appropriate 797 * iterator names. 798 */ 799 static void 800 make_explicit(struct node *np, int eventonly) 801 { 802 struct node *pnp; /* component of pathname */ 803 struct node *pnp2; 804 int count; 805 static size_t namesz; 806 807 if (Newname == NULL) { 808 namesz = 200; 809 Newname = MALLOC(namesz); 810 } 811 812 if (np == NULL) 813 return; /* all done */ 814 815 switch (np->t) { 816 case T_ASSIGN: 817 case T_CONDIF: 818 case T_CONDELSE: 819 case T_NE: 820 case T_EQ: 821 case T_LT: 822 case T_LE: 823 case T_GT: 824 case T_GE: 825 case T_BITAND: 826 case T_BITOR: 827 case T_BITXOR: 828 case T_BITNOT: 829 case T_LSHIFT: 830 case T_RSHIFT: 831 case T_LIST: 832 case T_AND: 833 case T_OR: 834 case T_NOT: 835 case T_ADD: 836 case T_SUB: 837 case T_MUL: 838 case T_DIV: 839 case T_MOD: 840 make_explicit(np->u.expr.left, eventonly); 841 make_explicit(np->u.expr.right, eventonly); 842 break; 843 844 case T_EVENT: 845 make_explicit(np->u.event.epname, 0); 846 make_explicit(np->u.event.eexprlist, 1); 847 break; 848 849 case T_FUNC: 850 make_explicit(np->u.func.arglist, eventonly); 851 break; 852 853 case T_NAME: 854 if (eventonly) 855 return; 856 for (pnp = np; pnp != NULL; pnp = pnp->u.name.next) 857 if (pnp->u.name.child == NULL) { 858 /* 859 * found implicit iterator. convert 860 * it to an explicit iterator by 861 * using the name of the component 862 * appended with '#' and the number 863 * of times we've seen this same 864 * component name in this path so far. 865 */ 866 count = 0; 867 for (pnp2 = np; pnp2 != NULL; 868 pnp2 = pnp2->u.name.next) 869 if (pnp2 == pnp) 870 break; 871 else if (pnp2->u.name.s == 872 pnp->u.name.s) 873 count++; 874 875 if (namesz < strlen(pnp->u.name.s) + 876 100) { 877 namesz = strlen(pnp->u.name.s) + 878 100; 879 FREE(Newname); 880 Newname = MALLOC(namesz); 881 } 882 /* 883 * made up interator name is: 884 * name#ordinal 885 * or 886 * name##ordinal 887 * the first one is used for vertical 888 * expansion, the second for horizontal. 889 * either way, the '#' embedded in 890 * the name makes it impossible to 891 * collide with an actual iterator 892 * given to us in the eversholt file. 893 */ 894 (void) snprintf(Newname, namesz, 895 "%s#%s%d", pnp->u.name.s, 896 (pnp->u.name.it == IT_HORIZONTAL) ? 897 "#" : "", count); 898 899 pnp->u.name.child = tree_name(Newname, 900 IT_NONE, pnp->file, pnp->line); 901 pnp->u.name.childgen = 1; 902 } 903 break; 904 } 905 } 906 907 struct node * 908 tree_pname(struct node *np) 909 { 910 make_explicit(np, 0); 911 return (np); 912 } 913 914 struct node * 915 tree_arrow(struct node *lhs, struct node *nnp, struct node *knp, 916 struct node *rhs) 917 { 918 struct node *ret; 919 920 ASSERT(lhs != NULL || rhs != NULL); 921 922 ret = newnode(T_ARROW, 923 (lhs) ? lhs->file : rhs->file, 924 (lhs) ? lhs->line : rhs->line); 925 926 ret->u.arrow.lhs = lhs; 927 ret->u.arrow.nnp = nnp; 928 ret->u.arrow.knp = knp; 929 ret->u.arrow.rhs = rhs; 930 931 make_explicit(lhs, 0); 932 make_explicit(rhs, 0); 933 934 check_arrow(ret); 935 936 return (ret); 937 } 938 939 static struct lut * 940 nvpair2lut(struct node *np, struct lut *lutp, enum nodetype t) 941 { 942 if (np) { 943 if (np->t == T_NVPAIR) { 944 ASSERTeq(np->u.expr.left->t, T_NAME, 945 ptree_nodetype2str); 946 check_stmt_allowed_properties(t, np, lutp); 947 lutp = tree_s2np_lut_add(lutp, 948 np->u.expr.left->u.name.s, np->u.expr.right); 949 } else if (np->t == T_LIST) { 950 lutp = nvpair2lut(np->u.expr.left, lutp, t); 951 lutp = nvpair2lut(np->u.expr.right, lutp, t); 952 } else 953 outfl(O_DIE, np->file, np->line, 954 "internal error: nvpair2lut type %s", 955 ptree_nodetype2str(np->t)); 956 } 957 958 return (lutp); 959 } 960 961 struct lut * 962 tree_s2np_lut_add(struct lut *root, const char *s, struct node *np) 963 { 964 return (lut_add(root, (void *)s, (void *)np, NULL)); 965 } 966 967 struct node * 968 tree_s2np_lut_lookup(struct lut *root, const char *s) 969 { 970 return (struct node *)lut_lookup(root, (void *)s, NULL); 971 } 972 973 struct lut * 974 tree_name2np_lut_add(struct lut *root, struct node *namep, struct node *np) 975 { 976 return (lut_add(root, (void *)namep, (void *)np, 977 (lut_cmp)tree_namecmp)); 978 } 979 980 struct node * 981 tree_name2np_lut_lookup(struct lut *root, struct node *namep) 982 { 983 return (struct node *) 984 lut_lookup(root, (void *)namep, (lut_cmp)tree_namecmp); 985 } 986 987 struct node * 988 tree_name2np_lut_lookup_name(struct lut *root, struct node *namep) 989 { 990 return (struct node *) 991 lut_lookup_lhs(root, (void *)namep, (lut_cmp)tree_namecmp); 992 } 993 994 struct lut * 995 tree_event2np_lut_add(struct lut *root, struct node *enp, struct node *np) 996 { 997 return (lut_add(root, (void *)enp, (void *)np, (lut_cmp)tree_eventcmp)); 998 } 999 1000 struct node * 1001 tree_event2np_lut_lookup(struct lut *root, struct node *enp) 1002 { 1003 return ((struct node *) 1004 lut_lookup(root, (void *)enp, (lut_cmp)tree_eventcmp)); 1005 } 1006 1007 struct node * 1008 tree_event2np_lut_lookup_event(struct lut *root, struct node *enp) 1009 { 1010 return ((struct node *) 1011 lut_lookup_lhs(root, (void *)enp, (lut_cmp)tree_eventcmp)); 1012 } 1013 1014 static struct node * 1015 dodecl(enum nodetype t, const char *file, int line, 1016 struct node *np, struct node *nvpairs, struct lut **lutpp, 1017 struct stats *countp, int justpath) 1018 { 1019 struct node *ret; 1020 struct node *decl; 1021 1022 /* allocate parse tree node */ 1023 ret = newnode(t, file, line); 1024 ret->u.stmt.np = np; 1025 ret->u.stmt.nvpairs = nvpairs; 1026 1027 /* 1028 * the global lut pointed to by lutpp (Faults, Defects, Upsets, 1029 * Errors, Ereports, Serds, FRUs, or ASRUs) keeps the first decl. 1030 * if this isn't the first declr, we merge the 1031 * nvpairs into the first decl so we have a 1032 * merged table to look up properties from. 1033 * if this is the first time we've seen this fault, 1034 * we add it to the global lut and start lutp 1035 * off with any nvpairs from this declaration statement. 1036 */ 1037 if (justpath && (decl = tree_name2np_lut_lookup(*lutpp, np)) == NULL) { 1038 /* this is the first time name is declared */ 1039 stats_counter_bump(countp); 1040 *lutpp = tree_name2np_lut_add(*lutpp, np, ret); 1041 ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t); 1042 } else if (!justpath && 1043 (decl = tree_event2np_lut_lookup(*lutpp, np)) == NULL) { 1044 /* this is the first time event is declared */ 1045 stats_counter_bump(countp); 1046 *lutpp = tree_event2np_lut_add(*lutpp, np, ret); 1047 ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t); 1048 } else { 1049 /* was declared before, just add new nvpairs to its lutp */ 1050 decl->u.stmt.lutp = nvpair2lut(nvpairs, decl->u.stmt.lutp, t); 1051 } 1052 1053 return (ret); 1054 } 1055 1056 /*ARGSUSED*/ 1057 static void 1058 update_serd_refstmt(void *lhs, void *rhs, void *arg) 1059 { 1060 struct node *serd; 1061 1062 ASSERT(rhs != NULL); 1063 1064 serd = tree_s2np_lut_lookup(((struct node *)rhs)->u.stmt.lutp, 1065 L_engine); 1066 if (serd == NULL) 1067 return; 1068 1069 ASSERT(serd->t == T_EVENT); 1070 if (arg != NULL && tree_eventcmp(serd, (struct node *)arg) != 0) 1071 return; 1072 1073 serd = tree_event2np_lut_lookup(SERDs, serd); 1074 if (serd != NULL) 1075 serd->u.stmt.flags |= STMT_REF; 1076 } 1077 1078 struct node * 1079 tree_decl(enum nodetype t, struct node *np, struct node *nvpairs, 1080 const char *file, int line) 1081 { 1082 struct node *decl; 1083 struct node *ret; 1084 1085 ASSERT(np != NULL); 1086 1087 check_type_iterator(np); 1088 1089 switch (t) { 1090 case T_EVENT: 1091 /* determine the type of event being declared */ 1092 ASSERT(np->u.event.ename->t == T_NAME); 1093 switch (np->u.event.ename->u.name.t) { 1094 case N_FAULT: 1095 ret = dodecl(T_FAULT, file, line, np, nvpairs, 1096 &Faults, Faultcount, 0); 1097 break; 1098 1099 case N_UPSET: 1100 ret = dodecl(T_UPSET, file, line, np, nvpairs, 1101 &Upsets, Upsetcount, 0); 1102 1103 /* increment serd statement reference */ 1104 decl = tree_event2np_lut_lookup(Upsets, np); 1105 update_serd_refstmt(NULL, decl, NULL); 1106 break; 1107 1108 case N_DEFECT: 1109 ret = dodecl(T_DEFECT, file, line, np, nvpairs, 1110 &Defects, Defectcount, 0); 1111 break; 1112 1113 case N_ERROR: 1114 ret = dodecl(T_ERROR, file, line, np, nvpairs, 1115 &Errors, Errorcount, 0); 1116 break; 1117 1118 case N_EREPORT: 1119 ret = dodecl(T_EREPORT, file, line, np, nvpairs, 1120 &Ereports, Ereportcount, 0); 1121 /* 1122 * keep a lut of just the enames, so that the DE 1123 * can subscribe to a uniqified list of event 1124 * classes. 1125 */ 1126 Ereportenames = 1127 tree_name2np_lut_add(Ereportenames, 1128 np->u.event.ename, np); 1129 break; 1130 1131 default: 1132 outfl(O_ERR, file, line, 1133 "tree_decl: internal error, event name type %s", 1134 ptree_nametype2str(np->u.event.ename->u.name.t)); 1135 } 1136 break; 1137 1138 case T_ENGINE: 1139 /* determine the type of engine being declared */ 1140 ASSERT(np->u.event.ename->t == T_NAME); 1141 switch (np->u.event.ename->u.name.t) { 1142 case N_SERD: 1143 ret = dodecl(T_SERD, file, line, np, nvpairs, 1144 &SERDs, SERDcount, 0); 1145 lut_walk(Upsets, update_serd_refstmt, np); 1146 break; 1147 1148 case N_STAT: 1149 ret = dodecl(T_STAT, file, line, np, nvpairs, 1150 &STATs, STATcount, 0); 1151 break; 1152 1153 default: 1154 outfl(O_ERR, file, line, 1155 "tree_decl: internal error, engine name type %s", 1156 ptree_nametype2str(np->u.event.ename->u.name.t)); 1157 } 1158 break; 1159 case T_ASRU: 1160 ret = dodecl(T_ASRU, file, line, np, nvpairs, 1161 &ASRUs, ASRUcount, 1); 1162 break; 1163 1164 case T_FRU: 1165 ret = dodecl(T_FRU, file, line, np, nvpairs, 1166 &FRUs, FRUcount, 1); 1167 break; 1168 1169 case T_CONFIG: 1170 /* 1171 * config statements are different from above: they 1172 * are not merged at all (until the configuration cache 1173 * code does its own style of merging. and the properties 1174 * are a free-for-all -- we don't check for allowed or 1175 * required config properties. 1176 */ 1177 ret = newnode(T_CONFIG, file, line); 1178 ret->u.stmt.np = np; 1179 ret->u.stmt.nvpairs = nvpairs; 1180 ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, T_CONFIG); 1181 1182 if (lut_lookup(Configs, np, (lut_cmp)tree_namecmp) == NULL) 1183 stats_counter_bump(Configcount); 1184 1185 Configs = lut_add(Configs, (void *)np, (void *)ret, NULL); 1186 break; 1187 1188 default: 1189 out(O_DIE, "tree_decl: internal error, type %s", 1190 ptree_nodetype2str(t)); 1191 } 1192 1193 return (ret); 1194 } 1195 1196 /* keep backpointers in arrows to the prop they belong to (used for scoping) */ 1197 static void 1198 set_arrow_prop(struct node *prop, struct node *np) 1199 { 1200 if (np == NULL) 1201 return; 1202 1203 if (np->t == T_ARROW) { 1204 np->u.arrow.prop = prop; 1205 set_arrow_prop(prop, np->u.arrow.lhs); 1206 /* 1207 * no need to recurse right or handle T_LIST since 1208 * T_ARROWs always cascade left and are at the top 1209 * of the parse tree. (you can see this in the rule 1210 * for "propbody" in escparse.y.) 1211 */ 1212 } 1213 } 1214 1215 struct node * 1216 tree_stmt(enum nodetype t, struct node *np, const char *file, int line) 1217 { 1218 struct node *ret = newnode(t, file, line); 1219 struct node *pp; 1220 int inlist = 0; 1221 1222 ret->u.stmt.np = np; 1223 1224 switch (t) { 1225 case T_PROP: 1226 check_proplists(t, np); 1227 check_propnames(t, np, 0, 0); 1228 check_propscope(np); 1229 set_arrow_prop(ret, np); 1230 1231 for (pp = Props; pp; pp = pp->u.stmt.next) { 1232 if (tree_treecmp(pp, ret, T_NAME, 1233 (lut_cmp)tree_namecmp) == 0) { 1234 inlist = 1; 1235 break; 1236 } 1237 } 1238 if (inlist == 0) 1239 stats_counter_bump(Propcount); 1240 1241 /* "Props" is a linked list of all prop statements */ 1242 if (Lastprops) 1243 Lastprops->u.stmt.next = ret; 1244 else 1245 Props = ret; 1246 Lastprops = ret; 1247 break; 1248 1249 case T_MASK: 1250 check_proplists(t, np); 1251 check_propnames(t, np, 0, 0); 1252 check_propscope(np); 1253 set_arrow_prop(ret, np); 1254 1255 for (pp = Masks; pp; pp = pp->u.stmt.next) { 1256 if (tree_treecmp(pp, ret, T_NAME, 1257 (lut_cmp)tree_namecmp) == 0) { 1258 inlist = 1; 1259 break; 1260 } 1261 } 1262 if (inlist == 0) 1263 stats_counter_bump(Maskcount); 1264 1265 /* "Masks" is a linked list of all mask statements */ 1266 if (Lastmasks) 1267 Lastmasks->u.stmt.next = ret; 1268 else 1269 Masks = ret; 1270 Lastmasks = ret; 1271 stats_counter_bump(Maskcount); 1272 break; 1273 1274 default: 1275 outfl(O_DIE, np->file, np->line, 1276 "tree_stmt: internal error (t %d)", t); 1277 } 1278 1279 return (ret); 1280 } 1281 1282 void 1283 tree_report() 1284 { 1285 /* 1286 * The only declarations with required properties 1287 * currently are faults and serds. Make sure the 1288 * the declarations have the required properties. 1289 */ 1290 lut_walk(Faults, (lut_cb)check_required_props, (void *)T_FAULT); 1291 lut_walk(Upsets, (lut_cb)check_required_props, (void *)T_UPSET); 1292 lut_walk(Errors, (lut_cb)check_required_props, (void *)T_ERROR); 1293 lut_walk(Ereports, (lut_cb)check_required_props, (void *)T_EREPORT); 1294 lut_walk(SERDs, (lut_cb)check_required_props, (void *)T_SERD); 1295 lut_walk(STATs, (lut_cb)check_required_props, (void *)T_STAT); 1296 1297 /* 1298 * we do this now rather than while building the parse 1299 * tree because it is inconvenient for the user if we 1300 * require SERD engines to be declared before used in 1301 * an upset "engine" property. 1302 */ 1303 lut_walk(Faults, (lut_cb)check_refcount, (void *)T_FAULT); 1304 lut_walk(Upsets, (lut_cb)check_upset_engine, (void *)T_UPSET); 1305 lut_walk(Upsets, (lut_cb)check_refcount, (void *)T_UPSET); 1306 lut_walk(Errors, (lut_cb)check_refcount, (void *)T_ERROR); 1307 lut_walk(Ereports, (lut_cb)check_refcount, (void *)T_EREPORT); 1308 lut_walk(SERDs, (lut_cb)check_refcount, (void *)T_SERD); 1309 1310 /* check for cycles */ 1311 lut_walk(Errors, (lut_cb)check_cycle, (void *)0); 1312 } 1313 1314 /* compare two T_NAMES by only looking at components, not iterators */ 1315 int 1316 tree_namecmp(struct node *np1, struct node *np2) 1317 { 1318 ASSERT(np1 != NULL); 1319 ASSERT(np2 != NULL); 1320 ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t)); 1321 ASSERTinfo(np2->t == T_NAME, ptree_nodetype2str(np1->t)); 1322 1323 while (np1 && np2 && np1->u.name.s == np2->u.name.s) { 1324 np1 = np1->u.name.next; 1325 np2 = np2->u.name.next; 1326 } 1327 if (np1 == NULL) 1328 if (np2 == NULL) 1329 return (0); 1330 else 1331 return (-1); 1332 else if (np2 == NULL) 1333 return (1); 1334 else 1335 return (np2->u.name.s - np1->u.name.s); 1336 } 1337 1338 int 1339 tree_eventcmp(struct node *np1, struct node *np2) 1340 { 1341 int ret; 1342 1343 ASSERT(np1 != NULL); 1344 ASSERT(np2 != NULL); 1345 ASSERTinfo(np1->t == T_EVENT, ptree_nodetype2str(np1->t)); 1346 ASSERTinfo(np2->t == T_EVENT, ptree_nodetype2str(np2->t)); 1347 1348 if ((ret = tree_namecmp(np1->u.event.ename, 1349 np2->u.event.ename)) == 0) { 1350 if (np1->u.event.epname == NULL && 1351 np2->u.event.epname == NULL) 1352 return (0); 1353 else if (np1->u.event.epname == NULL) 1354 return (-1); 1355 else if (np2->u.event.epname == NULL) 1356 return (1); 1357 else 1358 return tree_namecmp(np1->u.event.epname, 1359 np2->u.event.epname); 1360 } else 1361 return (ret); 1362 } 1363