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