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