MIG routine model
Internal representation of a .defs routine/simpleroutine and its arguments, used to drive user- and server-side code generation.
rtAlloc source
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; }
argAlloc source
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, … more in source
rtMakeRoutine source
routine_t * rtMakeRoutine(identifier_t name, argument_t *args) { routine_t *rt = rtAlloc(); rt->rtName = name; rt->rtKind = rkRoutine; rt->rtArgs = args; return rt; }
rtMakeSimpleRoutine source
routine_t * rtMakeSimpleRoutine(identifier_t name, argument_t *args) { routine_t *rt = rtAlloc(); rt->rtName = name; rt->rtKind = rkSimpleRoutine; rt->rtArgs = args; return rt; }
rtRoutineKindToStr source
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; } }
rtPrintArg source
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"); … more in source
rtPrintRoutine source
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"); }
rtCheckSimple source
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; }
rtCheckFit source
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; } … more in source
rtFindHowMany source
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; … more in source
rtCheckMask source
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; }
rtCheckMaskFunction source
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; }
rtCountKPDs source
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; }
rtCountFlags source
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; }
rtCountArgDescriptors source
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; }
rtCountMask source
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; }
rtDefaultArgKind source
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; }
rtProcessDeallocFlag source
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; … more in source
rtProcessSameCountFlag source
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; … more in source
rtProcessCountInOutFlag source
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; }
rtProcessPhysicalCopyFlag source
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; }
rtProcessRetCodeFlag source
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; } }
rtProcessOverwriteFlag source
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; }
rtDetectKPDArg source
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; } }
rtAugmentArgKind source
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 */ … more in source
rtSuffixExtArg source
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 */ /* … more in source
rtCheckRoutineArg source
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); … more in source
rtSetArgDefaults source
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: … more in source
rtAddCountArg source
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; … more in source
rtAddCountInOutArg source
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; }
rtAddPolyArg source
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) … more in source
rtAddDeallocArg source
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; } }
rtCheckRoutineArgs source
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) … more in source
rtCheckTrailerType source
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; }
rtCheckArgTypes source
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); … more in source
rtCheckArgTrans source
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); } } }
rtAddRetCode source
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; }
rtProcessRetCode source
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; } }
rtAddNdrCode source
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; }
rtProcessNdrCode source
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 && … more in source
rtAddWaitTime source
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); }
rtAddMsgOption source
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); }
rtProcessMsgOption source
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 */ }
rtProcessUseSpecialReplyPort source
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"); }
rtAddDummyReplyPort source
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); }
rtCheckOverwrite source
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; } } }
rtCheckVariable source
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++; … more in source
rtCheckDestroy source
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); } }
rtAddByReference source
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; if (IsKernelServer && IS_KERN_PROC_DATA(it)) { /* because of PAC we can't take the address of a signed pointer */ arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); } … more in source
rtAddSameCount source
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)) … more in source
rtAddArgSegment source
static void rtAddArgSegment(routine_t *rt) { argument_t *arg; for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { ipc_type_t *it = arg->argType; if (!UseMachMsg2) { char *segIn = malloc(16); if (!segIn) fatal("Unable to allocate argInSegment"); sprintf(segIn, "In%dP", arg->argRequestPos); arg->argInSegment = segIn; arg->argOutSegment = "OutP"; } else if (IS_KERN_PROC_DATA(it) || (akIdent(arg->argKind) == akePoly && IS_KERN_PROC_DATA(arg->argParent->argType))) { arg->argInSegment = "InKP"; arg->argOutSegment = "OutKP"; } else { char *segIn = malloc(16); if (!segIn) fatal("Unable to allocate argInSegment"); sprintf(segIn, "In%dUP", arg->argRequestPos); arg->argInSegment = segIn; arg->argOutSegment = "OutUP"; } } }
rtCheckRoutine source
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 … more in source
rtMinRequestSize source
void rtMinRequestSize(FILE *file, routine_t *rt, char *str) { fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); rtSizeDelta(file, akbRequest, rt); fprintf(file, ")"); }
rtMinReplySize source
void rtMinReplySize(FILE *file, routine_t *rt, char *str) { fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); rtSizeDelta(file, akbReply, rt); fprintf(file, ")"); }
rtSizeDelta source
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); … more in source