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