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