From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: 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 --- bootstrap_cmds/migcom.tproj/routine.c | 1844 +++++++++++++++++++++++++++++++++ 1 file changed, 1844 insertions(+) create mode 100644 bootstrap_cmds/migcom.tproj/routine.c (limited to 'bootstrap_cmds/migcom.tproj/routine.c') diff --git a/bootstrap_cmds/migcom.tproj/routine.c b/bootstrap_cmds/migcom.tproj/routine.c new file mode 100644 index 0000000..f4c0778 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/routine.c @@ -0,0 +1,1844 @@ +/* + * 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 "AS IS" + * 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 Mellon + * the rights to redistribute these changes. + */ + +#include "type.h" + +#include +#include +#include "mig_machine.h" +#include "error.h" +#include "alloc.h" +#include "global.h" +#include "routine.h" +#include "write.h" + +u_int rtNumber = 0; + +static void rtSizeDelta(FILE *file, u_int mask, routine_t *rt); + +routine_t * +rtAlloc(void) +{ + routine_t *new; + + new = (routine_t *) calloc(1, sizeof *new); + if (new == rtNULL) + fatal("rtAlloc(): %s", strerror(errno)); + new->rtNumber = rtNumber++; + new->rtName = strNULL; + new->rtErrorName = strNULL; + new->rtUserName = strNULL; + new->rtServerName = strNULL; + + return new; +} + +void +rtSkip(void) +{ + rtNumber++; +} + +argument_t * +argAlloc(void) +{ + extern void KPD_error(FILE *file, argument_t *arg); + + static argument_t prototype = + { + .argName = strNULL, + .argNext = argNULL, + .argKind = akNone, + .argType = itNULL, + .argKPD_Type = argKPD_NULL, + .argKPD_Template = (void(*)(FILE *, argument_t *, boolean_t))KPD_error, + .argKPD_Init = KPD_error, + .argKPD_Pack = KPD_error, + .argKPD_Extract = KPD_error, + .argKPD_TypeCheck = KPD_error, + .argVarName = strNULL, + .argMsgField = strNULL, + .argTTName = strNULL, + .argPadName = strNULL, + .argSuffix = strNULL, + .argFlags = flNone, + .argDeallocate = d_NO, + .argCountInOut = FALSE, + .argRoutine = rtNULL, + .argCount = argNULL, + .argSubCount = argNULL, + .argCInOut = argNULL, + .argPoly = argNULL, + .argDealloc = argNULL, + .argSameCount = argNULL, + .argParent = argNULL, + .argMultiplier = 1, + .argRequestPos = 0, + .argReplyPos = 0, + .argByReferenceUser = FALSE, + .argByReferenceServer = FALSE, + .argTempOnStack = FALSE + }; + argument_t *new; + + new = (argument_t *) malloc(sizeof *new); + if (new == argNULL) + fatal("argAlloc(): %s", strerror(errno)); + *new = prototype; + return new; +} + +routine_t * +rtMakeRoutine(identifier_t name, argument_t *args) +{ + routine_t *rt = rtAlloc(); + + rt->rtName = name; + rt->rtKind = rkRoutine; + rt->rtArgs = args; + + return rt; +} + +routine_t * +rtMakeSimpleRoutine(identifier_t name, argument_t *args) +{ + routine_t *rt = rtAlloc(); + + rt->rtName = name; + rt->rtKind = rkSimpleRoutine; + rt->rtArgs = args; + + return rt; +} + +char * +rtRoutineKindToStr(routine_kind_t rk) +{ + switch (rk) { + + case rkRoutine: + return "Routine"; + + case rkSimpleRoutine: + return "SimpleRoutine"; + + default: + fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk); + /*NOTREACHED*/ + return strNULL; + } +} + +static void +rtPrintArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + if (!akCheck(arg->argKind, akbUserArg|akbServerArg) || + (akIdent(arg->argKind) == akeCount) || + (akIdent(arg->argKind) == akeDealloc) || + (akIdent(arg->argKind) == akeNdrCode) || + (akIdent(arg->argKind) == akePoly)) + return; + + printf("\n\t"); + + switch (akIdent(arg->argKind)) { + + case akeRequestPort: + printf("RequestPort"); + break; + + case akeReplyPort: + printf("ReplyPort"); + break; + + case akeWaitTime: + printf("WaitTime"); + break; + + case akeSendTime: + printf("SendTime"); + break; + + case akeMsgOption: + printf("MsgOption"); + break; + + case akeMsgSeqno: + printf("MsgSeqno\t"); + break; + + case akeSecToken: + printf("SecToken\t"); + break; + + case akeAuditToken: + printf("AuditToken\t"); + break; + + case akeContextToken: + printf("ContextToken\t"); + break; + + case akeImplicit: + printf("Implicit\t"); + break; + + default: + if (akCheck(arg->argKind, akbRequest)) { + if (akCheck(arg->argKind, akbSend)) + printf("In"); + else + printf("(In)"); + } + if (akCheck(arg->argKind, akbReply)) { + if (akCheck(arg->argKind, akbReturn)) + printf("Out"); + else + printf("(Out)"); + } + printf("\t"); + } + + printf("\t%s: %s", arg->argName, it->itName); + + if (arg->argDeallocate == d_YES) + printf(", Dealloc"); + else if (arg->argDeallocate == d_MAYBE) + printf(", Dealloc[]"); + + if (arg->argCountInOut) + printf(", CountInOut"); + + if (arg->argFlags & flSameCount) + printf(", SameCount"); + + if (arg->argFlags & flPhysicalCopy) + printf(", PhysicalCopy"); + + if (arg->argFlags & flRetCode) + printf(", PhysicalCopy"); + + if (arg->argFlags & flOverwrite) + printf(", Overwrite"); + + if (arg->argFlags & flAuto) + printf(", Auto"); + + if (arg->argFlags & flConst) + printf(", Const"); +} + +void +rtPrintRoutine(routine_t *rt) +{ + argument_t *arg; + + printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind), rt->rtNumber, rt->rtName); + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + rtPrintArg(arg); + + printf(")\n"); + printf("\n"); +} + +/* + * Determines appropriate value of msg-simple for the message. + * One version for both In & Out. + */ + +static void +rtCheckSimple(argument_t *args, u_int mask, boolean_t *simple) +{ + argument_t *arg; + boolean_t MustBeComplex = FALSE; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, mask)) { + ipc_type_t *it = arg->argType; + + if (IS_KERN_PROC_DATA(it)) + MustBeComplex = TRUE; + } + + *simple = !MustBeComplex; +} + +static void +rtCheckFit(routine_t *rt, u_int mask, boolean_t *fitp, boolean_t *uselimp, u_int *knownp) +{ + boolean_t uselim = FALSE; + argument_t *arg; + u_int size = sizeof(mach_msg_header_t); + + if (!rt->rtSimpleRequest) + machine_alignment(size,sizeof(mach_msg_body_t)); + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, mask)) { + ipc_type_t *it = arg->argType; + + machine_alignment(size, it->itMinTypeSize); + if (it->itNative) + uselim = TRUE; + else if (IS_VARIABLE_SIZED_UNTYPED(it)) { + machine_alignment(size, it->itTypeSize); + size += it->itPadSize; + } + } + *knownp = size; + if (MaxMessSizeOnStack == -1) { + *fitp = TRUE; + *uselimp = FALSE; + } + else if (size > MaxMessSizeOnStack) { + *fitp = FALSE; + *uselimp = FALSE; + } + else if (!uselim) { + *fitp = TRUE; + *uselimp = FALSE; + } + else if (UserTypeLimit == -1) { + *fitp = FALSE; + *uselimp = FALSE; + } + else if (size + UserTypeLimit > MaxMessSizeOnStack) { + *fitp = FALSE; + *uselimp = TRUE; + } + else { + *fitp = TRUE; + *uselimp = TRUE; + } +} + +static void +rtFindHowMany(routine_t *rt) +{ + argument_t *arg; + int multiplier = 1; + boolean_t test; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (IS_MULTIPLE_KPD(it)) { + if (!it->itVarArray) + multiplier = it->itKPD_Number; + test = !it->itVarArray && !it->itElement->itVarArray; + it = it->itElement; + } + else + test = !it->itVarArray; + + if (akCheck(arg->argKind, akbSendKPD)) { + + if (it->itInLine) + rt->rtCountPortsIn += it->itNumber * multiplier; + else if (it->itPortType) { + if (test) + rt->rtCountOolPortsIn += it->itNumber * multiplier; + } + else { + if (test) + rt->rtCountOolIn += (it->itNumber * it->itSize + 7)/8 * multiplier; + } + } + if (akCheckAll(arg->argKind, akbReturnKPD)) { + if (it->itInLine) + rt->rtCountPortsOut += it->itNumber * multiplier; + else if (it->itPortType) { + if (test) + rt->rtCountOolPortsOut += it->itNumber * multiplier; + } + else { + if (test) + rt->rtCountOolOut += ((it->itNumber * it->itSize + 7)/8) * multiplier; + } + } + } +} + +boolean_t +rtCheckMask(argument_t *args, u_int mask) +{ + argument_t *arg; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + return TRUE; + return FALSE; +} + +boolean_t +rtCheckMaskFunction(argument_t *args, u_int mask, boolean_t (*func)(argument_t *arg)) +{ + argument_t *arg; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + if ((*func)(arg)) + return TRUE; + return FALSE; +} + + +int +rtCountKPDs(argument_t *args, u_int mask) +{ + argument_t *arg; + int count = 0; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + count += arg->argType->itKPD_Number; + return count; +} + +int +rtCountFlags(argument_t *args, u_int flag) +{ + argument_t *arg; + int count = 0; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (arg->argFlags & flag) + count++; + return count; +} + +int +rtCountArgDescriptors(argument_t *args, int *argcount) +{ + argument_t *arg; + int count = 0; + + if (argcount) + *argcount = 0; + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbServerArg)) { + if (RPCFixedArray(arg) || + RPCPort(arg) || + RPCVariableArray(arg) || + RPCPortArray(arg)) { + count++; + if (argcount) + (*argcount)++; + } + else { + if (argcount) { + if (arg->argType->itStruct && arg->argType->itNumber && + (arg->argType->itSize >= 32)) + *argcount += arg->argType->itNumber * (arg->argType->itSize / 32); + else + (*argcount)++; + } + } + } + return count; +} + +int +rtCountMask(argument_t *args, u_int mask) +{ + argument_t *arg; + int count = 0; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + count++; + return count; +} + +/* arg->argType may be NULL in this function */ + +static void +rtDefaultArgKind(routine_t *rt, argument_t *arg) +{ + if ((arg->argKind == akNone) && (rt->rtRequestPort == argNULL)) + arg->argKind = akRequestPort; + + if (arg->argKind == akNone) + arg->argKind = akIn; +} + +/* + * Initializes arg->argDeallocate, + * arg->argCountInOut from arg->argFlags + * and perform consistency check over the + * flags. + */ + +static ipc_flags_t +rtProcessDeallocFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, dealloc_t *what, string_t name) +{ + + /* only one of flDealloc, flNotDealloc, flMaybeDealloc */ + + if (flags & flMaybeDealloc) { + if (flags & (flDealloc|flNotDealloc)) { + warn("%s: Dealloc and NotDealloc ignored with Dealloc[]", name); + flags &= ~(flDealloc|flNotDealloc); + } + } + + if ((flags&(flDealloc|flNotDealloc)) == (flDealloc|flNotDealloc)) { + warn("%s: Dealloc and NotDealloc cancel out", name); + flags &= ~(flDealloc|flNotDealloc); + } + + if (((IsKernelServer && akCheck(kind, akbReturn)) || + (IsKernelUser && akCheck(kind, akbSend))) && + (flags & flDealloc)) { + /* + * For a KernelServer interface and an Out argument, + * or a KernelUser interface and an In argument, + * we avoid a possible spurious warning about the deallocate bit. + * For compatibility with Mach 2.5, the deallocate bit + * may need to be enabled on some inline arguments. + */ + + *what= d_YES; + } + else if (flags & (flMaybeDealloc|flDealloc)) { + /* only give semantic warnings if the user specified something */ + if (it->itInLine && !it->itPortType) { + warn("%s: Dealloc is ignored: it is meaningless for that type of argument", name); + flags &= ~(flMaybeDealloc|flDealloc); + } + else + *what = (flags & flMaybeDealloc) ? d_MAYBE : d_YES; + } + return flags; +} + +static void +rtProcessSameCountFlag(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + ipc_flags_t flags = arg->argFlags; + string_t name = arg->argVarName; + static argument_t *old_arg; + + if (flags & flSameCount) { + if (!it->itVarArray) { + warn("%s: SameCount is ignored - the argument is not variable", name); + flags &= ~flSameCount; + } + if (old_arg) { + if (old_arg->argParent) + old_arg = old_arg->argParent; + if (old_arg->argSameCount) + old_arg = old_arg->argSameCount; + + if (!old_arg->argType->itVarArray) { + warn("%s: SameCount is ignored - adjacent argument is not variable", name); + flags &= ~flSameCount; + } + +#define SAMECOUNT_MASK akeBITS|akbSend|akbReturn|akbRequest|akbReply|akbUserArg|akbServerArg + if (akCheck(old_arg->argKind, SAMECOUNT_MASK) != + akCheck(arg->argKind, SAMECOUNT_MASK) || + old_arg->argCountInOut != arg->argCountInOut) { + warn("%s: SameCount is ignored - inconsistencies with the adjacent argument\n", name); + flags &= ~flSameCount; + } + arg->argSameCount = old_arg; + } + arg->argFlags = flags; + } + old_arg = arg; +} + +static ipc_flags_t +rtProcessCountInOutFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, boolean_t *what, string_t name) +{ + if (flags & flCountInOut) { + if (!akCheck(kind, akbReply)) { + warn("%s: CountInOut is ignored: argument must be Out\n", name); + flags &= ~flCountInOut; + } + else if (!it->itVarArray || !it->itInLine) { + warn("%s: CountInOut is ignored: argument isn't variable or in-line\n", name); + flags &= ~flCountInOut; + } + else + *what = TRUE; + } + return flags; +} + +static ipc_flags_t +rtProcessPhysicalCopyFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name) +{ + if (flags & flPhysicalCopy) { + if (it->itInLine) { + warn("%s: PhysicalCopy is ignored, argument copied inline anyway", name); + flags &= ~flPhysicalCopy; + } + if (it->itPortType) { + warn("%s: PhysicalCopy is ignored, it does not apply to ports and array of ports", name); + flags &= ~flPhysicalCopy; + } + } + return flags; +} + +static void +rtProcessRetCodeFlag(argument_t *thisarg) +{ + ipc_type_t *it = thisarg->argType; + ipc_flags_t flags = thisarg->argFlags; + string_t name = thisarg->argVarName; + routine_t *thisrout = thisarg->argRoutine; + + if (flags & flRetCode) { + if (!it->itInLine || !it->itStruct || + it->itSize != 32 || it->itNumber != 1) { + warn("%s: RetCode is ignored - the type doesn't match a MIG RetCode", name); + flags &= ~flRetCode; + } + else if (thisrout->rtKind != rkSimpleRoutine) { + fatal("%s: RetCode is allowed only for SimpleRoutines", name); + } + else if (thisrout->rtRetCArg != argNULL) { + warn("%s: RetCode is ignored - only one argument can be flagged as RetCode", name); + flags &= ~flRetCode; + } + else { + thisrout->rtRetCArg = thisarg; + } + thisarg->argFlags = flags; + } +} + +static ipc_flags_t +rtProcessOverwriteFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name) +{ + if (flags & flOverwrite) + if (it->itInLine || it->itMigInLine || + /* among In, Out, InOut, we want only the Out! */ + !akCheck(kind, akbReturn) || akCheck(kind, akbSend)) { + warn("%s: Overwrite is ignored - it must be Out AND Ool!", name); + flags &= ~flOverwrite; + } + return flags; +} + +static void +rtDetectKPDArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *string; + + if (IS_KERN_PROC_DATA(it)) { + if (akCheck(arg->argKind, akbSendBody)) { + arg->argKind = akRemFeature(arg->argKind, akbSendBody); + arg->argKind = akAddFeature(arg->argKind, akbSendKPD); + } + if (akCheck(arg->argKind, akbReturnBody)) { + arg->argKind = akRemFeature(arg->argKind, akbReturnBody); + arg->argKind = akAddFeature(arg->argKind, akbReturnKPD); + } + if (it->itInLine) { + string = "mach_msg_port_descriptor_t"; + arg->argKPD_Type = MACH_MSG_PORT_DESCRIPTOR; + } + else if (it->itPortType) { + string = "mach_msg_ool_ports_descriptor_t"; + arg->argKPD_Type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + } + else { + string = "mach_msg_ool_descriptor_t"; + arg->argKPD_Type = MACH_MSG_OOL_DESCRIPTOR; + } + it->itKPDType = string; + } +} + +static void +rtAugmentArgKind(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + /* akbVariable means variable-sized inline */ + + if (IS_VARIABLE_SIZED_UNTYPED(it)) { + if (akCheckAll(arg->argKind, akbRequest|akbReply)) + error("%s: Inline variable-sized arguments can't be InOut", arg->argName); + arg->argKind = akAddFeature(arg->argKind, akbVariable); + } + if (IS_OPTIONAL_NATIVE(it)) + arg->argKind = akAddFeature(arg->argKind, akbVariable); + + /* + * Need to use a local variable in the following cases: + * 1) There is a translate-out function & the argument is being + * returned. We need to translate it before it hits the message. + * 2) There is a translate-in function & the argument is + * sent and returned. We need a local variable for its address. + * 3) There is a destructor function, which will be used + * (SendRcv and not ReturnSnd), and there is a translate-in + * function whose value must be saved for the destructor. + * 4) This is Complex KPD (array of KPD), and as such it has to + * be copied to a local array in input and output + * 5) Both poly and dealloc generate warnings compile time, because + * we attempt to take address of bit-field structure member + */ + + if ( + ((it->itOutTrans != strNULL) && akCheck(arg->argKind, akbReturnSnd)) || + ((it->itInTrans != strNULL) && akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) || + ((it->itDestructor != strNULL) && akCheck(arg->argKind, akbSendRcv) && !akCheck(arg->argKind, akbReturnSnd) && (it->itInTrans != strNULL)) || + (IS_MULTIPLE_KPD(it)) || + ((akIdent(arg->argKind) == akePoly) && akCheck(arg->argKind, akbReturnSnd)) || + ((akIdent(arg->argKind) == akeDealloc) && akCheck(arg->argKind, akbReturnSnd)) + ) { + arg->argKind = akRemFeature(arg->argKind, akbReplyCopy); + arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); + } +} + +/* + * The Suffix allows to handle KPDs as normal data. + * it is used in InArgMsgField. + */ +static void +rtSuffixExtArg(argument_t *args) +{ + argument_t *arg; + char *subindex; + char string[MAX_STR_LEN]; + + for (arg = args; arg != argNULL; arg = arg->argNext) { + if (akCheck(arg->argKind, akbSendKPD | akbReturnKPD)) { + if (IS_MULTIPLE_KPD(arg->argType)) + subindex = "[0]"; + else + subindex = ""; + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + (void)sprintf(string, "%s.name", subindex); + break; + + case MACH_MSG_OOL_DESCRIPTOR: + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + (void)sprintf(string, "%s.address", subindex); + break; + + default: + error("Type of kernel processed data unknown\n"); + } + arg->argSuffix = strconcat(arg->argMsgField, string); + /* see above the list of VarNeeded cases */ + /* + * argCount has been removed from the VarNeeded list, + * because VarSize arrays have their Count in the untyped + * section of the message, and because it is not possible + * to move anything in-line/out-of-line + */ + } + else if (akIdent(arg->argKind) == akePoly && + akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) { + argument_t *par_arg = arg->argParent; + + if (IS_MULTIPLE_KPD(par_arg->argType)) + subindex = "[0]"; + else + subindex = ""; + switch (par_arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + (void)sprintf(string, "%s.disposition", subindex); + arg->argSuffix = strconcat(par_arg->argMsgField, string); + break; + + default: + error("Type of kernel processed data inconsistent\n"); + } + } + else if (akIdent(arg->argKind) == akeDealloc && + akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) { + argument_t *par_arg = arg->argParent; + + if (IS_MULTIPLE_KPD(par_arg->argType)) + subindex = "[0]"; + else + subindex = ""; + switch (par_arg->argKPD_Type) { + + case MACH_MSG_OOL_DESCRIPTOR: + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + (void)sprintf(string, "%s.deallocate", subindex); + arg->argSuffix = strconcat(par_arg->argMsgField, string); + break; + + default: + error("Type of kernel processed data inconsistent\n"); + } + } + } +} + +/* arg->argType may be NULL in this function */ + +static void +rtCheckRoutineArg(routine_t *rt, argument_t *arg) +{ + switch (akIdent(arg->argKind)) { + + case akeRequestPort: + if (rt->rtRequestPort != argNULL) + warn("multiple RequestPort args in %s; %s won't be used", rt->rtName, rt->rtRequestPort->argName); + rt->rtRequestPort = arg; + break; + + case akeReplyPort: + if (rt->rtReplyPort != argNULL) + warn("multiple ReplyPort args in %s; %s won't be used", rt->rtName, rt->rtReplyPort->argName); + rt->rtReplyPort = arg; + break; + + case akeWaitTime: + if (rt->rtWaitTime != argNULL) + warn("multiple WaitTime/SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName); + rt->rtWaitTime = arg; + break; + + case akeSendTime: + if (rt->rtWaitTime != argNULL) { + if (akIdent(rt->rtWaitTime->argKind) == akeWaitTime) { + warn("SendTime type argument after a WaitTime in %s; SendTime %s won't be used", rt->rtName, arg->argName); + break; + } else { + warn("multiple SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName); + } + } + rt->rtWaitTime = arg; + break; + + case akeMsgOption: + if (rt->rtMsgOption != argNULL) + warn("multiple MsgOption args in %s; %s won't be used", rt->rtName, rt->rtMsgOption->argName); + rt->rtMsgOption = arg; + break; + + default: + break; + } +} + +/* arg->argType may be NULL in this function */ + +static void +rtSetArgDefaults(routine_t *rt, argument_t *arg) +{ + arg->argRoutine = rt; + if (arg->argVarName == strNULL) + arg->argVarName = arg->argName; + if (arg->argMsgField == strNULL) + switch(akIdent(arg->argKind)) { + + case akeRequestPort: + arg->argMsgField = "Head.msgh_request_port"; + break; + + case akeReplyPort: + arg->argMsgField = "Head.msgh_reply_port"; + break; + + case akeNdrCode: + arg->argMsgField = "NDR"; + break; + + case akeSecToken: + arg->argMsgField = "msgh_sender"; + break; + + case akeAuditToken: + arg->argMsgField = "msgh_audit"; + break; + + case akeContextToken: + arg->argMsgField = "msgh_context"; + break; + + case akeMsgSeqno: + arg->argMsgField = "msgh_seqno"; + break; + + case akeImplicit: + /* the field is set directly by Yacc */ + break; + + default: + arg->argMsgField = arg->argName; + break; + } + + if (arg->argTTName == strNULL) + arg->argTTName = strconcat(arg->argName, "Template"); + if (arg->argPadName == strNULL) + arg->argPadName = strconcat(arg->argName, "Pad"); + + /* + * The poly args for the request and reply ports have special defaults, + * because their msg-type-name values aren't stored in normal fields. + */ + + if ((rt->rtRequestPort != argNULL) && + (rt->rtRequestPort->argPoly == arg) && + (arg->argType != itNULL)) { + arg->argMsgField = "Head.msgh_bits"; + arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST"; + } + + if ((rt->rtReplyPort != argNULL) && + (rt->rtReplyPort->argPoly == arg) && + (arg->argType != itNULL)) { + arg->argMsgField = "Head.msgh_bits"; + arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; + } +} + +static void +rtAddCountArg(argument_t *arg) +{ + argument_t *count, *master; + ipc_type_t *it = arg->argType; + + count = argAlloc(); + + if (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray) { + count->argName = strconcat(arg->argName, "Subs"); + count->argType = itMakeSubCountType(it->itKPD_Number, it->itVarArray, arg->argVarName); + count->argKind = akeSubCount; + arg->argSubCount = count; + } + else { + count->argName = strconcat(arg->argName, "Cnt"); + count->argType = itMakeCountType(); + count->argKind = akeCount; + arg->argCount = count; + if (arg->argParent != argNULL) { + /* this is the case where we are at the second level of recursion: + we want the Parent to access it through argCount */ + arg->argParent->argCount = count; + } + } + master = (arg->argParent != argNULL) ? arg->argParent : arg; + if (IS_MULTIPLE_KPD(master->argType)) + count->argMultiplier = 1; + else + count->argMultiplier = it->itElement->itNumber; + count->argParent = arg; + count->argNext = arg->argNext; + arg->argNext = count; + + if (arg->argType->itString) { + /* C String gets no Count argument on either side, but are still in the msg */ + count->argKind = akAddFeature(count->argKind, akCheck(arg->argKind, akbSend) ? akbSendRcv : akbReturnRcv); + count->argVarName = (char *)0; + } + else { + /* + * Count arguments have to be present on the message body (NDR encoded) + * akbVariable has to be turned down, has it foul the algorithm + * for detecting the in-line variable sized arrays + */ + count->argKind |= akAddFeature(akbUserArg|akbServerArg, (arg->argKind) & ~akeBITS); + count->argKind = akRemFeature(count->argKind, akbVariable|akbVarNeeded); + if (IS_VARIABLE_SIZED_UNTYPED(arg->argType)) + /* + * Count arguments for the above types are explicitly declared + * BEFORE the variable (with those bits, they would come afterwards) + */ + count->argKind = akRemFeature(count->argKind, akbRequest|akbReply); + } +} + +static void +rtAddCountInOutArg(argument_t *arg) +{ + argument_t *count; + + /* + * The user sees a single count variable. However, to get the + * count passed from user to server for variable-sized inline OUT + * arrays, we need two count arguments internally. This is + * because the count value lives in different message fields (and + * is scaled differently) in the request and reply messages. + * + * The two variables have the same name to simplify code generation. + * + * This variable has a null argParent field because it has akbRequest. + * For example, see rtCheckVariable. + */ + + count = argAlloc(); + count->argName = strconcat(arg->argName, "Cnt"); + count->argType = itMakeCountType(); + count->argParent = argNULL; + count->argNext = arg->argNext; + arg->argNext = count; + (count->argCInOut = arg->argCount)->argCInOut = count; + count->argKind = akCountInOut; +} + +static void +rtAddPolyArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + argument_t *poly; + arg_kind_t akbsend, akbreturn; + + poly = argAlloc(); + poly->argName = strconcat(arg->argName, "Poly"); + poly->argType = itMakePolyType(); + poly->argParent = arg; + poly->argNext = arg->argNext; + arg->argNext = poly; + arg->argPoly = poly; + + /* + * akbsend is bits added if the arg is In; + * akbreturn is bits added if the arg is Out. + * The mysterious business with KernelServer subsystems: + * when packing Out arguments, they use OutNames instead + * of InNames, and the OutName determines if they are poly-in + * as well as poly-out. + */ + + akbsend = akbSend; + akbreturn = akbReturn; + + if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) { + akbsend |= akbUserArg|akbSendSnd; + if (!IsKernelServer) + akbreturn |= akbServerArg|akbReturnSnd; + } + if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) { + akbsend |= akbServerArg|akbSendRcv; + akbreturn |= akbUserArg|akbReturnRcv; + if (IsKernelServer) + akbreturn |= akbServerArg|akbReturnSnd; + } + + poly->argKind = akPoly; + if (akCheck(arg->argKind, akbSend)) + poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbsend)); + if (akCheck(arg->argKind, akbReturn)) + poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbreturn)); +} + +static void +rtAddDeallocArg(argument_t *arg) +{ + argument_t *dealloc; + + dealloc = argAlloc(); + dealloc->argName = strconcat(arg->argName, "Dealloc"); + dealloc->argType = itMakeDeallocType(); + dealloc->argParent = arg; + dealloc->argNext = arg->argNext; + arg->argNext = dealloc; + arg->argDealloc = dealloc; + + /* + * Dealloc flag can only be associated to KPDs. + */ + + dealloc->argKind = akeDealloc; + if (akCheck(arg->argKind, akbSend)) + dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbUserArg|akbSend|akbSendSnd)); + if (akCheck(arg->argKind, akbReturn)) { + dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbServerArg|akbReturn|akbReturnSnd)); + dealloc->argByReferenceServer = TRUE; + } +} + +static void +rtCheckRoutineArgs(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + rtDefaultArgKind(rt, arg); + rtCheckRoutineArg(rt, arg); + + /* need to set argTTName before adding implicit args */ + rtSetArgDefaults(rt, arg); + + /* the arg may not have a type (if there was some error in parsing it), + in which case we don't want to do these steps. */ + + if (it != itNULL) { + arg->argFlags = rtProcessDeallocFlag(it, arg->argFlags, arg->argKind, &arg->argDeallocate, arg->argVarName); + arg->argFlags = rtProcessCountInOutFlag(it, arg->argFlags, arg->argKind, &arg->argCountInOut, arg->argVarName); + rtProcessSameCountFlag(arg); + arg->argFlags = rtProcessPhysicalCopyFlag(it, arg->argFlags, arg->argKind, arg->argVarName); + rtProcessRetCodeFlag(arg); + arg->argFlags = rtProcessOverwriteFlag(it, arg->argFlags, arg->argKind, arg->argVarName); + rtAugmentArgKind(arg); + + /* args added here will get processed in later iterations */ + /* order of args is 'arg poly countinout count dealloc' */ + + if (arg->argDeallocate == d_MAYBE) + rtAddDeallocArg(arg); + if (it->itVarArray || (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray)) + rtAddCountArg(arg); + if (arg->argCountInOut) + rtAddCountInOutArg(arg); + if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) + rtAddPolyArg(arg); + /* + * Detects whether the arg has to become part of the + * Kernel Processed Data section; if yes, define the proper + * itUserKPDType, itServerKPDType + */ + rtDetectKPDArg(arg); + } + } +} + +boolean_t +rtCheckTrailerType(argument_t *arg) +{ + if (akIdent(arg->argKind) == akeSecToken || + akIdent(arg->argKind) == akeAuditToken || + akIdent(arg->argKind) == akeContextToken ) + itCheckTokenType(arg->argVarName, arg->argType); + + if (akIdent(arg->argKind) == akeMsgSeqno) + itCheckIntType(arg->argVarName, arg->argType); + /* + * if the built-in are not used, we cannot match + * the type/size of the desciption provided by the user + * with the one defined in message.h. + */ + + return TRUE; +} + +static void +rtCheckArgTypes(routine_t *rt) +{ + if (rt->rtRequestPort == argNULL) + error("%s %s doesn't have a server port argument", rtRoutineKindToStr(rt->rtKind), rt->rtName); + + if ((rt->rtRequestPort != argNULL) && + (rt->rtRequestPort->argType != itNULL)) + itCheckRequestPortType(rt->rtRequestPort->argName, rt->rtRequestPort->argType); + + if ((rt->rtReplyPort != argNULL) && + (rt->rtReplyPort->argType != itNULL)) + itCheckReplyPortType(rt->rtReplyPort->argName, rt->rtReplyPort->argType); + + if ((rt->rtWaitTime != argNULL) && + (rt->rtWaitTime->argType != itNULL)) + itCheckIntType(rt->rtWaitTime->argName, rt->rtWaitTime->argType); + + if ((rt->rtMsgOption != argNULL) && + (rt->rtMsgOption->argType != itNULL)) + itCheckIntType(rt->rtMsgOption->argName, rt->rtMsgOption->argType); + + if ((IsKernelServer && rt->rtServerImpl) || + (IsKernelUser && rt->rtUserImpl)) + fatal("Implicit data is not supported in the KernelUser and KernelServer modes"); + /* rtCheckTrailerType will hit a fatal() if something goes wrong */ + if (rt->rtServerImpl) + rtCheckMaskFunction(rt->rtArgs, akbServerImplicit, rtCheckTrailerType); + if (rt->rtUserImpl) + rtCheckMaskFunction(rt->rtArgs, akbUserImplicit, rtCheckTrailerType); +} + +/* + * Check for arguments which are missing seemingly needed functions. + * We make this check here instead of in itCheckDecl, because here + * we can take into account what kind of argument the type is + * being used with. + * + * These are warnings, not hard errors, because mig will generate + * reasonable code in any case. The generated code will work fine + * if the ServerType and TransType are really the same, even though + * they have different names. + */ + +static void +rtCheckArgTrans(routine_t *rt) +{ + argument_t *arg; + + /* the arg may not have a type (if there was some error in parsing it) */ + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if ((it != itNULL) && !streql(it->itServerType, it->itTransType)) { + if (akCheck(arg->argKind, akbSendRcv) && (it->itInTrans == strNULL)) + warn("%s: argument has no in-translation function", arg->argName); + + if (akCheck(arg->argKind, akbReturnSnd) && (it->itOutTrans == strNULL)) + warn("%s: argument has no out-translation function", arg->argName); + } + } +} + +/* + * Adds an implicit return-code argument. It exists in the reply message, + * where it is the first piece of data (After the NDR format label).. + */ + +static void +rtAddRetCode(routine_t *rt) +{ + argument_t *arg = argAlloc(); + + arg->argName = "RetCode"; + arg->argType = itRetCodeType; + arg->argKind = akRetCode; + rt->rtRetCode = arg; + + arg->argNext = rt->rtArgs; + rt->rtArgs = arg; +} + +/* + * Process the Return Code. + * The MIG protocol says that RetCode != 0 are only sent through + * mig_reply_error_t structures. Therefore, there is no need + * for reserving a RetCode in a complex Reply message. + */ +static void +rtProcessRetCode(routine_t *rt) +{ + if (!rt->rtOneWay && !rt->rtSimpleReply) { + argument_t *arg = rt->rtRetCode; + + arg->argKind = akRemFeature(arg->argKind, akbReply); + /* we want the RetCode to be a local variable instead */ + arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); + } + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + argument_t *arg = rt->rtRetCArg; + + arg->argKind = akeRetCode|akbUserArg|akbServerArg|akbSendRcv; + } +} + +/* + * Adds an implicit NDR argument. It exists in the reply message, + * where it is the first piece of data. + */ + +static void +rtAddNdrCode(routine_t *rt) +{ + argument_t *arg = argAlloc(); + + arg->argName = "NDR_record"; + arg->argType = itNdrCodeType; + arg->argKind = akeNdrCode; + rt->rtNdrCode = arg; + + /* add at beginning, so ndr-code is first in the reply message */ + arg->argNext = rt->rtArgs; + rt->rtArgs = arg; +} + +/* + * Process the NDR Code. + * We stick a NDR format label iff there is untyped data + */ +static void +rtProcessNdrCode(routine_t *rt) +{ + argument_t *ndr = rt->rtNdrCode; + argument_t *arg; + boolean_t found; + + /* akbSendSnd|akbSendBody initialize the NDR format label */ +#define ndr_send akbRequest|akbSend|akbSendSnd|akbSendBody + /* akbReplyInit initializes the NDR format label */ +#define ndr_rcv akbReply|akbReplyInit|akbReturn|akbReturnBody + + ndr->argKind = akAddFeature(ndr->argKind, ndr_send|ndr_rcv); + + for (found = FALSE, arg = ndr->argNext; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbSendRcv|akbSendBody) && + !akCheck(arg->argKind, akbServerImplicit) && !arg->argType->itPortType && + (!arg->argParent || akIdent(arg->argKind) == akeCount || + akIdent(arg->argKind) == akeCountInOut)) { + arg->argKind = akAddFeature(arg->argKind, akbSendNdr); + found = TRUE; + } + if (!found) + ndr->argKind = akRemFeature(ndr->argKind, ndr_send); + + found = FALSE; + if (!rt->rtOneWay) + for (arg = ndr->argNext; arg != argNULL; arg = arg->argNext) + if ((arg == rt->rtRetCode && akCheck(arg->argKind, akbReply)) || + (arg != rt->rtRetCode && + akCheck(arg->argKind, akbReturnRcv|akbReturnBody) && + !akCheck(arg->argKind, akbUserImplicit) && !arg->argType->itPortType && + (!arg->argParent || akIdent(arg->argKind) == akeCount || + akIdent(arg->argKind) == akeCountInOut))) { + arg->argKind = akAddFeature(arg->argKind, akbReturnNdr); + found = TRUE; + } + if (!found && !akCheck(rt->rtRetCode->argKind, akbReply)) + ndr->argKind = akRemFeature(ndr->argKind, ndr_rcv); +} + +/* + * Adds a dummy WaitTime argument to the function. + * This argument doesn't show up in any C argument lists; + * it implements the global WaitTime statement. + */ + +static void +rtAddWaitTime(routine_t *rt, identifier_t name, arg_kind_t kind) +{ + argument_t *arg = argAlloc(); + argument_t **loc; + + arg->argName = "dummy WaitTime arg"; + arg->argVarName = name; + arg->argType = itWaitTimeType; + arg->argKind = kind; + rt->rtWaitTime = arg; + + /* add wait-time after msg-option, if possible */ + + if (rt->rtMsgOption != argNULL) + loc = &rt->rtMsgOption->argNext; + else + loc = &rt->rtArgs; + + arg->argNext = *loc; + *loc = arg; + + rtSetArgDefaults(rt, arg); +} + +/* + * Adds a dummy MsgOption argument to the function. + * This argument doesn't show up in any C argument lists; + * it implements the global MsgOption statement. + */ + +static void +rtAddMsgOption(routine_t *rt, identifier_t name) +{ + argument_t *arg = argAlloc(); + argument_t **loc; + + arg->argName = "dummy MsgOption arg"; + arg->argVarName = name; + arg->argType = itMsgOptionType; + arg->argKind = akeMsgOption; + rt->rtMsgOption = arg; + + /* add msg-option after msg-seqno */ + + loc = &rt->rtArgs; + + arg->argNext = *loc; + *loc = arg; + + rtSetArgDefaults(rt, arg); +} + +/* + * Process the MsgOption Code. + * We must add the information to post a receive with the right + * Trailer options. + */ +static void +rtProcessMsgOption(routine_t *rt) +{ + argument_t *msgop = rt->rtMsgOption; + argument_t *arg; + boolean_t sectoken = FALSE; + boolean_t audittoken = FALSE; + boolean_t contexttoken = FALSE; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, akbReturn|akbUserImplicit)) { + if (akIdent(arg->argKind) == akeSecToken) + sectoken = TRUE; + else if (akIdent(arg->argKind) == akeAuditToken) + audittoken = TRUE; + else if (akIdent(arg->argKind) == akeContextToken) + contexttoken = TRUE; + } + + if (contexttoken == TRUE) + msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX)"); + else if (audittoken == TRUE) + msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)"); + else if (sectoken == TRUE) + msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)"); + /* other implicit data received by the user will be handled here */ +} + +static void +rtProcessUseSpecialReplyPort(routine_t *rt) +{ + if (IsKernelUser || IsKernelServer) { + fatal("UseSpecialReplyPort option cannot be used with KernelUser / KernelServer\n"); + } + rt->rtMsgOption->argVarName = strconcat(rt->rtMsgOption->argVarName, "|__MigSpecialReplyPortMsgOption"); +} + +/* + * Adds a dummy reply port argument to the function. + */ + +static void +rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type) +{ + argument_t *arg = argAlloc(); + argument_t **loc; + + arg->argName = "dummy ReplyPort arg"; + arg->argVarName = "dummy ReplyPort arg"; + arg->argType = type; + arg->argKind = akeReplyPort; + rt->rtReplyPort = arg; + + /* add the reply port after the request port */ + + if (rt->rtRequestPort != argNULL) + loc = &rt->rtRequestPort->argNext; + else + loc = &rt->rtArgs; + + arg->argNext = *loc; + *loc = arg; + + rtSetArgDefaults(rt, arg); +} + + +/* + * At least one overwrite keyword has been detected: + * we tag all the OOL entries (ports + data) with + * akbOverwrite which will tell us that we have to + * fill a KPD entry in the message-template + */ +static void +rtCheckOverwrite(routine_t *rt) +{ + argument_t *arg; + int howmany = rt->rtOverwrite; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (akCheck(arg->argKind, akbReturnKPD) && !it->itInLine) { + /* among OUT args, we want OOL, OOL ports and MigInLine */ + arg->argKind = akAddFeature(arg->argKind, akbOverwrite); + if (arg->argFlags & flOverwrite) + howmany--; + if (!howmany) + return; + } + } +} + +/* + * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos, + * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments + * that need it because of variable-sized inline considerations. + * + * argRequestPos and argReplyPos get -1 if the value shouldn't be used. + */ +static void +rtCheckVariable(routine_t *rt) +{ + argument_t *arg; + int NumRequestVar = 0; + int NumReplyVar = 0; + int MaxRequestPos = 0; + int MaxReplyPos = 0; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + argument_t *parent = arg->argParent; + + /* + * We skip KPDs. We have to make sure that the KPDs count + * present in the message body follow the RequestPos/ReplyPos logic + * The rest of the parameters are defaulted to have + * Arg{Request, Reply}Pos = 0 + */ + if (parent == argNULL || akCheck(parent->argKind, akbSendKPD|akbReturnKPD)) { + if (akCheckAll(arg->argKind, akbSend|akbSendBody)) { + arg->argRequestPos = NumRequestVar; + MaxRequestPos = NumRequestVar; + if (akCheck(arg->argKind, akbVariable)) + NumRequestVar++; + } + if (akCheckAll(arg->argKind, akbReturn|akbReturnBody)) { + arg->argReplyPos = NumReplyVar; + MaxReplyPos = NumReplyVar; + if (akCheck(arg->argKind, akbVariable)) + NumReplyVar++; + } + } + else { + arg->argRequestPos = parent->argRequestPos; + arg->argReplyPos = parent->argReplyPos; + } + /* + printf("Var %s Kind %x RequestPos %d\n", arg->argVarName, arg->argKind, arg->argRequestPos); + printf("* Var %s Kind %x ReplyPos %d\n", arg->argVarName, arg->argKind, arg->argReplyPos); + */ + + /* Out variables that follow a variable-sized field + need VarNeeded or ReplyCopy; they can't be stored + directly into the reply message. */ + + if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody) && + !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) && + (arg->argReplyPos > 0)) + arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); + } + + rt->rtNumRequestVar = NumRequestVar; + rt->rtNumReplyVar = NumReplyVar; + rt->rtMaxRequestPos = MaxRequestPos; + rt->rtMaxReplyPos = MaxReplyPos; +} + +/* + * Adds akbDestroy where needed. + */ + +static void +rtCheckDestroy(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if(akCheck(arg->argKind, akbSendRcv) && + !akCheck(arg->argKind, akbReturnSnd) && + (it->itDestructor != strNULL || IS_MIG_INLINE_EMUL(it))) { + arg->argKind = akAddFeature(arg->argKind, akbDestroy); + } + if (argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && + arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR && + (arg->argFlags & flAuto)) + arg->argKind = akAddFeature(arg->argKind, akbDestroy); + } +} + +/* + * Sets ByReferenceUser and ByReferenceServer. + */ + +static void +rtAddByReference(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (akCheck(arg->argKind, akbReturnRcv) && it->itStruct) { + arg->argByReferenceUser = TRUE; + + /* + * A CountInOut arg itself is not akbReturnRcv, + * so we need to set argByReferenceUser specially. + */ + + if (arg->argCInOut != argNULL) + arg->argCInOut->argByReferenceUser = TRUE; + } + + if ((akCheck(arg->argKind, akbReturnSnd) || + (akCheck(arg->argKind, akbServerImplicit) && + akCheck(arg->argKind, akbReturnRcv) && + akCheck(arg->argKind, akbSendRcv))) + && it->itStruct) { + arg->argByReferenceServer = TRUE; + } + } +} + +/* + * This procedure can be executed only when all the akb* and ake* have + * been set properly (when rtAddCountArg is executed, akbVarNeeded + * might not be set yet - see rtCheckVariable) + */ +void +rtAddSameCount(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (arg->argFlags & flSameCount) { + ipc_type_t *it = arg->argType; + argument_t *tmp_count; + argument_t *my_count = arg->argCount; + argument_t *ref_count = arg->argSameCount->argCount; + + tmp_count = argAlloc(); + *tmp_count = *ref_count; + /* + * if our count is a akbVarNeeded, we need to copy this + * attribute to the master count! + */ + tmp_count->argKind = akeSameCount; + ref_count->argKind = akAddFeature(ref_count->argKind, akCheck(my_count->argKind, akbVarNeeded)); + tmp_count->argKind = akAddFeature(tmp_count->argKind, akCheck(my_count->argKind, akbVarNeeded)); + tmp_count->argNext = my_count->argNext; + tmp_count->argMultiplier = my_count->argMultiplier; + tmp_count->argType = my_count->argType; + tmp_count->argParent = arg; + /* we don't need more */ + arg->argCount = tmp_count; + arg->argNext = tmp_count; + /* for these args, Cnt is not akbRequest, and therefore size is embedded */ + if (IS_VARIABLE_SIZED_UNTYPED(it)) + it->itMinTypeSize = 0; + tmp_count->argType->itMinTypeSize = 0; + tmp_count->argType->itTypeSize = 0; + } +} + +void +rtCheckRoutine(routine_t *rt) +{ + /* Initialize random fields. */ + + rt->rtErrorName = ErrorProc; + rt->rtOneWay = (rt->rtKind == rkSimpleRoutine); + rt->rtServerName = strconcat(ServerPrefix, rt->rtName); + rt->rtUserName = strconcat(UserPrefix, rt->rtName); + rt->rtUseSpecialReplyPort = UseSpecialReplyPort && !rt->rtOneWay; + rt->rtConsumeOnSendError = ConsumeOnSendError; + + /* Add implicit arguments. */ + + rtAddRetCode(rt); + rtAddNdrCode(rt); + + /* Check out the arguments and their types. Add count, poly + implicit args. Any arguments added after rtCheckRoutineArgs + should have rtSetArgDefaults called on them. */ + + rtCheckRoutineArgs(rt); + + /* Add dummy WaitTime and MsgOption arguments, if the routine + doesn't have its own args and the user specified global values. */ + + if (rt->rtReplyPort == argNULL) { + if (rt->rtOneWay) + rtAddDummyReplyPort(rt, itZeroReplyPortType); + else + rtAddDummyReplyPort(rt, itRealReplyPortType); + } else if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) { + /* If an explicit ReplyPort is used, we can't assume it will be the SRP */ + rt->rtUseSpecialReplyPort = FALSE; + } + if (rt->rtMsgOption == argNULL) { + if (MsgOption == strNULL) + rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE"); + else + rtAddMsgOption(rt, MsgOption); + } + if (rt->rtWaitTime == argNULL) { + if (WaitTime != strNULL) + rtAddWaitTime(rt, WaitTime, akeWaitTime); + else if (SendTime != strNULL) + rtAddWaitTime(rt, SendTime, akeSendTime); + } + if (rt->rtWaitTime && rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) { + warn("%s %s specifies a SendTime/WaitTime which may leak resources, " + "adopt \"ConsumeOnSendError Timeout\"", + rtRoutineKindToStr(rt->rtKind), rt->rtName); + } + + + /* Now that all the arguments are in place, do more checking. */ + + rtCheckArgTypes(rt); + rtCheckArgTrans(rt); + + if (rt->rtOneWay) { + if (rtCheckMask(rt->rtArgs, akbReturn) || rt->rtUserImpl) + error("%s %s has OUT argument", rtRoutineKindToStr(rt->rtKind), rt->rtName); + } + + /* If there were any errors, don't bother calculating more info + that is only used in code generation anyway. Therefore, + the following functions don't have to worry about null types. */ + + if (mig_errors > 0) + fatal("%d errors found. Abort.\n", mig_errors); + + rt->rtServerImpl = rtCountMask(rt->rtArgs, akbServerImplicit); + rt->rtUserImpl = rtCountMask(rt->rtArgs, akbUserImplicit); + /* + * ASSUMPTION: + * kernel cannot change a message from simple to complex, + * therefore SimpleSendReply and SimpleRcvReply become SimpleReply + */ + rtCheckSimple(rt->rtArgs, akbRequest, &rt->rtSimpleRequest); + rtCheckSimple(rt->rtArgs, akbReply, &rt->rtSimpleReply); + + rt->rtRequestKPDs = rtCountKPDs(rt->rtArgs, akbSendKPD); + rt->rtReplyKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD); + /* + * Determine how many overwrite parameters we have: + * # of Overwrite args -> rt->rtOverwrite + * flOverwrite -> the arg has to be overwritten + * akbOverwrite -> the arg has to be declared in the message-template + * (only as a placeholder if !flOverwrite). + */ + if ((rt->rtOverwrite = rtCountFlags(rt->rtArgs, flOverwrite))) { + rtCheckOverwrite(rt); + rt->rtOverwriteKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD|akbOverwrite); + if (IsKernelUser) + fatal("Overwrite option(s) do not match with the KernelUser personality\n"); + } + + rtCheckFit(rt, akbRequest, &rt->rtRequestFits, &rt->rtRequestUsedLimit, &rt->rtRequestSizeKnown); + rtCheckFit(rt, akbReply, &rt->rtReplyFits, &rt->rtReplyUsedLimit, &rt->rtReplySizeKnown); + + rtCheckVariable(rt); + rtCheckDestroy(rt); + rtAddByReference(rt); + rtSuffixExtArg(rt->rtArgs); + rtAddSameCount(rt); + rtProcessRetCode(rt); + rtProcessNdrCode(rt); + if (rt->rtUserImpl) + rtProcessMsgOption(rt); + if (rt->rtUseSpecialReplyPort) + rtProcessUseSpecialReplyPort(rt); + + rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd); + + if (UseEventLogger) + /* some more info's are needed for Event logging/Stats */ + rtFindHowMany(rt); +} + +void +rtMinRequestSize(FILE *file, routine_t *rt, char *str) +{ + fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); + rtSizeDelta(file, akbRequest, rt); + fprintf(file, ")"); +} + +void +rtMinReplySize(FILE *file, routine_t *rt, char *str) +{ + fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); + rtSizeDelta(file, akbReply, rt); + fprintf(file, ")"); +} + +static void +rtSizeDelta(FILE *file, u_int mask, routine_t *rt) +{ + argument_t *arg; + u_int min_size = sizeof(mach_msg_header_t); + u_int max_size; + boolean_t output = FALSE; + + if (!rt->rtSimpleRequest) + machine_alignment(min_size, sizeof(mach_msg_body_t)); + max_size = min_size; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, mask)) { + ipc_type_t *it = arg->argType; + + machine_alignment(min_size, it->itMinTypeSize); + machine_alignment(max_size, it->itMinTypeSize); + + if (IS_VARIABLE_SIZED_UNTYPED(it)) { + machine_alignment(max_size, it->itTypeSize); + max_size += it->itPadSize; + } + if (IS_OPTIONAL_NATIVE(it)) { + if (output) + fprintf(file, " + "); + else { + output = TRUE; + fprintf(file, " - ("); + } + fprintf(file, "_WALIGNSZ_(%s)", it->itUserType); + } + } + if (min_size != max_size) { + if (output) + fprintf(file, " + "); + else + fprintf(file, " - "); + fprintf(file, "%d", max_size - min_size); + } + if (output) + fprintf(file, ")"); +} + -- cgit v1.2.3-56-ge451