xref: /NextBSD/usr.bin/migcom/routine.c (revision 33da5adc555b3bc29986eeadca03829e4ad06b1e)
1 /*-
2  * Copyright (c) 2014, Matthew Macy <kmacy@FreeBSD.ORG>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  */
27 /*
28  * Copyright 1991-1998 by Open Software Foundation, Inc.
29  *              All Rights Reserved
30  *
31  * Permission to use, copy, modify, and distribute this software and
32  * its documentation for any purpose and without fee is hereby granted,
33  * provided that the above copyright notice appears in all copies and
34  * that both the copyright notice and this permission notice appear in
35  * supporting documentation.
36  *
37  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE
38  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
39  * FOR A PARTICULAR PURPOSE.
40  *
41  * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR
42  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
43  * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT,
44  * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
45  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
46  */
47 /*
48  * cmk1.1
49  */
50 /*
51  * Mach Operating System
52  * Copyright (c) 1991,1990 Carnegie Mellon University
53  * All Rights Reserved.
54  *
55  * Permission to use, copy, modify and distribute this software and its
56  * documentation is hereby granted, provided that both the copyright
57  * notice and this permission notice appear in all copies of the
58  * software, derivative works or modified versions, and any portions
59  * thereof, and that both notices appear in supporting documentation.
60  *
61  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
62  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
63  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
64  *
65  * Carnegie Mellon requests users of this software to return to
66  *
67  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
68  *  School of Computer Science
69  *  Carnegie Mellon University
70  *  Pittsburgh PA 15213-3890
71  *
72  * any improvements or extensions that they make and grant Carnegie Mellon
73  * the rights to redistribute these changes.
74  */
75 
76 /*
77  *  ABSTRACT:
78  *   Provides the routine used by parser.c to generate
79  *   routine structures for each routine statement.
80  *   The parser generates a threaded list of statements
81  *   of which the most interesting are the various kinds
82  *   routine statments. The routine structure is defined
83  *   in routine.h which includes it name, kind of routine
84  *   and other information,
85  *   a pointer to an argument list which contains the name
86  *   and type information for each argument, and a list
87  *   of distinguished arguments, eg.  Request and Reply
88  *   ports, waittime, retcode etc.
89  */
90 #include <stdio.h>
91 
92 #include "type.h"
93 #include <mach/message.h>
94 #include <mach/kern_return.h>
95 #include "mig_machine.h"
96 #include "error.h"
97 #include "alloc.h"
98 #include "global.h"
99 #include "routine.h"
100 #include "write.h"
101 #include "utils.h"
102 
103 u_int rtNumber = 0;
104 
105 static void rtSizeDelta();
106 
107 routine_t *
rtAlloc(void)108 rtAlloc(void)
109 {
110 	register routine_t *new;
111 
112 	new = (routine_t *) calloc(1, sizeof *new);
113 	if (new == rtNULL)
114 		fatal("rtAlloc(): %s", strerror(errno));
115 	new->rtNumber = rtNumber++;
116 	new->rtName = strNULL;
117 	new->rtErrorName = strNULL;
118 	new->rtUserName = strNULL;
119 	new->rtServerName = strNULL;
120 
121 	return new;
122 }
123 
124 void
rtSkip(void)125 rtSkip(void)
126 {
127 	rtNumber++;
128 }
129 
130 argument_t *
argAlloc(void)131 argAlloc(void)
132 {
133 	static argument_t prototype =
134 		{
135 			strNULL,      /* identifier_t argName */
136 			argNULL,      /* argument_t *argNext */
137 			akNone,       /* arg_kind_t argKind */
138 			itNULL,       /* ipc_type_t *argType */
139 			argKPD_NULL,  /* mach_msg_descriptor_type_t argKPD_Type */
140 			KPD_error,    /* KPD discipline for templates */
141 			KPD_error,    /* KPD discipline for initializing */
142 			KPD_error,    /* KPD discipline for packing */
143 			KPD_error,    /* KPD discipline for extracting */
144 			KPD_error,    /* KPD discipline for type checking */
145 			strNULL,      /* string_t argVarName */
146 			strNULL,      /* string_t argMsgField */
147 			strNULL,      /* string_t argTTName */
148 			strNULL,      /* string_t argPadName */
149 			strNULL,      /* string_t argSuffix */
150 			flNone,       /* ipc_flags_t argFlags */
151 			d_NO,         /* dealloc_t argDeallocate */
152 			FALSE,        /* boolean_t argCountInOut */
153 			rtNULL,       /* routine_t *argRoutine */
154 			argNULL,      /* argument_t *argCount */
155 			argNULL,      /* argument_t *argSubCount */
156 			argNULL,      /* argument_t *argCInOut */
157 			argNULL,      /* argument_t *argPoly */
158 			argNULL,      /* argument_t *argDealloc */
159 			argNULL,      /* argument_t *argSameCount */
160 			argNULL,      /* argument_t *argParent */
161 			1,            /* int argMultiplier */
162 			0,            /* int argRequestPos */
163 			0,            /* int argReplyPos */
164 			FALSE,        /* boolean_t argByReferenceUser */
165 			FALSE,			/* boolean_t argByReferenceServer */
166 			FALSE        	/* boolean_t argTempOnStack */
167 		};
168 	register argument_t *new;
169 
170 	new = (argument_t *) malloc(sizeof *new);
171 	if (new == argNULL)
172 		fatal("argAlloc(): %s", strerror(errno));
173 	*new = prototype;
174 	return new;
175 }
176 
177 routine_t *
rtMakeRoutine(identifier_t name,argument_t * args)178 rtMakeRoutine(identifier_t name, argument_t *args)
179 {
180 	register routine_t *rt = rtAlloc();
181 
182 	rt->rtName = name;
183 	rt->rtKind = rkRoutine;
184 	rt->rtArgs = args;
185 
186 	return rt;
187 }
188 
189 routine_t *
rtMakeSimpleRoutine(identifier_t name,argument_t * args)190 rtMakeSimpleRoutine(identifier_t name, argument_t *args)
191 {
192 	register routine_t *rt = rtAlloc();
193 
194 	rt->rtName = name;
195 	rt->rtKind = rkSimpleRoutine;
196 	rt->rtArgs = args;
197 
198 	return rt;
199 }
200 
201 const char *
rtRoutineKindToStr(routine_kind_t rk)202 rtRoutineKindToStr(routine_kind_t rk)
203 {
204     switch (rk)
205     {
206     case rkRoutine:
207 		return "Routine";
208     case rkSimpleRoutine:
209 		return "SimpleRoutine";
210     default:
211 		fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk);
212 		/*NOTREACHED*/
213 		return strNULL;
214 	}
215 
216 }
217 
218 static void
rtPrintArg(register argument_t * arg)219 rtPrintArg(register argument_t *arg)
220 {
221 	register ipc_type_t *it = arg->argType;
222 
223 	if (!akCheck(arg->argKind, akbUserArg|akbServerArg) ||
224 		(akIdent(arg->argKind) == akeCount) ||
225 		(akIdent(arg->argKind) == akeDealloc) ||
226 		(akIdent(arg->argKind) == akeNdrCode) ||
227 		(akIdent(arg->argKind) == akePoly))
228 		return;
229 
230 	printf("\n\t");
231 
232     switch (akIdent(arg->argKind))
233     {
234     case akeRequestPort:
235 		printf("RequestPort");
236 		break;
237     case akeReplyPort:
238 		printf("ReplyPort");
239 		break;
240     case akeWaitTime:
241 		printf("WaitTime");
242 		break;
243 
244     case akeSendTime:
245 		printf("SendTime");
246 		break;
247 
248     case akeMsgOption:
249 		printf("MsgOption");
250 		break;
251     case akeMsgSeqno:
252 		printf("MsgSeqno\t");
253 		break;
254     case akeSecToken:
255 		printf("SecToken\t");
256 		break;
257 
258     case akeAuditToken:
259 		printf("AuditToken\t");
260 		break;
261 
262     case akeContextToken:
263 		printf("ContextToken\t");
264 		break;
265 
266     case akeImplicit:
267 		printf("Implicit\t");
268 		break;
269     default:
270 		if (akCheck(arg->argKind, akbRequest)) {
271 			if (akCheck(arg->argKind, akbSend))
272 				printf("In");
273 			else
274 				printf("(In)");
275 		}
276 		if (akCheck(arg->argKind, akbReply)) {
277 			if (akCheck(arg->argKind, akbReturn))
278 				printf("Out");
279 			else
280 				printf("(Out)");
281 		}
282 		printf("\t");
283 	}
284 
285 	printf("\t%s: %s", arg->argName, it->itName);
286 
287 	if (arg->argDeallocate == d_YES)
288 		printf(", Dealloc");
289 	else if (arg->argDeallocate == d_MAYBE)
290 		printf(", Dealloc[]");
291 
292 	if (arg->argCountInOut)
293 		printf(", CountInOut");
294 
295 	if (arg->argFlags & flSameCount)
296 		printf(", SameCount");
297 
298 	if (arg->argFlags & flPhysicalCopy)
299 		printf(", PhysicalCopy");
300 
301 	if (arg->argFlags & flRetCode)
302 		printf(", PhysicalCopy");
303 
304 	if (arg->argFlags & flOverwrite)
305 		printf(", Overwrite");
306 
307 	if (arg->argFlags & flAuto)
308 		printf(", Auto");
309 
310 	if (arg->argFlags & flConst)
311 		printf(", Const");
312 }
313 
314 void
rtPrintRoutine(register routine_t * rt)315 rtPrintRoutine(register routine_t *rt)
316 {
317 	register argument_t *arg;
318 
319     printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind),
320 		   rt->rtNumber, rt->rtName);
321 
322 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
323 		rtPrintArg(arg);
324 
325 	printf(")\n");
326 	printf("\n");
327 }
328 
329 /*
330  * Determines appropriate value of msg-simple for the message.
331  * One version for both In & Out.
332  */
333 
334 static void
rtCheckSimple(argument_t * args,u_int mask,boolean_t * simple)335 rtCheckSimple(argument_t *args, u_int mask, boolean_t *simple)
336 {
337 	register argument_t *arg;
338 	boolean_t MustBeComplex = FALSE;
339 
340 	for (arg = args; arg != argNULL; arg = arg->argNext)
341 		if (akCheck(arg->argKind, mask)) {
342 			ipc_type_t *it = arg->argType;
343 
344 			if (IS_KERN_PROC_DATA(it))
345 				MustBeComplex = TRUE;
346 		}
347 
348 	*simple = !MustBeComplex;
349 }
350 
351 static void
rtCheckFit(routine_t * rt,u_int mask,boolean_t * fitp,boolean_t * uselimp,u_int * knownp)352 rtCheckFit(routine_t *rt, u_int mask, boolean_t *fitp, boolean_t *uselimp, u_int *knownp)
353 {
354 	boolean_t uselim = FALSE;
355 	argument_t *arg;
356     int size = sizeof(mach_msg_header_t);
357 
358 	if (!rt->rtSimpleRequest)
359 		machine_alignment(size,sizeof(mach_msg_body_t));
360 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
361 		if (akCheck(arg->argKind, mask)) {
362 			register ipc_type_t *it = arg->argType;
363 
364 			machine_alignment(size, it->itMinTypeSize);
365 			if (it->itNative)
366 				uselim = TRUE;
367 			else if (IS_VARIABLE_SIZED_UNTYPED(it)) {
368 				machine_alignment(size, it->itTypeSize);
369 				size += it->itPadSize;
370 			}
371 		}
372 	*knownp = size;
373 	if (MaxMessSizeOnStack == -1) {
374 		*fitp = TRUE;
375 		*uselimp = FALSE;
376     } else if (size > MaxMessSizeOnStack) {
377 		*fitp = FALSE;
378 		*uselimp = FALSE;
379     } else if (!uselim) {
380 		*fitp = TRUE;
381 		*uselimp = FALSE;
382     } else if (UserTypeLimit == -1) {
383 		*fitp = FALSE;
384 		*uselimp = FALSE;
385     } else if (size + UserTypeLimit > MaxMessSizeOnStack) {
386 		*fitp = FALSE;
387 		*uselimp = TRUE;
388     } else {
389 		*fitp = TRUE;
390 		*uselimp = TRUE;
391 	}
392 }
393 
394 static void
rtFindHowMany(routine_t * rt)395 rtFindHowMany(routine_t *rt)
396 {
397 	register argument_t *arg;
398 	int multiplier = 1;
399 	boolean_t test;
400 
401 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
402 		register ipc_type_t *it = arg->argType;
403 
404 		if (IS_MULTIPLE_KPD(it)) {
405 			if (!it->itVarArray)
406 				multiplier = it->itKPD_Number;
407 			test = !it->itVarArray && !it->itElement->itVarArray;
408 			it = it->itElement;
409 		} else
410 			test = !it->itVarArray;
411 
412 		if (akCheck(arg->argKind, akbSendKPD)) {
413 
414 			if (it->itInLine)
415 				rt->rtCountPortsIn += it->itNumber * multiplier;
416 			else if (it->itPortType) {
417 				if (test)
418 					rt->rtCountOolPortsIn += it->itNumber * multiplier;
419             } else {
420 				if (test)
421 					rt->rtCountOolIn += (it->itNumber * it->itSize + 7)/8 * multiplier;
422 			}
423 		}
424 		if (akCheckAll(arg->argKind, akbReturnKPD)) {
425 			if (it->itInLine)
426 				rt->rtCountPortsOut += it->itNumber * multiplier;
427 			else if (it->itPortType) {
428 				if (test)
429 					rt->rtCountOolPortsOut += it->itNumber * multiplier;
430             } else {
431 				if (test)
432 					rt->rtCountOolOut += ((it->itNumber * it->itSize + 7)/8) * multiplier;
433 			}
434 		}
435 	}
436 }
437 
438 boolean_t
rtCheckMask(argument_t * args,u_int mask)439 rtCheckMask(argument_t *args, u_int mask)
440 {
441 	register argument_t *arg;
442 
443 	for (arg = args; arg != argNULL; arg = arg->argNext)
444 		if (akCheckAll(arg->argKind, mask))
445 			return TRUE;
446 	return FALSE;
447 }
448 
449 boolean_t
rtCheckMaskFunction(argument_t * args,u_int mask,boolean_t (* func)())450 rtCheckMaskFunction(argument_t *args, u_int mask, boolean_t (*func)(/* argument_t *arg */))
451 {
452 	register argument_t *arg;
453 
454 	for (arg = args; arg != argNULL; arg = arg->argNext)
455 		if (akCheckAll(arg->argKind, mask))
456 			if ((*func)(arg))
457 				return TRUE;
458 	return FALSE;
459 }
460 
461 
462 static int
rtCountKPDs(argument_t * args,u_int mask)463 rtCountKPDs(argument_t *args, u_int mask)
464 {
465 	register argument_t *arg;
466 	int count = 0;
467 
468 	for (arg = args; arg != argNULL; arg = arg->argNext)
469 		if (akCheckAll(arg->argKind, mask))
470 			count += arg->argType->itKPD_Number;
471 	return count;
472 }
473 
474 static int
rtCountFlags(args,flag)475 rtCountFlags(args, flag)
476     argument_t *args;
477     u_int flag;
478 {
479 	register argument_t *arg;
480 	int count = 0;
481 
482 	for (arg = args; arg != argNULL; arg = arg->argNext)
483 		if (arg->argFlags & flag)
484 			count++;
485 	return count;
486 }
487 
488 int
rtCountArgDescriptors(argument_t * args,int * argcount)489 rtCountArgDescriptors(argument_t *args, int *argcount)
490 {
491 	register argument_t *arg;
492 	int count = 0;
493 
494 	if (argcount)
495 		*argcount = 0;
496 	for (arg = args; arg != argNULL; arg = arg->argNext)
497 		if (akCheck(arg->argKind, akbServerArg)) {
498 			if (RPCFixedArray(arg) ||
499 				RPCPort(arg) ||
500 				RPCVariableArray(arg) ||
501 				RPCPortArray(arg)) {
502 				count++;
503 				if (argcount)
504 					(*argcount)++;
505 			}
506 			else {
507 				if (argcount) {
508 					if (arg->argType->itStruct && arg->argType->itNumber &&
509 						(arg->argType->itSize >= 32))
510 						*argcount += arg->argType->itNumber * (arg->argType->itSize / 32);
511 					else
512 						(*argcount)++;
513 				}
514 			}
515 		}
516 	return count;
517 }
518 
519 static int
rtCountMask(argument_t * args,u_int mask)520 rtCountMask(argument_t *args, u_int mask)
521 {
522 	register argument_t *arg;
523 	int count = 0;
524 
525 	for (arg = args; arg != argNULL; arg = arg->argNext)
526 		if (akCheckAll(arg->argKind, mask))
527 			count++;
528 	return count;
529 }
530 
531 /* arg->argType may be NULL in this function */
532 
533 static void
rtDefaultArgKind(routine_t * rt,argument_t * arg)534 rtDefaultArgKind(routine_t *rt, argument_t *arg)
535 {
536     if ((arg->argKind == akNone) && (rt->rtRequestPort == argNULL))
537 		arg->argKind = akRequestPort;
538 
539 	if (arg->argKind == akNone)
540 		arg->argKind = akIn;
541 }
542 
543 /*
544  * Initializes arg->argDeallocate,
545  * arg->argCountInOut from arg->argFlags
546  * and perform consistency check over the
547  * flags.
548  */
549 
550 static ipc_flags_t
rtProcessDeallocFlag(register ipc_type_t * it,register ipc_flags_t flags,register arg_kind_t kind,dealloc_t * what,string_t name)551 rtProcessDeallocFlag(register ipc_type_t *it, register ipc_flags_t flags, register arg_kind_t kind, dealloc_t *what, string_t name)
552 {
553 
554 	/* only one of flDealloc, flNotDealloc, flMaybeDealloc */
555 
556 	if (flags & flMaybeDealloc) {
557 		if (flags & (flDealloc|flNotDealloc)) {
558 			warn("%s: Dealloc and NotDealloc ignored with Dealloc[]", name);
559 			flags &= ~(flDealloc|flNotDealloc);
560 		}
561 	}
562 
563 	if ((flags&(flDealloc|flNotDealloc)) == (flDealloc|flNotDealloc)) {
564 		warn("%s: Dealloc and NotDealloc cancel out", name);
565 		flags &= ~(flDealloc|flNotDealloc);
566 	}
567 
568 	if (((IsKernelServer && akCheck(kind, akbReturn)) ||
569 		 (IsKernelUser && akCheck(kind, akbSend))) &&
570 		(flags & flDealloc)) {
571 		/*
572 		 *  For a KernelServer interface and an Out argument,
573 		 *  or a KernelUser interface and an In argument,
574 		 *  we avoid a possible spurious warning about the deallocate bit.
575 		 *  For compatibility with Mach 2.5, the deallocate bit
576 		 *  may need to be enabled on some inline arguments.
577 		 */
578 
579 		*what= d_YES;
580     } else if (flags & (flMaybeDealloc|flDealloc)) {
581 		/* only give semantic warnings if the user specified something */
582 		if (it->itInLine && !it->itPortType) {
583 			warn("%s: Dealloc is ignored: it is meaningless  for that type of argument", name);
584 			flags &= ~(flMaybeDealloc|flDealloc);
585 		} else
586 			*what = (flags & flMaybeDealloc) ? d_MAYBE : d_YES;
587 	}
588 	return flags;
589 }
590 
591 static void
rtProcessSameCountFlag(register argument_t * arg)592 rtProcessSameCountFlag(register argument_t *arg)
593 {
594 	register ipc_type_t *it = arg->argType;
595 	register ipc_flags_t flags = arg->argFlags;
596 	string_t name = arg->argVarName;
597 	static argument_t *old_arg;
598 
599 	if (flags & flSameCount)  {
600 		if (!it->itVarArray) {
601 			warn("%s: SameCount is ignored - the argument is not variable", name);
602 			flags &= ~flSameCount;
603 		}
604 		if (old_arg) {
605 			if (old_arg->argParent)
606 				old_arg = old_arg->argParent;
607 			if (old_arg->argSameCount)
608 				old_arg = old_arg->argSameCount;
609 
610 			if (!old_arg->argType->itVarArray) {
611 				warn("%s: SameCount is ignored - adjacent argument is not variable", name);
612 				flags &= ~flSameCount;
613 			}
614 
615 #define SAMECOUNT_MASK akeBITS|akbSend|akbReturn|akbRequest|akbReply|akbUserArg|akbServerArg
616 			if (akCheck(old_arg->argKind, SAMECOUNT_MASK) !=
617 				akCheck(arg->argKind, SAMECOUNT_MASK) ||
618 				old_arg->argCountInOut != arg->argCountInOut) {
619 				warn("%s: SameCount is ignored - inconsistencies with the adjacent argument\n", name);
620 				flags &= ~flSameCount;
621 			}
622 			arg->argSameCount = old_arg;
623 		}
624 		arg->argFlags = flags;
625 	}
626 	old_arg = arg;
627 }
628 
629 static ipc_flags_t
rtProcessCountInOutFlag(ipc_type_t * it,ipc_flags_t flags,arg_kind_t kind,boolean_t * what,string_t name)630 rtProcessCountInOutFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, boolean_t *what, string_t name)
631 {
632 	if (flags & flCountInOut) {
633 		if (!akCheck(kind, akbReply)) {
634 			warn("%s: CountInOut is ignored: argument must be Out\n", name);
635 			flags &= ~flCountInOut;
636 		} else if (!it->itVarArray || !it->itInLine) {
637 			warn("%s: CountInOut is ignored: argument isn't variable or in-line\n", name);
638 			flags &= ~flCountInOut;
639 		} else
640 			*what = TRUE;
641 	}
642 	return flags;
643 }
644 
645 static ipc_flags_t
rtProcessPhysicalCopyFlag(register ipc_type_t * it,register ipc_flags_t flags,register arg_kind_t kind __unused,string_t name)646 rtProcessPhysicalCopyFlag(register ipc_type_t *it, register ipc_flags_t flags, register arg_kind_t kind __unused, string_t name)
647 {
648 	if (flags & flPhysicalCopy) {
649 		if (it->itInLine) {
650 			warn("%s: PhysicalCopy is ignored, argument copied inline anyway", name);
651 			flags &= ~flPhysicalCopy;
652 		}
653 		if (it->itPortType) {
654 			warn("%s: PhysicalCopy is ignored, it does not apply to ports and array of ports", name);
655 			flags &= ~flPhysicalCopy;
656 		}
657 	}
658 	return flags;
659 }
660 
661 static void
rtProcessRetCodeFlag(register argument_t * thisarg)662 rtProcessRetCodeFlag(register argument_t *thisarg)
663 {
664 	register ipc_type_t *it = thisarg->argType;
665 	register ipc_flags_t flags = thisarg->argFlags;
666 	string_t name = thisarg->argVarName;
667 	routine_t *thisrout = thisarg->argRoutine;
668 
669 	if (flags & flRetCode) {
670 		if (!it->itInLine || !it->itStruct ||
671 			it->itSize != 32 || it->itNumber != 1) {
672 			warn("%s: RetCode is ignored - the type doesn't match a MIG RetCode", name);
673 			flags &= ~flRetCode;
674 		} else if (thisrout->rtKind != rkSimpleRoutine) {
675 			fatal("%s: RetCode is allowed only for SimpleRoutines", name);
676 		} else if (thisrout->rtRetCArg != argNULL) {
677 			warn("%s: RetCode is ignored - only one argument can be flagged as RetCode", name);
678 			flags &= ~flRetCode;
679 		} else {
680 			thisrout->rtRetCArg = thisarg;
681 		}
682 		thisarg->argFlags = flags;
683 	}
684 }
685 
686 static ipc_flags_t
rtProcessOverwriteFlag(register ipc_type_t * it,register ipc_flags_t flags,register arg_kind_t kind,string_t name)687 rtProcessOverwriteFlag(register ipc_type_t *it, register ipc_flags_t flags, register arg_kind_t kind, string_t name)
688 {
689 	if (flags & flOverwrite)
690 		if (it->itInLine || it->itMigInLine ||
691 			/* among In, Out, InOut, we want only the Out! */
692 			!akCheck(kind, akbReturn) || akCheck(kind, akbSend)) {
693 			warn("%s: Overwrite is ignored - it must be Out AND Ool!", name);
694 			flags &= ~flOverwrite;
695 		}
696 	return flags;
697 }
698 
699 static void
rtDetectKPDArg(argument_t * arg)700 rtDetectKPDArg(argument_t *arg)
701 {
702 	register ipc_type_t *it = arg->argType;
703     const char *string;
704 
705 	if  (IS_KERN_PROC_DATA(it)) {
706 		if (akCheck(arg->argKind, akbSendBody)) {
707 			arg->argKind = akRemFeature(arg->argKind, akbSendBody);
708 			arg->argKind = akAddFeature(arg->argKind, akbSendKPD);
709 		}
710 		if (akCheck(arg->argKind, akbReturnBody)) {
711 			arg->argKind = akRemFeature(arg->argKind, akbReturnBody);
712 			arg->argKind = akAddFeature(arg->argKind, akbReturnKPD);
713 		}
714 		if (it->itInLine) {
715 			string = "mach_msg_port_descriptor_t";
716 			arg->argKPD_Type = MACH_MSG_PORT_DESCRIPTOR;
717         } else if (it->itPortType) {
718 			string = "mach_msg_ool_ports_descriptor_t";
719 			arg->argKPD_Type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
720         } else {
721 			string = "mach_msg_ool_descriptor_t";
722 			arg->argKPD_Type = MACH_MSG_OOL_DESCRIPTOR;
723 		}
724 		it->itKPDType = string;
725 	}
726 }
727 
728 static void
rtAugmentArgKind(argument_t * arg)729 rtAugmentArgKind(argument_t *arg)
730 {
731 	register ipc_type_t *it = arg->argType;
732 
733 	/* akbVariable means variable-sized inline */
734 
735 	if (IS_VARIABLE_SIZED_UNTYPED(it)) {
736 		if (akCheckAll(arg->argKind, akbRequest|akbReply))
737 			error("%s: Inline variable-sized arguments can't be InOut",
738 				  arg->argName);
739 		arg->argKind = akAddFeature(arg->argKind, akbVariable);
740 	}
741 	if (IS_OPTIONAL_NATIVE(it))
742 		arg->argKind = akAddFeature(arg->argKind, akbVariable);
743 
744 	/*
745 	 * Need to use a local variable in the following cases:
746 	 *  1) There is a translate-out function & the argument is being
747 	 *     returned.  We need to translate it before it hits the message.
748 	 *  2) There is a translate-in function & the argument is
749 	 *     sent and returned.  We need a local variable for its address.
750 	 *  3) There is a destructor function, which will be used
751 	 *     (SendRcv and not ReturnSnd), and there is a translate-in
752 	 *     function whose value must be saved for the destructor.
753 	 *  4) This is Complex KPD (array of KPD), and as such it has to
754 	 *     be copied to a local array in input and output
755 	 *  5) Both poly and dealloc generate warnings compile time, because
756 	 *     we attempt to take address of bit-field structure member
757 	 */
758 
759     if (((it->itOutTrans != strNULL) &&
760 		 akCheck(arg->argKind, akbReturnSnd)) ||
761 		((it->itInTrans != strNULL) &&
762 		 akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) ||
763 		((it->itDestructor != strNULL) &&
764 		 akCheck(arg->argKind, akbSendRcv) &&
765 		 !akCheck(arg->argKind, akbReturnSnd) &&
766 		 (it->itInTrans != strNULL)) ||
767 		(IS_MULTIPLE_KPD(it)) ||
768 		((akIdent(arg->argKind) == akePoly) &&
769 		 akCheck(arg->argKind, akbReturnSnd))  ||
770 		((akIdent(arg->argKind) == akeDealloc) &&
771 		 akCheck(arg->argKind, akbReturnSnd))
772 		)
773     {
774 		arg->argKind = akRemFeature(arg->argKind, akbReplyCopy);
775 		arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
776 	}
777 }
778 
779 /*
780  * The Suffix allows to handle KPDs as normal data.
781  * it is used in InArgMsgField.
782  */
783 static void
rtSuffixExtArg(register argument_t * args)784 rtSuffixExtArg(register argument_t *args)
785 {
786 	register argument_t *arg;
787     register const char *subindex;
788 	char string[MAX_STR_LEN];
789 
790 	for (arg = args; arg != argNULL; arg = arg->argNext)  {
791 		if (akCheck(arg->argKind, akbSendKPD | akbReturnKPD)) {
792 			if (IS_MULTIPLE_KPD(arg->argType))
793 				subindex = "[0]";
794 			else
795 				subindex = "";
796 			switch (arg->argKPD_Type) {
797 
798 			case MACH_MSG_PORT_DESCRIPTOR:
799 				(void)sprintf(string, "%s.name", subindex);
800 				break;
801 
802 			case MACH_MSG_OOL_DESCRIPTOR:
803 			case MACH_MSG_OOL_PORTS_DESCRIPTOR:
804 				(void)sprintf(string, "%s.address", subindex);
805 				break;
806 
807 			default:
808 				error("Type of kernel processed data unknown\n");
809 			}
810 			arg->argSuffix = strconcat(arg->argMsgField, string);
811 			/* see above the list of VarNeeded cases */
812 			/*
813 			 * argCount has been removed from the VarNeeded list,
814 			 * because VarSize arrays have their Count in the untyped
815 			 * section of the message, and because it is not possible
816 			 * to move anything in-line/out-of-line
817 			 */
818 		} else if (akIdent(arg->argKind) == akePoly &&
819 				   akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) {
820 			register argument_t *par_arg = arg->argParent;
821 
822 			if (IS_MULTIPLE_KPD(par_arg->argType))
823 				subindex = "[0]";
824 			else
825 				subindex = "";
826 			switch (par_arg->argKPD_Type) {
827 
828 			case MACH_MSG_PORT_DESCRIPTOR:
829 			case MACH_MSG_OOL_PORTS_DESCRIPTOR:
830 				(void)sprintf(string, "%s.disposition", subindex);
831 				arg->argSuffix = strconcat(par_arg->argMsgField, string);
832 				break;
833 			default:
834 				error("Type of kernel processed data inconsistent\n");
835 			}
836 		} else if (akIdent(arg->argKind) == akeDealloc &&
837 				   akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) {
838 			register argument_t *par_arg = arg->argParent;
839 
840 			if (IS_MULTIPLE_KPD(par_arg->argType))
841 				subindex = "[0]";
842 			else
843 				subindex = "";
844 			switch (par_arg->argKPD_Type) {
845 
846 			case MACH_MSG_OOL_DESCRIPTOR:
847 			case MACH_MSG_OOL_PORTS_DESCRIPTOR:
848 				(void)sprintf(string, "%s.deallocate", subindex);
849 				arg->argSuffix = strconcat(par_arg->argMsgField, string);
850 				break;
851 
852 			default:
853 				error("Type of kernel processed data inconsistent\n");
854 			}
855 		}
856 	}
857 }
858 
859 /* arg->argType may be NULL in this function */
860 
861 static void
rtCheckRoutineArg(routine_t * rt,argument_t * arg)862 rtCheckRoutineArg(routine_t *rt, argument_t *arg)
863 {
864     switch (akIdent(arg->argKind))
865     {
866     case akeRequestPort:
867 		if (rt->rtRequestPort != argNULL)
868 			warn("multiple RequestPort args in %s; %s won't be used",
869 				 rt->rtName, rt->rtRequestPort->argName);
870 		rt->rtRequestPort = arg;
871 		break;
872 
873     case akeReplyPort:
874 		if (rt->rtReplyPort != argNULL)
875 			warn("multiple ReplyPort args in %s; %s won't be used",
876 				 rt->rtName, rt->rtReplyPort->argName);
877 		rt->rtReplyPort = arg;
878 		break;
879 
880     case akeWaitTime:
881 		if (rt->rtWaitTime != argNULL)
882 			warn("multiple WaitTime/SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName);
883 		rt->rtWaitTime = arg;
884 		break;
885 
886     case akeSendTime:
887 		if (rt->rtWaitTime != argNULL) {
888 			if (akIdent(rt->rtWaitTime->argKind) == akeWaitTime) {
889 				warn("SendTime type argument after a WaitTime in %s; SendTime %s won't be used", rt->rtName, arg->argName);
890 				break;
891 			} else
892 				warn("multiple SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName);
893 		}
894 		rt->rtWaitTime = arg;
895 		break;
896 
897     case akeMsgOption:
898 		if (rt->rtMsgOption != argNULL)
899 			warn("multiple MsgOption args in %s; %s won't be used",
900 				 rt->rtName, rt->rtMsgOption->argName);
901 		rt->rtMsgOption = arg;
902 		break;
903 
904     default:
905 		break;
906 	}
907 }
908 
909 /* arg->argType may be NULL in this function */
910 
911 static void
rtSetArgDefaults(routine_t * rt,register argument_t * arg)912 rtSetArgDefaults(routine_t *rt, register argument_t *arg)
913 {
914 	arg->argRoutine = rt;
915 	if (arg->argVarName == strNULL)
916 		arg->argVarName = arg->argName;
917 	if (arg->argMsgField == strNULL)
918 		switch(akIdent(arg->argKind)) {
919 		case akeRequestPort:
920 			arg->argMsgField = "Head.msgh_request_port";
921 			break;
922 		case akeReplyPort:
923 			arg->argMsgField = "Head.msgh_reply_port";
924 			break;
925 		case akeNdrCode:
926 			arg->argMsgField = "NDR";
927 			break;
928 		case akeSecToken:
929 			arg->argMsgField = "msgh_sender";
930 			break;
931 
932 		case akeAuditToken:
933 			arg->argMsgField = "msgh_audit";
934 			break;
935 
936 		case akeContextToken:
937 			arg->argMsgField = "msgh_context";
938 			break;
939 
940 		case akeMsgSeqno:
941 			arg->argMsgField = "msgh_seqno";
942 			break;
943 		case akeImplicit:
944 			/* the field is set directly by Yacc */
945 			break;
946 		default:
947 			arg->argMsgField = arg->argName;
948 			break;
949 		}
950 
951 	if (arg->argTTName == strNULL)
952 		arg->argTTName = strconcat(arg->argName, "Template");
953 	if (arg->argPadName == strNULL)
954 		arg->argPadName = strconcat(arg->argName, "Pad");
955 
956 	/*
957 	 *  The poly args for the request and reply ports have special defaults,
958 	 *  because their msg-type-name values aren't stored in normal fields.
959 	 */
960 
961 	if ((rt->rtRequestPort != argNULL) &&
962 		(rt->rtRequestPort->argPoly == arg) &&
963 		(arg->argType != itNULL)) {
964 		arg->argMsgField = "Head.msgh_bits";
965 		arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST";
966 	}
967 
968 	if ((rt->rtReplyPort != argNULL) &&
969 		(rt->rtReplyPort->argPoly == arg) &&
970 		(arg->argType != itNULL)) {
971 		arg->argMsgField = "Head.msgh_bits";
972 		arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY";
973 	}
974 }
975 
976 static void
rtAddCountArg(register argument_t * arg)977 rtAddCountArg(register argument_t *arg)
978 {
979 	register argument_t *count, *master;
980 	register ipc_type_t *it = arg->argType;
981 
982 	count = argAlloc();
983 
984 	if (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray) {
985 		count->argName = strconcat(arg->argName, "Subs");
986 		count->argType = itMakeSubCountType(it->itKPD_Number, it->itVarArray, arg->argVarName);
987 		count->argKind = akeSubCount;
988 		arg->argSubCount = count;
989     } else {
990 		count->argName = strconcat(arg->argName, "Cnt");
991 		count->argType = itMakeCountType();
992 		count->argKind = akeCount;
993 		arg->argCount = count;
994 		if (arg->argParent != argNULL)  {
995 			/* this is the case where we are at the second level of recursion:
996 			   we want the Parent to access it through argCount */
997 			arg->argParent->argCount = count;
998 		}
999 	}
1000 	master = (arg->argParent != argNULL) ? arg->argParent : arg;
1001 	if (IS_MULTIPLE_KPD(master->argType))
1002 		count->argMultiplier = 1;
1003 	else
1004 		count->argMultiplier = it->itElement->itNumber;
1005 	count->argParent = arg;
1006 	count->argNext = arg->argNext;
1007 	arg->argNext = count;
1008 
1009 	if (arg->argType->itString) {
1010 	    /* C String gets no Count argument on either side. */
1011 		count->argKind = akAddFeature(count->argKind, akCheck(arg->argKind, akbSend) ? akbSendRcv : akbReturnRcv);
1012 		count->argVarName = (char *)0;
1013     } else {
1014 		/*
1015 		 * Count arguments have to be present on the message body (NDR encoded)
1016 		 * akbVariable has to be turned down, has it foul the algorithm
1017 		 * for detecting the in-line variable sized arrays
1018 		 */
1019 		count->argKind |= akAddFeature(akbUserArg|akbServerArg, (arg->argKind) & ~akeBITS);
1020 		count->argKind = akRemFeature(count->argKind, akbVariable|akbVarNeeded);
1021 		if (IS_VARIABLE_SIZED_UNTYPED(arg->argType))
1022 			/*
1023 			 * Count arguments for the above types are explicitly declared
1024 			 * BEFORE the variable (with those bits, they would come afterwards)
1025 			 */
1026 			count->argKind = akRemFeature(count->argKind, akbRequest|akbReply);
1027 	}
1028 }
1029 
1030 static void
rtAddCountInOutArg(register argument_t * arg)1031 rtAddCountInOutArg(register argument_t *arg)
1032 {
1033 	register argument_t *count;
1034 
1035 	/*
1036 	 *  The user sees a single count variable.  However, to get the
1037 	 *  count passed from user to server for variable-sized inline OUT
1038 	 *  arrays, we need two count arguments internally.  This is
1039 	 *  because the count value lives in different message fields (and
1040 	 *  is scaled differently) in the request and reply messages.
1041 	 *
1042 	 *  The two variables have the same name to simplify code generation.
1043 	 *
1044 	 *  This variable has a null argParent field because it has akbRequest.
1045 	 *  For example, see rtCheckVariable.
1046 	 */
1047 
1048 	count = argAlloc();
1049 	count->argName = strconcat(arg->argName, "Cnt");
1050 	count->argType = itMakeCountType();
1051 	count->argParent = argNULL;
1052 	count->argNext = arg->argNext;
1053 	arg->argNext = count;
1054 	(count->argCInOut = arg->argCount)->argCInOut = count;
1055 	count->argKind = akCountInOut;
1056 }
1057 
1058 static void
rtAddPolyArg(register argument_t * arg)1059 rtAddPolyArg(register argument_t *arg)
1060 {
1061 	register ipc_type_t *it = arg->argType;
1062 	register argument_t *poly;
1063 	arg_kind_t akbsend, akbreturn;
1064 
1065 	poly = argAlloc();
1066 	poly->argName = strconcat(arg->argName, "Poly");
1067 	poly->argType = itMakePolyType();
1068 	poly->argParent = arg;
1069 	poly->argNext = arg->argNext;
1070 	arg->argNext = poly;
1071 	arg->argPoly = poly;
1072 
1073 	/*
1074 	 * akbsend is bits added if the arg is In;
1075 	 * akbreturn is bits added if the arg is Out.
1076 	 * The mysterious business with KernelServer subsystems:
1077 	 * when packing Out arguments, they use OutNames instead
1078 	 * of InNames, and the OutName determines if they are poly-in
1079 	 * as well as poly-out.
1080 	 */
1081 
1082 	akbsend = akbSend;
1083 	akbreturn = akbReturn;
1084 
1085     if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC)
1086     {
1087 		akbsend |= akbUserArg|akbSendSnd;
1088 		if (!IsKernelServer)
1089 			akbreturn |= akbServerArg|akbReturnSnd;
1090 	}
1091     if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
1092     {
1093 		akbsend |= akbServerArg|akbSendRcv;
1094 		akbreturn |= akbUserArg|akbReturnRcv;
1095 		if (IsKernelServer)
1096 			akbreturn |= akbServerArg|akbReturnSnd;
1097 	}
1098 
1099 	poly->argKind = akPoly;
1100 	if (akCheck(arg->argKind, akbSend))
1101 		poly->argKind = akAddFeature(poly->argKind,
1102 									 akCheck(arg->argKind, akbsend));
1103 	if (akCheck(arg->argKind, akbReturn))
1104 		poly->argKind = akAddFeature(poly->argKind,
1105 									 akCheck(arg->argKind, akbreturn));
1106 }
1107 
1108 static void
rtAddDeallocArg(register argument_t * arg)1109 rtAddDeallocArg(register argument_t *arg)
1110 {
1111 	register argument_t *dealloc;
1112 
1113 	dealloc = argAlloc();
1114 	dealloc->argName = strconcat(arg->argName, "Dealloc");
1115 	dealloc->argType = itMakeDeallocType();
1116 	dealloc->argParent = arg;
1117 	dealloc->argNext = arg->argNext;
1118 	arg->argNext = dealloc;
1119 	arg->argDealloc = dealloc;
1120 
1121 	/*
1122 	 * Dealloc flag can only be associated to KPDs.
1123 	 */
1124 
1125 	dealloc->argKind = akeDealloc;
1126 	if (akCheck(arg->argKind, akbSend))
1127 		dealloc->argKind = akAddFeature(dealloc->argKind,
1128 										akCheck(arg->argKind, akbUserArg|akbSend|akbSendSnd));
1129 	if (akCheck(arg->argKind, akbReturn)) {
1130 		dealloc->argKind = akAddFeature(dealloc->argKind,
1131 										akCheck(arg->argKind, akbServerArg|akbReturn|akbReturnSnd));
1132 
1133 		dealloc->argByReferenceServer = TRUE;
1134 	}
1135 }
1136 
1137 static void
rtCheckRoutineArgs(routine_t * rt)1138 rtCheckRoutineArgs(routine_t *rt)
1139 {
1140 	register argument_t *arg;
1141 
1142     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
1143     {
1144 		register ipc_type_t *it = arg->argType;
1145 
1146 		rtDefaultArgKind(rt, arg);
1147 		rtCheckRoutineArg(rt, arg);
1148 
1149 		/* need to set argTTName before adding implicit args */
1150 		rtSetArgDefaults(rt, arg);
1151 
1152 		/* the arg may not have a type (if there was some error in parsing it),
1153 		   in which case we don't want to do these steps. */
1154 
1155 		if (it != itNULL) {
1156 			arg->argFlags = rtProcessDeallocFlag(it, arg->argFlags, arg->argKind, &arg->argDeallocate, arg->argVarName);
1157 			arg->argFlags = rtProcessCountInOutFlag(it, arg->argFlags, arg->argKind, &arg->argCountInOut, arg->argVarName);
1158 			rtProcessSameCountFlag(arg);
1159 			arg->argFlags = rtProcessPhysicalCopyFlag(it, arg->argFlags, arg->argKind, arg->argVarName);
1160 			rtProcessRetCodeFlag(arg);
1161 			arg->argFlags = rtProcessOverwriteFlag(it, arg->argFlags, arg->argKind, arg->argVarName);
1162 			rtAugmentArgKind(arg);
1163 
1164 			/* args added here will get processed in later iterations */
1165 			/* order of args is 'arg poly countinout count dealloc' */
1166 
1167 			if (arg->argDeallocate == d_MAYBE)
1168 				rtAddDeallocArg(arg);
1169 			if (it->itVarArray || (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray))
1170 				rtAddCountArg(arg);
1171 			if (arg->argCountInOut)
1172 				rtAddCountInOutArg(arg);
1173 			if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) ||
1174 				(it->itOutName == MACH_MSG_TYPE_POLYMORPHIC))
1175 				rtAddPolyArg(arg);
1176 			/*
1177 			 * Detects whether the arg has to become part of the
1178 			 * Kernel Processed Data section; if yes, define the proper
1179 			 * itUserKPDType, itServerKPDType
1180 			 */
1181 			rtDetectKPDArg(arg);
1182 		}
1183 	}
1184 }
1185 
1186 static boolean_t
rtCheckTrailerType(register argument_t * arg)1187 rtCheckTrailerType(register argument_t *arg)
1188 {
1189     if (akIdent(arg->argKind) == akeSecToken ||
1190 		akIdent(arg->argKind) == akeAuditToken ||
1191 		akIdent(arg->argKind) == akeContextToken)
1192 		itCheckTokenType(arg->argVarName, arg->argType);
1193 
1194 	if (akIdent(arg->argKind) == akeMsgSeqno)
1195 		itCheckIntType(arg->argVarName, arg->argType);
1196 	/*
1197 	 * if the built-in are not used, we cannot match
1198 	 * the type/size of the desciption provided by the user
1199 	 * with the one defined in message.h.
1200 	 */
1201 	return (TRUE);
1202 }
1203 
1204 static void
rtCheckArgTypes(routine_t * rt)1205 rtCheckArgTypes(routine_t *rt)
1206 {
1207 	if (rt->rtRequestPort == argNULL)
1208 		error("%s %s doesn't have a server port argument",
1209 			  rtRoutineKindToStr(rt->rtKind), rt->rtName);
1210 
1211 	if ((rt->rtRequestPort != argNULL) &&
1212 		(rt->rtRequestPort->argType != itNULL))
1213 		itCheckRequestPortType(rt->rtRequestPort->argName,
1214 							   rt->rtRequestPort->argType);
1215 
1216 	if ((rt->rtReplyPort != argNULL) &&
1217 		(rt->rtReplyPort->argType != itNULL))
1218 		itCheckReplyPortType(rt->rtReplyPort->argName,
1219 							 rt->rtReplyPort->argType);
1220 
1221 	if ((rt->rtWaitTime != argNULL) &&
1222 		(rt->rtWaitTime->argType != itNULL))
1223 		itCheckIntType(rt->rtWaitTime->argName,
1224 					   rt->rtWaitTime->argType);
1225 
1226 	if ((rt->rtMsgOption != argNULL) &&
1227 		(rt->rtMsgOption->argType != itNULL))
1228 		itCheckIntType(rt->rtMsgOption->argName,
1229 					   rt->rtMsgOption->argType);
1230 
1231 	if ((IsKernelServer && rt->rtServerImpl) ||
1232 		(IsKernelUser   && rt->rtUserImpl))
1233 		fatal("Implicit data is not supported in the KernelUser and KernelServer modes");
1234 	/* rtCheckTrailerType will hit a fatal() if something goes wrong */
1235 	if (rt->rtServerImpl)
1236 		rtCheckMaskFunction(rt->rtArgs, akbServerImplicit, rtCheckTrailerType);
1237 	if (rt->rtUserImpl)
1238 		rtCheckMaskFunction(rt->rtArgs, akbUserImplicit, rtCheckTrailerType);
1239 }
1240 
1241 /*
1242  * Check for arguments which are missing seemingly needed functions.
1243  * We make this check here instead of in itCheckDecl, because here
1244  * we can take into account what kind of argument the type is
1245  * being used with.
1246  *
1247  * These are warnings, not hard errors, because mig will generate
1248  * reasonable code in any case.  The generated code will work fine
1249  * if the ServerType and TransType are really the same, even though
1250  * they have different names.
1251  */
1252 
1253 static void
rtCheckArgTrans(routine_t * rt)1254 rtCheckArgTrans(routine_t *rt)
1255 {
1256 	argument_t *arg;
1257 
1258 	/* the arg may not have a type (if there was some error in parsing it) */
1259 
1260     for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1261 		ipc_type_t *it = arg->argType;
1262 
1263 		if ((it != itNULL) && !streql(it->itServerType, it->itTransType)) {
1264 			if (akCheck(arg->argKind, akbSendRcv) && (it->itInTrans == strNULL))
1265 				warn("%s: argument has no in-translation function", arg->argName);
1266 
1267 			if (akCheck(arg->argKind, akbReturnSnd) && (it->itOutTrans == strNULL))
1268 				warn("%s: argument has no out-translation function", arg->argName);
1269 		}
1270 	}
1271 }
1272 
1273 /*
1274  * Adds an implicit return-code argument.  It exists in the reply message,
1275  * where it is the first piece of data (After the NDR format label)..
1276  */
1277 
1278 static void
rtAddRetCode(routine_t * rt)1279 rtAddRetCode(routine_t *rt)
1280 {
1281 	register argument_t *arg = argAlloc();
1282 
1283 	arg->argName = "RetCode";
1284 	arg->argType = itRetCodeType;
1285 	arg->argKind = akRetCode;
1286 	rt->rtRetCode = arg;
1287 
1288 	arg->argNext = rt->rtArgs;
1289 	rt->rtArgs = arg;
1290 }
1291 
1292 /*
1293  * Process the Return Code.
1294  * The MIG protocol says that RetCode != 0 are only sent through
1295  * mig_reply_error_t structures. Therefore, there is no need
1296  * for reserving a RetCode in a complex Reply message.
1297  */
1298 static void
rtProcessRetCode(routine_t * rt)1299 rtProcessRetCode(routine_t *rt)
1300 {
1301 
1302 	if (!rt->rtOneWay && !rt->rtSimpleReply) {
1303 		register argument_t *arg = rt->rtRetCode;
1304 
1305 		arg->argKind = akRemFeature(arg->argKind, akbReply);
1306 		/* we want the RetCode to be a local variable instead */
1307 		arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
1308 	}
1309 	if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
1310 		register argument_t *arg = rt->rtRetCArg;
1311 
1312 		arg->argKind = akeRetCode|akbUserArg|akbServerArg|akbSendRcv;
1313 	}
1314 }
1315 
1316 /*
1317  * Adds an implicit NDR argument.  It exists in the reply message,
1318  * where it is the first piece of data.
1319  */
1320 
1321 static void
rtAddNdrCode(routine_t * rt)1322 rtAddNdrCode(routine_t *rt)
1323 {
1324 	register argument_t *arg = argAlloc();
1325 
1326 	arg->argName = "NDR_record";
1327 	arg->argType = itNdrCodeType;
1328 	arg->argKind = akeNdrCode;
1329 	rt->rtNdrCode = arg;
1330 
1331 	/* add at beginning, so ndr-code is first in the reply message  */
1332 	arg->argNext = rt->rtArgs;
1333 	rt->rtArgs = arg;
1334 }
1335 
1336 /*
1337  * Process the NDR Code.
1338  * We stick a NDR format label iff there is untyped data
1339  */
1340 static void
rtProcessNdrCode(routine_t * rt)1341 rtProcessNdrCode(routine_t *rt)
1342 {
1343 	register argument_t *ndr = rt->rtNdrCode;
1344 	argument_t *arg;
1345 	boolean_t found;
1346 
1347 	/* akbSendSnd|akbSendBody initialize the NDR format label */
1348 #define ndr_send akbRequest|akbSend|akbSendSnd|akbSendBody
1349 	/* akbReplyInit initializes the NDR format label */
1350 #define ndr_rcv  akbReply|akbReplyInit|akbReturn|akbReturnBody
1351 
1352 	ndr->argKind = akAddFeature(ndr->argKind, ndr_send|ndr_rcv);
1353 
1354 	for (found = FALSE, arg = ndr->argNext; arg != argNULL; arg = arg->argNext)
1355 		if (akCheck(arg->argKind, akbSendRcv|akbSendBody) &&
1356 			!akCheck(arg->argKind, akbServerImplicit) && !arg->argType->itPortType &&
1357 			(!arg->argParent || akIdent(arg->argKind) == akeCount ||
1358 			 akIdent(arg->argKind) == akeCountInOut)) {
1359 			arg->argKind = akAddFeature(arg->argKind, akbSendNdr);
1360 			found = TRUE;
1361 		}
1362 	if (!found)
1363 		ndr->argKind = akRemFeature(ndr->argKind, ndr_send);
1364 
1365 	found = FALSE;
1366 	if (!rt->rtOneWay)
1367 		for (arg = ndr->argNext; arg != argNULL; arg = arg->argNext)
1368 			if ((arg == rt->rtRetCode && akCheck(arg->argKind, akbReply)) ||
1369 				(arg != rt->rtRetCode &&
1370 				 akCheck(arg->argKind, akbReturnRcv|akbReturnBody) &&
1371 				 !akCheck(arg->argKind, akbUserImplicit) && !arg->argType->itPortType &&
1372 				 (!arg->argParent || akIdent(arg->argKind) == akeCount ||
1373 				  akIdent(arg->argKind) == akeCountInOut))) {
1374 				arg->argKind = akAddFeature(arg->argKind, akbReturnNdr);
1375 				found = TRUE;
1376 			}
1377 	if (!found && !akCheck(rt->rtRetCode->argKind, akbReply))
1378 		ndr->argKind = akRemFeature(ndr->argKind, ndr_rcv);
1379 }
1380 
1381 /*
1382  *  Adds a dummy WaitTime argument to the function.
1383  *  This argument doesn't show up in any C argument lists;
1384  *  it implements the global WaitTime statement.
1385  */
1386 
1387 static void
rtAddWaitTime(routine_t * rt,identifier_t name,arg_kind_t kind)1388 rtAddWaitTime(routine_t *rt, identifier_t name, arg_kind_t kind)
1389 {
1390 	register argument_t *arg = argAlloc();
1391 	argument_t **loc;
1392 
1393 	arg->argName = "dummy WaitTime arg";
1394 	arg->argVarName = name;
1395 	arg->argType = itWaitTimeType;
1396 	arg->argKind = kind;
1397 	rt->rtWaitTime = arg;
1398 
1399 	/* add wait-time after msg-option, if possible */
1400 
1401 	if (rt->rtMsgOption != argNULL)
1402 		loc = &rt->rtMsgOption->argNext;
1403 	else
1404 		loc = &rt->rtArgs;
1405 
1406 	arg->argNext = *loc;
1407 	*loc = arg;
1408 
1409 	rtSetArgDefaults(rt, arg);
1410 }
1411 
1412 /*
1413  *  Adds a dummy MsgOption argument to the function.
1414  *  This argument doesn't show up in any C argument lists;
1415  *  it implements the global MsgOption statement.
1416  */
1417 
1418 static void
rtAddMsgOption(routine_t * rt,identifier_t name)1419 rtAddMsgOption(routine_t *rt, identifier_t name)
1420 {
1421 	register argument_t *arg = argAlloc();
1422 	argument_t **loc;
1423 
1424 	arg->argName = "dummy MsgOption arg";
1425 	arg->argVarName = name;
1426 	arg->argType = itMsgOptionType;
1427 	arg->argKind = akeMsgOption;
1428 	rt->rtMsgOption = arg;
1429 
1430 	/* add msg-option after msg-seqno */
1431 
1432 	loc = &rt->rtArgs;
1433 
1434 	arg->argNext = *loc;
1435 	*loc = arg;
1436 
1437 	rtSetArgDefaults(rt, arg);
1438 }
1439 
1440 /*
1441  * Process the MsgOption Code.
1442  * We must add the information to post a receive with the right
1443  * Trailer options.
1444  */
1445 static void
rtProcessMsgOption(routine_t * rt)1446 rtProcessMsgOption(routine_t *rt)
1447 {
1448 	register argument_t *msgop = rt->rtMsgOption;
1449 	register argument_t *arg;
1450 	boolean_t sectoken = FALSE;
1451 	boolean_t audittoken = FALSE;
1452 	boolean_t contexttoken = FALSE;
1453 
1454 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
1455 		if (akCheckAll(arg->argKind, akbReturn|akbUserImplicit)) {
1456 			if (akIdent(arg->argKind) == akeSecToken)
1457 				sectoken = TRUE;
1458 			else if (akIdent(arg->argKind) == akeAuditToken)
1459 				audittoken = TRUE;
1460 			else if (akIdent(arg->argKind) == akeContextToken)
1461 				contexttoken = TRUE;
1462 		}
1463 
1464 	if (contexttoken == TRUE)
1465 		msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX)");
1466 	else if (audittoken == TRUE)
1467 		msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)");
1468 	else if (sectoken == TRUE)
1469 		msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)");
1470 	/* other implicit data received by the user will be handled here */
1471 }
1472 
1473 
1474 /*
1475  *  Adds a dummy reply port argument to the function.
1476  */
1477 
1478 static void
rtAddDummyReplyPort(routine_t * rt,ipc_type_t * type)1479 rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type)
1480 {
1481 	register argument_t *arg = argAlloc();
1482 	argument_t **loc;
1483 
1484 	arg->argName = "dummy ReplyPort arg";
1485 	arg->argVarName = "dummy ReplyPort arg";
1486 	arg->argType = type;
1487 	arg->argKind = akeReplyPort;
1488 	rt->rtReplyPort = arg;
1489 
1490 	/* add the reply port after the request port */
1491 
1492 	if (rt->rtRequestPort != argNULL)
1493 		loc = &rt->rtRequestPort->argNext;
1494 	else
1495 		loc = &rt->rtArgs;
1496 
1497 	arg->argNext = *loc;
1498 	*loc = arg;
1499 
1500 	rtSetArgDefaults(rt, arg);
1501 }
1502 
1503 
1504 /*
1505  * At least one overwrite keyword has been detected:
1506  * we tag all the OOL entries (ports + data) with
1507  * akbOverwrite which will tell us that we have to
1508  * fill a KPD entry in the message-template
1509  */
1510 static void
rtCheckOverwrite(register routine_t * rt)1511 rtCheckOverwrite(register routine_t *rt)
1512 {
1513 	register argument_t *arg;
1514 	register int howmany = rt->rtOverwrite;
1515 
1516 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1517 		register ipc_type_t *it = arg->argType;
1518 
1519 		if (akCheck(arg->argKind, akbReturnKPD) && !it->itInLine) {
1520 			/* among OUT args, we want OOL, OOL ports and MigInLine */
1521 			arg->argKind = akAddFeature(arg->argKind, akbOverwrite);
1522 			if (arg->argFlags & flOverwrite)
1523 				howmany--;
1524 			if (!howmany)
1525 				return;
1526 		}
1527 	}
1528 }
1529 
1530 /*
1531  * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos,
1532  * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments
1533  * that need it because of variable-sized inline considerations.
1534  *
1535  * argRequestPos and argReplyPos get -1 if the value shouldn't be used.
1536  */
1537 static void
rtCheckVariable(register routine_t * rt)1538 rtCheckVariable(register routine_t *rt)
1539 {
1540 	register argument_t *arg;
1541 	int NumRequestVar = 0;
1542 	int NumReplyVar = 0;
1543 	int MaxRequestPos = 0;
1544 	int MaxReplyPos = 0;
1545 
1546 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1547 		register argument_t *parent = arg->argParent;
1548 
1549 		/*
1550 		 * We skip KPDs. We have to make sure that the KPDs count
1551 		 * present in the message body follow the RequestPos/ReplyPos logic
1552 		 * The rest of the parameters are defaulted to have
1553 		 * Arg{Request, Reply}Pos = 0
1554 		 */
1555 		if (parent == argNULL || akCheck(parent->argKind, akbSendKPD|akbReturnKPD)) {
1556 			if (akCheckAll(arg->argKind, akbSend|akbSendBody)) {
1557 				arg->argRequestPos = NumRequestVar;
1558 				MaxRequestPos = NumRequestVar;
1559 				if (akCheck(arg->argKind, akbVariable))
1560 					NumRequestVar++;
1561 			}
1562 			if (akCheckAll(arg->argKind, akbReturn|akbReturnBody)) {
1563 				arg->argReplyPos = NumReplyVar;
1564 				MaxReplyPos = NumReplyVar;
1565 				if (akCheck(arg->argKind, akbVariable))
1566 					NumReplyVar++;
1567 			}
1568 		} else {
1569 			arg->argRequestPos = parent->argRequestPos;
1570 			arg->argReplyPos = parent->argReplyPos;
1571 		}
1572 		/*
1573 		  printf("Var %s Kind %x RequestPos %d\n", arg->argVarName, arg->argKind, arg->argRequestPos);
1574 		  printf("* Var %s Kind %x ReplyPos %d\n", arg->argVarName, arg->argKind, arg->argReplyPos);
1575 		*/
1576 
1577 		/* Out variables that follow a variable-sized field
1578 		   need VarNeeded or ReplyCopy; they can't be stored
1579 		   directly into the reply message. */
1580 
1581 		if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody) &&
1582 			!akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) &&
1583 			(arg->argReplyPos > 0))
1584 			arg->argKind = akAddFeature(arg->argKind, akbVarNeeded);
1585 	}
1586 
1587 	rt->rtNumRequestVar = NumRequestVar;
1588 	rt->rtNumReplyVar = NumReplyVar;
1589 	rt->rtMaxRequestPos = MaxRequestPos;
1590 	rt->rtMaxReplyPos = MaxReplyPos;
1591 }
1592 
1593 /*
1594  * Adds akbDestroy where needed.
1595  */
1596 
1597 static void
rtCheckDestroy(register routine_t * rt)1598 rtCheckDestroy(register routine_t *rt)
1599 {
1600 	register argument_t *arg;
1601 
1602 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1603 		register ipc_type_t *it = arg->argType;
1604 
1605 		if(akCheck(arg->argKind, akbSendRcv) &&
1606 		   !akCheck(arg->argKind, akbReturnSnd) &&
1607 		   (it->itDestructor != strNULL || IS_MIG_INLINE_EMUL(it))) {
1608 			arg->argKind = akAddFeature(arg->argKind, akbDestroy);
1609 		}
1610 		if (argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
1611 			arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR &&
1612 			(arg->argFlags & flAuto))
1613 			arg->argKind = akAddFeature(arg->argKind, akbDestroy);
1614 	}
1615 }
1616 
1617 /*
1618  * Sets ByReferenceUser and ByReferenceServer.
1619  */
1620 
1621 static void
rtAddByReference(register routine_t * rt)1622 rtAddByReference(register routine_t *rt)
1623 {
1624 	register argument_t *arg;
1625 
1626 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1627 		register ipc_type_t *it = arg->argType;
1628 
1629 		if (akCheck(arg->argKind, akbReturnRcv) && it->itStruct) {
1630 			arg->argByReferenceUser = TRUE;
1631 
1632 			/*
1633 			 *  A CountInOut arg itself is not akbReturnRcv,
1634 			 *  so we need to set argByReferenceUser specially.
1635 			 */
1636 
1637 			if (arg->argCInOut != argNULL)
1638 				arg->argCInOut->argByReferenceUser = TRUE;
1639 		}
1640 
1641 		if ((akCheck(arg->argKind, akbReturnSnd) ||
1642 			(akCheck(arg->argKind, akbServerImplicit) &&
1643 			 akCheck(arg->argKind, akbReturnRcv) &&
1644 			 akCheck(arg->argKind, akbSendRcv)))
1645 			&& it->itStruct) {
1646 			arg->argByReferenceServer = TRUE;
1647 		}
1648 	}
1649 }
1650 
1651 /*
1652  * This procedure can be executed only when all the akb* and ake* have
1653  * been set properly (when rtAddCountArg is executed, akbVarNeeded
1654  * might not be set yet - see rtCheckVariable)
1655  */
1656 static void
rtAddSameCount(register routine_t * rt)1657 rtAddSameCount(register routine_t *rt)
1658 {
1659 	register argument_t *arg;
1660 
1661 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
1662 		if (arg->argFlags & flSameCount) {
1663 			register ipc_type_t *it = arg->argType;
1664 			register argument_t *tmp_count;
1665 			register argument_t *my_count = arg->argCount;
1666 			register argument_t *ref_count = arg->argSameCount->argCount;
1667 
1668 			tmp_count = argAlloc();
1669 			*tmp_count = *ref_count;
1670 			/*
1671 			 * if our count is a akbVarNeeded, we need to copy this
1672 			 * attribute to the master count!
1673 			 */
1674 			tmp_count->argKind = akeSameCount;
1675 			ref_count->argKind = akAddFeature(ref_count->argKind, akCheck(my_count->argKind, akbVarNeeded));
1676 			tmp_count->argKind = akAddFeature(tmp_count->argKind, akCheck(my_count->argKind, akbVarNeeded));
1677 			tmp_count->argNext = my_count->argNext;
1678 			tmp_count->argMultiplier = my_count->argMultiplier;
1679 			tmp_count->argType = my_count->argType;
1680 			tmp_count->argParent = arg;
1681 			/* we don't need more */
1682 			arg->argCount = tmp_count;
1683 			arg->argNext = tmp_count;
1684 			/* for these args, Cnt is not akbRequest, and therefore size is embedded */
1685 			if (IS_VARIABLE_SIZED_UNTYPED(it))
1686 				it->itMinTypeSize = 0;
1687 			tmp_count->argType->itMinTypeSize = 0;
1688 			tmp_count->argType->itTypeSize = 0;
1689 		}
1690 }
1691 
1692 void
rtCheckRoutine(register routine_t * rt)1693 rtCheckRoutine(register routine_t *rt)
1694 {
1695 	/* Initialize random fields. */
1696 
1697 	rt->rtErrorName = ErrorProc;
1698 	rt->rtOneWay = (rt->rtKind == rkSimpleRoutine);
1699 	rt->rtServerName = strconcat(ServerPrefix, rt->rtName);
1700 	rt->rtUserName = strconcat(UserPrefix, rt->rtName);
1701 
1702 	/* Add implicit arguments. */
1703 
1704 	rtAddRetCode(rt);
1705 	rtAddNdrCode(rt);
1706 
1707 	/* Check out the arguments and their types.  Add count, poly
1708 	   implicit args.  Any arguments added after rtCheckRoutineArgs
1709 	   should have rtSetArgDefaults called on them. */
1710 
1711 	rtCheckRoutineArgs(rt);
1712 
1713 	/* Add dummy WaitTime and MsgOption arguments, if the routine
1714 	   doesn't have its own args and the user specified global values. */
1715 
1716 	if (rt->rtReplyPort == argNULL) {
1717 		if (rt->rtOneWay)
1718 			rtAddDummyReplyPort(rt, itZeroReplyPortType);
1719 		else
1720 			rtAddDummyReplyPort(rt, itRealReplyPortType);
1721 	}
1722 	if (rt->rtMsgOption == argNULL) {
1723 		if (MsgOption == strNULL)
1724 			rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE");
1725 		else
1726 			rtAddMsgOption(rt, MsgOption);
1727 	}
1728 	if (rt->rtWaitTime == argNULL) {
1729 		if (WaitTime != strNULL)
1730 			rtAddWaitTime(rt, WaitTime, akeWaitTime);
1731 		else if (SendTime != strNULL)
1732 			rtAddWaitTime(rt, SendTime, akeSendTime);
1733 	}
1734 
1735 
1736 	/* Now that all the arguments are in place, do more checking. */
1737 
1738 	rtCheckArgTypes(rt);
1739 	rtCheckArgTrans(rt);
1740 
1741     if (rt->rtOneWay &&
1742     	(rtCheckMask(rt->rtArgs, akbReturn) || rt->rtUserImpl))
1743 		error("%s %s has OUT argument",
1744 			  rtRoutineKindToStr(rt->rtKind), rt->rtName);
1745 
1746 	/* If there were any errors, don't bother calculating more info
1747 	   that is only used in code generation anyway.  Therefore,
1748 	   the following functions don't have to worry about null types. */
1749 
1750     if (errors > 0)
1751         fatal("%d errors found. Abort.\n", errors);
1752 
1753 	rt->rtServerImpl  = rtCountMask(rt->rtArgs, akbServerImplicit);
1754 	rt->rtUserImpl = rtCountMask(rt->rtArgs, akbUserImplicit);
1755 	/*
1756 	 * ASSUMPTION:
1757 	 * kernel cannot change a message from simple to complex,
1758 	 * therefore SimpleSendReply and SimpleRcvReply become SimpleReply
1759 	 */
1760 #ifdef notyet
1761 	/* Setting this to true causes MIG to generate incorrect code */
1762 	rtCheckSimple(rt->rtArgs, akbRequest, &rt->rtSimpleRequest);
1763 #endif
1764 	rtCheckSimple(rt->rtArgs, akbReply, &rt->rtSimpleReply);
1765 
1766 	rt->rtRequestKPDs = rtCountKPDs(rt->rtArgs, akbSendKPD);
1767 	rt->rtReplyKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD);
1768 	/*
1769 	 * Determine how many overwrite parameters we have:
1770 	 *  # of Overwrite args -> rt->rtOverwrite
1771 	 *  flOverwrite -> the arg has to be overwritten
1772 	 *  akbOverwrite -> the arg has to be declared in the message-template
1773 	 *  (only as a placeholder if !flOverwrite).
1774 	 */
1775 	if ((rt->rtOverwrite = rtCountFlags(rt->rtArgs, flOverwrite))) {
1776 		rtCheckOverwrite(rt);
1777 		rt->rtOverwriteKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD|akbOverwrite);
1778 		if (IsKernelUser)
1779 			fatal("Overwrite option(s) do not match with the KernelUser personality\n");
1780 	}
1781 
1782     rtCheckFit(rt, akbRequest, &rt->rtRequestFits, &rt->rtRequestUsedLimit, &rt->rtRequestSizeKnown);
1783     rtCheckFit(rt, akbReply, &rt->rtReplyFits, &rt->rtReplyUsedLimit, &rt->rtReplySizeKnown);
1784 
1785 	rtCheckVariable(rt);
1786 	rtCheckDestroy(rt);
1787 	rtAddByReference(rt);
1788 	rtSuffixExtArg(rt->rtArgs);
1789 	rtAddSameCount(rt);
1790 	rtProcessRetCode(rt);
1791 	rtProcessNdrCode(rt);
1792 	if (rt->rtUserImpl)
1793 		rtProcessMsgOption(rt);
1794 
1795 	rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd);
1796 
1797 	if (UseEventLogger)
1798 		/* some more info's are needed for Event logging/Stats */
1799 		rtFindHowMany(rt);
1800 }
1801 
1802 void
rtMinRequestSize(FILE * file,routine_t * rt,const char * str)1803 rtMinRequestSize(FILE *file, routine_t *rt, const char *str)
1804 {
1805     fprintf(file, "(sizeof(%s)", str);
1806 	rtSizeDelta(file, akbRequest, rt);
1807 	fprintf(file, ")");
1808 }
1809 
1810 void
rtMinReplySize(FILE * file,routine_t * rt,const char * str)1811 rtMinReplySize(FILE *file, routine_t *rt, const char *str)
1812 {
1813     fprintf(file, "(sizeof(%s)", str);
1814 	rtSizeDelta(file, akbReply, rt);
1815 	fprintf(file, ")");
1816 }
1817 
1818 static void
rtSizeDelta(FILE * file,u_int mask,routine_t * rt)1819 rtSizeDelta(FILE *file, u_int mask, routine_t *rt)
1820 {
1821 	argument_t *arg;
1822 	u_int min_size = sizeof(mach_msg_header_t);
1823 	u_int max_size;
1824 	boolean_t output = FALSE;
1825 
1826 	if (!rt->rtSimpleRequest)
1827 		machine_alignment(min_size, sizeof(mach_msg_body_t));
1828 	max_size = min_size;
1829 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
1830 		if (akCheck(arg->argKind, mask)) {
1831 			register ipc_type_t *it = arg->argType;
1832 
1833 			machine_alignment(min_size, it->itMinTypeSize);
1834 			machine_alignment(max_size, it->itMinTypeSize);
1835 
1836 			if (IS_VARIABLE_SIZED_UNTYPED(it)) {
1837 				machine_alignment(max_size, it->itTypeSize);
1838 				max_size += it->itPadSize;
1839 			}
1840 			if (IS_OPTIONAL_NATIVE(it)) {
1841 				if (output)
1842 					fprintf(file, " + ");
1843 				else {
1844 					output = TRUE;
1845 					fprintf(file, " - (");
1846 				}
1847 				fprintf(file, "_WALIGNSZ_(%s)", it->itUserType);
1848 			}
1849 		}
1850 	if (min_size != max_size) {
1851 		if (output)
1852 			fprintf(file, " + ");
1853 		else
1854 			fprintf(file, " - ");
1855 		fprintf(file, "%d", max_size - min_size);
1856 	}
1857 	if (output)
1858 		fprintf(file, ")");
1859 }
1860 
1861