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