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