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
generate(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
generate_struct(ndr_typeinfo_t * ti)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
generate_params(ndr_typeinfo_t * ti)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
generate_union(ndr_typeinfo_t * ti)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
generate_arg(ndr_node_t * np)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
generate_member_macro(char * memkind,char * macro,ndr_member_t * mem,ndr_typeinfo_t * ti)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
generate_member_macro_with_arg(char * memkind,char * macro,ndr_member_t * mem,ndr_typeinfo_t * ti,ndr_node_t * np)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
generate_prototypes(ndr_typeinfo_t * ti,char * fname_type)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
generate_member_prototypes(ndr_typeinfo_t * ti,ndr_member_t * mem,char * fname_type)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
generate_member(ndr_typeinfo_t * ti,ndr_member_t * mem)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
generate_aggregate_common_begin(ndr_typeinfo_t * ti)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
generate_aggregate_common_finish(ndr_typeinfo_t * ti)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
generate_typeinfo_packing(ndr_typeinfo_t * ti)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
generate_typeinfo_typeinfo(ndr_typeinfo_t * ti,int is_static,char * fname_type)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