]> git.cameronkatri.com Git - apple_cmds.git/blob - bootstrap_cmds/migcom.tproj/user.c
bootstrap_cmds: Update to 121.100.1
[apple_cmds.git] / bootstrap_cmds / migcom.tproj / user.c
1 /*
2 * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23 /*
24 * Mach Operating System
25 * Copyright (c) 1991,1990 Carnegie Mellon University
26 * All Rights Reserved.
27 *
28 * Permission to use, copy, modify and distribute this software and its
29 * documentation is hereby granted, provided that both the copyright
30 * notice and this permission notice appear in all copies of the
31 * software, derivative works or modified versions, and any portions
32 * thereof, and that both notices appear in supporting documentation.
33 *
34 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
35 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
36 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
37 *
38 * Carnegie Mellon requests users of this software to return to
39 *
40 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
41 * School of Computer Science
42 * Carnegie Mellon University
43 * Pittsburgh PA 15213-3890
44 *
45 * any improvements or extensions that they make and grant Carnegie the
46 * rights to redistribute these changes.
47 */
48
49 #include <stdlib.h>
50 #include <assert.h>
51
52 #include <mach/message.h>
53 #include "write.h"
54 #include "error.h"
55 #include "utils.h"
56 #include "global.h"
57
58 #ifndef USE_IMMEDIATE_SEND_TIMEOUT
59 #define USE_IMMEDIATE_SEND_TIMEOUT 0
60 #endif
61
62 char *MessAllocRoutine = "mig_user_allocate";
63 char *MessFreeRoutine = "mig_user_deallocate";
64
65 char stRetCode[] = "ReturnValue";
66 char stRetNone[] = "";
67
68 void WriteLogDefines(FILE *file, string_t who);
69 void WriteIdentificationString(FILE *file);
70
71 static void
72 WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t overwrite, boolean_t varying, argument_t *arg, boolean_t bracket)
73 {
74 ipc_type_t *it = arg->argType;
75 char string[MAX_STR_LEN];
76
77 fprintf(file, "\t{\n");
78 fprintf(file, "\t %s\t*ptr;\n", it->itKPDType);
79 fprintf(file, "\t int\ti");
80 if (varying && !in)
81 fprintf(file, ", j");
82 fprintf(file, ";\n\n");
83
84 if (in)
85 sprintf(string, "InP");
86 else if (overwrite)
87 sprintf(string, "InOvTemplate");
88 else
89 sprintf(string, "Out%dP", arg->argRequestPos);
90
91 fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField);
92
93 if (varying) {
94 argument_t *count = arg->argCount;
95 char *cref = count->argByReferenceUser ? "*" : "";
96
97 if (in || overwrite) {
98 fprintf(file, "\t if (%s%s > %d)\n", cref, count->argVarName, it->itKPD_Number);
99 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
100 fprintf(file, "\t for (i = 0; i < %s%s; ptr++, i++) %s\n", cref, count->argVarName, (bracket) ? "{" : "");
101 }
102 else {
103 fprintf(file, "\t j = min(Out%dP->%s, %s%s);\n", count->argReplyPos, count->argVarName, cref, count->argVarName);
104 fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n",(bracket) ? "{" : "");
105 }
106 }
107 else
108 fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : "");
109 }
110
111 /*************************************************************
112 * Writes the standard includes. The subsystem specific
113 * includes are in <SubsystemName>.h and writen by
114 * header:WriteHeader. Called by WriteProlog.
115 *************************************************************/
116 static void
117 WriteMyIncludes(FILE *file, statement_t *stats)
118 {
119 #ifdef MIG_KERNEL_PORT_CONVERSION
120 if (IsKernelServer)
121 {
122 /*
123 * We want to get the user-side definitions of types
124 * like task_t, ipc_space_t, etc. in mach/mach_types.h.
125 */
126
127 fprintf(file, "#undef\tMACH_KERNEL\n");
128
129 if (InternalHeaderFileName != strNULL)
130 {
131 char *cp;
132
133 /* Strip any leading path from InternalHeaderFileName. */
134 cp = strrchr(InternalHeaderFileName, '/');
135 if (cp == 0)
136 cp = InternalHeaderFileName;
137 else
138 cp++; /* skip '/' */
139 fprintf(file, "#include \"%s\"\n", cp);
140 }
141 }
142 #endif
143
144 if (UserHeaderFileName == strNULL || UseSplitHeaders)
145 WriteIncludes(file, TRUE, FALSE);
146 if (UserHeaderFileName != strNULL)
147 {
148 char *cp;
149
150 /* Strip any leading path from UserHeaderFileName. */
151 cp = strrchr(UserHeaderFileName, '/');
152 if (cp == 0)
153 cp = UserHeaderFileName;
154 else
155 cp++; /* skip '/' */
156 fprintf(file, "#include \"%s\"\n", cp);
157 }
158 if (UseSplitHeaders)
159 WriteImplImports(file, stats, TRUE);
160
161 if (UseEventLogger) {
162 if (IsKernelUser) {
163 fprintf(file, "#if\t__MigKernelSpecificCode\n");
164 fprintf(file, "#include <mig_debug.h>\n");
165 fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
166 }
167 fprintf(file, "#if MIG_DEBUG\n");
168 fprintf(file, "#include <mach/mig_log.h>\n");
169 fprintf(file, "#endif /* MIG_DEBUG */\n");
170 }
171 if (HasConsumeOnSendError && !IsKernelUser) {
172 fprintf(file, "#include <mach/mach.h>\n");
173 }
174 if (BeLint) {
175 fprintf(file, "/* LINTLIBRARY */\n");
176 }
177 fprintf(file, "\n");
178 if (!BeAnsiC) {
179 fprintf(file, "#if\t%s\n", NewCDecl);
180 fprintf(file, "#else\t/* %s */\n", NewCDecl);
181 fprintf(file, "extern mach_port_t mig_get_reply_port();\n");
182 fprintf(file, "extern void mig_dealloc_reply_port();\n");
183 fprintf(file, "extern char *%s();\n", MessAllocRoutine);
184 fprintf(file, "extern void %s();\n", MessFreeRoutine);
185 fprintf(file, "#endif\t/* %s */\n", NewCDecl);
186 }
187 if (HasUseSpecialReplyPort) {
188 fprintf(file, "\n");
189 fprintf(file, "#include <TargetConditionals.h>\n");
190 fprintf(file, "#include <mach/mach_sync_ipc.h>\n");
191 fprintf(file, "#ifndef __MigSpecialReplyPortMsgOption\n");
192 fprintf(file, "#define __MigSpecialReplyPortMsgOption "
193 "(MACH_SEND_SYNC_OVERRIDE|MACH_SEND_SYNC_USE_THRPRI|MACH_RCV_SYNC_WAIT)\n");
194 fprintf(file, "#endif /* __MigSpecialReplyPortMsgOption */\n");
195 }
196 /*
197 * extern the definition of mach_msg_destroy
198 * (to avoid inserting mach/mach.h everywhere)
199 */
200 fprintf(file, "/* TODO: #include <mach/mach.h> */\n");
201 fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
202 fprintf(file, "extern void mach_msg_destroy(mach_msg_header_t *);\n");
203 fprintf(file, "#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
204
205 fprintf(file, "\n");
206 }
207
208 static void
209 WriteGlobalDecls(FILE *file)
210 {
211 if (RCSId != strNULL)
212 WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId);
213
214 fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
215 fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
216 fprintf(file, "\n");
217 if (UseEventLogger)
218 WriteLogDefines(file, "MACH_MSG_LOG_USER");
219 fprintf(file, "\n");
220 }
221
222 static void
223 WriteOneMachErrorDefine(FILE *file, char *name, boolean_t timeout, boolean_t SpecialReplyPort)
224 {
225 fprintf(file, "#ifndef\t%s\n", name);
226 fprintf(file, "#define\t%s(_R_) { \\\n", name);
227 fprintf(file, "\tswitch (_R_) { \\\n");
228 fprintf(file, "\tcase MACH_SEND_INVALID_DATA: \\\n");
229 fprintf(file, "\tcase MACH_SEND_INVALID_DEST: \\\n");
230 fprintf(file, "\tcase MACH_SEND_INVALID_HEADER: \\\n");
231 if (!SpecialReplyPort) {
232 fprintf(file, "\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n");
233 }
234 fprintf(file, "\t\tbreak; \\\n");
235 if (timeout) {
236 fprintf(file, "\tcase MACH_SEND_TIMED_OUT: \\\n");
237 fprintf(file, "\tcase MACH_RCV_TIMED_OUT: \\\n");
238 }
239 fprintf(file, "\tdefault: \\\n");
240 if (SpecialReplyPort) {
241 fprintf(file, "\t\tmig_dealloc_special_reply_port(InP->Head.msgh_reply_port); \\\n");
242 } else {
243 fprintf(file, "\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n");
244 }
245 fprintf(file, "\t} \\\n}\n");
246 fprintf(file, "#endif\t/* %s */\n", name);
247 fprintf(file, "\n");
248 }
249
250 static void
251 WriteMachErrorDefines(FILE *file)
252 {
253 WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeout", TRUE, FALSE);
254 WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeout", FALSE, FALSE);
255 if (HasUseSpecialReplyPort) {
256 WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeoutSRP", TRUE, TRUE);
257 WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeoutSRP", FALSE, TRUE);
258 }
259 }
260
261 static void
262 WriteMIGCheckDefines(FILE *file)
263 {
264 fprintf(file, "#define\t__MIG_check__Reply__%s_subsystem__ 1\n", SubsystemName);
265 fprintf(file, "\n");
266 }
267
268 static void
269 WriteNDRDefines(FILE *file)
270 {
271 fprintf(file, "#define\t__NDR_convert__Reply__%s_subsystem__ 1\n", SubsystemName);
272 fprintf(file, "#define\t__NDR_convert__mig_reply_error_subsystem__ 1\n");
273 fprintf(file, "\n");
274 }
275
276 /*************************************************************
277 * Writes the standard #includes, #defines, and
278 * RCS declaration. Called by WriteUser.
279 *************************************************************/
280 static void
281 WriteProlog(FILE *file, statement_t *stats)
282 {
283 WriteIdentificationString(file);
284 WriteMIGCheckDefines(file);
285 if (CheckNDR)
286 WriteNDRDefines(file);
287 WriteMyIncludes(file, stats);
288 WriteBogusDefines(file);
289 WriteMachErrorDefines(file);
290 WriteApplDefaults(file, "Send");
291 WriteGlobalDecls(file);
292 }
293
294 /*ARGSUSED*/
295 static void
296 WriteEpilog(FILE *file)
297 {
298 /* nothing to see here, move along... */
299 }
300
301 static string_t
302 WriteHeaderPortType(argument_t *arg)
303 {
304 if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC)
305 return arg->argPoly->argVarName;
306 else
307 return arg->argType->itInNameStr;
308 }
309
310 static void
311 WriteRequestHead(FILE *file, routine_t *rt)
312 {
313 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest)
314 fprintf(file, "ready_to_send:\n");
315
316 if (rt->rtMaxRequestPos > 0) {
317 if (rt->rtOverwrite)
318 fprintf(file, "\tInP = &MessRequest;\n");
319 else
320 fprintf(file, "\tInP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->"));
321 }
322
323 fprintf(file, "\tInP->Head.msgh_bits =");
324 if (rt->rtRetCArg == argNULL && !rt->rtSimpleRequest)
325 fprintf(file, " MACH_MSGH_BITS_COMPLEX|");
326 fprintf(file, "\n");
327 fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n", WriteHeaderPortType(rt->rtRequestPort), WriteHeaderPortType(rt->rtReplyPort));
328 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
329 fprintf(file, "\tif (!%s)\n", rt->rtRetCArg->argVarName);
330 fprintf(file, "\t\tInP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
331 }
332
333
334 fprintf(file, "\t/* msgh_size passed as argument */\n");
335
336 /*
337 * KernelUser stubs need to cast the request and reply ports
338 * from ipc_port_t to mach_port_t.
339 */
340
341 #ifdef MIG_KERNEL_PORT_CONVERSION
342 if (IsKernelUser)
343 fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName);
344 else
345 #endif
346 fprintf(file, "\tInP->%s = %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName);
347
348 if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) {
349 #ifdef MIG_KERNEL_PORT_CONVERSION
350 if (IsKernelUser)
351 fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName);
352 else
353 #endif
354 fprintf(file, "\tInP->%s = %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName);
355 }
356 else if (rt->rtOneWay)
357 fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n", rt->rtReplyPort->argMsgField);
358 else if (rt->rtUseSpecialReplyPort)
359 fprintf(file, "\tInP->%s = mig_get_special_reply_port();\n", rt->rtReplyPort->argMsgField);
360 else
361 fprintf(file, "\tInP->%s = mig_get_reply_port();\n", rt->rtReplyPort->argMsgField);
362
363 fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase);
364 fprintf(file, "\tInP->Head.msgh_reserved = 0;\n");
365
366
367 if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) {
368 fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n");
369 fprintf(file, "#ifdef USING_VOUCHERS\n");
370 fprintf(file, "\tif (voucher_mach_msg_set != NULL) {\n");
371 fprintf(file, "\t\tvoucher_mach_msg_set(&InP->Head);\n");
372 fprintf(file, "\t}\n");
373 fprintf(file, "#endif // USING_VOUCHERS\n");
374 fprintf(file, "\t\n/* END VOUCHER CODE */\n");
375 }
376 }
377
378 /*************************************************************
379 * Writes declarations for the message types, variables
380 * and return variable if needed. Called by WriteRoutine.
381 *************************************************************/
382 static void
383 WriteVarDecls(FILE *file, routine_t *rt)
384 {
385 int i;
386
387 if (rt->rtOverwrite) {
388 fprintf(file, "\tRequest MessRequest;\n");
389 fprintf(file, "\tRequest *InP = &MessRequest;\n\n");
390
391 fprintf(file, "\tunion {\n");
392 fprintf(file, "\t\tOverwriteTemplate In;\n");
393 fprintf(file, "\t\tReply Out;\n");
394 fprintf(file, "\t} MessReply;\n");
395
396 fprintf(file, "\tOverwriteTemplate *InOvTemplate = &MessReply.In;\n");
397 fprintf(file, "\tReply *Out0P = &MessReply.Out;\n");
398 for (i = 1; i <= rt->rtMaxReplyPos; i++)
399 fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i);
400 }
401 else {
402 if (rtMessOnStack(rt))
403 fprintf(file, "\tunion {\n");
404 else
405 fprintf(file, "\tunion %sMessU {\n", rt->rtName);
406 fprintf(file, "\t\tRequest In;\n");
407 if (!rt->rtOneWay)
408 fprintf(file, "\t\tReply Out;\n");
409 if (rtMessOnStack(rt))
410 fprintf(file, "\t} Mess;\n");
411 else
412 fprintf(file, "\t} *Mess = (union %sMessU *) %s(sizeof(*Mess));\n",
413 rt->rtName, MessAllocRoutine);
414 fprintf(file, "\n");
415
416 fprintf(file, "\tRequest *InP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->"));
417 if (!rt->rtOneWay) {
418 fprintf(file, "\tReply *Out0P = &Mess%sOut;\n", (rtMessOnStack(rt) ? "." : "->"));
419 for (i = 1; i <= rt->rtMaxReplyPos; i++)
420 fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i);
421 }
422 }
423
424 fprintf(file, "\n");
425
426 fprintf(file, "\tmach_msg_return_t msg_result;\n");
427
428 /* if request is variable, we need msgh_size_delta and msgh_size */
429 if (rt->rtNumRequestVar > 0)
430 fprintf(file, "\tunsigned int msgh_size;\n");
431 if (rt->rtMaxRequestPos > 0)
432 fprintf(file, "\tunsigned int msgh_size_delta;\n");
433 if (rt->rtNumRequestVar > 1 || rt->rtMaxRequestPos > 0)
434 fprintf(file, "\n");
435
436 if (rt->rtUserImpl) {
437 fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n");
438 fprintf(file, "#if\t__MigTypeCheck\n");
439 fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n");
440 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
441 }
442 fprintf(file, "\n");
443 fprintf(file, "#ifdef\t__MIG_check__Reply__%s_t__defined\n", rt->rtName);
444 fprintf(file, "\tkern_return_t check_result;\n");
445 fprintf(file, "#endif\t/* __MIG_check__Reply__%s_t__defined */\n", rt->rtName);
446 fprintf(file, "\n");
447 WriteApplMacro(file, "Send", "Declare", rt);
448 fprintf(file, "\n");
449 }
450
451 static void
452 WriteReturn(FILE *file, routine_t *rt, char *before, char *value, char *after, boolean_t deallocate_mess)
453 {
454 if (rtMessOnStack(rt)) {
455 if (value != stRetCode) {
456 /* get the easy case (no braces needed) out of the way */
457 fprintf(file, "%sreturn%s%s;%s", before, (*value ? " " : ""), value, after);
458 return;
459 }
460 else {
461 fprintf(file, "%s{\n", before);
462 fprintf(file, "%s\treturn Out0P->RetCode;\n%s}%s", before, before, after);
463 return;
464 }
465 }
466
467 if (value == stRetCode) {
468 fprintf(file, "%s{\n%s\t%s ReturnValue;\n", before, before, ReturnTypeStr(rt));
469 fprintf(file, "%s\tReturnValue = Out0P->RetCode;\n%s\t", before, before);
470 }
471 else {
472 fprintf(file, "%s{ ", before);
473 }
474
475 if (deallocate_mess) {
476 fprintf(file, "%s((char *) Mess, sizeof(*Mess)); ", MessFreeRoutine);
477 }
478
479 if (value == stRetCode)
480 fprintf(file, "return ReturnValue;\n%s}%s", before, after);
481 else if (value == stRetNone)
482 fprintf(file, "return; }%s", after);
483 else
484 fprintf(file, "return %s; }%s", value, after);
485 }
486
487 static void
488 WriteRetCodeArg(FILE *file, routine_t *rt)
489 {
490 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
491 argument_t *arg = rt->rtRetCArg;
492
493 fprintf(file, "\tif (%s) {\n", arg->argVarName);
494 fprintf(file, "\t\t((mig_reply_error_t *)InP)->RetCode = %s;\n", arg->argVarName);
495 fprintf(file, "\t\t((mig_reply_error_t *)InP)->NDR = NDR_record;\n");
496 fprintf(file, "\t\tgoto ready_to_send;\n");
497 fprintf(file, "\t}\n\n");
498 }
499 }
500
501 /*************************************************************
502 * Writes the logic to check for a message send timeout, and
503 * deallocate any relocated ool data so as not to leak.
504 *************************************************************/
505 static void
506 WriteMsgCheckForSendErrors(FILE *file, routine_t *rt)
507 {
508 if (rt->rtConsumeOnSendError != ConsumeOnSendErrorAny && rt->rtWaitTime == argNULL) {
509 return;
510 }
511
512 if (rt->rtConsumeOnSendError == ConsumeOnSendErrorAny) {
513 // other errors mean the kernel consumed some of the rights
514 // and we can't possibly know if there's something left to destroy
515 fputs("\n"
516 "\t" "if (msg_result == MACH_SEND_INVALID_DEST ||" "\n"
517 "\t\t" "msg_result == MACH_SEND_TIMED_OUT) {" "\n", file);
518 } else {
519 fputs("\n"
520 "\t" "if (msg_result == MACH_SEND_TIMED_OUT) {" "\n", file);
521 }
522
523 if (rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) {
524 argument_t *arg_ptr;
525
526 // iterate over arg list
527 for (arg_ptr = rt->rtArgs; arg_ptr != NULL; arg_ptr = arg_ptr->argNext) {
528
529 // if argument contains ool data
530 if (akCheck(arg_ptr->argKind, akbSendKPD) && arg_ptr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
531 // generate code to test current arg address vs. address before the msg_send call
532 // if not at the same address, mig_deallocate the argument
533 fprintf(file, "\t\t" "if((vm_offset_t) InP->%s.address != (vm_offset_t) %s)\n",
534 arg_ptr->argVarName, arg_ptr->argVarName);
535 fprintf(file, "\t\t\t" "mig_deallocate((vm_offset_t) InP->%s.address, "
536 "(vm_size_t) InP->%s.size);\n", arg_ptr->argVarName, arg_ptr->argVarName);
537 }
538 }
539 } else {
540 /*
541 * The original MIG would leak most resources on send timeout without
542 * leaving a chance for callers to know how to dispose of most of the
543 * resources, as the caller can't possibly guess the new names
544 * picked during pseudo-receive.
545 */
546 if (IsKernelUser) {
547 fputs("#if\t__MigKernelSpecificCode" "\n", file);
548 fputs("\t\t" "mach_msg_destroy_from_kernel(&InP->Head);" "\n", file);
549 fputs("#endif\t/* __MigKernelSpecificCode */" "\n", file);
550 } else {
551 fputs("\t\t" "/* mach_msg_destroy doesn't handle the local port */" "\n", file);
552 fputs("\t\t" "switch (MACH_MSGH_BITS_LOCAL(InP->Head.msgh_bits)) {" "\n", file);
553 fputs("\t\t" "case MACH_MSG_TYPE_MOVE_SEND:" "\n", file);
554 fputs("\t\t\t" "mach_port_deallocate(mach_task_self(), InP->Head.msgh_local_port);" "\n", file);
555 fputs("\t\t\t" "break;" "\n", file);
556 fputs("\t\t" "}" "\n", file);
557 fputs("\t\t" "mach_msg_destroy(&InP->Head);" "\n", file);
558 }
559 }
560
561 fputs("\t" "}" "\n\n", file);
562 return;
563 }
564
565 /*************************************************************
566 * Writes the send call when there is to be no subsequent
567 * receive. Called by WriteRoutine SimpleRoutines
568 *************************************************************/
569 static void
570 WriteMsgSend(FILE *file, routine_t *rt)
571 {
572 char *SendSize = "";
573 char string[MAX_STR_LEN];
574
575 if (rt->rtNumRequestVar == 0)
576 SendSize = "(mach_msg_size_t)sizeof(Request)";
577 else
578 SendSize = "msgh_size";
579
580 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
581 sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
582 SendSize = strconcat(string, SendSize);
583 }
584
585 if (IsKernelUser) {
586 fprintf(file, "#if\t__MigKernelSpecificCode\n");
587 fprintf(file, "\tmsg_result = mach_msg_send_from_kernel(");
588 fprintf(file, "&InP->Head, %s);\n", SendSize);
589 fprintf(file, "#else\n");
590 }
591 fprintf(file, "\tmsg_result = mach_msg("
592 "&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, MACH_PORT_NULL, %s, MACH_PORT_NULL);\n",
593 rt->rtWaitTime !=argNULL ? "MACH_SEND_TIMEOUT|" : "",
594 rt->rtMsgOption->argVarName,
595 SendSize,
596 rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName:"MACH_MSG_TIMEOUT_NONE");
597
598 if (IsKernelUser) {
599 fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
600 }
601
602 WriteApplMacro(file, "Send", "After", rt);
603
604 WriteMsgCheckForSendErrors(file, rt);
605
606 WriteReturn(file, rt, "\t", "msg_result", "\n", TRUE);
607 }
608
609 /*************************************************************
610 * Writes to code to check for error returns from receive.
611 * Called by WriteMsgSendReceive and WriteMsgRPC
612 *************************************************************/
613 static void
614 WriteMsgCheckReceiveCleanupMigReplyPort(FILE *file, routine_t *rt, char *success)
615 {
616 if (!akCheck(rt->rtReplyPort->argKind, akbUserArg))
617 {
618 /* If we aren't using a user-supplied reply port, then
619 deallocate the reply port when it is invalid or
620 for TIMED_OUT errors. */
621 fprintf(file, "\tif (msg_result != %s) {\n", success);
622 if (rt->rtWaitTime != argNULL) {
623 fprintf(file, "\t\t__MachMsgErrorWithTimeout%s(msg_result);\n",
624 rt->rtUseSpecialReplyPort ? "SRP" : "");
625 } else {
626 fprintf(file, "\t\t__MachMsgErrorWithoutTimeout%s(msg_result);\n",
627 rt->rtUseSpecialReplyPort ? "SRP" : "");
628 }
629 fprintf(file, "\t}\n");
630 }
631 }
632
633 static void
634 WriteMsgCheckReceive(FILE *file, routine_t *rt, char *success)
635 {
636 fprintf(file, "\tif (msg_result != %s) {\n", success);
637 WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result");
638 fprintf(file, "\t}\n");
639 }
640
641 /*************************************************************
642 * Writes the send and receive calls and code to check
643 * for errors. Normally the rpc code is generated instead
644 * although, the subsytem can be compiled with the -R option
645 * which will cause this code to be generated. Called by
646 * WriteRoutine if UseMsgRPC option is false.
647 *************************************************************/
648 static void
649 WriteMsgSendReceive(FILE *file, routine_t *rt)
650 {
651 char *SendSize = "";
652 char string[MAX_STR_LEN];
653
654 if (rt->rtNumRequestVar == 0)
655 SendSize = "(mach_msg_size_t)sizeof(Request)";
656 else
657 SendSize = "msgh_size";
658
659 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
660 sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
661 SendSize = strconcat(string, SendSize);
662 }
663
664 /* IsKernelUser to be done! */
665 fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, ", rt->rtWaitTime != argNULL ? "MACH_SEND_TIMEOUT|" : "", rt->rtMsgOption->argVarName, SendSize);
666 fprintf(file, " MACH_PORT_NULL, %s, MACH_PORT_NULL);\n",
667 #if !USE_IMMEDIATE_SEND_TIMEOUT
668 (rt->rtWaitTime != argNULL) ? rt->rtWaitTime->argVarName :
669 #endif
670 "MACH_MSG_TIMEOUT_NONE");
671 fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
672 WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result");
673 fprintf(file, "\n");
674
675 fprintf(file, "\tmsg_result = mach_msg(&Out0P->Head, MACH_RCV_MSG|%s%s%s, 0, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n",
676 rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
677 (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? "MACH_RCV_TIMEOUT|" : "",
678 rt->rtMsgOption->argVarName,
679 (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
680 WriteApplMacro(file, "Send", "After", rt);
681 WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS");
682 WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
683 fprintf(file, "\n");
684 }
685
686 /*************************************************************
687 * Writes the rpc call and the code to check for errors.
688 * This is the default code to be generated. Called by WriteRoutine
689 * for all routine types except SimpleRoutine.
690 *************************************************************/
691 static void
692 WriteMsgRPC(FILE *file, routine_t *rt)
693 {
694 char *SendSize = "";
695 char string[MAX_STR_LEN];
696
697 if (rt->rtNumRequestVar == 0)
698 SendSize = "(mach_msg_size_t)sizeof(Request)";
699 else
700 SendSize = "msgh_size";
701
702 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
703 sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
704 SendSize = strconcat(string, SendSize);
705 }
706
707 if (IsKernelUser) {
708 fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNELSPECIFIC_CODE_)\n");
709 fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, (mach_msg_size_t)sizeof(Reply));\n", SendSize);
710 fprintf(file, "#else\n");
711 }
712 if (rt->rtOverwrite) {
713 fprintf(file, "\tmsg_result = mach_msg_overwrite(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_OVERWRITE|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL, ",
714 rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
715 rt->rtWaitTime != argNULL ?
716 (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "",
717 rt->rtMsgOption->argVarName,
718 SendSize,
719 rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
720 fprintf(file, " &InOvTemplate->Head, (mach_msg_size_t)sizeof(OverwriteTemplate));\n");
721 }
722 else {
723 fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n",
724 rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
725 rt->rtWaitTime != argNULL ?
726 (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "",
727 rt->rtMsgOption->argVarName,
728 SendSize,
729 rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
730 }
731 if (IsKernelUser)
732 fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
733 WriteApplMacro(file, "Send", "After", rt);
734
735 WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS");
736 WriteMsgCheckForSendErrors(file, rt);
737
738 WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
739 fprintf(file, "\n");
740 }
741
742 /*
743 * argKPD_Pack discipline for Port types.
744 */
745 static void
746 WriteKPD_port(FILE *file, argument_t *arg)
747 {
748 ipc_type_t *it = arg->argType;
749 char *subindex = "";
750 char *recast = "";
751 char firststring[MAX_STR_LEN];
752 char string[MAX_STR_LEN];
753 char *ref = arg->argByReferenceUser ? "*" : "";
754 ipc_type_t *real_it;
755
756 if (IS_MULTIPLE_KPD(it)) {
757 WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
758 (void)sprintf(firststring, "\t*ptr");
759 (void)sprintf(string, "\tptr->");
760 subindex = "[i]";
761 real_it = it->itElement;
762 }
763 else {
764 (void)sprintf(firststring, "InP->%s", arg->argMsgField);
765 (void)sprintf(string, "InP->%s.", arg->argMsgField);
766 real_it = it;
767 }
768
769 #ifdef MIG_KERNEL_PORT_CONVERSION
770 if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t"))
771 recast = "(mach_port_t)";
772 #endif
773 fprintf(file, "#if\tUseStaticTemplates\n");
774 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
775 /* ref is required also in the Request part, because of inout parameters */
776 fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex);
777 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
778 argument_t *poly = arg->argPoly;
779
780 fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName);
781 }
782 fprintf(file, "#else\t/* UseStaticTemplates */\n");
783 fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex);
784 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
785 argument_t *poly = arg->argPoly;
786
787 fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName);
788 }
789 else
790 fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr);
791 fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
792 fprintf(file, "#endif\t/* UseStaticTemplates */\n");
793 if (IS_MULTIPLE_KPD(it)) {
794 fprintf(file, "\t }\n");
795 if (it->itVarArray) {
796 fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
797 /* fill the rest of the statically allocated KPD entries with MACH_PORT_NULL */
798 fprintf(file, "#if\tUseStaticTemplates\n");
799 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
800 fprintf(file, "#else\t/* UseStaticTemplates */\n");
801 fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string);
802 fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
803 fprintf(file, "#endif\t/* UseStaticTemplates */\n");
804 fprintf(file, "\t }\n");
805 }
806 fprintf(file, "\t}\n");
807 }
808 fprintf(file, "\n");
809 }
810
811 static void
812 WriteKPD_ool_varsize(FILE *file, argument_t *arg, char *who, char *where, boolean_t iscomplex)
813 {
814 ipc_type_t *it = arg->argType;
815 argument_t *count;
816 char *cref;
817
818 if (iscomplex) {
819 it = it->itElement;
820 count = arg->argSubCount;
821 }
822 else
823 count = arg->argCount;
824 cref = count->argByReferenceUser ? "*" : "";
825
826 /* size has to be expressed in bytes! */
827 if (count->argMultiplier > 1 || it->itSize > 8)
828 fprintf(file, "\t%s->%s = %s%s%s * %d;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "", count->argMultiplier * it->itSize / 8);
829 else
830 fprintf(file, "\t%s->%s = %s%s%s;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "");
831 }
832
833 /*
834 * argKPD_Pack discipline for out-of-line types.
835 */
836 static void
837 WriteKPD_ool(FILE *file, argument_t *arg)
838 {
839 ipc_type_t *it = arg->argType;
840 char *ref = arg->argByReferenceUser ? "*" : "";
841 char firststring[MAX_STR_LEN];
842 char string[MAX_STR_LEN];
843 boolean_t VarArray;
844 u_int howmany, howbig;
845 char *subindex;
846
847 if (IS_MULTIPLE_KPD(it)) {
848 WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
849 (void)sprintf(firststring, "\t*ptr");
850 (void)sprintf(string, "\tptr->");
851 VarArray = it->itElement->itVarArray;
852 howmany = it->itElement->itNumber;
853 howbig = it->itElement->itSize;
854 subindex = "[i]";
855 }
856 else {
857 (void)sprintf(firststring, "InP->%s", arg->argMsgField);
858 (void)sprintf(string, "InP->%s.", arg->argMsgField);
859 VarArray = it->itVarArray;
860 howmany = it->itNumber;
861 howbig = it->itSize;
862 subindex = "";
863 }
864
865 fprintf(file, "#if\tUseStaticTemplates\n");
866
867 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
868 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
869 if (VarArray) {
870 if (IS_MULTIPLE_KPD(it))
871 WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE);
872 else
873 WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE);
874 }
875
876 if (arg->argDeallocate == d_MAYBE)
877 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
878
879 fprintf(file, "#else\t/* UseStaticTemplates */\n");
880
881 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
882 if (VarArray)
883 if (IS_MULTIPLE_KPD(it))
884 WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE);
885 else
886 WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE);
887 else
888 fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
889 if (arg->argDeallocate == d_MAYBE)
890 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
891 else
892 fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
893 fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
894 #ifdef ALIGNMENT
895 fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, (it->itElement->itSize < 8) ? 1 : it->itElement->itSize / 8);
896 #endif
897 fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
898
899 fprintf(file, "#endif\t/* UseStaticTemplates */\n");
900 if (IS_MULTIPLE_KPD(it)) {
901 fprintf(file, "\t }\n");
902 if (it->itVarArray) {
903 fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
904 /* fill the rest of the statically allocated KPD entries with size NULL */
905 fprintf(file, "#if\tUseStaticTemplates\n");
906 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
907 if (!VarArray)
908 fprintf(file, "\t%ssize = 0;\n", string);
909 /* otherwise the size in the template would be != 0! */
910 fprintf(file, "#else\t/* UseStaticTemplates */\n");
911 fprintf(file, "\t%ssize = 0;\n", string);
912 fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
913 fprintf(file, "#endif\t/* UseStaticTemplates */\n");
914 fprintf(file, "\t }\n");
915 }
916 fprintf(file, "\t}\n");
917 }
918 fprintf(file, "\n");
919 }
920
921 /*
922 * argKPD_Pack discipline for out-of-line Port types.
923 */
924 static void
925 WriteKPD_oolport(FILE *file, argument_t *arg)
926 {
927 ipc_type_t *it = arg->argType;
928 char *ref = arg->argByReferenceUser ? "*" : "";
929 argument_t *count;
930 boolean_t VarArray;
931 string_t howstr;
932 u_int howmany;
933 char *subindex;
934 char firststring[MAX_STR_LEN];
935 char string[MAX_STR_LEN];
936
937 if (IS_MULTIPLE_KPD(it)) {
938 WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
939 (void)sprintf(firststring, "\t*ptr");
940 (void)sprintf(string, "\tptr->");
941 VarArray = it->itElement->itVarArray;
942 howmany = it->itElement->itNumber;
943 howstr = it->itElement->itInNameStr;
944 count = arg->argSubCount;
945 subindex = "[i]";
946 }
947 else {
948 (void)sprintf(firststring, "InP->%s", arg->argMsgField);
949 (void)sprintf(string, "InP->%s.", arg->argMsgField);
950 VarArray = it->itVarArray;
951 howmany = it->itNumber;
952 howstr = it->itInNameStr;
953 count = arg->argCount;
954 subindex = "";
955 }
956
957 fprintf(file, "#if\tUseStaticTemplates\n");
958
959 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
960 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
961 if (VarArray)
962 fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex);
963 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
964 argument_t *poly = arg->argPoly;
965 char *pref = poly->argByReferenceUser ? "*" : "";
966
967 fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName);
968 }
969 if (arg->argDeallocate == d_MAYBE)
970 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
971
972 fprintf(file, "#else\t/* UseStaticTemplates */\n");
973
974 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
975 if (VarArray)
976 fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex);
977 else
978 fprintf(file, "\t%scount = %d;\n", string, howmany);
979 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
980 argument_t *poly = arg->argPoly;
981 char *pref = poly->argByReferenceUser ? "*" : "";
982
983 fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName);
984 }
985 else
986 fprintf(file, "\t%sdisposition = %s;\n", string, howstr);
987 if (arg->argDeallocate == d_MAYBE)
988 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
989 else
990 fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
991 fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
992
993 fprintf(file, "#endif\t/* UseStaticTemplates */\n");
994 fprintf(file, "\n");
995
996 if (IS_MULTIPLE_KPD(it)) {
997 fprintf(file, "\t }\n");
998 if (it->itVarArray) {
999 fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
1000 /* fill the rest of the statically allocated KPD entries with size NULL */
1001 fprintf(file, "#if\tUseStaticTemplates\n");
1002 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1003 if (!VarArray)
1004 fprintf(file, "\t%scount = 0;\n", string);
1005 /* otherwise the size in the template would be != 0! */
1006 fprintf(file, "#else\t/* UseStaticTemplates */\n");
1007 fprintf(file, "\t%scount = 0;\n", string);
1008 fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
1009 fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1010 fprintf(file, "\t }\n");
1011 }
1012 fprintf(file, "\t}\n");
1013 }
1014 fprintf(file, "\n");
1015 }
1016
1017 static void
1018 WriteOverwriteTemplate(FILE *file, routine_t *rt)
1019 {
1020 argument_t *arg;
1021 char string[MAX_STR_LEN];
1022 char *subindex = "";
1023 boolean_t finish = FALSE;
1024
1025 fprintf(file, "\t/* Initialize the template for overwrite */\n");
1026 fprintf(file, "\tInOvTemplate->msgh_body.msgh_descriptor_count = %d;\n", rt->rtOverwriteKPDs);
1027 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1028 ipc_type_t *it = arg->argType;
1029 char *ref = arg->argByReferenceUser ? "*" : "";
1030 argument_t *count;
1031 char *cref;
1032 boolean_t VarIndex;
1033 u_int howmany, howbig;
1034
1035 if (akCheck(arg->argKind, akbOverwrite)) {
1036 if (arg->argFlags & flOverwrite) {
1037 if (IS_MULTIPLE_KPD(it)) {
1038 WriteKPD_Iterator(file, FALSE, TRUE, it->itVarArray, arg, TRUE);
1039 if (it->itVarArray)
1040 finish = TRUE;
1041 sprintf(string, "\tptr->");
1042 subindex = "[i]";
1043 count = arg->argSubCount;
1044 VarIndex = it->itElement->itVarArray;
1045 howmany = it->itElement->itNumber;
1046 howbig = it->itElement->itSize;
1047 }
1048 else {
1049 sprintf(string, "InOvTemplate->%s.", arg->argMsgField);
1050 subindex = "";
1051 count = arg->argCount;
1052 VarIndex = it->itVarArray;
1053 howmany = it->itNumber;
1054 howbig = it->itSize;
1055 }
1056
1057 fprintf(file, "\t%saddress = (void *) %s%s%s;\n", string, ref, arg->argVarName, subindex);
1058
1059 if (it->itPortType) {
1060 fprintf(file, "\t%scount = ", string);
1061 if (VarIndex) {
1062 cref = count->argByReferenceUser ? "*" : "";
1063 fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex);
1064 }
1065 else
1066 fprintf(file, "%d;\n", howmany);
1067 }
1068 else {
1069 fprintf(file, "\t%ssize = ", string);
1070 if (VarIndex) {
1071 cref = count->argByReferenceUser ? "*" : "";
1072 if (count->argMultiplier > 1 || howbig > 8)
1073 fprintf(file, "%s%s%s * %d;\n", cref, count->argVarName, subindex, count->argMultiplier * howbig / 8);
1074 else
1075 fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex);
1076 }
1077 else
1078 fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
1079 }
1080 fprintf(file, "\t%scopy = MACH_MSG_OVERWRITE;\n", string);
1081 fprintf(file, "\t%stype = MACH_MSG_OOL_%sDESCRIPTOR;\n", string, (it->itPortType) ? "PORTS_" : "");
1082 if (IS_MULTIPLE_KPD(it))
1083 fprintf(file, "\t }\n");
1084 if (finish) {
1085 fprintf(file, "\t for (i = %s%s; i < %d; ptr++, i++) {\n", (arg->argCount->argByReferenceUser) ? "*" : "", arg->argCount->argVarName, it->itKPD_Number);
1086 fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n");
1087 fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : "");
1088 fprintf(file, "\t }\n");
1089 }
1090 if (IS_MULTIPLE_KPD(it))
1091 fprintf(file, "\t}\n");
1092 }
1093 else {
1094 /* just a placeholder */
1095 if (IS_MULTIPLE_KPD(it)) {
1096 WriteKPD_Iterator(file, FALSE, TRUE, FALSE, arg, TRUE);
1097 fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n");
1098 fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : "");
1099 fprintf(file, "\t }\n\t}\n");
1100 }
1101 else {
1102 fprintf(file, "\tInOvTemplate->%s.copy = MACH_MSG_ALLOCATE;\n", arg->argMsgField);
1103 /* not sure whether this is needed */
1104 fprintf(file, "\tInOvTemplate->%s.type = MACH_MSG_OOL_%sDESCRIPTOR;\n", arg->argMsgField, (it->itPortType) ? "PORTS_" : "");
1105 }
1106 }
1107 }
1108 }
1109 fprintf(file, "\n");
1110 }
1111
1112 /*************************************************************
1113 * Writes code to copy an argument into the request message.
1114 * Called by WriteRoutine for each argument that is to placed
1115 * in the request message.
1116 *************************************************************/
1117
1118 static void
1119 WritePackArgValueNormal(FILE *file, argument_t *arg)
1120 {
1121 ipc_type_t *it = arg->argType;
1122 char *ref = (arg->argByReferenceUser ||
1123 it->itNativePointer) ? "*" : "";
1124
1125 if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
1126 if (it->itString) {
1127 /*
1128 * Copy variable-size C string with mig_strncpy.
1129 * Save the string length (+ 1 for trailing 0)
1130 * in the argument`s count field.
1131 */
1132 fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
1133 fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n");
1134 fprintf(file, "\t\tInP->%s = (%s) mig_strncpy_zerofill(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber);
1135 fprintf(file, "\t} else {\n");
1136 fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
1137
1138 fprintf(file, "\t\tInP->%s = (%s) mig_strncpy(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber);
1139
1140 fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
1141 fprintf(file, "\t}\n");
1142 fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
1143
1144 fprintf(file, "\tInP->%sOffset = 0;\n", arg->argMsgField);
1145 }
1146 else if (it->itNoOptArray)
1147 fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, %d);\n", arg->argMsgField, ref, arg->argVarName, it->itTypeSize);
1148 else {
1149
1150 /*
1151 * Copy in variable-size inline array with (void)memcpy,
1152 * after checking that number of elements doesn`t
1153 * exceed declared maximum.
1154 */
1155 argument_t *count = arg->argCount;
1156 char *countRef = count->argByReferenceUser ? "*" : "";
1157 ipc_type_t *btype = it->itElement;
1158
1159 /* Note btype->itNumber == count->argMultiplier */
1160
1161 if (akIdent(arg->argKind) != akeSubCount) {
1162 /* we skip the SubCount case, as we have already taken care of */
1163 fprintf(file, "\tif (%s%s > %d) {\n", countRef, count->argVarName, it->itNumber/btype->itNumber);
1164 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
1165 fprintf(file, "\t}\n");
1166 }
1167
1168 fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, ", arg->argMsgField, ref, arg->argVarName);
1169 if (btype->itTypeSize > 1)
1170 fprintf(file, "%d * ", btype->itTypeSize);
1171 fprintf(file, "%s%s);\n", countRef, count->argVarName);
1172 }
1173 }
1174 else if (IS_OPTIONAL_NATIVE(it)) {
1175 fprintf(file, "\tif ((InP->__Present__%s = (%s != %s))) {\n", arg->argMsgField, arg->argVarName, it->itBadValue);
1176 WriteCopyType(file, it, TRUE, "\tInP->%s.__Real__%s", "/* %s%s */ %s%s", arg->argMsgField, arg->argMsgField, ref, arg->argVarName);
1177 fprintf(file, "\t}\n");
1178 }
1179 else
1180 WriteCopyType(file, it, TRUE, "InP->%s", "/* %s */ %s%s", arg->argMsgField, ref, arg->argVarName);
1181
1182 if (arg->argPadName != NULL && it->itPadSize != 0) {
1183 fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize);
1184 fprintf(file, "\t\t InP->%s[i] = 0;\n", arg->argPadName);
1185 }
1186 fprintf(file, "\n");
1187 }
1188
1189 /*
1190 * Calculate the size of a variable-length message field.
1191 */
1192 static void
1193 WriteArgSizeVariable(FILE *file, argument_t *arg, ipc_type_t *ptype)
1194 {
1195 int bsize = ptype->itElement->itTypeSize;
1196 argument_t *count = arg->argCount;
1197
1198 if (PackMsg == FALSE) {
1199 fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
1200 return;
1201 }
1202
1203 /* If the base type size of the data field isn`t a multiple of 4,
1204 we have to round up. */
1205 if (bsize % itWordAlign != 0)
1206 fprintf(file, "_WALIGN_");
1207 fprintf(file, "(");
1208 if (bsize > 1)
1209 fprintf(file, "%d * ", bsize);
1210 if (ptype->itString)
1211 /* get count from descriptor in message */
1212 fprintf(file, "InP->%s", count->argMsgField);
1213 else
1214 /* get count from argument */
1215 fprintf(file, "%s%s", count->argByReferenceUser ? "*" : "", count->argVarName);
1216 fprintf(file, ")");
1217 }
1218
1219 static void
1220 WriteArgSizeOptional(FILE *file, argument_t *arg, ipc_type_t *ptype)
1221 {
1222 fprintf(file, "(InP->__Present__%s ? _WALIGNSZ_(%s) : 0)", arg->argVarName, ptype->itUserType);
1223 }
1224
1225 static void
1226 WriteArgSize(FILE *file, argument_t *arg)
1227
1228 {
1229 ipc_type_t *ptype = arg->argType;
1230
1231 if (IS_OPTIONAL_NATIVE(ptype))
1232 WriteArgSizeOptional(file, arg, ptype);
1233 else
1234 WriteArgSizeVariable(file, arg, ptype);
1235 }
1236
1237 /*
1238 * Adjust message size and advance request pointer.
1239 * Called after packing a variable-length argument that
1240 * has more arguments following.
1241 */
1242 static void
1243 WriteAdjustMsgSize(FILE *file, argument_t *arg)
1244 {
1245 ipc_type_t *ptype = arg->argType;
1246
1247 /* There are more In arguments. We need to adjust msgh_size
1248 and advance InP, so we save the size of the current field
1249 in msgh_size_delta. */
1250
1251 fprintf(file, "\tmsgh_size_delta = ");
1252 WriteArgSize(file, arg);
1253 fprintf(file, ";\n");
1254
1255 if (arg->argRequestPos == 0) {
1256 /* First variable-length argument. The previous msgh_size value
1257 is the minimum request size. */
1258
1259 fprintf(file, "\tmsgh_size = ");
1260 rtMinRequestSize(file, arg->argRoutine, "Request");
1261 fprintf(file, " + msgh_size_delta;\n");
1262 }
1263 else
1264 fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
1265
1266 if (PackMsg == TRUE) {
1267 fprintf(file, "\tInP = (Request *) ((pointer_t) InP + msgh_size_delta - ");
1268 if (IS_OPTIONAL_NATIVE(ptype))
1269 fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType);
1270 else
1271 fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
1272 fprintf(file, ");\n\n");
1273 }
1274 }
1275
1276 /*
1277 * Calculate the size of the message. Called after the
1278 * last argument has been packed.
1279 */
1280 static void
1281 WriteFinishMsgSize(FILE *file, argument_t *arg)
1282 {
1283 /* No more In arguments. If this is the only variable In
1284 argument, the previous msgh_size value is the minimum
1285 request size. */
1286
1287 if (arg->argRequestPos == 0) {
1288 fprintf(file, "\tmsgh_size = ");
1289 rtMinRequestSize(file, arg->argRoutine, "Request");
1290 fprintf(file, " + (");
1291 WriteArgSize(file, arg);
1292 fprintf(file, ");\n");
1293 }
1294 else {
1295 fprintf(file, "\tmsgh_size += ");
1296 WriteArgSize(file, arg);
1297 fprintf(file, ";\n");
1298 }
1299 }
1300
1301 static void
1302 WriteInitializeCount(FILE *file, argument_t *arg)
1303 {
1304 ipc_type_t *ptype = arg->argCInOut->argParent->argType;
1305 ipc_type_t *btype = ptype->itElement;
1306
1307 fprintf(file, "\tif (%s%s < %d)\n", arg->argByReferenceUser ? "*" : "", arg->argVarName, ptype->itNumber/btype->itNumber);
1308 fprintf(file, "\t\tInP->%s = %s%s;\n", arg->argMsgField, arg->argByReferenceUser ? "*" : "", arg->argVarName);
1309 fprintf(file, "\telse\n");
1310 fprintf(file, "\t\tInP->%s = %d;\n", arg->argMsgField, ptype->itNumber/btype->itNumber);
1311 fprintf(file, "\n");
1312 }
1313
1314 /*
1315 * Generate code to fill in all of the request arguments and their
1316 * message types.
1317 */
1318 static void
1319 WriteRequestArgs(FILE *file, routine_t *rt)
1320 {
1321 argument_t *arg;
1322 argument_t *lastVarArg;
1323
1324 /*
1325 * 1. The Kernel Processed Data
1326 */
1327 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
1328 if (akCheckAll(arg->argKind, akbSendSnd|akbSendKPD))
1329 (*arg->argKPD_Pack)(file, arg);
1330
1331 /*
1332 * 2. The Data Stream
1333 */
1334 lastVarArg = argNULL;
1335 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1336 /*
1337 * Adjust message size and advance message pointer if
1338 * the last request argument was variable-length and the
1339 * request position will change.
1340 */
1341 if (lastVarArg != argNULL &&
1342 lastVarArg->argRequestPos < arg->argRequestPos) {
1343 WriteAdjustMsgSize(file, lastVarArg);
1344 lastVarArg = argNULL;
1345 }
1346
1347 if ((akIdent(arg->argKind) == akeCountInOut) &&
1348 akCheck(arg->argKind, akbSendSnd))
1349 WriteInitializeCount(file, arg);
1350 else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody))
1351 WritePackArgValueNormal(file, arg);
1352 /*
1353 * Remember whether this was variable-length.
1354 */
1355 if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable))
1356 lastVarArg = arg;
1357 }
1358 /*
1359 * Finish the message size.
1360 */
1361 if (lastVarArg != argNULL)
1362 WriteFinishMsgSize(file, lastVarArg);
1363 }
1364
1365 /*************************************************************
1366 * Writes code to check that the return msgh_id is correct and that
1367 * the size of the return message is correct. Called by
1368 * WriteRoutine.
1369 *************************************************************/
1370 static void
1371 WriteCheckIdentity(FILE *file, routine_t *rt)
1372 {
1373 fprintf(file, "\tif (Out0P->Head.msgh_id != %d) {\n", rt->rtNumber + SubsystemBase + 100);
1374 fprintf(file, "\t if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n");
1375 fprintf(file, "\t\t{ return MIG_SERVER_DIED; }\n");
1376 fprintf(file, "\t else\n");
1377 fprintf(file, "\t\t{ return MIG_REPLY_MISMATCH; }\n");
1378 fprintf(file, "\t}\n");
1379 fprintf(file, "\n");
1380 if (!rt->rtSimpleReply)
1381 fprintf(file, "\tmsgh_simple = !(Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
1382 fprintf(file, "#if\t__MigTypeCheck\n");
1383
1384 if (!rt->rtNoReplyArgs)
1385 fprintf(file, "\tmsgh_size = Out0P->Head.msgh_size;\n\n");
1386
1387 if (rt->rtSimpleReply) {
1388 /* Expecting a simple message. We can factor out the check for
1389 * a simple message, since the error reply message is also simple.
1390 */
1391 fprintf(file, "\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
1392 if (rt->rtNoReplyArgs)
1393 fprintf(file, "\t (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n");
1394 else {
1395 /*
1396 * We have an error iff:
1397 * 1) the message size is not the one expected AND
1398 * 2) the message size is also different from sizeof(mig_reply_error_t)
1399 * or the RetCode == KERN_SUCCESS
1400 */
1401 if (rt->rtNumReplyVar > 0) {
1402 fprintf(file, "\t ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < ");
1403 rtMinReplySize(file, rt, "__Reply");
1404 fprintf(file, ") &&\n");
1405 }
1406 else
1407 fprintf(file, "\t ((msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n");
1408 fprintf(file, "\t (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
1409 fprintf(file, "\t Out0P->RetCode == KERN_SUCCESS)))\n");
1410 }
1411 }
1412 else {
1413 /* Expecting a complex message. */
1414
1415 fprintf(file, "\t" "if ((msgh_simple || Out0P->msgh_body.msgh_descriptor_count != %d ||\n", rt->rtReplyKPDs);
1416 if (rt->rtNumReplyVar > 0) {
1417 fprintf(file, "\t msgh_size < ");
1418 rtMinReplySize(file, rt, "__Reply");
1419 fprintf(file, " || msgh_size > (mach_msg_size_t)sizeof(__Reply)) &&\n");
1420 }
1421 else
1422 fprintf(file, "\t msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n");
1423 fprintf(file, "\t (!msgh_simple || msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
1424 fprintf(file, "\t ((mig_reply_error_t *)Out0P)->RetCode == KERN_SUCCESS))\n");
1425 }
1426 fprintf(file, "\t\t{ return MIG_TYPE_ERROR ; }\n");
1427 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1428 fprintf(file, "\n");
1429 }
1430
1431 /*************************************************************
1432 * Write code to generate error handling code if the RetCode
1433 * argument of a Routine is not KERN_SUCCESS.
1434 *************************************************************/
1435 static void
1436 WriteRetCodeCheck(FILE *file, routine_t *rt)
1437 {
1438 if (rt->rtSimpleReply)
1439 fprintf(file, "\tif (Out0P->RetCode != KERN_SUCCESS) {\n");
1440 else
1441 fprintf(file, "\tif (msgh_simple) {\n");
1442 if (CheckNDR) {
1443 fprintf(file, "#ifdef\t__NDR_convert__mig_reply_error_t__defined\n");
1444 fprintf(file, "\t\t__NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P);\n");
1445 fprintf(file, "#endif\t/* __NDR_convert__mig_reply_error_t__defined */\n");
1446 }
1447 fprintf(file, "\t\treturn ((mig_reply_error_t *)Out0P)->RetCode;\n");
1448 fprintf(file, "\t}\n");
1449 fprintf(file, "\n");
1450 }
1451
1452 /*
1453 * argKPD_TypeCheck discipline for Port types.
1454 */
1455 static void
1456 WriteTCheckKPD_port(FILE *file, argument_t *arg)
1457 {
1458 ipc_type_t *it = arg->argType;
1459 char *tab = "";
1460 char string[MAX_STR_LEN];
1461 boolean_t close = FALSE;
1462
1463 if (IS_MULTIPLE_KPD(it)) {
1464 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
1465 (void)sprintf(string, "ptr->");
1466 tab = "\t";
1467 close = TRUE;
1468 }
1469 else
1470 (void)sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
1471 fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string);
1472 if (arg->argPoly == argNULL && !it->itVarArray)
1473 /* we can't check disposition when poly or VarArray,
1474 (because some of the entries could be empty) */
1475 fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr);
1476 fprintf(file,
1477 ") {\n"
1478 "\t\t%s" "return MIG_TYPE_ERROR;\n"
1479 "\t%s" "}\n"
1480 , tab, tab);
1481 if (close)
1482 fprintf(file, "\t }\n\t}\n");
1483 }
1484
1485 /*
1486 * argKPD_TypeCheck discipline for out-of-line types.
1487 */
1488 static void
1489 WriteTCheckKPD_ool(FILE *file, argument_t *arg)
1490 {
1491 ipc_type_t *it = arg->argType;
1492 char *tab, string[MAX_STR_LEN];
1493 boolean_t test;
1494 u_int howmany, howbig;
1495
1496 if (IS_MULTIPLE_KPD(it)) {
1497 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
1498 tab = "\t";
1499 sprintf(string, "ptr->");
1500 howmany = it->itElement->itNumber;
1501 howbig = it->itElement->itSize;
1502 test = !it->itVarArray && !it->itElement->itVarArray;
1503 }
1504 else {
1505 tab = "";
1506 sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
1507 howmany = it->itNumber;
1508 howbig = it->itSize;
1509 test = !it->itVarArray;
1510 }
1511
1512 fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string);
1513 if (test)
1514 /* if VarArray we may use no-op; if itElement->itVarArray size might change */
1515 fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8);
1516 fprintf(file,
1517 ") {\n"
1518 "\t\t%s" "return MIG_TYPE_ERROR;\n"
1519 "\t%s" "}\n"
1520 , tab, tab);
1521 if (IS_MULTIPLE_KPD(it))
1522 fprintf(file, "\t }\n\t}\n");
1523 }
1524
1525 /*
1526 * argKPD_TypeCheck discipline for out-of-line Port types.
1527 */
1528 static void
1529 WriteTCheckKPD_oolport(FILE *file, argument_t *arg)
1530 {
1531 ipc_type_t *it = arg->argType;
1532 char *tab, string[MAX_STR_LEN];
1533 boolean_t test;
1534 u_int howmany;
1535 char *howstr;
1536
1537 if (IS_MULTIPLE_KPD(it)) {
1538 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
1539 tab = "\t";
1540 sprintf(string, "ptr->");
1541 howmany = it->itElement->itNumber;
1542 test = !it->itVarArray && !it->itElement->itVarArray;
1543 howstr = it->itElement->itOutNameStr;
1544 }
1545 else {
1546 tab = "";
1547 sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
1548 howmany = it->itNumber;
1549 test = !it->itVarArray;
1550 howstr = it->itOutNameStr;
1551 }
1552
1553 fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string);
1554 if (test)
1555 /* if VarArray we may use no-op; if itElement->itVarArray size might change */
1556 fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany);
1557 if (arg->argPoly == argNULL)
1558 fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr);
1559 fprintf(file, ") {\n"
1560 "\t\t%s" "return MIG_TYPE_ERROR;\n"
1561 "\t%s" "}\n"
1562 ,tab, tab);
1563 if (IS_MULTIPLE_KPD(it))
1564 fprintf(file, "\t }\n\t}\n");
1565 }
1566
1567 /*************************************************************
1568 * Writes code to check that the type of each of the arguments
1569 * in the reply message is what is expected. Called by
1570 * WriteRoutine for each out && typed argument in the reply message.
1571 *************************************************************/
1572 static void
1573 WriteTypeCheck(FILE *file, argument_t *arg)
1574 {
1575 fprintf(file, "#if\t__MigTypeCheck\n");
1576 (*arg->argKPD_TypeCheck)(file, arg);
1577 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1578 }
1579
1580
1581 /*
1582 * argKPD_Extract discipline for Port types.
1583 */
1584 static void
1585 WriteExtractKPD_port(FILE *file, argument_t *arg)
1586 {
1587 ipc_type_t *it = arg->argType;
1588 char *ref = arg->argByReferenceUser ? "*" : "";
1589 char *subindex;
1590 char *recast = "";
1591 ipc_type_t *real_it;
1592
1593 real_it = (IS_MULTIPLE_KPD(it)) ? it->itElement : it;
1594 #ifdef MIG_KERNEL_PORT_CONVERSION
1595 if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t"))
1596 recast = "(mach_port_t)";
1597 #endif
1598 if (IS_MULTIPLE_KPD(it)) {
1599 WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
1600
1601 fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast);
1602 if (it->itVarArray) {
1603 argument_t *count = arg->argCount;
1604 char *cref = count->argByReferenceUser ? "*" : "";
1605
1606 fprintf(file, "\t if (Out%dP->%s >",count->argReplyPos, count->argVarName);
1607 if (arg->argCountInOut) {
1608 fprintf(file, " %s%s)\n", cref, count->argVarName);
1609 }
1610 else {
1611 fprintf(file, " %d)\n", it->itNumber/it->itElement->itNumber);
1612 }
1613 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
1614 }
1615 fprintf(file, "\t}\n");
1616 subindex = "[0]";
1617 }
1618 else {
1619 fprintf(file, "\t%s%s = %sOut%dP->%s.name;\n", ref, arg->argVarName, recast, arg->argReplyPos, arg->argMsgField);
1620 subindex = "";
1621 }
1622
1623 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) {
1624 argument_t *poly = arg->argPoly;
1625 char *pref = poly->argByReferenceUser ? "*" : "";
1626
1627 fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex);
1628 }
1629 }
1630
1631 /*
1632 * argKPD_Extract discipline for out-of-line types.
1633 */
1634 static void
1635 WriteExtractKPD_ool(FILE *file, argument_t *arg)
1636 {
1637 char *ref = arg->argByReferenceUser ? "*" : "";
1638 ipc_type_t *it = arg->argType;
1639
1640 if (IS_MULTIPLE_KPD(it)) {
1641 WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
1642 fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
1643 fprintf(file, "\t}\n");
1644 }
1645 else
1646 fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField);
1647 /*
1648 * In case of variable sized arrays,
1649 * the count field will be retrieved from the untyped
1650 * section of the message
1651 */
1652 }
1653
1654 /*
1655 * argKPD_Extract discipline for out-of-line Port types.
1656 */
1657 static void
1658 WriteExtractKPD_oolport(FILE *file, argument_t *arg)
1659 {
1660 char *ref = arg->argByReferenceUser ? "*" : "";
1661 ipc_type_t *it = arg->argType;
1662 char *subindex;
1663
1664 if (IS_MULTIPLE_KPD(it)) {
1665 WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
1666 fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
1667 fprintf(file, "\t}\n");
1668 subindex = "[0]";
1669 }
1670 else {
1671 fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField);
1672 subindex = "";
1673 }
1674 /*
1675 * In case of variable sized arrays,
1676 * the count field will be retrieved from the untyped
1677 * section of the message
1678 */
1679 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) {
1680 argument_t *poly = arg->argPoly;
1681 char *pref = poly->argByReferenceUser ? "*" : "";
1682
1683 fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex);
1684 }
1685 }
1686
1687 /*************************************************************
1688 * Write code to copy an argument from the reply message
1689 * to the parameter. Called by WriteRoutine for each argument
1690 * in the reply message.
1691 *************************************************************/
1692
1693 static void
1694 WriteExtractArgValueNormal(FILE *file, argument_t *arg)
1695 {
1696 ipc_type_t *argType = arg->argType;
1697 char *ref = arg->argByReferenceUser ? "*" : "";
1698 char who[20];
1699
1700 if (akCheck(arg->argKind, akbUserImplicit))
1701 sprintf(who, "TrailerP");
1702 else
1703 sprintf(who, "Out%dP", arg->argReplyPos);
1704
1705 if (IS_VARIABLE_SIZED_UNTYPED(argType) || argType->itNoOptArray) {
1706 if (argType->itString) {
1707 /*
1708 * Copy out variable-size C string with mig_strncpy, not the zerofill variant.
1709 * We don't risk leaking process / kernel memory on this copy-out because
1710 * we've already zero-filled the buffer on copy-in.
1711 */
1712 fprintf(file, "\t(void) mig_strncpy(%s%s, %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itNumber);
1713 }
1714 else if (argType->itNoOptArray)
1715 fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itTypeSize);
1716 else {
1717
1718 /*
1719 * Copy out variable-size inline array with (void)memcpy,
1720 * after checking that number of elements doesn`t
1721 * exceed user`s maximum.
1722 */
1723 argument_t *count = arg->argCount;
1724 char *countRef = count->argByReferenceUser ? "*" : "";
1725 ipc_type_t *btype = argType->itElement;
1726
1727 /* Note count->argMultiplier == btype->itNumber */
1728 /* Note II: trailer logic isn't supported in this case */
1729 fprintf(file, "\tif (Out%dP->%s", count->argReplyPos, count->argMsgField);
1730 if (arg->argCountInOut) {
1731 fprintf(file, " > %s%s) {\n", countRef, count->argVarName);
1732 }
1733 else {
1734 fprintf(file, " > %d) {\n", argType->itNumber/btype->itNumber);
1735 }
1736
1737 /*
1738 * If number of elements is too many for user receiving area,
1739 * fill user`s area as much as possible. Return the correct
1740 * number of elements.
1741 */
1742 fprintf(file, "\t\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField);
1743 if (btype->itTypeSize > 1)
1744 fprintf(file, "%d * ", btype->itTypeSize);
1745 if (arg->argCountInOut) {
1746 fprintf(file, " %s%s);\n", countRef, count->argVarName);
1747 }
1748 else {
1749 fprintf(file, " %d);\n", argType->itNumber/btype->itNumber);
1750 }
1751 fprintf(file, "\t\t%s%s = Out%dP->%s", countRef, count->argVarName, count->argReplyPos, count->argMsgField);
1752 fprintf(file, ";\n");
1753 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
1754
1755 fprintf(file, "\t}\n");
1756
1757 fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField);
1758 if (btype->itTypeSize > 1)
1759 fprintf(file, "%d * ", btype->itTypeSize);
1760 fprintf(file, "Out%dP->%s);\n", count->argReplyPos, count->argMsgField);
1761 }
1762 }
1763 else
1764 WriteCopyType(file, argType, FALSE, "%s%s", "/* %s%s */ %s->%s", ref, arg->argVarName, who, arg->argMsgField);
1765 fprintf(file, "\n");
1766 }
1767
1768 static void
1769 WriteCalcArgSize(FILE *file, argument_t *arg)
1770 {
1771 ipc_type_t *ptype = arg->argType;
1772 ipc_type_t *btype = ptype->itElement;
1773 argument_t *count = arg->argCount;
1774 int multiplier = btype->itTypeSize;
1775
1776 /* If the base type size of the data field isn`t a multiple of 4,
1777 we have to round up. */
1778 if (btype->itTypeSize % itWordAlign != 0)
1779 fprintf(file, "_WALIGN_(");
1780
1781 fprintf(file, "Out%dP->%s", count->argReplyPos, count->argMsgField);
1782 if (multiplier > 1)
1783 fprintf(file, " * %d", multiplier);
1784
1785 if (btype->itTypeSize % itWordAlign != 0)
1786 fprintf(file, ")");
1787 }
1788
1789 static void
1790 WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator)
1791 {
1792 ipc_type_t *ptype = arg->argType;
1793 ipc_type_t *btype = ptype->itElement;
1794 argument_t *count = arg->argCount;
1795 int multiplier = btype->itTypeSize;
1796
1797 fprintf(file, "\tif (((msgh_size - ");
1798 rtMinReplySize(file, rt, "__Reply");
1799 fprintf(file, ")");
1800 if (multiplier > 1)
1801 fprintf(file, " / %d", multiplier);
1802 fprintf(file, "< Out%dP->%s) ||\n", count->argReplyPos, count->argMsgField);
1803 fprintf(file, "\t (msgh_size %s ", comparator);
1804 rtMinReplySize(file, rt, "__Reply");
1805 fprintf(file, " + ");
1806 WriteCalcArgSize(file, arg);
1807 fprintf(file, ")");
1808 fprintf(file, ")\n\t\t{ return MIG_TYPE_ERROR ; }\n");
1809 }
1810
1811
1812 /* NDR Conversion routines */
1813
1814
1815 void
1816 WriteReplyNDRConvertIntRepArgCond(FILE *file, argument_t *arg)
1817 {
1818 routine_t *rt = arg->argRoutine;
1819
1820 fprintf(file, "defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
1821 }
1822
1823 void
1824 WriteReplyNDRConvertCharRepArgCond(FILE *file, argument_t *arg)
1825 {
1826 routine_t *rt = arg->argRoutine;
1827
1828 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
1829 fprintf(file, "defined(__NDR_convert__char_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
1830 else
1831 fprintf(file, "0");
1832 }
1833
1834 void
1835 WriteReplyNDRConvertFloatRepArgCond(FILE *file, argument_t *arg)
1836 {
1837 routine_t *rt = arg->argRoutine;
1838
1839 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
1840 fprintf(file, "defined(__NDR_convert__float_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
1841 else
1842 fprintf(file, "0");
1843 }
1844
1845 void
1846 WriteReplyNDRConvertIntRepArgDecl(FILE *file, argument_t *arg)
1847 {
1848 WriteNDRConvertArgDecl(file, arg, "int_rep", "Reply");
1849 }
1850
1851 void
1852 WriteReplyNDRConvertCharRepArgDecl(FILE *file, argument_t *arg)
1853 {
1854 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
1855 WriteNDRConvertArgDecl(file, arg, "char_rep", "Reply");
1856 }
1857
1858 void
1859 WriteReplyNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg)
1860 {
1861 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
1862 WriteNDRConvertArgDecl(file, arg, "float_rep", "Reply");
1863 }
1864
1865
1866
1867 void
1868 WriteReplyNDRConvertArgUse(FILE *file, argument_t *arg, char *convert)
1869 {
1870 routine_t *rt = arg->argRoutine;
1871 argument_t *count = arg->argCount;
1872 char argname[MAX_STR_LEN];
1873
1874 if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) &&
1875 (arg->argParent && akCheck(arg->argParent->argKind, akbReturnNdr)))
1876 return;
1877
1878 if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
1879 if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) {
1880 fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, count->argMsgField);
1881 fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argReplyPos, count->argMsgField, count->argReplyPos);
1882 fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, count->argMsgField);
1883 }
1884
1885 sprintf(argname, "(%s)(Out%dP->%s.address)", FetchServerType(arg->argType), arg->argReplyPos, arg->argMsgField);
1886 }
1887 else {
1888 sprintf(argname, "&Out%dP->%s", arg->argReplyPos, arg->argMsgField);
1889 }
1890
1891 fprintf(file, "#if defined(__NDR_convert__%s__Reply__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField);
1892 fprintf(file, "\t\t__NDR_convert__%s__Reply__%s_t__%s(%s, Out0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert);
1893 if (count)
1894 fprintf(file, ", Out%dP->%s", count->argReplyPos, count->argMsgField);
1895 fprintf(file, ");\n");
1896 fprintf(file, "#endif /* __NDR_convert__%s__Reply__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField);
1897 }
1898
1899 void
1900 WriteReplyNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg)
1901 {
1902 routine_t *rt = arg->argRoutine;
1903
1904 fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField);
1905 fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep)\n");
1906 fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argReplyPos, arg->argMsgField, arg->argReplyPos);
1907 fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField);
1908 }
1909
1910 void
1911 WriteReplyNDRConvertIntRepArgUse(FILE *file, argument_t *arg)
1912 {
1913 WriteReplyNDRConvertArgUse(file, arg, "int_rep");
1914 }
1915
1916 void
1917 WriteReplyNDRConvertCharRepArgUse(FILE *file, argument_t *arg)
1918 {
1919 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
1920 WriteReplyNDRConvertArgUse(file, arg, "char_rep");
1921 }
1922
1923 void
1924 WriteReplyNDRConvertFloatRepArgUse(FILE *file, argument_t *arg)
1925 {
1926 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
1927 WriteReplyNDRConvertArgUse(file, arg, "float_rep");
1928 }
1929
1930 static void
1931 WriteCheckMsgSize(FILE *file, argument_t *arg)
1932 {
1933 routine_t *rt = arg->argRoutine;
1934 ipc_type_t *it = arg->argType;
1935 ipc_type_t *btype = it->itElement;
1936
1937 /* If there aren't any more Out args after this, then
1938 we can use the msgh_size_delta value directly in
1939 the TypeCheck conditional. */
1940
1941 if (CheckNDR && arg->argCount && !arg->argSameCount)
1942 WriteReplyNDRConvertIntRepOneArgUse(file, arg->argCount);
1943
1944 if (arg->argReplyPos == rt->rtMaxReplyPos) {
1945 fprintf(file, "#if\t__MigTypeCheck\n");
1946
1947 /*
1948 * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type.
1949 */
1950 fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos,
1951 arg->argCount->argMsgField, it->itNumber/btype->itNumber);
1952 fputs("\t\t" "return MIG_TYPE_ERROR;\n", file);
1953 /* ...end... */
1954
1955 WriteCheckArgSize(file, rt, arg, "!=");
1956
1957 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1958 }
1959 else {
1960 /* If there aren't any more variable-sized arguments after this,
1961 then we must check for exact msg-size and we don't need
1962 to update msgh_size. */
1963
1964 boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar;
1965
1966 /* calculate the actual size in bytes of the data field. note
1967 that this quantity must be a multiple of four. hence, if
1968 the base type size isn't a multiple of four, we have to
1969 round up. note also that btype->itNumber must
1970 divide btype->itTypeSize (see itCalculateSizeInfo). */
1971
1972 fprintf(file, "\tmsgh_size_delta = ");
1973 WriteCalcArgSize(file, arg);
1974 fprintf(file, ";\n");
1975 fprintf(file, "#if\t__MigTypeCheck\n");
1976
1977 /*
1978 * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type.
1979 */
1980 fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos,
1981 arg->argCount->argMsgField, it->itNumber/btype->itNumber);
1982 fputs("\t\t" "return MIG_TYPE_ERROR;\n", file);
1983 /* ...end... */
1984
1985 WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<");
1986
1987 if (!LastVarArg)
1988 fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
1989
1990 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1991 }
1992 fprintf(file, "\n");
1993 }
1994
1995 void
1996 WriteAdjustReplyMsgPtr(FILE *file, argument_t *arg)
1997 {
1998 ipc_type_t *ptype = arg->argType;
1999
2000 fprintf(file, "\t*Out%dPP = Out%dP = (__Reply *) ((pointer_t) Out%dP + msgh_size_delta - %d);\n\n",
2001 arg->argReplyPos+1, arg->argReplyPos +1, arg->argReplyPos, ptype->itTypeSize + ptype->itPadSize);
2002 }
2003
2004 static void
2005 WriteReplyArgs(FILE *file, routine_t *rt)
2006 {
2007 argument_t *arg;
2008
2009 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2010 if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) {
2011 WriteExtractArgValueNormal(file, arg);
2012 }
2013 else if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnKPD)) {
2014 /*
2015 * KPDs have argReplyPos 0, therefore they escape the above logic
2016 */
2017 (*arg->argKPD_Extract)(file, arg);
2018 }
2019 else if (akCheck(arg->argKind, akbUserImplicit)) {
2020 WriteExtractArgValueNormal(file, arg);
2021 }
2022 }
2023 }
2024
2025 /*************************************************************
2026 * Writes code to return the return value. Called by WriteRoutine
2027 * for routines and functions.
2028 *************************************************************/
2029 static void
2030 WriteReturnValue(FILE *file, routine_t *rt)
2031 {
2032 /* If returning RetCode, we have already checked that it is KERN_SUCCESS */
2033 WriteReturn(file, rt, "\t", "KERN_SUCCESS", "\n", TRUE);
2034 }
2035
2036 /*************************************************************
2037 * Writes the elements of the message type declaration: the
2038 * msg_type structure, the argument itself and any padding
2039 * that is required to make the argument a multiple of 4 bytes.
2040 * Called by WriteRoutine for all the arguments in the request
2041 * message first and then the reply message.
2042 *************************************************************/
2043 static void
2044 WriteFieldDecl(FILE *file, argument_t *arg)
2045 {
2046 if (akCheck(arg->argKind, akbSendKPD) ||
2047 akCheck(arg->argKind, akbReturnKPD))
2048 WriteFieldDeclPrim(file, arg, FetchKPDType);
2049 else
2050 WriteFieldDeclPrim(file, arg, FetchUserType);
2051 }
2052
2053 /* Fill in the string with an expression that refers to the size
2054 * of the specified array:
2055 */
2056 static void
2057 GetArraySize(argument_t *arg, char *size)
2058 {
2059 ipc_type_t *it = arg->argType;
2060
2061 if (it->itVarArray) {
2062 if (arg->argCount->argByReferenceUser) {
2063 sprintf(size, "*%s", arg->argCount->argVarName);
2064 }
2065 else
2066 sprintf(size, "%s", arg->argCount->argVarName);
2067 }
2068 else {
2069 sprintf(size, "%d", (it->itNumber * it->itSize + 7) / 8);
2070 }
2071 }
2072
2073
2074 static void
2075 WriteRPCPortDisposition(FILE *file, argument_t *arg)
2076 {
2077 /*
2078 * According to the MIG specification, the port disposition could be different
2079 * on input and output. If we stay with this then a new bitfield will have
2080 * to be added. Right now the port disposition is the same for in and out cases.
2081 */
2082 switch(arg->argType->itInName) {
2083
2084 case MACH_MSG_TYPE_MOVE_RECEIVE:
2085 fprintf(file, " | MACH_RPC_MOVE_RECEIVE");
2086 break;
2087
2088 case MACH_MSG_TYPE_MOVE_SEND:
2089 fprintf(file, " | MACH_RPC_MOVE_SEND");
2090 break;
2091
2092 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
2093 fprintf(file, " | MACH_RPC_MOVE_SEND_ONCE");
2094 break;
2095
2096 case MACH_MSG_TYPE_COPY_SEND:
2097 fprintf(file, " | MACH_RPC_COPY_SEND");
2098 break;
2099
2100 case MACH_MSG_TYPE_MAKE_SEND:
2101 fprintf(file, " | MACH_RPC_MAKE_SEND");
2102 break;
2103
2104 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
2105 fprintf(file, " | MACH_RPC_MAKE_SEND_ONCE");
2106 break;
2107 }
2108 }
2109
2110 static void
2111 WriteRPCArgDescriptor(FILE *file, argument_t *arg, int offset)
2112 {
2113 fprintf(file, " {\n 0 ");
2114 if (RPCPort(arg)) {
2115 fprintf(file, "| MACH_RPC_PORT ");
2116 if (arg->argType->itNumber > 1)
2117 fprintf(file, "| MACH_RPC_ARRAY ");
2118 if (arg->argType->itVarArray)
2119 fprintf(file, "| MACH_RPC_VARIABLE ");
2120 WriteRPCPortDisposition(file, arg);
2121 }
2122 else if (RPCPortArray(arg)) {
2123 fprintf(file, "| MACH_RPC_PORT_ARRAY ");
2124 if (arg->argType->itVarArray)
2125 fprintf(file, "| MACH_RPC_VARIABLE ");
2126 WriteRPCPortDisposition(file, arg);
2127 }
2128 else if (RPCFixedArray(arg))
2129 fprintf(file, "| MACH_RPC_ARRAY_FIXED ");
2130 else if (RPCVariableArray(arg))
2131 fprintf(file, "| MACH_RPC_ARRAY_VARIABLE ");
2132 if (argIsIn(arg))
2133 fprintf(file, " | MACH_RPC_IN ");
2134 if (argIsOut(arg))
2135 fprintf(file, " | MACH_RPC_OUT ");
2136 if ((! arg->argType->itInLine) && (! arg->argType->itMigInLine))
2137 fprintf(file, " | MACH_RPC_POINTER ");
2138 if (arg->argFlags & flDealloc)
2139 fprintf(file, " | MACH_RPC_DEALLOCATE ");
2140 if (arg->argFlags & flPhysicalCopy)
2141 fprintf(file, " | MACH_RPC_PHYSICAL_COPY ");
2142 fprintf(file, ",\n");
2143 fprintf(file, " %d,\n", (arg->argType->itSize / 8));
2144 fprintf(file, " %d,\n", arg->argType->itNumber);
2145 fprintf(file, " %d,\n },\n", offset);
2146 }
2147
2148 void
2149 WriteRPCRoutineDescriptor(FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array)
2150 {
2151 fprintf(file, " { (mig_impl_routine_t) 0,\n\
2152 (mig_stub_routine_t) %s, ", stub_routine);
2153 fprintf(file, "%d, %d, %s}", arg_count, descr_count, sig_array);
2154 }
2155
2156 void
2157 WriteRPCRoutineArgDescriptor(FILE *file, routine_t *rt)
2158 {
2159 argument_t *arg;
2160 int offset = 0;
2161 int size = 0;
2162
2163 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2164 boolean_t compound = arg->argType->itStruct && arg->argType->itInLine;
2165
2166 if (RPCPort(arg) || RPCPortArray(arg) ||
2167 RPCFixedArray(arg) || RPCVariableArray(arg)) {
2168 WriteRPCArgDescriptor(file, arg, offset);
2169 size = 4;
2170 }
2171 if (! size) {
2172 if (compound)
2173 size = arg->argType->itNumber * (arg->argType->itSize / 8);
2174 else
2175 size = (arg->argType->itSize / 8);
2176 }
2177 if (akCheck(arg->argKind, akbServerArg))
2178 offset += size;
2179 size = 0;
2180 }
2181 }
2182
2183
2184 static void
2185 WriteRPCSignature(FILE *file, routine_t *rt)
2186 {
2187 int arg_count = 0;
2188 int descr_count = 0;
2189
2190 fprintf(file, " kern_return_t rtn;\n");
2191 descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count);
2192 fprintf(file, " const static struct\n {\n");
2193 fprintf(file, " struct rpc_routine_descriptor rd;\n");
2194 fprintf(file, " struct rpc_routine_arg_descriptor rad[%d];\n", descr_count);
2195 fprintf(file, " } sig =\n {\n");
2196 WriteRPCRoutineDescriptor(file, rt, arg_count, descr_count, "0", "sig.rad, 0");
2197 fprintf(file, ",\n");
2198 fprintf(file, " {\n");
2199 WriteRPCRoutineArgDescriptor(file, rt);
2200 fprintf(file, "\n }\n");
2201 fprintf(file, "\n };\n\n");
2202 }
2203
2204 static void
2205 WriteRPCCall(FILE *file, routine_t *rt)
2206 {
2207 argument_t *arg;
2208 int i;
2209
2210 i = 0;
2211 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2212 if (akIdent(arg->argKind) == akeRequestPort) {
2213 fprintf(file, " rtn = (MACH_RPC(&sig, (mach_msg_size_t)sizeof(sig), %d, %s,\n", rt->rtNumber + SubsystemBase, arg->argVarName);
2214 fprintf(file, " (%s", arg->argVarName);
2215 }
2216 else if (akCheck(arg->argKind, akbServerArg)) {
2217 if (i && (i++ % 6 == 0))
2218 fprintf(file, ",\n ");
2219 else
2220 fprintf(file, ", ");
2221 fprintf(file, "%s", arg->argVarName);
2222 }
2223 }
2224 fprintf(file, ")));\n");
2225 fprintf(file, "\n");
2226 fprintf(file, " if (rtn != KERN_NO_ACCESS) return rtn;\n\n");
2227 fprintf(file, "/* The following message rpc code is generated for the network case */\n\n");
2228 }
2229
2230 static int
2231 CheckRPCCall(routine_t *rt)
2232 {
2233 argument_t *arg;
2234 int i;
2235
2236 i = 0;
2237 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2238 if (akCheck(arg->argKind, akbUserArg) &&
2239 ((arg->argType->itOutName == -1) || (arg->argType->itInName == -1))) {
2240 return FALSE;
2241 }
2242 if (arg->argFlags & flMaybeDealloc) {
2243 return FALSE;
2244 }
2245 }
2246 return TRUE;
2247 }
2248
2249 static void
2250 WriteRPCRoutine(FILE *file, routine_t *rt)
2251 {
2252 if (CheckRPCCall(rt)) {
2253 WriteRPCSignature(file, rt);
2254 WriteRPCCall(file, rt);
2255 }
2256 }
2257
2258 /********************** End UserRPCTrap Routines*************************/
2259
2260 /* Process an IN/INOUT arg before the short-circuited RPC */
2261 static void
2262 WriteShortCircInArgBefore(FILE *file, argument_t *arg)
2263 {
2264 ipc_type_t *it = arg->argType;
2265 char size[128];
2266
2267 fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName);
2268
2269 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
2270 switch (arg->argKPD_Type) {
2271
2272 case MACH_MSG_PORT_DESCRIPTOR:
2273 break;
2274
2275 case MACH_MSG_OOL_DESCRIPTOR:
2276 /* Arg is an out-of-line array: */
2277 if (!(arg->argFlags & flDealloc) &&
2278 (!(arg->argFlags & flAuto) || !(arg->argFlags & flConst))) {
2279 /* Need to map a copy of the array: */
2280 GetArraySize(arg, size);
2281 fprintf(file, "\t(void)vm_read(mach_task_self(),\n");
2282 fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName);
2283 /* Point argument at the copy: */
2284 fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
2285 }
2286 else if ((arg->argFlags & flDealloc) &&
2287 ((arg->argFlags & flAuto) || it->itMigInLine)) {
2288 /* Point the temp var at the original argument: */
2289 fprintf(file, "\t_%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName);
2290 }
2291 break;
2292
2293 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2294 break;
2295
2296 default:
2297 printf("MiG internal error: type of kernel processed data unknown\n");
2298 exit(1);
2299 } /* end of switch */
2300 }
2301 else if (it->itNumber > 1) {
2302 if (it->itStruct) {
2303 /* Arg is a struct -- nothing to do. */
2304 }
2305 else {
2306 /* Arg is a C string or an in-line array: */
2307 if (!argIsOut(arg) && !(arg->argFlags & flConst)) {
2308 /* Have to copy it into a temp. Use a stack var, if this would
2309 * not overflow the -maxonstack specification:
2310 * Conservatively assume ILP32 thresholds
2311 */
2312 if (it->itTypeSize <= sizeof(natural_t) ||
2313 rtMessOnStack(arg->argRoutine) ||
2314 arg->argRoutine->rtTempBytesOnStack +
2315 it->itTypeSize <= MaxMessSizeOnStack) {
2316 fprintf(file, "\t{ char _%sTemp_[%d];\n", arg->argVarName, it->itTypeSize);
2317 arg->argRoutine->rtTempBytesOnStack += it->itTypeSize;
2318 arg->argTempOnStack = TRUE;
2319 }
2320 else {
2321 fprintf(file, "\t{ _%sTemp_ = (char *) %s(%d);\n", arg->argVarName, MessAllocRoutine, it->itTypeSize);
2322 arg->argTempOnStack = FALSE;
2323 }
2324 WriteCopyArg(file, arg, TRUE, "_%sTemp_", "/* %s */ (char *) %s", arg->argVarName, arg->argVarName);
2325 /* Point argument at temp: */
2326 fprintf(file, "\t *(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
2327 fprintf(file, "\t}\n");
2328 }
2329 }
2330 }
2331 }
2332
2333
2334 /* Process an INOUT/OUT arg before the short-circuited RPC */
2335 static void
2336 WriteShortCircOutArgBefore(FILE *file, argument_t *arg)
2337 {
2338 ipc_type_t *it = arg->argType;
2339
2340 fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName);
2341
2342 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
2343 switch (arg->argKPD_Type) {
2344
2345 case MACH_MSG_PORT_DESCRIPTOR:
2346 break;
2347
2348 case MACH_MSG_OOL_DESCRIPTOR:
2349 /* Arg is an out-of-line array: */
2350 if (!argIsIn(arg) && (arg->argFlags & flOverwrite)) {
2351 /* Point the temp var at the original argument: */
2352 fprintf(file, "\t _%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName);
2353 }
2354 break;
2355
2356 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2357 break;
2358
2359 default:
2360 printf("MiG internal error: type of kernel processed data unknown\n");
2361 exit(1);
2362 } /* end of switch */
2363 }
2364 else if (it->itNumber > 1) {
2365 /* Arg is an in-line array: */
2366 }
2367 }
2368
2369
2370
2371 /* Process an IN arg after the short-circuited RPC */
2372 static void
2373 WriteShortCircInArgAfter(FILE *file, argument_t *arg)
2374 {
2375 ipc_type_t *it = arg->argType;
2376 char size[128];
2377
2378 fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName);
2379
2380 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
2381 switch (arg->argKPD_Type) {
2382
2383 case MACH_MSG_PORT_DESCRIPTOR:
2384 break;
2385
2386 case MACH_MSG_OOL_DESCRIPTOR:
2387 /* Arg is an out-of-line array: */
2388 GetArraySize(arg, size);
2389 if ((!(arg->argFlags & flAuto) && it->itMigInLine) ||
2390 ((arg->argFlags & flAuto) &&
2391 ((arg->argFlags & flDealloc) ||
2392 !(arg->argFlags & flConst))
2393 )) {
2394 /* Need to dealloc the temporary: */
2395 fprintf(file, "\t(void)vm_deallocate(mach_task_self(),");
2396 fprintf(file, " (vm_address_t *) _%sTemp_, %s);\n", arg->argVarName, size);
2397 }
2398 break;
2399
2400 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2401 break;
2402
2403 default:
2404 printf("MiG internal error: type of kernel processed data unknown\n");
2405 exit(1);
2406 } /* end of switch */
2407 }
2408 else if (it->itNumber > 1) {
2409 if (it->itStruct) {
2410 /* Arg is a struct -- nothing to do. */
2411 }
2412 else {
2413 /* Arg is a C string or an in-line array: */
2414 if (!argIsOut(arg) && !(arg->argFlags & flConst)) {
2415 /* A temp needs to be deallocated, if not on stack: */
2416 if (!arg->argTempOnStack) {
2417 fprintf(file, "\t%s(_%sTemp_, %d);\n", MessFreeRoutine, arg->argVarName, it->itTypeSize);
2418 }
2419 }
2420 }
2421 }
2422 }
2423
2424 static void
2425 WriteShortCircOutArgAfter(FILE *file, argument_t *arg)
2426 {
2427 ipc_type_t *it = arg->argType;
2428 char size[128];
2429
2430 fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName);
2431
2432 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
2433 switch (arg->argKPD_Type) {
2434
2435 case MACH_MSG_PORT_DESCRIPTOR:
2436 break;
2437
2438 case MACH_MSG_OOL_DESCRIPTOR:
2439 /* Arg is an out-of-line array: */
2440
2441 /* Calculate size of array: */
2442 GetArraySize(arg, size);
2443 if (!(arg->argFlags & flDealloc) || (arg->argFlags & flOverwrite)) {
2444 /* Copy argument to vm_allocated Temp: */
2445 fprintf(file, "\t(void)vm_read(mach_task_self(),\n");
2446 fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName);
2447 if (!argIsIn(arg) && (arg->argFlags & flDealloc) &&
2448 (arg->argFlags & flOverwrite)) {
2449 /* Deallocate argument returned by server */
2450 fprintf(file, "\t(void)vm_deallocate(mach_task_self(),");
2451 fprintf(file, " (vm_address_t *) %s%s, %s);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size);
2452 }
2453 /* Point argument at new temporary: */
2454 fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
2455 }
2456 break;
2457
2458 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2459 break;
2460
2461 default:
2462 printf("MiG internal error: type of kernel processed data unknown\n");
2463 exit(1);
2464 } /* end of switch */
2465 }
2466 else if (it->itNumber != 1) {
2467 /* Arg is an in-line array: */
2468 }
2469 }
2470
2471
2472 static void
2473 WriteShortCircRPC(FILE *file, routine_t *rt)
2474 {
2475 argument_t *arg;
2476 int server_argc, i;
2477 boolean_t ShortCircOkay = TRUE;
2478 boolean_t first_OOL_arg = TRUE;
2479
2480 fprintf(file, " if (0 /* Should be: !(%s & 0x3) XXX */) {\n", rt->rtRequestPort->argVarName);
2481
2482 if (rt->rtOneWay) {
2483 /* Do not short-circuit simple routines: */
2484 ShortCircOkay = FALSE;
2485 }
2486 else {
2487 /* Scan for any types we can't yet handle. If found, give up on short-
2488 * circuiting and fall back to mach_msg:
2489 */
2490 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2491 if (arg->argFlags & flMaybeDealloc) {
2492 ShortCircOkay = FALSE;
2493 break;
2494 }
2495 /* Can't yet handle ports: */
2496 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
2497 (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR ||
2498 arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR)) {
2499 ShortCircOkay = FALSE;
2500 break;
2501 }
2502 }
2503 }
2504
2505 if (ShortCircOkay) {
2506
2507 fprintf(file," rpc_subsystem_t subsystem = ((rpc_port_t)%s)->rp_subsystem;\n", rt->rtRequestPort->argVarName);
2508 fprintf(file, "\n");
2509 fprintf(file, " if (subsystem && subsystem->start == %d) {\n", SubsystemBase);
2510 fprintf(file, "\tkern_return_t rtn;\n");
2511 fprintf(file, "\n");
2512
2513 /* Declare temp vars for out-of-line array args, and for all array
2514 * args, if -maxonstack has forced us to allocate in-line arrays
2515 * off the stack:
2516 */
2517 rt->rtTempBytesOnStack = 0;
2518 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2519 arg->argTempOnStack = FALSE;
2520 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
2521 arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
2522 if (first_OOL_arg) {
2523 /* Need a garbage temporary to hold the datacount
2524 * returned by vm_read, which we always ignore:
2525 */
2526 fprintf(file, "\tmach_msg_type_number_t _MIG_Ignore_Count_;\n");
2527 first_OOL_arg = FALSE;
2528 }
2529 }
2530 else if (!rtMessOnStack(rt) &&
2531 arg->argType->itNumber > 1 && !arg->argType->itStruct) {
2532 }
2533 else
2534 continue;
2535 fprintf(file, "\tchar *_%sTemp_;\n", arg->argVarName);
2536 /* Conservatively assume ILP32 thresholds */
2537 rt->rtTempBytesOnStack += sizeof(natural_t);
2538 }
2539
2540 /* Process the IN arguments, in order: */
2541
2542 fprintf(file, "\t/* Pre-Process the IN arguments: */\n");
2543 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2544 if (argIsIn(arg))
2545 WriteShortCircInArgBefore(file, arg);
2546 if (argIsOut(arg))
2547 WriteShortCircOutArgBefore(file, arg);
2548 }
2549 fprintf(file, "\n");
2550
2551 /* Count the number of server args: */
2552 server_argc = 0;
2553 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
2554 if (akCheck(arg->argKind, akbServerArg))
2555 server_argc++;
2556
2557 /* Call RPC_SIMPLE to switch to server stack and function: */
2558 i = 0;
2559 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2560 if (akIdent(arg->argKind) == akeRequestPort) {
2561 fprintf(file, "\trtn = RPC_SIMPLE(%s, %d, %d, (", arg->argVarName, rt->rtNumber + SubsystemBase, server_argc);
2562 fprintf(file, "%s", arg->argVarName);
2563 }
2564 else if (akCheck(arg->argKind, akbServerArg)) {
2565 if (i++ % 6 == 0)
2566 fprintf(file, ",\n\t\t");
2567 else
2568 fprintf(file, ", ");
2569 fprintf(file, "%s", arg->argVarName);
2570 }
2571 }
2572 fprintf(file, "));\n");
2573 fprintf(file, "\n");
2574
2575 /* Process the IN and OUT arguments, in order: */
2576 fprintf(file, "\t/* Post-Process the IN and OUT arguments: */\n");
2577 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2578 if (argIsIn(arg))
2579 WriteShortCircInArgAfter(file, arg);
2580 if (argIsOut(arg))
2581 WriteShortCircOutArgAfter(file, arg);
2582 }
2583 fprintf(file, "\n");
2584
2585 fprintf(file, "\treturn rtn;\n");
2586 fprintf(file, " }\n");
2587 }
2588
2589 /* In latest design, the following is not necessary, because in
2590 * kernel-loaded tasks, the Mach port name is the same as the handle
2591 * used by the RPC mechanism, namely a pointer to the ipc_port, and
2592 * in user-mode tasks, the Mach port name gets renamed to be a pointer
2593 * to the user-mode rpc_port_t struct.
2594 */
2595 #if 0
2596 if (IsKernelUser)
2597 fprintf(file, " %s = (ipc_port_t)%s->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName);
2598 else
2599 fprintf(file, " %s = ((rpc_port_t)%s)->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName);
2600 #endif
2601
2602 fprintf(file, " }\n");
2603 }
2604
2605 static void
2606 WriteStubDecl(FILE *file, routine_t *rt)
2607 {
2608 fprintf(file, "\n");
2609 fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
2610 fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName);
2611 if (BeAnsiC) {
2612 fprintf(file, "(\n");
2613 WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
2614 fprintf(file, ")\n");
2615 }
2616 else {
2617 fprintf(file, "#if\t%s\n", NewCDecl);
2618 fprintf(file, "(\n");
2619 WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
2620 fprintf(file, ")\n");
2621 fprintf(file, "#else\n");
2622 fprintf(file, "\t(");
2623 WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
2624 fprintf(file, ")\n");
2625 WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
2626 fprintf(file, "#endif\t/* %s */\n", NewCDecl);
2627 }
2628 fprintf(file, "{\n");
2629 }
2630
2631 static void
2632 InitKPD_Disciplines(argument_t *args)
2633 {
2634 argument_t *arg;
2635 extern void KPD_noop(FILE *file, argument_t *arg);
2636 extern void KPD_error(FILE *file, argument_t *arg);
2637 extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in);
2638 extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in);
2639 extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in);
2640
2641 /*
2642 * WriteKPD_port, WriteExtractKPD_port,
2643 * WriteKPD_ool, WriteExtractKPD_ool,
2644 * WriteKPD_oolport, WriteExtractKPD_oolport
2645 * are local to this module (which is the reason why this initialization
2646 * takes place here rather than in utils.c).
2647 * Common routines for user and server will be established SOON, and
2648 * all of them (including the initialization) will be transfert to
2649 * utils.c
2650 * All the KPD disciplines are defaulted to be KPD_error().
2651 * Note that akbSendKPD and akbReturnKPd are not exclusive,
2652 * because of inout type of parameters.
2653 */
2654 for (arg = args; arg != argNULL; arg = arg->argNext)
2655 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD))
2656 switch (arg->argKPD_Type) {
2657
2658 case MACH_MSG_PORT_DESCRIPTOR:
2659 arg->argKPD_Init = KPD_noop;
2660 if akCheck(arg->argKind, akbSendKPD) {
2661 arg->argKPD_Template = WriteTemplateKPD_port;
2662 arg->argKPD_Pack = WriteKPD_port;
2663 }
2664 if akCheck(arg->argKind, akbReturnKPD) {
2665 arg->argKPD_Extract = WriteExtractKPD_port;
2666 arg->argKPD_TypeCheck = WriteTCheckKPD_port;
2667 }
2668 break;
2669
2670 case MACH_MSG_OOL_DESCRIPTOR:
2671 arg->argKPD_Init = KPD_noop;
2672 if akCheck(arg->argKind, akbSendKPD) {
2673 arg->argKPD_Template = WriteTemplateKPD_ool;
2674 arg->argKPD_Pack = WriteKPD_ool;
2675 }
2676 if akCheck(arg->argKind, akbReturnKPD) {
2677 arg->argKPD_TypeCheck = WriteTCheckKPD_ool;
2678 arg->argKPD_Extract = WriteExtractKPD_ool;
2679 }
2680 break;
2681
2682 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2683 arg->argKPD_Init = KPD_noop;
2684 if akCheck(arg->argKind, akbSendKPD) {
2685 arg->argKPD_Template = WriteTemplateKPD_oolport;
2686 arg->argKPD_Pack = WriteKPD_oolport;
2687 }
2688 if akCheck(arg->argKind, akbReturnKPD) {
2689 arg->argKPD_TypeCheck = WriteTCheckKPD_oolport;
2690 arg->argKPD_Extract = WriteExtractKPD_oolport;
2691 }
2692 break;
2693
2694 default:
2695 printf("MiG internal error: type of kernel processed data unknown\n");
2696 exit(1);
2697 } /* end of switch */
2698 }
2699
2700 static void
2701 WriteLimitCheck(FILE *file, routine_t *rt)
2702 {
2703 if (MaxMessSizeOnStack == -1 || UserTypeLimit == -1)
2704 return;
2705 if (!rt->rtRequestUsedLimit && !rt->rtReplyUsedLimit)
2706 return;
2707 fprintf(file, "#if LimitCheck\n");
2708 if (rt->rtRequestUsedLimit) {
2709 if (rt->rtRequestFits) {
2710 fprintf(file, "\tif ((sizeof(Request) - %d) > %d)\n", rt->rtRequestSizeKnown, UserTypeLimit);
2711 fprintf(file, "\t __RequestOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
2712 }
2713 else if (rt->rtReplyFits) {
2714 fprintf(file, "\tif (sizeof(Request) < %d)\n", MaxMessSizeOnStack);
2715 fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
2716 }
2717 }
2718 if (rt->rtReplyUsedLimit) {
2719 if (rt->rtReplyFits) {
2720 fprintf(file, "\tif ((sizeof(Reply) - %d) > %d)\n", rt->rtReplySizeKnown, UserTypeLimit);
2721 fprintf(file, "\t __ReplyOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
2722 }
2723 else if (rt->rtRequestFits) {
2724 fprintf(file, "\tif (sizeof(Reply) < %d)\n", MaxMessSizeOnStack);
2725 fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
2726 }
2727 }
2728 if (rt->rtRequestUsedLimit && rt->rtReplyUsedLimit &&
2729 ! (rt->rtRequestFits || rt->rtReplyFits)) {
2730 fprintf(file, "\tif (sizeof(Request) < %d \n", MaxMessSizeOnStack);
2731 fprintf(file, "&& sizeof(Reply) < %d)\n", MaxMessSizeOnStack);
2732 fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
2733 }
2734 fprintf(file, "#endif /* LimitCheck */\n");
2735 }
2736
2737 static void
2738 WriteOOLSizeCheck(FILE *file, routine_t *rt)
2739 {
2740 /* Emit code to validate the actual size of ool data vs. the reported size */
2741 argument_t *argPtr;
2742 boolean_t openedTypeCheckConditional = FALSE;
2743
2744 // scan through arguments to see if there are any ool data blocks
2745 for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2746 if (akCheck(argPtr->argKind, akbReturnKPD)) {
2747 ipc_type_t *it = argPtr->argType;
2748 boolean_t multiple_kpd = IS_MULTIPLE_KPD(it);
2749 char string[MAX_STR_LEN];
2750 boolean_t test;
2751 argument_t *argCountPtr;
2752 char *tab;
2753
2754 if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
2755
2756 if (multiple_kpd) {
2757 if ( !openedTypeCheckConditional ) {
2758 openedTypeCheckConditional = TRUE;
2759 fputs("#if __MigTypeCheck\n", file);
2760 }
2761
2762 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE);
2763 tab = "\t";
2764 sprintf(string, "ptr->");
2765 test = !it->itVarArray && !it->itElement->itVarArray;
2766 it = it->itElement; // point to element descriptor, so size calculation is correct
2767 argCountPtr = argPtr->argSubCount;
2768 } else {
2769 tab = "";
2770 sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField);
2771 test = !it->itVarArray;
2772 argCountPtr = argPtr->argCount;
2773 }
2774
2775 if (!test) {
2776 int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1;
2777
2778 if ( !openedTypeCheckConditional ) {
2779 openedTypeCheckConditional = TRUE;
2780 fputs("#if __MigTypeCheck\n", file);
2781 }
2782
2783 fprintf(file, "\t%s" "if (%ssize ", tab, string);
2784 if (multiplier > 1)
2785 fprintf(file, "/ %d ", multiplier);
2786 fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
2787 if (it->itOOL_Number) {
2788 fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos,
2789 argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
2790 }
2791 fprintf(file,")\n");
2792 fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
2793 }
2794
2795 if (multiple_kpd)
2796 fprintf(file, "\t }\n\t}\n");
2797 } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) {
2798 if (multiple_kpd) {
2799 if ( !openedTypeCheckConditional ) {
2800 openedTypeCheckConditional = TRUE;
2801 fputs("#if __MigTypeCheck\n", file);
2802 }
2803
2804 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE);
2805 tab = "\t";
2806 sprintf(string, "ptr->");
2807 test = !it->itVarArray && !it->itElement->itVarArray;
2808 it = it->itElement; // point to element descriptor, so size calculation is correct
2809 argCountPtr = argPtr->argSubCount;
2810 } else {
2811 tab = "";
2812 sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField);
2813 test = !it->itVarArray;
2814 argCountPtr = argPtr->argCount;
2815 }
2816
2817 if (!test) {
2818 if ( !openedTypeCheckConditional ) {
2819 openedTypeCheckConditional = TRUE;
2820 fputs("#if __MigTypeCheck\n", file);
2821 }
2822
2823 fprintf(file, "\t%s" "if (%scount ", tab, string);
2824 fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
2825 if (it->itOOL_Number) {
2826 fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos,
2827 argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
2828 }
2829 fprintf(file,")\n");
2830 fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
2831 }
2832
2833 if (multiple_kpd)
2834 fprintf(file, "\t }\n\t}\n");
2835 }
2836 }
2837 }
2838
2839 if ( openedTypeCheckConditional )
2840 fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file);
2841 }
2842
2843 static void
2844 WriteCheckReply(FILE *file, routine_t *rt)
2845 {
2846 int i;
2847
2848 /* initialize the disciplines for the handling of KPDs */
2849 InitKPD_Disciplines(rt->rtArgs);
2850
2851 if (rt->rtOneWay)
2852 return;
2853
2854 fprintf(file, "\n");
2855 fprintf(file, "#if ( __MigTypeCheck ");
2856 if (CheckNDR)
2857 fprintf(file, "|| __NDR_convert__ ");
2858 fprintf(file, ")\n");
2859 fprintf(file, "#if __MIG_check__Reply__%s_subsystem__\n", SubsystemName);
2860 fprintf(file, "#if !defined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName);
2861 fprintf(file, "#define __MIG_check__Reply__%s_t__defined\n", rt->rtName);
2862 if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) {
2863 WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgDecl, akbReturnNdr, "\n", "\n");
2864 WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgDecl, akbReturnNdr, "\n", "\n");
2865 WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgDecl, akbReturnNdr, "\n", "\n");
2866 }
2867 fprintf(file, "\n");
2868 fprintf(file, "mig_internal kern_return_t __MIG_check__Reply__%s_t(__Reply__%s_t *Out0P", rt->rtName, rt->rtName);
2869 for (i = 1; i <= rt->rtMaxReplyPos; i++)
2870 fprintf(file, ", __Reply__%s_t **Out%dPP", rt->rtName, i);
2871 fprintf(file, ")\n{\n");
2872
2873
2874 fprintf(file, "\n\ttypedef __Reply__%s_t __Reply __attribute__((unused));\n", rt->rtName);
2875 for (i = 1; i <= rt->rtMaxReplyPos; i++)
2876 fprintf(file, "\t__Reply *Out%dP;\n", i);
2877 if (!rt->rtSimpleReply)
2878 fprintf(file, "\tboolean_t msgh_simple;\n");
2879 if (!rt->rtNoReplyArgs) {
2880 fprintf(file, "#if\t__MigTypeCheck\n");
2881 fprintf(file, "\tunsigned int msgh_size;\n");
2882 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
2883 }
2884 if (rt->rtMaxReplyPos > 0)
2885 fprintf(file, "\tunsigned int msgh_size_delta;\n");
2886 if (rt->rtNumReplyVar > 0 || rt->rtMaxReplyPos > 0)
2887 fprintf(file, "\n");
2888
2889 /* Check the values that are returned in the reply message */
2890
2891 WriteCheckIdentity(file, rt);
2892
2893 /* Check the remote port is NULL */
2894 fprintf(file, "#if\t__MigTypeCheck\n");
2895 fprintf(file, "\tif (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {\n");
2896 fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
2897 fprintf(file, "\t}\n");
2898 fprintf(file, "#endif\t/* __MigTypeCheck */\n");
2899
2900 /* If the reply message has no Out parameters or return values
2901 other than the return code, we can type-check it and
2902 return it directly. */
2903
2904 if (rt->rtNoReplyArgs && !rt->rtUserImpl) {
2905 if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply) && rt->rtRetCode)
2906 WriteReplyNDRConvertIntRepOneArgUse(file, rt->rtRetCode);
2907 WriteReturn(file, rt, "\t", stRetCode, "\n", FALSE);
2908 }
2909 else {
2910 if (UseEventLogger)
2911 WriteLogMsg(file, rt, LOG_USER, LOG_REPLY);
2912
2913 WriteRetCodeCheck(file, rt);
2914
2915 /* Type Checking for the Out parameters which are typed */
2916 WriteList(file, rt->rtArgs, WriteTypeCheck, akbReturnKPD, "\n", "\n");
2917
2918 {
2919 argument_t *arg, *lastVarArg;
2920
2921 lastVarArg = argNULL;
2922 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2923 /*
2924 * Advance message pointer if the last reply argument was
2925 * variable-length and the reply position will change.
2926 */
2927 if (lastVarArg != argNULL &&
2928 lastVarArg->argReplyPos < arg->argReplyPos) {
2929 WriteAdjustReplyMsgPtr(file, lastVarArg);
2930 lastVarArg = argNULL;
2931 }
2932
2933 if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) {
2934 if (akCheck(arg->argKind, akbVariable)) {
2935 WriteCheckMsgSize(file, arg);
2936 lastVarArg = arg;
2937 }
2938 }
2939 }
2940 }
2941
2942 if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) {
2943 fprintf(file, "#if\t");
2944 WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
2945 fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep) {\n");
2946 WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgUse, akbReturnNdr, "", "");
2947 fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n");
2948
2949 WriteOOLSizeCheck(file, rt);
2950
2951 fprintf(file, "#if\t");
2952 WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
2953 fprintf(file, "\tif (Out0P->NDR.char_rep != NDR_record.char_rep) {\n");
2954 WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgUse, akbReturnNdr, "", "");
2955 fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n");
2956
2957 fprintf(file, "#if\t");
2958 WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
2959 fprintf(file, "\tif (Out0P->NDR.float_rep != NDR_record.float_rep) {\n");
2960 WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgUse, akbReturnNdr, "", "");
2961 fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n");
2962 } else {
2963 WriteOOLSizeCheck(file, rt);
2964 }
2965 fprintf(file, "\treturn MACH_MSG_SUCCESS;\n");
2966 }
2967 fprintf(file, "}\n");
2968 fprintf(file, "#endif /* !defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName);
2969 fprintf(file, "#endif /* __MIG_check__Reply__%s_subsystem__ */\n", SubsystemName);
2970 fprintf(file, "#endif /* ( __MigTypeCheck ");
2971 if (CheckNDR)
2972 fprintf(file, "|| __NDR_convert__ ");
2973 fprintf(file, ") */\n\n");
2974 }
2975
2976 static void
2977 WriteCheckReplyCall(FILE *file, routine_t *rt)
2978 {
2979 int i;
2980
2981 fprintf(file, "\n");
2982 fprintf(file, "#if\tdefined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName);
2983 fprintf(file, "\tcheck_result = __MIG_check__Reply__%s_t((__Reply__%s_t *)Out0P", rt->rtName, rt->rtName);
2984 for (i = 1; i <= rt->rtMaxReplyPos; i++)
2985 fprintf(file, ", (__Reply__%s_t **)&Out%dP", rt->rtName, i);
2986 fprintf(file, ");\n");
2987 fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS) {\n");
2988 if (IsKernelUser) {
2989 fprintf(file, "#if\t__MigKernelSpecificCode\n");
2990 fprintf(file, "\t\tmach_msg_destroy_from_kernel(&Out0P->Head);\n");
2991 fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
2992 } else {
2993 fprintf(file, "\t\tmach_msg_destroy(&Out0P->Head);\n");
2994 }
2995 WriteReturnMsgError(file, rt, TRUE, argNULL, "check_result");
2996 fprintf(file, "\t}\n");
2997 fprintf(file, "#endif\t/* defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName);
2998 fprintf(file, "\n");
2999 }
3000
3001 void
3002 WriteCheckReplies(FILE *file, statement_t *stats)
3003 {
3004 statement_t *stat;
3005
3006 for (stat = stats; stat != stNULL; stat = stat->stNext)
3007 if (stat->stKind == skRoutine)
3008 WriteCheckReply(file, stat->stRoutine);
3009 }
3010
3011 static void
3012 WriteCheckReplyTrailerArgs(FILE *file, routine_t *rt)
3013 {
3014 argument_t *arg;
3015
3016 if (rt->rtUserImpl)
3017 WriteCheckTrailerHead(file, rt, TRUE);
3018
3019 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
3020 if (akCheck(arg->argKind, akbUserImplicit))
3021 WriteCheckTrailerSize(file, TRUE, arg);
3022 }
3023 if (rt->rtUserImpl)
3024 fprintf(file, "\n");
3025 }
3026
3027
3028 /*************************************************************
3029 * Writes all the code comprising a routine body. Called by
3030 * WriteUser for each routine.
3031 *************************************************************/
3032 static void
3033 WriteRoutine(FILE *file, routine_t *rt)
3034 {
3035 /* write the stub's declaration */
3036 WriteStubDecl(file, rt);
3037
3038 /* Use the RPC trap for user-user and user-kernel RPC */
3039 if (UseRPCTrap)
3040 WriteRPCRoutine(file, rt);
3041
3042 /* write the code for doing a short-circuited RPC: */
3043 if (ShortCircuit)
3044 WriteShortCircRPC(file, rt);
3045
3046 /* typedef of structure for Request and Reply messages */
3047 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, FALSE, FALSE, FALSE);
3048 if (!rt->rtOneWay) {
3049 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply", rt->rtSimpleReply, TRUE, rt->rtUserImpl, FALSE);
3050 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "__Reply", rt->rtSimpleReply, FALSE, FALSE, FALSE);
3051 }
3052 if (rt->rtOverwrite)
3053 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply|akbOverwrite, "OverwriteTemplate", FALSE, TRUE, FALSE, TRUE);
3054 /*
3055 * Define a Minimal Reply structure to be used in case of errors
3056 */
3057 fprintf(file, "\t/*\n");
3058 fprintf(file, "\t * typedef struct {\n");
3059 fprintf(file, "\t * \tmach_msg_header_t Head;\n");
3060 fprintf(file, "\t * \tNDR_record_t NDR;\n");
3061 fprintf(file, "\t * \tkern_return_t RetCode;\n");
3062 fprintf(file, "\t * } mig_reply_error_t;\n");
3063 fprintf(file, "\t */\n");
3064 fprintf(file, "\n");
3065
3066
3067 /* declarations for local vars: Union of Request and Reply messages,
3068 InP, OutP and return value */
3069
3070 WriteVarDecls(file, rt);
3071
3072 /* declarations and initializations of the mach_msg_type_descriptor_t variables
3073 for each argument that is a Kernel Processed Data */
3074
3075 WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbRequest | akbSendKPD, "\n", "\n");
3076
3077 WriteLimitCheck(file, rt);
3078 WriteRetCodeArg(file, rt);
3079
3080 /* fill in the fields that are non related to parameters */
3081
3082 if (!rt->rtSimpleRequest)
3083 fprintf(file, "\tInP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtRequestKPDs);
3084
3085 /* fill in all the request message types and then arguments */
3086
3087 WriteRequestArgs(file, rt);
3088
3089 /* fill in request message head */
3090
3091 WriteRequestHead(file, rt);
3092 fprintf(file, "\n");
3093
3094 /* give the application a chance to do some stuff. */
3095 WriteApplMacro(file, "Send", "Before", rt);
3096
3097 /* Write the send/receive or rpc call */
3098
3099 if (UseEventLogger)
3100 WriteLogMsg(file, rt, LOG_USER, LOG_REQUEST);
3101
3102
3103 if (rt->rtOneWay) {
3104 WriteMsgSend(file, rt);
3105 }
3106 else {
3107 if (UseMsgRPC
3108 #if USE_IMMEDIATE_SEND_TIMEOUT
3109 && (rt->rtWaitTime == argNULL)
3110 #endif
3111 ) {
3112 /* overwrite mode meaningful only when UseMsgRPC is enabled */
3113 if (rt->rtOverwrite)
3114 WriteOverwriteTemplate(file, rt);
3115 WriteMsgRPC(file, rt);
3116 }
3117 else
3118 WriteMsgSendReceive(file, rt);
3119
3120 WriteCheckReplyCall(file, rt);
3121 WriteCheckReplyTrailerArgs(file, rt);
3122
3123 if (UseEventLogger)
3124 WriteLogMsg(file, rt, LOG_USER, LOG_REPLY);
3125
3126 WriteReplyArgs(file, rt);
3127 }
3128 /* return the return value, if any */
3129 if (!rt->rtOneWay) // WriteMsgSend() already wrote the 'return'
3130 WriteReturnValue(file, rt);
3131 fprintf(file, "}\n");
3132 }
3133
3134 static void
3135 WriteRPCClientFunctions(FILE *file, statement_t *stats)
3136 {
3137 statement_t *stat;
3138 char *fname;
3139 char *argfmt = "(mach_port_t, char *, mach_msg_type_number_t)";
3140
3141 fprintf(file, "#ifdef AUTOTEST\n");
3142 for (stat = stats; stat != stNULL; stat = stat->stNext)
3143 if (stat->stKind == skRoutine) {
3144 fname = stat->stRoutine->rtName;
3145 fprintf(file, "extern void client_%s%s;\n", fname, argfmt);
3146 }
3147 fprintf(file, "function_table_entry %s_client_functions[] =\n", SubsystemName);
3148 fprintf(file, "{\n");
3149 for (stat = stats; stat != stNULL; stat = stat->stNext)
3150 if (stat->stKind == skRoutine) {
3151 fname = stat->stRoutine->rtName;
3152 fprintf(file, " { \"%s\", client_%s },\n", fname, fname);
3153 }
3154 fprintf(file, " { (char *) 0, (function_ptr_t) 0 }\n");
3155 fprintf(file, "};\n");
3156 fprintf(file, "#endif /* AUTOTEST */\n");
3157 }
3158
3159 /*************************************************************
3160 * Writes out the xxxUser.c file. Called by mig.c
3161 *************************************************************/
3162 void
3163 WriteUser(FILE *file, statement_t *stats)
3164 {
3165 statement_t *stat;
3166
3167 WriteProlog(file, stats);
3168 if (TestRPCTrap)
3169 WriteRPCClientFunctions(file, stats);
3170 for (stat = stats; stat != stNULL; stat = stat->stNext)
3171 switch (stat->stKind) {
3172
3173 case skRoutine:
3174 WriteCheckReply(file, stat->stRoutine);
3175 WriteRoutine(file, stat->stRoutine);
3176 break;
3177
3178 case skImport:
3179 case skUImport:
3180 case skSImport:
3181 case skDImport:
3182 case skIImport:
3183 break;
3184
3185 default:
3186 fatal("WriteUser(): bad statement_kind_t (%d)", (int) stat->stKind);
3187 }
3188 WriteEpilog(file);
3189 }
3190
3191 /*************************************************************
3192 * Writes out individual .c user files for each routine. Called by mig.c
3193 *************************************************************/
3194 void
3195 WriteUserIndividual(statement_t *stats)
3196 {
3197 statement_t *stat;
3198
3199 for (stat = stats; stat != stNULL; stat = stat->stNext)
3200 switch (stat->stKind) {
3201
3202 case skRoutine: {
3203 FILE *file;
3204 char *filename;
3205
3206 filename = strconcat(UserFilePrefix, strconcat(stat->stRoutine->rtName, ".c"));
3207 file = fopen(filename, "w");
3208 if (file == NULL)
3209 fatal("fopen(%s): %s", filename, strerror(errno));
3210 WriteProlog(file, stats);
3211 WriteRoutine(file, stat->stRoutine);
3212 WriteEpilog(file);
3213 fclose(file);
3214 strfree(filename);
3215 }
3216 break;
3217
3218 case skImport:
3219 case skUImport:
3220 case skSImport:
3221 case skDImport:
3222 case skIImport:
3223 break;
3224
3225 default:
3226 fatal("WriteUserIndividual(): bad statement_kind_t (%d)", (int) stat->stKind);
3227 }
3228 }