MIG type marshaling
How MIG types (from the .defs 'type' declarations) are described and marshaled into and out of messages, including port rights, arrays, and counted buffers.
itLookUp source
Searches for a named type. We use a simple
self-organizing linked list.
ipc_type_t * itLookUp(identifier_t name) { ipc_type_t *it, **last; for (it = *(last = &list); it != itNULL; it = *(last = &it->itNext)) if (streql(name, it->itName)) { /* move this type to the front of the list */ *last = it->itNext; it->itNext = list; list = it; return it; } return itNULL; }
itInsert source
Enters a new name-type association into
our self-organizing linked list.
void itInsert(identifier_t name, ipc_type_t *it) { it->itName = name; it->itNext = list; list = it; }
itAlloc source
static ipc_type_t * itAlloc(void) { static ipc_type_t prototype = { strNULL, /* identifier_t itName */ 0, /* ipc_type_t *itNext */ 0, /* u_int itTypeSize */ 0, /* u_int itPadSize */ 0, /* u_int itMinTypeSize */ 0, /* u_int itInName */ 0, /* u_int itOutName */ 0, /* u_int itSize */ 1, /* u_int itNumber */ 0, /* u_int itKPD_Number */ TRUE, /* boolean_t itInLine */ FALSE, /* boolean_t itMigInLine */ FALSE, /* boolean_t itPortType */ strNULL, /* string_t itInNameStr */ strNULL, /* string_t itOutNameStr */ TRUE, /* boolean_t itStruct */ FALSE, /* boolean_t itString */ FALSE, /* boolean_t itVarArray */ FALSE, /* boolean_t itNoOptArray */ FALSE, /* boolean_t itNative */ FALSE, /* boolean_t itNativePointer */ itNULL, /* ipc_type_t *itElement */ strNULL, /* identifier_t itUserType */ strNULL, /* identifier_t itServerType */ strNULL, /* identifier_t itTransType */ … more in source
itNameToString source
Convert an IPC type-name into a string.
static char * itNameToString(u_int name) { char buffer[100]; (void) sprintf(buffer, "%u", name); return strmake(buffer); }
itCalculateSizeInfo source
Calculate itTypeSize, itPadSize, itMinTypeSize
Every type needs this info; it is recalculated
when itInLine, itNumber, or itSize changes.
static void itCalculateSizeInfo(ipc_type_t *it) { if (!IS_KERN_PROC_DATA(it)) { u_int bytes = (it->itNumber * it->itSize + 7) / 8; u_int padding = machine_padding(bytes); it->itTypeSize = bytes; it->itPadSize = padding; if (IS_VARIABLE_SIZED_UNTYPED(it)) { /* * for these arrays, the argCount is not a akbRequest|akbReply, * therefore we need to account here for the space of the count * (itMinTypeSize is used only in rtFindSize) */ it->itMinTypeSize = sizeof (mach_msg_type_number_t); /* * NDR encoded VarString carry the extra offset 4-bytes fields * for MIG, it should be always 0; */ if (it->itString) it->itMinTypeSize += sizeof (mach_msg_type_number_t); } else it->itMinTypeSize = bytes + padding; } else { /* * 1) ports 2) OOL 3) ports OOL … more in source
itCalculateNameInfo source
Fill in default values for some fields used in code generation:
itInNameStr, itOutNameStr, itUserType, itServerType, itTransType
Every argument's type should have these values filled in.
static void itCalculateNameInfo(ipc_type_t *it) { if (it->itInNameStr == strNULL) it->itInNameStr = strmake(itNameToString(it->itInName)); if (it->itOutNameStr == strNULL) it->itOutNameStr = strmake(itNameToString(it->itOutName)); if (it->itUserType == strNULL) it->itUserType = it->itName; if (it->itServerType == strNULL) it->itServerType = it->itName; #if 0 /* * KernelServer and KernelUser interfaces get special treatment here. * On the kernel side of the interface, ports are really internal * port pointers (ipc_port_t), not port names (mach_port_t). * At this point, we don't know if the argument is in or out, * so we don't know if we should look at itInName or itOutName. * Looking at both should be OK. * * This is definitely a hack, but I think it is cleaner than * mucking with type declarations throughout the kernel .def files, * hand-conditionalizing on KERNEL_SERVER and KERNEL_USER. */ if (IsKernelServer && streql(it->itServerType, "mach_port_t") && (((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) && (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) || … more in source
itCheckDecl source
****************************************************
Checks for non-implemented types, conflicting type
flags and whether the long or short form of msg type
descriptor is appropriate. Called after each type statement
is parsed.
****************************************************
static void itCheckDecl(identifier_t name, ipc_type_t *it) { it->itName = name; itCalculateNameInfo(it); /* do a bit of error checking, mostly necessary because of limitations in Mig */ if (it->itVarArray) { if ((it->itInTrans != strNULL) || (it->itOutTrans != strNULL)) error("%s: can't translate variable-sized arrays", name); if (it->itDestructor != strNULL) error("%s: can't destroy variable-sized array", name); } }
itPrintTrans source
Pretty-prints translation/destruction/type information.
static void itPrintTrans(ipc_type_t *it) { if (!streql(it->itName, it->itUserType)) printf("\tCUserType:\t%s\n", it->itUserType); if (!streql(it->itName, it->itServerType)) printf("\tCServerType:\t%s\n", it->itServerType); if (it->itInTrans != strNULL) printf("\tInTran:\t\t%s %s(%s)\n", it->itTransType, it->itInTrans, it->itServerType); if (it->itOutTrans != strNULL) printf("\tOutTran:\t%s %s(%s)\n", it->itServerType, it->itOutTrans, it->itTransType); if (it->itDestructor != strNULL) printf("\tDestructor:\t%s(%s)\n", it->itDestructor, it->itTransType); }
itPrintDecl source
Pretty-prints type declarations.
static void itPrintDecl(identifier_t name, ipc_type_t *it) { printf("Type %s = ", name); if (!it->itInLine) printf("^ "); if (it->itVarArray) if (it->itNumber == 0 || it->itMigInLine) printf("array [] of "); else printf("array [*:%d] of ", it->itNumber); else if (it->itStruct && ((it->itNumber != 1) || (it->itInName == MACH_MSG_TYPE_STRING_C))) printf("struct [%d] of ", it->itNumber); else if (it->itNumber != 1) printf("array [%d] of ", it->itNumber); if (streql(it->itInNameStr, it->itOutNameStr)) printf("(%s,", it->itInNameStr); else printf("(%s|%s", it->itInNameStr, it->itOutNameStr); printf(" %d)\n", it->itSize); itPrintTrans(it); printf("\n"); }
itTypeDecl source
Handles named type-specs, which can occur in type
declarations or in argument lists. For example,
type foo = type-spec; // itInsert will get called later
routine foo(arg : bar = type-spec); // itInsert won't get called
void itTypeDecl(identifier_t name, ipc_type_t *it) { itCheckDecl(name, it); if (BeVerbose) itPrintDecl(name, it); }
itShortDecl source
Handles declarations like
type new = name;
type new = inname|outname;
ipc_type_t * itShortDecl(u_int inname, string_t instr, u_int outname, string_t outstr, u_int defsize) { ipc_type_t *it; if (defsize == 0) error("must use full IPC type decl"); it = itAlloc(); it->itInName = inname; it->itInNameStr = instr; it->itOutName = outname; it->itOutNameStr = outstr; it->itSize = defsize; if (inname == MACH_MSG_TYPE_STRING_C) { it->itStruct = FALSE; it->itString = TRUE; } /* * I check only inname, because outname * has to be a port as well (polymorphic types * are now restricted to port rights) */ if (MACH_MSG_TYPE_PORT_ANY(inname) || inname == MACH_MSG_TYPE_POLYMORPHIC) { it->itPortType = TRUE; it->itKPD_Number = 1; } … more in source
itCopyType source
static ipc_type_t * itCopyType(ipc_type_t *old) { ipc_type_t *new = itAlloc(); *new = *old; new->itName = strNULL; new->itNext = itNULL; new->itElement = old; /* size info still valid */ return new; }
itResetType source
A call to itCopyType is almost always followed with itResetType.
The exception is itPrevDecl. Also called before adding any new
translation/destruction/type info (see parser.y).
type new = old; // new doesn't get old's info
type new = array[*:10] of old;
// new doesn't get old's info, but new->itElement does
type new = array[*:10] of struct[3] of old;
// new and new->itElement don't get old's info
ipc_type_t * itResetType(ipc_type_t *old) { /* reset all special translation/destruction/type info */ old->itInTrans = strNULL; old->itOutTrans = strNULL; old->itDestructor = strNULL; old->itUserType = strNULL; old->itServerType = strNULL; old->itTransType = strNULL; return old; }
itPrevDecl source
Handles the declaration
type new = old;
ipc_type_t * itPrevDecl(identifier_t name) { ipc_type_t *old; old = itLookUp(name); if (old == itNULL) { error("type '%s' not defined", name); return itAlloc(); } else return itCopyType(old); }
itVarArrayDecl source
Handles the declarations
type new = array[] of old; // number is oo
type new = array[*] of old; // number is oo
type new = array[*:number] of old;
ipc_type_t * itVarArrayDecl(u_int number, ipc_type_t *old) { ipc_type_t *it = itResetType(itCopyType(old)); if (!it->itInLine) { /* already an initialized KPD */ if (it->itKPD_Number != 1 || !number) error("IPC type decl is too complicated for Kernel Processed Data"); it->itKPD_Number *= number; it->itNumber = 1; it->itInLine = FALSE; it->itStruct = FALSE; it->itOOL_Number = number; } else if (it->itVarArray) error("IPC type decl is too complicated"); else if (number) { it->itNumber *= number; /* * Bounded [Scalar, Port] VarArray: in-line! */ it->itInLine = TRUE; it->itStruct = FALSE; if (it->itPortType) it->itKPD_Number *= number; it->itOOL_Number = number; } else { it->itNumber = 0; … more in source
itArrayDecl source
Handles the declaration
type new = array[number] of old;
ipc_type_t * itArrayDecl(u_int number, ipc_type_t *old) { ipc_type_t *it = itResetType(itCopyType(old)); if (!it->itInLine) { /* already an initialized KPD */ if (it->itKPD_Number != 1) error("IPC type decl is too complicated for Kernel Processed Data"); it->itKPD_Number *= number; it->itNumber = 1; it->itStruct = FALSE; it->itString = FALSE; it->itVarArray = FALSE; } else if (it->itVarArray) error("IPC type decl is too complicated"); else { it->itNumber *= number; it->itStruct = FALSE; it->itString = FALSE; if (it->itPortType) it->itKPD_Number *= number; } itCalculateSizeInfo(it); return it; }
itPtrDecl source
Handles the declaration
type new = ^ old;
ipc_type_t * itPtrDecl(ipc_type_t *it) { if (!it->itInLine && !it->itMigInLine) error("IPC type decl is already defined to be Out-Of-Line"); it->itInLine = FALSE; it->itStruct = TRUE; it->itString = FALSE; it->itMigInLine = FALSE; it->itKPD_Number = 1; itCalculateSizeInfo(it); return it; }
itStructDecl source
Handles the declaration
type new = struct[number] of old;
ipc_type_t * itStructDecl(u_int number, ipc_type_t *old) { ipc_type_t *it = itResetType(itCopyType(old)); if (!it->itInLine || it->itVarArray) error("IPC type decl is too complicated"); it->itNumber *= number; it->itStruct = TRUE; it->itString = FALSE; itCalculateSizeInfo(it); return it; }
itCStringDecl source
Treat 'c_string[n]' as
'array[n] of (MSG_TYPE_STRING_C, 8)'
ipc_type_t * itCStringDecl(int count, boolean_t varying) { ipc_type_t *it; ipc_type_t *itElement; itElement = itShortDecl(MACH_MSG_TYPE_STRING_C, "MACH_MSG_TYPE_STRING_C", MACH_MSG_TYPE_STRING_C, "MACH_MSG_TYPE_STRING_C", 8); itCheckDecl("char", itElement); it = itResetType(itCopyType(itElement)); it->itNumber = count; it->itVarArray = varying; it->itStruct = FALSE; it->itString = TRUE; itCalculateSizeInfo(it); return it; }
itMakeSubCountType source
extern ipc_type_t * itMakeSubCountType(int count, boolean_t varying, string_t name) { ipc_type_t *it; ipc_type_t *itElement; itElement = itShortDecl(machine_integer_size, machine_integer_name, machine_integer_size, machine_integer_name, machine_integer_bits); itCheckDecl("mach_msg_type_number_t", itElement); it = itResetType(itCopyType(itElement)); it->itNumber = count; /* * I cannot consider it as a Fixed array, otherwise MiG will try * to follow the path for efficient copy of arrays */ it->itVarArray = FALSE; it->itStruct = FALSE; it->itString = FALSE; it->itInLine = TRUE; it->itName = "mach_msg_type_number_t *"; if (varying) it->itVarArray = TRUE; else /* to skip the optimized copy of fixed array: in fact we need to * reference each element and we also miss a user type for it */ it->itNoOptArray = TRUE; itCalculateSizeInfo(it); itCalculateNameInfo(it); return it; … more in source
itMakeCountType source
extern ipc_type_t * itMakeCountType(void) { ipc_type_t *it = itAlloc(); it->itName = "mach_msg_type_number_t"; it->itInName = machine_integer_size; it->itInNameStr = machine_integer_name; it->itOutName = machine_integer_size; it->itOutNameStr = machine_integer_name; it->itSize = machine_integer_bits; itCalculateSizeInfo(it); itCalculateNameInfo(it); return it; }
itMakePolyType source
extern ipc_type_t * itMakePolyType(void) { ipc_type_t *it = itAlloc(); it->itName = "mach_msg_type_name_t"; it->itInName = machine_integer_size; it->itInNameStr = machine_integer_name; it->itOutName = machine_integer_size; it->itOutNameStr = machine_integer_name; it->itSize = machine_integer_bits; itCalculateSizeInfo(it); itCalculateNameInfo(it); return it; }
itMakeDeallocType source
extern ipc_type_t * itMakeDeallocType(void) { ipc_type_t *it = itAlloc(); it->itName = "boolean_t"; it->itInName = MACH_MSG_TYPE_BOOLEAN; it->itInNameStr = "MACH_MSG_TYPE_BOOLEAN"; it->itOutName = MACH_MSG_TYPE_BOOLEAN; it->itOutNameStr = "MACH_MSG_TYPE_BOOLEAN"; it->itSize = machine_integer_bits; itCalculateSizeInfo(it); itCalculateNameInfo(it); return it; }
itNativeType source
extern ipc_type_t * itNativeType(identifier_t id, boolean_t ptr, identifier_t badval) { ipc_type_t *it = itAlloc(); it->itInName = MACH_MSG_TYPE_BYTE; it->itInNameStr = "MACH_MSG_TYPE_BYTE"; it->itOutName = MACH_MSG_TYPE_BYTE; it->itOutNameStr = "MACH_MSG_TYPE_BYTE"; it->itInLine = TRUE; it->itNative = TRUE; it->itNativePointer = ptr; it->itServerType = id; it->itUserType = id; it->itTransType = id; it->itBadValue = badval; itCalculateSizeInfo(it); itCalculateNameInfo(it); return it; }
init_type source
Initializes the pre-defined types.
void init_type(void) { u_int size; size = NBBY * sizeof (natural_t); if (size == 32) { machine_integer_name = "MACH_MSG_TYPE_INTEGER_32"; machine_integer_size = MACH_MSG_TYPE_INTEGER_32; } else if (size == 64) { machine_integer_name = "MACH_MSG_TYPE_INTEGER_64"; machine_integer_size = MACH_MSG_TYPE_INTEGER_64; } else error("init_type unknown size %d", size); machine_integer_bits = size; itRetCodeType = itAlloc(); itRetCodeType->itName = "kern_return_t"; itRetCodeType->itInName = machine_integer_size; itRetCodeType->itInNameStr = machine_integer_name; itRetCodeType->itOutName = machine_integer_size; itRetCodeType->itOutNameStr = machine_integer_name; itRetCodeType->itSize = machine_integer_bits; itCalculateSizeInfo(itRetCodeType); itCalculateNameInfo(itRetCodeType); itNdrCodeType = itAlloc(); … more in source
itCheckReturnType source
****************************************************
Make sure return values of functions are assignable.
****************************************************
void itCheckReturnType(identifier_t name, ipc_type_t *it) { if (!it->itStruct) error("type of %s is too complicated", name); if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) error("type of %s can't be polymorphic", name); }
itCheckRequestPortType source
****************************************************
Called by routine.c to check that request ports are
simple and correct ports with send rights.
****************************************************
void itCheckRequestPortType(identifier_t name, ipc_type_t *it) { /* error("Port size = %d %d name = %s\n", PortSize, it->itSize, it->itName); error("server = %s user = %x\n",it->itServerType, it->itUserType); */ if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) && (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) && (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC)) || (it->itNumber != 1) || (it->itSize != PortSize) || !it->itInLine || !it->itStruct || it->itVarArray) error("argument %s isn't a proper request port", name); }
itCheckReplyPortType source
****************************************************
Called by routine.c to check that reply ports are
simple and correct ports with send rights.
****************************************************
void itCheckReplyPortType(identifier_t name, ipc_type_t *it) { if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) && (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) && (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) && (it->itOutName != 0)) || (it->itNumber != 1) || (it->itSize != PortSize) || !it->itInLine || !it->itStruct || it->itVarArray) error("argument %s isn't a proper reply port", name); }
itCheckIntType source
****************************************************
Used by routine.c to check that WaitTime is a
simple bit machine_integer_bits integer.
****************************************************
void itCheckIntType(identifier_t name, ipc_type_t *it) { if ((it->itInName != machine_integer_size) || (it->itOutName != machine_integer_size) || (it->itNumber != 1) || (it->itSize != machine_integer_bits) || !it->itInLine || !it->itStruct || it->itVarArray) error("argument %s isn't a proper integer", name); }
itCheckTokenType source
void itCheckTokenType(identifier_t name, ipc_type_t *it) { if (it->itMigInLine || it->itNoOptArray || it->itString || it->itTypeSize != 8 || !it->itInLine || !it->itStruct || it->itVarArray || it->itPortType) error("argument %s isn't a proper Token", name); }