aboutsummaryrefslogtreecommitdiffstats
path: root/bootstrap_cmds/migcom.tproj/user.c
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /bootstrap_cmds/migcom.tproj/user.c
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
Import macOS userland
adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106
Diffstat (limited to 'bootstrap_cmds/migcom.tproj/user.c')
-rw-r--r--bootstrap_cmds/migcom.tproj/user.c3260
1 files changed, 3260 insertions, 0 deletions
diff --git a/bootstrap_cmds/migcom.tproj/user.c b/bootstrap_cmds/migcom.tproj/user.c
new file mode 100644
index 0000000..839732d
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/user.c
@@ -0,0 +1,3260 @@
+/*
+ * Copyright (c) 1999-2018 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+
+#include <mach/message.h>
+#include "write.h"
+#include "error.h"
+#include "utils.h"
+#include "global.h"
+
+#ifndef DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT
+#define DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT 1
+#endif
+
+#ifndef DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR
+#define DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR 1
+#endif
+
+#ifndef USE_IMMEDIATE_SEND_TIMEOUT
+#define USE_IMMEDIATE_SEND_TIMEOUT 0
+#endif
+
+char *MessAllocRoutine = "mig_user_allocate";
+char *MessFreeRoutine = "mig_user_deallocate";
+
+char stRetCode[] = "ReturnValue";
+char stRetNone[] = "";
+
+void WriteLogDefines(FILE *file, string_t who);
+void WriteIdentificationString(FILE *file);
+
+static void
+WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t overwrite, boolean_t varying, argument_t *arg, boolean_t bracket)
+{
+ ipc_type_t *it = arg->argType;
+ char string[MAX_STR_LEN];
+
+ fprintf(file, "\t{\n");
+ fprintf(file, "\t %s\t*ptr;\n", it->itKPDType);
+ fprintf(file, "\t int\ti");
+ if (varying && !in)
+ fprintf(file, ", j");
+ fprintf(file, ";\n\n");
+
+ if (in)
+ sprintf(string, "InP");
+ else if (overwrite)
+ sprintf(string, "InOvTemplate");
+ else
+ sprintf(string, "Out%dP", arg->argRequestPos);
+
+ fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField);
+
+ if (varying) {
+ argument_t *count = arg->argCount;
+ char *cref = count->argByReferenceUser ? "*" : "";
+
+ if (in || overwrite) {
+ fprintf(file, "\t if (%s%s > %d)\n", cref, count->argVarName, it->itKPD_Number);
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+ fprintf(file, "\t for (i = 0; i < %s%s; ptr++, i++) %s\n", cref, count->argVarName, (bracket) ? "{" : "");
+ }
+ else {
+ fprintf(file, "\t j = min(Out%dP->%s, %s%s);\n", count->argReplyPos, count->argVarName, cref, count->argVarName);
+ fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n",(bracket) ? "{" : "");
+}
+ }
+ else
+ fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : "");
+}
+
+/*************************************************************
+ * Writes the standard includes. The subsystem specific
+ * includes are in <SubsystemName>.h and writen by
+ * header:WriteHeader. Called by WriteProlog.
+ *************************************************************/
+static void
+WriteMyIncludes(FILE *file, statement_t *stats)
+{
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelServer)
+ {
+ /*
+ * We want to get the user-side definitions of types
+ * like task_t, ipc_space_t, etc. in mach/mach_types.h.
+ */
+
+ fprintf(file, "#undef\tMACH_KERNEL\n");
+
+ if (InternalHeaderFileName != strNULL)
+ {
+ char *cp;
+
+ /* Strip any leading path from InternalHeaderFileName. */
+ cp = strrchr(InternalHeaderFileName, '/');
+ if (cp == 0)
+ cp = InternalHeaderFileName;
+ else
+ cp++; /* skip '/' */
+ fprintf(file, "#include \"%s\"\n", cp);
+ }
+ }
+#endif
+
+ if (UserHeaderFileName == strNULL || UseSplitHeaders)
+ WriteIncludes(file, TRUE, FALSE);
+ if (UserHeaderFileName != strNULL)
+ {
+ char *cp;
+
+ /* Strip any leading path from UserHeaderFileName. */
+ cp = strrchr(UserHeaderFileName, '/');
+ if (cp == 0)
+ cp = UserHeaderFileName;
+ else
+ cp++; /* skip '/' */
+ fprintf(file, "#include \"%s\"\n", cp);
+ }
+ if (UseSplitHeaders)
+ WriteImplImports(file, stats, TRUE);
+
+ if (UseEventLogger) {
+ if (IsKernelUser) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "#include <mig_debug.h>\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "#include <mach/mig_log.h>\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n");
+ }
+ if (HasConsumeOnSendError && !IsKernelUser) {
+ fprintf(file, "#include <mach/mach.h>\n");
+ }
+ if (BeLint) {
+ fprintf(file, "/* LINTLIBRARY */\n");
+ }
+ fprintf(file, "\n");
+ if (!BeAnsiC) {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "#else\t/* %s */\n", NewCDecl);
+ fprintf(file, "extern mach_port_t mig_get_reply_port();\n");
+ fprintf(file, "extern void mig_dealloc_reply_port();\n");
+ fprintf(file, "extern char *%s();\n", MessAllocRoutine);
+ fprintf(file, "extern void %s();\n", MessFreeRoutine);
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ if (HasUseSpecialReplyPort) {
+ fprintf(file, "\n");
+ fprintf(file, "#include <TargetConditionals.h>\n");
+ fprintf(file, "#include <mach/mach_sync_ipc.h>\n");
+#if DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR
+ fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n");
+ fprintf(file, "#if TARGET_OS_SIMULATOR\n");
+ fprintf(file, "#define __MigCanUseSpecialReplyPort 0\n");
+ fprintf(file, "#define mig_get_special_reply_port() MACH_PORT_DEAD\n");
+ fprintf(file, "#define mig_dealloc_special_reply_port(port) __builtin_trap()\n");
+ fprintf(file, "#endif\n");
+ fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n");
+#endif
+#if DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT
+ fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n");
+ fprintf(file, "#if TARGET_OS_OSX\n");
+ fprintf(file, "extern _Bool _os_xbs_chrooted;\n");
+ fprintf(file, "#define __MigCanUseSpecialReplyPort (!_os_xbs_chrooted)\n");
+ fprintf(file, "#endif\n");
+ fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n");
+#endif
+ fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n");
+ fprintf(file, "#define __MigCanUseSpecialReplyPort 1\n");
+ fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n");
+ fprintf(file, "#ifndef __MigSpecialReplyPortMsgOption\n");
+ fprintf(file, "#define __MigSpecialReplyPortMsgOption (__MigCanUseSpecialReplyPort ? "
+ "(MACH_SEND_SYNC_OVERRIDE|MACH_SEND_SYNC_USE_THRPRI|MACH_RCV_SYNC_WAIT) : MACH_MSG_OPTION_NONE)\n");
+ fprintf(file, "#endif /* __MigSpecialReplyPortMsgOption */\n");
+ }
+ /*
+ * extern the definition of mach_msg_destroy
+ * (to avoid inserting mach/mach.h everywhere)
+ */
+ fprintf(file, "/* TODO: #include <mach/mach.h> */\n");
+ fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n");
+ fprintf(file, "extern void mach_msg_destroy(mach_msg_header_t *);\n");
+ fprintf(file, "#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n");
+
+ fprintf(file, "\n");
+}
+
+static void
+WriteGlobalDecls(FILE *file)
+{
+ if (RCSId != strNULL)
+ WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId);
+
+ fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
+ fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
+ fprintf(file, "\n");
+ if (UseEventLogger)
+ WriteLogDefines(file, "MACH_MSG_LOG_USER");
+ fprintf(file, "\n");
+}
+
+static void
+WriteOneMachErrorDefine(FILE *file, char *name, boolean_t timeout, boolean_t SpecialReplyPort)
+{
+ fprintf(file, "#ifndef\t%s\n", name);
+ fprintf(file, "#define\t%s(_R_) { \\\n", name);
+ fprintf(file, "\tswitch (_R_) { \\\n");
+ fprintf(file, "\tcase MACH_SEND_INVALID_DATA: \\\n");
+ fprintf(file, "\tcase MACH_SEND_INVALID_DEST: \\\n");
+ fprintf(file, "\tcase MACH_SEND_INVALID_HEADER: \\\n");
+ if (SpecialReplyPort) {
+ fprintf(file, "\t\tif (!__MigCanUseSpecialReplyPort) { \\\n");
+ fprintf(file, "\t\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n");
+ fprintf(file, "\t\t} \\\n");
+ } else {
+ fprintf(file, "\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n");
+ }
+ fprintf(file, "\t\tbreak; \\\n");
+ if (timeout) {
+ fprintf(file, "\tcase MACH_SEND_TIMED_OUT: \\\n");
+ fprintf(file, "\tcase MACH_RCV_TIMED_OUT: \\\n");
+ }
+ fprintf(file, "\tdefault: \\\n");
+ if (SpecialReplyPort) {
+ fprintf(file, "\t\tif (__MigCanUseSpecialReplyPort) { \\\n");
+ fprintf(file, "\t\t\tmig_dealloc_special_reply_port(InP->Head.msgh_reply_port); \\\n");
+ fprintf(file, "\t\t} else { \\\n");
+ fprintf(file, "\t\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n");
+ fprintf(file, "\t\t} \\\n");
+ } else {
+ fprintf(file, "\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n");
+ }
+ fprintf(file, "\t} \\\n}\n");
+ fprintf(file, "#endif\t/* %s */\n", name);
+ fprintf(file, "\n");
+}
+
+static void
+WriteMachErrorDefines(FILE *file)
+{
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeout", TRUE, FALSE);
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeout", FALSE, FALSE);
+ if (HasUseSpecialReplyPort) {
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeoutSRP", TRUE, TRUE);
+ WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeoutSRP", FALSE, TRUE);
+ }
+}
+
+static void
+WriteMIGCheckDefines(FILE *file)
+{
+ fprintf(file, "#define\t__MIG_check__Reply__%s_subsystem__ 1\n", SubsystemName);
+ fprintf(file, "\n");
+}
+
+static void
+WriteNDRDefines(FILE *file)
+{
+ fprintf(file, "#define\t__NDR_convert__Reply__%s_subsystem__ 1\n", SubsystemName);
+ fprintf(file, "#define\t__NDR_convert__mig_reply_error_subsystem__ 1\n");
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Writes the standard #includes, #defines, and
+ * RCS declaration. Called by WriteUser.
+ *************************************************************/
+static void
+WriteProlog(FILE *file, statement_t *stats)
+{
+ WriteIdentificationString(file);
+ WriteMIGCheckDefines(file);
+ if (CheckNDR)
+ WriteNDRDefines(file);
+ WriteMyIncludes(file, stats);
+ WriteBogusDefines(file);
+ WriteMachErrorDefines(file);
+ WriteApplDefaults(file, "Send");
+ WriteGlobalDecls(file);
+}
+
+/*ARGSUSED*/
+static void
+WriteEpilog(FILE *file)
+{
+ /* nothing to see here, move along... */
+}
+
+static string_t
+WriteHeaderPortType(argument_t *arg)
+{
+ if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC)
+ return arg->argPoly->argVarName;
+ else
+ return arg->argType->itInNameStr;
+}
+
+static void
+WriteRequestHead(FILE *file, routine_t *rt)
+{
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest)
+ fprintf(file, "ready_to_send:\n");
+
+ if (rt->rtMaxRequestPos > 0) {
+ if (rt->rtOverwrite)
+ fprintf(file, "\tInP = &MessRequest;\n");
+ else
+ fprintf(file, "\tInP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->"));
+ }
+
+ fprintf(file, "\tInP->Head.msgh_bits =");
+ if (rt->rtRetCArg == argNULL && !rt->rtSimpleRequest)
+ fprintf(file, " MACH_MSGH_BITS_COMPLEX|");
+ fprintf(file, "\n");
+ fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n", WriteHeaderPortType(rt->rtRequestPort), WriteHeaderPortType(rt->rtReplyPort));
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ fprintf(file, "\tif (!%s)\n", rt->rtRetCArg->argVarName);
+ fprintf(file, "\t\tInP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
+ }
+
+
+ fprintf(file, "\t/* msgh_size passed as argument */\n");
+
+ /*
+ * KernelUser stubs need to cast the request and reply ports
+ * from ipc_port_t to mach_port_t.
+ */
+
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser)
+ fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName);
+ else
+#endif
+ fprintf(file, "\tInP->%s = %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName);
+
+ if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) {
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser)
+ fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName);
+ else
+#endif
+ fprintf(file, "\tInP->%s = %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName);
+ }
+ else if (rt->rtOneWay)
+ fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n", rt->rtReplyPort->argMsgField);
+ else if (rt->rtUseSpecialReplyPort)
+ fprintf(file, "\tInP->%s = __MigCanUseSpecialReplyPort ? mig_get_special_reply_port() : mig_get_reply_port();\n", rt->rtReplyPort->argMsgField);
+ else
+ fprintf(file, "\tInP->%s = mig_get_reply_port();\n", rt->rtReplyPort->argMsgField);
+
+ fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase);
+ fprintf(file, "\tInP->Head.msgh_reserved = 0;\n");
+
+
+ if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) {
+ fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n");
+ fprintf(file, "#ifdef USING_VOUCHERS\n");
+ fprintf(file, "\tif (voucher_mach_msg_set != NULL) {\n");
+ fprintf(file, "\t\tvoucher_mach_msg_set(&InP->Head);\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif // USING_VOUCHERS\n");
+ fprintf(file, "\t\n/* END VOUCHER CODE */\n");
+ }
+}
+
+/*************************************************************
+ * Writes declarations for the message types, variables
+ * and return variable if needed. Called by WriteRoutine.
+ *************************************************************/
+static void
+WriteVarDecls(FILE *file, routine_t *rt)
+{
+ int i;
+
+ if (rt->rtOverwrite) {
+ fprintf(file, "\tRequest MessRequest;\n");
+ fprintf(file, "\tRequest *InP = &MessRequest;\n\n");
+
+ fprintf(file, "\tunion {\n");
+ fprintf(file, "\t\tOverwriteTemplate In;\n");
+ fprintf(file, "\t\tReply Out;\n");
+ fprintf(file, "\t} MessReply;\n");
+
+ fprintf(file, "\tOverwriteTemplate *InOvTemplate = &MessReply.In;\n");
+ fprintf(file, "\tReply *Out0P = &MessReply.Out;\n");
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i);
+ }
+ else {
+ if (rtMessOnStack(rt))
+ fprintf(file, "\tunion {\n");
+ else
+ fprintf(file, "\tunion %sMessU {\n", rt->rtName);
+ fprintf(file, "\t\tRequest In;\n");
+ if (!rt->rtOneWay)
+ fprintf(file, "\t\tReply Out;\n");
+ if (rtMessOnStack(rt))
+ fprintf(file, "\t} Mess;\n");
+ else
+ fprintf(file, "\t} *Mess = (union %sMessU *) %s(sizeof(*Mess));\n",
+ rt->rtName, MessAllocRoutine);
+ fprintf(file, "\n");
+
+ fprintf(file, "\tRequest *InP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->"));
+ if (!rt->rtOneWay) {
+ fprintf(file, "\tReply *Out0P = &Mess%sOut;\n", (rtMessOnStack(rt) ? "." : "->"));
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i);
+ }
+ }
+
+ fprintf(file, "\n");
+
+ fprintf(file, "\tmach_msg_return_t msg_result;\n");
+
+ /* if request is variable, we need msgh_size_delta and msgh_size */
+ if (rt->rtNumRequestVar > 0)
+ fprintf(file, "\tunsigned int msgh_size;\n");
+ if (rt->rtMaxRequestPos > 0)
+ fprintf(file, "\tunsigned int msgh_size_delta;\n");
+ if (rt->rtNumRequestVar > 1 || rt->rtMaxRequestPos > 0)
+ fprintf(file, "\n");
+
+ if (rt->rtUserImpl) {
+ fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ fprintf(file, "\n");
+ fprintf(file, "#ifdef\t__MIG_check__Reply__%s_t__defined\n", rt->rtName);
+ fprintf(file, "\tkern_return_t check_result;\n");
+ fprintf(file, "#endif\t/* __MIG_check__Reply__%s_t__defined */\n", rt->rtName);
+ fprintf(file, "\n");
+ WriteApplMacro(file, "Send", "Declare", rt);
+ fprintf(file, "\n");
+}
+
+static void
+WriteReturn(FILE *file, routine_t *rt, char *before, char *value, char *after, boolean_t deallocate_mess)
+{
+ if (rtMessOnStack(rt)) {
+ if (value != stRetCode) {
+ /* get the easy case (no braces needed) out of the way */
+ fprintf(file, "%sreturn%s%s;%s", before, (*value ? " " : ""), value, after);
+ return;
+ }
+ else {
+ fprintf(file, "%s{\n", before);
+ fprintf(file, "%s\treturn Out0P->RetCode;\n%s}%s", before, before, after);
+ return;
+ }
+ }
+
+ if (value == stRetCode) {
+ fprintf(file, "%s{\n%s\t%s ReturnValue;\n", before, before, ReturnTypeStr(rt));
+ fprintf(file, "%s\tReturnValue = Out0P->RetCode;\n%s\t", before, before);
+ }
+ else {
+ fprintf(file, "%s{ ", before);
+ }
+
+ if (deallocate_mess) {
+ fprintf(file, "%s((char *) Mess, sizeof(*Mess)); ", MessFreeRoutine);
+ }
+
+ if (value == stRetCode)
+ fprintf(file, "return ReturnValue;\n%s}%s", before, after);
+ else if (value == stRetNone)
+ fprintf(file, "return; }%s", after);
+ else
+ fprintf(file, "return %s; }%s", value, after);
+}
+
+static void
+WriteRetCodeArg(FILE *file, routine_t *rt)
+{
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ argument_t *arg = rt->rtRetCArg;
+
+ fprintf(file, "\tif (%s) {\n", arg->argVarName);
+ fprintf(file, "\t\t((mig_reply_error_t *)InP)->RetCode = %s;\n", arg->argVarName);
+ fprintf(file, "\t\t((mig_reply_error_t *)InP)->NDR = NDR_record;\n");
+ fprintf(file, "\t\tgoto ready_to_send;\n");
+ fprintf(file, "\t}\n\n");
+ }
+}
+
+/*************************************************************
+ * Writes the logic to check for a message send timeout, and
+ * deallocate any relocated ool data so as not to leak.
+ *************************************************************/
+static void
+WriteMsgCheckForSendErrors(FILE *file, routine_t *rt)
+{
+ if (rt->rtConsumeOnSendError != ConsumeOnSendErrorAny && rt->rtWaitTime == argNULL) {
+ return;
+ }
+
+ if (rt->rtConsumeOnSendError == ConsumeOnSendErrorAny) {
+ // other errors mean the kernel consumed some of the rights
+ // and we can't possibly know if there's something left to destroy
+ fputs("\n"
+ "\t" "if (msg_result == MACH_SEND_INVALID_DEST ||" "\n"
+ "\t\t" "msg_result == MACH_SEND_TIMED_OUT) {" "\n", file);
+ } else {
+ fputs("\n"
+ "\t" "if (msg_result == MACH_SEND_TIMED_OUT) {" "\n", file);
+ }
+
+ if (rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) {
+ argument_t *arg_ptr;
+
+ // iterate over arg list
+ for (arg_ptr = rt->rtArgs; arg_ptr != NULL; arg_ptr = arg_ptr->argNext) {
+
+ // if argument contains ool data
+ if (akCheck(arg_ptr->argKind, akbSendKPD) && arg_ptr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ // generate code to test current arg address vs. address before the msg_send call
+ // if not at the same address, mig_deallocate the argument
+ fprintf(file, "\t\t" "if((vm_offset_t) InP->%s.address != (vm_offset_t) %s)\n",
+ arg_ptr->argVarName, arg_ptr->argVarName);
+ fprintf(file, "\t\t\t" "mig_deallocate((vm_offset_t) InP->%s.address, "
+ "(vm_size_t) InP->%s.size);\n", arg_ptr->argVarName, arg_ptr->argVarName);
+ }
+ }
+ } else {
+ /*
+ * The original MIG would leak most resources on send timeout without
+ * leaving a chance for callers to know how to dispose of most of the
+ * resources, as the caller can't possibly guess the new names
+ * picked during pseudo-receive.
+ */
+ if (IsKernelUser) {
+ fputs("#if\t__MigKernelSpecificCode" "\n", file);
+ fputs("\t\t" "mach_msg_destroy_from_kernel(&InP->Head);" "\n", file);
+ fputs("#endif\t/* __MigKernelSpecificCode */" "\n", file);
+ } else {
+ fputs("\t\t" "/* mach_msg_destroy doesn't handle the local port */" "\n", file);
+ fputs("\t\t" "switch (MACH_MSGH_BITS_LOCAL(InP->Head.msgh_bits)) {" "\n", file);
+ fputs("\t\t" "case MACH_MSG_TYPE_MOVE_SEND:" "\n", file);
+ fputs("\t\t\t" "mach_port_deallocate(mach_task_self(), InP->Head.msgh_local_port);" "\n", file);
+ fputs("\t\t\t" "break;" "\n", file);
+ fputs("\t\t" "}" "\n", file);
+ fputs("\t\t" "mach_msg_destroy(&InP->Head);" "\n", file);
+ }
+ }
+
+ fputs("\t" "}" "\n\n", file);
+ return;
+}
+
+/*************************************************************
+ * Writes the send call when there is to be no subsequent
+ * receive. Called by WriteRoutine SimpleRoutines
+ *************************************************************/
+static void
+WriteMsgSend(FILE *file, routine_t *rt)
+{
+ char *SendSize = "";
+ char string[MAX_STR_LEN];
+
+ if (rt->rtNumRequestVar == 0)
+ SendSize = "(mach_msg_size_t)sizeof(Request)";
+ else
+ SendSize = "msgh_size";
+
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
+ SendSize = strconcat(string, SendSize);
+ }
+
+ if (IsKernelUser) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "\tmsg_result = mach_msg_send_from_kernel(");
+ fprintf(file, "&InP->Head, %s);\n", SendSize);
+ fprintf(file, "#else\n");
+ }
+ fprintf(file, "\tmsg_result = mach_msg("
+ "&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, MACH_PORT_NULL, %s, MACH_PORT_NULL);\n",
+ rt->rtWaitTime !=argNULL ? "MACH_SEND_TIMEOUT|" : "",
+ rt->rtMsgOption->argVarName,
+ SendSize,
+ rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName:"MACH_MSG_TIMEOUT_NONE");
+
+ if (IsKernelUser) {
+ fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
+ }
+
+ WriteApplMacro(file, "Send", "After", rt);
+
+ WriteMsgCheckForSendErrors(file, rt);
+
+ WriteReturn(file, rt, "\t", "msg_result", "\n", TRUE);
+}
+
+/*************************************************************
+ * Writes to code to check for error returns from receive.
+ * Called by WriteMsgSendReceive and WriteMsgRPC
+ *************************************************************/
+static void
+WriteMsgCheckReceiveCleanupMigReplyPort(FILE *file, routine_t *rt, char *success)
+{
+ if (!akCheck(rt->rtReplyPort->argKind, akbUserArg))
+ {
+ /* If we aren't using a user-supplied reply port, then
+ deallocate the reply port when it is invalid or
+ for TIMED_OUT errors. */
+ fprintf(file, "\tif (msg_result != %s) {\n", success);
+ if (rt->rtWaitTime != argNULL) {
+ fprintf(file, "\t\t__MachMsgErrorWithTimeout%s(msg_result);\n",
+ rt->rtUseSpecialReplyPort ? "SRP" : "");
+ } else {
+ fprintf(file, "\t\t__MachMsgErrorWithoutTimeout%s(msg_result);\n",
+ rt->rtUseSpecialReplyPort ? "SRP" : "");
+ }
+ fprintf(file, "\t}\n");
+ }
+}
+
+static void
+WriteMsgCheckReceive(FILE *file, routine_t *rt, char *success)
+{
+ fprintf(file, "\tif (msg_result != %s) {\n", success);
+ WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result");
+ fprintf(file, "\t}\n");
+}
+
+/*************************************************************
+ * Writes the send and receive calls and code to check
+ * for errors. Normally the rpc code is generated instead
+ * although, the subsytem can be compiled with the -R option
+ * which will cause this code to be generated. Called by
+ * WriteRoutine if UseMsgRPC option is false.
+ *************************************************************/
+static void
+WriteMsgSendReceive(FILE *file, routine_t *rt)
+{
+ char *SendSize = "";
+ char string[MAX_STR_LEN];
+
+ if (rt->rtNumRequestVar == 0)
+ SendSize = "(mach_msg_size_t)sizeof(Request)";
+ else
+ SendSize = "msgh_size";
+
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
+ SendSize = strconcat(string, SendSize);
+ }
+
+ /* IsKernelUser to be done! */
+ 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);
+ fprintf(file, " MACH_PORT_NULL, %s, MACH_PORT_NULL);\n",
+#if !USE_IMMEDIATE_SEND_TIMEOUT
+ (rt->rtWaitTime != argNULL) ? rt->rtWaitTime->argVarName :
+#endif
+ "MACH_MSG_TIMEOUT_NONE");
+ fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n");
+ WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result");
+ fprintf(file, "\n");
+
+ 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",
+ rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
+ (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? "MACH_RCV_TIMEOUT|" : "",
+ rt->rtMsgOption->argVarName,
+ (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
+ WriteApplMacro(file, "Send", "After", rt);
+ WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS");
+ WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Writes the rpc call and the code to check for errors.
+ * This is the default code to be generated. Called by WriteRoutine
+ * for all routine types except SimpleRoutine.
+ *************************************************************/
+static void
+WriteMsgRPC(FILE *file, routine_t *rt)
+{
+ char *SendSize = "";
+ char string[MAX_STR_LEN];
+
+ if (rt->rtNumRequestVar == 0)
+ SendSize = "(mach_msg_size_t)sizeof(Request)";
+ else
+ SendSize = "msgh_size";
+
+ if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
+ sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName);
+ SendSize = strconcat(string, SendSize);
+ }
+
+ if (IsKernelUser) {
+ fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNELSPECIFIC_CODE_)\n");
+ fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, (mach_msg_size_t)sizeof(Reply));\n", SendSize);
+ fprintf(file, "#else\n");
+ }
+ if (rt->rtOverwrite) {
+ 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, ",
+ rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
+ rt->rtWaitTime != argNULL ?
+ (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "",
+ rt->rtMsgOption->argVarName,
+ SendSize,
+ rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
+ fprintf(file, " &InOvTemplate->Head, (mach_msg_size_t)sizeof(OverwriteTemplate));\n");
+ }
+ else {
+ 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",
+ rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "",
+ rt->rtWaitTime != argNULL ?
+ (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "",
+ rt->rtMsgOption->argVarName,
+ SendSize,
+ rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE");
+ }
+ if (IsKernelUser)
+ fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
+ WriteApplMacro(file, "Send", "After", rt);
+
+ WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS");
+ WriteMsgCheckForSendErrors(file, rt);
+
+ WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS");
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Pack discipline for Port types.
+ */
+static void
+WriteKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *subindex = "";
+ char *recast = "";
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ ipc_type_t *real_it;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ subindex = "[i]";
+ real_it = it->itElement;
+ }
+ else {
+ (void)sprintf(firststring, "InP->%s", arg->argMsgField);
+ (void)sprintf(string, "InP->%s.", arg->argMsgField);
+ real_it = it;
+ }
+
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t"))
+ recast = "(mach_port_t)";
+#endif
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ /* ref is required also in the Request part, because of inout parameters */
+ fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName);
+ }
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName);
+ }
+ else
+ fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr);
+ fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray) {
+ fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
+ /* fill the rest of the statically allocated KPD entries with MACH_PORT_NULL */
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t }\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+static void
+WriteKPD_ool_varsize(FILE *file, argument_t *arg, char *who, char *where, boolean_t iscomplex)
+{
+ ipc_type_t *it = arg->argType;
+ argument_t *count;
+ char *cref;
+
+ if (iscomplex) {
+ it = it->itElement;
+ count = arg->argSubCount;
+ }
+ else
+ count = arg->argCount;
+ cref = count->argByReferenceUser ? "*" : "";
+
+ /* size has to be expressed in bytes! */
+ if (count->argMultiplier > 1 || it->itSize > 8)
+ fprintf(file, "\t%s->%s = %s%s%s * %d;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "", count->argMultiplier * it->itSize / 8);
+ else
+ fprintf(file, "\t%s->%s = %s%s%s;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "");
+}
+
+/*
+ * argKPD_Pack discipline for out-of-line types.
+ */
+static void
+WriteKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+ boolean_t VarArray;
+ u_int howmany, howbig;
+ char *subindex;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ subindex = "[i]";
+ }
+ else {
+ (void)sprintf(firststring, "InP->%s", arg->argMsgField);
+ (void)sprintf(string, "InP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ subindex = "";
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray) {
+ if (IS_MULTIPLE_KPD(it))
+ WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE);
+ else
+ WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE);
+ }
+
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray)
+ if (IS_MULTIPLE_KPD(it))
+ WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE);
+ else
+ WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE);
+ else
+ fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+ else
+ fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
+#ifdef ALIGNMENT
+ fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, (it->itElement->itSize < 8) ? 1 : it->itElement->itSize / 8);
+#endif
+ fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
+
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray) {
+ fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
+ /* fill the rest of the statically allocated KPD entries with size NULL */
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ if (!VarArray)
+ fprintf(file, "\t%ssize = 0;\n", string);
+ /* otherwise the size in the template would be != 0! */
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%ssize = 0;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t }\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_Pack discipline for out-of-line Port types.
+ */
+static void
+WriteKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ argument_t *count;
+ boolean_t VarArray;
+ string_t howstr;
+ u_int howmany;
+ char *subindex;
+ char firststring[MAX_STR_LEN];
+ char string[MAX_STR_LEN];
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE);
+ (void)sprintf(firststring, "\t*ptr");
+ (void)sprintf(string, "\tptr->");
+ VarArray = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howstr = it->itElement->itInNameStr;
+ count = arg->argSubCount;
+ subindex = "[i]";
+ }
+ else {
+ (void)sprintf(firststring, "InP->%s", arg->argMsgField);
+ (void)sprintf(string, "InP->%s.", arg->argMsgField);
+ VarArray = it->itVarArray;
+ howmany = it->itNumber;
+ howstr = it->itInNameStr;
+ count = arg->argCount;
+ subindex = "";
+ }
+
+ fprintf(file, "#if\tUseStaticTemplates\n");
+
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray)
+ fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName);
+ }
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+
+ fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex);
+ if (VarArray)
+ fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex);
+ else
+ fprintf(file, "\t%scount = %d;\n", string, howmany);
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName);
+ }
+ else
+ fprintf(file, "\t%sdisposition = %s;\n", string, howstr);
+ if (arg->argDeallocate == d_MAYBE)
+ fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
+ else
+ fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
+ fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
+
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\n");
+
+ if (IS_MULTIPLE_KPD(it)) {
+ fprintf(file, "\t }\n");
+ if (it->itVarArray) {
+ fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number);
+ /* fill the rest of the statically allocated KPD entries with size NULL */
+ fprintf(file, "#if\tUseStaticTemplates\n");
+ fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
+ if (!VarArray)
+ fprintf(file, "\t%scount = 0;\n", string);
+ /* otherwise the size in the template would be != 0! */
+ fprintf(file, "#else\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t%scount = 0;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
+ fprintf(file, "#endif\t/* UseStaticTemplates */\n");
+ fprintf(file, "\t }\n");
+ }
+ fprintf(file, "\t}\n");
+ }
+ fprintf(file, "\n");
+}
+
+static void
+WriteOverwriteTemplate(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ char string[MAX_STR_LEN];
+ char *subindex = "";
+ boolean_t finish = FALSE;
+
+ fprintf(file, "\t/* Initialize the template for overwrite */\n");
+ fprintf(file, "\tInOvTemplate->msgh_body.msgh_descriptor_count = %d;\n", rt->rtOverwriteKPDs);
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ argument_t *count;
+ char *cref;
+ boolean_t VarIndex;
+ u_int howmany, howbig;
+
+ if (akCheck(arg->argKind, akbOverwrite)) {
+ if (arg->argFlags & flOverwrite) {
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, TRUE, it->itVarArray, arg, TRUE);
+ if (it->itVarArray)
+ finish = TRUE;
+ sprintf(string, "\tptr->");
+ subindex = "[i]";
+ count = arg->argSubCount;
+ VarIndex = it->itElement->itVarArray;
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ }
+ else {
+ sprintf(string, "InOvTemplate->%s.", arg->argMsgField);
+ subindex = "";
+ count = arg->argCount;
+ VarIndex = it->itVarArray;
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ }
+
+ fprintf(file, "\t%saddress = (void *) %s%s%s;\n", string, ref, arg->argVarName, subindex);
+
+ if (it->itPortType) {
+ fprintf(file, "\t%scount = ", string);
+ if (VarIndex) {
+ cref = count->argByReferenceUser ? "*" : "";
+ fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex);
+ }
+ else
+ fprintf(file, "%d;\n", howmany);
+ }
+ else {
+ fprintf(file, "\t%ssize = ", string);
+ if (VarIndex) {
+ cref = count->argByReferenceUser ? "*" : "";
+ if (count->argMultiplier > 1 || howbig > 8)
+ fprintf(file, "%s%s%s * %d;\n", cref, count->argVarName, subindex, count->argMultiplier * howbig / 8);
+ else
+ fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex);
+ }
+ else
+ fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8);
+ }
+ fprintf(file, "\t%scopy = MACH_MSG_OVERWRITE;\n", string);
+ fprintf(file, "\t%stype = MACH_MSG_OOL_%sDESCRIPTOR;\n", string, (it->itPortType) ? "PORTS_" : "");
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n");
+ if (finish) {
+ fprintf(file, "\t for (i = %s%s; i < %d; ptr++, i++) {\n", (arg->argCount->argByReferenceUser) ? "*" : "", arg->argCount->argVarName, it->itKPD_Number);
+ fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n");
+ fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : "");
+ fprintf(file, "\t }\n");
+ }
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t}\n");
+ }
+ else {
+ /* just a placeholder */
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, TRUE, FALSE, arg, TRUE);
+ fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n");
+ fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : "");
+ fprintf(file, "\t }\n\t}\n");
+ }
+ else {
+ fprintf(file, "\tInOvTemplate->%s.copy = MACH_MSG_ALLOCATE;\n", arg->argMsgField);
+ /* not sure whether this is needed */
+ fprintf(file, "\tInOvTemplate->%s.type = MACH_MSG_OOL_%sDESCRIPTOR;\n", arg->argMsgField, (it->itPortType) ? "PORTS_" : "");
+ }
+ }
+ }
+ }
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Writes code to copy an argument into the request message.
+ * Called by WriteRoutine for each argument that is to placed
+ * in the request message.
+ *************************************************************/
+
+static void
+WritePackArgValueNormal(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = (arg->argByReferenceUser ||
+ it->itNativePointer) ? "*" : "";
+
+ if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
+ if (it->itString) {
+ /*
+ * Copy variable-size C string with mig_strncpy.
+ * Save the string length (+ 1 for trailing 0)
+ * in the argument`s count field.
+ */
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n");
+ 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);
+ fprintf(file, "\t} else {\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+
+ 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);
+
+ fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n");
+
+ fprintf(file, "\tInP->%sOffset = 0;\n", arg->argMsgField);
+ }
+ else if (it->itNoOptArray)
+ fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, %d);\n", arg->argMsgField, ref, arg->argVarName, it->itTypeSize);
+ else {
+
+ /*
+ * Copy in variable-size inline array with (void)memcpy,
+ * after checking that number of elements doesn`t
+ * exceed declared maximum.
+ */
+ argument_t *count = arg->argCount;
+ char *countRef = count->argByReferenceUser ? "*" : "";
+ ipc_type_t *btype = it->itElement;
+
+ /* Note btype->itNumber == count->argMultiplier */
+
+ if (akIdent(arg->argKind) != akeSubCount) {
+ /* we skip the SubCount case, as we have already taken care of */
+ fprintf(file, "\tif (%s%s > %d) {\n", countRef, count->argVarName, it->itNumber/btype->itNumber);
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+ fprintf(file, "\t}\n");
+ }
+
+ fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, ", arg->argMsgField, ref, arg->argVarName);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ fprintf(file, "%s%s);\n", countRef, count->argVarName);
+ }
+ }
+ else if (IS_OPTIONAL_NATIVE(it)) {
+ fprintf(file, "\tif ((InP->__Present__%s = (%s != %s))) {\n", arg->argMsgField, arg->argVarName, it->itBadValue);
+ WriteCopyType(file, it, TRUE, "\tInP->%s.__Real__%s", "/* %s%s */ %s%s", arg->argMsgField, arg->argMsgField, ref, arg->argVarName);
+ fprintf(file, "\t}\n");
+ }
+ else
+ WriteCopyType(file, it, TRUE, "InP->%s", "/* %s */ %s%s", arg->argMsgField, ref, arg->argVarName);
+
+ if (arg->argPadName != NULL && it->itPadSize != 0) {
+ fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize);
+ fprintf(file, "\t\t InP->%s[i] = 0;\n", arg->argPadName);
+ }
+ fprintf(file, "\n");
+}
+
+/*
+ * Calculate the size of a variable-length message field.
+ */
+static void
+WriteArgSizeVariable(FILE *file, argument_t *arg, ipc_type_t *ptype)
+{
+ int bsize = ptype->itElement->itTypeSize;
+ argument_t *count = arg->argCount;
+
+ if (PackMsg == FALSE) {
+ fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
+ return;
+ }
+
+ /* If the base type size of the data field isn`t a multiple of 4,
+ we have to round up. */
+ if (bsize % itWordAlign != 0)
+ fprintf(file, "_WALIGN_");
+ fprintf(file, "(");
+ if (bsize > 1)
+ fprintf(file, "%d * ", bsize);
+ if (ptype->itString)
+ /* get count from descriptor in message */
+ fprintf(file, "InP->%s", count->argMsgField);
+ else
+ /* get count from argument */
+ fprintf(file, "%s%s", count->argByReferenceUser ? "*" : "", count->argVarName);
+ fprintf(file, ")");
+}
+
+static void
+WriteArgSizeOptional(FILE *file, argument_t *arg, ipc_type_t *ptype)
+{
+ fprintf(file, "(InP->__Present__%s ? _WALIGNSZ_(%s) : 0)", arg->argVarName, ptype->itUserType);
+}
+
+static void
+WriteArgSize(FILE *file, argument_t *arg)
+
+{
+ ipc_type_t *ptype = arg->argType;
+
+ if (IS_OPTIONAL_NATIVE(ptype))
+ WriteArgSizeOptional(file, arg, ptype);
+ else
+ WriteArgSizeVariable(file, arg, ptype);
+}
+
+/*
+ * Adjust message size and advance request pointer.
+ * Called after packing a variable-length argument that
+ * has more arguments following.
+ */
+static void
+WriteAdjustMsgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+
+ /* There are more In arguments. We need to adjust msgh_size
+ and advance InP, so we save the size of the current field
+ in msgh_size_delta. */
+
+ fprintf(file, "\tmsgh_size_delta = ");
+ WriteArgSize(file, arg);
+ fprintf(file, ";\n");
+
+ if (arg->argRequestPos == 0) {
+ /* First variable-length argument. The previous msgh_size value
+ is the minimum request size. */
+
+ fprintf(file, "\tmsgh_size = ");
+ rtMinRequestSize(file, arg->argRoutine, "Request");
+ fprintf(file, " + msgh_size_delta;\n");
+ }
+ else
+ fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
+
+ if (PackMsg == TRUE) {
+ fprintf(file, "\tInP = (Request *) ((pointer_t) InP + msgh_size_delta - ");
+ if (IS_OPTIONAL_NATIVE(ptype))
+ fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType);
+ else
+ fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
+ fprintf(file, ");\n\n");
+ }
+}
+
+/*
+ * Calculate the size of the message. Called after the
+ * last argument has been packed.
+ */
+static void
+WriteFinishMsgSize(FILE *file, argument_t *arg)
+{
+ /* No more In arguments. If this is the only variable In
+ argument, the previous msgh_size value is the minimum
+ request size. */
+
+ if (arg->argRequestPos == 0) {
+ fprintf(file, "\tmsgh_size = ");
+ rtMinRequestSize(file, arg->argRoutine, "Request");
+ fprintf(file, " + (");
+ WriteArgSize(file, arg);
+ fprintf(file, ");\n");
+ }
+ else {
+ fprintf(file, "\tmsgh_size += ");
+ WriteArgSize(file, arg);
+ fprintf(file, ";\n");
+ }
+}
+
+static void
+WriteInitializeCount(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argCInOut->argParent->argType;
+ ipc_type_t *btype = ptype->itElement;
+
+ fprintf(file, "\tif (%s%s < %d)\n", arg->argByReferenceUser ? "*" : "", arg->argVarName, ptype->itNumber/btype->itNumber);
+ fprintf(file, "\t\tInP->%s = %s%s;\n", arg->argMsgField, arg->argByReferenceUser ? "*" : "", arg->argVarName);
+ fprintf(file, "\telse\n");
+ fprintf(file, "\t\tInP->%s = %d;\n", arg->argMsgField, ptype->itNumber/btype->itNumber);
+ fprintf(file, "\n");
+}
+
+/*
+ * Generate code to fill in all of the request arguments and their
+ * message types.
+ */
+static void
+WriteRequestArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ argument_t *lastVarArg;
+
+ /*
+ * 1. The Kernel Processed Data
+ */
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheckAll(arg->argKind, akbSendSnd|akbSendKPD))
+ (*arg->argKPD_Pack)(file, arg);
+
+ /*
+ * 2. The Data Stream
+ */
+ lastVarArg = argNULL;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ /*
+ * Adjust message size and advance message pointer if
+ * the last request argument was variable-length and the
+ * request position will change.
+ */
+ if (lastVarArg != argNULL &&
+ lastVarArg->argRequestPos < arg->argRequestPos) {
+ WriteAdjustMsgSize(file, lastVarArg);
+ lastVarArg = argNULL;
+ }
+
+ if ((akIdent(arg->argKind) == akeCountInOut) &&
+ akCheck(arg->argKind, akbSendSnd))
+ WriteInitializeCount(file, arg);
+ else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody))
+ WritePackArgValueNormal(file, arg);
+ /*
+ * Remember whether this was variable-length.
+ */
+ if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable))
+ lastVarArg = arg;
+ }
+ /*
+ * Finish the message size.
+ */
+ if (lastVarArg != argNULL)
+ WriteFinishMsgSize(file, lastVarArg);
+}
+
+/*************************************************************
+ * Writes code to check that the return msgh_id is correct and that
+ * the size of the return message is correct. Called by
+ * WriteRoutine.
+ *************************************************************/
+static void
+WriteCheckIdentity(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\tif (Out0P->Head.msgh_id != %d) {\n", rt->rtNumber + SubsystemBase + 100);
+ fprintf(file, "\t if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n");
+ fprintf(file, "\t\t{ return MIG_SERVER_DIED; }\n");
+ fprintf(file, "\t else\n");
+ fprintf(file, "\t\t{ return MIG_REPLY_MISMATCH; }\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "\n");
+ if (!rt->rtSimpleReply)
+ fprintf(file, "\tmsgh_simple = !(Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ if (!rt->rtNoReplyArgs)
+ fprintf(file, "\tmsgh_size = Out0P->Head.msgh_size;\n\n");
+
+ if (rt->rtSimpleReply) {
+ /* Expecting a simple message. We can factor out the check for
+ * a simple message, since the error reply message is also simple.
+ */
+ fprintf(file, "\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
+ if (rt->rtNoReplyArgs)
+ fprintf(file, "\t (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n");
+ else {
+ /*
+ * We have an error iff:
+ * 1) the message size is not the one expected AND
+ * 2) the message size is also different from sizeof(mig_reply_error_t)
+ * or the RetCode == KERN_SUCCESS
+ */
+ if (rt->rtNumReplyVar > 0) {
+ fprintf(file, "\t ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < ");
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, ") &&\n");
+ }
+ else
+ fprintf(file, "\t ((msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n");
+ fprintf(file, "\t (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
+ fprintf(file, "\t Out0P->RetCode == KERN_SUCCESS)))\n");
+ }
+ }
+ else {
+ /* Expecting a complex message. */
+
+ fprintf(file, "\t" "if ((msgh_simple || Out0P->msgh_body.msgh_descriptor_count != %d ||\n", rt->rtReplyKPDs);
+ if (rt->rtNumReplyVar > 0) {
+ fprintf(file, "\t msgh_size < ");
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, " || msgh_size > (mach_msg_size_t)sizeof(__Reply)) &&\n");
+ }
+ else
+ fprintf(file, "\t msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n");
+ fprintf(file, "\t (!msgh_simple || msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n");
+ fprintf(file, "\t ((mig_reply_error_t *)Out0P)->RetCode == KERN_SUCCESS))\n");
+ }
+ fprintf(file, "\t\t{ return MIG_TYPE_ERROR ; }\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ fprintf(file, "\n");
+}
+
+/*************************************************************
+ * Write code to generate error handling code if the RetCode
+ * argument of a Routine is not KERN_SUCCESS.
+ *************************************************************/
+static void
+WriteRetCodeCheck(FILE *file, routine_t *rt)
+{
+ if (rt->rtSimpleReply)
+ fprintf(file, "\tif (Out0P->RetCode != KERN_SUCCESS) {\n");
+ else
+ fprintf(file, "\tif (msgh_simple) {\n");
+ if (CheckNDR) {
+ fprintf(file, "#ifdef\t__NDR_convert__mig_reply_error_t__defined\n");
+ fprintf(file, "\t\t__NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P);\n");
+ fprintf(file, "#endif\t/* __NDR_convert__mig_reply_error_t__defined */\n");
+ }
+ fprintf(file, "\t\treturn ((mig_reply_error_t *)Out0P)->RetCode;\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for Port types.
+ */
+static void
+WriteTCheckKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab = "";
+ char string[MAX_STR_LEN];
+ boolean_t close = FALSE;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
+ (void)sprintf(string, "ptr->");
+ tab = "\t";
+ close = TRUE;
+ }
+ else
+ (void)sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
+ fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string);
+ if (arg->argPoly == argNULL && !it->itVarArray)
+ /* we can't check disposition when poly or VarArray,
+ (because some of the entries could be empty) */
+ fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr);
+ fprintf(file,
+ ") {\n"
+ "\t\t%s" "return MIG_TYPE_ERROR;\n"
+ "\t%s" "}\n"
+ , tab, tab);
+ if (close)
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for out-of-line types.
+ */
+static void
+WriteTCheckKPD_ool(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab, string[MAX_STR_LEN];
+ boolean_t test;
+ u_int howmany, howbig;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ howmany = it->itElement->itNumber;
+ howbig = it->itElement->itSize;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ }
+ else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
+ howmany = it->itNumber;
+ howbig = it->itSize;
+ test = !it->itVarArray;
+ }
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string);
+ if (test)
+ /* if VarArray we may use no-op; if itElement->itVarArray size might change */
+ fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8);
+ fprintf(file,
+ ") {\n"
+ "\t\t%s" "return MIG_TYPE_ERROR;\n"
+ "\t%s" "}\n"
+ , tab, tab);
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*
+ * argKPD_TypeCheck discipline for out-of-line Port types.
+ */
+static void
+WriteTCheckKPD_oolport(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *tab, string[MAX_STR_LEN];
+ boolean_t test;
+ u_int howmany;
+ char *howstr;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ howmany = it->itElement->itNumber;
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ howstr = it->itElement->itOutNameStr;
+ }
+ else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField);
+ howmany = it->itNumber;
+ test = !it->itVarArray;
+ howstr = it->itOutNameStr;
+ }
+
+ fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string);
+ if (test)
+ /* if VarArray we may use no-op; if itElement->itVarArray size might change */
+ fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany);
+ if (arg->argPoly == argNULL)
+ fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr);
+ fprintf(file, ") {\n"
+ "\t\t%s" "return MIG_TYPE_ERROR;\n"
+ "\t%s" "}\n"
+ ,tab, tab);
+ if (IS_MULTIPLE_KPD(it))
+ fprintf(file, "\t }\n\t}\n");
+}
+
+/*************************************************************
+ * Writes code to check that the type of each of the arguments
+ * in the reply message is what is expected. Called by
+ * WriteRoutine for each out && typed argument in the reply message.
+ *************************************************************/
+static void
+WriteTypeCheck(FILE *file, argument_t *arg)
+{
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ (*arg->argKPD_TypeCheck)(file, arg);
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+}
+
+
+/*
+ * argKPD_Extract discipline for Port types.
+ */
+static void
+WriteExtractKPD_port(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ char *subindex;
+ char *recast = "";
+ ipc_type_t *real_it;
+
+ real_it = (IS_MULTIPLE_KPD(it)) ? it->itElement : it;
+#ifdef MIG_KERNEL_PORT_CONVERSION
+ if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t"))
+ recast = "(mach_port_t)";
+#endif
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
+
+ fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast);
+ if (it->itVarArray) {
+ argument_t *count = arg->argCount;
+ char *cref = count->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t if (Out%dP->%s >",count->argReplyPos, count->argVarName);
+ if (arg->argCountInOut) {
+ fprintf(file, " %s%s)\n", cref, count->argVarName);
+ }
+ else {
+ fprintf(file, " %d)\n", it->itNumber/it->itElement->itNumber);
+ }
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+ }
+ fprintf(file, "\t}\n");
+ subindex = "[0]";
+ }
+ else {
+ fprintf(file, "\t%s%s = %sOut%dP->%s.name;\n", ref, arg->argVarName, recast, arg->argReplyPos, arg->argMsgField);
+ subindex = "";
+ }
+
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex);
+ }
+}
+
+/*
+ * argKPD_Extract discipline for out-of-line types.
+ */
+static void
+WriteExtractKPD_ool(FILE *file, argument_t *arg)
+{
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ ipc_type_t *it = arg->argType;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
+ fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
+ fprintf(file, "\t}\n");
+ }
+ else
+ fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField);
+ /*
+ * In case of variable sized arrays,
+ * the count field will be retrieved from the untyped
+ * section of the message
+ */
+}
+
+/*
+ * argKPD_Extract discipline for out-of-line Port types.
+ */
+static void
+WriteExtractKPD_oolport(FILE *file, argument_t *arg)
+{
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ ipc_type_t *it = arg->argType;
+ char *subindex;
+
+ if (IS_MULTIPLE_KPD(it)) {
+ WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE);
+ fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
+ fprintf(file, "\t}\n");
+ subindex = "[0]";
+ }
+ else {
+ fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField);
+ subindex = "";
+ }
+ /*
+ * In case of variable sized arrays,
+ * the count field will be retrieved from the untyped
+ * section of the message
+ */
+ if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) {
+ argument_t *poly = arg->argPoly;
+ char *pref = poly->argByReferenceUser ? "*" : "";
+
+ fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex);
+ }
+}
+
+/*************************************************************
+ * Write code to copy an argument from the reply message
+ * to the parameter. Called by WriteRoutine for each argument
+ * in the reply message.
+ *************************************************************/
+
+static void
+WriteExtractArgValueNormal(FILE *file, argument_t *arg)
+{
+ ipc_type_t *argType = arg->argType;
+ char *ref = arg->argByReferenceUser ? "*" : "";
+ char who[20];
+
+ if (akCheck(arg->argKind, akbUserImplicit))
+ sprintf(who, "TrailerP");
+ else
+ sprintf(who, "Out%dP", arg->argReplyPos);
+
+ if (IS_VARIABLE_SIZED_UNTYPED(argType) || argType->itNoOptArray) {
+ if (argType->itString) {
+ /*
+ * Copy out variable-size C string with mig_strncpy, not the zerofill variant.
+ * We don't risk leaking process / kernel memory on this copy-out because
+ * we've already zero-filled the buffer on copy-in.
+ */
+ fprintf(file, "\t(void) mig_strncpy(%s%s, %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itNumber);
+ }
+ else if (argType->itNoOptArray)
+ fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itTypeSize);
+ else {
+
+ /*
+ * Copy out variable-size inline array with (void)memcpy,
+ * after checking that number of elements doesn`t
+ * exceed user`s maximum.
+ */
+ argument_t *count = arg->argCount;
+ char *countRef = count->argByReferenceUser ? "*" : "";
+ ipc_type_t *btype = argType->itElement;
+
+ /* Note count->argMultiplier == btype->itNumber */
+ /* Note II: trailer logic isn't supported in this case */
+ fprintf(file, "\tif (Out%dP->%s", count->argReplyPos, count->argMsgField);
+ if (arg->argCountInOut) {
+ fprintf(file, " > %s%s) {\n", countRef, count->argVarName);
+ }
+ else {
+ fprintf(file, " > %d) {\n", argType->itNumber/btype->itNumber);
+ }
+
+ /*
+ * If number of elements is too many for user receiving area,
+ * fill user`s area as much as possible. Return the correct
+ * number of elements.
+ */
+ fprintf(file, "\t\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ if (arg->argCountInOut) {
+ fprintf(file, " %s%s);\n", countRef, count->argVarName);
+ }
+ else {
+ fprintf(file, " %d);\n", argType->itNumber/btype->itNumber);
+ }
+ fprintf(file, "\t\t%s%s = Out%dP->%s", countRef, count->argVarName, count->argReplyPos, count->argMsgField);
+ fprintf(file, ";\n");
+ WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE");
+
+ fprintf(file, "\t}\n");
+
+ fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField);
+ if (btype->itTypeSize > 1)
+ fprintf(file, "%d * ", btype->itTypeSize);
+ fprintf(file, "Out%dP->%s);\n", count->argReplyPos, count->argMsgField);
+ }
+ }
+ else
+ WriteCopyType(file, argType, FALSE, "%s%s", "/* %s%s */ %s->%s", ref, arg->argVarName, who, arg->argMsgField);
+ fprintf(file, "\n");
+}
+
+static void
+WriteCalcArgSize(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+ ipc_type_t *btype = ptype->itElement;
+ argument_t *count = arg->argCount;
+ int multiplier = btype->itTypeSize;
+
+ /* If the base type size of the data field isn`t a multiple of 4,
+ we have to round up. */
+ if (btype->itTypeSize % itWordAlign != 0)
+ fprintf(file, "_WALIGN_(");
+
+ fprintf(file, "Out%dP->%s", count->argReplyPos, count->argMsgField);
+ if (multiplier > 1)
+ fprintf(file, " * %d", multiplier);
+
+ if (btype->itTypeSize % itWordAlign != 0)
+ fprintf(file, ")");
+}
+
+static void
+WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator)
+{
+ ipc_type_t *ptype = arg->argType;
+ ipc_type_t *btype = ptype->itElement;
+ argument_t *count = arg->argCount;
+ int multiplier = btype->itTypeSize;
+
+ fprintf(file, "\tif (((msgh_size - ");
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, ")");
+ if (multiplier > 1)
+ fprintf(file, " / %d", multiplier);
+ fprintf(file, "< Out%dP->%s) ||\n", count->argReplyPos, count->argMsgField);
+ fprintf(file, "\t (msgh_size %s ", comparator);
+ rtMinReplySize(file, rt, "__Reply");
+ fprintf(file, " + ");
+ WriteCalcArgSize(file, arg);
+ fprintf(file, ")");
+ fprintf(file, ")\n\t\t{ return MIG_TYPE_ERROR ; }\n");
+}
+
+
+/* NDR Conversion routines */
+
+
+void
+WriteReplyNDRConvertIntRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+}
+
+void
+WriteReplyNDRConvertCharRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ fprintf(file, "defined(__NDR_convert__char_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+ else
+ fprintf(file, "0");
+}
+
+void
+WriteReplyNDRConvertFloatRepArgCond(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ fprintf(file, "defined(__NDR_convert__float_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
+ else
+ fprintf(file, "0");
+}
+
+void
+WriteReplyNDRConvertIntRepArgDecl(FILE *file, argument_t *arg)
+{
+ WriteNDRConvertArgDecl(file, arg, "int_rep", "Reply");
+}
+
+void
+WriteReplyNDRConvertCharRepArgDecl(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteNDRConvertArgDecl(file, arg, "char_rep", "Reply");
+}
+
+void
+WriteReplyNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteNDRConvertArgDecl(file, arg, "float_rep", "Reply");
+}
+
+
+
+void
+WriteReplyNDRConvertArgUse(FILE *file, argument_t *arg, char *convert)
+{
+ routine_t *rt = arg->argRoutine;
+ argument_t *count = arg->argCount;
+ char argname[MAX_STR_LEN];
+
+ if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) &&
+ (arg->argParent && akCheck(arg->argParent->argKind, akbReturnNdr)))
+ return;
+
+ if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) {
+ fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, count->argMsgField);
+ 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);
+ fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, count->argMsgField);
+ }
+
+ sprintf(argname, "(%s)(Out%dP->%s.address)", FetchServerType(arg->argType), arg->argReplyPos, arg->argMsgField);
+ }
+ else {
+ sprintf(argname, "&Out%dP->%s", arg->argReplyPos, arg->argMsgField);
+ }
+
+ fprintf(file, "#if defined(__NDR_convert__%s__Reply__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField);
+ fprintf(file, "\t\t__NDR_convert__%s__Reply__%s_t__%s(%s, Out0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert);
+ if (count)
+ fprintf(file, ", Out%dP->%s", count->argReplyPos, count->argMsgField);
+ fprintf(file, ");\n");
+ fprintf(file, "#endif /* __NDR_convert__%s__Reply__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField);
+}
+
+void
+WriteReplyNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField);
+ fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep)\n");
+ 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);
+ fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField);
+}
+
+void
+WriteReplyNDRConvertIntRepArgUse(FILE *file, argument_t *arg)
+{
+ WriteReplyNDRConvertArgUse(file, arg, "int_rep");
+}
+
+void
+WriteReplyNDRConvertCharRepArgUse(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteReplyNDRConvertArgUse(file, arg, "char_rep");
+}
+
+void
+WriteReplyNDRConvertFloatRepArgUse(FILE *file, argument_t *arg)
+{
+ if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode)
+ WriteReplyNDRConvertArgUse(file, arg, "float_rep");
+}
+
+static void
+WriteCheckMsgSize(FILE *file, argument_t *arg)
+{
+ routine_t *rt = arg->argRoutine;
+
+ /* If there aren't any more Out args after this, then
+ we can use the msgh_size_delta value directly in
+ the TypeCheck conditional. */
+
+ if (CheckNDR && arg->argCount && !arg->argSameCount)
+ WriteReplyNDRConvertIntRepOneArgUse(file, arg->argCount);
+
+ if (arg->argReplyPos == rt->rtMaxReplyPos) {
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /*
+ * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type.
+ */
+ fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, arg->argCount->argMsgField, arg->argType->itNumber);
+ fputs("\t\t" "return MIG_TYPE_ERROR;\n", file);
+ /* ...end... */
+
+ WriteCheckArgSize(file, rt, arg, "!=");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ else {
+ /* If there aren't any more variable-sized arguments after this,
+ then we must check for exact msg-size and we don't need
+ to update msgh_size. */
+
+ boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar;
+
+ /* calculate the actual size in bytes of the data field. note
+ that this quantity must be a multiple of four. hence, if
+ the base type size isn't a multiple of four, we have to
+ round up. note also that btype->itNumber must
+ divide btype->itTypeSize (see itCalculateSizeInfo). */
+
+ fprintf(file, "\tmsgh_size_delta = ");
+ WriteCalcArgSize(file, arg);
+ fprintf(file, ";\n");
+ fprintf(file, "#if\t__MigTypeCheck\n");
+
+ /*
+ * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type.
+ */
+ fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, arg->argCount->argMsgField, arg->argType->itNumber);
+ fputs("\t\t" "return MIG_TYPE_ERROR;\n", file);
+ /* ...end... */
+
+ WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<");
+
+ if (!LastVarArg)
+ fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
+
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ fprintf(file, "\n");
+}
+
+void
+WriteAdjustReplyMsgPtr(FILE *file, argument_t *arg)
+{
+ ipc_type_t *ptype = arg->argType;
+
+ fprintf(file, "\t*Out%dPP = Out%dP = (__Reply *) ((pointer_t) Out%dP + msgh_size_delta - %d);\n\n",
+ arg->argReplyPos+1, arg->argReplyPos +1, arg->argReplyPos, ptype->itTypeSize + ptype->itPadSize);
+}
+
+static void
+WriteReplyArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) {
+ WriteExtractArgValueNormal(file, arg);
+ }
+ else if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnKPD)) {
+ /*
+ * KPDs have argReplyPos 0, therefore they escape the above logic
+ */
+ (*arg->argKPD_Extract)(file, arg);
+ }
+ else if (akCheck(arg->argKind, akbUserImplicit)) {
+ WriteExtractArgValueNormal(file, arg);
+ }
+ }
+}
+
+/*************************************************************
+ * Writes code to return the return value. Called by WriteRoutine
+ * for routines and functions.
+ *************************************************************/
+static void
+WriteReturnValue(FILE *file, routine_t *rt)
+{
+ /* If returning RetCode, we have already checked that it is KERN_SUCCESS */
+ WriteReturn(file, rt, "\t", "KERN_SUCCESS", "\n", TRUE);
+}
+
+/*************************************************************
+ * Writes the elements of the message type declaration: the
+ * msg_type structure, the argument itself and any padding
+ * that is required to make the argument a multiple of 4 bytes.
+ * Called by WriteRoutine for all the arguments in the request
+ * message first and then the reply message.
+ *************************************************************/
+static void
+WriteFieldDecl(FILE *file, argument_t *arg)
+{
+ if (akCheck(arg->argKind, akbSendKPD) ||
+ akCheck(arg->argKind, akbReturnKPD))
+ WriteFieldDeclPrim(file, arg, FetchKPDType);
+ else
+ WriteFieldDeclPrim(file, arg, FetchUserType);
+}
+
+/* Fill in the string with an expression that refers to the size
+ * of the specified array:
+ */
+static void
+GetArraySize(argument_t *arg, char *size)
+{
+ ipc_type_t *it = arg->argType;
+
+ if (it->itVarArray) {
+ if (arg->argCount->argByReferenceUser) {
+ sprintf(size, "*%s", arg->argCount->argVarName);
+ }
+ else
+ sprintf(size, "%s", arg->argCount->argVarName);
+ }
+ else {
+ sprintf(size, "%d", (it->itNumber * it->itSize + 7) / 8);
+ }
+}
+
+
+static void
+WriteRPCPortDisposition(FILE *file, argument_t *arg)
+{
+ /*
+ * According to the MIG specification, the port disposition could be different
+ * on input and output. If we stay with this then a new bitfield will have
+ * to be added. Right now the port disposition is the same for in and out cases.
+ */
+ switch(arg->argType->itInName) {
+
+ case MACH_MSG_TYPE_MOVE_RECEIVE:
+ fprintf(file, " | MACH_RPC_MOVE_RECEIVE");
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND:
+ fprintf(file, " | MACH_RPC_MOVE_SEND");
+ break;
+
+ case MACH_MSG_TYPE_MOVE_SEND_ONCE:
+ fprintf(file, " | MACH_RPC_MOVE_SEND_ONCE");
+ break;
+
+ case MACH_MSG_TYPE_COPY_SEND:
+ fprintf(file, " | MACH_RPC_COPY_SEND");
+ break;
+
+ case MACH_MSG_TYPE_MAKE_SEND:
+ fprintf(file, " | MACH_RPC_MAKE_SEND");
+ break;
+
+ case MACH_MSG_TYPE_MAKE_SEND_ONCE:
+ fprintf(file, " | MACH_RPC_MAKE_SEND_ONCE");
+ break;
+ }
+}
+
+static void
+WriteRPCArgDescriptor(FILE *file, argument_t *arg, int offset)
+{
+ fprintf(file, " {\n 0 ");
+ if (RPCPort(arg)) {
+ fprintf(file, "| MACH_RPC_PORT ");
+ if (arg->argType->itNumber > 1)
+ fprintf(file, "| MACH_RPC_ARRAY ");
+ if (arg->argType->itVarArray)
+ fprintf(file, "| MACH_RPC_VARIABLE ");
+ WriteRPCPortDisposition(file, arg);
+ }
+ else if (RPCPortArray(arg)) {
+ fprintf(file, "| MACH_RPC_PORT_ARRAY ");
+ if (arg->argType->itVarArray)
+ fprintf(file, "| MACH_RPC_VARIABLE ");
+ WriteRPCPortDisposition(file, arg);
+ }
+ else if (RPCFixedArray(arg))
+ fprintf(file, "| MACH_RPC_ARRAY_FIXED ");
+ else if (RPCVariableArray(arg))
+ fprintf(file, "| MACH_RPC_ARRAY_VARIABLE ");
+ if (argIsIn(arg))
+ fprintf(file, " | MACH_RPC_IN ");
+ if (argIsOut(arg))
+ fprintf(file, " | MACH_RPC_OUT ");
+ if ((! arg->argType->itInLine) && (! arg->argType->itMigInLine))
+ fprintf(file, " | MACH_RPC_POINTER ");
+ if (arg->argFlags & flDealloc)
+ fprintf(file, " | MACH_RPC_DEALLOCATE ");
+ if (arg->argFlags & flPhysicalCopy)
+ fprintf(file, " | MACH_RPC_PHYSICAL_COPY ");
+ fprintf(file, ",\n");
+ fprintf(file, " %d,\n", (arg->argType->itSize / 8));
+ fprintf(file, " %d,\n", arg->argType->itNumber);
+ fprintf(file, " %d,\n },\n", offset);
+}
+
+void
+WriteRPCRoutineDescriptor(FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array)
+{
+ fprintf(file, " { (mig_impl_routine_t) 0,\n\
+ (mig_stub_routine_t) %s, ", stub_routine);
+ fprintf(file, "%d, %d, %s}", arg_count, descr_count, sig_array);
+}
+
+void
+WriteRPCRoutineArgDescriptor(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ int offset = 0;
+ int size = 0;
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ boolean_t compound = arg->argType->itStruct && arg->argType->itInLine;
+
+ if (RPCPort(arg) || RPCPortArray(arg) ||
+ RPCFixedArray(arg) || RPCVariableArray(arg)) {
+ WriteRPCArgDescriptor(file, arg, offset);
+ size = 4;
+ }
+ if (! size) {
+ if (compound)
+ size = arg->argType->itNumber * (arg->argType->itSize / 8);
+ else
+ size = (arg->argType->itSize / 8);
+ }
+ if (akCheck(arg->argKind, akbServerArg))
+ offset += size;
+ size = 0;
+ }
+}
+
+
+static void
+WriteRPCSignature(FILE *file, routine_t *rt)
+{
+ int arg_count = 0;
+ int descr_count = 0;
+
+ fprintf(file, " kern_return_t rtn;\n");
+ descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count);
+ fprintf(file, " const static struct\n {\n");
+ fprintf(file, " struct rpc_routine_descriptor rd;\n");
+ fprintf(file, " struct rpc_routine_arg_descriptor rad[%d];\n", descr_count);
+ fprintf(file, " } sig =\n {\n");
+ WriteRPCRoutineDescriptor(file, rt, arg_count, descr_count, "0", "sig.rad, 0");
+ fprintf(file, ",\n");
+ fprintf(file, " {\n");
+ WriteRPCRoutineArgDescriptor(file, rt);
+ fprintf(file, "\n }\n");
+ fprintf(file, "\n };\n\n");
+}
+
+static void
+WriteRPCCall(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ int i;
+
+ i = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akIdent(arg->argKind) == akeRequestPort) {
+ fprintf(file, " rtn = (MACH_RPC(&sig, (mach_msg_size_t)sizeof(sig), %d, %s,\n", rt->rtNumber + SubsystemBase, arg->argVarName);
+ fprintf(file, " (%s", arg->argVarName);
+ }
+ else if (akCheck(arg->argKind, akbServerArg)) {
+ if (i && (i++ % 6 == 0))
+ fprintf(file, ",\n ");
+ else
+ fprintf(file, ", ");
+ fprintf(file, "%s", arg->argVarName);
+ }
+ }
+ fprintf(file, ")));\n");
+ fprintf(file, "\n");
+ fprintf(file, " if (rtn != KERN_NO_ACCESS) return rtn;\n\n");
+ fprintf(file, "/* The following message rpc code is generated for the network case */\n\n");
+}
+
+static int
+CheckRPCCall(routine_t *rt)
+{
+ argument_t *arg;
+ int i;
+
+ i = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheck(arg->argKind, akbUserArg) &&
+ ((arg->argType->itOutName == -1) || (arg->argType->itInName == -1))) {
+ return FALSE;
+ }
+ if (arg->argFlags & flMaybeDealloc) {
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static void
+WriteRPCRoutine(FILE *file, routine_t *rt)
+{
+ if (CheckRPCCall(rt)) {
+ WriteRPCSignature(file, rt);
+ WriteRPCCall(file, rt);
+ }
+}
+
+/********************** End UserRPCTrap Routines*************************/
+
+/* Process an IN/INOUT arg before the short-circuited RPC */
+static void
+WriteShortCircInArgBefore(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char size[128];
+
+ fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+ if (!(arg->argFlags & flDealloc) &&
+ (!(arg->argFlags & flAuto) || !(arg->argFlags & flConst))) {
+ /* Need to map a copy of the array: */
+ GetArraySize(arg, size);
+ fprintf(file, "\t(void)vm_read(mach_task_self(),\n");
+ 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);
+ /* Point argument at the copy: */
+ fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
+ }
+ else if ((arg->argFlags & flDealloc) &&
+ ((arg->argFlags & flAuto) || it->itMigInLine)) {
+ /* Point the temp var at the original argument: */
+ fprintf(file, "\t_%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber > 1) {
+ if (it->itStruct) {
+ /* Arg is a struct -- nothing to do. */
+ }
+ else {
+ /* Arg is a C string or an in-line array: */
+ if (!argIsOut(arg) && !(arg->argFlags & flConst)) {
+ /* Have to copy it into a temp. Use a stack var, if this would
+ * not overflow the -maxonstack specification:
+ * Conservatively assume ILP32 thresholds
+ */
+ if (it->itTypeSize <= sizeof(natural_t) ||
+ rtMessOnStack(arg->argRoutine) ||
+ arg->argRoutine->rtTempBytesOnStack +
+ it->itTypeSize <= MaxMessSizeOnStack) {
+ fprintf(file, "\t{ char _%sTemp_[%d];\n", arg->argVarName, it->itTypeSize);
+ arg->argRoutine->rtTempBytesOnStack += it->itTypeSize;
+ arg->argTempOnStack = TRUE;
+ }
+ else {
+ fprintf(file, "\t{ _%sTemp_ = (char *) %s(%d);\n", arg->argVarName, MessAllocRoutine, it->itTypeSize);
+ arg->argTempOnStack = FALSE;
+ }
+ WriteCopyArg(file, arg, TRUE, "_%sTemp_", "/* %s */ (char *) %s", arg->argVarName, arg->argVarName);
+ /* Point argument at temp: */
+ fprintf(file, "\t *(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
+ fprintf(file, "\t}\n");
+ }
+ }
+ }
+}
+
+
+/* Process an INOUT/OUT arg before the short-circuited RPC */
+static void
+WriteShortCircOutArgBefore(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+
+ fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+ if (!argIsIn(arg) && (arg->argFlags & flOverwrite)) {
+ /* Point the temp var at the original argument: */
+ fprintf(file, "\t _%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber > 1) {
+ /* Arg is an in-line array: */
+ }
+}
+
+
+
+/* Process an IN arg after the short-circuited RPC */
+static void
+WriteShortCircInArgAfter(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char size[128];
+
+ fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+ GetArraySize(arg, size);
+ if ((!(arg->argFlags & flAuto) && it->itMigInLine) ||
+ ((arg->argFlags & flAuto) &&
+ ((arg->argFlags & flDealloc) ||
+ !(arg->argFlags & flConst))
+ )) {
+ /* Need to dealloc the temporary: */
+ fprintf(file, "\t(void)vm_deallocate(mach_task_self(),");
+ fprintf(file, " (vm_address_t *) _%sTemp_, %s);\n", arg->argVarName, size);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber > 1) {
+ if (it->itStruct) {
+ /* Arg is a struct -- nothing to do. */
+ }
+ else {
+ /* Arg is a C string or an in-line array: */
+ if (!argIsOut(arg) && !(arg->argFlags & flConst)) {
+ /* A temp needs to be deallocated, if not on stack: */
+ if (!arg->argTempOnStack) {
+ fprintf(file, "\t%s(_%sTemp_, %d);\n", MessFreeRoutine, arg->argVarName, it->itTypeSize);
+ }
+ }
+ }
+ }
+}
+
+static void
+WriteShortCircOutArgAfter(FILE *file, argument_t *arg)
+{
+ ipc_type_t *it = arg->argType;
+ char size[128];
+
+ fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName);
+
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) {
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ /* Arg is an out-of-line array: */
+
+ /* Calculate size of array: */
+ GetArraySize(arg, size);
+ if (!(arg->argFlags & flDealloc) || (arg->argFlags & flOverwrite)) {
+ /* Copy argument to vm_allocated Temp: */
+ fprintf(file, "\t(void)vm_read(mach_task_self(),\n");
+ 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);
+ if (!argIsIn(arg) && (arg->argFlags & flDealloc) &&
+ (arg->argFlags & flOverwrite)) {
+ /* Deallocate argument returned by server */
+ fprintf(file, "\t(void)vm_deallocate(mach_task_self(),");
+ fprintf(file, " (vm_address_t *) %s%s, %s);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size);
+ }
+ /* Point argument at new temporary: */
+ fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName);
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+ }
+ else if (it->itNumber != 1) {
+ /* Arg is an in-line array: */
+ }
+}
+
+
+static void
+WriteShortCircRPC(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+ int server_argc, i;
+ boolean_t ShortCircOkay = TRUE;
+ boolean_t first_OOL_arg = TRUE;
+
+ fprintf(file, " if (0 /* Should be: !(%s & 0x3) XXX */) {\n", rt->rtRequestPort->argVarName);
+
+ if (rt->rtOneWay) {
+ /* Do not short-circuit simple routines: */
+ ShortCircOkay = FALSE;
+ }
+ else {
+ /* Scan for any types we can't yet handle. If found, give up on short-
+ * circuiting and fall back to mach_msg:
+ */
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (arg->argFlags & flMaybeDealloc) {
+ ShortCircOkay = FALSE;
+ break;
+ }
+ /* Can't yet handle ports: */
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
+ (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR ||
+ arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR)) {
+ ShortCircOkay = FALSE;
+ break;
+ }
+ }
+ }
+
+ if (ShortCircOkay) {
+
+ fprintf(file," rpc_subsystem_t subsystem = ((rpc_port_t)%s)->rp_subsystem;\n", rt->rtRequestPort->argVarName);
+ fprintf(file, "\n");
+ fprintf(file, " if (subsystem && subsystem->start == %d) {\n", SubsystemBase);
+ fprintf(file, "\tkern_return_t rtn;\n");
+ fprintf(file, "\n");
+
+ /* Declare temp vars for out-of-line array args, and for all array
+ * args, if -maxonstack has forced us to allocate in-line arrays
+ * off the stack:
+ */
+ rt->rtTempBytesOnStack = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ arg->argTempOnStack = FALSE;
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
+ arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+ if (first_OOL_arg) {
+ /* Need a garbage temporary to hold the datacount
+ * returned by vm_read, which we always ignore:
+ */
+ fprintf(file, "\tmach_msg_type_number_t _MIG_Ignore_Count_;\n");
+ first_OOL_arg = FALSE;
+ }
+ }
+ else if (!rtMessOnStack(rt) &&
+ arg->argType->itNumber > 1 && !arg->argType->itStruct) {
+ }
+ else
+ continue;
+ fprintf(file, "\tchar *_%sTemp_;\n", arg->argVarName);
+ /* Conservatively assume ILP32 thresholds */
+ rt->rtTempBytesOnStack += sizeof(natural_t);
+ }
+
+ /* Process the IN arguments, in order: */
+
+ fprintf(file, "\t/* Pre-Process the IN arguments: */\n");
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (argIsIn(arg))
+ WriteShortCircInArgBefore(file, arg);
+ if (argIsOut(arg))
+ WriteShortCircOutArgBefore(file, arg);
+ }
+ fprintf(file, "\n");
+
+ /* Count the number of server args: */
+ server_argc = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbServerArg))
+ server_argc++;
+
+ /* Call RPC_SIMPLE to switch to server stack and function: */
+ i = 0;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akIdent(arg->argKind) == akeRequestPort) {
+ fprintf(file, "\trtn = RPC_SIMPLE(%s, %d, %d, (", arg->argVarName, rt->rtNumber + SubsystemBase, server_argc);
+ fprintf(file, "%s", arg->argVarName);
+ }
+ else if (akCheck(arg->argKind, akbServerArg)) {
+ if (i++ % 6 == 0)
+ fprintf(file, ",\n\t\t");
+ else
+ fprintf(file, ", ");
+ fprintf(file, "%s", arg->argVarName);
+ }
+ }
+ fprintf(file, "));\n");
+ fprintf(file, "\n");
+
+ /* Process the IN and OUT arguments, in order: */
+ fprintf(file, "\t/* Post-Process the IN and OUT arguments: */\n");
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (argIsIn(arg))
+ WriteShortCircInArgAfter(file, arg);
+ if (argIsOut(arg))
+ WriteShortCircOutArgAfter(file, arg);
+ }
+ fprintf(file, "\n");
+
+ fprintf(file, "\treturn rtn;\n");
+ fprintf(file, " }\n");
+ }
+
+ /* In latest design, the following is not necessary, because in
+ * kernel-loaded tasks, the Mach port name is the same as the handle
+ * used by the RPC mechanism, namely a pointer to the ipc_port, and
+ * in user-mode tasks, the Mach port name gets renamed to be a pointer
+ * to the user-mode rpc_port_t struct.
+ */
+#if 0
+ if (IsKernelUser)
+ fprintf(file, " %s = (ipc_port_t)%s->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName);
+ else
+ fprintf(file, " %s = ((rpc_port_t)%s)->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName);
+#endif
+
+ fprintf(file, " }\n");
+}
+
+static void
+WriteStubDecl(FILE *file, routine_t *rt)
+{
+ fprintf(file, "\n");
+ fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
+ fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName);
+ if (BeAnsiC) {
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
+ fprintf(file, ")\n");
+ }
+ else {
+ fprintf(file, "#if\t%s\n", NewCDecl);
+ fprintf(file, "(\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n");
+ fprintf(file, ")\n");
+ fprintf(file, "#else\n");
+ fprintf(file, "\t(");
+ WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", "");
+ fprintf(file, ")\n");
+ WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n");
+ fprintf(file, "#endif\t/* %s */\n", NewCDecl);
+ }
+ fprintf(file, "{\n");
+}
+
+static void
+InitKPD_Disciplines(argument_t *args)
+{
+ argument_t *arg;
+ extern void KPD_noop(FILE *file, argument_t *arg);
+ extern void KPD_error(FILE *file, argument_t *arg);
+ extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in);
+ extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in);
+ extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in);
+
+ /*
+ * WriteKPD_port, WriteExtractKPD_port,
+ * WriteKPD_ool, WriteExtractKPD_ool,
+ * WriteKPD_oolport, WriteExtractKPD_oolport
+ * are local to this module (which is the reason why this initialization
+ * takes place here rather than in utils.c).
+ * Common routines for user and server will be established SOON, and
+ * all of them (including the initialization) will be transfert to
+ * utils.c
+ * All the KPD disciplines are defaulted to be KPD_error().
+ * Note that akbSendKPD and akbReturnKPd are not exclusive,
+ * because of inout type of parameters.
+ */
+ for (arg = args; arg != argNULL; arg = arg->argNext)
+ if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD))
+ switch (arg->argKPD_Type) {
+
+ case MACH_MSG_PORT_DESCRIPTOR:
+ arg->argKPD_Init = KPD_noop;
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_port;
+ arg->argKPD_Pack = WriteKPD_port;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_Extract = WriteExtractKPD_port;
+ arg->argKPD_TypeCheck = WriteTCheckKPD_port;
+ }
+ break;
+
+ case MACH_MSG_OOL_DESCRIPTOR:
+ arg->argKPD_Init = KPD_noop;
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_ool;
+ arg->argKPD_Pack = WriteKPD_ool;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_TypeCheck = WriteTCheckKPD_ool;
+ arg->argKPD_Extract = WriteExtractKPD_ool;
+ }
+ break;
+
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ arg->argKPD_Init = KPD_noop;
+ if akCheck(arg->argKind, akbSendKPD) {
+ arg->argKPD_Template = WriteTemplateKPD_oolport;
+ arg->argKPD_Pack = WriteKPD_oolport;
+ }
+ if akCheck(arg->argKind, akbReturnKPD) {
+ arg->argKPD_TypeCheck = WriteTCheckKPD_oolport;
+ arg->argKPD_Extract = WriteExtractKPD_oolport;
+ }
+ break;
+
+ default:
+ printf("MiG internal error: type of kernel processed data unknown\n");
+ exit(1);
+ } /* end of switch */
+}
+
+static void
+WriteLimitCheck(FILE *file, routine_t *rt)
+{
+ if (MaxMessSizeOnStack == -1 || UserTypeLimit == -1)
+ return;
+ if (!rt->rtRequestUsedLimit && !rt->rtReplyUsedLimit)
+ return;
+ fprintf(file, "#if LimitCheck\n");
+ if (rt->rtRequestUsedLimit) {
+ if (rt->rtRequestFits) {
+ fprintf(file, "\tif ((sizeof(Request) - %d) > %d)\n", rt->rtRequestSizeKnown, UserTypeLimit);
+ fprintf(file, "\t __RequestOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ else if (rt->rtReplyFits) {
+ fprintf(file, "\tif (sizeof(Request) < %d)\n", MaxMessSizeOnStack);
+ fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ }
+ if (rt->rtReplyUsedLimit) {
+ if (rt->rtReplyFits) {
+ fprintf(file, "\tif ((sizeof(Reply) - %d) > %d)\n", rt->rtReplySizeKnown, UserTypeLimit);
+ fprintf(file, "\t __ReplyOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ else if (rt->rtRequestFits) {
+ fprintf(file, "\tif (sizeof(Reply) < %d)\n", MaxMessSizeOnStack);
+ fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ }
+ if (rt->rtRequestUsedLimit && rt->rtReplyUsedLimit &&
+ ! (rt->rtRequestFits || rt->rtReplyFits)) {
+ fprintf(file, "\tif (sizeof(Request) < %d \n", MaxMessSizeOnStack);
+ fprintf(file, "&& sizeof(Reply) < %d)\n", MaxMessSizeOnStack);
+ fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName);
+ }
+ fprintf(file, "#endif /* LimitCheck */\n");
+}
+
+static void
+WriteOOLSizeCheck(FILE *file, routine_t *rt)
+{
+ /* Emit code to validate the actual size of ool data vs. the reported size */
+ argument_t *argPtr;
+ boolean_t openedTypeCheckConditional = FALSE;
+
+ // scan through arguments to see if there are any ool data blocks
+ for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
+ if (akCheck(argPtr->argKind, akbReturnKPD)) {
+ ipc_type_t *it = argPtr->argType;
+ boolean_t multiple_kpd = IS_MULTIPLE_KPD(it);
+ char string[MAX_STR_LEN];
+ boolean_t test;
+ argument_t *argCountPtr;
+ char *tab;
+
+ if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
+
+ if (multiple_kpd) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement; // point to element descriptor, so size calculation is correct
+ argCountPtr = argPtr->argSubCount;
+ } else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField);
+ test = !it->itVarArray;
+ argCountPtr = argPtr->argCount;
+ }
+
+ if (!test) {
+ int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1;
+
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ fprintf(file, "\t%s" "if (%ssize ", tab, string);
+ if (multiplier > 1)
+ fprintf(file, "/ %d ", multiplier);
+ fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
+ if (it->itOOL_Number) {
+ fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos,
+ argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
+ }
+ fprintf(file,")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+ }
+
+ if (multiple_kpd)
+ fprintf(file, "\t }\n\t}\n");
+ } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) {
+ if (multiple_kpd) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE);
+ tab = "\t";
+ sprintf(string, "ptr->");
+ test = !it->itVarArray && !it->itElement->itVarArray;
+ it = it->itElement; // point to element descriptor, so size calculation is correct
+ argCountPtr = argPtr->argSubCount;
+ } else {
+ tab = "";
+ sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField);
+ test = !it->itVarArray;
+ argCountPtr = argPtr->argCount;
+ }
+
+ if (!test) {
+ if ( !openedTypeCheckConditional ) {
+ openedTypeCheckConditional = TRUE;
+ fputs("#if __MigTypeCheck\n", file);
+ }
+
+ fprintf(file, "\t%s" "if (%scount ", tab, string);
+ fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : "");
+ if (it->itOOL_Number) {
+ fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos,
+ argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number);
+ }
+ fprintf(file,")\n");
+ fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
+ }
+
+ if (multiple_kpd)
+ fprintf(file, "\t }\n\t}\n");
+ }
+ }
+ }
+
+ if ( openedTypeCheckConditional )
+ fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file);
+}
+
+static void
+WriteCheckReply(FILE *file, routine_t *rt)
+{
+ int i;
+
+ /* initialize the disciplines for the handling of KPDs */
+ InitKPD_Disciplines(rt->rtArgs);
+
+ if (rt->rtOneWay)
+ return;
+
+ fprintf(file, "\n");
+ fprintf(file, "#if ( __MigTypeCheck ");
+ if (CheckNDR)
+ fprintf(file, "|| __NDR_convert__ ");
+ fprintf(file, ")\n");
+ fprintf(file, "#if __MIG_check__Reply__%s_subsystem__\n", SubsystemName);
+ fprintf(file, "#if !defined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName);
+ fprintf(file, "#define __MIG_check__Reply__%s_t__defined\n", rt->rtName);
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) {
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgDecl, akbReturnNdr, "\n", "\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgDecl, akbReturnNdr, "\n", "\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgDecl, akbReturnNdr, "\n", "\n");
+ }
+ fprintf(file, "\n");
+ fprintf(file, "mig_internal kern_return_t __MIG_check__Reply__%s_t(__Reply__%s_t *Out0P", rt->rtName, rt->rtName);
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, ", __Reply__%s_t **Out%dPP", rt->rtName, i);
+ fprintf(file, ")\n{\n");
+
+
+ fprintf(file, "\n\ttypedef __Reply__%s_t __Reply __attribute__((unused));\n", rt->rtName);
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, "\t__Reply *Out%dP;\n", i);
+ if (!rt->rtSimpleReply)
+ fprintf(file, "\tboolean_t msgh_simple;\n");
+ if (!rt->rtNoReplyArgs) {
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tunsigned int msgh_size;\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+ }
+ if (rt->rtMaxReplyPos > 0)
+ fprintf(file, "\tunsigned int msgh_size_delta;\n");
+ if (rt->rtNumReplyVar > 0 || rt->rtMaxReplyPos > 0)
+ fprintf(file, "\n");
+
+ /* Check the values that are returned in the reply message */
+
+ WriteCheckIdentity(file, rt);
+
+ /* Check the remote port is NULL */
+ fprintf(file, "#if\t__MigTypeCheck\n");
+ fprintf(file, "\tif (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {\n");
+ fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif\t/* __MigTypeCheck */\n");
+
+ /* If the reply message has no Out parameters or return values
+ other than the return code, we can type-check it and
+ return it directly. */
+
+ if (rt->rtNoReplyArgs && !rt->rtUserImpl) {
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply) && rt->rtRetCode)
+ WriteReplyNDRConvertIntRepOneArgUse(file, rt->rtRetCode);
+ WriteReturn(file, rt, "\t", stRetCode, "\n", FALSE);
+ }
+ else {
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_USER, LOG_REPLY);
+
+ WriteRetCodeCheck(file, rt);
+
+ /* Type Checking for the Out parameters which are typed */
+ WriteList(file, rt->rtArgs, WriteTypeCheck, akbReturnKPD, "\n", "\n");
+
+ {
+ argument_t *arg, *lastVarArg;
+
+ lastVarArg = argNULL;
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ /*
+ * Advance message pointer if the last reply argument was
+ * variable-length and the reply position will change.
+ */
+ if (lastVarArg != argNULL &&
+ lastVarArg->argReplyPos < arg->argReplyPos) {
+ WriteAdjustReplyMsgPtr(file, lastVarArg);
+ lastVarArg = argNULL;
+ }
+
+ if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) {
+ if (akCheck(arg->argKind, akbVariable)) {
+ WriteCheckMsgSize(file, arg);
+ lastVarArg = arg;
+ }
+ }
+ }
+ }
+
+ if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) {
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgUse, akbReturnNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n");
+
+ WriteOOLSizeCheck(file, rt);
+
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (Out0P->NDR.char_rep != NDR_record.char_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgUse, akbReturnNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n");
+
+ fprintf(file, "#if\t");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgCond, akbReturnNdr, " || \\\n\t", "\n");
+ fprintf(file, "\tif (Out0P->NDR.float_rep != NDR_record.float_rep) {\n");
+ WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgUse, akbReturnNdr, "", "");
+ fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n");
+ } else {
+ WriteOOLSizeCheck(file, rt);
+ }
+ fprintf(file, "\treturn MACH_MSG_SUCCESS;\n");
+ }
+ fprintf(file, "}\n");
+ fprintf(file, "#endif /* !defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName);
+ fprintf(file, "#endif /* __MIG_check__Reply__%s_subsystem__ */\n", SubsystemName);
+ fprintf(file, "#endif /* ( __MigTypeCheck ");
+ if (CheckNDR)
+ fprintf(file, "|| __NDR_convert__ ");
+ fprintf(file, ") */\n\n");
+}
+
+static void
+WriteCheckReplyCall(FILE *file, routine_t *rt)
+{
+ int i;
+
+ fprintf(file, "\n");
+ fprintf(file, "#if\tdefined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName);
+ fprintf(file, "\tcheck_result = __MIG_check__Reply__%s_t((__Reply__%s_t *)Out0P", rt->rtName, rt->rtName);
+ for (i = 1; i <= rt->rtMaxReplyPos; i++)
+ fprintf(file, ", (__Reply__%s_t **)&Out%dP", rt->rtName, i);
+ fprintf(file, ");\n");
+ fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS) {\n");
+ if (IsKernelUser) {
+ fprintf(file, "#if\t__MigKernelSpecificCode\n");
+ fprintf(file, "\t\tmach_msg_destroy_from_kernel(&Out0P->Head);\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ } else {
+ fprintf(file, "\t\tmach_msg_destroy(&Out0P->Head);\n");
+ }
+ WriteReturnMsgError(file, rt, TRUE, argNULL, "check_result");
+ fprintf(file, "\t}\n");
+ fprintf(file, "#endif\t/* defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName);
+ fprintf(file, "\n");
+}
+
+void
+WriteCheckReplies(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine)
+ WriteCheckReply(file, stat->stRoutine);
+}
+
+static void
+WriteCheckReplyTrailerArgs(FILE *file, routine_t *rt)
+{
+ argument_t *arg;
+
+ if (rt->rtUserImpl)
+ WriteCheckTrailerHead(file, rt, TRUE);
+
+ for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
+ if (akCheck(arg->argKind, akbUserImplicit))
+ WriteCheckTrailerSize(file, TRUE, arg);
+ }
+ if (rt->rtUserImpl)
+ fprintf(file, "\n");
+}
+
+
+/*************************************************************
+ * Writes all the code comprising a routine body. Called by
+ * WriteUser for each routine.
+ *************************************************************/
+static void
+WriteRoutine(FILE *file, routine_t *rt)
+{
+ /* write the stub's declaration */
+ WriteStubDecl(file, rt);
+
+ /* Use the RPC trap for user-user and user-kernel RPC */
+ if (UseRPCTrap)
+ WriteRPCRoutine(file, rt);
+
+ /* write the code for doing a short-circuited RPC: */
+ if (ShortCircuit)
+ WriteShortCircRPC(file, rt);
+
+ /* typedef of structure for Request and Reply messages */
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, FALSE, FALSE, FALSE);
+ if (!rt->rtOneWay) {
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply", rt->rtSimpleReply, TRUE, rt->rtUserImpl, FALSE);
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "__Reply", rt->rtSimpleReply, FALSE, FALSE, FALSE);
+ }
+ if (rt->rtOverwrite)
+ WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply|akbOverwrite, "OverwriteTemplate", FALSE, TRUE, FALSE, TRUE);
+ /*
+ * Define a Minimal Reply structure to be used in case of errors
+ */
+ fprintf(file, "\t/*\n");
+ fprintf(file, "\t * typedef struct {\n");
+ fprintf(file, "\t * \tmach_msg_header_t Head;\n");
+ fprintf(file, "\t * \tNDR_record_t NDR;\n");
+ fprintf(file, "\t * \tkern_return_t RetCode;\n");
+ fprintf(file, "\t * } mig_reply_error_t;\n");
+ fprintf(file, "\t */\n");
+ fprintf(file, "\n");
+
+
+ /* declarations for local vars: Union of Request and Reply messages,
+ InP, OutP and return value */
+
+ WriteVarDecls(file, rt);
+
+ /* declarations and initializations of the mach_msg_type_descriptor_t variables
+ for each argument that is a Kernel Processed Data */
+
+ WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbRequest | akbSendKPD, "\n", "\n");
+
+ WriteLimitCheck(file, rt);
+ WriteRetCodeArg(file, rt);
+
+ /* fill in the fields that are non related to parameters */
+
+ if (!rt->rtSimpleRequest)
+ fprintf(file, "\tInP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtRequestKPDs);
+
+ /* fill in all the request message types and then arguments */
+
+ WriteRequestArgs(file, rt);
+
+ /* fill in request message head */
+
+ WriteRequestHead(file, rt);
+ fprintf(file, "\n");
+
+ /* give the application a chance to do some stuff. */
+ WriteApplMacro(file, "Send", "Before", rt);
+
+ /* Write the send/receive or rpc call */
+
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_USER, LOG_REQUEST);
+
+
+ if (rt->rtOneWay) {
+ WriteMsgSend(file, rt);
+ }
+ else {
+ if (UseMsgRPC
+#if USE_IMMEDIATE_SEND_TIMEOUT
+ && (rt->rtWaitTime == argNULL)
+#endif
+ ) {
+ /* overwrite mode meaningful only when UseMsgRPC is enabled */
+ if (rt->rtOverwrite)
+ WriteOverwriteTemplate(file, rt);
+ WriteMsgRPC(file, rt);
+ }
+ else
+ WriteMsgSendReceive(file, rt);
+
+ WriteCheckReplyCall(file, rt);
+ WriteCheckReplyTrailerArgs(file, rt);
+
+ if (UseEventLogger)
+ WriteLogMsg(file, rt, LOG_USER, LOG_REPLY);
+
+ WriteReplyArgs(file, rt);
+ }
+ /* return the return value, if any */
+ if (!rt->rtOneWay) // WriteMsgSend() already wrote the 'return'
+ WriteReturnValue(file, rt);
+ fprintf(file, "}\n");
+}
+
+static void
+WriteRPCClientFunctions(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+ char *fname;
+ char *argfmt = "(mach_port_t, char *, mach_msg_type_number_t)";
+
+ fprintf(file, "#ifdef AUTOTEST\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ fname = stat->stRoutine->rtName;
+ fprintf(file, "extern void client_%s%s;\n", fname, argfmt);
+ }
+ fprintf(file, "function_table_entry %s_client_functions[] =\n", SubsystemName);
+ fprintf(file, "{\n");
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ if (stat->stKind == skRoutine) {
+ fname = stat->stRoutine->rtName;
+ fprintf(file, " { \"%s\", client_%s },\n", fname, fname);
+ }
+ fprintf(file, " { (char *) 0, (function_ptr_t) 0 }\n");
+ fprintf(file, "};\n");
+ fprintf(file, "#endif /* AUTOTEST */\n");
+}
+
+/*************************************************************
+ * Writes out the xxxUser.c file. Called by mig.c
+ *************************************************************/
+void
+WriteUser(FILE *file, statement_t *stats)
+{
+ statement_t *stat;
+
+ WriteProlog(file, stats);
+ if (TestRPCTrap)
+ WriteRPCClientFunctions(file, stats);
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine:
+ WriteCheckReply(file, stat->stRoutine);
+ WriteRoutine(file, stat->stRoutine);
+ break;
+
+ case skImport:
+ case skUImport:
+ case skSImport:
+ case skDImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteUser(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+ WriteEpilog(file);
+}
+
+/*************************************************************
+ * Writes out individual .c user files for each routine. Called by mig.c
+ *************************************************************/
+void
+WriteUserIndividual(statement_t *stats)
+{
+ statement_t *stat;
+
+ for (stat = stats; stat != stNULL; stat = stat->stNext)
+ switch (stat->stKind) {
+
+ case skRoutine: {
+ FILE *file;
+ char *filename;
+
+ filename = strconcat(UserFilePrefix, strconcat(stat->stRoutine->rtName, ".c"));
+ file = fopen(filename, "w");
+ if (file == NULL)
+ fatal("fopen(%s): %s", filename, strerror(errno));
+ WriteProlog(file, stats);
+ WriteRoutine(file, stat->stRoutine);
+ WriteEpilog(file);
+ fclose(file);
+ strfree(filename);
+ }
+ break;
+
+ case skImport:
+ case skUImport:
+ case skSImport:
+ case skDImport:
+ case skIImport:
+ break;
+
+ default:
+ fatal("WriteUserIndividual(): bad statement_kind_t (%d)", (int) stat->stKind);
+ }
+}