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