diff options
Diffstat (limited to 'mig/user.c')
-rw-r--r-- | mig/user.c | 1332 |
1 files changed, 0 insertions, 1332 deletions
diff --git a/mig/user.c b/mig/user.c deleted file mode 100644 index a5ca5fb..0000000 --- a/mig/user.c +++ /dev/null @@ -1,1332 +0,0 @@ -/* - * Mach Operating System - * Copyright (c) 1992,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 <assert.h> - -#include "write.h" -#include "error.h" -#include "utils.h" -#include "global.h" -#include "mig_string.h" -#include "cpu.h" - -/************************************************************* - * Writes the standard includes. The subsystem specific - * includes are in <SubsystemName>.h and writen by - * header:WriteHeader. Called by WriteProlog. - *************************************************************/ -static void -WriteIncludes(FILE *file) -{ - 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\tKERNEL\n"); - - if (InternalHeaderFileName != strNULL) - { - register 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); - } - } - - if (UserHeaderFileName != strNULL) - { - register 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); - } - - fprintf(file, "#define EXPORT_BOOLEAN\n"); - fprintf(file, "#include <mach/boolean.h>\n"); - fprintf(file, "#include <mach/kern_return.h>\n"); - fprintf(file, "#include <mach/message.h>\n"); - fprintf(file, "#include <mach/notify.h>\n"); - fprintf(file, "#include <mach/mach_types.h>\n"); - fprintf(file, "#include <mach/mig_errors.h>\n"); - fprintf(file, "#include <mach/mig_support.h>\n"); - fprintf(file, "#include <mach/msg_type.h>\n"); - fprintf(file, "/* LINTLIBRARY */\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"); -} - -/************************************************************* - * Writes the standard #includes, #defines, and - * RCS declaration. Called by WriteUser. - *************************************************************/ -static void -WriteProlog(FILE *file) -{ - WriteIncludes(file); - WriteBogusDefines(file); - WriteGlobalDecls(file); -} - -/*ARGSUSED*/ -static void -WriteEpilog(FILE *file) -{ -} - -static const_string_t -WriteHeaderPortType(const 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, const routine_t *rt) -{ - if (rt->rtMaxRequestPos > 0) - fprintf(file, "\tInP = &Mess.In;\n"); - - if (rt->rtSimpleFixedRequest) { - fprintf(file, "\tInP->Head.msgh_bits ="); - if (!rt->rtSimpleSendRequest) - fprintf(file, " MACH_MSGH_BITS_COMPLEX|"); - fprintf(file, "\n"); - fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n", - WriteHeaderPortType(rt->rtRequestPort), - WriteHeaderPortType(rt->rtUReplyPort)); - } else { - fprintf(file, "\tInP->Head.msgh_bits = msgh_simple ?\n"); - fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s) :\n", - WriteHeaderPortType(rt->rtRequestPort), - WriteHeaderPortType(rt->rtUReplyPort)); - fprintf(file, "\t\t(MACH_MSGH_BITS_COMPLEX|\n"); - fprintf(file, "\t\t MACH_MSGH_BITS(%s, %s));\n", - WriteHeaderPortType(rt->rtRequestPort), - WriteHeaderPortType(rt->rtUReplyPort)); - } - - 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. - */ - - if (IsKernelUser) - fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", - rt->rtRequestPort->argMsgField, - rt->rtRequestPort->argVarName); - else - fprintf(file, "\tInP->%s = %s;\n", - rt->rtRequestPort->argMsgField, - rt->rtRequestPort->argVarName); - - if (akCheck(rt->rtUReplyPort->argKind, akbUserArg)) { - if (IsKernelUser) - fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", - rt->rtUReplyPort->argMsgField, - rt->rtUReplyPort->argVarName); - else - fprintf(file, "\tInP->%s = %s;\n", - rt->rtUReplyPort->argMsgField, - rt->rtUReplyPort->argVarName); - } else if (rt->rtOneWay || IsKernelUser) - fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n", - rt->rtUReplyPort->argMsgField); - else - fprintf(file, "\tInP->%s = %smig_get_reply_port();\n", - rt->rtUReplyPort->argMsgField, SubrPrefix); - - fprintf(file, "\tInP->Head.msgh_seqno = 0;\n"); - fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase); -} - -/************************************************************* - * Writes declarations for the message types, variables - * and return variable if needed. Called by WriteRoutine. - *************************************************************/ -static void -WriteVarDecls(FILE *file, const routine_t *rt) -{ - fprintf(file, "\tunion {\n"); - fprintf(file, "\t\tRequest In;\n"); - if (!rt->rtOneWay) - fprintf(file, "\t\tReply Out;\n"); - fprintf(file, "\t} Mess;\n"); - fprintf(file, "\n"); - - fprintf(file, "\tregister Request *InP = &Mess.In;\n"); - if (!rt->rtOneWay) - fprintf(file, "\tregister Reply *OutP = &Mess.Out;\n"); - fprintf(file, "\n"); - - if (!rt->rtOneWay || rt->rtProcedure) - fprintf(file, "\tmach_msg_return_t msg_result;\n"); - - if (!rt->rtSimpleFixedRequest) - fprintf(file, "\tboolean_t msgh_simple = %s;\n", - strbool(rt->rtSimpleSendRequest)); - else if (!rt->rtOneWay && - !(rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply)) { - fprintf(file, "#if\tTypeCheck\n"); - fprintf(file, "\tboolean_t msgh_simple;\n"); - fprintf(file, "#endif\t/* TypeCheck */\n"); - } - - if (rt->rtNumRequestVar > 0) - fprintf(file, "\tunsigned int msgh_size;\n"); - else if (!rt->rtOneWay && !rt->rtNoReplyArgs) - { - fprintf(file, "#if\tTypeCheck\n"); - fprintf(file, "\tunsigned int msgh_size;\n"); - fprintf(file, "#endif\t/* TypeCheck */\n"); - } - - /* if either request or reply is variable, we need msgh_size_delta */ - if ((rt->rtMaxRequestPos > 0) || - (rt->rtMaxReplyPos > 0)) - fprintf(file, "\tunsigned int msgh_size_delta;\n"); - - fprintf(file, "\n"); -} - -/************************************************************* - * Writes code to call the user provided error procedure - * when a MIG error occurs. Called by WriteMsgSend, - * WriteMsgCheckReceive, WriteMsgSendReceive, WriteCheckIdentity, - * WriteRetCodeCheck, WriteTypeCheck, WritePackArgValue. - *************************************************************/ -static void -WriteMsgError(FILE *file, const routine_t *rt, const char *error_msg) -{ - if (rt->rtProcedure) - fprintf(file, "\t\t{ %s(%s); return; }\n", rt->rtErrorName, error_msg); - else if (rt->rtReturn != rt->rtRetCode) - { - fprintf(file, "\t\t{ %s(%s); ", rt->rtErrorName, error_msg); - if (rt->rtNumReplyVar > 0) - fprintf(file, "OutP = &Mess.Out; "); - fprintf(file, "return OutP->%s; }\n", rt->rtReturn->argMsgField); - } - else - fprintf(file, "\t\treturn %s;\n", error_msg); -} - -/************************************************************* - * Writes the send call when there is to be no subsequent - * receive. Called by WriteRoutine for SimpleProcedures - * or SimpleRoutines - *************************************************************/ -static void -WriteMsgSend(FILE *file, const routine_t *rt) -{ - const char *MsgResult = (rt->rtProcedure) - ? "msg_result =" - : "return"; - - char SendSize[24]; - - if (rt->rtNumRequestVar == 0) - sprintf(SendSize, "%d", rt->rtRequestSize); - else - strcpy(SendSize, "msgh_size"); - - if (IsKernelUser) - { - fprintf(file, "\t%s %smach_msg_send_from_kernel(", - MsgResult, SubrPrefix); - fprintf(file, "&InP->Head, %s);\n", SendSize); - } - else - { - fprintf(file, "\t%s %smach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0,", - MsgResult, - SubrPrefix, - rt->rtMsgOption->argVarName, - SendSize); - fprintf(file, - " MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n" - ); - } - - if (rt->rtProcedure) - { - fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n"); - WriteMsgError(file, rt, "msg_result"); - } -} - -/************************************************************* - * Writes to code to check for error returns from receive. - * Called by WriteMsgSendReceive and WriteMsgRPC - *************************************************************/ -static void -WriteMsgCheckReceive(FILE *file, const routine_t *rt, const char *success) -{ - fprintf(file, "\tif (msg_result != %s) {\n", success); - if (!akCheck(rt->rtUReplyPort->argKind, akbUserArg) && !IsKernelUser) - { - /* If we aren't using a user-supplied reply port, - then deallocate the reply port on any message transmission - errors. */ - fprintf(file, "\t\t%smig_dealloc_reply_port(%s);\n", - SubrPrefix, "InP->Head.msgh_reply_port"); - } - WriteMsgError(file, rt, "msg_result"); - fprintf(file, "\t}\n"); - - /* - * If not using a user supplied reply port, tell the port - * allocator we're done with the port. - */ - if (!akCheck(rt->rtUReplyPort->argKind, akbUserArg) && !IsKernelUser) - { - fprintf(file, "\t%smig_put_reply_port(InP->Head.msgh_reply_port);\n", - SubrPrefix); - } -} - -/************************************************************* - * 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, const routine_t *rt) -{ - char SendSize[24]; - - if (rt->rtNumRequestVar == 0) - sprintf(SendSize, "%d", rt->rtRequestSize); - else - strcpy(SendSize, "msgh_size"); - - fprintf(file, "\tmsg_result = %smach_msg(&InP->Head, MACH_SEND_MSG|%s, %s, 0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL);\n", - SubrPrefix, - rt->rtMsgOption->argVarName, - SendSize); - - fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n"); - WriteMsgError(file, rt, "msg_result"); - fprintf(file, "\n"); - - fprintf(file, "\tmsg_result = %smach_msg(&OutP->Head, MACH_RCV_MSG|%s%s, 0, sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n", - SubrPrefix, - rt->rtMsgOption->argVarName, - rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "", - rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); - 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 SimpleProcedure and SimpleRoutine. - *************************************************************/ -static void -WriteMsgRPC(FILE *file, const routine_t *rt) -{ - char SendSize[24]; - - if (rt->rtNumRequestVar == 0) - sprintf(SendSize, "%d", rt->rtRequestSize); - else - strcpy(SendSize, "msgh_size"); - - if (IsKernelUser) - fprintf(file, "\tmsg_result = %smach_msg_rpc_from_kernel(&InP->Head, %s, sizeof(Reply));\n", - SubrPrefix, - SendSize); - else - fprintf(file, "\tmsg_result = %smach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s, %s, sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n", - SubrPrefix, - rt->rtMsgOption->argVarName, - rt->rtWaitTime != argNULL ? "|MACH_RCV_TIMEOUT" : "", - SendSize, - rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); - WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS"); - fprintf(file, "\n"); -} - -/************************************************************* - * Sets the correct value of the dealloc flag and calls - * Utils:WritePackMsgType to fill in the ipc msg type word(s) - * in the request message. Called by WriteRoutine for each - * argument that is to be sent in the request message. - *************************************************************/ -static void -WritePackArgType(FILE *file, const argument_t *arg) -{ - WritePackMsgType(file, arg->argType, - arg->argType->itIndefinite ? d_NO : arg->argDeallocate, - arg->argLongForm, TRUE, - "InP->%s", "%s", arg->argTTName); - 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 -WritePackArgValue(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *it = arg->argType; - register const char *ref = arg->argByReferenceUser ? "*" : ""; - - if (it->itInLine && it->itVarArray) { - - 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, - "\tInP->%s = %smig_strncpy(InP->%s, %s, %d);\n", - arg->argCount->argMsgField, - SubrPrefix, - arg->argMsgField, - arg->argVarName, - it->itNumber); - } - else { - - /* - * Copy in variable-size inline array with memcpy, - * after checking that number of elements doesn`t - * exceed declared maximum. - */ - register const argument_t *count = arg->argCount; - register const char *countRef = count->argByReferenceUser ? "*" :""; - register const ipc_type_t *btype = it->itElement; - - /* Note btype->itNumber == count->argMultiplier */ - - fprintf(file, "\tif (%s%s > %d) {\n", - countRef, count->argVarName, - it->itNumber/btype->itNumber); - if (it->itIndefinite) { - fprintf(file, "\t\tInP->%s%s.msgt_inline = FALSE;\n", - arg->argTTName, - arg->argLongForm ? ".msgtl_header" : ""); - if (arg->argDeallocate == d_YES) - fprintf(file, "\t\tInP->%s%s.msgt_deallocate = TRUE;\n", - arg->argTTName, - arg->argLongForm ? ".msgtl_header" : ""); - else if (arg->argDeallocate == d_MAYBE) - fprintf(file, "\t\tInP->%s%s.msgt_deallocate = %s%s;\n", - arg->argTTName, - arg->argLongForm ? ".msgtl_header" : "", - arg->argDealloc->argByReferenceUser ? "*" : "", - arg->argDealloc->argVarName); - fprintf(file, "\t\t*((%s **)InP->%s) = %s%s;\n", - FetchUserType(btype), - arg->argMsgField, - ref, arg->argVarName); - if (!arg->argRoutine->rtSimpleFixedRequest) - fprintf(file, "\t\tmsgh_simple = FALSE;\n"); - } - else - WriteMsgError(file, arg->argRoutine, "MIG_ARRAY_TOO_LARGE"); - - fprintf(file, "\t}\n\telse {\n"); - - fprintf(file, "\t\tmemcpy(InP->%s, %s%s, ", arg->argMsgField, - ref, arg->argVarName); - if (btype->itTypeSize > 1) - fprintf(file, "%d * ", btype->itTypeSize); - fprintf(file, "%s%s);\n", - countRef, count->argVarName); - fprintf(file, "\t}\n"); - } - } - else if (arg->argMultiplier > 1) - WriteCopyType(file, it, "InP->%s", "/* %s */ %d * %s%s", - arg->argMsgField, arg->argMultiplier, - ref, arg->argVarName); - else - WriteCopyType(file, it, "InP->%s", "/* %s */ %s%s", - arg->argMsgField, ref, arg->argVarName); - fprintf(file, "\n"); -} - -static void -WriteAdjustMsgSimple(FILE *file, register const argument_t *arg) -{ - if (!arg->argRoutine->rtSimpleFixedRequest) - { - register const char *ref = arg->argByReferenceUser ? "*" : ""; - - fprintf(file, "\tif (MACH_MSG_TYPE_PORT_ANY(%s%s))\n", - ref, arg->argVarName); - fprintf(file, "\t\tmsgh_simple = FALSE;\n"); - fprintf(file, "\n"); - } -} - -/* - * Calculate the size of a variable-length message field. - */ -static void -WriteArgSize(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *ptype = arg->argType; - register int bsize = ptype->itElement->itTypeSize; - register const argument_t *count = arg->argCount; - - if (ptype->itIndefinite) { - /* - * Check descriptor. If out-of-line, use standard size. - */ - fprintf(file, "(InP->%s%s.msgt_inline) ? ", - arg->argTTName, arg->argLongForm ? ".msgtl_header" : ""); - } - if (bsize % 4 != 0) - 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); - - /* - * If the base type size is not a multiple of sizeof(int) [4], - * we have to round up. - */ - if (bsize % 4 != 0) - fprintf(file, " + 3) & ~3"); - - if (ptype->itIndefinite) { - fprintf(file, " : sizeof(%s *)", - FetchUserType(ptype->itElement)); - } -} - -/* - * Adjust message size and advance request pointer. - * Called after packing a variable-length argument that - * has more arguments following. - */ -static void -WriteAdjustMsgSize(FILE *file, register const argument_t *arg) -{ - register const 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 = %d + msgh_size_delta;\n", - arg->argRoutine->rtRequestSize); - else - fprintf(file, "\tmsgh_size += msgh_size_delta;\n"); - - fprintf(file, - "\tInP = (Request *) ((char *) InP + msgh_size_delta - %d);\n", - ptype->itTypeSize + ptype->itPadSize); -} - -/* - * Calculate the size of the message. Called after the - * last argument has been packed. - */ -static void -WriteFinishMsgSize(FILE *file, register const 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 = %d + (", - arg->argRoutine->rtRequestSize); - WriteArgSize(file, arg); - fprintf(file, ");\n"); - } - else { - fprintf(file, "\tmsgh_size += "); - WriteArgSize(file, arg); - fprintf(file, ";\n"); - } -} - -static void -WriteInitializeCount(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *ptype = arg->argCInOut->argParent->argType; - register const 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"); -} - -/* - * Called for every argument. Responsible for packing that - * argument into the request message. - */ -static void -WritePackArg(FILE *file, register const argument_t *arg) -{ - if (akCheck(arg->argKind, akbRequest)) - WritePackArgType(file, arg); - - if ((akIdent(arg->argKind) == akePoly) && - akCheckAll(arg->argKind, akbSendSnd|akbUserArg)) - WriteAdjustMsgSimple(file, arg); - - if ((akIdent(arg->argKind) == akeCountInOut) && - akCheck(arg->argKind, akbSendSnd)) - WriteInitializeCount(file, arg); - else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody)) - WritePackArgValue(file, arg); -} - -/* - * Generate code to fill in all of the request arguments and their - * message types. - */ -static void -WriteRequestArgs(FILE *file, register const routine_t *rt) -{ - register const argument_t *arg; - register const argument_t *lastVarArg; - - 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; - } - - /* - * Copy the argument - */ - WritePackArg(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, const routine_t *rt) -{ - fprintf(file, "\tif (OutP->Head.msgh_id != %d) {\n", - rt->rtNumber + SubsystemBase + 100); - fprintf(file, "\t\tif (OutP->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n"); - WriteMsgError(file, rt, "MIG_SERVER_DIED"); - fprintf(file, "\t\telse {\n"); - fprintf(file, "\t\t\t%smig_dealloc_reply_port(%s);\n\t", - SubrPrefix,"InP->Head.msgh_reply_port"); - WriteMsgError(file, rt, "MIG_REPLY_MISMATCH"); - fprintf(file, "\t\t}\n\t}\n"); - fprintf(file, "\n"); - fprintf(file, "#if\tTypeCheck\n"); - - if (rt->rtSimpleCheckReply && rt->rtSimpleReceiveReply) - { - /* Expecting a simple message. We can factor out the check for - a simple message, since the error reply message is also simple. - */ - - if (!rt->rtNoReplyArgs) - fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n\n"); - - fprintf(file, - "\tif ((OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n"); - if (rt->rtNoReplyArgs) - fprintf(file, "\t (OutP->Head.msgh_size != %d))\n", - rt->rtReplySize); - else { - fprintf(file, "\t ((msgh_size %s %d) &&\n", - (rt->rtNumReplyVar > 0) ? "<" : "!=", - rt->rtReplySize); - fprintf(file, "\t ((msgh_size != sizeof(mig_reply_header_t)) ||\n"); - fprintf(file, "\t (OutP->RetCode == KERN_SUCCESS))))\n"); - } - } - else { - /* Expecting a complex message, or may vary at run time. */ - - fprintf(file, "\tmsgh_size = OutP->Head.msgh_size;\n"); - fprintf(file, "\tmsgh_simple = !(OutP->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n"); - fprintf(file, "\n"); - - fprintf(file, "\tif (((msgh_size %s %d)", - (rt->rtNumReplyVar > 0) ? "<" : "!=", - rt->rtReplySize); - - if (rt->rtSimpleCheckReply) - /* if rtSimpleReceiveReply was true, then we would have - executed the code above. So we know that the message - is complex. */ - fprintf(file, " || msgh_simple"); - fprintf(file, ") &&\n"); - - fprintf(file, "\t ((msgh_size != sizeof(mig_reply_header_t)) ||\n"); - fprintf(file, "\t !msgh_simple ||\n"); - fprintf(file, "\t (OutP->RetCode == KERN_SUCCESS)))\n"); - } - WriteMsgError(file, rt, "MIG_TYPE_ERROR"); - fprintf(file, "#endif\t/* TypeCheck */\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, const routine_t *rt) -{ - fprintf(file, "\tif (OutP->RetCode != KERN_SUCCESS)\n"); - WriteMsgError(file, rt, "OutP->RetCode"); - fprintf(file, "\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 argument in the reply message. - *************************************************************/ -static void -WriteTypeCheck(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *it = arg->argType; - register const routine_t *rt = arg->argRoutine; - - fprintf(file, "#if\tTypeCheck\n"); - if (akCheck(arg->argKind, akbReplyQC)) - { - fprintf(file, "\tif (* (int *) &OutP->%s != * (int *) &%sCheck)\n", - arg->argTTName, arg->argVarName); - } - else - { - fprintf(file, "\tif ("); - if (!it->itIndefinite) { - fprintf(file, "(OutP->%s%s.msgt_inline != %s) ||\n\t ", - arg->argTTName, - arg->argLongForm ? ".msgtl_header" : "", - strbool(it->itInLine)); - } - fprintf(file, "(OutP->%s%s.msgt_longform != %s) ||\n", - arg->argTTName, - arg->argLongForm ? ".msgtl_header" : "", - strbool(arg->argLongForm)); - if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) - { - if (!rt->rtSimpleCheckReply) - fprintf(file, "\t (MACH_MSG_TYPE_PORT_ANY(OutP->%s.msgt%s_name) && msgh_simple) ||\n", - arg->argTTName, - arg->argLongForm ? "l" : ""); - } - else - fprintf(file, "\t (OutP->%s.msgt%s_name != %s) ||\n", - arg->argTTName, - arg->argLongForm ? "l" : "", - it->itOutNameStr); - if (!it->itVarArray) - fprintf(file, "\t (OutP->%s.msgt%s_number != %d) ||\n", - arg->argTTName, - arg->argLongForm ? "l" : "", - it->itNumber); - fprintf(file, "\t (OutP->%s.msgt%s_size != %d))\n", - arg->argTTName, - arg->argLongForm ? "l" : "", - it->itSize); - } - WriteMsgError(file, rt, "MIG_TYPE_ERROR"); - fprintf(file, "#endif\t/* TypeCheck */\n"); - fprintf(file, "\n"); -} - -static void -WriteCheckArgSize(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *ptype = arg->argType; - register const ipc_type_t *btype = ptype->itElement; - const argument_t *count = arg->argCount; - int multiplier = btype->itTypeSize / btype->itNumber; - - if (ptype->itIndefinite) { - /* - * Check descriptor. If out-of-line, use standard size. - */ - fprintf(file, "(OutP->%s%s.msgt_inline) ? ", - arg->argTTName, arg->argLongForm ? ".msgtl_header" : ""); - } - - if (btype->itTypeSize % 4 != 0) - fprintf(file, "("); - - if (multiplier > 1) - fprintf(file, "%d * ", multiplier); - - fprintf(file, "OutP->%s", count->argMsgField); - - /* If the base type size of the data field isn`t a multiple of 4, - we have to round up. */ - if (btype->itTypeSize % 4 != 0) - fprintf(file, " + 3) & ~3"); - - if (ptype->itIndefinite) - fprintf(file, " : sizeof(%s *)", FetchUserType(btype)); -} - -static void -WriteCheckMsgSize(FILE *file, register const argument_t *arg) -{ - register const 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 (arg->argReplyPos == rt->rtMaxReplyPos) - { - fprintf(file, "#if\tTypeCheck\n"); - fprintf(file, "\tif (msgh_size != %d + (", - rt->rtReplySize); - WriteCheckArgSize(file, arg); - fprintf(file, "))\n"); - - WriteMsgError(file, rt, "MIG_TYPE_ERROR"); - fprintf(file, "#endif\t/* TypeCheck */\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 = "); - WriteCheckArgSize(file, arg); - fprintf(file, ";\n"); - fprintf(file, "#if\tTypeCheck\n"); - - /* Don't decrement msgh_size until we've checked that - it won't underflow. */ - - if (LastVarArg) - fprintf(file, "\tif (msgh_size != %d + msgh_size_delta)\n", - rt->rtReplySize); - else - fprintf(file, "\tif (msgh_size < %d + msgh_size_delta)\n", - rt->rtReplySize); - WriteMsgError(file, rt, "MIG_TYPE_ERROR"); - - if (!LastVarArg) - fprintf(file, "\tmsgh_size -= msgh_size_delta;\n"); - - fprintf(file, "#endif\t/* TypeCheck */\n"); - } - fprintf(file, "\n"); -} - -/************************************************************* - * 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 -WriteExtractArgValue(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *argType = arg->argType; - register const char *ref = arg->argByReferenceUser ? "*" : ""; - - if (argType->itInLine && argType->itVarArray) { - - if (argType->itString) { - /* - * Copy out variable-size C string with mig_strncpy. - */ - fprintf(file, "\t(void) %smig_strncpy(%s%s, OutP->%s, %d);\n", - SubrPrefix, - ref, - arg->argVarName, - arg->argMsgField, - argType->itNumber); - } - else if (argType->itIndefinite) { - /* - * If data was returned out-of-line, - * change user`s pointer to point to it. - * If data was returned in-line but doesn`t fit, - * allocate a new buffer, copy the data to it, - * and change user`s pointer to point to it. - * If data was returned in-line and fits, - * copy to buffer. - */ - const argument_t *count = arg->argCount; - const char *countRef = count->argByReferenceUser ? "*" : ""; - const ipc_type_t *btype = argType->itElement; - - fprintf(file, "\tif (!OutP->%s%s.msgt_inline)\n", - arg->argTTName, - arg->argLongForm ? ".msgtl_header" : ""); - fprintf(file, "\t %s%s = *((%s **)OutP->%s);\n", - ref, arg->argVarName, - FetchUserType(btype), arg->argMsgField); - fprintf(file, "\telse if (OutP->%s", count->argMsgField); - if (btype->itNumber > 1) - fprintf(file, " / %d", btype->itNumber); - fprintf(file, " > %s%s) {\n", countRef, count->argVarName); - fprintf(file, "\t %smig_allocate((vm_offset_t *)%s,\n\t\t", - SubrPrefix, arg->argVarName); /* no ref! */ - if (btype->itTypeSize != btype->itNumber) - fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber); - fprintf(file, "OutP->%s);\n", count->argMsgField); - fprintf(file, "\t memcpy(%s%s, OutP->%s, ", ref, arg->argVarName, - arg->argMsgField); - if (btype->itTypeSize != btype->itNumber) - fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber); - fprintf(file, "OutP->%s);\n", count->argMsgField); - fprintf(file, "\t}\n"); - fprintf(file, "\telse {\n"); - - fprintf(file, "\t memcpy(%s%s, OutP->%s, ", ref, arg->argVarName, - arg->argMsgField); - if (btype->itTypeSize != btype->itNumber) - fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber); - fprintf(file, "OutP->%s);\n", count->argMsgField); - fprintf(file, "\t}\n"); - } - else { - - /* - * Copy out variable-size inline array with memcpy, - * after checking that number of elements doesn`t - * exceed user`s maximum. - */ - register const argument_t *count = arg->argCount; - register const char *countRef = count->argByReferenceUser ? "*" :""; - register const ipc_type_t *btype = argType->itElement; - - /* Note count->argMultiplier == btype->itNumber */ - - fprintf(file, "\tif (OutP->%s", count->argMsgField); - if (btype->itNumber > 1) - fprintf(file, " / %d", btype->itNumber); - fprintf(file, " > %s%s) {\n", - countRef, count->argVarName); - - /* - * 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\tmemcpy(%s%s, OutP->%s, ", ref, arg->argVarName, - arg->argMsgField); - if (btype->itTypeSize > 1) - fprintf(file, "%d * ", btype->itTypeSize); - fprintf(file, "%s%s);\n", - countRef, count->argVarName); - - fprintf(file, "\t\t%s%s = OutP->%s", - countRef, count->argVarName, count->argMsgField); - if (btype->itNumber > 1) - fprintf(file, " / %d", btype->itNumber); - fprintf(file, ";\n"); - WriteMsgError(file,arg->argRoutine, "MIG_ARRAY_TOO_LARGE"); - - fprintf(file, "\t}\n\telse {\n"); - - fprintf(file, "\t\tmemcpy(%s%s, OutP->%s, ", ref, arg->argVarName, - arg->argMsgField); - if (btype->itTypeSize != btype->itNumber) - fprintf(file, "%d * ", btype->itTypeSize/btype->itNumber); - fprintf(file, "OutP->%s);\n", count->argMsgField); - fprintf(file, "\t}\n"); - } - } - else if (arg->argMultiplier > 1) - WriteCopyType(file, argType, - "%s%s", "/* %s%s */ OutP->%s / %d", - ref, arg->argVarName, arg->argMsgField, - arg->argMultiplier); - else - WriteCopyType(file, argType, - "%s%s", "/* %s%s */ OutP->%s", - ref, arg->argVarName, arg->argMsgField); - fprintf(file, "\n"); -} - -static void -WriteExtractArg(FILE *file, register const argument_t *arg) -{ - register const routine_t *rt = arg->argRoutine; - - if (akCheck(arg->argKind, akbReply)) - WriteTypeCheck(file, arg); - - if (akCheckAll(arg->argKind, akbVariable|akbReply)) - WriteCheckMsgSize(file, arg); - - /* Now that the RetCode is type-checked, check its value. - Must abort immediately if it isn't KERN_SUCCESS, because - in that case the reply message is truncated. */ - - if (arg == rt->rtRetCode) - WriteRetCodeCheck(file, rt); - - if (akCheckAll(arg->argKind, akbReturnRcv)) - WriteExtractArgValue(file, arg); -} - -static void -WriteAdjustReplyMsgPtr(FILE *file, register const argument_t *arg) -{ - register const ipc_type_t *ptype = arg->argType; - - fprintf(file, - "\tOutP = (Reply *) ((char *) OutP + msgh_size_delta - %d);\n\n", - ptype->itTypeSize + ptype->itPadSize); -} - -static void -WriteReplyArgs(FILE *file, register const routine_t *rt) -{ - register const argument_t *arg; - register const argument_t *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; - } - - /* - * Copy the argument - */ - WriteExtractArg(file, arg); - - /* - * Remember whether this was variable-length. - */ - if (akCheckAll(arg->argKind, akbReturnRcv|akbVariable)) - lastVarArg = arg; - } -} - -/************************************************************* - * Writes code to return the return value. Called by WriteRoutine - * for routines and functions. - *************************************************************/ -static void -WriteReturnValue(FILE *file, const routine_t *rt) -{ - if (rt->rtReturn == rt->rtRetCode) - /* If returning RetCode, we have already checked that it is - KERN_SUCCESS */ - fprintf(file, "\treturn KERN_SUCCESS;\n"); - - else - { - if (rt->rtNumReplyVar > 0) - fprintf(file, "\tOutP = &Mess.Out;\n"); - - fprintf(file, "\treturn OutP->%s;\n", rt->rtReturn->argMsgField); - } -} - -/************************************************************* - * 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, const argument_t *arg) -{ - WriteFieldDeclPrim(file, arg, FetchUserType); -} - -static void -WriteStubDecl(FILE *file, register const 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); - fprintf(file, "(\n"); - WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); - fprintf(file, ")\n"); - fprintf(file, "{\n"); -} - -/************************************************************* - * Writes all the code comprising a routine body. Called by - * WriteUser for each routine. - *************************************************************/ -static void -WriteRoutine(FILE *file, register const routine_t *rt) -{ - /* write the stub's declaration */ - - WriteStubDecl(file, rt); - - /* typedef of structure for Request and Reply messages */ - - WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request"); - if (!rt->rtOneWay) - WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply"); - - /* 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_t variables - for each argument */ - - WriteList(file, rt->rtArgs, WriteTypeDeclIn, akbRequest, "\n", "\n"); - if (!rt->rtOneWay) - WriteList(file, rt->rtArgs, WriteCheckDecl, akbReplyQC, "\n", "\n"); - - /* fill in all the request message types and then arguments */ - - WriteRequestArgs(file, rt); - - /* fill in request message head */ - - WriteRequestHead(file, rt); - fprintf(file, "\n"); - - /* Write the send/receive or rpc call */ - - if (rt->rtOneWay) - WriteMsgSend(file, rt); - else - { - if (UseMsgRPC) - WriteMsgRPC(file, rt); - else - WriteMsgSendReceive(file, rt); - - /* Check the values that are returned in the reply message */ - - WriteCheckIdentity(file, rt); - - /* 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) - { - WriteTypeCheck(file, rt->rtRetCode); - - fprintf(file, "\treturn OutP->RetCode;\n"); - } - else { - WriteReplyArgs(file, rt); - - /* return the return value, if any */ - - if (rt->rtProcedure) - fprintf(file, "\t/* Procedure - no return needed */\n"); - else - WriteReturnValue(file, rt); - } - } - - fprintf(file, "}\n"); -} - -/************************************************************* - * Writes out the xxxUser.c file. Called by mig.c - *************************************************************/ -void -WriteUser(FILE *file, const statement_t *stats) -{ - register const statement_t *stat; - - WriteProlog(file); - for (stat = stats; stat != stNULL; stat = stat->stNext) - switch (stat->stKind) - { - case skRoutine: - WriteRoutine(file, stat->stRoutine); - break; - case skImport: - case skUImport: - WriteImport(file, stat->stFileName); - break; - case skSImport: - 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(const statement_t *stats) -{ - register const statement_t *stat; - - for (stat = stats; stat != stNULL; stat = stat->stNext) - switch (stat->stKind) - { - case skRoutine: - { - FILE *file; - register char *filename; - - filename = strconcat(UserFilePrefix, - strconcat(stat->stRoutine->rtName, ".c")); - file = fopen(filename, "w"); - if (file == NULL) - fatal("fopen(%s): %s", filename, - unix_error_string(errno)); - WriteProlog(file); - - { - /* Write all the imports. */ - const statement_t *s; - for (s = stats; s != stNULL; s = s->stNext) - switch (s->stKind) - { - case skImport: - case skUImport: - WriteImport(file, s->stFileName); - break; - } - } - - WriteRoutine(file, stat->stRoutine); - WriteEpilog(file); - fclose(file); - strfree(filename); - } - break; - case skImport: - case skUImport: - break; - case skSImport: - break; - default: - fatal("WriteUserIndividual(): bad statement_kind_t (%d)", - (int) stat->stKind); - } -} |