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