1/*
2 * Copyright (c) 1999-2009 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 * @OSF_COPYRIGHT@
25 */
26/*
27 * Mach Operating System
28 * Copyright (c) 1991,1990 Carnegie Mellon University
29 * All Rights Reserved.
30 *
31 * Permission to use, copy, modify and distribute this software and its
32 * documentation is hereby granted, provided that both the copyright
33 * notice and this permission notice appear in all copies of the
34 * software, derivative works or modified versions, and any portions
35 * thereof, and that both notices appear in supporting documentation.
36 *
37 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
38 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
39 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
40 *
41 * Carnegie Mellon requests users of this software to return to
42 *
43 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
44 *  School of Computer Science
45 *  Carnegie Mellon University
46 *  Pittsburgh PA 15213-3890
47 *
48 * any improvements or extensions that they make and grant Carnegie Mellon
49 * the rights to redistribute these changes.
50 */
51
52#include <assert.h>
53#include <stdlib.h>
54
55#include <mach/message.h>
56#include "write.h"
57#include "utils.h"
58#include "global.h"
59#include "error.h"
60
61#ifndef max
62#define max(a,b) (((a) > (b)) ? (a) : (b))
63#endif  /* max */
64
65void WriteLogDefines();
66void WriteIdentificationString();
67static void WriteFieldDecl();
68
69static void
70WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t varying, argument_t *arg, boolean_t bracket)
71{
72  register ipc_type_t *it = arg->argType;
73  char string[MAX_STR_LEN];
74
75  fprintf(file, "\t{\n");
76  fprintf(file, "\t    register\t%s\t*ptr;\n", it->itKPDType);
77  fprintf(file, "\t    register int\ti");
78  if (varying && !in)
79    fprintf(file, ", j");
80  fprintf(file, ";\n\n");
81
82  if (in)
83    sprintf(string, "In%dP", arg->argRequestPos);
84  else
85    sprintf(string, "OutP");
86
87  fprintf(file, "\t    ptr = &%s->%s[0];\n", string, arg->argMsgField);
88
89  if (varying) {
90    register argument_t *count = arg->argCount;
91
92    if (in)
93      fprintf(file, "\t    for (i = 0; i < In%dP->%s; ptr++, i++) %s\n", count->argRequestPos, count->argMsgField, (bracket) ? "{" : "");
94    else {
95      fprintf(file, "\t    j = min(%d, ", it->itKPD_Number);
96      if (akCheck(count->argKind, akbVarNeeded))
97        fprintf(file, "%s);\n", count->argName);
98      else
99        fprintf(file, "%s->%s);\n", string, count->argMsgField);
100      fprintf(file, "\t    for (i = 0; i < j; ptr++, i++) %s\n", (bracket) ? "{" : "");
101    }
102}
103  else
104    fprintf(file, "\t    for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : "");
105}
106
107static void
108WriteMyIncludes(FILE *file, statement_t *stats)
109{
110  if (ServerHeaderFileName == strNULL || UseSplitHeaders)
111    WriteIncludes(file, FALSE, FALSE);
112  if (ServerHeaderFileName != strNULL)
113  {
114    register char *cp;
115
116    /* Strip any leading path from ServerHeaderFileName. */
117    cp = strrchr(ServerHeaderFileName, '/');
118    if (cp == 0)
119      cp = ServerHeaderFileName;
120    else
121      cp++;       /* skip '/' */
122    fprintf(file, "#include \"%s\"\n", cp);
123  }
124  if (ServerHeaderFileName == strNULL || UseSplitHeaders)
125    WriteImplImports(file, stats, FALSE);
126  if (UseEventLogger) {
127    if (IsKernelServer) {
128      fprintf(file, "#if\t__MigKernelSpecificCode\n");
129      fprintf(file, "#include <mig_debug.h>\n");
130      fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
131    }
132    fprintf(file, "#if  MIG_DEBUG\n");
133    fprintf(file, "#include <mach/mig_log.h>\n");
134    fprintf(file, "#endif /* MIG_DEBUG */\n");
135  }
136
137  fprintf(file, "\n");
138}
139
140static void
141WriteGlobalDecls(FILE *file)
142{
143  if (BeAnsiC) {
144    fprintf(file, "#define novalue void\n");
145  }
146  else {
147    fprintf(file, "#if\t%s\n", NewCDecl);
148    fprintf(file, "#define novalue void\n");
149    fprintf(file, "#else\n");
150    fprintf(file, "#define novalue int\n");
151    fprintf(file, "#endif\t/* %s */\n", NewCDecl);
152  }
153  fprintf(file, "\n");
154
155  if (RCSId != strNULL)
156    WriteRCSDecl(file, strconcat(SubsystemName, "_server"), RCSId);
157
158  /* Used for locations in the request message, *not* reply message.
159   Reply message locations aren't dependent on IsKernelServer. */
160
161  if (IsKernelServer) {
162    fprintf(file, "#if\t__MigKernelSpecificCode\n");
163    fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
164    fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
165    fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
166    fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
167    fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
168    fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
169    fprintf(file, "#else\n");
170  }
171  fprintf(file, "#define msgh_request_port\tmsgh_local_port\n");
172  fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
173  fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
174  fprintf(file, "#define msgh_reply_port\t\tmsgh_remote_port\n");
175  fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
176  fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
177  if (IsKernelServer) {
178    fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
179  }
180  fprintf(file, "\n");
181  if (UseEventLogger)
182    WriteLogDefines(file, "MACH_MSG_LOG_SERVER");
183  fprintf(file, "#define MIG_RETURN_ERROR(X, code)\t{\\\n");
184  fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->RetCode = code;\\\n");
185  fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->NDR = NDR_record;\\\n");
186  fprintf(file, "\t\t\t\treturn;\\\n");
187  fprintf(file, "\t\t\t\t}\n");
188  fprintf(file, "\n");
189}
190
191
192static void
193WriteForwardDeclarations(FILE *file, statement_t *stats)
194{
195  register statement_t *stat;
196
197  fprintf(file, "/* Forward Declarations */\n\n");
198  for (stat = stats; stat != stNULL; stat = stat->stNext)
199    if (stat->stKind == skRoutine) {
200      fprintf(file, "\nmig_internal novalue _X%s\n", stat->stRoutine->rtName);
201      fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);\n");
202    }
203  fprintf(file, "\n");
204}
205
206static void
207WriteMIGCheckDefines(FILE *file)
208{
209   fprintf(file, "#define\t__MIG_check__Request__%s_subsystem__ 1\n", SubsystemName);
210   fprintf(file, "\n");
211}
212
213static void
214WriteNDRDefines(FILE *file)
215{
216   fprintf(file, "#define\t__NDR_convert__Request__%s_subsystem__ 1\n", SubsystemName);
217   fprintf(file, "\n");
218}
219
220static void
221WriteProlog(FILE *file, statement_t *stats)
222{
223  WriteIdentificationString(file);
224  fprintf(file, "\n");
225  fprintf(file, "/* Module %s */\n", SubsystemName);
226  fprintf(file, "\n");
227  WriteMIGCheckDefines(file);
228  if (CheckNDR)
229	  WriteNDRDefines(file);
230  WriteMyIncludes(file, stats);
231  WriteBogusDefines(file);
232  WriteApplDefaults(file, "Rcv");
233  WriteGlobalDecls(file);
234  if (ServerHeaderFileName == strNULL) {
235    WriteRequestTypes(file, stats);
236    WriteReplyTypes(file, stats);
237    WriteServerReplyUnion(file, stats);
238  }
239}
240
241static void
242WriteSymTabEntries(FILE *file, statement_t *stats)
243{
244  register statement_t *stat;
245  register u_int current = 0;
246
247  for (stat = stats; stat != stNULL; stat = stat->stNext)
248    if (stat->stKind == skRoutine) {
249      register  int num = stat->stRoutine->rtNumber;
250      char  *name = stat->stRoutine->rtName;
251      while (++current <= num)
252        fprintf(file,"\t\t\t{ \"\", 0, 0 },\n");
253      fprintf(file, "\t{ \"%s\", %d, _X%s },\n", name, SubsystemBase + current - 1, name);
254    }
255  while (++current <= rtNumber)
256    fprintf(file,"\t{ \"\", 0, 0 },\n");
257}
258
259static void
260WriteRoutineEntries(FILE *file, statement_t *stats)
261{
262  register u_int current = 0;
263  register statement_t *stat;
264  char *sig_array, *rt_name;
265  int arg_count, descr_count;
266  int offset = 0;
267  size_t serverSubsysNameLen = strlen(ServerSubsys);
268
269  fprintf(file, "\t{\n");
270  for (stat = stats; stat != stNULL; stat = stat->stNext)
271    if (stat->stKind == skRoutine) {
272      register  routine_t *rt = stat->stRoutine;
273      size_t       rtNameLen = strlen(rt->rtName);
274
275      // Include length of rt->rtName in calculation of necessary buffer size, since that string
276      // is actually written into the buffer along with the Server Subsystem name.
277      sig_array = (char *) malloc(serverSubsysNameLen + rtNameLen + 80);
278      rt_name = (char *) malloc(rtNameLen + 5);
279      while (current++ < rt->rtNumber)
280        fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n");
281      // NOTE: if either of the two string constants in the sprintf() function calls below get
282      // much longer, be sure to increase the constant '80' (in the first malloc() call) to ensure
283      // that the allocated buffer is large enough. (Currently, I count 66 characters in the first
284      // string constant, 65 in the second. 80 ought to be enough for now...)
285      if (UseRPCTrap) {
286        sprintf(sig_array, "&%s.arg_descriptor[%d], (mach_msg_size_t)sizeof(__Reply__%s_t)", ServerSubsys, offset, rt->rtName);
287      }
288      else {
289        sprintf(sig_array, "(routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__%s_t)", rt->rtName);
290      }
291      sprintf(rt_name, "_X%s", rt->rtName);
292      descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count);
293      offset += descr_count;
294      WriteRPCRoutineDescriptor(file, rt, arg_count, (UseRPCTrap) ? descr_count : 0, rt_name, sig_array);
295      fprintf(file, ",\n");
296      free(sig_array);
297      free(rt_name);
298    }
299  while (current++ < rtNumber)
300    fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n");
301
302  fprintf(file, "\t}");
303}
304
305static void
306WriteArgDescriptorEntries(FILE *file, statement_t *stats)
307{
308  register statement_t *stat;
309
310  fprintf(file, ",\n\n\t{\n");
311  for (stat = stats; stat != stNULL; stat = stat->stNext)
312    if (stat->stKind == skRoutine) {
313      register routine_t *rt = stat->stRoutine;
314
315      /* For each arg of the routine, write an arg descriptor:
316       */
317      WriteRPCRoutineArgDescriptor(file, rt);
318    }
319  fprintf(file, "\t},\n\n");
320}
321
322
323/*
324 * Write out the description of this subsystem, for use in direct RPC
325 */
326static void
327WriteSubsystem(FILE *file, statement_t *stats)
328{
329  register statement_t *stat;
330  int descr_count = 0;
331
332  for (stat = stats; stat != stNULL; stat = stat->stNext)
333    if (stat->stKind == skRoutine) {
334      register routine_t *rt = stat->stRoutine;
335      descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0);
336    }
337  fprintf(file, "\n");
338  if (ServerHeaderFileName == strNULL) {
339    WriteMigExternal(file);
340    fprintf(file, "boolean_t %s(", ServerDemux);
341    if (BeAnsiC) {
342      fprintf(file, "\n\t\tmach_msg_header_t *InHeadP,");
343      fprintf(file, "\n\t\tmach_msg_header_t *OutHeadP");
344    }
345    fprintf(file, ");\n\n");
346
347    WriteMigExternal(file);
348    fprintf(file, "mig_routine_t %s_routine(", ServerDemux);
349    if (BeAnsiC) {
350      fprintf(file, "\n\t\tmach_msg_header_t *InHeadP");
351    }
352    fprintf(file, ");\n\n");
353  }
354  fprintf(file, "\n/* Description of this subsystem, for use in direct RPC */\n");
355  if (ServerHeaderFileName == strNULL) {
356    fprintf(file, "const struct %s {\n", ServerSubsys);
357    if (UseRPCTrap) {
358      fprintf(file, "\tstruct subsystem *\tsubsystem;\t/* Reserved for system use */\n");
359    }
360    else {
361      fprintf(file, "\tmig_server_routine_t \tserver;\t/* Server routine */\n");
362    }
363    fprintf(file, "\tmach_msg_id_t\tstart;\t/* Min routine number */\n");
364    fprintf(file, "\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n");
365    fprintf(file, "\tunsigned int\tmaxsize;\t/* Max msg size */\n");
366    if (UseRPCTrap) {
367      fprintf(file, "\tvm_address_t\tbase_addr;\t/* Base address */\n");
368      fprintf(file, "\tstruct rpc_routine_descriptor\t/*Array of routine descriptors */\n");
369    }
370    else {
371      fprintf(file, "\tvm_address_t\treserved;\t/* Reserved */\n");
372      fprintf(file, "\tstruct routine_descriptor\t/*Array of routine descriptors */\n");
373    }
374    fprintf(file, "\t\troutine[%d];\n", rtNumber);
375    if (UseRPCTrap) {
376      fprintf(file, "\tstruct rpc_routine_arg_descriptor\t/*Array of arg descriptors */\n");
377      fprintf(file, "\t\targ_descriptor[%d];\n", descr_count);
378    }
379    fprintf(file, "} %s = {\n", ServerSubsys);
380  }
381  else {
382    fprintf(file, "const struct %s %s = {\n", ServerSubsys, ServerSubsys);
383  }
384  if (UseRPCTrap) {
385    fprintf(file, "\t0,\n");
386  }
387  else {
388    fprintf(file, "\t%s_routine,\n", ServerDemux);
389  }
390  fprintf(file, "\t%d,\n", SubsystemBase);
391  fprintf(file, "\t%d,\n", SubsystemBase + rtNumber);
392  fprintf(file, "\t(mach_msg_size_t)sizeof(union __ReplyUnion__%s),\n", ServerSubsys);
393  if (UseRPCTrap) {
394    fprintf(file, "\t(vm_address_t)&%s,\n", ServerSubsys);
395  }
396  else {
397    fprintf(file, "\t(vm_address_t)0,\n");
398  }
399  WriteRoutineEntries(file, stats);
400
401  if (UseRPCTrap)
402    WriteArgDescriptorEntries(file, stats);
403  else
404    fprintf(file, "\n");
405
406  fprintf(file, "};\n\n");
407}
408
409#if NOT_CURRENTLY_USED
410
411static void
412WriteArraySizes(FILE *file, statement_t *stats)
413{
414  register u_int current = 0;
415  register statement_t *stat;
416
417  for (stat = stats; stat != stNULL; stat = stat->stNext)
418    if (stat->stKind == skRoutine) {
419      register routine_t *rt = stat->stRoutine;
420
421      while (current++ < rt->rtNumber)
422        fprintf(file, "\t\t0,\n");
423      fprintf(file, "\t\t(mach_msg_size_t)sizeof(__Reply__%s_t),\n", rt->rtName);
424    }
425  while (current++ < rtNumber)
426    fprintf(file, "\t\t\t0,\n");
427}
428
429#endif /* NOT_CURRENTLY_USED */
430
431void
432WriteServerRequestUnion(FILE *file, statement_t *stats)
433{
434  register statement_t *stat;
435
436  fprintf(file, "\n");
437  fprintf(file, "/* union of all requests */\n\n");
438  fprintf(file, "#ifndef __RequestUnion__%s__defined\n", ServerSubsys);
439  fprintf(file, "#define __RequestUnion__%s__defined\n", ServerSubsys);
440  fprintf(file, "union __RequestUnion__%s {\n", ServerSubsys);
441  for (stat = stats; stat != stNULL; stat = stat->stNext) {
442    if (stat->stKind == skRoutine) {
443      register routine_t *rt;
444
445      rt = stat->stRoutine;
446      fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtName);
447    }
448  }
449  fprintf(file, "};\n");
450  fprintf(file, "#endif /* __RequestUnion__%s__defined */\n", ServerSubsys);
451}
452
453void
454WriteServerReplyUnion(FILE *file, statement_t *stats)
455{
456  register statement_t *stat;
457
458  fprintf(file, "\n");
459  fprintf(file, "/* union of all replies */\n\n");
460  fprintf(file, "#ifndef __ReplyUnion__%s__defined\n", ServerSubsys);
461  fprintf(file, "#define __ReplyUnion__%s__defined\n", ServerSubsys);
462  fprintf(file, "union __ReplyUnion__%s {\n", ServerSubsys);
463  for (stat = stats; stat != stNULL; stat = stat->stNext) {
464    if (stat->stKind == skRoutine) {
465      register routine_t *rt;
466
467      rt = stat->stRoutine;
468      fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtName);
469    }
470  }
471  fprintf(file, "};\n");
472  fprintf(file, "#endif /* __RequestUnion__%s__defined */\n", ServerSubsys);
473}
474
475static void
476WriteDispatcher(FILE *file, statement_t *stats)
477{
478  /*
479   * Write the subsystem stuff.
480   */
481  fprintf(file, "\n");
482  WriteSubsystem(file, stats);
483
484  /*
485   * Then, the server routine
486   */
487  fprintf(file, "mig_external boolean_t %s\n", ServerDemux);
488  if (BeAnsiC) {
489    fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
490  }
491  else {
492    fprintf(file, "#if\t%s\n", NewCDecl);
493    fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
494    fprintf(file, "#else\n");
495    fprintf(file, "\t(InHeadP, OutHeadP)\n");
496    fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
497    fprintf(file, "#endif\t/* %s */\n", NewCDecl);
498  }
499
500  fprintf(file, "{\n");
501  fprintf(file, "\t/*\n");
502  fprintf(file, "\t * typedef struct {\n");
503  fprintf(file, "\t * \tmach_msg_header_t Head;\n");
504  fprintf(file, "\t * \tNDR_record_t NDR;\n");
505  fprintf(file, "\t * \tkern_return_t RetCode;\n");
506  fprintf(file, "\t * } mig_reply_error_t;\n");
507  fprintf(file, "\t */\n");
508  fprintf(file, "\n");
509
510  fprintf(file, "\tregister mig_routine_t routine;\n");
511  fprintf(file, "\n");
512
513  fprintf(file, "\tOutHeadP->msgh_bits = ");
514  fprintf(file, "MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);\n");
515  fprintf(file, "\tOutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;\n");
516  fprintf(file, "\t/* Minimal size: routine() will update it if different */\n");
517  fprintf(file, "\tOutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);\n");
518  fprintf(file, "\tOutHeadP->msgh_local_port = MACH_PORT_NULL;\n");
519  fprintf(file, "\tOutHeadP->msgh_id = InHeadP->msgh_id + 100;\n");
520  fprintf(file, "\n");
521
522  fprintf(file, "\tif ((InHeadP->msgh_id > %d) || (InHeadP->msgh_id < %d) ||\n", SubsystemBase + rtNumber - 1, SubsystemBase);
523  fprintf(file, "\t    ((routine = %s.routine[InHeadP->msgh_id - %d].stub_routine) == 0)) {\n", ServerSubsys, SubsystemBase);
524  fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;\n");
525  fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;\n");
526  if (UseEventLogger) {
527    fprintf(file, "#if  MIG_DEBUG\n");
528    fprintf(file, "\t\tLOG_ERRORS(MACH_MSG_LOG_SERVER, MACH_MSG_ERROR_UNKNOWN_ID,\n");
529    fprintf(file, "\t\t\t&InHeadP->msgh_id, __FILE__, __LINE__);\n");
530    fprintf(file, "#endif /* MIG_DEBUG */\n");
531  }
532  fprintf(file, "\t\treturn FALSE;\n");
533  fprintf(file, "\t}\n");
534
535  /* Call appropriate routine */
536  fprintf(file, "\t(*routine) (InHeadP, OutHeadP);\n");
537  fprintf(file, "\treturn TRUE;\n");
538  fprintf(file, "}\n");
539  fprintf(file, "\n");
540
541  /*
542   * Then, the <subsystem>_server_routine routine
543   */
544  fprintf(file, "mig_external mig_routine_t %s_routine\n", ServerDemux);
545  if (BeAnsiC) {
546    fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
547  }
548  else {
549    fprintf(file, "#if\t%s\n", NewCDecl);
550    fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
551    fprintf(file, "#else\n");
552    fprintf(file, "\t(InHeadP)\n");
553    fprintf(file, "\tmach_msg_header_t *InHeadP;\n");
554    fprintf(file, "#endif\t/* %s */\n", NewCDecl);
555  }
556
557  fprintf(file, "{\n");
558  fprintf(file, "\tregister int msgh_id;\n");
559  fprintf(file, "\n");
560  fprintf(file, "\tmsgh_id = InHeadP->msgh_id - %d;\n", SubsystemBase);
561  fprintf(file, "\n");
562  fprintf(file, "\tif ((msgh_id > %d) || (msgh_id < 0))\n", rtNumber - 1);
563  fprintf(file, "\t\treturn 0;\n");
564  fprintf(file, "\n");
565  fprintf(file, "\treturn %s.routine[msgh_id].stub_routine;\n", ServerSubsys);
566  fprintf(file, "}\n");
567
568  /* symtab */
569
570  if (GenSymTab) {
571    fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName);
572    WriteSymTabEntries(file,stats);
573    fprintf(file,"};\n");
574    fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase);
575    fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber);
576  }
577}
578
579#if NOT_CURRENTLY_USED
580/*
581 *  Returns the return type of the server-side work function.
582 *  Suitable for "extern %s serverfunc()".
583 */
584static char *
585ServerSideType(routine_t *rt)
586{
587  return rt->rtRetCode->argType->itTransType;
588}
589#endif /* NOT_CURRENTLY_USED */
590
591static void
592WriteRetCode(FILE *file, register argument_t *ret)
593{
594  register ipc_type_t *it = ret->argType;
595
596  if (akCheck(ret->argKind, akbVarNeeded)) {
597    fprintf(file, "\t%s %s;\n", it->itTransType, ret->argVarName);
598  }
599}
600
601static void
602WriteLocalVarDecl(FILE *file, register argument_t *arg)
603{
604  register ipc_type_t *it = arg->argType;
605  register ipc_type_t *btype = it->itElement;
606
607  if (IS_VARIABLE_SIZED_UNTYPED(it))
608    fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, btype->itNumber ? it->itNumber/btype->itNumber : 0);
609  else if (IS_MULTIPLE_KPD(it)) {
610    if (btype->itTransType != strNULL)
611      fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, it->itKPD_Number);
612    else
613    /* arrays of ool or oolport */
614      fprintf(file, "\tvoid *%s[%d]", arg->argVarName, it->itKPD_Number);
615  }
616  else
617    fprintf(file, "\t%s %s", it->itTransType, arg->argVarName);
618}
619
620#if NOT_CURRENTLY_USED
621static void
622WriteServerArgDecl(FILE *file, argument_t *arg)
623{
624  fprintf(file, "%s %s%s", arg->argType->itTransType, arg->argByReferenceServer ? "*" : "", arg->argVarName);
625}
626#endif /* NOT_CURRENTLY_USED */
627
628/*
629 *  Writes the local variable declarations which are always
630 *  present:  InP, OutP, the server-side work function.
631 */
632static void
633WriteVarDecls(FILE *file, routine_t *rt)
634{
635  int i;
636
637  fprintf(file, "\tRequest *In0P = (Request *) InHeadP;\n");
638  for (i = 1; i <= rt->rtMaxRequestPos; i++)
639    fprintf(file, "\tRequest *In%dP;\n", i);
640  fprintf(file, "\tReply *OutP = (Reply *) OutHeadP;\n");
641
642  /* if reply is variable, we may need msgh_size_delta and msgh_size */
643  if (rt->rtNumReplyVar > 1)
644    fprintf(file, "\tunsigned int msgh_size;\n");
645  if (rt->rtMaxReplyPos > 0)
646    fprintf(file, "\tunsigned int msgh_size_delta;\n");
647  if (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos > 0)
648    fprintf(file, "\n");
649
650  if (rt->rtServerImpl) {
651    fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n");
652    fprintf(file, "#if\t__MigTypeCheck\n");
653    fprintf(file, "\tunsigned int trailer_size;\n");
654    fprintf(file, "#endif\t/* __MigTypeCheck */\n");
655  }
656  fprintf(file, "#ifdef\t__MIG_check__Request__%s_t__defined\n", rt->rtName);
657  fprintf(file, "\tkern_return_t check_result;\n");
658  fprintf(file, "#endif\t/* __MIG_check__Request__%s_t__defined */\n", rt->rtName);
659  fprintf(file, "\n");
660}
661
662static void
663WriteReplyInit(FILE *file, routine_t *rt)
664{
665  fprintf(file, "\n");
666  if  (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos)
667    /* WritheAdjustMsgSize() has been executed at least once! */
668    fprintf(file, "\tOutP = (Reply *) OutHeadP;\n");
669
670  if (!rt->rtSimpleReply)  /* complex reply message */
671    fprintf(file, "\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
672
673  if (rt->rtNumReplyVar == 0) {
674    fprintf(file, "\tOutP->Head.msgh_size = ");
675    rtMinReplySize(file, rt, "Reply");
676    fprintf(file, ";\n");
677  }
678  else if (rt->rtNumReplyVar > 1)
679    fprintf(file, "\tOutP->Head.msgh_size = msgh_size;\n");
680  /* the case rt->rtNumReplyVar = 1 is taken care of in WriteAdjustMsgSize() */
681}
682
683static void
684WriteRetCArgCheckError(FILE *file, routine_t *rt)
685{
686  fprintf(file, "\tif (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&\n");
687  fprintf(file, "\t    (In0P->Head.msgh_size == (mach_msg_size_t)sizeof(mig_reply_error_t)))\n");
688  fprintf(file, "\t{\n");
689}
690
691static void
692WriteRetCArgFinishError(FILE *file, routine_t *rt)
693{
694  argument_t *retcode = rt->rtRetCArg;
695
696  fprintf(file, "\treturn;\n");
697  fprintf(file, "\t}\n");
698  retcode->argMsgField = "KERN_SUCCESS";
699}
700
701static void
702WriteCheckHead(FILE *file, routine_t *rt)
703{
704  fprintf(file, "#if\t__MigTypeCheck\n");
705  if (rt->rtNumRequestVar > 0)
706    fprintf(file, "\tmsgh_size = In0P->Head.msgh_size;\n");
707
708  if (rt->rtSimpleRequest) {
709    /* Expecting a simple message. */
710    fprintf(file, "\tif ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
711    if (rt->rtNumRequestVar > 0) {
712      fprintf(file, "\t    (msgh_size < ");
713      rtMinRequestSize(file, rt, "__Request");
714      fprintf(file, ") ||  (msgh_size > (mach_msg_size_t)sizeof(__Request)))\n");
715    }
716    else
717      fprintf(file, "\t    (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request)))\n");
718  }
719  else {
720    /* Expecting a complex message. */
721
722    fprintf(file, "\tif (");
723    if (rt->rtRetCArg != argNULL)
724      fprintf(file, "(");
725    fprintf(file, "!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
726    fprintf(file, "\t    (In0P->msgh_body.msgh_descriptor_count != %d) ||\n", rt->rtRequestKPDs);
727    if (rt->rtNumRequestVar > 0) {
728      fprintf(file, "\t    (msgh_size < ");
729      rtMinRequestSize(file, rt, "__Request");
730      fprintf(file, ") ||  (msgh_size > (mach_msg_size_t)sizeof(__Request))");
731    }
732    else
733      fprintf(file, "\t    (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request))");
734    if (rt->rtRetCArg == argNULL)
735      fprintf(file, ")\n");
736    else {
737      fprintf(file, ") &&\n");
738      fprintf(file, "\t    ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
739      fprintf(file, "\t    In0P->Head.msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
740      fprintf(file, "\t    ((mig_reply_error_t *)In0P)->RetCode == KERN_SUCCESS))\n");
741    }
742  }
743  fprintf(file, "\t\treturn MIG_BAD_ARGUMENTS;\n");
744  fprintf(file, "#endif\t/* __MigTypeCheck */\n");
745  fprintf(file, "\n");
746}
747
748void
749WriteRequestNDRConvertIntRepArgCond(FILE *file, argument_t *arg)
750{
751  routine_t *rt = arg->argRoutine;
752
753  fprintf(file, "defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
754}
755
756void
757WriteRequestNDRConvertCharRepArgCond(FILE *file, argument_t *arg)
758{
759  routine_t *rt = arg->argRoutine;
760
761  if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
762    fprintf(file, "defined(__NDR_convert__char_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
763  else
764    fprintf(file, "0");
765}
766
767void
768WriteRequestNDRConvertFloatRepArgCond(FILE *file, argument_t *arg)
769{
770  routine_t *rt = arg->argRoutine;
771
772  if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
773    fprintf(file, "defined(__NDR_convert__float_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
774  else
775    fprintf(file, "0");
776}
777
778void
779WriteRequestNDRConvertIntRepArgDecl(FILE *file, argument_t *arg)
780{
781  WriteNDRConvertArgDecl(file, arg, "int_rep", "Request");
782}
783
784void
785WriteRequestNDRConvertCharRepArgDecl(FILE *file, argument_t *arg)
786{
787  if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
788    WriteNDRConvertArgDecl(file, arg, "char_rep", "Request");
789}
790
791void
792WriteRequestNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg)
793{
794  if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
795    WriteNDRConvertArgDecl(file, arg, "float_rep", "Request");
796}
797
798void
799WriteRequestNDRConvertArgUse(FILE *file, argument_t *arg, char *convert)
800{
801  routine_t *rt = arg->argRoutine;
802  argument_t *count = arg->argCount;
803  char argname[MAX_STR_LEN];
804
805  if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) &&
806      (arg->argParent && akCheck(arg->argParent->argKind, akbSendNdr)))
807    return;
808
809  if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
810    if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) {
811      fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, count->argMsgField);
812      fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argRequestPos, count->argMsgField, count->argRequestPos);
813      fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, count->argMsgField);
814    }
815
816    sprintf(argname, "(%s)(In%dP->%s.address)", FetchServerType(arg->argType), arg->argRequestPos, arg->argMsgField);
817  }
818  else {
819    sprintf(argname, "&In%dP->%s", arg->argRequestPos, arg->argMsgField);
820  }
821
822  fprintf(file, "#if defined(__NDR_convert__%s__Request__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField);
823  fprintf(file, "\t\t__NDR_convert__%s__Request__%s_t__%s(%s, In0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert);
824  if (count)
825    fprintf(file, ", In%dP->%s", count->argRequestPos, count->argMsgField);
826  fprintf(file, ");\n");
827  fprintf(file, "#endif\t/* __NDR_convert__%s__Request__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField);
828}
829
830void
831WriteRequestNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg)
832{
833  routine_t *rt = arg->argRoutine;
834
835  fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField);
836  fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep)\n");
837  fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argRequestPos, arg->argMsgField, arg->argRequestPos);
838  fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField);
839}
840
841void
842WriteRequestNDRConvertIntRepArgUse(FILE *file, argument_t *arg)
843{
844  WriteRequestNDRConvertArgUse(file, arg, "int_rep");
845}
846
847void
848WriteRequestNDRConvertCharRepArgUse(FILE *file, argument_t *arg)
849{
850  if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
851    WriteRequestNDRConvertArgUse(file, arg, "char_rep");
852}
853
854void
855WriteRequestNDRConvertFloatRepArgUse(FILE *file, argument_t *arg)
856{
857  if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
858    WriteRequestNDRConvertArgUse(file, arg, "float_rep");
859}
860
861static void
862WriteCalcArgSize(FILE *file, register argument_t *arg)
863{
864  register ipc_type_t *ptype = arg->argType;
865
866  if (PackMsg == FALSE) {
867    fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
868    return;
869  }
870
871  if (IS_OPTIONAL_NATIVE(ptype))
872    fprintf(file, "(In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0)" , arg->argRequestPos, arg->argMsgField, ptype->itServerType);
873  else {
874    register ipc_type_t *btype = ptype->itElement;
875    argument_t *count = arg->argCount;
876    int multiplier = btype->itTypeSize;
877
878    if (btype->itTypeSize % itWordAlign != 0)
879      fprintf(file, "_WALIGN_");
880    fprintf(file, "(");
881
882    if (multiplier > 1)
883      fprintf(file, "%d * ", multiplier);
884    fprintf(file, "In%dP->%s", count->argRequestPos, count->argMsgField);
885    fprintf(file, ")");
886  }
887}
888
889static void
890WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator)
891{
892  register ipc_type_t *ptype = arg->argType;
893
894
895  fprintf(file, "\tif (((msgh_size - ");
896  rtMinRequestSize(file, rt, "__Request");
897  fprintf(file, ") ");
898  if (PackMsg == FALSE) {
899	  fprintf(file, "%s %d)", comparator, ptype->itTypeSize + ptype->itPadSize);
900  } else if (IS_OPTIONAL_NATIVE(ptype)) {
901	  fprintf(file, "%s (In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0))" , comparator, arg->argRequestPos, arg->argMsgField, ptype->itServerType);
902  } else {
903    register ipc_type_t *btype = ptype->itElement;
904    argument_t *count = arg->argCount;
905    int multiplier = btype->itTypeSize;
906
907    if (multiplier > 1)
908      fprintf(file, "/ %d ", multiplier);
909    fprintf(file, "< In%dP->%s) ||\n", count->argRequestPos, count->argMsgField);
910    fprintf(file, "\t    (msgh_size %s ", comparator);
911    rtMinRequestSize(file, rt, "__Request");
912    fprintf(file, " + ");
913    WriteCalcArgSize(file, arg);
914    fprintf(file, ")");
915  }
916  fprintf(file, ")\n\t\treturn MIG_BAD_ARGUMENTS;\n");
917}
918
919static void
920WriteCheckMsgSize(FILE *file, register argument_t *arg)
921{
922  register routine_t *rt = arg->argRoutine;
923
924  if (arg->argCount && !arg->argSameCount)
925    WriteRequestNDRConvertIntRepOneArgUse(file, arg->argCount);
926  if (arg->argRequestPos == rt->rtMaxRequestPos)  {
927    fprintf(file, "#if\t__MigTypeCheck\n");
928
929    /* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */
930    fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber);
931    fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file);
932    /* ...end... */
933
934    WriteCheckArgSize(file, rt, arg, "!=");
935
936    fprintf(file, "#endif\t/* __MigTypeCheck */\n");
937  }
938  else {
939    /* If there aren't any more variable-sized arguments after this,
940       then we must check for exact msg-size and we don't need to
941       update msgh_size. */
942
943    boolean_t LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar;
944
945    /* calculate the actual size in bytes of the data field.  note
946       that this quantity must be a multiple of four.  hence, if
947       the base type size isn't a multiple of four, we have to
948       round up.  note also that btype->itNumber must
949       divide btype->itTypeSize (see itCalculateSizeInfo). */
950
951    fprintf(file, "\tmsgh_size_delta = ");
952    WriteCalcArgSize(file, arg);
953    fprintf(file, ";\n");
954    fprintf(file, "#if\t__MigTypeCheck\n");
955
956    /* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */
957    fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber);
958    fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file);
959    /* ...end... */
960
961    /* Don't decrement msgh_size until we've checked that
962       it won't underflow. */
963    WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<");
964
965    if (!LastVarArg)
966      fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
967
968    fprintf(file, "#endif\t/* __MigTypeCheck */\n");
969  }
970  fprintf(file, "\n");
971}
972
973static char *
974InArgMsgField(register argument_t *arg,  char *str)
975{
976  static char buffer[MAX_STR_LEN];
977  char who[20] = {0};
978
979  /*
980   * Inside the kernel, the request and reply port fields
981   * really hold ipc_port_t values, not mach_port_t values.
982   * Hence we must cast the values.
983   */
984
985  if (!(arg->argFlags & flRetCode)) {
986    if (akCheck(arg->argKind, akbServerImplicit))
987      sprintf(who, "TrailerP->");
988    else
989      sprintf(who, "In%dP->", arg->argRequestPos);
990  }
991
992#ifdef MIG_KERNEL_PORT_CONVERSION
993  if (IsKernelServer &&
994      ((akIdent(arg->argKind) == akeRequestPort) ||
995       (akIdent(arg->argKind) == akeReplyPort)))
996    sprintf(buffer, "(ipc_port_t) %s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
997  else
998#endif
999    sprintf(buffer, "%s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
1000
1001  return buffer;
1002}
1003
1004static void
1005WriteExtractArgValue(FILE *file, register argument_t *arg)
1006{
1007  register ipc_type_t *it = arg->argType;
1008  string_t recast;
1009
1010#ifdef MIG_KERNEL_PORT_CONVERSION
1011  if (IsKernelServer && it->itPortType && streql(it->itServerType, "ipc_port_t")
1012      && akIdent(arg->argKind) != akeRequestPort
1013      && akIdent(arg->argKind) != akeReplyPort)
1014    recast = "(mach_port_t)";
1015  else
1016#endif
1017    recast = "";
1018  if (it->itInTrans != strNULL)
1019    WriteCopyType(file, it, "%s", "/* %s */ %s(%s%s)", arg->argVarName, it->itInTrans, recast, InArgMsgField(arg, ""));
1020  else
1021    WriteCopyType(file, it, "%s", "/* %s */ %s%s", arg->argVarName, recast, InArgMsgField(arg, ""));
1022
1023  fprintf(file, "\n");
1024}
1025
1026/*
1027 * argKPD_Extract discipline for Port types.
1028 */
1029static void
1030WriteExtractKPD_port(FILE *file,  register argument_t *arg)
1031{
1032  register ipc_type_t *it = arg->argType;
1033  char *recast = "";
1034
1035  WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
1036  /* translation function do not apply to complex types */
1037#ifdef MIG_KERNEL_PORT_CONVERSION
1038  if (IsKernelServer)
1039    recast = "(mach_port_t)";
1040#endif
1041  fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast);
1042  fprintf(file, "\t}\n");
1043}
1044
1045/*
1046 * argKPD_Extract discipline for out-of-line types.
1047 */
1048static void
1049WriteExtractKPD_ool(FILE *file, register argument_t *arg)
1050{
1051  register ipc_type_t *it = arg->argType;
1052
1053  WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
1054  fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
1055  fprintf(file, "\t}\n");
1056}
1057
1058/*
1059 * argKPD_Extract discipline for out-of-line Port types.
1060 */
1061static void
1062WriteExtractKPD_oolport(FILE *file, register argument_t *arg)
1063{
1064  register ipc_type_t *it = arg->argType;
1065
1066  WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
1067  fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
1068  fprintf(file, "\t}\n");
1069  if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendRcv)) {
1070    register argument_t *poly = arg->argPoly;
1071    register char *pref = poly->argByReferenceServer ? "*" : "";
1072
1073    fprintf(file, "\t%s%s = In%dP->%s[0].disposition;\n", pref, poly->argVarName, arg->argRequestPos, arg->argMsgField);
1074  }
1075}
1076
1077
1078static void
1079WriteInitializeCount(FILE *file, register argument_t *arg)
1080{
1081  register ipc_type_t *ptype = arg->argParent->argType;
1082  register ipc_type_t *btype = ptype->itElement;
1083  identifier_t newstr;
1084
1085  /*
1086   * Initialize 'count' argument for variable-length inline OUT parameter
1087   * with maximum allowed number of elements.
1088   */
1089
1090  if (akCheck(arg->argKind, akbVarNeeded))
1091    newstr = arg->argMsgField;
1092  else
1093    newstr = (identifier_t)strconcat("OutP->", arg->argMsgField);
1094
1095  fprintf(file, "\t%s = ", newstr);
1096  if (IS_MULTIPLE_KPD(ptype))
1097    fprintf(file, "%d;\n", ptype->itKPD_Number);
1098  else
1099    fprintf(file, "%d;\n", btype->itNumber? ptype->itNumber/btype->itNumber : 0);
1100
1101  /*
1102   * If the user passed in a count, then we use the minimum.
1103   * We can't let the user completely override our maximum,
1104   * or the user might convince the server to overwrite the buffer.
1105   */
1106
1107  if (arg->argCInOut != argNULL) {
1108    char *msgfield = InArgMsgField(arg->argCInOut, "");
1109
1110    fprintf(file, "\tif (%s < %s)\n", msgfield, newstr);
1111    fprintf(file, "\t\t%s = %s;\n", newstr, msgfield);
1112  }
1113
1114  fprintf(file, "\n");
1115}
1116
1117static void
1118WriteAdjustRequestMsgPtr(FILE *file, register argument_t *arg)
1119{
1120  register ipc_type_t *ptype = arg->argType;
1121
1122  if (PackMsg == FALSE) {
1123    fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP);\n\n", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos);
1124    return;
1125  }
1126
1127  fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP + msgh_size_delta - ", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos);
1128  if (IS_OPTIONAL_NATIVE(ptype))
1129    fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType);
1130  else
1131    fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
1132  fprintf(file, ");\n\n");
1133}
1134
1135static void
1136WriteCheckRequestTrailerArgs(FILE *file, routine_t *rt)
1137{
1138  register argument_t *arg;
1139
1140  if (rt->rtServerImpl)
1141    WriteCheckTrailerHead(file, rt, FALSE);
1142
1143  for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1144    if (akCheck(arg->argKind, akbServerImplicit))
1145      WriteCheckTrailerSize(file, FALSE, arg);
1146  }
1147}
1148
1149static void
1150WriteExtractArg(FILE *file, register argument_t *arg)
1151{
1152  if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded)) {
1153    if (akCheck(arg->argKind, akbSendKPD))
1154      (*arg->argKPD_Extract)(file, arg);
1155    else
1156      WriteExtractArgValue(file, arg);
1157  }
1158
1159  if ((akIdent(arg->argKind) == akeCount) &&
1160      akCheck(arg->argKind, akbReturnSnd)) {
1161
1162    register ipc_type_t *ptype = arg->argParent->argType;
1163    /*
1164     * the count will be initialized to 0 in the case of
1165     * unbounded arrays (MigInLine = TRUE): this is because
1166     * the old interface used to pass to the target procedure
1167     * the maximum in-line size (it was 2048 bytes)
1168     */
1169    if (IS_VARIABLE_SIZED_UNTYPED(ptype) ||
1170        IS_MIG_INLINE_EMUL(ptype) ||
1171        (IS_MULTIPLE_KPD(ptype) && ptype->itVarArray))
1172      WriteInitializeCount(file, arg);
1173  }
1174}
1175
1176static void
1177WriteServerCallArg(FILE *file, register argument_t *arg)
1178{
1179  ipc_type_t *it = arg->argType;
1180  boolean_t NeedClose = FALSE;
1181  string_t  at = (arg->argByReferenceServer ||
1182                  it->itNativePointer) ? "&" : "";
1183  string_t  star = (arg->argByReferenceServer) ? " *" : "";
1184  string_t  msgfield =
1185  (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField;
1186
1187  if ((it->itInTrans != strNULL) &&
1188      akCheck(arg->argKind, akbSendRcv) &&
1189      !akCheck(arg->argKind, akbVarNeeded)) {
1190    fprintf(file, "%s%s(", at, it->itInTrans);
1191    NeedClose = TRUE;
1192  }
1193
1194  if (akCheckAll(arg->argKind, akbVarNeeded|akbServerArg))
1195    fprintf(file, "%s%s", at, arg->argVarName);
1196  else if (akCheckAll(arg->argKind, akbSendRcv|akbSendKPD)) {
1197    if (!it->itInLine)
1198      /* recast the void *, although it is not necessary */
1199      fprintf(file, "(%s%s)%s(%s)", it->itTransType, star, at, InArgMsgField(arg, ""));
1200    else
1201#ifdef MIG_KERNEL_PORT_CONVERSION
1202      if (IsKernelServer && streql(it->itServerType, "ipc_port_t"))
1203        /* recast the port to the kernel internal form value */
1204        fprintf(file, "(ipc_port_t%s)%s(%s)", star, at, InArgMsgField(arg, ""));
1205      else
1206#endif
1207        fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
1208  }
1209  else if (akCheck(arg->argKind, akbSendRcv)) {
1210    if (IS_OPTIONAL_NATIVE(it)) {
1211      fprintf(file, "(%s ? ", InArgMsgField(arg, "__Present__"));
1212      fprintf(file, "%s%s.__Real__%s : %s)", at, InArgMsgField(arg, ""), arg->argMsgField, it->itBadValue);
1213    }
1214    else
1215      fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
1216  }
1217  else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD)) {
1218    if (!it->itInLine)
1219      /* recast the void *, although it is not necessary */
1220      fprintf(file, "(%s%s)%s(OutP->%s)", it->itTransType, star, at, msgfield);
1221    else
1222#ifdef MIG_KERNEL_PORT_CONVERSION
1223      if (IsKernelServer && streql(it->itServerType, "ipc_port_t"))
1224      /* recast the port to the kernel internal form value */
1225        fprintf(file, "(mach_port_t%s)%s(OutP->%s)", star, at, msgfield);
1226      else
1227#endif
1228        fprintf(file, "%sOutP->%s", at, msgfield);
1229
1230  }
1231  else  if (akCheck(arg->argKind, akbReturnSnd))
1232    fprintf(file, "%sOutP->%s", at, msgfield);
1233
1234  if (NeedClose)
1235    fprintf(file, ")");
1236}
1237
1238/*
1239 * Shrunk version of WriteServerCallArg, to implement the RetCode functionality:
1240 * we have received a mig_reply_error_t, therefore we want to call the target
1241 * routine with all 0s except for the error code (and the implicit data).
1242 * We know that we are a SimpleRoutine.
1243 */
1244static void
1245WriteConditionalCallArg(FILE *file, register argument_t *arg)
1246{
1247  ipc_type_t *it = arg->argType;
1248  boolean_t NeedClose = FALSE;
1249
1250  if ((it->itInTrans != strNULL) &&
1251      akCheck(arg->argKind, akbSendRcv) &&
1252      !akCheck(arg->argKind, akbVarNeeded)) {
1253    fprintf(file, "%s(", it->itInTrans);
1254    NeedClose = TRUE;
1255  }
1256
1257  if (akCheck(arg->argKind, akbSendRcv)) {
1258    if (akIdent(arg->argKind) == akeRequestPort ||
1259        akCheck(arg->argKind, akbServerImplicit))
1260      fprintf(file, "%s", InArgMsgField(arg, ""));
1261    else if (akIdent(arg->argKind) == akeRetCode)
1262      fprintf(file, "((mig_reply_error_t *)In0P)->RetCode");
1263    else
1264      fprintf(file, "(%s)(0)", it->itTransType);
1265  }
1266
1267  if (NeedClose)
1268    fprintf(file, ")");
1269}
1270
1271static void
1272WriteDestroyArg(FILE *file, register argument_t *arg)
1273{
1274  register ipc_type_t *it = arg->argType;
1275
1276  /*
1277   * Deallocate IN/INOUT out-of-line args if specified by "auto" flag.
1278   *
1279   * We also have to deallocate in the cases where the target routine
1280   * is given a itInLine semantic whereas the underlying transmission
1281   * was out-of-line
1282   */
1283  if ((argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
1284       arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR &&
1285       (arg->argFlags & flAuto))
1286      ||
1287      IS_MIG_INLINE_EMUL(it)
1288      ) {
1289    /*
1290     * Deallocate only if out-of-line.
1291     */
1292    argument_t *count = arg->argCount;
1293    ipc_type_t *btype = it->itElement;
1294    int multiplier = btype->itNumber ? btype->itSize / (8 * btype->itNumber) : 0;
1295
1296    if (IsKernelServer) {
1297      fprintf(file, "#if __MigKernelSpecificCode\n");
1298      fprintf(file, "\tvm_map_copy_discard(%s);\n", InArgMsgField(arg, ""));
1299      fprintf(file, "#else\n");
1300    }
1301    fprintf(file, "\tmig_deallocate((vm_offset_t) %s, ", InArgMsgField(arg, ""));
1302    if (it->itVarArray) {
1303      if (multiplier > 1)
1304        fprintf(file, "%d * ", multiplier);
1305      fprintf(file, "%s);\n", InArgMsgField(count, ""));
1306    }
1307    else
1308      fprintf(file, "%d);\n", (it->itNumber * it->itSize + 7) / 8);
1309    if (IsKernelServer) {
1310      fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1311    }
1312    fprintf(file, "\t%s = (void *) 0;\n", InArgMsgField(arg, ""));
1313    fprintf(file, "\tIn%dP->%s.%s = (mach_msg_size_t) 0;\n", arg->argRequestPos, arg->argMsgField, (RPCPortArray(arg) ? "count" : "size"));
1314  }
1315  else {
1316    if (akCheck(arg->argKind, akbVarNeeded))
1317      fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName);
1318    else
1319      fprintf(file, "\t%s(%s);\n", it->itDestructor, InArgMsgField(arg, ""));
1320  }
1321}
1322
1323static void
1324WriteDestroyPortArg(FILE *file, register argument_t *arg)
1325{
1326  register ipc_type_t *it = arg->argType;
1327
1328  /*
1329   * If a translated port argument occurs in the body of a request
1330   * message, and the message is successfully processed, then the
1331   * port right should be deallocated.  However, the called function
1332   * didn't see the port right; it saw the translation.  So we have
1333   * to release the port right for it.
1334   *
1335   *  The test over it->itInTrans will exclude any complex type
1336   *  made out of ports
1337   */
1338  if ((it->itInTrans != strNULL) &&
1339      (it->itOutName == MACH_MSG_TYPE_PORT_SEND)) {
1340    fprintf(file, "\n");
1341    fprintf(file, "\tif (IP_VALID((ipc_port_t)%s))\n", InArgMsgField(arg, ""));
1342    fprintf(file, "\t\tipc_port_release_send((ipc_port_t)%s);\n", InArgMsgField(arg, ""));
1343  }
1344}
1345
1346/*
1347 * Check whether WriteDestroyPortArg would generate any code for arg.
1348 */
1349boolean_t
1350CheckDestroyPortArg(register argument_t *arg)
1351{
1352  register ipc_type_t *it = arg->argType;
1353
1354  if ((it->itInTrans != strNULL) &&
1355      (it->itOutName == MACH_MSG_TYPE_PORT_SEND))  {
1356    return TRUE;
1357  }
1358  return FALSE;
1359}
1360
1361static void
1362WriteServerCall(FILE *file, routine_t *rt,  void (*func)())
1363{
1364  argument_t *arg = rt->rtRetCode;
1365  ipc_type_t *it = arg->argType;
1366  boolean_t NeedClose = FALSE;
1367
1368  fprintf(file, "\t");
1369  if (akCheck(arg->argKind, akbVarNeeded))
1370    fprintf(file, "%s = ", arg->argMsgField);
1371  else
1372    fprintf(file, "OutP->%s = ", arg->argMsgField);
1373  if (it->itOutTrans != strNULL) {
1374    fprintf(file, "%s(", it->itOutTrans);
1375    NeedClose = TRUE;
1376  }
1377  fprintf(file, "%s(", rt->rtServerName);
1378  WriteList(file, rt->rtArgs, func, akbServerArg, ", ", "");
1379  if (NeedClose)
1380    fprintf(file, ")");
1381  fprintf(file, ");\n");
1382}
1383
1384static void
1385WriteCheckReturnValue(FILE *file, register routine_t *rt)
1386{
1387  argument_t *arg = rt->rtRetCode;
1388  char string[MAX_STR_LEN];
1389
1390  if (akCheck(arg->argKind, akbVarNeeded))
1391    sprintf(string, "%s", arg->argMsgField);
1392  else
1393    sprintf(string, "OutP->%s", arg->argMsgField);
1394  fprintf(file, "\tif (%s != KERN_SUCCESS) {\n", string);
1395  fprintf(file, "\t\tMIG_RETURN_ERROR(OutP, %s);\n", string);
1396  fprintf(file, "\t}\n");
1397}
1398
1399/*
1400 * WriteInitKPD_port, WriteInitKPD_ool, WriteInitKPD_oolport
1401 * initializes the OutP KPD fields (this job cannot be done once
1402 * the target routine has been called, otherwise informations
1403 * would be lost)
1404 */
1405/*
1406 * argKPD_Init discipline for Port types.
1407 */
1408static void
1409WriteInitKPD_port(FILE *file, register argument_t *arg)
1410{
1411  register ipc_type_t *it = arg->argType;
1412  char *subindex = "";
1413  boolean_t close = FALSE;
1414  char firststring[MAX_STR_LEN];
1415  char string[MAX_STR_LEN];
1416
1417  if (IS_MULTIPLE_KPD(it)) {
1418    WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
1419    (void)sprintf(firststring, "\t*ptr");
1420    (void)sprintf(string, "\tptr->");
1421    subindex = "[i]";
1422    close = TRUE;
1423  }
1424  else {
1425    (void)sprintf(firststring, "OutP->%s", arg->argMsgField);
1426    (void)sprintf(string, "OutP->%s.", arg->argMsgField);
1427  }
1428
1429  fprintf(file, "#if\tUseStaticTemplates\n");
1430  fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1431  fprintf(file, "#else\t/* UseStaticTemplates */\n");
1432  if (IS_MULTIPLE_KPD(it) && it->itVarArray)
1433    fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string);
1434  if (arg->argPoly == argNULL) {
1435    if (IsKernelServer) {
1436      fprintf(file, "#if __MigKernelSpecificCode\n");
1437      fprintf(file, "\t%sdisposition = %s;\n", string, it->itOutNameStr);
1438      fprintf(file, "#else\n");
1439    }
1440    fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr);
1441    if (IsKernelServer)
1442      fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1443  }
1444  fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
1445  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1446  if (close)
1447    fprintf(file, "\t    }\n\t}\n");
1448  fprintf(file, "\n");
1449}
1450
1451/*
1452 * argKPD_Init discipline for out-of-line types.
1453 */
1454static void
1455WriteInitKPD_ool(FILE *file, register argument_t *arg)
1456{
1457  register ipc_type_t *it = arg->argType;
1458  char firststring[MAX_STR_LEN];
1459  char string[MAX_STR_LEN];
1460  boolean_t VarArray;
1461  u_int howmany, howbig;
1462
1463  if (IS_MULTIPLE_KPD(it)) {
1464    WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
1465    (void)sprintf(firststring, "\t*ptr");
1466    (void)sprintf(string, "\tptr->");
1467    VarArray = it->itElement->itVarArray;
1468    howmany = it->itElement->itNumber;
1469    howbig = it->itElement->itSize;
1470  }
1471  else {
1472    (void)sprintf(firststring, "OutP->%s", arg->argMsgField);
1473    (void)sprintf(string, "OutP->%s.", arg->argMsgField);
1474    VarArray = it->itVarArray;
1475    howmany = it->itNumber;
1476    howbig = it->itSize;
1477  }
1478
1479  fprintf(file, "#if\tUseStaticTemplates\n");
1480  fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1481  fprintf(file, "#else\t/* UseStaticTemplates */\n");
1482  if (!VarArray)
1483    fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
1484  if (arg->argDeallocate != d_MAYBE)
1485    fprintf(file, "\t%sdeallocate =  %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
1486  fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
1487#ifdef ALIGNMENT
1488  fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, arg->argMsgField, (howbig < 8) ? 1 : howbig / 8);
1489#endif
1490  fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
1491  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1492
1493  if (IS_MULTIPLE_KPD(it))
1494    fprintf(file, "\t    }\n\t}\n");
1495  fprintf(file, "\n");
1496}
1497
1498/*
1499 * argKPD_Init discipline for out-of-line Port types.
1500 */
1501static void
1502WriteInitKPD_oolport(FILE *file, register argument_t *arg)
1503{
1504  register ipc_type_t *it = arg->argType;
1505  boolean_t VarArray;
1506  ipc_type_t *howit;
1507  u_int howmany;
1508  char firststring[MAX_STR_LEN];
1509  char string[MAX_STR_LEN];
1510
1511  if (IS_MULTIPLE_KPD(it)) {
1512    WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
1513    (void)sprintf(firststring, "\t*ptr");
1514    (void)sprintf(string, "\tptr->");
1515    VarArray = it->itElement->itVarArray;
1516    howmany = it->itElement->itNumber;
1517    howit = it->itElement;
1518  }
1519  else {
1520    (void)sprintf(firststring, "OutP->%s", arg->argMsgField);
1521    (void)sprintf(string, "OutP->%s.", arg->argMsgField);
1522    VarArray = it->itVarArray;
1523    howmany = it->itNumber;
1524    howit = it;
1525  }
1526
1527  fprintf(file, "#if\tUseStaticTemplates\n");
1528  fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1529  fprintf(file, "#else\t/* UseStaticTemplates */\n");
1530
1531  if (!VarArray)
1532    fprintf(file, "\t%scount = %d;\n", string, howmany);
1533  if (arg->argPoly == argNULL) {
1534    if (IsKernelServer) {
1535      fprintf(file, "#if\t__MigKernelSpecificCode\n");
1536      fprintf(file, "\t%sdisposition = %s;\n", string, howit->itOutNameStr);
1537      fprintf(file, "#else\n");
1538    }
1539    fprintf(file, "\t%sdisposition = %s;\n", string, howit->itInNameStr);
1540    if (IsKernelServer)
1541      fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1542  }
1543  if (arg->argDeallocate != d_MAYBE)
1544    fprintf(file, "\t%sdeallocate =  %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
1545  fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
1546  fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1547
1548  if (IS_MULTIPLE_KPD(it))
1549    fprintf(file, "\t    }\n\t}\n");
1550  fprintf(file, "\n");
1551}
1552
1553static void
1554WriteInitKPDValue(FILE *file, register argument_t *arg)
1555{
1556  (*arg->argKPD_Init)(file, arg);
1557}
1558
1559static void
1560WriteAdjustMsgCircular(FILE *file, register argument_t *arg)
1561{
1562  fprintf(file, "\n");
1563
1564  fprintf(file,"#if\t__MigKernelSpecificCode\n");
1565  if (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
1566    fprintf(file, "\tif (%s == MACH_MSG_TYPE_PORT_RECEIVE)\n", arg->argPoly->argVarName);
1567
1568  /*
1569   * The carried port right can be accessed in OutP->XXXX.  Normally
1570   * the server function stuffs it directly there.  If it is InOut,
1571   * then it has already been copied into the reply message.
1572   * If the server function deposited it into a variable (perhaps
1573   * because the reply message is variable-sized) then it has already
1574   * been copied into the reply message.
1575   *
1576   *  The old MiG does not check for circularity in the case of
1577   *  array of ports. So do I ...
1578   */
1579
1580  fprintf(file, "\t  if (IP_VALID((ipc_port_t) In0P->Head.msgh_reply_port) &&\n");
1581  fprintf(file, "\t    IP_VALID((ipc_port_t) OutP->%s.name) &&\n", arg->argMsgField);
1582  fprintf(file, "\t    ipc_port_check_circularity((ipc_port_t) OutP->%s.name, (ipc_port_t) In0P->Head.msgh_reply_port))\n", arg->argMsgField);
1583  fprintf(file, "\t\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;\n");
1584  fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1585}
1586
1587/*
1588 * argKPD_Pack discipline for Port types.
1589 */
1590static void
1591WriteKPD_port(FILE *file, register argument_t *arg)
1592{
1593  register ipc_type_t *it = arg->argType;
1594  char *subindex = "";
1595  char *recast = "";
1596  boolean_t close = FALSE;
1597  char string[MAX_STR_LEN];
1598  ipc_type_t *real_it;
1599
1600  if (akCheck(arg->argKind, akbVarNeeded)) {
1601    if (IS_MULTIPLE_KPD(it)) {
1602      WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
1603      (void)sprintf(string, "\tptr->");
1604      subindex = "[i]";
1605      close = TRUE;
1606      real_it = it->itElement;
1607    }
1608    else {
1609      (void)sprintf(string, "OutP->%s.", arg->argMsgField);
1610      real_it = it;
1611    }
1612#ifdef MIG_KERNEL_PORT_CONVERSIONS
1613    if (IsKernelServer && streql(real_it->itTransType, "ipc_port_t"))
1614      recast = "(mach_port_t)";
1615#endif
1616
1617    if (it->itOutTrans != strNULL && !close)
1618      fprintf(file, "\t%sname = (mach_port_t)%s(%s);\n", string, it->itOutTrans, arg->argVarName);
1619    else
1620      fprintf(file, "\t%sname = %s%s%s;\n", string, recast, arg->argVarName, subindex);
1621    if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd)) {
1622      register argument_t *poly = arg->argPoly;
1623
1624      if  (akCheck(arg->argPoly->argKind, akbVarNeeded))
1625        fprintf(file, "\t%sdisposition = %s;\n", string, poly->argVarName);
1626      else if (close)
1627        fprintf(file, "\t%sdisposition = OutP->%s;\n", string, poly->argSuffix);
1628    }
1629    if (close)
1630      fprintf(file, "\t    }\n\t}\n");
1631    fprintf(file, "\n");
1632  }
1633  else  if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd|akbVarNeeded))
1634    fprintf(file, "\tOutP->%s.disposition = %s;\n", arg->argMsgField, arg->argPoly->argVarName);
1635  /*
1636   * If this is a KernelServer, and the reply message contains
1637   * a receive right, we must check for the possibility of a
1638   * port/message circularity.  If queueing the reply message
1639   * would cause a circularity, we mark the reply message
1640   * with the circular bit.
1641   */
1642  if (IsKernelServer && !(IS_MULTIPLE_KPD(it)) &&
1643      ((arg->argType->itOutName == MACH_MSG_TYPE_PORT_RECEIVE) ||
1644       (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)))
1645    WriteAdjustMsgCircular(file, arg);
1646}
1647
1648/*
1649 * argKPD_Pack discipline for out-of-line types.
1650 */
1651static void
1652WriteKPD_ool(FILE *file, register argument_t *arg)
1653{
1654  register ipc_type_t *it = arg->argType;
1655  char string[MAX_STR_LEN];
1656  boolean_t VarArray;
1657  argument_t *count;
1658  u_int howbig;
1659  char *subindex;
1660
1661  if (IS_MULTIPLE_KPD(it)) {
1662    WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
1663    (void)sprintf(string, "\tptr->");
1664    VarArray = it->itElement->itVarArray;
1665    count = arg->argSubCount;
1666    howbig = it->itElement->itSize;
1667    subindex = "[i]";
1668  }
1669  else {
1670    (void)sprintf(string, "OutP->%s.", arg->argMsgField);
1671    VarArray = it->itVarArray;
1672    count = arg->argCount;
1673    howbig = it->itSize;
1674    subindex = "";
1675  }
1676
1677  if (akCheck(arg->argKind, akbVarNeeded))
1678    fprintf(file, "\t%saddress = (void *)%s%s;\n", string, arg->argMsgField, subindex);
1679  if (arg->argDealloc != argNULL)
1680    if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
1681      fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
1682  if (VarArray) {
1683    fprintf(file, "\t%ssize = ", string);
1684    if (akCheck(count->argKind, akbVarNeeded))
1685      fprintf(file, "%s%s", count->argName, subindex);
1686    else
1687      fprintf(file, "OutP->%s%s", count->argMsgField, subindex);
1688
1689    if (count->argMultiplier > 1 || howbig > 8)
1690      fprintf(file, " * %d;\n", count->argMultiplier * howbig / 8);
1691    else
1692      fprintf(file, ";\n");
1693  }
1694
1695  if (IS_MULTIPLE_KPD(it)) {
1696    fprintf(file, "\t    }\n");
1697    if (it->itVarArray && !it->itElement->itVarArray) {
1698      fprintf(file, "\t    for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number);
1699      /* since subordinate arrays aren't variable, they are initialized from template:
1700       here we must no-op 'em */
1701      fprintf(file, "\t\tptr->size = 0;\n");
1702    }
1703    fprintf(file, "\t}\n");
1704  }
1705  fprintf(file, "\n");
1706}
1707
1708/*
1709 * argKPD_Pack discipline for out-of-line Port types.
1710 */
1711static void
1712WriteKPD_oolport(FILE *file, register argument_t *arg)
1713{
1714  register ipc_type_t *it = arg->argType;
1715  boolean_t VarArray;
1716  argument_t *count;
1717  char *subindex, string[MAX_STR_LEN];
1718
1719  if (IS_MULTIPLE_KPD(it)) {
1720    WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
1721    (void)sprintf(string, "\tptr->");
1722    VarArray = it->itElement->itVarArray;
1723    count = arg->argSubCount;
1724    subindex = "[i]";
1725  }
1726  else {
1727    (void)sprintf(string, "OutP->%s.", arg->argMsgField);
1728    VarArray = it->itVarArray;
1729    count = arg->argCount;
1730    subindex = "";
1731  }
1732
1733  if (akCheck(arg->argKind, akbVarNeeded))
1734    fprintf(file, "\t%saddress = (void *)%s%s;\n", string, arg->argMsgField, subindex);
1735  if (arg->argDealloc != argNULL)
1736    if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
1737      fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
1738  if (VarArray) {
1739    fprintf(file, "\t%scount = ", string);
1740    if (akCheck(count->argKind, akbVarNeeded))
1741      fprintf(file, "%s%s;\n", count->argName, subindex);
1742    else
1743      fprintf(file, "OutP->%s%s;\n", count->argMsgField, subindex);
1744  }
1745  if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd))
1746    if (akCheck(arg->argPoly->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
1747      fprintf(file, "\t%sdisposition = %s;\n", string, arg->argPoly->argVarName);
1748  if (IS_MULTIPLE_KPD(it)) {
1749    fprintf(file, "\t    }\n");
1750    if (it->itVarArray && !it->itElement->itVarArray) {
1751      fprintf(file, "\t    for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number);
1752      /* since subordinate arrays aren't variable, they are initialized from template:
1753       here we must no-op 'em */
1754      fprintf(file, "\t%scount = 0;\n", string);
1755    }
1756    fprintf(file, "\t}\n");
1757  }
1758  fprintf(file, "\n");
1759}
1760
1761/*
1762 * argKPD_TypeCheck discipline for Port types.
1763 */
1764static void
1765WriteTCheckKPD_port(FILE *file, register argument_t *arg)
1766{
1767  register ipc_type_t *it = arg->argType;
1768  char *tab = "";
1769  char string[MAX_STR_LEN];
1770  boolean_t close = FALSE;
1771
1772  if (IS_MULTIPLE_KPD(it)) {
1773    WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
1774    (void)sprintf(string, "ptr->");
1775    tab = "\t";
1776    close = TRUE;
1777  }
1778  else
1779    (void)sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
1780
1781  fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string);
1782  /*
1783   * We can't check disposition on varArray
1784   * (because some of the entries could be empty).
1785   */
1786  if (!it->itVarArray) {
1787    if (arg->argPoly != argNULL) {
1788      switch (it->itOutName) {
1789
1790        case MACH_MSG_TYPE_MOVE_RECEIVE:
1791          fprintf(file, " || \n\t%s    %sdisposition != MACH_MSG_TYPE_MOVE_RECEIVE", tab, string);
1792          break;
1793
1794        case MACH_MSG_TYPE_MOVE_SEND_ONCE:
1795          fprintf(file, " || (\n\t%s    %sdisposition != MACH_MSG_TYPE_MOVE_SEND_ONCE", tab, string);
1796          fprintf(file, " &&  \n\t%s    %sdisposition != MACH_MSG_TYPE_MAKE_SEND_ONCE)", tab, string);
1797          break;
1798
1799        case MACH_MSG_TYPE_MOVE_SEND:
1800          fprintf(file, " || (\n\t%s    %sdisposition != MACH_MSG_TYPE_MOVE_SEND", tab, string);
1801          fprintf(file, " &&  \n\t%s    %sdisposition != MACH_MSG_TYPE_MAKE_SEND", tab, string);
1802          fprintf(file, " &&  \n\t%s    %sdisposition != MACH_MSG_TYPE_COPY_SEND)", tab, string);
1803          break;
1804      }
1805    }
1806    else {
1807      fprintf(file, " ||\n\t%s    %sdisposition != %s", tab, string, it->itOutNameStr);
1808    }
1809  }
1810  fprintf(file, ")\n");
1811  fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
1812  if (close)
1813    fprintf(file, "\t    }\n\t}\n");
1814}
1815
1816/*
1817 * argKPD_TypeCheck discipline for out-of-line types.
1818 */
1819static void
1820WriteTCheckKPD_ool(FILE *file, register argument_t *arg)
1821{
1822  register ipc_type_t *it = arg->argType;
1823  char *tab, string[MAX_STR_LEN];
1824  boolean_t test;
1825  u_int howmany, howbig;
1826
1827  if (IS_MULTIPLE_KPD(it)) {
1828    WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
1829    tab = "\t\t\t";
1830    sprintf(string, "ptr->");
1831    howmany = it->itElement->itNumber;
1832    howbig = it->itElement->itSize;
1833    test = !it->itVarArray && !it->itElement->itVarArray;
1834  }
1835  else {
1836    tab = "";
1837    sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
1838    howmany = it->itNumber;
1839    howbig = it->itSize;
1840    test = !it->itVarArray;
1841  }
1842
1843  fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string);
1844  if (test) {
1845    /* if VarArray we may use no-op; if itElement->itVarArray size might change */
1846    fprintf(file, " ||\n\t%s    %ssize != %d", tab, string, (howmany * howbig + 7)/8);
1847  }
1848
1849  fprintf(file, ")\n");
1850  fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
1851
1852  if (IS_MULTIPLE_KPD(it))
1853    fprintf(file, "\t    }\n\t}\n");
1854}
1855
1856/*
1857 * argKPD_TypeCheck discipline for out-of-line Port types.
1858 */
1859static void
1860WriteTCheckKPD_oolport(FILE *file, register argument_t *arg)
1861{
1862  register ipc_type_t *it = arg->argType;
1863  char *tab, string[MAX_STR_LEN];
1864  boolean_t test;
1865  u_int howmany;
1866  char *howstr;
1867
1868  if (IS_MULTIPLE_KPD(it)) {
1869    WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
1870    tab = "\t";
1871    sprintf(string, "ptr->");
1872    howmany = it->itElement->itNumber;
1873    test = !it->itVarArray && !it->itElement->itVarArray;
1874    howstr = it->itElement->itOutNameStr;
1875  }
1876  else {
1877    tab = "";
1878    sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
1879    howmany = it->itNumber;
1880    test = !it->itVarArray;
1881    howstr = it->itOutNameStr;
1882  }
1883
1884  fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string);
1885  if (test)
1886  /* if VarArray we may use no-op; if itElement->itVarArray size might change */
1887    fprintf(file, " ||\n\t%s    %scount != %d", tab, string, howmany);
1888  if (arg->argPoly == argNULL)
1889    fprintf(file, " ||\n\t%s    %sdisposition != %s", tab, string, howstr);
1890  fprintf(file, ")\n");
1891  fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
1892
1893  if (IS_MULTIPLE_KPD(it))
1894    fprintf(file, "\t    }\n\t}\n");
1895}
1896
1897/*************************************************************
1898 *  Writes code to check that the type of each of the arguments
1899 *  in the reply message is what is expected. Called by
1900 *  WriteRoutine for each in && typed argument in the request message.
1901 *************************************************************/
1902static void
1903WriteTypeCheck(FILE *file, register argument_t *arg)
1904{
1905  fprintf(file, "#if\t__MigTypeCheck\n");
1906  (*arg->argKPD_TypeCheck)(file, arg);
1907  fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1908}
1909
1910static void
1911WritePackArgValueNormal(FILE *file, register argument_t *arg)
1912{
1913  register ipc_type_t *it = arg->argType;
1914
1915  if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
1916    if (it->itString) {
1917      /*
1918       * Copy variable-size C string with mig_strncpy.
1919       * Save the string length (+ 1 for trailing 0)
1920       * in the argument`s count field.
1921       */
1922      fprintf(file, "\tOutP->%s = mig_strncpy(OutP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argMsgField, arg->argVarName, it->itNumber);
1923    }
1924    else if (it->itNoOptArray)
1925      fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, %d);\n", arg->argMsgField, arg->argVarName, it->itTypeSize);
1926    else {
1927      register argument_t *count = arg->argCount;
1928      register ipc_type_t *btype = it->itElement;
1929      identifier_t newstr;
1930
1931      /* Note btype->itNumber == count->argMultiplier */
1932
1933      fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, ", arg->argMsgField, arg->argVarName);
1934      if (btype->itTypeSize > 1)
1935        fprintf(file, "%d * ", btype->itTypeSize);
1936      /* count is a akbVarNeeded if arg is akbVarNeeded */
1937      if (akCheck(count->argKind, akbVarNeeded))
1938        newstr = count->argVarName;
1939      else
1940        newstr = (identifier_t)strconcat("OutP->", count->argMsgField);
1941      fprintf(file, "%s);\n", newstr);
1942    }
1943  }
1944  else if (it->itOutTrans != strNULL)
1945    WriteCopyType(file, it, "OutP->%s", "/* %s */ %s(%s)", arg->argMsgField, it->itOutTrans, arg->argVarName);
1946  else
1947    WriteCopyType(file, it, "OutP->%s", "/* %s */ %s", arg->argMsgField, arg->argVarName);
1948}
1949
1950static void
1951WritePackArgValueVariable(FILE *file, register argument_t *arg)
1952{
1953  register ipc_type_t *it = arg->argType;
1954
1955  /*
1956   * only itString are treated here so far
1957   */
1958  if (it->itString) {
1959    /*
1960     * Emit logic to call strlen to calculate the size of the argument, and ensure that it fits within the 32-bit result field
1961     * in the Reply, when targeting a 64-bit architecture. If a 32-bit architecture is the target, we emit code to just call
1962     * strlen() directly (since it'll return a 32-bit value that is guaranteed to fit).
1963     */
1964    fputs("#ifdef __LP64__\n", file);
1965    fprintf(file, "\t{\n"
1966                  "\t\t" "size_t strLength = strlen(OutP->%s) + 1;\n", arg->argMsgField);
1967    fputs(        "\t\t" "if (strLength > 0xffffffff)\n"
1968                  "\t\t\t"  "MIG_RETURN_ERROR(OutP, MIG_BAD_ARGUMENTS);\n", file);
1969    fprintf(file, "\t\t" "OutP->%s = (mach_msg_type_number_t) strLength;\n"
1970                  "\t}\n", arg->argCount->argMsgField);
1971    fputs("#else\n", file);
1972    fprintf(file, "\tOutP->%s = (mach_msg_type_number_t) strlen(OutP->%s) + 1;\n", arg->argCount->argMsgField, arg->argMsgField);
1973    fputs("#endif /* __LP64__ */\n", file);
1974
1975  }
1976}
1977
1978static void
1979WriteCopyArgValue(FILE *file, argument_t *arg)
1980{
1981  fprintf(file, "\n");
1982  WriteCopyType(file, arg->argType, "/* %d */ OutP->%s", "In%dP->%s", arg->argRequestPos, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
1983}
1984
1985static void
1986WriteInitArgValue(FILE *file, argument_t *arg)
1987{
1988  fprintf(file, "\n");
1989  fprintf(file, "\tOutP->%s = %s;\n\n", arg->argMsgField, arg->argVarName);
1990}
1991
1992/*
1993 * Calculate the size of a variable-length message field.
1994 */
1995static void
1996WriteArgSize(FILE *file, register argument_t *arg)
1997{
1998  register ipc_type_t *ptype = arg->argType;
1999  register int bsize = ptype->itElement->itTypeSize;
2000  register argument_t *count = arg->argCount;
2001
2002  /* If the base type size of the data field isn`t a multiple of 4,
2003   we have to round up. */
2004  if (bsize % itWordAlign != 0)
2005    fprintf(file, "_WALIGN_");
2006
2007  /* Here, we generate ((value + %d) & ~%d). We have to put two (( at the
2008   * the beginning.
2009   */
2010  fprintf(file, "((");
2011  if (bsize > 1)
2012    fprintf(file, "%d * ", bsize);
2013  if (ptype->itString || !akCheck(count->argKind, akbVarNeeded))
2014    /* get count from descriptor in message */
2015    fprintf(file, "OutP->%s", count->argMsgField);
2016  else
2017    /* get count from argument */
2018    fprintf(file, "%s", count->argVarName);
2019
2020  /*
2021   * If the base type size is not a multiple of sizeof(natural_t),
2022   * we have to round up.
2023   */
2024  if (bsize % sizeof(natural_t) != 0)
2025    fprintf(file, " + %d) & ~%d)", (int)sizeof(natural_t)-1, (int)sizeof(natural_t)-1);
2026  else
2027    fprintf(file, "))");
2028}
2029
2030/*
2031 * Adjust message size and advance reply pointer.
2032 * Called after packing a variable-length argument that
2033 * has more arguments following.
2034 */
2035static void
2036WriteAdjustMsgSize(FILE *file, register argument_t *arg)
2037{
2038  register routine_t *rt = arg->argRoutine;
2039  register ipc_type_t *ptype = arg->argType;
2040
2041  /* There are more Out arguments.  We need to adjust msgh_size
2042     and advance OutP, so we save the size of the current field
2043     in msgh_size_delta. */
2044
2045  fprintf(file, "\tmsgh_size_delta = ");
2046  WriteArgSize(file, arg);
2047  fprintf(file, ";\n");
2048
2049  if (rt->rtNumReplyVar == 1) {
2050    /* We can still address the message header directly.  Fill
2051       in the size field. */
2052
2053    fprintf(file, "\tOutP->Head.msgh_size = ");
2054    rtMinReplySize(file, rt, "Reply");
2055    fprintf(file, " + msgh_size_delta;\n");
2056  }
2057  else if (arg->argReplyPos == 0) {
2058    /* First variable-length argument.  The previous msgh_size value
2059       is the minimum reply size. */
2060
2061    fprintf(file, "\tmsgh_size = ");
2062    rtMinReplySize(file, rt, "Reply");
2063    fprintf(file, " + msgh_size_delta;\n");
2064  }
2065  else
2066    fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
2067
2068  fprintf(file, "\tOutP = (Reply *) ((pointer_t) OutP + msgh_size_delta - %d);\n", ptype->itTypeSize + ptype->itPadSize);
2069}
2070
2071/*
2072 * Calculate the size of the message.  Called after the
2073 * last argument has been packed.
2074 */
2075static void
2076WriteFinishMsgSize(FILE *file, register argument_t *arg)
2077{
2078  /* No more Out arguments.  If this is the only variable Out
2079     argument, we can assign to msgh_size directly. */
2080
2081  if (arg->argReplyPos == 0) {
2082    fprintf(file, "\tOutP->Head.msgh_size = ");
2083    rtMinReplySize(file, arg->argRoutine, "Reply");
2084    fprintf(file, " + (");
2085    WriteArgSize(file, arg);
2086    fprintf(file, ");\n");
2087  }
2088  else {
2089    fprintf(file, "\tmsgh_size += ");
2090    WriteArgSize(file, arg);
2091    fprintf(file, ";\n");
2092  }
2093}
2094
2095/*
2096 * Handle reply arguments - fill in message types and copy arguments
2097 * that need to be copied.
2098 */
2099static void
2100WriteReplyArgs(FILE *file, register routine_t *rt)
2101{
2102  register argument_t *arg;
2103  register argument_t *lastVarArg;
2104
2105  /*
2106   * 1. The Kernel Processed Data
2107   */
2108  for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
2109    if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD))
2110      (*arg->argKPD_Pack)(file, arg);
2111  /*
2112   * 2. The Data Stream
2113   */
2114  lastVarArg = argNULL;
2115  for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)  {
2116    /*
2117     * Adjust message size and advance message pointer if
2118     * the last request argument was variable-length and the
2119     * request position will change.
2120     */
2121    if (lastVarArg != argNULL &&
2122        lastVarArg->argReplyPos < arg->argReplyPos) {
2123      WriteAdjustMsgSize(file, lastVarArg);
2124      lastVarArg = argNULL;
2125    }
2126
2127    if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVarNeeded))
2128      WritePackArgValueNormal(file, arg);
2129    else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable))
2130      WritePackArgValueVariable(file, arg);
2131
2132    if (akCheck(arg->argKind, akbReplyCopy))
2133      WriteCopyArgValue(file, arg);
2134    if (akCheck(arg->argKind, akbReplyInit))
2135      WriteInitArgValue(file, arg);
2136    /*
2137     * Remember whether this was variable-length.
2138     */
2139    if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable))
2140      lastVarArg = arg;
2141  }
2142  /*
2143   * Finish the message size.
2144   */
2145  if (lastVarArg != argNULL)
2146    WriteFinishMsgSize(file, lastVarArg);
2147}
2148
2149static void
2150WriteFieldDecl(FILE *file, argument_t *arg)
2151{
2152  if (akCheck(arg->argKind, akbSendKPD) ||
2153      akCheck(arg->argKind, akbReturnKPD))
2154    WriteFieldDeclPrim(file, arg, FetchKPDType);
2155  else
2156    WriteFieldDeclPrim(file, arg, FetchServerType);
2157}
2158
2159static void
2160InitKPD_Disciplines(argument_t *args)
2161{
2162  argument_t *arg;
2163  extern void KPD_noop();
2164  extern void KPD_error();
2165  extern void WriteTemplateKPD_port();
2166  extern void WriteTemplateKPD_ool();
2167  extern void WriteTemplateKPD_oolport();
2168
2169  /*
2170   * WriteInitKPD_port, WriteKPD_port,  WriteExtractKPD_port,
2171   * WriteInitKPD_ool, WriteKPD_ool,  WriteExtractKPD_ool,
2172   * WriteInitKPD_oolport, WriteKPD_oolport,  WriteExtractKPD_oolport
2173   * are local to this module (which is the reason why this initialization
2174   * takes place here rather than in utils.c).
2175   * Common routines for user and server will be established SOON, and
2176   * all of them (including the initialization) will be transfert to
2177   * utils.c
2178   * All the KPD disciplines are defaulted to be KPD_error().
2179   * Note that akbSendKPD and akbReturnKPd are not exclusive,
2180   * because of inout type of parameters.
2181   */
2182  for (arg = args; arg != argNULL; arg = arg->argNext)
2183    if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD))
2184      switch (arg->argKPD_Type) {
2185
2186        case MACH_MSG_PORT_DESCRIPTOR:
2187          if akCheck(arg->argKind, akbSendKPD) {
2188            arg->argKPD_Extract =
2189            (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_port : WriteExtractArgValue;
2190            arg->argKPD_TypeCheck = WriteTCheckKPD_port;
2191          }
2192          if akCheck(arg->argKind, akbReturnKPD) {
2193            arg->argKPD_Template = WriteTemplateKPD_port;
2194            arg->argKPD_Init = WriteInitKPD_port;
2195            arg->argKPD_Pack = WriteKPD_port;
2196          }
2197          break;
2198
2199        case MACH_MSG_OOL_DESCRIPTOR:
2200          if akCheck(arg->argKind, akbSendKPD) {
2201            arg->argKPD_Extract =
2202            (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_ool : WriteExtractArgValue;
2203            arg->argKPD_TypeCheck = WriteTCheckKPD_ool;
2204          }
2205          if akCheck(arg->argKind, akbReturnKPD) {
2206            arg->argKPD_Template = WriteTemplateKPD_ool;
2207            arg->argKPD_Init = WriteInitKPD_ool;
2208            arg->argKPD_Pack = WriteKPD_ool;
2209          }
2210          break;
2211
2212        case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2213          if akCheck(arg->argKind, akbSendKPD) {
2214            arg->argKPD_Extract =
2215            (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_oolport : WriteExtractArgValue;
2216            arg->argKPD_TypeCheck = WriteTCheckKPD_oolport;
2217          }
2218          if akCheck(arg->argKind, akbReturnKPD) {
2219            arg->argKPD_Template = WriteTemplateKPD_oolport;
2220            arg->argKPD_Init = WriteInitKPD_oolport;
2221            arg->argKPD_Pack = WriteKPD_oolport;
2222          }
2223          break;
2224
2225        default:
2226          printf("MiG internal error: type of kernel processed data unknown\n");
2227          exit(1);
2228      }   /* end of switch */
2229}
2230
2231static void WriteStringTerminatorCheck(FILE *file, routine_t *rt)
2232{
2233  // generate code to verify that the length of a C string is not greater than the size of the
2234  // buffer in which it is stored.
2235  argument_t  *argPtr;
2236  int msg_limit_calculated = FALSE;
2237  int found_string_argument = FALSE;
2238  int variable_length_args_present = (rt->rtMaxRequestPos > 0);
2239
2240  // scan through arguments to see if there are any strings
2241  for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2242    if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) {
2243      found_string_argument = TRUE;
2244      break;
2245    }
2246  }
2247
2248  if (found_string_argument) {
2249    // create a new scope, for local variables
2250    fputs("#if __MigTypeCheck\n" "\t" "{" "\n", file);
2251
2252    for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2253      if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) {
2254        //fprintf(stderr, "### found itString: variable name = %s, max length = %d\n", argPtr->argName, argPtr->argType->itNumber);
2255
2256        if (!msg_limit_calculated) {
2257          msg_limit_calculated = TRUE; // only need to do this once
2258          fputs("\t\t" "char * msg_limit = ((char *) In0P) + In0P->Head.msgh_size;\n", file);
2259          if (IsKernelServer) {
2260            fputs("#if __MigKernelSpecificCode\n", file);
2261            fputs("\t\t" "size_t strnlen_limit;" "\n", file);
2262            fputs("#else\n", file);
2263          }
2264          fputs("\t\t" "size_t memchr_limit;" "\n", file);
2265          if (IsKernelServer) {
2266            fputs("#endif /* __MigKernelSpecificCode */" "\n", file);
2267          }
2268          fputc('\n', file);
2269        }
2270
2271        // I would really prefer to use strnlen() here, to ensure that the byte scanning logic does not extend beyond
2272        // the end of the buffer, but it's not necessarily guaranteed to be available. Instead, I'll use memchr(),
2273        // and let it look for the terminating null byte.
2274        // (later...)
2275        // It turns out that the kernel does not have memchr() available, but strnlen() IS available, so we'll just
2276        // have to emit some conditional code to use the appropriate runtime environment scanning function.
2277        //
2278        if (IsKernelServer) {
2279          fputs("#if __MigKernelSpecificCode\n", file);
2280          fputs("\t\t" "strnlen_limit = min((msg_limit - ", file);
2281          // If there are variable-length arguments within the message, the proper (adjusted)
2282          // pointers must be used to access those strings
2283          fprintf(file, "In%dP->%s),  %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
2284          fputs("\t\t" "if (", file);
2285          fprintf(file, "( strnlen(In%dP->%s, strnlen_limit) >= %d + 1 )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
2286          fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file);
2287          fputs("#else\n", file);
2288        }
2289        // If there are variable-length arguments within the message, the proper (adjusted)
2290        // pointers must be used to access those strings
2291        fprintf(file, "\t\t" "memchr_limit = min((msg_limit - In%dP->%s),  %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
2292        fputs("\t\t" "if (", file);
2293        fprintf(file, "( memchr(In%dP->%s, '\\0', memchr_limit) == NULL )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName);
2294        fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file);
2295        if (IsKernelServer) {
2296          fputs("#endif /* __MigKernelSpecificCode */" "\n", file);
2297        }
2298      }
2299    }
2300    fputs("\t" "}" "\n" "#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); // terminate new scope
2301  }
2302
2303  return;
2304}
2305
2306static void
2307WriteOOLSizeCheck(FILE *file, routine_t *rt)
2308{
2309  /* Emit code to validate the actual size of ool data vs. the reported size */
2310
2311  argument_t  *argPtr;
2312  boolean_t   openedTypeCheckConditional = FALSE;
2313
2314  // scan through arguments to see if there are any ool data blocks
2315  for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2316    if (akCheck(argPtr->argKind, akbSendKPD) && (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR)) {
2317      register ipc_type_t *it = argPtr->argType;
2318      char *tab, string[MAX_STR_LEN];
2319      boolean_t test;
2320      argument_t  *argCountPtr;
2321
2322      if ( !openedTypeCheckConditional ) {
2323        openedTypeCheckConditional = TRUE;
2324        fputs("#if __MigTypeCheck\n", file);
2325      }
2326
2327      if (IS_MULTIPLE_KPD(it)) {
2328        WriteKPD_Iterator(file, TRUE, FALSE, argPtr, TRUE);
2329        tab = "\t\t\t";
2330        sprintf(string, "ptr->");
2331        test = !it->itVarArray && !it->itElement->itVarArray;
2332        it = it->itElement; // point to element descriptor, so size calculation is correct
2333        argCountPtr = argPtr->argSubCount;
2334      }
2335      else {
2336        tab = "";
2337        sprintf(string, "In%dP->%s.", argPtr->argRequestPos, argPtr->argMsgField);
2338        test = !it->itVarArray;
2339        argCountPtr = argPtr->argCount;
2340      }
2341
2342      if (!test) {
2343        int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1;
2344        fprintf(file, "\t%s" "if (%ssize ", tab, string);
2345        if (multiplier > 1)
2346          fprintf(file, "/ %d ", multiplier);
2347	fprintf(file,"!= In%dP->%s%s)\n", argCountPtr->argRequestPos, argCountPtr->argVarName, IS_MULTIPLE_KPD(it) ? "[i]" : "");
2348
2349        fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
2350      }
2351
2352      if (IS_MULTIPLE_KPD(it))
2353        fprintf(file, "\t    }\n\t}\n");
2354
2355    }
2356  }
2357
2358  if ( openedTypeCheckConditional )
2359    fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file);
2360}
2361
2362
2363void
2364WriteCheckRequest(FILE *file, routine_t *rt)
2365{
2366  int i;
2367
2368  /* initialize the disciplines for the handling of KPDs */
2369  InitKPD_Disciplines(rt->rtArgs);
2370
2371  fprintf(file, "\n");
2372  fprintf(file, "#if ( __MigTypeCheck ");
2373  if (CheckNDR)
2374	  fprintf(file, "|| __NDR_convert__ ");
2375  fprintf(file, ")\n");
2376  fprintf(file, "#if __MIG_check__Request__%s_subsystem__\n", SubsystemName);
2377  fprintf(file, "#if !defined(__MIG_check__Request__%s_t__defined)\n", rt->rtName);
2378  fprintf(file, "#define __MIG_check__Request__%s_t__defined\n", rt->rtName);
2379  if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) {
2380    WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgDecl, akbSendNdr, "", "");
2381    WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgDecl, akbSendNdr, "", "");
2382    WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgDecl, akbSendNdr, "", "");
2383  }
2384  fprintf(file, "\n");
2385  fprintf(file, "mig_internal kern_return_t __MIG_check__Request__%s_t(__attribute__((__unused__)) __Request__%s_t *In0P", rt->rtName, rt->rtName);
2386  for (i = 1; i <= rt->rtMaxRequestPos; i++)
2387    fprintf(file, ", __attribute__((__unused__)) __Request__%s_t **In%dPP", rt->rtName, i);
2388  fprintf(file, ")\n{\n");
2389
2390  fprintf(file, "\n\ttypedef __Request__%s_t __Request;\n", rt->rtName);
2391  for (i = 1; i <= rt->rtMaxRequestPos; i++)
2392    fprintf(file, "\t__Request *In%dP;\n", i);
2393  if (rt->rtNumRequestVar > 0) {
2394    fprintf(file, "#if\t__MigTypeCheck\n");
2395    fprintf(file, "\tunsigned int msgh_size;\n");
2396    fprintf(file, "#endif\t/* __MigTypeCheck */\n");
2397  }
2398  if (rt->rtMaxRequestPos > 0)
2399    fprintf(file, "\tunsigned int msgh_size_delta;\n");
2400  if (rt->rtNumRequestVar > 0 || rt->rtMaxRequestPos > 0)
2401    fprintf(file, "\n");
2402
2403  WriteCheckHead(file, rt);
2404
2405  WriteList(file, rt->rtArgs, WriteTypeCheck, akbSendKPD, "\n", "\n");
2406
2407  {
2408    argument_t *arg, *lastVarArg;
2409
2410    lastVarArg = argNULL;
2411    for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2412      if (lastVarArg != argNULL &&
2413          lastVarArg->argRequestPos < arg->argRequestPos) {
2414        WriteAdjustRequestMsgPtr(file, lastVarArg);
2415        lastVarArg = argNULL;
2416      }
2417      if (akCheckAll(arg->argKind, akbSendRcv|akbSendBody)) {
2418        if (akCheck(arg->argKind, akbVariable)) {
2419          WriteCheckMsgSize(file, arg);
2420          lastVarArg = arg;
2421        }
2422      }
2423    }
2424  }
2425
2426  if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) {
2427    fprintf(file, "#if\t");
2428    WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgCond, akbSendNdr, " || \\\n\t", "\n");
2429    fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep) {\n");
2430    WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgUse, akbSendNdr, "", "");
2431    fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n");
2432
2433    WriteOOLSizeCheck(file, rt);
2434
2435    fprintf(file, "#if\t");
2436    WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgCond, akbSendNdr, " || \\\n\t", "\n");
2437    fprintf(file, "\tif (In0P->NDR.char_rep != NDR_record.char_rep) {\n");
2438    WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgUse, akbSendNdr, "", "");
2439    fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n");
2440
2441    fprintf(file, "#if\t");
2442    WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgCond, akbSendNdr, " || \\\n\t", "\n");
2443    fprintf(file, "\tif (In0P->NDR.float_rep != NDR_record.float_rep) {\n");
2444    WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgUse, akbSendNdr, "", "");
2445    fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n");
2446  } else {
2447   WriteOOLSizeCheck(file, rt);
2448  }
2449
2450  WriteStringTerminatorCheck(file, rt);
2451
2452  fprintf(file, "\treturn MACH_MSG_SUCCESS;\n");
2453  fprintf(file, "}\n");
2454  fprintf(file, "#endif /* !defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName);
2455  fprintf(file, "#endif /* __MIG_check__Request__%s_subsystem__ */\n", SubsystemName);
2456  fprintf(file, "#endif /* ( __MigTypeCheck ");
2457  if (CheckNDR)
2458	  fprintf(file, "|| __NDR_convert__ ");
2459  fprintf(file, ") */\n");
2460  fprintf(file, "\n");
2461}
2462
2463void
2464WriteCheckRequestCall(FILE *file, routine_t *rt)
2465{
2466  int i;
2467
2468  fprintf(file, "\n");
2469  fprintf(file, "#if\tdefined(__MIG_check__Request__%s_t__defined)\n", rt->rtName);
2470  fprintf(file, "\tcheck_result = __MIG_check__Request__%s_t((__Request *)In0P", rt->rtName);
2471  for (i = 1; i <= rt->rtMaxRequestPos; i++)
2472    fprintf(file, ", (__Request **)&In%dP", i);
2473  fprintf(file, ");\n");
2474  fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS)\n");
2475  fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, check_result); }\n");
2476  fprintf(file, "#endif\t/* defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName);
2477  fprintf(file, "\n");
2478}
2479
2480void
2481WriteCheckRequests(FILE *file, statement_t *stats)
2482{
2483  statement_t *stat;
2484
2485  for (stat = stats; stat != stNULL; stat = stat->stNext)
2486    if (stat->stKind == skRoutine)
2487      WriteCheckRequest(file, stat->stRoutine);
2488}
2489
2490static void
2491WriteRoutine(FILE *file, register routine_t *rt)
2492{
2493  /*  Declare the server work function: */
2494  if (ServerHeaderFileName == strNULL)
2495    WriteServerRoutine(file, rt);
2496
2497  fprintf(file, "\n");
2498
2499  fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
2500  fprintf(file, "mig_internal novalue _X%s\n", rt->rtName);
2501  if (BeAnsiC) {
2502    fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
2503  }
2504  else {
2505    fprintf(file, "#if\t%s\n", NewCDecl);
2506    fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
2507    fprintf(file, "#else\n");
2508    fprintf(file, "\t(InHeadP, OutHeadP)\n");
2509    fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
2510    fprintf(file, "#endif\t/* %s */\n", NewCDecl);
2511  }
2512
2513  fprintf(file, "{\n");
2514  WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, TRUE, rt->rtServerImpl, FALSE);
2515  fprintf(file, "\ttypedef __Request__%s_t __Request;\n", rt->rtName);
2516  fprintf(file, "\ttypedef __Reply__%s_t Reply;\n\n", rt->rtName);
2517
2518  /*
2519   * Define a Minimal Reply structure to be used in case of errors
2520   */
2521  fprintf(file, "\t/*\n");
2522  fprintf(file, "\t * typedef struct {\n");
2523  fprintf(file, "\t * \tmach_msg_header_t Head;\n");
2524  fprintf(file, "\t * \tNDR_record_t NDR;\n");
2525  fprintf(file, "\t * \tkern_return_t RetCode;\n");
2526  fprintf(file, "\t * } mig_reply_error_t;\n");
2527  fprintf(file, "\t */\n");
2528  fprintf(file, "\n");
2529
2530  WriteVarDecls(file, rt);
2531
2532  if (IsKernelServer) {
2533    fprintf(file, "#if\t__MigKernelSpecificCode\n");
2534    WriteList(file, rt->rtArgs, WriteTemplateDeclOut, akbReturnKPD, "\n", "\n");
2535    fprintf(file, "#else\n");
2536  }
2537  WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbReturnKPD, "\n", "\n");
2538  if (IsKernelServer) {
2539    fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
2540  }
2541  WriteRetCode(file, rt->rtRetCode);
2542  WriteList(file, rt->rtArgs, WriteLocalVarDecl, akbVarNeeded | akbServerArg, ";\n", ";\n\n");
2543  WriteApplMacro(file, "Rcv", "Declare", rt);
2544  WriteApplMacro(file, "Rcv", "Before", rt);
2545  if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
2546    WriteRetCArgCheckError(file, rt);
2547    if (rt->rtServerImpl)
2548      WriteCheckTrailerHead(file, rt, FALSE);
2549    WriteServerCall(file, rt, WriteConditionalCallArg);
2550    WriteRetCArgFinishError(file, rt);
2551  }
2552
2553  WriteCheckRequestCall(file, rt);
2554  WriteCheckRequestTrailerArgs(file, rt);
2555
2556  /*
2557   * Initialize the KPD records in the Reply structure with the
2558   * templates. We do this beforehand because the call to the procedure
2559   * will overwrite some of the values (after the call it would be impossible
2560   * to initialize the KPD records from the static Templates, because we
2561   * would lose data).
2562   */
2563  WriteList(file, rt->rtArgs, WriteInitKPDValue, akbReturnKPD, "\n", "\n");
2564
2565  WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", "");
2566
2567  if (UseEventLogger)
2568    WriteLogMsg(file, rt, LOG_SERVER, LOG_REQUEST);
2569
2570  WriteServerCall(file, rt, WriteServerCallArg);
2571
2572  WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", "");
2573
2574  /*
2575   * For one-way routines, it doesn`t make sense to check the return
2576   * code, because we return immediately afterwards.  However,
2577   * kernel servers may want to deallocate port arguments - and the
2578   * deallocation must not be done if the return code is not KERN_SUCCESS.
2579   */
2580  if (rt->rtOneWay || rt->rtNoReplyArgs) {
2581    if (IsKernelServer) {
2582      fprintf(file,"#if\t__MigKernelSpecificCode\n");
2583      if (rtCheckMaskFunction(rt->rtArgs, akbSendKPD, CheckDestroyPortArg)) {
2584        WriteCheckReturnValue(file, rt);
2585      }
2586      WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", "");
2587      fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
2588    }
2589    /* although we have an empty reply, we still have to make sure that
2590     some fields such as NDR get properly initialized */
2591    if (!rt->rtOneWay)
2592      WriteList(file, rt->rtArgs, WriteInitArgValue, akbReplyInit, "\n", "\n");
2593  }
2594  else {
2595    WriteCheckReturnValue(file, rt);
2596
2597    if (IsKernelServer) {
2598      fprintf(file,"#if\t__MigKernelSpecificCode\n");
2599      WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", "");
2600      fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
2601    }
2602    WriteReplyArgs(file, rt);
2603    WriteReplyInit(file, rt);
2604    if (!rt->rtSimpleReply)
2605      fprintf(file, "\tOutP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtReplyKPDs);
2606  }
2607  if (UseEventLogger)
2608    WriteLogMsg(file, rt, LOG_SERVER, LOG_REPLY);
2609
2610  WriteApplMacro(file, "Rcv", "After", rt);
2611  fprintf(file, "}\n");
2612}
2613
2614void
2615WriteServer(FILE *file, statement_t *stats)
2616{
2617  register statement_t *stat;
2618
2619  WriteProlog(file, stats);
2620  if (BeAnsiC)
2621    WriteForwardDeclarations(file, stats);
2622  for (stat = stats; stat != stNULL; stat = stat->stNext)
2623    switch (stat->stKind) {
2624
2625      case skRoutine:
2626        WriteCheckRequest(file, stat->stRoutine);
2627        WriteRoutine(file, stat->stRoutine);
2628        break;
2629
2630      case skIImport:
2631      case skImport:
2632      case skSImport:
2633      case skDImport:
2634      case skUImport:
2635        break;
2636
2637      default:
2638        fatal("WriteServer(): bad statement_kind_t (%d)",
2639              (int) stat->stKind);
2640    }
2641  WriteDispatcher(file, stats);
2642}
2643