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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
25 * tree.c -- routines for manipulating the prop tree
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.
32 #pragma ident "%Z%%M% %I% %E% SMI"
50 static struct node
*Root
;
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
;
70 struct lut
*Usedprops
;
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);
90 stats_new_counter("parser.nodesize", "sizeof(struct node)", 1);
91 stats_counter_add(Nodesize
, sizeof (struct node
));
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
);
113 /* free entire parse tree */
116 /* free up the luts we keep for decls */
117 lut_free(Faults
, NULL
, NULL
);
119 lut_free(Upsets
, NULL
, NULL
);
121 lut_free(Defects
, NULL
, NULL
);
123 lut_free(Errors
, NULL
, NULL
);
125 lut_free(Ereports
, NULL
, 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
);
133 lut_free(STATs
, NULL
, NULL
);
135 lut_free(ASRUs
, NULL
, NULL
);
137 lut_free(FRUs
, NULL
, NULL
);
139 lut_free(Configs
, NULL
, NULL
);
141 lut_free(Usedprops
, NULL
, NULL
);
144 Props
= Lastprops
= NULL
;
145 Masks
= Lastmasks
= NULL
;
146 Problems
= Lastproblems
= NULL
;
148 if (Newname
!= NULL
) {
156 nodesize(enum nodetype t
, struct node
*ret
)
158 int size
= sizeof (struct node
);
162 size
+= sizeof (ret
->u
.name
) - sizeof (ret
->u
);
166 size
+= sizeof (ret
->u
.globid
) - sizeof (ret
->u
);
171 size
+= sizeof (ret
->u
.ull
) - sizeof (ret
->u
);
175 size
+= sizeof (ret
->u
.quote
) - sizeof (ret
->u
);
179 size
+= sizeof (ret
->u
.func
) - sizeof (ret
->u
);
194 size
+= sizeof (ret
->u
.stmt
) - sizeof (ret
->u
);
198 size
+= sizeof (ret
->u
.event
) - sizeof (ret
->u
);
202 size
+= sizeof (ret
->u
.arrow
) - sizeof (ret
->u
);
206 size
+= sizeof (ret
->u
.expr
) - sizeof (ret
->u
);
213 newnode(enum nodetype t
, const char *file
, int line
)
215 struct node
*ret
= NULL
;
216 int size
= nodesize(t
, ret
);
218 ret
= alloc_xmalloc(size
);
219 stats_counter_bump(Nodecount
);
222 ret
->file
= (file
== NULL
) ? "<nofile>" : file
;
230 tree_free(struct node
*root
)
237 tree_free(root
->u
.name
.child
);
238 tree_free(root
->u
.name
.next
);
241 tree_free(root
->u
.func
.arglist
);
267 tree_free(root
->u
.expr
.left
);
268 tree_free(root
->u
.expr
.right
);
271 tree_free(root
->u
.event
.ename
);
272 tree_free(root
->u
.event
.epname
);
273 tree_free(root
->u
.event
.eexprlist
);
276 tree_free(root
->u
.expr
.left
);
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
);
286 tree_free(root
->u
.stmt
.np
);
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
);
312 "internal error: tree_free unexpected nodetype: %d",
316 alloc_xfree((char *)root
, nodesize(root
->t
, root
));
320 tree_treecmp(struct node
*np1
, struct node
*np2
, enum nodetype t
,
323 if (np1
== NULL
|| np2
== NULL
)
326 if (np1
->t
!= np2
->t
)
329 ASSERT(cmp_func
!= NULL
);
332 return ((*cmp_func
)(np1
, np2
));
336 if (tree_treecmp(np1
->u
.name
.child
, np2
->u
.name
.child
, t
,
339 return (tree_treecmp(np1
->u
.name
.next
, np2
->u
.name
.next
, t
,
344 return (tree_treecmp(np1
->u
.func
.arglist
, np2
->u
.func
.arglist
,
372 if (tree_treecmp(np1
->u
.expr
.left
, np2
->u
.expr
.left
, t
,
375 return (tree_treecmp(np1
->u
.expr
.right
, np2
->u
.expr
.right
, t
,
380 if (tree_treecmp(np1
->u
.event
.ename
, np2
->u
.event
.ename
, t
,
383 if (tree_treecmp(np1
->u
.event
.epname
, np2
->u
.event
.epname
, t
,
386 return (tree_treecmp(np1
->u
.event
.eexprlist
,
387 np2
->u
.event
.eexprlist
, t
, cmp_func
));
391 return (tree_treecmp(np1
->u
.expr
.left
, np2
->u
.expr
.left
, t
,
396 if (tree_treecmp(np1
->u
.arrow
.lhs
, np2
->u
.arrow
.lhs
, t
,
399 if (tree_treecmp(np1
->u
.arrow
.nnp
, np2
->u
.arrow
.nnp
, t
,
402 if (tree_treecmp(np1
->u
.arrow
.knp
, np2
->u
.arrow
.knp
, t
,
405 return (tree_treecmp(np1
->u
.arrow
.rhs
, np2
->u
.arrow
.rhs
, t
,
411 return (tree_treecmp(np1
->u
.stmt
.np
, np2
->u
.stmt
.np
, t
,
424 if (tree_treecmp(np1
->u
.stmt
.np
, np2
->u
.stmt
.np
, t
, cmp_func
))
426 return (tree_treecmp(np1
->u
.stmt
.nvpairs
, np2
->u
.stmt
.nvpairs
,
438 "internal error: tree_treecmp unexpected nodetype: %d",
448 tree_root(struct node
*np
)
458 return (newnode(T_NOTHING
, L_nofile
, 0));
462 tree_expr(enum nodetype t
, struct node
*left
, struct node
*right
)
466 ASSERTinfo(left
!= NULL
|| right
!= NULL
, ptree_nodetype2str(t
));
469 (left
) ? left
->file
: right
->file
,
470 (left
) ? left
->line
: right
->line
);
472 ret
->u
.expr
.left
= left
;
473 ret
->u
.expr
.right
= right
;
481 * ename_compress -- convert event class name in to more space-efficient form
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.
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.
495 ename_compress(struct node
*ename
)
505 ASSERT(ename
->t
== T_NAME
);
507 if (ename
->u
.name
.next
== NULL
)
508 return (ename
); /* no compression to be applied here */
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
);
515 cp
= buf
= alloca(len
);
516 for (np
= ename
; np
!= NULL
; np
= np
->u
.name
.next
) {
517 ASSERT(np
->t
== T_NAME
);
520 (void) strcpy(cp
, np
->u
.name
.s
);
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
;
532 tree_event(struct node
*ename
, struct node
*epname
, struct node
*eexprlist
)
536 ASSERT(ename
!= NULL
);
538 ret
= newnode(T_EVENT
, ename
->file
, ename
->line
);
540 ret
->u
.event
.ename
= ename_compress(ename
);
541 ret
->u
.event
.epname
= epname
;
542 ret
->u
.event
.eexprlist
= eexprlist
;
550 tree_name(const char *s
, enum itertype it
, const char *file
, int line
)
552 struct node
*ret
= newnode(T_NAME
, file
, line
);
556 stats_counter_bump(Namecount
);
557 ret
->u
.name
.t
= N_UNSPEC
;
558 ret
->u
.name
.s
= stable(s
);
560 ret
->u
.name
.last
= ret
;
562 if (it
== IT_ENAME
) {
563 /* PHASE2, possible optimization: convert to table driven */
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
;
579 outfl(O_ERR
, file
, line
, "unknown class: %s", s
);
585 tree_iname(const char *s
, const char *file
, int line
)
591 ASSERT(s
!= NULL
&& *s
!= '\0');
595 ptr
= &ss
[strlen(ss
) - 1];
596 if (!isdigit(*ptr
)) {
597 outfl(O_ERR
, file
, line
,
598 "instanced name expected (i.e. \"x0/y1\")");
600 return (tree_name(s
, IT_NONE
, file
, line
));
602 while (ptr
> ss
&& isdigit(*(ptr
- 1)))
605 ret
= newnode(T_NAME
, file
, line
);
606 stats_counter_bump(Namecount
);
607 ret
->u
.name
.child
= tree_num(ptr
, file
, line
);
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
;
619 tree_globid(const char *s
, const char *file
, int line
)
621 struct node
*ret
= newnode(T_GLOBID
, file
, line
);
625 ret
->u
.globid
.s
= stable(s
);
631 tree_name_append(struct node
*np1
, struct node
*np2
)
633 ASSERT(np1
!= NULL
&& np2
!= NULL
);
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
);
642 ASSERT(np1
->u
.name
.last
!= NULL
);
644 np1
->u
.name
.last
->u
.name
.next
= np2
;
645 np1
->u
.name
.last
= np2
;
650 * tree_name_repairdash -- repair a class name that contained a dash
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.
660 tree_name_repairdash(struct node
*np
, const char *s
)
665 ASSERT(np
!= NULL
&& s
!= NULL
);
668 outfl(O_DIE
, np
->file
, np
->line
,
669 "tree_name_repairdash: internal error (np type %d)",
672 ASSERT(np
->u
.name
.last
!= NULL
);
674 len
= strlen(np
->u
.name
.last
->u
.name
.s
) + 1 + strlen(s
) + 1;
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
);
683 tree_name_repairdash2(const char *s
, struct node
*np
)
688 ASSERT(np
!= NULL
&& s
!= NULL
);
691 outfl(O_DIE
, np
->file
, np
->line
,
692 "tree_name_repairdash: internal error (np type %d)",
695 ASSERT(np
->u
.name
.last
!= NULL
);
697 len
= strlen(np
->u
.name
.last
->u
.name
.s
) + 1 + strlen(s
) + 1;
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
);
706 tree_name_iterator(struct node
*np1
, struct node
*np2
)
710 ASSERTinfo(np1
->t
== T_NAME
, ptree_nodetype2str(np1
->t
));
712 np1
->u
.name
.child
= np2
;
714 check_name_iterator(np1
);
720 tree_timeval(const char *s
, const char *suffix
, const char *file
, int line
)
722 struct node
*ret
= newnode(T_TIMEVAL
, file
, line
);
723 const unsigned long long *ullp
;
726 ASSERT(suffix
!= NULL
);
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 */
734 ret
->u
.ull
= (unsigned long long)strtoul(s
, NULL
, 0) * *ullp
;
741 tree_num(const char *s
, const char *file
, int line
)
743 struct node
*ret
= newnode(T_NUM
, file
, line
);
745 ret
->u
.ull
= (unsigned long long)strtoul(s
, NULL
, 0);
750 tree_quote(const char *s
, const char *file
, int line
)
752 struct node
*ret
= newnode(T_QUOTE
, file
, line
);
754 ret
->u
.quote
.s
= stable(s
);
759 tree_func(const char *s
, struct node
*np
, const char *file
, int line
)
761 struct node
*ret
= newnode(T_FUNC
, file
, line
);
765 ret
->u
.func
.arglist
= np
;
770 * keep track of the properties we're interested in so we can ignore the
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) {
788 Usedprops
= lut_add(Usedprops
, (void *)ptr
, (void *)ptr
, NULL
);
790 Usedprops
= lut_add(Usedprops
, (void *)ptr
, (void *)ptr
, NULL
);
797 * given a list from a prop or mask statement or a function argument,
798 * convert all iterators to explicit iterators by inventing appropriate
802 make_explicit(struct node
*np
, int eventonly
)
804 struct node
*pnp
; /* component of pathname */
807 static size_t namesz
;
809 if (Newname
== NULL
) {
811 Newname
= MALLOC(namesz
);
815 return; /* all done */
842 make_explicit(np
->u
.expr
.left
, eventonly
);
843 make_explicit(np
->u
.expr
.right
, eventonly
);
847 make_explicit(np
->u
.event
.epname
, 0);
848 make_explicit(np
->u
.event
.eexprlist
, 1);
852 make_explicit(np
->u
.func
.arglist
, eventonly
);
858 for (pnp
= np
; pnp
!= NULL
; pnp
= pnp
->u
.name
.next
)
859 if (pnp
->u
.name
.child
== NULL
) {
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.
869 for (pnp2
= np
; pnp2
!= NULL
;
870 pnp2
= pnp2
->u
.name
.next
)
873 else if (pnp2
->u
.name
.s
==
877 if (namesz
< strlen(pnp
->u
.name
.s
) +
879 namesz
= strlen(pnp
->u
.name
.s
) +
882 Newname
= MALLOC(namesz
);
885 * made up interator name is:
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.
896 (void) snprintf(Newname
, namesz
,
897 "%s#%s%d", pnp
->u
.name
.s
,
898 (pnp
->u
.name
.it
== IT_HORIZONTAL
) ?
901 pnp
->u
.name
.child
= tree_name(Newname
,
902 IT_NONE
, pnp
->file
, pnp
->line
);
903 pnp
->u
.name
.childgen
= 1;
910 tree_pname(struct node
*np
)
912 make_explicit(np
, 0);
917 tree_arrow(struct node
*lhs
, struct node
*nnp
, struct node
*knp
,
922 ASSERT(lhs
!= NULL
|| rhs
!= NULL
);
924 ret
= newnode(T_ARROW
,
925 (lhs
) ? lhs
->file
: rhs
->file
,
926 (lhs
) ? lhs
->line
: rhs
->line
);
928 ret
->u
.arrow
.lhs
= lhs
;
929 ret
->u
.arrow
.nnp
= nnp
;
930 ret
->u
.arrow
.knp
= knp
;
931 ret
->u
.arrow
.rhs
= rhs
;
933 make_explicit(lhs
, 0);
934 make_explicit(rhs
, 0);
942 nvpair2lut(struct node
*np
, struct lut
*lutp
, enum nodetype t
)
945 if (np
->t
== T_NVPAIR
) {
946 ASSERTeq(np
->u
.expr
.left
->t
, T_NAME
,
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
);
955 outfl(O_DIE
, np
->file
, np
->line
,
956 "internal error: nvpair2lut type %s",
957 ptree_nodetype2str(np
->t
));
964 tree_s2np_lut_add(struct lut
*root
, const char *s
, struct node
*np
)
966 return (lut_add(root
, (void *)s
, (void *)np
, NULL
));
970 tree_s2np_lut_lookup(struct lut
*root
, const char *s
)
972 return (struct node
*)lut_lookup(root
, (void *)s
, NULL
);
976 tree_name2np_lut_add(struct lut
*root
, struct node
*namep
, struct node
*np
)
978 return (lut_add(root
, (void *)namep
, (void *)np
,
979 (lut_cmp
)tree_namecmp
));
983 tree_name2np_lut_lookup(struct lut
*root
, struct node
*namep
)
985 return (struct node
*)
986 lut_lookup(root
, (void *)namep
, (lut_cmp
)tree_namecmp
);
990 tree_name2np_lut_lookup_name(struct lut
*root
, struct node
*namep
)
992 return (struct node
*)
993 lut_lookup_lhs(root
, (void *)namep
, (lut_cmp
)tree_namecmp
);
997 tree_event2np_lut_add(struct lut
*root
, struct node
*enp
, struct node
*np
)
999 return (lut_add(root
, (void *)enp
, (void *)np
, (lut_cmp
)tree_eventcmp
));
1003 tree_event2np_lut_lookup(struct lut
*root
, struct node
*enp
)
1005 return ((struct node
*)
1006 lut_lookup(root
, (void *)enp
, (lut_cmp
)tree_eventcmp
));
1010 tree_event2np_lut_lookup_event(struct lut
*root
, struct node
*enp
)
1012 return ((struct node
*)
1013 lut_lookup_lhs(root
, (void *)enp
, (lut_cmp
)tree_eventcmp
));
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
)
1024 /* allocate parse tree node */
1025 ret
= newnode(t
, file
, line
);
1026 ret
->u
.stmt
.np
= np
;
1027 ret
->u
.stmt
.nvpairs
= nvpairs
;
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.
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
);
1051 /* was declared before, just add new nvpairs to its lutp */
1052 decl
->u
.stmt
.lutp
= nvpair2lut(nvpairs
, decl
->u
.stmt
.lutp
, t
);
1060 update_serd_refstmt(void *lhs
, void *rhs
, void *arg
)
1064 ASSERT(rhs
!= NULL
);
1066 serd
= tree_s2np_lut_lookup(((struct node
*)rhs
)->u
.stmt
.lutp
,
1071 ASSERT(serd
->t
== T_EVENT
);
1072 if (arg
!= NULL
&& tree_eventcmp(serd
, (struct node
*)arg
) != 0)
1075 serd
= tree_event2np_lut_lookup(SERDs
, serd
);
1077 serd
->u
.stmt
.flags
|= STMT_REF
;
1081 tree_decl(enum nodetype t
, struct node
*np
, struct node
*nvpairs
,
1082 const char *file
, int line
)
1089 check_type_iterator(np
);
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
) {
1097 ret
= dodecl(T_FAULT
, file
, line
, np
, nvpairs
,
1098 &Faults
, Faultcount
, 0);
1100 /* increment serd statement reference */
1101 decl
= tree_event2np_lut_lookup(Faults
, np
);
1102 update_serd_refstmt(NULL
, decl
, NULL
);
1106 ret
= dodecl(T_UPSET
, file
, line
, np
, nvpairs
,
1107 &Upsets
, Upsetcount
, 0);
1109 /* increment serd statement reference */
1110 decl
= tree_event2np_lut_lookup(Upsets
, np
);
1111 update_serd_refstmt(NULL
, decl
, NULL
);
1115 ret
= dodecl(T_DEFECT
, file
, line
, np
, nvpairs
,
1116 &Defects
, Defectcount
, 0);
1118 /* increment serd statement reference */
1119 decl
= tree_event2np_lut_lookup(Defects
, np
);
1120 update_serd_refstmt(NULL
, decl
, NULL
);
1124 ret
= dodecl(T_ERROR
, file
, line
, np
, nvpairs
,
1125 &Errors
, Errorcount
, 0);
1129 ret
= dodecl(T_EREPORT
, file
, line
, np
, nvpairs
,
1130 &Ereports
, Ereportcount
, 0);
1132 * Keep a lut of just the enames, so that the DE
1133 * can subscribe to a uniqified list of event
1137 tree_name2np_lut_add(Ereportenames
,
1138 np
->u
.event
.ename
, np
);
1141 * Keep a lut of the enames (event classes) to
1142 * silently discard if we can't find a matching
1143 * configuration node when an ereport of of a given
1144 * class is received. Such events are declaired
1145 * with 'discard_if_config_unknown=1'.
1147 if (tree_s2np_lut_lookup(ret
->u
.stmt
.lutp
,
1148 L_discard_if_config_unknown
)) {
1149 Ereportenames_discard
= lut_add(
1150 Ereportenames_discard
,
1151 (void *)np
->u
.event
.ename
->u
.name
.s
,
1152 (void *)np
->u
.event
.ename
->u
.name
.s
, NULL
);
1157 outfl(O_ERR
, file
, line
,
1158 "tree_decl: internal error, event name type %s",
1159 ptree_nametype2str(np
->u
.event
.ename
->u
.name
.t
));
1164 /* determine the type of engine being declared */
1165 ASSERT(np
->u
.event
.ename
->t
== T_NAME
);
1166 switch (np
->u
.event
.ename
->u
.name
.t
) {
1168 ret
= dodecl(T_SERD
, file
, line
, np
, nvpairs
,
1169 &SERDs
, SERDcount
, 0);
1170 lut_walk(Upsets
, update_serd_refstmt
, np
);
1174 ret
= dodecl(T_STAT
, file
, line
, np
, nvpairs
,
1175 &STATs
, STATcount
, 0);
1179 outfl(O_ERR
, file
, line
,
1180 "tree_decl: internal error, engine name type %s",
1181 ptree_nametype2str(np
->u
.event
.ename
->u
.name
.t
));
1185 ret
= dodecl(T_ASRU
, file
, line
, np
, nvpairs
,
1186 &ASRUs
, ASRUcount
, 1);
1190 ret
= dodecl(T_FRU
, file
, line
, np
, nvpairs
,
1191 &FRUs
, FRUcount
, 1);
1196 * config statements are different from above: they
1197 * are not merged at all (until the configuration cache
1198 * code does its own style of merging. and the properties
1199 * are a free-for-all -- we don't check for allowed or
1200 * required config properties.
1202 ret
= newnode(T_CONFIG
, file
, line
);
1203 ret
->u
.stmt
.np
= np
;
1204 ret
->u
.stmt
.nvpairs
= nvpairs
;
1205 ret
->u
.stmt
.lutp
= nvpair2lut(nvpairs
, NULL
, T_CONFIG
);
1207 if (lut_lookup(Configs
, np
, (lut_cmp
)tree_namecmp
) == NULL
)
1208 stats_counter_bump(Configcount
);
1210 Configs
= lut_add(Configs
, (void *)np
, (void *)ret
, NULL
);
1214 out(O_DIE
, "tree_decl: internal error, type %s",
1215 ptree_nodetype2str(t
));
1221 /* keep backpointers in arrows to the prop they belong to (used for scoping) */
1223 set_arrow_prop(struct node
*prop
, struct node
*np
)
1228 if (np
->t
== T_ARROW
) {
1229 np
->u
.arrow
.prop
= prop
;
1230 set_arrow_prop(prop
, np
->u
.arrow
.lhs
);
1232 * no need to recurse right or handle T_LIST since
1233 * T_ARROWs always cascade left and are at the top
1234 * of the parse tree. (you can see this in the rule
1235 * for "propbody" in escparse.y.)
1241 tree_stmt(enum nodetype t
, struct node
*np
, const char *file
, int line
)
1243 struct node
*ret
= newnode(t
, file
, line
);
1247 ret
->u
.stmt
.np
= np
;
1251 check_proplists(t
, np
);
1252 check_propnames(t
, np
, 0, 0);
1253 check_propscope(np
);
1254 set_arrow_prop(ret
, np
);
1256 for (pp
= Props
; pp
; pp
= pp
->u
.stmt
.next
) {
1257 if (tree_treecmp(pp
, ret
, T_NAME
,
1258 (lut_cmp
)tree_namecmp
) == 0) {
1264 stats_counter_bump(Propcount
);
1266 /* "Props" is a linked list of all prop statements */
1268 Lastprops
->u
.stmt
.next
= ret
;
1275 check_proplists(t
, np
);
1276 check_propnames(t
, np
, 0, 0);
1277 check_propscope(np
);
1278 set_arrow_prop(ret
, np
);
1280 for (pp
= Masks
; pp
; pp
= pp
->u
.stmt
.next
) {
1281 if (tree_treecmp(pp
, ret
, T_NAME
,
1282 (lut_cmp
)tree_namecmp
) == 0) {
1288 stats_counter_bump(Maskcount
);
1290 /* "Masks" is a linked list of all mask statements */
1292 Lastmasks
->u
.stmt
.next
= ret
;
1296 stats_counter_bump(Maskcount
);
1300 outfl(O_DIE
, np
->file
, np
->line
,
1301 "tree_stmt: internal error (t %d)", t
);
1311 * The only declarations with required properties
1312 * currently are faults and serds. Make sure the
1313 * the declarations have the required properties.
1315 lut_walk(Faults
, (lut_cb
)check_required_props
, (void *)T_FAULT
);
1316 lut_walk(Upsets
, (lut_cb
)check_required_props
, (void *)T_UPSET
);
1317 lut_walk(Errors
, (lut_cb
)check_required_props
, (void *)T_ERROR
);
1318 lut_walk(Ereports
, (lut_cb
)check_required_props
, (void *)T_EREPORT
);
1319 lut_walk(SERDs
, (lut_cb
)check_required_props
, (void *)T_SERD
);
1320 lut_walk(STATs
, (lut_cb
)check_required_props
, (void *)T_STAT
);
1323 * we do this now rather than while building the parse
1324 * tree because it is inconvenient for the user if we
1325 * require SERD engines to be declared before used in
1326 * an upset "engine" property.
1328 lut_walk(Faults
, (lut_cb
)check_refcount
, (void *)T_FAULT
);
1329 lut_walk(Faults
, (lut_cb
)check_upset_engine
, (void *)T_FAULT
);
1330 lut_walk(Defects
, (lut_cb
)check_upset_engine
, (void *)T_DEFECT
);
1331 lut_walk(Upsets
, (lut_cb
)check_upset_engine
, (void *)T_UPSET
);
1332 lut_walk(Upsets
, (lut_cb
)check_refcount
, (void *)T_UPSET
);
1333 lut_walk(Errors
, (lut_cb
)check_refcount
, (void *)T_ERROR
);
1334 lut_walk(Ereports
, (lut_cb
)check_refcount
, (void *)T_EREPORT
);
1335 lut_walk(SERDs
, (lut_cb
)check_refcount
, (void *)T_SERD
);
1337 /* check for cycles */
1338 lut_walk(Errors
, (lut_cb
)check_cycle
, NULL
);
1341 /* compare two T_NAMES by only looking at components, not iterators */
1343 tree_namecmp(struct node
*np1
, struct node
*np2
)
1345 ASSERT(np1
!= NULL
);
1346 ASSERT(np2
!= NULL
);
1347 ASSERTinfo(np1
->t
== T_NAME
, ptree_nodetype2str(np1
->t
));
1348 ASSERTinfo(np2
->t
== T_NAME
, ptree_nodetype2str(np1
->t
));
1350 while (np1
&& np2
&& np1
->u
.name
.s
== np2
->u
.name
.s
) {
1351 np1
= np1
->u
.name
.next
;
1352 np2
= np2
->u
.name
.next
;
1359 else if (np2
== NULL
)
1362 return (np2
->u
.name
.s
- np1
->u
.name
.s
);
1366 tree_eventcmp(struct node
*np1
, struct node
*np2
)
1370 ASSERT(np1
!= NULL
);
1371 ASSERT(np2
!= NULL
);
1372 ASSERTinfo(np1
->t
== T_EVENT
, ptree_nodetype2str(np1
->t
));
1373 ASSERTinfo(np2
->t
== T_EVENT
, ptree_nodetype2str(np2
->t
));
1375 if ((ret
= tree_namecmp(np1
->u
.event
.ename
,
1376 np2
->u
.event
.ename
)) == 0) {
1377 if (np1
->u
.event
.epname
== NULL
&&
1378 np2
->u
.event
.epname
== NULL
)
1380 else if (np1
->u
.event
.epname
== NULL
)
1382 else if (np2
->u
.event
.epname
== NULL
)
1385 return tree_namecmp(np1
->u
.event
.epname
,
1386 np2
->u
.event
.epname
);