#include "type.h"
#include <sys/types.h>
#include <mach/message.h>
#include <mach/std_types.h>
#include <mach/ndr.h>
#include "mig_machine.h"
#include "routine.h"
#include "error.h"
#include "alloc.h"
#include "global.h"
#include <stdio.h>
#define PortSize (sizeof (mach_port_t) * NBBY)
ipc_type_t *itRetCodeType;
ipc_type_t *itNdrCodeType;
ipc_type_t *itDummyType;
ipc_type_t *itTidType;
ipc_type_t *itRequestPortType;
ipc_type_t *itZeroReplyPortType;
ipc_type_t *itRealReplyPortType;
ipc_type_t *itWaitTimeType;
ipc_type_t *itMsgOptionType;
static ipc_type_t *list = itNULL;
static char *machine_integer_name;
static u_int machine_integer_size;
static u_int machine_integer_bits;
ipc_type_t *
itLookUp(identifier_t name)
{
register ipc_type_t *it, **last;
for (it = *(last = &list); it != itNULL; it = *(last = &it->itNext))
if (streql(name, it->itName)) {
*last = it->itNext;
it->itNext = list;
list = it;
return it;
}
return itNULL;
}
void
itInsert(identifier_t name, ipc_type_t *it)
{
it->itName = name;
it->itNext = list;
list = it;
}
static ipc_type_t *
itAlloc(void)
{
static ipc_type_t prototype =
{
strNULL,
0,
0,
0,
0,
0,
0,
0,
1,
0,
TRUE,
FALSE,
FALSE,
strNULL,
strNULL,
TRUE,
FALSE,
FALSE,
FALSE,
FALSE,
FALSE,
itNULL,
strNULL,
strNULL,
strNULL,
strNULL,
strNULL,
strNULL,
strNULL,
strNULL,
};
register ipc_type_t *new;
new = (ipc_type_t *) malloc(sizeof *new);
if (new == itNULL)
fatal("itAlloc(): %s", strerror(errno));
*new = prototype;
return new;
}
static char *
itNameToString(u_int name)
{
char buffer[100];
(void) sprintf(buffer, "%u", name);
return strmake(buffer);
}
static void
itCalculateSizeInfo(register 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)) {
it->itMinTypeSize = sizeof (mach_msg_type_number_t);
if (it->itString)
it->itMinTypeSize += sizeof (mach_msg_type_number_t);
}
else
it->itMinTypeSize = bytes + padding;
}
else {
u_int bytes;
if (IS_MULTIPLE_KPD(it))
bytes = it->itKPD_Number * sizeof(mach_msg_descriptor_t);
else
bytes = sizeof(mach_msg_descriptor_t);
it->itTypeSize = bytes;
it->itPadSize = 0;
it->itMinTypeSize = bytes;
}
if ((it->itTypeSize == 0) && !it->itVarArray && !it->itNative)
warn("sizeof(%s) == 0");
}
static void
itCalculateNameInfo(register 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
if (IsKernelServer &&
streql(it->itServerType, "mach_port_t") &&
(((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) &&
(it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ||
MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
MACH_MSG_TYPE_PORT_ANY(it->itOutName)))
it->itServerType = "ipc_port_t";
if (IsKernelUser &&
streql(it->itUserType, "mach_port_t") &&
(((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) &&
(it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) ||
MACH_MSG_TYPE_PORT_ANY(it->itInName) ||
MACH_MSG_TYPE_PORT_ANY(it->itOutName)))
it->itUserType = "ipc_port_t";
#endif
if (it->itTransType == strNULL)
it->itTransType = it->itServerType;
}
static void
itCheckDecl(identifier_t name, register ipc_type_t *it)
{
it->itName = name;
itCalculateNameInfo(it);
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);
}
}
static void
itPrintTrans(register 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);
}
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");
}
void
itTypeDecl(identifier_t name, ipc_type_t *it)
{
itCheckDecl(name, it);
if (BeVerbose)
itPrintDecl(name, it);
}
ipc_type_t *
itShortDecl(u_int inname, string_t instr, u_int outname, string_t outstr, u_int defsize)
{
register 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;
}
if (MACH_MSG_TYPE_PORT_ANY(inname) ||
inname == MACH_MSG_TYPE_POLYMORPHIC) {
it->itPortType = TRUE;
it->itKPD_Number = 1;
}
itCalculateSizeInfo(it);
return it;
}
static ipc_type_t *
itCopyType(ipc_type_t *old)
{
register ipc_type_t *new = itAlloc();
*new = *old;
new->itName = strNULL;
new->itNext = itNULL;
new->itElement = old;
return new;
}
ipc_type_t *
itResetType(ipc_type_t *old)
{
old->itInTrans = strNULL;
old->itOutTrans = strNULL;
old->itDestructor = strNULL;
old->itUserType = strNULL;
old->itServerType = strNULL;
old->itTransType = strNULL;
return old;
}
ipc_type_t *
itPrevDecl(identifier_t name)
{
register ipc_type_t *old;
old = itLookUp(name);
if (old == itNULL) {
error("type '%s' not defined", name);
return itAlloc();
}
else
return itCopyType(old);
}
ipc_type_t *
itVarArrayDecl(u_int number, register ipc_type_t *old)
{
register ipc_type_t *it = itResetType(itCopyType(old));
if (!it->itInLine) {
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;
}
else if (it->itVarArray)
error("IPC type decl is too complicated");
else if (number) {
it->itNumber *= number;
it->itInLine = TRUE;
it->itStruct = FALSE;
if (it->itPortType)
it->itKPD_Number *= number;
}
else {
it->itNumber = 0;
it->itMigInLine = TRUE;
it->itInLine = FALSE;
it->itStruct = TRUE;
it->itKPD_Number = 1;
}
it->itVarArray = TRUE;
it->itString = FALSE;
itCalculateSizeInfo(it);
return it;
}
ipc_type_t *
itArrayDecl(u_int number, ipc_type_t *old)
{
register ipc_type_t *it = itResetType(itCopyType(old));
if (!it->itInLine) {
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;
}
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;
}
ipc_type_t *
itStructDecl(u_int number, ipc_type_t *old)
{
register 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;
}
ipc_type_t *
itCStringDecl(int count, boolean_t varying)
{
register ipc_type_t *it;
register 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;
}
extern ipc_type_t *
itMakeSubCountType(int count, boolean_t varying, string_t name)
{
register ipc_type_t *it;
register 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;
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
it->itNoOptArray = TRUE;
itCalculateSizeInfo(it);
itCalculateNameInfo(it);
return it;
}
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;
}
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;
}
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;
}
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;
}
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();
itNdrCodeType->itName = "NDR_record_t";
itNdrCodeType->itInName = 0;
itNdrCodeType->itInNameStr = "NDR_record_t";
itNdrCodeType->itOutName = 0;
itNdrCodeType->itOutNameStr = "NDR_record_t";
itNdrCodeType->itSize = sizeof(NDR_record_t) * 8;
itCalculateSizeInfo(itNdrCodeType);
itCalculateNameInfo(itNdrCodeType);
itDummyType = itAlloc();
itDummyType->itName = "char *";
itDummyType->itInName = MACH_MSG_TYPE_UNSTRUCTURED;
itDummyType->itInNameStr = "MACH_MSG_TYPE_UNSTRUCTURED";
itDummyType->itOutName = MACH_MSG_TYPE_UNSTRUCTURED;
itDummyType->itOutNameStr = "MACH_MSG_TYPE_UNSTRUCTURED";
itDummyType->itSize = PortSize;
itCalculateSizeInfo(itDummyType);
itCalculateNameInfo(itDummyType);
itTidType = itAlloc();
itTidType->itName = "tid_t";
itTidType->itInName = machine_integer_size;
itTidType->itInNameStr = machine_integer_name;
itTidType->itOutName = machine_integer_size;
itTidType->itOutNameStr = machine_integer_name;
itTidType->itSize = machine_integer_bits;
itTidType->itNumber = 6;
itCalculateSizeInfo(itTidType);
itCalculateNameInfo(itTidType);
itRequestPortType = itAlloc();
itRequestPortType->itName = "mach_port_t";
itRequestPortType->itInName = MACH_MSG_TYPE_COPY_SEND;
itRequestPortType->itInNameStr = "MACH_MSG_TYPE_COPY_SEND";
itRequestPortType->itOutName = MACH_MSG_TYPE_PORT_SEND;
itRequestPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND";
itRequestPortType->itSize = PortSize;
itCalculateSizeInfo(itRequestPortType);
itCalculateNameInfo(itRequestPortType);
itZeroReplyPortType = itAlloc();
itZeroReplyPortType->itName = "mach_port_t";
itZeroReplyPortType->itInName = 0;
itZeroReplyPortType->itInNameStr = "0";
itZeroReplyPortType->itOutName = 0;
itZeroReplyPortType->itOutNameStr = "0";
itZeroReplyPortType->itSize = PortSize;
itCalculateSizeInfo(itZeroReplyPortType);
itCalculateNameInfo(itZeroReplyPortType);
itRealReplyPortType = itAlloc();
itRealReplyPortType->itName = "mach_port_t";
itRealReplyPortType->itInName = MACH_MSG_TYPE_MAKE_SEND_ONCE;
itRealReplyPortType->itInNameStr = "MACH_MSG_TYPE_MAKE_SEND_ONCE";
itRealReplyPortType->itOutName = MACH_MSG_TYPE_PORT_SEND_ONCE;
itRealReplyPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND_ONCE";
itRealReplyPortType->itSize = PortSize;
itCalculateSizeInfo(itRealReplyPortType);
itCalculateNameInfo(itRealReplyPortType);
itWaitTimeType = itMakeCountType();
itMsgOptionType = itMakeCountType();
}
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);
}
void
itCheckRequestPortType(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->itNumber != 1) ||
(it->itSize != PortSize) ||
!it->itInLine ||
!it->itStruct ||
it->itVarArray)
error("argument %s isn't a proper request port", name);
}
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);
}
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);
}
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);
}