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