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