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