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
tree_init(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
tree_fini(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
nodesize(enum nodetype t,struct node * ret)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 *
newnode(enum nodetype t,const char * file,int line)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
tree_free(struct node * root)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
tree_treecmp(struct node * np1,struct node * np2,enum nodetype t,lut_cmp cmp_func)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 *
tree_root(struct node * np)448 tree_root(struct node *np)
449 {
450 if (np)
451 Root = np;
452 return (Root);
453 }
454
455 struct node *
tree_nothing(void)456 tree_nothing(void)
457 {
458 return (newnode(T_NOTHING, L_nofile, 0));
459 }
460
461 struct node *
tree_expr(enum nodetype t,struct node * left,struct node * right)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 *
ename_compress(struct node * ename)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 *
tree_event(struct node * ename,struct node * epname,struct node * eexprlist)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 *
tree_name(const char * s,enum itertype it,const char * file,int line)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 *
tree_iname(const char * s,const char * file,int line)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 *
tree_globid(const char * s,const char * file,int line)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 *
tree_name_append(struct node * np1,struct node * np2)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 *
tree_name_repairdash(struct node * np,const char * s)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 *
tree_name_repairdash2(const char * s,struct node * np)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 *
tree_name_iterator(struct node * np1,struct node * np2)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 *
tree_timeval(const char * s,const char * suffix,const char * file,int line)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 *
tree_num(const char * s,const char * file,int line)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 *
tree_quote(const char * s,const char * file,int line)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 *
tree_func(const char * s,struct node * np,const char * file,int line)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
make_explicit(struct node * np,int eventonly)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 *
tree_pname(struct node * np)910 tree_pname(struct node *np)
911 {
912 make_explicit(np, 0);
913 return (np);
914 }
915
916 struct node *
tree_arrow(struct node * lhs,struct node * nnp,struct node * knp,struct node * rhs)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 *
nvpair2lut(struct node * np,struct lut * lutp,enum nodetype t)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 *
tree_s2np_lut_add(struct lut * root,const char * s,struct node * np)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 *
tree_s2np_lut_lookup(struct lut * root,const char * s)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 *
tree_name2np_lut_add(struct lut * root,struct node * namep,struct node * np)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 *
tree_name2np_lut_lookup(struct lut * root,struct node * namep)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 *
tree_name2np_lut_lookup_name(struct lut * root,struct node * namep)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 *
tree_event2np_lut_add(struct lut * root,struct node * enp,struct node * np)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 *
tree_event2np_lut_lookup(struct lut * root,struct node * enp)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 *
tree_event2np_lut_lookup_event(struct lut * root,struct node * enp)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 *
dodecl(enum nodetype t,const char * file,int line,struct node * np,struct node * nvpairs,struct lut ** lutpp,struct stats * countp,int justpath)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
update_serd_refstmt(void * lhs,void * rhs,void * arg)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 *
tree_decl(enum nodetype t,struct node * np,struct node * nvpairs,const char * file,int line)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
1100 /* increment serd statement reference */
1101 decl = tree_event2np_lut_lookup(Faults, np);
1102 update_serd_refstmt(NULL, decl, NULL);
1103 break;
1104
1105 case N_UPSET:
1106 ret = dodecl(T_UPSET, file, line, np, nvpairs,
1107 &Upsets, Upsetcount, 0);
1108
1109 /* increment serd statement reference */
1110 decl = tree_event2np_lut_lookup(Upsets, np);
1111 update_serd_refstmt(NULL, decl, NULL);
1112 break;
1113
1114 case N_DEFECT:
1115 ret = dodecl(T_DEFECT, file, line, np, nvpairs,
1116 &Defects, Defectcount, 0);
1117
1118 /* increment serd statement reference */
1119 decl = tree_event2np_lut_lookup(Defects, np);
1120 update_serd_refstmt(NULL, decl, NULL);
1121 break;
1122
1123 case N_ERROR:
1124 ret = dodecl(T_ERROR, file, line, np, nvpairs,
1125 &Errors, Errorcount, 0);
1126 break;
1127
1128 case N_EREPORT:
1129 ret = dodecl(T_EREPORT, file, line, np, nvpairs,
1130 &Ereports, Ereportcount, 0);
1131 /*
1132 * Keep a lut of just the enames, so that the DE
1133 * can subscribe to a uniqified list of event
1134 * classes.
1135 */
1136 Ereportenames =
1137 tree_name2np_lut_add(Ereportenames,
1138 np->u.event.ename, np);
1139
1140 /*
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'.
1146 */
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);
1153 }
1154 break;
1155
1156 default:
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));
1160 }
1161 break;
1162
1163 case T_ENGINE:
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) {
1167 case N_SERD:
1168 ret = dodecl(T_SERD, file, line, np, nvpairs,
1169 &SERDs, SERDcount, 0);
1170 lut_walk(Upsets, update_serd_refstmt, np);
1171 break;
1172
1173 case N_STAT:
1174 ret = dodecl(T_STAT, file, line, np, nvpairs,
1175 &STATs, STATcount, 0);
1176 break;
1177
1178 default:
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));
1182 }
1183 break;
1184 case T_ASRU:
1185 ret = dodecl(T_ASRU, file, line, np, nvpairs,
1186 &ASRUs, ASRUcount, 1);
1187 break;
1188
1189 case T_FRU:
1190 ret = dodecl(T_FRU, file, line, np, nvpairs,
1191 &FRUs, FRUcount, 1);
1192 break;
1193
1194 case T_CONFIG:
1195 /*
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.
1201 */
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);
1206
1207 if (lut_lookup(Configs, np, (lut_cmp)tree_namecmp) == NULL)
1208 stats_counter_bump(Configcount);
1209
1210 Configs = lut_add(Configs, (void *)np, (void *)ret, NULL);
1211 break;
1212
1213 default:
1214 out(O_DIE, "tree_decl: internal error, type %s",
1215 ptree_nodetype2str(t));
1216 }
1217
1218 return (ret);
1219 }
1220
1221 /* keep backpointers in arrows to the prop they belong to (used for scoping) */
1222 static void
set_arrow_prop(struct node * prop,struct node * np)1223 set_arrow_prop(struct node *prop, struct node *np)
1224 {
1225 if (np == NULL)
1226 return;
1227
1228 if (np->t == T_ARROW) {
1229 np->u.arrow.prop = prop;
1230 set_arrow_prop(prop, np->u.arrow.lhs);
1231 /*
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.)
1236 */
1237 }
1238 }
1239
1240 struct node *
tree_stmt(enum nodetype t,struct node * np,const char * file,int line)1241 tree_stmt(enum nodetype t, struct node *np, const char *file, int line)
1242 {
1243 struct node *ret = newnode(t, file, line);
1244 struct node *pp;
1245 int inlist = 0;
1246
1247 ret->u.stmt.np = np;
1248
1249 switch (t) {
1250 case T_PROP:
1251 check_proplists(t, np);
1252 check_propnames(t, np, 0, 0);
1253 check_propscope(np);
1254 set_arrow_prop(ret, np);
1255
1256 for (pp = Props; pp; pp = pp->u.stmt.next) {
1257 if (tree_treecmp(pp, ret, T_NAME,
1258 (lut_cmp)tree_namecmp) == 0) {
1259 inlist = 1;
1260 break;
1261 }
1262 }
1263 if (inlist == 0)
1264 stats_counter_bump(Propcount);
1265
1266 /* "Props" is a linked list of all prop statements */
1267 if (Lastprops)
1268 Lastprops->u.stmt.next = ret;
1269 else
1270 Props = ret;
1271 Lastprops = ret;
1272 break;
1273
1274 case T_MASK:
1275 check_proplists(t, np);
1276 check_propnames(t, np, 0, 0);
1277 check_propscope(np);
1278 set_arrow_prop(ret, np);
1279
1280 for (pp = Masks; pp; pp = pp->u.stmt.next) {
1281 if (tree_treecmp(pp, ret, T_NAME,
1282 (lut_cmp)tree_namecmp) == 0) {
1283 inlist = 1;
1284 break;
1285 }
1286 }
1287 if (inlist == 0)
1288 stats_counter_bump(Maskcount);
1289
1290 /* "Masks" is a linked list of all mask statements */
1291 if (Lastmasks)
1292 Lastmasks->u.stmt.next = ret;
1293 else
1294 Masks = ret;
1295 Lastmasks = ret;
1296 stats_counter_bump(Maskcount);
1297 break;
1298
1299 default:
1300 outfl(O_DIE, np->file, np->line,
1301 "tree_stmt: internal error (t %d)", t);
1302 }
1303
1304 return (ret);
1305 }
1306
1307 void
tree_report()1308 tree_report()
1309 {
1310 /*
1311 * The only declarations with required properties
1312 * currently are faults and serds. Make sure the
1313 * the declarations have the required properties.
1314 */
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);
1321
1322 /*
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.
1327 */
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);
1336
1337 /* check for cycles */
1338 lut_walk(Errors, (lut_cb)check_cycle, (void *)0);
1339 }
1340
1341 /* compare two T_NAMES by only looking at components, not iterators */
1342 int
tree_namecmp(struct node * np1,struct node * np2)1343 tree_namecmp(struct node *np1, struct node *np2)
1344 {
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));
1349
1350 while (np1 && np2 && np1->u.name.s == np2->u.name.s) {
1351 np1 = np1->u.name.next;
1352 np2 = np2->u.name.next;
1353 }
1354 if (np1 == NULL)
1355 if (np2 == NULL)
1356 return (0);
1357 else
1358 return (-1);
1359 else if (np2 == NULL)
1360 return (1);
1361 else
1362 return (np2->u.name.s - np1->u.name.s);
1363 }
1364
1365 int
tree_eventcmp(struct node * np1,struct node * np2)1366 tree_eventcmp(struct node *np1, struct node *np2)
1367 {
1368 int ret;
1369
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));
1374
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)
1379 return (0);
1380 else if (np1->u.event.epname == NULL)
1381 return (-1);
1382 else if (np2->u.event.epname == NULL)
1383 return (1);
1384 else
1385 return tree_namecmp(np1->u.event.epname,
1386 np2->u.event.epname);
1387 } else
1388 return (ret);
1389 }
1390