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