xref: /illumos-gate/usr/src/tools/ndrgen/ndr_gen.c (revision 3c2328bf3bf6527c6b28445336d32183a277b1e1)
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 2009 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 <string.h>
32 #include "ndrgen.h"
33 #include "y.tab.h"
34 
35 
36 static void generate_struct(ndr_typeinfo_t *);
37 static void generate_params(ndr_typeinfo_t *);
38 static void generate_union(ndr_typeinfo_t *);
39 static void generate_arg(ndr_node_t *);
40 static void generate_member_macro(char *, char *, ndr_member_t *,
41     ndr_typeinfo_t *);
42 static void generate_member_macro_with_arg(char *, char *, ndr_member_t *,
43     ndr_typeinfo_t *, ndr_node_t *);
44 static void generate_prototypes(ndr_typeinfo_t *, char *);
45 static void generate_member_prototypes(ndr_typeinfo_t *, ndr_member_t *,
46     char *);
47 static void generate_member(ndr_typeinfo_t *, ndr_member_t *);
48 static void generate_aggregate_common_begin(ndr_typeinfo_t *);
49 static void generate_aggregate_common_finish(ndr_typeinfo_t *);
50 static void generate_typeinfo_packing(ndr_typeinfo_t *);
51 static void generate_typeinfo_typeinfo(ndr_typeinfo_t *, int, char *);
52 
53 
54 void
55 generate(void)
56 {
57 	ndr_typeinfo_t		*ti;
58 	char			fname_type[NDLBUFSZ];
59 
60 	(void) printf("\n");
61 
62 	for (ti = typeinfo_list; ti; ti = ti->next) {
63 		if (ti->is_extern || ti->advice.a_extern) {
64 			type_extern_suffix(ti, fname_type, NDLBUFSZ);
65 			(void) printf(
66 			    "extern struct ndr_typeinfo ndt_%s;\n",
67 			    fname_type);
68 			continue;
69 		}
70 
71 		switch (ti->type_op) {
72 		case STRUCT_KW:
73 			if (ti->advice.a_operation)
74 				generate_params(ti);
75 			else
76 				generate_struct(ti);
77 			break;
78 
79 		case UNION_KW:
80 			generate_union(ti);
81 			break;
82 
83 		case TYPEDEF_KW:
84 			/* silently skip */
85 			continue;
86 
87 		case STRING_KW:
88 		case STAR:
89 		case LB:
90 		case BASIC_TYPE:
91 			if (!ti->is_referenced) {
92 				type_extern_suffix(ti, fname_type, NDLBUFSZ);
93 				(void) printf("extern ndt_%s\n", fname_type);
94 				type_null_decl(ti, fname_type, NDLBUFSZ);
95 				(void) printf("/* %s */\n", fname_type);
96 			}
97 			break;
98 
99 		default:
100 			continue;
101 		}
102 	}
103 }
104 
105 static void
106 generate_struct(ndr_typeinfo_t *ti)
107 {
108 	int		i;
109 	ndr_member_t	*mem;
110 
111 	if (ti->advice.a_no_reorder) {
112 		/* just use generate_params(), which can safely do this */
113 		generate_params(ti);
114 		return;
115 	}
116 
117 	generate_aggregate_common_begin(ti);
118 
119 	(void) printf("	/* do all basic elements first */\n");
120 	for (i = 0; i < ti->n_member; i++) {
121 		mem = &ti->member[i];
122 		if (mem->type->type_op != BASIC_TYPE)
123 			continue;
124 
125 		generate_member(ti, mem);
126 	}
127 
128 	(void) printf("\n");
129 	(void) printf("	/* do all constructed elements w/o pointers */\n");
130 	for (i = 0; i < ti->n_member; i++) {
131 		mem = &ti->member[i];
132 		if (mem->type->type_op == BASIC_TYPE)
133 			continue;
134 
135 		if (mem->type->has_pointers)
136 			continue;
137 
138 		generate_member(ti, mem);
139 	}
140 
141 	(void) printf("\n");
142 	(void) printf("	/* do members with pointers in order */\n");
143 	for (i = 0; i < ti->n_member; i++) {
144 		mem = &ti->member[i];
145 		if (mem->type->type_op == BASIC_TYPE)
146 			continue;
147 
148 		if (!mem->type->has_pointers)
149 			continue;
150 
151 		generate_member(ti, mem);
152 	}
153 
154 	generate_aggregate_common_finish(ti);
155 }
156 
157 static void
158 generate_params(ndr_typeinfo_t *ti)
159 {
160 	int		i;
161 	ndr_member_t	*mem;
162 
163 	generate_aggregate_common_begin(ti);
164 
165 	(void) printf("	/* do all members in order */\n");
166 	for (i = 0; i < ti->n_member; i++) {
167 		mem = &ti->member[i];
168 
169 		generate_member(ti, mem);
170 	}
171 
172 	generate_aggregate_common_finish(ti);
173 }
174 
175 static void
176 generate_union(ndr_typeinfo_t *ti)
177 {
178 	int		i;
179 	ndr_member_t	*mem;
180 	int		have_default = 0;
181 	ndr_node_t	*np;
182 
183 	generate_aggregate_common_begin(ti);
184 
185 	(void) printf("    switch (encl_ref->switch_is) {\n");
186 
187 	for (i = 0; i < ti->n_member; i++) {
188 		mem = &ti->member[i];
189 
190 		if ((np = mem->advice.a_case) != 0) {
191 			(void) printf("    case ");
192 			print_node(np->n_a_arg);
193 			(void) printf(":\n");
194 		} else if ((np = mem->advice.a_default) != 0) {
195 			(void) printf("    default:\n");
196 			if (have_default++) {
197 				compile_error("multiple defaults");
198 			}
199 		} else {
200 			compile_error("syntax error");
201 		}
202 
203 		generate_member(ti, mem);
204 		(void) printf("	break;\n\n");
205 	}
206 
207 	if (!have_default) {
208 		(void) printf("    default:\n");
209 		(void) printf("	NDR_SET_ERROR(encl_ref, "
210 		    "NDR_ERR_SWITCH_VALUE_INVALID);\n");
211 		(void) printf("	return 0;\n");
212 		(void) printf("	break;\n");
213 	}
214 
215 	(void) printf("    }\n");
216 	(void) printf("\n");
217 
218 	generate_aggregate_common_finish(ti);
219 }
220 
221 static void
222 generate_arg(ndr_node_t *np)
223 {
224 	ndr_node_t	*arg = np;
225 
226 	if (np == NULL) {
227 		compile_error("invalid node pointer <null>");
228 		return;
229 	}
230 
231 	if (np->label != IDENTIFIER && np->label != INTEGER)
232 		arg = np->n_a_arg;
233 
234 	switch (np->label) {
235 	case SIZE_IS_KW:
236 	case LENGTH_IS_KW:
237 	case SWITCH_IS_KW:
238 		(void) printf("val->");
239 		print_field_attr(np);
240 		break;
241 	default:
242 		if (arg->label == IDENTIFIER)
243 			(void) printf("val->%s", arg->n_sym->name);
244 		else
245 			print_node(arg);
246 		break;
247 	}
248 }
249 
250 static void
251 generate_member_macro(char *memkind, char *macro, ndr_member_t *mem,
252     ndr_typeinfo_t *ti)
253 {
254 	char	fname_type[NDLBUFSZ];
255 
256 	if (!macro)
257 		macro = "";
258 	if (!ti)
259 		ti = mem->type;
260 
261 	type_extern_suffix(ti, fname_type, NDLBUFSZ);
262 
263 	if (memkind) {
264 		(void) printf("	NDR_%sMEMBER%s (%s, %s);\n",
265 		    memkind, macro, fname_type, mem->name);
266 	} else {
267 		(void) printf("	NDR_MEMBER%s (%s, %s, %uUL);\n",
268 		    macro, fname_type, mem->name, mem->pdu_offset);
269 	}
270 }
271 
272 static void
273 generate_member_macro_with_arg(char *memkind, char *macro,
274     ndr_member_t *mem, ndr_typeinfo_t *ti, ndr_node_t *np)
275 {
276 	char	fname_type[NDLBUFSZ];
277 
278 	if (!macro)
279 		macro = "_WITH_ARG";
280 	if (!ti)
281 		ti = mem->type;
282 
283 	type_extern_suffix(ti, fname_type, NDLBUFSZ);
284 
285 	if (memkind) {
286 		(void) printf("	NDR_%sMEMBER%s (%s, %s,\n",
287 		    memkind, macro, fname_type, mem->name);
288 	} else {
289 		(void) printf("	NDR_MEMBER%s (%s, %s, %uUL,\n",
290 		    macro, fname_type, mem->name, mem->pdu_offset);
291 	}
292 
293 	(void) printf("\t\t");
294 	generate_arg(np);
295 	(void) printf(");\n");
296 }
297 
298 static void
299 generate_prototypes(ndr_typeinfo_t *ti, char *fname_type)
300 {
301 	ndr_member_t *mem;
302 	int i;
303 
304 	if (ti->type_op == STRUCT_KW && ti->advice.a_operation) {
305 		for (i = 0; i < ti->n_member; i++) {
306 			mem = &ti->member[i];
307 
308 			generate_member_prototypes(ti, mem, fname_type);
309 		}
310 	}
311 }
312 
313 static void
314 generate_member_prototypes(ndr_typeinfo_t *ti,
315     ndr_member_t *mem, char *fname_type)
316 {
317 	char val_buf[NDLBUFSZ];
318 	ndr_typeinfo_t ptr;
319 
320 	if (mem->type->type_op == UNION_KW) {
321 		if (!mem->advice.a_in && mem->advice.a_out) {
322 			ptr.type_op = STAR;
323 			ptr.type_down = ti;
324 			type_name_decl(&ptr, val_buf, NDLBUFSZ, "val");
325 
326 			(void) printf("\nextern void fixup%s(%s);\n",
327 			    fname_type, val_buf);
328 		}
329 	}
330 }
331 
332 static void
333 generate_member(ndr_typeinfo_t *ti, ndr_member_t *mem)
334 {
335 	static char *fixup[] = {
336 		"/*",
337 		" * Cannot use the canned offsets to unmarshall multiple",
338 		" * entry discriminated unions.  The service must provide",
339 		" * this function to patch the offsets at runtime.",
340 		" */"
341 	};
342 
343 	char		fname_type[NDLBUFSZ];
344 	ndr_node_t	*np;
345 	int		is_reference = 0;
346 	char		*memkind = 0;
347 	int		cond_pending = 0;
348 	int		i;
349 
350 	if (ti->advice.a_operation)
351 		memkind = "TOPMOST_";
352 	else if (ti->advice.a_interface)
353 		memkind = "PARAMS_";
354 
355 	if (mem->advice.a_in && !mem->advice.a_out) {
356 		cond_pending = 1;
357 		(void) printf("    if (NDR_DIR_IS_IN) {\n");
358 	}
359 
360 	if (!mem->advice.a_in && mem->advice.a_out) {
361 		cond_pending = 1;
362 		(void) printf("    if (NDR_DIR_IS_OUT) {\n");
363 	}
364 
365 	type_extern_suffix(ti, fname_type, NDLBUFSZ);
366 
367 	switch (mem->type->type_op) {
368 	case BASIC_TYPE:
369 	case STRUCT_KW:
370 		generate_member_macro(memkind, 0, mem, 0);
371 		break;
372 
373 	case UNION_KW:
374 		np = mem->advice.a_switch_is;
375 
376 		if (!mem->advice.a_in && mem->advice.a_out) {
377 			for (i = 0; i < sizeof (fixup)/sizeof (fixup[0]); ++i)
378 				(void) printf("\t%s\n", fixup[i]);
379 
380 			(void) printf("\tfixup%s(val);\n", fname_type);
381 		}
382 
383 		generate_member_macro_with_arg(memkind,
384 		    "_WITH_SWITCH_IS", mem, 0, np);
385 		break;
386 
387 	case STAR:
388 		if (mem->advice.a_reference)
389 			is_reference = 1;
390 		else
391 			is_reference = 0;
392 
393 		np = mem->advice.a_size_is;
394 		if (np) {
395 			generate_member_macro_with_arg(memkind,
396 			    is_reference ?
397 			    "_REF_WITH_SIZE_IS" : "_PTR_WITH_SIZE_IS",
398 			    mem, mem->type->type_down, np);
399 			break;
400 		}
401 
402 		np = mem->advice.a_length_is;
403 		if (np) {
404 			generate_member_macro_with_arg(memkind,
405 			    is_reference ?
406 			    "_REF_WITH_LENGTH_IS" : "_PTR_WITH_LENGTH_IS",
407 			    mem, mem->type->type_down, np);
408 			break;
409 		}
410 
411 		generate_member_macro(memkind,
412 		    is_reference ? "_REF" : "_PTR",
413 		    mem, mem->type->type_down);
414 		break;
415 
416 	case LB:
417 		np = mem->advice.a_size_is;
418 		if (np) {
419 			generate_member_macro_with_arg(memkind,
420 			    "_ARR_WITH_SIZE_IS",
421 			    mem, mem->type->type_down, np);
422 			break;
423 		}
424 
425 		np = mem->advice.a_length_is;
426 		if (np) {
427 			generate_member_macro_with_arg(memkind,
428 			    "_WITH_LENGTH_IS",
429 			    mem, mem->type->type_down, np);
430 			break;
431 		}
432 
433 		generate_member_macro_with_arg(memkind,
434 		    "_ARR_WITH_DIMENSION",
435 		    mem, mem->type->type_down, mem->type->type_dim);
436 		break;
437 
438 	default:
439 		generate_member_macro(memkind, "_???", mem, 0);
440 		break;
441 	}
442 
443 	if (cond_pending)
444 		(void) printf("    }\n");
445 }
446 
447 static void
448 generate_aggregate_common_begin(ndr_typeinfo_t *ti)
449 {
450 	char			val_buf[NDLBUFSZ];
451 	char			cast_buf[NDLBUFSZ];
452 	char			fname_type[NDLBUFSZ];
453 	ndr_typeinfo_t		ptr;
454 
455 	type_extern_suffix(ti, fname_type, NDLBUFSZ);
456 	generate_typeinfo_typeinfo(ti, 0, fname_type);
457 	generate_prototypes(ti, fname_type);
458 
459 	(void) printf("\n");
460 	(void) printf("/*\n * ");
461 	show_advice(&ti->advice, 0);
462 	(void) printf(" */\n");
463 	(void) printf("int\n");
464 	(void) printf("ndr_%s (struct ndr_reference *encl_ref)\n",
465 	    fname_type);
466 	(void) printf("{\n");
467 
468 	ptr.type_op = STAR;
469 	ptr.type_down = ti;
470 
471 	type_name_decl(&ptr, val_buf, NDLBUFSZ, "val");
472 	type_null_decl(&ptr, cast_buf, NDLBUFSZ);
473 
474 	(void) printf("	%s = %s encl_ref->datum;\n", val_buf, cast_buf);
475 
476 	(void) printf("	struct ndr_reference myref;\n");
477 	(void) printf("\n");
478 	(void) printf("	(void) bzero(&myref, sizeof (myref));\n");
479 	(void) printf("	myref.enclosing = encl_ref;\n");
480 	(void) printf("	myref.stream = encl_ref->stream;\n");
481 	generate_typeinfo_packing(ti);
482 	(void) printf("\n");
483 }
484 
485 /* ARGSUSED */
486 static void
487 generate_aggregate_common_finish(ndr_typeinfo_t *ti)
488 {
489 	(void) printf("\n");
490 	(void) printf("	return 1;\n");
491 	(void) printf("}\n");
492 }
493 
494 /*
495  * Structures are normally 4-byte (dword) aligned but the align directive
496  * can be used to pack on a 2-byte (word) boundary.  An align value of
497  * zero is taken to mean use default (dword) alignment.  Default packing
498  * doesn't need to be flagged.
499  */
500 static void
501 generate_typeinfo_packing(ndr_typeinfo_t *ti)
502 {
503 	ndr_node_t *np;
504 	unsigned long packing;
505 
506 	if ((np = ti->advice.a_align) == NULL)
507 		return;
508 
509 	if ((np = np->n_a_arg) == NULL)
510 		return;
511 
512 	packing = np->n_int;
513 	if ((packing == 0) || (packing == 4)) {
514 		/* default alignment */
515 		return;
516 	}
517 
518 	if (packing != 2) {
519 		fatal_error("invalid align directive: %lu", packing);
520 		/* NOTREACHED */
521 	}
522 
523 	(void) printf("	myref.packed_alignment = %lu;\n", packing);
524 }
525 
526 static void
527 generate_typeinfo_typeinfo(ndr_typeinfo_t *ti, int is_static, char *fname_type)
528 {
529 	char		flags[NDLBUFSZ];
530 
531 	*flags = 0;
532 	if (ti->is_conformant)
533 		(void) strlcat(flags, "|NDR_F_CONFORMANT", NDLBUFSZ);
534 
535 	if (ti->advice.a_fake)
536 		(void) strlcat(flags, "|NDR_F_FAKE", NDLBUFSZ);
537 
538 	if (ti->type_op == STRUCT_KW) {
539 		if (ti->advice.a_operation)
540 			(void) strlcat(flags, "|NDR_F_OPERATION", NDLBUFSZ);
541 		else
542 			(void) strlcat(flags, "|NDR_F_STRUCT", NDLBUFSZ);
543 	}
544 
545 	if (ti->type_op == UNION_KW) {
546 		if (ti->advice.a_interface)
547 			(void) strlcat(flags, "|NDR_F_INTERFACE", NDLBUFSZ);
548 		else
549 			(void) strlcat(flags, "|NDR_F_UNION", NDLBUFSZ);
550 	}
551 
552 	if (ti->type_op == STRING_KW)
553 		(void) strlcat(flags, "|NDR_F_STRING", NDLBUFSZ);
554 	if (ti->type_op == LB)
555 		(void) strlcat(flags, "|NDR_F_ARRAY", NDLBUFSZ);
556 	if (ti->type_op == STAR)
557 		(void) strlcat(flags, "|NDR_F_POINTER", NDLBUFSZ);
558 
559 	if (*flags == 0)
560 		(void) strlcpy(flags, "NDR_F_NONE", NDLBUFSZ);
561 	else
562 		(void) strlcpy(flags, flags+1, NDLBUFSZ);
563 
564 	(void) printf("\n\n\n");
565 	if (is_static)
566 		(void) printf("static ");
567 
568 	(void) printf("int ndr_%s (struct ndr_reference *encl_ref);\n",
569 	    fname_type);
570 	if (is_static)
571 		(void) printf("static ");
572 
573 	(void) printf("struct ndr_typeinfo ndt_%s = {\n", fname_type);
574 	(void) printf("\t1,		/* NDR version */\n");
575 	(void) printf("\t%d,		/* alignment */\n", ti->alignment);
576 	(void) printf("\t%s,	/* flags */\n", flags);
577 	(void) printf("\tndr_%s,	/* ndr_func */\n", fname_type);
578 	(void) printf("\t%d,		/* pdu_size_fixed_part */\n",
579 	    ti->size_fixed_part);
580 	(void) printf("\t%d,		/* pdu_size_variable_part */\n",
581 	    ti->size_variable_part);
582 
583 	(void) printf("\t%d,		/* c_size_fixed_part */\n",
584 	    ti->size_fixed_part);
585 	(void) printf("\t%d,		/* c_size_variable_part */\n",
586 	    ti->size_variable_part);
587 	(void) printf("};\n\n");
588 }
589