xref: /illumos-gate/usr/src/tools/ndrgen/ndr_anal.c (revision ce8560ee)
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 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * Copyright 2020 Tintri by DDN, Inc. All rights reserved.
29  */
30 
31 #include <strings.h>
32 #include <string.h>
33 #include "ndrgen.h"
34 #include "y.tab.h"
35 
36 
37 #define	ALLOW_NOTHING	0
38 #define	ALLOW_VARSIZE	1
39 #define	ALLOW_INOUT	2
40 #define	ALLOW_CASE	4
41 #define	ALLOW_NO_UNIONS	8		/* for topmost structures */
42 #define	ALLOW_NO_SWITCH 16
43 
44 struct tup {
45 	struct tup		*up;
46 	ndr_typeinfo_t		*ti;
47 };
48 
49 static void type_ident_decl(ndr_typeinfo_t *, char *, size_t, char *);
50 static void type_ident_decl1(struct tup *, char *, size_t, char *);
51 static void analyze_typeinfo_list(void);
52 static void analyze_typeinfo_typedef(ndr_typeinfo_t *);
53 static void analyze_typeinfo_struct(ndr_typeinfo_t *);
54 static void analyze_typeinfo_union(ndr_typeinfo_t *);
55 static void analyze_typeinfo_aggregate_finish(ndr_typeinfo_t *);
56 static void analyze_member(ndr_node_t *, ndr_member_t *, unsigned long *, int);
57 static void seed_basic_types(void);
58 static void seed_construct_types(void);
59 static void append_typeinfo(ndr_typeinfo_t *);
60 static ndr_typeinfo_t *bind_typeinfo(ndr_typeinfo_t *);
61 static ndr_typeinfo_t *find_typeinfo_by_name(ndr_node_t *);
62 static void determine_advice(ndr_advice_t *, ndr_node_t *);
63 static ndr_node_t *find_advice(ndr_node_t *advice_list, int label);
64 
65 
66 void
analyze(void)67 analyze(void)
68 {
69 	seed_basic_types();
70 	seed_construct_types();
71 
72 	analyze_typeinfo_list();
73 }
74 
75 void
show_typeinfo_list(void)76 show_typeinfo_list(void)
77 {
78 	ndr_typeinfo_t		*ti;
79 	ndr_typeinfo_t		*tdti;
80 	int			i;
81 	ndr_member_t		*mem;
82 	char			*p;
83 	char			fname_type[NDLBUFSZ];
84 
85 	for (ti = typeinfo_list; ti; ti = ti->next) {
86 		switch (ti->type_op) {
87 		case STRUCT_KW:
88 			p = "struct";
89 			break;
90 
91 		case UNION_KW:
92 			p = "union";
93 			break;
94 
95 		case TYPEDEF_KW:
96 			p = "typedef";
97 			break;
98 
99 		case STRING_KW:
100 		case STAR:
101 		case LB:
102 		case BASIC_TYPE:
103 			type_extern_suffix(ti, fname_type, NDLBUFSZ);
104 			if (ti->is_extern) {
105 				(void) printf("extern ndr_%s()\n",
106 				    fname_type);
107 			} else if (!ti->is_referenced) {
108 				(void) printf("implied ndr_%s\n", fname_type);
109 			}
110 			continue;
111 
112 		default:
113 			(void) printf("show_typeinfo skipping %d\n",
114 			    ti->type_op);
115 			continue;
116 		}
117 
118 		(void) printf("\n\n");
119 		show_advice(&ti->advice, 0);
120 		(void) printf("%s %s {\n", p, ti->type_name->n_sym->name);
121 
122 		for (i = 0; i < ti->n_member; i++) {
123 			mem = &ti->member[i];
124 			show_advice(&mem->advice, 2);
125 			type_extern_suffix(mem->type, fname_type, NDLBUFSZ);
126 			(void) printf("    %-16s ndr_%-13s",
127 			    mem->name, fname_type);
128 
129 			tdti = mem->type;
130 			(void) printf(" fsiz=%d vsiz=%d algn=%d off=%d\n",
131 			    tdti->size_fixed_part,
132 			    tdti->size_variable_part,
133 			    tdti->alignment,
134 			    mem->pdu_offset);
135 		}
136 
137 		(void) printf("} fsiz=%d vsiz=%d algn=%d comp=%d ptrs=%d\n",
138 		    ti->size_fixed_part,
139 		    ti->size_variable_part,
140 		    ti->alignment,
141 		    ti->complete,
142 		    ti->has_pointers);
143 	}
144 }
145 
146 void
type_extern_suffix(ndr_typeinfo_t * tsti,char * funcbuf,size_t buflen)147 type_extern_suffix(ndr_typeinfo_t *tsti, char *funcbuf, size_t buflen)
148 {
149 	ndr_typeinfo_t		*ti;
150 	char			*p_fb = funcbuf;
151 
152 	*p_fb = 0;
153 
154 	for (ti = tsti; ti; ti = ti->type_down) {
155 		switch (ti->type_op) {
156 		case BASIC_TYPE:
157 		case STRUCT_KW:
158 		case TYPEDEF_KW:
159 		case UNION_KW:
160 			(void) snprintf(p_fb, buflen, "_%s",
161 			    ti->type_name->n_sym->name);
162 			break;
163 
164 		case STAR:
165 			(void) strlcpy(p_fb, "p", buflen);
166 			break;
167 
168 		case LB:
169 			if (ti->type_dim) {
170 				(void) snprintf(p_fb, buflen, "a%ld",
171 				    ti->type_dim->n_int);
172 			} else {
173 				(void) snprintf(p_fb, buflen, "ac");
174 			}
175 			break;
176 
177 		case STRING_KW:
178 			(void) strlcpy(p_fb, "s", buflen);
179 			break;
180 
181 		default:
182 			(void) snprintf(p_fb, buflen, "?<%d>", ti->type_op);
183 			break;
184 		}
185 		while (*p_fb)
186 			p_fb++;
187 	}
188 }
189 
190 static void
type_ident_decl1(struct tup * tup,char * funcbuf,size_t buflen,char * ident)191 type_ident_decl1(struct tup *tup, char *funcbuf, size_t buflen, char *ident)
192 {
193 	ndr_typeinfo_t		*ti;
194 	char			fb[NDLBUFSZ];
195 	char			*p;
196 
197 	if (!tup) {
198 		(void) strlcpy(funcbuf, ident, buflen);
199 		return;
200 	}
201 	ti = tup->ti;
202 
203 	switch (ti->type_op) {
204 	case BASIC_TYPE:
205 	case TYPEDEF_KW:
206 		type_ident_decl1(tup->up, fb, NDLBUFSZ, ident);
207 		(void) snprintf(funcbuf, buflen, "%s%s%s%s",
208 		    "", ti->type_name->n_sym->name, *fb ? " " : "", fb);
209 		break;
210 
211 	case STRUCT_KW:
212 		type_ident_decl1(tup->up, fb, NDLBUFSZ, ident);
213 		(void) snprintf(funcbuf, buflen, "%s%s%s%s",
214 		    "struct ", ti->type_name->n_sym->name, *fb ? " " : "", fb);
215 		break;
216 
217 	case UNION_KW:
218 		type_ident_decl1(tup->up, fb, NDLBUFSZ, ident);
219 		(void) snprintf(funcbuf, buflen, "%s%s%s%s",
220 		    "union ", ti->type_name->n_sym->name, *fb ? " " : "", fb);
221 		break;
222 
223 	case STAR:
224 		*funcbuf = '*';
225 		type_ident_decl1(tup->up, funcbuf+1, buflen - 1, ident);
226 		break;
227 
228 	case LB:
229 		p = fb;
230 		*p++ = '(';
231 		type_ident_decl1(tup->up, p, NDLBUFSZ - 1, ident);
232 		if (*p == '*') {
233 			p = fb;
234 			(void) strlcat(p, ")", NDLBUFSZ);
235 		}
236 		if (ti->type_dim) {
237 			(void) snprintf(funcbuf, buflen, "%s[%ld]",
238 			    p, ti->type_dim->n_int);
239 		} else {
240 			(void) snprintf(funcbuf, buflen,
241 			    "%s[NDR_ANYSIZE_DIM]", p);
242 		}
243 		break;
244 
245 	case STRING_KW:
246 		p = fb;
247 		*p++ = '(';
248 		type_ident_decl1(tup->up, p, NDLBUFSZ - 1, ident);
249 		if (*p == '*') {
250 			p = fb;
251 			(void) strlcat(p, ")", NDLBUFSZ);
252 		}
253 		(void) snprintf(funcbuf, buflen, "%s[NDR_STRING_DIM]", p);
254 		break;
255 
256 	default:
257 		compile_error("unknown type or keyword <%d>", ti->type_op);
258 		break;
259 	}
260 }
261 
262 static void
type_ident_decl(ndr_typeinfo_t * tsti,char * funcbuf,size_t buflen,char * ident)263 type_ident_decl(ndr_typeinfo_t *tsti, char *funcbuf, size_t buflen, char *ident)
264 {
265 	ndr_typeinfo_t		*ti;
266 	struct tup		tup_tab[40];
267 	struct tup		*tup;
268 	struct tup		*up = 0;
269 	int			n_tt = 0;
270 
271 	for (ti = tsti; ti; ti = ti->type_down, n_tt++) {
272 		tup = &tup_tab[n_tt];
273 		tup->up = up;
274 		tup->ti = ti;
275 		up = tup;
276 	}
277 
278 	type_ident_decl1(up, funcbuf, buflen, ident);
279 }
280 
281 void
type_null_decl(ndr_typeinfo_t * tsti,char * funcbuf,size_t buflen)282 type_null_decl(ndr_typeinfo_t *tsti, char *funcbuf, size_t buflen)
283 {
284 	funcbuf[0] = '(';
285 	type_ident_decl(tsti, funcbuf+1, buflen, "");
286 	(void) strlcat(funcbuf, ")", buflen);
287 }
288 
289 void
type_name_decl(ndr_typeinfo_t * tsti,char * funcbuf,size_t buflen,char * name)290 type_name_decl(ndr_typeinfo_t *tsti, char *funcbuf, size_t buflen, char *name)
291 {
292 	type_ident_decl(tsti, funcbuf, buflen, name);
293 }
294 
295 void
show_advice(ndr_advice_t * adv,int indent)296 show_advice(ndr_advice_t *adv, int indent)
297 {
298 	int		i;
299 	int		n = 0;
300 
301 	for (i = 0; i < N_ADVICE; i++) {
302 		if (!adv->a_nodes[i])
303 			continue;
304 
305 		if (n++ == 0)
306 			(void) printf("%-*s[", indent, "");
307 		else
308 			(void) printf(" ");
309 
310 		print_node(adv->a_nodes[i]);
311 	}
312 
313 	if (n)
314 		(void) printf("]\n");
315 }
316 
317 static void
analyze_typeinfo_list(void)318 analyze_typeinfo_list(void)
319 {
320 	ndr_typeinfo_t		*ti;
321 
322 	for (ti = typeinfo_list; ti; ti = ti->next) {
323 		switch (ti->type_op) {
324 		case STRUCT_KW:
325 			analyze_typeinfo_struct(ti);
326 			break;
327 
328 		case UNION_KW:
329 			analyze_typeinfo_union(ti);
330 			break;
331 
332 		case TYPEDEF_KW:
333 			analyze_typeinfo_typedef(ti);
334 			break;
335 		}
336 	}
337 }
338 
339 static void
analyze_typeinfo_typedef(ndr_typeinfo_t * ti)340 analyze_typeinfo_typedef(ndr_typeinfo_t *ti)
341 {
342 	ndr_node_t		*mem_np;
343 	ndr_member_t		*mem;
344 	int			i;
345 	int			allow;
346 	unsigned long		offset;
347 
348 	assert(ti->type_op == TYPEDEF_KW);
349 
350 	/*
351 	 * Snarf the advice.
352 	 */
353 	determine_advice(&ti->advice, ti->definition->n_c_advice);
354 
355 	/*
356 	 * Convert the members to table.
357 	 * Determine layout metrics along the way.
358 	 */
359 	mem_np = ti->definition->n_c_members;
360 	i = 0;
361 	offset = 0;
362 	assert(i < ti->n_member);
363 	mem = &ti->member[i];
364 
365 	allow = ALLOW_NO_SWITCH;
366 
367 	analyze_member(mem_np, mem,
368 	    &offset,		/* progress offset */
369 	    allow);		/* see above */
370 
371 	assert(1 == ti->n_member);
372 
373 	analyze_typeinfo_aggregate_finish(ti);
374 
375 	/* Align offset to determine overall size */
376 	while (offset & ti->alignment)
377 		offset++;
378 
379 	ti->size_fixed_part = offset;
380 }
381 
382 static void
analyze_typeinfo_struct(ndr_typeinfo_t * ti)383 analyze_typeinfo_struct(ndr_typeinfo_t *ti)
384 {
385 	ndr_node_t		*mem_np;
386 	ndr_member_t		*mem;
387 	int			i;
388 	int			allow;
389 	unsigned long		offset;
390 
391 	assert(ti->type_op == STRUCT_KW);
392 
393 	/*
394 	 * Snarf the advice. Only recognize [operation()] for
395 	 * struct definitions.
396 	 */
397 	determine_advice(&ti->advice, ti->definition->n_c_advice);
398 
399 	/*
400 	 * Convert the members from list to table.
401 	 * Determine layout metrics along the way.
402 	 */
403 	mem_np = ti->definition->n_c_members;
404 	i = 0;
405 	offset = 0;
406 	for (; mem_np; i++, mem_np = mem_np->n_next) {
407 		assert(i < ti->n_member);
408 		mem = &ti->member[i];
409 
410 		if (!ti->advice.a_operation /* no var-size in op param */ &&
411 		    i == ti->n_member-1)  /* only last mem may be var-size */
412 			allow = ALLOW_VARSIZE;
413 		else
414 			allow = 0;
415 
416 		analyze_member(mem_np, mem, &offset, allow);
417 	}
418 	assert(i == ti->n_member);
419 
420 	analyze_typeinfo_aggregate_finish(ti);	/* align,complete,ptrs,etc */
421 
422 	/* Align offset to determine overall size */
423 	while (offset & ti->alignment)
424 		offset++;
425 
426 	ti->size_fixed_part = offset;
427 
428 	/* If last member is var-sized, so is this struct */
429 	mem = &ti->member[ti->n_member-1];
430 	ti->size_variable_part = mem->type->size_variable_part;
431 
432 	if (ti->size_variable_part)
433 		ti->is_conformant = 1;
434 }
435 
436 static void
analyze_typeinfo_union(ndr_typeinfo_t * ti)437 analyze_typeinfo_union(ndr_typeinfo_t *ti)
438 {
439 	ndr_node_t		*mem_np;
440 	ndr_member_t		*mem;
441 	int			i;
442 	unsigned long		offset;
443 	unsigned long		size;
444 
445 	assert(ti->type_op == UNION_KW);
446 
447 	/*
448 	 * Snarf the advice. None supported for union definitions.
449 	 * Only [switch_is()] supported for union instances.
450 	 */
451 	determine_advice(&ti->advice, ti->definition->n_c_advice);
452 
453 	/*
454 	 * Convert the members from list to table.
455 	 * Determine layout metrics along the way.
456 	 */
457 	mem_np = ti->definition->n_c_members;
458 	i = 0;
459 	size = 0;
460 	for (; mem_np; i++, mem_np = mem_np->n_next) {
461 		assert(i < ti->n_member);
462 		mem = &ti->member[i];
463 
464 		offset = 0;			/* all members offset=0 */
465 		analyze_member(mem_np, mem,
466 		    &offset,
467 		    ALLOW_CASE+ALLOW_NO_UNIONS); /* var-size disallowed */
468 
469 		if (size < mem->type->size_fixed_part)
470 			size = mem->type->size_fixed_part;
471 	}
472 	assert(i == ti->n_member);
473 
474 	analyze_typeinfo_aggregate_finish(ti);	/* align,complete,ptrs,etc */
475 
476 	/* align size to determine overall size */
477 	while (size & ti->alignment)
478 		size++;
479 
480 	ti->size_fixed_part = size;
481 }
482 
483 static void
analyze_typeinfo_aggregate_finish(ndr_typeinfo_t * ti)484 analyze_typeinfo_aggregate_finish(ndr_typeinfo_t *ti)
485 {
486 	int			i;
487 	ndr_member_t		*mem;
488 	int			complete = 1;
489 	int			has_pointers = 0;
490 
491 	for (i = 0; i < ti->n_member; i++) {
492 		mem = &ti->member[i];
493 
494 		complete &= mem->type->complete;
495 		has_pointers |= mem->type->has_pointers;
496 		ti->alignment |= mem->type->alignment;
497 	}
498 
499 	ti->complete = complete;
500 	ti->has_pointers = has_pointers;
501 }
502 
503 static void
analyze_member(ndr_node_t * mem_np,ndr_member_t * mem,unsigned long * offsetp,int allow)504 analyze_member(ndr_node_t *mem_np, ndr_member_t *mem,
505     unsigned long *offsetp, int allow)
506 {
507 	int			i, n_decl_ops;
508 	ndr_node_t		*decl_ops[NDLBUFSZ];
509 	ndr_typeinfo_t		*type_down;
510 	ndr_typeinfo_t		proto_ti;
511 	ndr_node_t		*np;
512 
513 	/*
514 	 * Set line_number for error reporting (so we know where to look)
515 	 */
516 	line_number = mem_np->line_number;
517 
518 	/*
519 	 * Simple parts of member
520 	 */
521 	mem->definition = mem_np;
522 	determine_advice(&mem->advice, mem_np->n_m_advice);
523 
524 	/*
525 	 * The node list for the declarator is in outside-to-inside
526 	 * order. It is also decorated with the LP nodes for
527 	 * precedence, which are in our way at this point.
528 	 *
529 	 * These two loops reverse the list, which is easier
530 	 * to analyze. For example, the declaration:
531 	 *
532 	 *	ulong *		(id[100]);
533 	 *
534 	 * will have the node list (=> indicates n_d_descend):
535 	 *
536 	 *	ulong  =>  STAR  =>  LP  =>  LB[100]  =>  id
537 	 *
538 	 * and the conversion will result in type info (=> indicates
539 	 * type_down):
540 	 *
541 	 *	id  =>  LB[100]  =>  STAR  =>  ulong
542 	 *
543 	 * which is closer to how you would pronounce the declaration:
544 	 *
545 	 *	id is an array size 100 of pointers to ulong.
546 	 */
547 
548 	/* first pass -- turn the list into a table */
549 	n_decl_ops = 0;
550 	for (np = mem_np->n_m_decl; np; np = np->n_d_descend) {
551 		if (np->label == IDENTIFIER) {
552 			break;		/* done */
553 		}
554 
555 		if (np->label == LP)
556 			continue;	/* ignore precedence nodes */
557 
558 		decl_ops[n_decl_ops++] = np;
559 	}
560 	if (!np) {
561 		compile_error("declaration error");
562 		print_node(mem_np->n_m_decl);
563 		(void) printf("\n");
564 	} else {
565 		mem->name = np->n_sym->name;
566 	}
567 
568 	/* second pass -- turn the table into push-back list */
569 	type_down = find_typeinfo_by_name(mem_np->n_m_type);
570 
571 	if (type_down->type_op == TYPEDEF_KW)
572 		type_down = type_down->member[0].type;
573 
574 	if (mem->advice.a_string) {
575 		bzero(&proto_ti, sizeof (proto_ti));
576 		proto_ti.type_op = STRING_KW;
577 		proto_ti.type_down = type_down;
578 		type_down = bind_typeinfo(&proto_ti);
579 	}
580 
581 	for (i = n_decl_ops; i-- > 0; ) {
582 		np = decl_ops[i];
583 
584 		bzero(&proto_ti, sizeof (proto_ti));
585 
586 		proto_ti.type_op = np->label;
587 		proto_ti.type_down = type_down;
588 
589 		switch (np->label) {
590 		case LB:
591 			proto_ti.type_dim = np->n_d_dim;
592 			break;
593 		}
594 
595 		/*
596 		 * bind_typeinfo() reuses (interns) typeinfo's to
597 		 * make later code generation easier. It will report
598 		 * some errors.
599 		 */
600 		type_down = bind_typeinfo(&proto_ti);
601 	}
602 
603 	/* bind the member to its type info */
604 	mem->type = type_down;
605 	type_down->is_referenced = 1;	/* we handle first-level indirection */
606 
607 	/*
608 	 * Now, apply the type info to the member layout metrics.
609 	 */
610 
611 	/* alignment */
612 	while (*offsetp & type_down->alignment)
613 		++*offsetp;
614 
615 	mem->pdu_offset = *offsetp;
616 
617 	*offsetp += type_down->size_fixed_part;
618 
619 	if (mem->advice.a_length_is)
620 		compile_error("[length_is()] is not supported");
621 
622 	if (mem->advice.a_transmit_as)
623 		compile_error("[transmit_as()] is not supported");
624 
625 	if (mem->advice.a_arg_is)
626 		compile_error("[arg_is()] is not supported");
627 
628 	/*
629 	 * Disallow
630 	 *	[case(x)] TYPE	xxx;
631 	 *	[default] TYPE	xxx;
632 	 *
633 	 * These only make sense within unions.
634 	 */
635 	if (allow & ALLOW_CASE) {
636 		int		n = 0;
637 
638 		if (mem->advice.a_case)
639 			n++;
640 		if (mem->advice.a_default)
641 			n++;
642 
643 		if (n == 0)
644 			compile_error("no [case/default] advice");
645 		else if (n > 1)
646 			compile_error("too many [case/default] advice");
647 	} else {
648 		if (mem->advice.a_case && mem->advice.a_default)
649 			compile_error("[case/default] advice not allowed");
650 	}
651 
652 	/*
653 	 * Disallow
654 	 *	[operation(x)]	TYPE	foo;
655 	 *	[interface(x)]	TYPE	foo;
656 	 *	[uuid(x)]	TYPE	foo;
657 	 *
658 	 * The [operation()] advice may only appear on a struct to
659 	 * indicate that the structure is a top-most (parameter)
660 	 * structure, and the opcode associated with the parameters.
661 	 */
662 	if (mem->advice.a_operation)
663 		compile_error("[operation()] advice not allowed");
664 
665 	if (mem->advice.a_interface)
666 		compile_error("[interface()] advice not allowed");
667 
668 	if (mem->advice.a_uuid)
669 		compile_error("[uuid()] advice not allowed");
670 
671 	/*
672 	 * Allow
673 	 *	[switch_is(x)] union foo	xxx;
674 	 *
675 	 * Disallow [switch_is] on anything which is not a union.
676 	 */
677 	if (mem->advice.a_switch_is && type_down->type_op != UNION_KW) {
678 		compile_error("[switch_is()] advice not allowed");
679 	}
680 
681 	/*
682 	 * Allow
683 	 *	[size_is(x)] TYPE *	ptr;
684 	 *	[size_is(x)] TYPE	arr[];
685 	 *
686 	 * Disallow [size_is()] on anything other than pointer and
687 	 * variable length array.
688 	 */
689 	if (mem->advice.a_size_is &&
690 	    type_down->type_op != STAR &&
691 	    !(type_down->type_op == LB &&
692 	    type_down->type_dim == 0)) {
693 		compile_error("[size_is()] advice not allowed");
694 	}
695 
696 	/*
697 	 * Allow
698 	 *	[string] char *		ptr_string;
699 	 *
700 	 * Disallow [string] on anything else. The determination
701 	 * of size (for the outer header) on anything else is
702 	 * impossible.
703 	 */
704 	if (mem->advice.a_string && type_down->type_op != STAR) {
705 		compile_error("[string] advice not allowed");
706 	}
707 
708 	if (type_down->type_op == LB &&
709 	    type_down->type_dim == 0) { /* var-length array of some sort */
710 
711 		int		n = 0;
712 
713 		/*
714 		 * Requires [size_is()] directive
715 		 *	[size_is(x)] TYPE	array[]
716 		 */
717 
718 		if (mem->advice.a_size_is)
719 			n++;
720 
721 		if (!n)
722 			compile_error("var-size missing sizing directive");
723 		else if (n > 1)
724 			compile_error("var-size too many sizing directives");
725 	}
726 
727 	/*
728 	 * Nested unions and struct members, other than the last one,
729 	 * cannot contain variable sized members.
730 	 */
731 	if (type_down->size_variable_part && !(allow & ALLOW_VARSIZE)) {
732 		compile_error("var-size member not allowed");
733 	}
734 
735 	/*
736 	 * Disallow unions in operations (i.e. [operation()] struct ...),
737 	 * The switch_is() value is not reliably available. DCE/RPC
738 	 * automatically synthesizes an encapsulated union for
739 	 * these situations, which we have to do by hand:
740 	 *
741 	 *	struct { long switch_value; union foo x; } synth;
742 	 *
743 	 * We also can not allow unions within unions because
744 	 * there is no way to pass the separate [switch_is(x)] selector.
745 	 */
746 	if (type_down->type_op == UNION_KW) {
747 		if (allow & ALLOW_NO_UNIONS) {
748 			compile_error("unencapsulated union not allowed");
749 		} else if (!mem->advice.a_switch_is &&
750 		    !(allow & ALLOW_NO_SWITCH)) {
751 			compile_error("union instance without selector");
752 		}
753 	}
754 }
755 
756 static void
seed_basic_types(void)757 seed_basic_types(void)
758 {
759 	ndr_symbol_t		*sym;
760 	ndr_typeinfo_t		*ti;
761 	ndr_typeinfo_t		proto_ti;
762 
763 	for (sym = symbol_list; sym; sym = sym->next) {
764 		if (!sym->kw)
765 			continue;
766 
767 		if (sym->kw->token != BASIC_TYPE)
768 			continue;
769 
770 		ti = ndr_alloc(1, sizeof (ndr_typeinfo_t));
771 
772 		ti->type_op = BASIC_TYPE;
773 		ti->definition = &sym->s_node;
774 		ti->type_name = &sym->s_node;
775 		ti->size_fixed_part = sym->kw->value;
776 		ti->alignment = ti->size_fixed_part - 1;
777 		ti->complete = 1;
778 		ti->is_extern = 1;
779 
780 		append_typeinfo(ti);
781 
782 		bzero(&proto_ti, sizeof (proto_ti));
783 		proto_ti.type_op = STRING_KW;
784 		proto_ti.type_down = ti;
785 
786 		ti = bind_typeinfo(&proto_ti);
787 		ti->is_extern = 1;
788 	}
789 }
790 
791 static void
seed_construct_types(void)792 seed_construct_types(void)
793 {
794 	ndr_node_t		*construct;
795 	ndr_node_t		*np;
796 	unsigned		n_member;
797 	ndr_typeinfo_t		*ti;
798 
799 	construct = construct_list;
800 	for (; construct; construct = construct->n_next) {
801 		ti = ndr_alloc(1, sizeof (ndr_typeinfo_t));
802 
803 		ti->type_op = construct->label;
804 		ti->definition = construct;
805 
806 		switch (ti->type_op) {
807 		case TYPEDEF_KW:
808 		case STRUCT_KW:
809 		case UNION_KW:
810 			ti->type_name = construct->n_c_typename;
811 
812 			np = construct->n_c_members;
813 			n_member = 0;
814 			for (; np; np = np->n_next)
815 				n_member++;
816 
817 			ti->n_member = n_member;
818 			if (n_member > 0)
819 				ti->member = ndr_alloc(n_member,
820 				    sizeof (ndr_member_t));
821 			break;
822 
823 		default:
824 			fatal_error("seed_construct unknown %d\n", ti->type_op);
825 			break;
826 		}
827 
828 		determine_advice(&ti->advice, construct->n_c_advice);
829 
830 		ti->is_referenced = 1;	/* always generate */
831 
832 		append_typeinfo(ti);
833 	}
834 }
835 
836 static void
append_typeinfo(ndr_typeinfo_t * ti)837 append_typeinfo(ndr_typeinfo_t *ti)
838 {
839 	ndr_typeinfo_t		**pp;
840 
841 	for (pp = &typeinfo_list; *pp; pp = &(*pp)->next)
842 		;
843 
844 	*pp = ti;
845 	ti->next = 0;
846 }
847 
848 static ndr_typeinfo_t *
bind_typeinfo(ndr_typeinfo_t * proto_ti)849 bind_typeinfo(ndr_typeinfo_t *proto_ti)
850 {
851 	ndr_typeinfo_t		*ti;
852 	ndr_typeinfo_t		*tdti = proto_ti->type_down;
853 
854 	for (ti = typeinfo_list; ti; ti = ti->next) {
855 		if (ti->type_op != proto_ti->type_op)
856 			continue;
857 
858 		switch (ti->type_op) {
859 		case STAR:
860 			if (ti->type_down != proto_ti->type_down)
861 				continue;
862 			break;
863 
864 		case STRING_KW:
865 			if (ti->type_down != proto_ti->type_down)
866 				continue;
867 			break;
868 
869 		case LB:
870 			if (ti->type_down != proto_ti->type_down)
871 				continue;
872 			if (ti->type_dim != proto_ti->type_dim)
873 				continue;
874 			break;
875 
876 		case BASIC_TYPE:
877 		case STRUCT_KW:
878 		case TYPEDEF_KW:
879 		case UNION_KW:
880 			if (ti->type_name != proto_ti->type_name)
881 				continue;
882 			break;
883 
884 		default:
885 			fatal_error("bind_typeinfo unknown %d\n", ti->type_op);
886 			break;
887 		}
888 
889 		return (ti);
890 	}
891 
892 	ti = ndr_alloc(1, sizeof (ndr_typeinfo_t));
893 
894 	*ti = *proto_ti;
895 	append_typeinfo(ti);
896 
897 	switch (ti->type_op) {
898 	case STAR:
899 		ti->size_fixed_part = 4;
900 		ti->alignment = 3;
901 		ti->complete = 1;
902 		ti->has_pointers = 1;
903 		break;
904 
905 	case STRING_KW:
906 	case LB:
907 		if (tdti->complete) {
908 			ti->alignment = tdti->alignment;
909 			if (tdti->size_variable_part) {
910 				compile_error("array of var-size type");
911 			} else if (ti->type_dim) {
912 				ti->size_fixed_part = tdti->size_fixed_part *
913 				    ti->type_dim->n_int;
914 			} else {
915 				ti->size_variable_part = tdti->size_fixed_part;
916 				ti->is_conformant = 1;
917 			}
918 		} else {
919 			compile_error("array of incomplete type");
920 		}
921 
922 		ti->has_pointers = tdti->has_pointers;
923 		ti->complete = 1;
924 		break;
925 
926 	default:
927 		compile_error("bind_type internal error op=%d", ti->type_op);
928 		break;
929 	}
930 
931 	/*
932 	 * Disallow
933 	 *	union foo	*ptrfoo;
934 	 * There is no way to pass the selector (switch_is)in
935 	 */
936 	if (ti->type_op == STAR && ti->type_down->type_op == UNION_KW) {
937 		compile_error("pointers to unions not allowed");
938 	}
939 
940 	/*
941 	 * Disallow
942 	 *	union foo	fooarr[n];
943 	 * Each element needs a distinct selector
944 	 */
945 	if (ti->type_op == LB && ti->type_down->type_op == UNION_KW) {
946 		compile_error("arrays of unions not allowed");
947 	}
948 
949 	return (ti);
950 }
951 
952 static ndr_typeinfo_t *
find_typeinfo_by_name(ndr_node_t * typename)953 find_typeinfo_by_name(ndr_node_t *typename)
954 {
955 	ndr_typeinfo_t		*ti;
956 
957 	for (ti = typeinfo_list; ti; ti = ti->next) {
958 		if (ti->type_name == typename)
959 			return (ti);
960 	}
961 
962 	compile_error("unknown type %s", typename->n_sym->name);
963 
964 	/* fake BASIC_TYPE */
965 	ti = ndr_alloc(1, sizeof (ndr_typeinfo_t));
966 	ti->type_op = BASIC_TYPE;
967 	ti->definition = typename;
968 	ti->type_name = typename;
969 	ti->size_fixed_part = 0;
970 	ti->alignment = 0;
971 
972 	append_typeinfo(ti);
973 	return (ti);
974 }
975 
976 static void
determine_advice(ndr_advice_t * advice,ndr_node_t * advice_list)977 determine_advice(ndr_advice_t *advice, ndr_node_t *advice_list)
978 {
979 	/* alias for basic types */
980 	advice->a_transmit_as = find_advice(advice_list, TRANSMIT_AS_KW);
981 
982 	/* arg used for size, union, or generic purpose */
983 	advice->a_arg_is = find_advice(advice_list, ARG_IS_KW);
984 
985 	/* operation parameter in/out stuff */
986 	advice->a_operation = find_advice(advice_list, OPERATION_KW);
987 	advice->a_in = find_advice(advice_list, IN_KW);
988 	advice->a_out = find_advice(advice_list, OUT_KW);
989 
990 	/* size stuff */
991 	advice->a_string = find_advice(advice_list, STRING_KW);
992 	advice->a_size_is = find_advice(advice_list, SIZE_IS_KW);
993 	advice->a_length_is = find_advice(advice_list, LENGTH_IS_KW);
994 
995 	/* union stuff */
996 	advice->a_case = find_advice(advice_list, CASE_KW);
997 	advice->a_default = find_advice(advice_list, DEFAULT_KW);
998 	advice->a_switch_is = find_advice(advice_list, SWITCH_IS_KW);
999 
1000 	/* interface stuff */
1001 	advice->a_interface = find_advice(advice_list, INTERFACE_KW);
1002 	advice->a_uuid = find_advice(advice_list, UUID_KW);
1003 	advice->a_no_reorder = find_advice(advice_list, _NO_REORDER_KW);
1004 	advice->a_extern = find_advice(advice_list, EXTERN_KW);
1005 
1006 	advice->a_reference = find_advice(advice_list, REFERENCE_KW);
1007 	advice->a_align = find_advice(advice_list, ALIGN_KW);
1008 	advice->a_fake = find_advice(advice_list, FAKE_KW);
1009 }
1010 
1011 static ndr_node_t *
find_advice(ndr_node_t * advice_list,int label)1012 find_advice(ndr_node_t *advice_list, int label)
1013 {
1014 	ndr_node_t		*np;
1015 
1016 	for (np = advice_list; np; np = np->n_next)
1017 		if (np->label == label)
1018 			break;
1019 
1020 	return (np);
1021 }
1022 
1023 void
member_fixup(ndr_node_t * member_np)1024 member_fixup(ndr_node_t *member_np)
1025 {
1026 	ndr_node_t		*np;
1027 
1028 	for (np = member_np->n_m_decl; np; np = np->n_d_descend)
1029 		if (np->label == IDENTIFIER)
1030 			break;
1031 
1032 	member_np->n_m_name = np;
1033 }
1034 
1035 void
construct_fixup(ndr_node_t * construct_np)1036 construct_fixup(ndr_node_t *construct_np)
1037 {
1038 	construct_np->n_c_typename->n_sym->typedefn = construct_np;
1039 }
1040