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