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