#include <assert.h>
#include <mach/message.h>
#include <write.h>
#include <utils.h>
#include <global.h>
#include <error.h>
static void
WriteIncludes(FILE *file)
{
fprintf(file, "#define EXPORT_BOOLEAN\n");
fprintf(file, "#include <mach/boolean.h>\n");
fprintf(file, "#include <mach/kern_return.h>\n");
fprintf(file, "#include <mach/message.h>\n");
fprintf(file, "#include <mach/mig_errors.h>\n");
fprintf(file, "#include <mach/mig_support.h>\n");
if (IsKernelServer)
fprintf(file, "#include <ipc/ipc_port.h>\n");
fprintf(file, "\n");
}
static void
WriteGlobalDecls(FILE *file)
{
if (RCSId != strNULL)
WriteRCSDecl(file, strconcat(SubsystemName, "_server"), RCSId);
if (IsKernelServer)
{
fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
}
else
{
fprintf(file, "#define msgh_request_port\tmsgh_local_port\n");
fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
fprintf(file, "#define msgh_reply_port\t\tmsgh_remote_port\n");
fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
}
fprintf(file, "\n");
}
static void
WriteProlog(FILE *file)
{
fprintf(file, "/* Module %s */\n", SubsystemName);
fprintf(file, "\n");
WriteIncludes(file);
WriteBogusDefines(file);
WriteGlobalDecls(file);
}
static void
WriteSymTabEntries(FILE *file, const statement_t *stats)
{
register const statement_t *stat;
register u_int current = 0;
for (stat = stats; stat != stNULL; stat = stat->stNext)
if (stat->stKind == skRoutine) {
register num = stat->stRoutine->rtNumber;
const char *name = stat->stRoutine->rtName;
while (++current <= num)
fprintf(file,"\t\t\t{ \"\", 0, 0 },\n");
fprintf(file, "\t{ \"%s\", %d, _X%s },\n",
name,
SubsystemBase + current - 1,
name);
}
while (++current <= rtNumber)
fprintf(file,"\t{ \"\", 0, 0 },\n");
}
static void
WriteArrayEntries(FILE *file, const statement_t *stats)
{
register u_int current = 0;
register const statement_t *stat;
for (stat = stats; stat != stNULL; stat = stat->stNext)
if (stat->stKind == skRoutine)
{
register const routine_t *rt = stat->stRoutine;
while (current++ < rt->rtNumber)
fprintf(file, "\t\t0,\n");
fprintf(file, "\t\t_X%s,\n", rt->rtName);
}
while (current++ < rtNumber)
fprintf(file, "\t\t\t0,\n");
}
static void
WriteEpilog(FILE *file, const statement_t *stats)
{
fprintf(file, "\n");
fprintf(file, "static mig_routine_t %s_routines[] = {\n", ServerDemux);
WriteArrayEntries(file, stats);
fprintf(file, "};\n");
fprintf(file, "\n");
fprintf(file, "mig_external boolean_t %s\n", ServerDemux);
fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
fprintf(file, "{\n");
fprintf(file, "\tregister mach_msg_header_t *InP = InHeadP;\n");
fprintf(file, "\tregister mig_reply_header_t *OutP = (mig_reply_header_t *) OutHeadP;\n");
fprintf(file, "\n");
WriteStaticDecl(file, itRetCodeType,
itRetCodeType->itDeallocate, itRetCodeType->itLongForm,
!IsKernelServer, "RetCodeType");
fprintf(file, "\n");
fprintf(file, "\tregister mig_routine_t routine;\n");
fprintf(file, "\n");
fprintf(file, "\tOutP->Head.msgh_bits = ");
fprintf(file, "MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InP->msgh_bits), 0);\n");
fprintf(file, "\tOutP->Head.msgh_size = sizeof *OutP;\n");
fprintf(file, "\tOutP->Head.msgh_remote_port = InP->msgh_reply_port;\n");
fprintf(file, "\tOutP->Head.msgh_local_port = MACH_PORT_NULL;\n");
fprintf(file, "\tOutP->Head.msgh_seqno = 0;\n");
fprintf(file, "\tOutP->Head.msgh_id = InP->msgh_id + 100;\n");
fprintf(file, "\n");
WritePackMsgType(file, itRetCodeType,
itRetCodeType->itDeallocate, itRetCodeType->itLongForm,
!IsKernelServer, "OutP->RetCodeType", "RetCodeType");
fprintf(file, "\n");
fprintf(file, "\tif ((InP->msgh_id > %d) || (InP->msgh_id < %d) ||\n",
SubsystemBase + rtNumber - 1, SubsystemBase);
fprintf(file, "\t ((routine = %s_routines[InP->msgh_id - %d]) == 0)) {\n",
ServerDemux, SubsystemBase);
fprintf(file, "\t\tOutP->RetCode = MIG_BAD_ID;\n");
fprintf(file, "\t\treturn FALSE;\n");
fprintf(file, "\t}\n");
fprintf(file, "\t(*routine) (InP, &OutP->Head);\n");
fprintf(file, "\treturn TRUE;\n");
fprintf(file, "}\n");
fprintf(file, "\n");
fprintf(file, "mig_external mig_routine_t %s_routine\n", ServerDemux);
fprintf(file, "\t(const mach_msg_header_t *InHeadP)\n");
fprintf(file, "{\n");
fprintf(file, "\tregister int msgh_id;\n");
fprintf(file, "\n");
fprintf(file, "\tmsgh_id = InHeadP->msgh_id - %d;\n", SubsystemBase);
fprintf(file, "\n");
fprintf(file, "\tif ((msgh_id > %d) || (msgh_id < 0))\n",
rtNumber - 1);
fprintf(file, "\t\treturn 0;\n");
fprintf(file, "\n");
fprintf(file, "\treturn %s_routines[msgh_id];\n", ServerDemux);
fprintf(file, "}\n");
fprintf(file, "\n");
if (GenSymTab) {
fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName);
WriteSymTabEntries(file,stats);
fprintf(file,"};\n");
fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase);
fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber);
}
}
static const char *
ServerSideType(const routine_t *rt)
{
if (rt->rtServerReturn == argNULL)
return "void";
else
return rt->rtServerReturn->argType->itTransType;
}
static void
WriteLocalVarDecl(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
if (it->itInLine && it->itVarArray)
{
register const ipc_type_t *btype = it->itElement;
fprintf(file, "\t%s %s[%d]", btype->itTransType,
arg->argVarName, it->itNumber/btype->itNumber);
}
else
fprintf(file, "\t%s %s", it->itTransType, arg->argVarName);
}
static void
WriteLocalPtrDecl(FILE *file, register const argument_t *arg)
{
fprintf(file, "\t%s *%sP",
FetchServerType(arg->argType->itElement),
arg->argVarName);
}
static void
WriteServerArgDecl(FILE *file, const argument_t *arg)
{
fprintf(file, "%s %s%s",
arg->argType->itTransType,
arg->argByReferenceServer ? "*" : "",
arg->argVarName);
}
static void
WriteVarDecls(FILE *file, const routine_t *rt)
{
int i;
boolean_t NeedMsghSize = FALSE;
boolean_t NeedMsghSizeDelta = FALSE;
fprintf(file, "\tregister Request *In0P = (Request *) InHeadP;\n");
for (i = 1; i <= rt->rtMaxRequestPos; i++)
fprintf(file, "\tregister Request *In%dP;\n", i);
fprintf(file, "\tregister Reply *OutP = (Reply *) OutHeadP;\n");
fprintf(file, "\tmig_external %s %s\n",
ServerSideType(rt), rt->rtServerName);
fprintf(file, "\t\t(");
WriteList(file, rt->rtArgs, WriteServerArgDecl, akbServerArg, ", ", "");
fprintf(file, ");\n");
fprintf(file, "\n");
if (!rt->rtSimpleFixedReply)
fprintf(file, "\tboolean_t msgh_simple;\n");
else if (!rt->rtSimpleCheckRequest)
{
fprintf(file, "#if\tTypeCheck\n");
fprintf(file, "\tboolean_t msgh_simple;\n");
fprintf(file, "#endif\t/* TypeCheck */\n");
fprintf(file, "\n");
}
if (rt->rtNumRequestVar > 0)
NeedMsghSize = TRUE;
if (rt->rtMaxRequestPos > 0)
NeedMsghSizeDelta = TRUE;
if (rt->rtNumReplyVar > 1)
NeedMsghSize = TRUE;
if (rt->rtMaxReplyPos > 0)
NeedMsghSizeDelta = TRUE;
if (NeedMsghSize)
fprintf(file, "\tunsigned int msgh_size;\n");
if (NeedMsghSizeDelta)
fprintf(file, "\tunsigned int msgh_size_delta;\n");
if (NeedMsghSize || NeedMsghSizeDelta)
fprintf(file, "\n");
}
static void
WriteMsgError(FILE *file, const char *error_msg)
{
fprintf(file, "\t\t{ OutP->RetCode = %s; return; }\n", error_msg);
}
static void
WriteReplyInit(FILE *file, const routine_t *rt)
{
boolean_t printed_nl = FALSE;
if (rt->rtSimpleFixedReply)
{
if (!rt->rtSimpleSendReply)
{
printed_nl = TRUE;
fprintf(file, "\n");
fprintf(file,
"\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
}
}
else
{
printed_nl = TRUE;
fprintf(file, "\n");
fprintf(file, "\tmsgh_simple = %s;\n",
strbool(rt->rtSimpleSendReply));
}
if (rt->rtNumReplyVar == 0)
{
if (!printed_nl)
fprintf(file, "\n");
fprintf(file, "\tOutP->Head.msgh_size = %d;\n", rt->rtReplySize);
}
}
static void
WriteReplyHead(FILE *file, const routine_t *rt)
{
if ((!rt->rtSimpleFixedReply) ||
(rt->rtNumReplyVar > 1))
{
fprintf(file, "\n");
if (rt->rtMaxReplyPos > 0)
fprintf(file, "\tOutP = (Reply *) OutHeadP;\n");
}
if (!rt->rtSimpleFixedReply)
{
fprintf(file, "\tif (!msgh_simple)\n");
fprintf(file,
"\t\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
}
if (rt->rtNumReplyVar > 1)
fprintf(file, "\tOutP->Head.msgh_size = msgh_size;\n");
}
static void
WriteCheckHead(FILE *file, const routine_t *rt)
{
fprintf(file, "#if\tTypeCheck\n");
if (rt->rtNumRequestVar > 0)
fprintf(file, "\tmsgh_size = In0P->Head.msgh_size;\n");
if (!rt->rtSimpleCheckRequest)
fprintf(file, "\tmsgh_simple = !(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n");
if (rt->rtNumRequestVar > 0)
fprintf(file, "\tif ((msgh_size < %d)",
rt->rtRequestSize);
else
fprintf(file, "\tif ((In0P->Head.msgh_size != %d)",
rt->rtRequestSize);
if (rt->rtSimpleCheckRequest)
fprintf(file, " ||\n\t %s(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX)",
rt->rtSimpleReceiveRequest ? "" : "!");
fprintf(file, ")\n");
WriteMsgError(file, "MIG_BAD_ARGUMENTS");
fprintf(file, "#endif\t/* TypeCheck */\n");
fprintf(file, "\n");
}
static void
WriteTypeCheck(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
register const routine_t *rt = arg->argRoutine;
fprintf(file, "#if\tTypeCheck\n");
if (akCheck(arg->argKind, akbRequestQC))
fprintf(file, "\tif (* (int *) &In%dP->%s != * (int *) &%sCheck)\n",
arg->argRequestPos, arg->argTTName, arg->argVarName);
else
{
fprintf(file, "\tif (");
if (!it->itIndefinite) {
fprintf(file, "(In%dP->%s%s.msgt_inline != %s) ||\n\t ",
arg->argRequestPos, arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "",
strbool(it->itInLine));
}
fprintf(file, "(In%dP->%s%s.msgt_longform != %s) ||\n",
arg->argRequestPos, arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "",
strbool(arg->argLongForm));
if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
{
if (!rt->rtSimpleCheckRequest)
fprintf(file, "\t (MACH_MSG_TYPE_PORT_ANY(In%dP->%s.msgt%s_name) && msgh_simple) ||\n",
arg->argRequestPos, arg->argTTName,
arg->argLongForm ? "l" : "");
}
else
fprintf(file, "\t (In%dP->%s.msgt%s_name != %s) ||\n",
arg->argRequestPos, arg->argTTName,
arg->argLongForm ? "l" : "",
it->itOutNameStr);
if (!it->itVarArray)
fprintf(file, "\t (In%dP->%s.msgt%s_number != %d) ||\n",
arg->argRequestPos, arg->argTTName,
arg->argLongForm ? "l" : "",
it->itNumber);
fprintf(file, "\t (In%dP->%s.msgt%s_size != %d))\n",
arg->argRequestPos, arg->argTTName,
arg->argLongForm ? "l" : "",
it->itSize);
}
WriteMsgError(file, "MIG_BAD_ARGUMENTS");
fprintf(file, "#endif\t/* TypeCheck */\n");
fprintf(file, "\n");
}
static void
WriteCheckArgSize(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *ptype = arg->argType;
register const ipc_type_t *btype = ptype->itElement;
const argument_t *count = arg->argCount;
int multiplier = btype->itTypeSize / btype->itNumber;
if (ptype->itIndefinite) {
fprintf(file, "(In%dP->%s%s.msgt_inline) ? ",
arg->argRequestPos,
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
}
if (btype->itTypeSize % 4 != 0)
fprintf(file, "(");
if (multiplier > 1)
fprintf(file, "%d * ", multiplier);
fprintf(file, "In%dP->%s", arg->argRequestPos, count->argMsgField);
if (btype->itTypeSize % 4 != 0)
fprintf(file, " + 3) & ~3");
if (ptype->itIndefinite) {
fprintf(file, " : sizeof(%s *)", FetchServerType(btype));
}
}
static void
WriteCheckMsgSize(FILE *file, register const argument_t *arg)
{
register const routine_t *rt = arg->argRoutine;
if (arg->argRequestPos == rt->rtMaxRequestPos)
{
fprintf(file, "#if\tTypeCheck\n");
fprintf(file, "\tif (msgh_size != %d + (", rt->rtRequestSize);
WriteCheckArgSize(file, arg);
fprintf(file, "))\n");
WriteMsgError(file, "MIG_BAD_ARGUMENTS");
fprintf(file, "#endif\t/* TypeCheck */\n");
}
else
{
boolean_t LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar;
fprintf(file, "\tmsgh_size_delta = ");
WriteCheckArgSize(file, arg);
fprintf(file, ";\n");
fprintf(file, "#if\tTypeCheck\n");
if (LastVarArg)
fprintf(file, "\tif (msgh_size != %d + msgh_size_delta)\n",
rt->rtRequestSize);
else
fprintf(file, "\tif (msgh_size < %d + msgh_size_delta)\n",
rt->rtRequestSize);
WriteMsgError(file, "MIG_BAD_ARGUMENTS");
if (!LastVarArg)
fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
fprintf(file, "#endif\t/* TypeCheck */\n");
}
fprintf(file, "\n");
}
static const char *
InArgMsgField(register const argument_t *arg)
{
static char buffer[100];
if (IsKernelServer &&
((akIdent(arg->argKind) == akeRequestPort) ||
(akIdent(arg->argKind) == akeReplyPort)))
sprintf(buffer, "(ipc_port_t) In%dP->%s",
arg->argRequestPos, arg->argMsgField);
else
sprintf(buffer, "In%dP->%s",
arg->argRequestPos, arg->argMsgField);
return buffer;
}
static void
WriteExtractArgValue(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
if (arg->argMultiplier > 1)
WriteCopyType(file, it, "%s", "/* %s */ %s / %d",
arg->argVarName, InArgMsgField(arg), arg->argMultiplier);
else if (it->itInTrans != strNULL)
WriteCopyType(file, it, "%s", "/* %s */ %s(%s)",
arg->argVarName, it->itInTrans, InArgMsgField(arg));
else
WriteCopyType(file, it, "%s", "/* %s */ %s",
arg->argVarName, InArgMsgField(arg));
fprintf(file, "\n");
}
static void
WriteInitializeCount(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *ptype = arg->argParent->argType;
register const ipc_type_t *btype = ptype->itElement;
fprintf(file, "\t%s = %d;\n", arg->argVarName,
ptype->itNumber/btype->itNumber);
if (arg->argCInOut != argNULL) {
const char *msgfield = InArgMsgField(arg->argCInOut);
fprintf(file, "\tif (%s < %s)\n", msgfield, arg->argVarName);
fprintf(file, "\t\t%s = %s;\n", arg->argVarName, msgfield);
}
fprintf(file, "\n");
}
static void
WriteInitializePtr(FILE *file, register const argument_t *arg)
{
if (akCheck(arg->argKind, akbVarNeeded))
fprintf(file, "\t%sP = %s;\n",
arg->argVarName, arg->argVarName);
else
fprintf(file, "\t%sP = OutP->%s;\n",
arg->argVarName, arg->argMsgField);
}
static void
WriteTypeCheckArg(FILE *file, register const argument_t *arg)
{
if (akCheck(arg->argKind, akbRequest)) {
WriteTypeCheck(file, arg);
if (akCheck(arg->argKind, akbVariable))
WriteCheckMsgSize(file, arg);
}
}
static void
WriteAdjustRequestMsgPtr(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *ptype = arg->argType;
fprintf(file,
"\tIn%dP = (Request *) ((char *) In%dP + msgh_size_delta - %d);\n\n",
arg->argRequestPos+1, arg->argRequestPos,
ptype->itTypeSize + ptype->itPadSize);
}
static void
WriteTypeCheckRequestArgs(FILE *file, register const routine_t *rt)
{
register const argument_t *arg;
register const argument_t *lastVarArg;
lastVarArg = argNULL;
for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
if (lastVarArg != argNULL &&
lastVarArg->argRequestPos < arg->argRequestPos)
{
WriteAdjustRequestMsgPtr(file, lastVarArg);
lastVarArg = argNULL;
}
WriteTypeCheckArg(file, arg);
if (akCheckAll(arg->argKind, akbVariable|akbRequest))
lastVarArg = arg;
}
}
static void
WriteExtractArg(FILE *file, register const argument_t *arg)
{
if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded))
WriteExtractArgValue(file, arg);
if ((akIdent(arg->argKind) == akeCount) &&
akCheck(arg->argKind, akbReturnSnd))
{
register ipc_type_t *ptype = arg->argParent->argType;
if (ptype->itInLine && ptype->itVarArray)
WriteInitializeCount(file, arg);
}
if (akCheckAll(arg->argKind, akbReturnSnd|akbPointer))
WriteInitializePtr(file, arg);
}
static void
WriteServerCallArg(FILE *file, register const argument_t *arg)
{
const ipc_type_t *it = arg->argType;
boolean_t NeedClose = FALSE;
if (arg->argByReferenceServer)
fprintf(file, "&");
if ((it->itInTrans != strNULL) &&
akCheck(arg->argKind, akbSendRcv) &&
!akCheck(arg->argKind, akbVarNeeded))
{
fprintf(file, "%s(", it->itInTrans);
NeedClose = TRUE;
}
if (akCheck(arg->argKind, akbPointer))
fprintf(file, "%sP", arg->argVarName);
else if (akCheck(arg->argKind, akbVarNeeded))
fprintf(file, "%s", arg->argVarName);
else if (akCheck(arg->argKind, akbSendRcv)) {
if (akCheck(arg->argKind, akbIndefinite)) {
fprintf(file, "(In%dP->%s%s.msgt_inline) ",
arg->argRequestPos,
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
fprintf(file, "? %s ", InArgMsgField(arg));
fprintf(file, ": *((%s **)%s)",
FetchServerType(arg->argType->itElement),
InArgMsgField(arg));
}
else
fprintf(file, "%s", InArgMsgField(arg));
}
else
fprintf(file, "OutP->%s", arg->argMsgField);
if (NeedClose)
fprintf(file, ")");
if (!arg->argByReferenceServer && (arg->argMultiplier > 1))
fprintf(file, " / %d", arg->argMultiplier);
}
static void
WriteDestroyArg(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
if (akCheck(arg->argKind, akbIndefinite)) {
argument_t *count = arg->argCount;
ipc_type_t *btype = it->itElement;
int multiplier = btype->itTypeSize / btype->itNumber;
fprintf(file, "\tif (!In%dP->%s%s.msgt_inline)\n",
arg->argRequestPos,
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
fprintf(file, "\t\tmig_deallocate(* (vm_offset_t *) %s, ",
InArgMsgField(arg));
if (multiplier > 1)
fprintf(file, "%d * ", multiplier);
fprintf(file, " %s);\n", InArgMsgField(count));
} else {
if (akCheck(arg->argKind, akbVarNeeded))
fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName);
else
fprintf(file, "\t%s(%s);\n", it->itDestructor,
InArgMsgField(arg));
}
}
static void
WriteDestroyPortArg(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
if ((it->itInTrans != strNULL) &&
(it->itOutName == MACH_MSG_TYPE_PORT_SEND))
{
fprintf(file, "\n");
fprintf(file, "\tif (IP_VALID(%s))\n", InArgMsgField(arg));
fprintf(file, "\t\tipc_port_release_send(%s);\n", InArgMsgField(arg));
}
}
static boolean_t
CheckDestroyPortArg(register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
if ((it->itInTrans != strNULL) &&
(it->itOutName == MACH_MSG_TYPE_PORT_SEND))
{
return TRUE;
}
return FALSE;
}
static void
WriteServerCall(FILE *file, const routine_t *rt)
{
boolean_t NeedClose = FALSE;
fprintf(file, "\t");
if (rt->rtServerReturn != argNULL)
{
const argument_t *arg = rt->rtServerReturn;
const ipc_type_t *it = arg->argType;
fprintf(file, "OutP->%s = ", arg->argMsgField);
if (it->itOutTrans != strNULL)
{
fprintf(file, "%s(", it->itOutTrans);
NeedClose = TRUE;
}
}
fprintf(file, "%s(", rt->rtServerName);
WriteList(file, rt->rtArgs, WriteServerCallArg, akbServerArg, ", ", "");
if (NeedClose)
fprintf(file, ")");
fprintf(file, ");\n");
}
static void
WriteGetReturnValue(FILE *file, register const routine_t *rt)
{
if (rt->rtServerReturn != rt->rtRetCode)
fprintf(file, "\tOutP->%s = KERN_SUCCESS;\n",
rt->rtRetCode->argMsgField);
}
static void
WriteCheckReturnValue(FILE *file, register const routine_t *rt)
{
if (rt->rtServerReturn == rt->rtRetCode)
{
fprintf(file, "\tif (OutP->%s != KERN_SUCCESS)\n",
rt->rtRetCode->argMsgField);
fprintf(file, "\t\treturn;\n");
}
}
static void
WritePackArgType(FILE *file, register const argument_t *arg)
{
fprintf(file, "\n");
WritePackMsgType(file, arg->argType,
arg->argType->itIndefinite ? d_NO : arg->argDeallocate,
arg->argLongForm, !IsKernelServer,
"OutP->%s", "%s", arg->argTTName);
}
static void
WritePackArgValue(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *it = arg->argType;
fprintf(file, "\n");
if (it->itInLine && it->itVarArray) {
if (it->itString) {
fprintf(file,
"\tOutP->%s = mig_strncpy(OutP->%s, %s, %d);\n",
arg->argCount->argMsgField,
arg->argMsgField,
arg->argVarName,
it->itNumber);
}
else {
register argument_t *count = arg->argCount;
register ipc_type_t *btype = it->itElement;
if (it->itIndefinite) {
fprintf(file, "\tif (%sP != %s) {\n",
arg->argVarName,
arg->argVarName);
fprintf(file, "\t\tOutP->%s%s.msgt_inline = FALSE;\n",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
if (arg->argDeallocate == d_YES)
fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = TRUE;\n",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
else if (arg->argDeallocate == d_MAYBE)
fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = %s;\n",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "",
arg->argDealloc->argVarName);
fprintf(file, "\t\t*((%s **)OutP->%s) = %sP;\n",
FetchServerType(btype),
arg->argMsgField,
arg->argVarName);
if (!arg->argRoutine->rtSimpleFixedReply)
fprintf(file, "\t\tmsgh_simple = FALSE;\n");
fprintf(file, "\t}\n\telse {\n\t");
}
fprintf(file, "\tmemcpy(OutP->%s, %s, ",
arg->argMsgField, arg->argVarName);
if (btype->itTypeSize > 1)
fprintf(file, "%d * ",
btype->itTypeSize);
fprintf(file, "%s);\n",
count->argVarName);
if (it->itIndefinite)
fprintf(file, "\t}\n");
}
}
else if (arg->argMultiplier > 1)
WriteCopyType(file, it, "OutP->%s", "/* %s */ %d * %s",
arg->argMsgField,
arg->argMultiplier,
arg->argVarName);
else if (it->itOutTrans != strNULL)
WriteCopyType(file, it, "OutP->%s", "/* %s */ %s(%s)",
arg->argMsgField, it->itOutTrans, arg->argVarName);
else
WriteCopyType(file, it, "OutP->%s", "/* %s */ %s",
arg->argMsgField, arg->argVarName);
}
static void
WriteCopyArgValue(FILE *file, register const argument_t *arg)
{
fprintf(file, "\n");
WriteCopyType(file, arg->argType, "/* %d */ OutP->%s", "In%dP->%s",
arg->argRequestPos, arg->argMsgField);
}
static void
WriteAdjustMsgSimple(FILE *file, register const argument_t *arg)
{
if (!arg->argRoutine->rtSimpleFixedReply)
{
fprintf(file, "\n");
fprintf(file, "\tif (MACH_MSG_TYPE_PORT_ANY(%s))\n", arg->argVarName);
fprintf(file, "\t\tmsgh_simple = FALSE;\n");
}
}
static void
WriteAdjustMsgCircular(FILE *file, register const argument_t *arg)
{
fprintf(file, "\n");
if (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
fprintf(file, "\tif (%s == MACH_MSG_TYPE_PORT_RECEIVE)\n",
arg->argPoly->argVarName);
fprintf(file, "\tif (IP_VALID((ipc_port_t) InHeadP->msgh_reply_port) &&\n");
fprintf(file, "\t IP_VALID((ipc_port_t) OutP->%s) &&\n", arg->argMsgField);
fprintf(file, "\t ipc_port_check_circularity((ipc_port_t) OutP->%s, (ipc_port_t) InHeadP->msgh_reply_port))\n", arg->argMsgField);
fprintf(file, "\t\tOutHeadP->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;\n");
}
static void
WriteArgSize(FILE *file, register const argument_t *arg)
{
register const ipc_type_t *ptype = arg->argType;
register int bsize = ptype->itElement->itTypeSize;
register const argument_t *count = arg->argCount;
if (ptype->itIndefinite) {
fprintf(file, "(OutP->%s%s.msgt_inline) ? ",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
}
if (bsize % 4 != 0)
fprintf(file, "(");
if (bsize > 1)
fprintf(file, "%d * ", bsize);
if (ptype->itString)
fprintf(file, "OutP->%s", count->argMsgField);
else
fprintf(file, "%s", count->argVarName);
if (bsize % 4 != 0)
fprintf(file, " + 3) & ~3");
if (ptype->itIndefinite) {
fprintf(file, " : sizeof(%s *)",
FetchServerType(ptype->itElement));
}
}
static void
WriteAdjustMsgSize(FILE *file, register const argument_t *arg)
{
register routine_t *rt = arg->argRoutine;
register ipc_type_t *ptype = arg->argType;
fprintf(file, "\tmsgh_size_delta = ");
WriteArgSize(file, arg);
fprintf(file, ";\n");
if (rt->rtNumReplyVar == 1)
fprintf(file, "\tOutP->Head.msgh_size = %d + msgh_size_delta;\n",
rt->rtReplySize);
else
if (arg->argReplyPos == 0)
fprintf(file, "\tmsgh_size = %d + msgh_size_delta;\n",
rt->rtReplySize);
else
fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
fprintf(file,
"\tOutP = (Reply *) ((char *) OutP + msgh_size_delta - %d);\n",
ptype->itTypeSize + ptype->itPadSize);
}
static void
WriteFinishMsgSize(FILE *file, register const argument_t *arg)
{
if (arg->argReplyPos == 0) {
fprintf(file, "\tOutP->Head.msgh_size = %d + (",
arg->argRoutine->rtReplySize);
WriteArgSize(file, arg);
fprintf(file, ");\n");
}
else {
fprintf(file, "\tmsgh_size += ");
WriteArgSize(file, arg);
fprintf(file, ";\n");
}
}
static void
WritePackArg(FILE *file, register const argument_t *arg)
{
if (akCheck(arg->argKind, akbReplyInit))
WritePackArgType(file, arg);
if ((akIdent(arg->argKind) == akePoly) &&
akCheck(arg->argKind, akbReturnSnd))
WriteAdjustMsgSimple(file, arg);
if (akCheckAll(arg->argKind, akbReturnSnd|akbVarNeeded))
WritePackArgValue(file, arg);
else if (akCheckAll(arg->argKind, akbReturnSnd|akbVariable)) {
register const ipc_type_t *it = arg->argType;
if (it->itString) {
fprintf(file, "\tOutP->%s = strlen(OutP->%s) + 1;\n",
arg->argCount->argMsgField, arg->argMsgField);
} else if (it->itIndefinite) {
fprintf(file, "\tif (%sP != OutP->%s) {\n",
arg->argVarName,
arg->argMsgField);
fprintf(file, "\t\tOutP->%s%s.msgt_inline = FALSE;\n",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
if (arg->argDeallocate == d_YES)
fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = TRUE;\n",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "");
else if (arg->argDeallocate == d_MAYBE)
fprintf(file, "\t\tOutP->%s%s.msgt_deallocate = %s;\n",
arg->argTTName,
arg->argLongForm ? ".msgtl_header" : "",
arg->argDealloc->argVarName);
fprintf(file, "\t\t*((%s **)OutP->%s) = %sP;\n",
FetchServerType(it->itElement),
arg->argMsgField,
arg->argVarName);
if (!arg->argRoutine->rtSimpleFixedReply)
fprintf(file, "\t\tmsgh_simple = FALSE;\n");
fprintf(file, "\t}\n");
}
}
if (akCheck(arg->argKind, akbReplyCopy))
WriteCopyArgValue(file, arg);
if (IsKernelServer &&
akCheck(arg->argKind, akbReturnSnd) &&
((arg->argType->itOutName == MACH_MSG_TYPE_PORT_RECEIVE) ||
(arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)))
WriteAdjustMsgCircular(file, arg);
}
static void
WritePackReplyArgs(FILE *file, register const routine_t *rt)
{
register const argument_t *arg;
register const argument_t *lastVarArg;
lastVarArg = argNULL;
for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
if (lastVarArg != argNULL &&
lastVarArg->argReplyPos < arg->argReplyPos)
{
WriteAdjustMsgSize(file, lastVarArg);
lastVarArg = argNULL;
}
WritePackArg(file, arg);
if (akCheckAll(arg->argKind, akbReturnSnd|akbVariable))
lastVarArg = arg;
}
if (lastVarArg != argNULL)
WriteFinishMsgSize(file, lastVarArg);
}
static void
WriteFieldDecl(FILE *file, const argument_t *arg)
{
WriteFieldDeclPrim(file, arg, FetchServerType);
}
static void
WriteRoutine(FILE *file, register const routine_t *rt)
{
fprintf(file, "\n");
fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
fprintf(file, "mig_internal void _X%s\n", rt->rtName);
fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
fprintf(file, "{\n");
WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request");
WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply");
WriteVarDecls(file, rt);
WriteList(file, rt->rtArgs, WriteCheckDecl, akbRequestQC, "\n", "\n");
WriteList(file, rt->rtArgs,
IsKernelServer ? WriteTypeDeclOut : WriteTypeDeclIn,
akbReplyInit, "\n", "\n");
WriteList(file, rt->rtArgs, WriteLocalVarDecl,
akbVarNeeded, ";\n", ";\n\n");
WriteList(file, rt->rtArgs, WriteLocalPtrDecl,
akbPointer, ";\n", ";\n\n");
WriteCheckHead(file, rt);
WriteTypeCheckRequestArgs(file, rt);
WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", "");
WriteServerCall(file, rt);
WriteGetReturnValue(file, rt);
WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", "");
if (rt->rtOneWay || rt->rtNoReplyArgs)
{
if (IsKernelServer)
{
if (rtCheckMaskFunction(rt->rtArgs, akbSendBody|akbSendRcv,
CheckDestroyPortArg))
{
WriteCheckReturnValue(file, rt);
}
WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg,
akbSendBody|akbSendRcv, "", "");
}
}
else
{
WriteCheckReturnValue(file, rt);
if (IsKernelServer)
WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg,
akbSendBody|akbSendRcv, "", "");
WriteReplyInit(file, rt);
WritePackReplyArgs(file, rt);
WriteReplyHead(file, rt);
}
fprintf(file, "}\n");
}
void
WriteServer(FILE *file, const statement_t *stats)
{
register const statement_t *stat;
WriteProlog(file);
for (stat = stats; stat != stNULL; stat = stat->stNext)
switch (stat->stKind)
{
case skRoutine:
WriteRoutine(file, stat->stRoutine);
break;
case skImport:
case skSImport:
WriteImport(file, stat->stFileName);
break;
case skUImport:
break;
default:
fatal("WriteServer(): bad statement_kind_t (%d)",
(int) stat->stKind);
}
WriteEpilog(file, stats);
}