bootstrap_cmds/migcom.tproj/user.c

bootstrap_cmds source @ c71d2d7 2025-04-30 · 3255 lines · view on GitHub
1/* 2 * Copyright (c) 1999-2018 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23/* 24 * Mach Operating System 25 * Copyright (c) 1991,1990 Carnegie Mellon University 26 * All Rights Reserved. 27 * 28 * Permission to use, copy, modify and distribute this software and its 29 * documentation is hereby granted, provided that both the copyright 30 * notice and this permission notice appear in all copies of the 31 * software, derivative works or modified versions, and any portions 32 * thereof, and that both notices appear in supporting documentation. 33 * 34 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS 35 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 36 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 37 * 38 * Carnegie Mellon requests users of this software to return to 39 * 40 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 41 * School of Computer Science 42 * Carnegie Mellon University 43 * Pittsburgh PA 15213-3890 44 * 45 * any improvements or extensions that they make and grant Carnegie the 46 * rights to redistribute these changes. 47 */ 48 49#include <stdlib.h> 50#include <assert.h> 51 52#include <mach/message.h> 53#include "write.h" 54#include "error.h" 55#include "utils.h" 56#include "global.h" 57 58#ifndef USE_IMMEDIATE_SEND_TIMEOUT 59#define USE_IMMEDIATE_SEND_TIMEOUT 0 60#endif 61 62char *MessAllocRoutine = "mig_user_allocate"; 63char *MessFreeRoutine = "mig_user_deallocate"; 64 65char stRetCode[] = "ReturnValue"; 66char stRetNone[] = ""; 67 68void WriteLogDefines(FILE *file, string_t who); 69void WriteIdentificationString(FILE *file); 70 71static void 72WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t overwrite, boolean_t varying, argument_t *arg, boolean_t bracket) 73{ 74 ipc_type_t *it = arg->argType; 75 char string[MAX_STR_LEN]; 76 77 fprintf(file, "\t{\n"); 78 fprintf(file, "\t %s\t*ptr;\n", it->itKPDType); 79 fprintf(file, "\t int\ti"); 80 if (varying && !in) 81 fprintf(file, ", j"); 82 fprintf(file, ";\n\n"); 83 84 if (in) 85 sprintf(string, "InP"); 86 else if (overwrite) 87 sprintf(string, "InOvTemplate"); 88 else 89 sprintf(string, "Out%dP", arg->argRequestPos); 90 91 fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField); 92 93 if (varying) { 94 argument_t *count = arg->argCount; 95 char *cref = count->argByReferenceUser ? "*" : ""; 96 97 if (in || overwrite) { 98 fprintf(file, "\t if (%s%s > %d)\n", cref, count->argVarName, it->itKPD_Number); 99 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); 100 fprintf(file, "\t for (i = 0; i < %s%s; ptr++, i++) %s\n", cref, count->argVarName, (bracket) ? "{" : ""); 101 } 102 else { 103 fprintf(file, "\t j = min(Out%dP->%s, %s%s);\n", count->argReplyPos, count->argVarName, cref, count->argVarName); 104 fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n",(bracket) ? "{" : ""); 105} 106 } 107 else 108 fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : ""); 109} 110 111/************************************************************* 112 * Writes the standard includes. The subsystem specific 113 * includes are in <SubsystemName>.h and writen by 114 * header:WriteHeader. Called by WriteProlog. 115 *************************************************************/ 116static void 117WriteMyIncludes(FILE *file, statement_t *stats) 118{ 119#ifdef MIG_KERNEL_PORT_CONVERSION 120 if (IsKernelServer) 121 { 122 /* 123 * We want to get the user-side definitions of types 124 * like task_t, ipc_space_t, etc. in mach/mach_types.h. 125 */ 126 127 fprintf(file, "#undef\tMACH_KERNEL\n"); 128 129 if (InternalHeaderFileName != strNULL) 130 { 131 char *cp; 132 133 /* Strip any leading path from InternalHeaderFileName. */ 134 cp = strrchr(InternalHeaderFileName, '/'); 135 if (cp == 0) 136 cp = InternalHeaderFileName; 137 else 138 cp++; /* skip '/' */ 139 fprintf(file, "#include \"%s\"\n", cp); 140 } 141 } 142#endif 143 144 if (UserHeaderFileName == strNULL || UseSplitHeaders) 145 WriteIncludes(file, TRUE, FALSE); 146 if (UserHeaderFileName != strNULL) 147 { 148 char *cp; 149 150 /* Strip any leading path from UserHeaderFileName. */ 151 cp = strrchr(UserHeaderFileName, '/'); 152 if (cp == 0) 153 cp = UserHeaderFileName; 154 else 155 cp++; /* skip '/' */ 156 fprintf(file, "#include \"%s\"\n", cp); 157 } 158 if (UseSplitHeaders) 159 WriteImplImports(file, stats, TRUE); 160 161 if (UseEventLogger) { 162 if (IsKernelUser) { 163 fprintf(file, "#if\t__MigKernelSpecificCode\n"); 164 fprintf(file, "#include <mig_debug.h>\n"); 165 fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n"); 166 } 167 fprintf(file, "#if MIG_DEBUG\n"); 168 fprintf(file, "#include <mach/mig_log.h>\n"); 169 fprintf(file, "#endif /* MIG_DEBUG */\n"); 170 } 171 if (HasConsumeOnSendError && !IsKernelUser) { 172 fprintf(file, "#include <mach/mach.h>\n"); 173 } 174 if (BeLint) { 175 fprintf(file, "/* LINTLIBRARY */\n"); 176 } 177 fprintf(file, "\n"); 178 if (!BeAnsiC) { 179 fprintf(file, "#if\t%s\n", NewCDecl); 180 fprintf(file, "#else\t/* %s */\n", NewCDecl); 181 fprintf(file, "extern mach_port_t mig_get_reply_port();\n"); 182 fprintf(file, "extern void mig_dealloc_reply_port();\n"); 183 fprintf(file, "extern char *%s();\n", MessAllocRoutine); 184 fprintf(file, "extern void %s();\n", MessFreeRoutine); 185 fprintf(file, "#endif\t/* %s */\n", NewCDecl); 186 } 187 if (HasUseSpecialReplyPort) { 188 fprintf(file, "\n"); 189 fprintf(file, "#include <TargetConditionals.h>\n"); 190 fprintf(file, "#include <mach/mach_sync_ipc.h>\n"); 191 fprintf(file, "#ifndef __MigSpecialReplyPortMsgOption\n"); 192 fprintf(file, "#define __MigSpecialReplyPortMsgOption " 193 "(MACH_SEND_SYNC_OVERRIDE|MACH_SEND_SYNC_USE_THRPRI|MACH_RCV_SYNC_WAIT)\n"); 194 fprintf(file, "#endif /* __MigSpecialReplyPortMsgOption */\n"); 195 } 196 if (IsKernelServer) { 197 fprintf(file, "\n"); 198 fprintf(file, "#include <TargetConditionals.h>\n"); 199 fprintf(file, "#if defined(MACH_SEND_AUX_TOO_SMALL) && (defined(__arm64__) || defined(__LP64__))\n"); 200 fprintf(file, "#undef mach_msg\n"); 201 fprintf(file, "#define mach_msg mig_mach_msg\n"); 202 fprintf(file, "static inline mach_msg_return_t\n"); 203 fprintf(file, "mig_mach_msg(\n"); 204 fprintf(file, "\tmach_msg_header_t *msg,\n"); 205 fprintf(file, "\tmach_msg_option_t option,\n"); 206 fprintf(file, "\tmach_msg_size_t send_size,\n"); 207 fprintf(file, "\tmach_msg_size_t rcv_size,\n"); 208 fprintf(file, "\tmach_port_name_t rcv_name,\n"); 209 fprintf(file, "\tmach_msg_timeout_t timeout,\n"); 210 fprintf(file, "\tmach_port_name_t notify)\n"); 211 fprintf(file, "{\n"); 212 fprintf(file, "\t(void)notify;\n"); 213 fprintf(file, "\treturn mach_msg2(msg, option | MACH64_SEND_KOBJECT_CALL,\n"); 214 fprintf(file, "\t\t*msg, send_size, rcv_size, rcv_name, timeout, 0);\n"); 215 fprintf(file, "}\n"); 216 fprintf(file, "#endif\n"); 217 } 218 /* 219 * extern the definition of mach_msg_destroy 220 * (to avoid inserting mach/mach.h everywhere) 221 */ 222 fprintf(file, "/* TODO: #include <mach/mach.h> */\n"); 223 fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n"); 224 fprintf(file, "extern void mach_msg_destroy(mach_msg_header_t *);\n"); 225 fprintf(file, "#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n"); 226 227 fprintf(file, "\n"); 228} 229 230static void 231WriteGlobalDecls(FILE *file) 232{ 233 if (RCSId != strNULL) 234 WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId); 235 236 fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n"); 237 fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n"); 238 fprintf(file, "\n"); 239 if (UseEventLogger) 240 WriteLogDefines(file, "MACH_MSG_LOG_USER"); 241 fprintf(file, "\n"); 242} 243 244static void 245WriteOneMachErrorDefine(FILE *file, char *name, boolean_t timeout, boolean_t SpecialReplyPort) 246{ 247 fprintf(file, "#ifndef\t%s\n", name); 248 fprintf(file, "#define\t%s(_R_) { \\\n", name); 249 fprintf(file, "\tswitch (_R_) { \\\n"); 250 fprintf(file, "\tcase MACH_SEND_INVALID_DATA: \\\n"); 251 fprintf(file, "\tcase MACH_SEND_INVALID_DEST: \\\n"); 252 fprintf(file, "\tcase MACH_SEND_INVALID_HEADER: \\\n"); 253 if (!SpecialReplyPort) { 254 fprintf(file, "\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n"); 255 } 256 fprintf(file, "\t\tbreak; \\\n"); 257 if (timeout) { 258 fprintf(file, "\tcase MACH_SEND_TIMED_OUT: \\\n"); 259 fprintf(file, "\tcase MACH_RCV_TIMED_OUT: \\\n"); 260 } 261 fprintf(file, "\tdefault: \\\n"); 262 if (SpecialReplyPort) { 263 fprintf(file, "\t\tmig_dealloc_special_reply_port(InP->Head.msgh_reply_port); \\\n"); 264 } else { 265 fprintf(file, "\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n"); 266 } 267 fprintf(file, "\t} \\\n}\n"); 268 fprintf(file, "#endif\t/* %s */\n", name); 269 fprintf(file, "\n"); 270} 271 272static void 273WriteMachErrorDefines(FILE *file) 274{ 275 WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeout", TRUE, FALSE); 276 WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeout", FALSE, FALSE); 277 if (HasUseSpecialReplyPort) { 278 WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeoutSRP", TRUE, TRUE); 279 WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeoutSRP", FALSE, TRUE); 280 } 281} 282 283static void 284WriteMIGCheckDefines(FILE *file) 285{ 286 fprintf(file, "#define\t__MIG_check__Reply__%s_subsystem__ 1\n", SubsystemName); 287 fprintf(file, "\n"); 288} 289 290static void 291WriteNDRDefines(FILE *file) 292{ 293 fprintf(file, "#define\t__NDR_convert__Reply__%s_subsystem__ 1\n", SubsystemName); 294 fprintf(file, "#define\t__NDR_convert__mig_reply_error_subsystem__ 1\n"); 295 fprintf(file, "\n"); 296} 297 298/************************************************************* 299 * Writes the standard #includes, #defines, and 300 * RCS declaration. Called by WriteUser. 301 *************************************************************/ 302static void 303WriteProlog(FILE *file, statement_t *stats) 304{ 305 WriteIdentificationString(file); 306 WriteMIGCheckDefines(file); 307 if (CheckNDR) 308 WriteNDRDefines(file); 309 WriteMyIncludes(file, stats); 310 WriteBogusDefines(file); 311 WriteMachErrorDefines(file); 312 WriteApplDefaults(file, "Send"); 313 WriteGlobalDecls(file); 314} 315 316/*ARGSUSED*/ 317static void 318WriteEpilog(FILE *file) 319{ 320 /* nothing to see here, move along... */ 321} 322 323static string_t 324WriteHeaderPortType(argument_t *arg) 325{ 326 if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC) 327 return arg->argPoly->argVarName; 328 else 329 return arg->argType->itInNameStr; 330} 331 332static void 333WriteRequestHead(FILE *file, routine_t *rt) 334{ 335 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) 336 fprintf(file, "ready_to_send:\n"); 337 338 if (rt->rtMaxRequestPos > 0) { 339 if (rt->rtOverwrite) 340 fprintf(file, "\tInP = &MessRequest;\n"); 341 else 342 fprintf(file, "\tInP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->")); 343 } 344 345 if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) { 346#ifdef MIG_KERNEL_PORT_CONVERSION 347 if (IsKernelUser) 348 fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName); 349 else 350#endif 351 fprintf(file, "\tInP->%s = %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName); 352 } 353 else if (rt->rtOneWay) 354 fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n", rt->rtReplyPort->argMsgField); 355 else if (rt->rtUseSpecialReplyPort) 356 fprintf(file, "\tInP->%s = mig_get_special_reply_port();\n", rt->rtReplyPort->argMsgField); 357 else 358 fprintf(file, "\tInP->%s = mig_get_reply_port();\n", rt->rtReplyPort->argMsgField); 359 360 fprintf(file, "\tInP->Head.msgh_bits ="); 361 if (rt->rtRetCArg == argNULL && !rt->rtSimpleRequest) 362 fprintf(file, " MACH_MSGH_BITS_COMPLEX|"); 363 fprintf(file, "\n"); 364 fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n", WriteHeaderPortType(rt->rtRequestPort), WriteHeaderPortType(rt->rtReplyPort)); 365 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { 366 fprintf(file, "\tif (!%s)\n", rt->rtRetCArg->argVarName); 367 fprintf(file, "\t\tInP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n"); 368 } 369 370 if (!IsKernelServer) { 371 fprintf(file, "\t/* msgh_size passed as argument */\n"); 372 } else if (rt->rtNumRequestVar == 0) { 373 fprintf(file, "\tInP->Head.msgh_size = (mach_msg_size_t)sizeof(Request);\n"); 374 } else { 375 fprintf(file, "\tInP->Head.msgh_size = msgh_size;\n"); 376 } 377 378 /* 379 * KernelUser stubs need to cast the request and reply ports 380 * from ipc_port_t to mach_port_t. 381 */ 382 383#ifdef MIG_KERNEL_PORT_CONVERSION 384 if (IsKernelUser) 385 fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName); 386 else 387#endif 388 fprintf(file, "\tInP->%s = %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName); 389 390 fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase); 391 fprintf(file, "\tInP->Head.msgh_reserved = 0;\n"); 392 393 394 if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) { 395 fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n"); 396 fprintf(file, "#ifdef USING_VOUCHERS\n"); 397 fprintf(file, "\tif (voucher_mach_msg_set != NULL) {\n"); 398 fprintf(file, "\t\tvoucher_mach_msg_set(&InP->Head);\n"); 399 fprintf(file, "\t}\n"); 400 fprintf(file, "#endif // USING_VOUCHERS\n"); 401 fprintf(file, "\t\n/* END VOUCHER CODE */\n"); 402 } 403} 404 405/************************************************************* 406 * Writes declarations for the message types, variables 407 * and return variable if needed. Called by WriteRoutine. 408 *************************************************************/ 409static void 410WriteVarDecls(FILE *file, routine_t *rt) 411{ 412 int i; 413 414 if (rt->rtOverwrite) { 415 fprintf(file, "\tRequest MessRequest;\n"); 416 fprintf(file, "\tRequest *InP = &MessRequest;\n\n"); 417 418 fprintf(file, "\tunion {\n"); 419 fprintf(file, "\t\tOverwriteTemplate In;\n"); 420 fprintf(file, "\t\tReply Out;\n"); 421 fprintf(file, "\t} MessReply;\n"); 422 423 fprintf(file, "\tOverwriteTemplate *InOvTemplate = &MessReply.In;\n"); 424 fprintf(file, "\tReply *Out0P = &MessReply.Out;\n"); 425 for (i = 1; i <= rt->rtMaxReplyPos; i++) 426 fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i); 427 } 428 else { 429 if (rtMessOnStack(rt)) 430 fprintf(file, "\tunion {\n"); 431 else 432 fprintf(file, "\tunion %sMessU {\n", rt->rtName); 433 fprintf(file, "\t\tRequest In;\n"); 434 if (!rt->rtOneWay) 435 fprintf(file, "\t\tReply Out;\n"); 436 if (rtMessOnStack(rt)) 437 fprintf(file, "\t} Mess;\n"); 438 else 439 fprintf(file, "\t} *Mess = (union %sMessU *) %s(sizeof(*Mess));\n", 440 rt->rtName, MessAllocRoutine); 441 fprintf(file, "\n"); 442 443 fprintf(file, "\tRequest *InP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->")); 444 if (!rt->rtOneWay) { 445 fprintf(file, "\tReply *Out0P = &Mess%sOut;\n", (rtMessOnStack(rt) ? "." : "->")); 446 for (i = 1; i <= rt->rtMaxReplyPos; i++) 447 fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i); 448 } 449 } 450 451 fprintf(file, "\n"); 452 453 fprintf(file, "\tmach_msg_return_t msg_result;\n"); 454 455 /* if request is variable, we need msgh_size_delta and msgh_size */ 456 if (rt->rtNumRequestVar > 0) 457 fprintf(file, "\tunsigned int msgh_size;\n"); 458 if (rt->rtMaxRequestPos > 0) 459 fprintf(file, "\tunsigned int msgh_size_delta;\n"); 460 if (rt->rtNumRequestVar > 1 || rt->rtMaxRequestPos > 0) 461 fprintf(file, "\n"); 462 463 if (rt->rtUserImpl) { 464 fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n"); 465 fprintf(file, "#if\t__MigTypeCheck\n"); 466 fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n"); 467 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 468 } 469 fprintf(file, "\n"); 470 fprintf(file, "#ifdef\t__MIG_check__Reply__%s_t__defined\n", rt->rtName); 471 fprintf(file, "\tkern_return_t check_result;\n"); 472 fprintf(file, "#endif\t/* __MIG_check__Reply__%s_t__defined */\n", rt->rtName); 473 fprintf(file, "\n"); 474 WriteApplMacro(file, "Send", "Declare", rt); 475 fprintf(file, "\n"); 476} 477 478static void 479WriteReturn(FILE *file, routine_t *rt, char *before, char *value, char *after, boolean_t deallocate_mess) 480{ 481 if (rtMessOnStack(rt)) { 482 if (value != stRetCode) { 483 /* get the easy case (no braces needed) out of the way */ 484 fprintf(file, "%sreturn%s%s;%s", before, (*value ? " " : ""), value, after); 485 return; 486 } 487 else { 488 fprintf(file, "%s{\n", before); 489 fprintf(file, "%s\treturn Out0P->RetCode;\n%s}%s", before, before, after); 490 return; 491 } 492 } 493 494 if (value == stRetCode) { 495 fprintf(file, "%s{\n%s\t%s ReturnValue;\n", before, before, ReturnTypeStr(rt)); 496 fprintf(file, "%s\tReturnValue = Out0P->RetCode;\n%s\t", before, before); 497 } 498 else { 499 fprintf(file, "%s{ ", before); 500 } 501 502 if (deallocate_mess) { 503 fprintf(file, "%s((char *) Mess, sizeof(*Mess)); ", MessFreeRoutine); 504 } 505 506 if (value == stRetCode) 507 fprintf(file, "return ReturnValue;\n%s}%s", before, after); 508 else if (value == stRetNone) 509 fprintf(file, "return; }%s", after); 510 else 511 fprintf(file, "return %s; }%s", value, after); 512} 513 514static void 515WriteRetCodeArg(FILE *file, routine_t *rt) 516{ 517 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { 518 argument_t *arg = rt->rtRetCArg; 519 520 fprintf(file, "\tif (%s) {\n", arg->argVarName); 521 fprintf(file, "\t\t((mig_reply_error_t *)InP)->RetCode = %s;\n", arg->argVarName); 522 fprintf(file, "\t\t((mig_reply_error_t *)InP)->NDR = NDR_record;\n"); 523 fprintf(file, "\t\tgoto ready_to_send;\n"); 524 fprintf(file, "\t}\n\n"); 525 } 526} 527 528/************************************************************* 529 * Writes the logic to check for a message send timeout, and 530 * deallocate any relocated ool data so as not to leak. 531 *************************************************************/ 532static void 533WriteMsgCheckForSendErrors(FILE *file, routine_t *rt) 534{ 535 if (rt->rtConsumeOnSendError != ConsumeOnSendErrorAny && rt->rtWaitTime == argNULL) { 536 return; 537 } 538 539 if (rt->rtConsumeOnSendError == ConsumeOnSendErrorAny) { 540 // other errors mean the kernel consumed some of the rights 541 // and we can't possibly know if there's something left to destroy 542 fputs("\n" 543 "\t" "if (msg_result == MACH_SEND_INVALID_DEST ||" "\n" 544 "\t\t" "msg_result == MACH_SEND_TIMED_OUT) {" "\n", file); 545 } else { 546 fputs("\n" 547 "\t" "if (msg_result == MACH_SEND_TIMED_OUT) {" "\n", file); 548 } 549 550 if (rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) { 551 argument_t *arg_ptr; 552 553 // iterate over arg list 554 for (arg_ptr = rt->rtArgs; arg_ptr != NULL; arg_ptr = arg_ptr->argNext) { 555 556 // if argument contains ool data 557 if (akCheck(arg_ptr->argKind, akbSendKPD) && arg_ptr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { 558 // generate code to test current arg address vs. address before the msg_send call 559 // if not at the same address, mig_deallocate the argument 560 fprintf(file, "\t\t" "if((vm_offset_t) InP->%s.address != (vm_offset_t) %s)\n", 561 arg_ptr->argVarName, arg_ptr->argVarName); 562 fprintf(file, "\t\t\t" "mig_deallocate((vm_offset_t) InP->%s.address, " 563 "(vm_size_t) InP->%s.size);\n", arg_ptr->argVarName, arg_ptr->argVarName); 564 } 565 } 566 } else { 567 /* 568 * The original MIG would leak most resources on send timeout without 569 * leaving a chance for callers to know how to dispose of most of the 570 * resources, as the caller can't possibly guess the new names 571 * picked during pseudo-receive. 572 */ 573 if (IsKernelUser) { 574 fputs("#if\t__MigKernelSpecificCode" "\n", file); 575 fputs("\t\t" "mach_msg_destroy_from_kernel(&InP->Head);" "\n", file); 576 fputs("#endif\t/* __MigKernelSpecificCode */" "\n", file); 577 } else { 578 fputs("\t\t" "/* mach_msg_destroy doesn't handle the local port */" "\n", file); 579 fputs("\t\t" "switch (MACH_MSGH_BITS_LOCAL(InP->Head.msgh_bits)) {" "\n", file); 580 fputs("\t\t" "case MACH_MSG_TYPE_MOVE_SEND:" "\n", file); 581 fputs("\t\t\t" "mach_port_deallocate(mach_task_self(), InP->Head.msgh_local_port);" "\n", file); 582 fputs("\t\t\t" "break;" "\n", file); 583 fputs("\t\t" "}" "\n", file); 584 fputs("\t\t" "mach_msg_destroy(&InP->Head);" "\n", file); 585 } 586 } 587 588 fputs("\t" "}" "\n\n", file); 589 return; 590} 591 592/************************************************************* 593 * Writes the send call when there is to be no subsequent 594 * receive. Called by WriteRoutine SimpleRoutines 595 *************************************************************/ 596static void 597WriteMsgSend(FILE *file, routine_t *rt) 598{ 599 char *SendSize = ""; 600 char string[MAX_STR_LEN]; 601 602 if (rt->rtNumRequestVar == 0) 603 SendSize = "(mach_msg_size_t)sizeof(Request)"; 604 else 605 SendSize = "msgh_size"; 606 607 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { 608 sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName); 609 SendSize = strconcat(string, SendSize); 610 } 611 612 if (IsKernelUser) { 613 fprintf(file, "#if\t__MigKernelSpecificCode\n"); 614 fprintf(file, "\tmsg_result = mach_msg_send_from_kernel("); 615 fprintf(file, "&InP->Head, %s);\n", SendSize); 616 fprintf(file, "#else\n"); 617 } 618 fprintf(file, "\tmsg_result = mach_msg(" 619 "&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, MACH_PORT_NULL, %s, MACH_PORT_NULL);\n", 620 rt->rtWaitTime !=argNULL ? "MACH_SEND_TIMEOUT|" : "", 621 rt->rtMsgOption->argVarName, 622 SendSize, 623 rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName:"MACH_MSG_TIMEOUT_NONE"); 624 625 if (IsKernelUser) { 626 fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); 627 } 628 629 WriteApplMacro(file, "Send", "After", rt); 630 631 WriteMsgCheckForSendErrors(file, rt); 632 633 WriteReturn(file, rt, "\t", "msg_result", "\n", TRUE); 634} 635 636/************************************************************* 637 * Writes to code to check for error returns from receive. 638 * Called by WriteMsgSendReceive and WriteMsgRPC 639 *************************************************************/ 640static void 641WriteMsgCheckReceiveCleanupMigReplyPort(FILE *file, routine_t *rt, char *success) 642{ 643 if (!akCheck(rt->rtReplyPort->argKind, akbUserArg)) 644 { 645 /* If we aren't using a user-supplied reply port, then 646 deallocate the reply port when it is invalid or 647 for TIMED_OUT errors. */ 648 fprintf(file, "\tif (msg_result != %s) {\n", success); 649 if (rt->rtWaitTime != argNULL) { 650 fprintf(file, "\t\t__MachMsgErrorWithTimeout%s(msg_result);\n", 651 rt->rtUseSpecialReplyPort ? "SRP" : ""); 652 } else { 653 fprintf(file, "\t\t__MachMsgErrorWithoutTimeout%s(msg_result);\n", 654 rt->rtUseSpecialReplyPort ? "SRP" : ""); 655 } 656 fprintf(file, "\t}\n"); 657 } 658} 659 660static void 661WriteMsgCheckReceive(FILE *file, routine_t *rt, char *success) 662{ 663 fprintf(file, "\tif (msg_result != %s) {\n", success); 664 WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result"); 665 fprintf(file, "\t}\n"); 666} 667 668/************************************************************* 669 * Writes the send and receive calls and code to check 670 * for errors. Normally the rpc code is generated instead 671 * although, the subsytem can be compiled with the -R option 672 * which will cause this code to be generated. Called by 673 * WriteRoutine if UseMsgRPC option is false. 674 *************************************************************/ 675static void 676WriteMsgSendReceive(FILE *file, routine_t *rt) 677{ 678 char *SendSize = ""; 679 char string[MAX_STR_LEN]; 680 681 if (rt->rtNumRequestVar == 0) 682 SendSize = "(mach_msg_size_t)sizeof(Request)"; 683 else 684 SendSize = "msgh_size"; 685 686 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { 687 sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName); 688 SendSize = strconcat(string, SendSize); 689 } 690 691 /* IsKernelUser to be done! */ 692 fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, ", rt->rtWaitTime != argNULL ? "MACH_SEND_TIMEOUT|" : "", rt->rtMsgOption->argVarName, SendSize); 693 fprintf(file, " MACH_PORT_NULL, %s, MACH_PORT_NULL);\n", 694#if !USE_IMMEDIATE_SEND_TIMEOUT 695 (rt->rtWaitTime != argNULL) ? rt->rtWaitTime->argVarName : 696#endif 697 "MACH_MSG_TIMEOUT_NONE"); 698 fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n"); 699 WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result"); 700 fprintf(file, "\n"); 701 702 fprintf(file, "\tmsg_result = mach_msg(&Out0P->Head, MACH_RCV_MSG|%s%s%s, 0, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n", 703 rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "", 704 (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? "MACH_RCV_TIMEOUT|" : "", 705 rt->rtMsgOption->argVarName, 706 (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); 707 WriteApplMacro(file, "Send", "After", rt); 708 WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS"); 709 WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS"); 710 fprintf(file, "\n"); 711} 712 713/************************************************************* 714 * Writes the rpc call and the code to check for errors. 715 * This is the default code to be generated. Called by WriteRoutine 716 * for all routine types except SimpleRoutine. 717 *************************************************************/ 718static void 719WriteMsgRPC(FILE *file, routine_t *rt) 720{ 721 char *SendSize = ""; 722 char string[MAX_STR_LEN]; 723 724 if (rt->rtNumRequestVar == 0) 725 SendSize = "(mach_msg_size_t)sizeof(Request)"; 726 else 727 SendSize = "msgh_size"; 728 729 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { 730 sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName); 731 SendSize = strconcat(string, SendSize); 732 } 733 734 if (IsKernelUser) { 735 fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNELSPECIFIC_CODE_)\n"); 736 fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, (mach_msg_size_t)sizeof(Reply));\n", SendSize); 737 fprintf(file, "#else\n"); 738 } 739 if (rt->rtOverwrite) { 740 fprintf(file, "\tmsg_result = mach_msg_overwrite(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_OVERWRITE|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL, ", 741 rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "", 742 rt->rtWaitTime != argNULL ? 743 (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "", 744 rt->rtMsgOption->argVarName, 745 SendSize, 746 rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); 747 fprintf(file, " &InOvTemplate->Head, (mach_msg_size_t)sizeof(OverwriteTemplate));\n"); 748 } 749 else { 750 fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n", 751 rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "", 752 rt->rtWaitTime != argNULL ? 753 (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "", 754 rt->rtMsgOption->argVarName, 755 SendSize, 756 rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); 757 } 758 if (IsKernelUser) 759 fprintf(file,"#endif /* __MigKernelSpecificCode */\n"); 760 WriteApplMacro(file, "Send", "After", rt); 761 762 WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS"); 763 WriteMsgCheckForSendErrors(file, rt); 764 765 WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS"); 766 fprintf(file, "\n"); 767} 768 769/* 770 * argKPD_Pack discipline for Port types. 771 */ 772static void 773WriteKPD_port(FILE *file, argument_t *arg) 774{ 775 ipc_type_t *it = arg->argType; 776 char *subindex = ""; 777 char *recast = ""; 778 char firststring[MAX_STR_LEN]; 779 char string[MAX_STR_LEN]; 780 char *ref = arg->argByReferenceUser ? "*" : ""; 781 ipc_type_t *real_it; 782 783 if (IS_MULTIPLE_KPD(it)) { 784 WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE); 785 (void)sprintf(firststring, "\t*ptr"); 786 (void)sprintf(string, "\tptr->"); 787 subindex = "[i]"; 788 real_it = it->itElement; 789 } 790 else { 791 (void)sprintf(firststring, "InP->%s", arg->argMsgField); 792 (void)sprintf(string, "InP->%s.", arg->argMsgField); 793 real_it = it; 794 } 795 796#ifdef MIG_KERNEL_PORT_CONVERSION 797 if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t")) 798 recast = "(mach_port_t)"; 799#endif 800 fprintf(file, "#if\tUseStaticTemplates\n"); 801 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); 802 /* ref is required also in the Request part, because of inout parameters */ 803 fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex); 804 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { 805 argument_t *poly = arg->argPoly; 806 807 fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName); 808 } 809 fprintf(file, "#else\t/* UseStaticTemplates */\n"); 810 fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex); 811 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { 812 argument_t *poly = arg->argPoly; 813 814 fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName); 815 } 816 else 817 fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr); 818 fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string); 819 fprintf(file, "#endif\t/* UseStaticTemplates */\n"); 820 if (IS_MULTIPLE_KPD(it)) { 821 fprintf(file, "\t }\n"); 822 if (it->itVarArray) { 823 fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number); 824 /* fill the rest of the statically allocated KPD entries with MACH_PORT_NULL */ 825 fprintf(file, "#if\tUseStaticTemplates\n"); 826 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); 827 fprintf(file, "#else\t/* UseStaticTemplates */\n"); 828 fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string); 829 fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string); 830 fprintf(file, "#endif\t/* UseStaticTemplates */\n"); 831 fprintf(file, "\t }\n"); 832 } 833 fprintf(file, "\t}\n"); 834 } 835 fprintf(file, "\n"); 836} 837 838static void 839WriteKPD_ool_varsize(FILE *file, argument_t *arg, char *who, char *where, boolean_t iscomplex) 840{ 841 ipc_type_t *it = arg->argType; 842 argument_t *count; 843 char *cref; 844 845 if (iscomplex) { 846 it = it->itElement; 847 count = arg->argSubCount; 848 } 849 else 850 count = arg->argCount; 851 cref = count->argByReferenceUser ? "*" : ""; 852 853 /* size has to be expressed in bytes! */ 854 if (count->argMultiplier > 1 || it->itSize > 8) 855 fprintf(file, "\t%s->%s = %s%s%s * %d;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "", count->argMultiplier * it->itSize / 8); 856 else 857 fprintf(file, "\t%s->%s = %s%s%s;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : ""); 858} 859 860/* 861 * argKPD_Pack discipline for out-of-line types. 862 */ 863static void 864WriteKPD_ool(FILE *file, argument_t *arg) 865{ 866 ipc_type_t *it = arg->argType; 867 char *ref = arg->argByReferenceUser ? "*" : ""; 868 char firststring[MAX_STR_LEN]; 869 char string[MAX_STR_LEN]; 870 boolean_t VarArray; 871 u_int howmany, howbig; 872 char *subindex; 873 874 if (IS_MULTIPLE_KPD(it)) { 875 WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE); 876 (void)sprintf(firststring, "\t*ptr"); 877 (void)sprintf(string, "\tptr->"); 878 VarArray = it->itElement->itVarArray; 879 howmany = it->itElement->itNumber; 880 howbig = it->itElement->itSize; 881 subindex = "[i]"; 882 } 883 else { 884 (void)sprintf(firststring, "InP->%s", arg->argMsgField); 885 (void)sprintf(string, "InP->%s.", arg->argMsgField); 886 VarArray = it->itVarArray; 887 howmany = it->itNumber; 888 howbig = it->itSize; 889 subindex = ""; 890 } 891 892 fprintf(file, "#if\tUseStaticTemplates\n"); 893 894 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); 895 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); 896 if (VarArray) { 897 if (IS_MULTIPLE_KPD(it)) 898 WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE); 899 else 900 WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE); 901 } 902 903 if (arg->argDeallocate == d_MAYBE) 904 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); 905 906 fprintf(file, "#else\t/* UseStaticTemplates */\n"); 907 908 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); 909 if (VarArray) 910 if (IS_MULTIPLE_KPD(it)) 911 WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE); 912 else 913 WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE); 914 else 915 fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8); 916 if (arg->argDeallocate == d_MAYBE) 917 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); 918 else 919 fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); 920 fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY"); 921#ifdef ALIGNMENT 922 fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, (it->itElement->itSize < 8) ? 1 : it->itElement->itSize / 8); 923#endif 924 fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string); 925 926 fprintf(file, "#endif\t/* UseStaticTemplates */\n"); 927 if (IS_MULTIPLE_KPD(it)) { 928 fprintf(file, "\t }\n"); 929 if (it->itVarArray) { 930 fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number); 931 /* fill the rest of the statically allocated KPD entries with size NULL */ 932 fprintf(file, "#if\tUseStaticTemplates\n"); 933 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); 934 if (!VarArray) 935 fprintf(file, "\t%ssize = 0;\n", string); 936 /* otherwise the size in the template would be != 0! */ 937 fprintf(file, "#else\t/* UseStaticTemplates */\n"); 938 fprintf(file, "\t%ssize = 0;\n", string); 939 fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string); 940 fprintf(file, "#endif\t/* UseStaticTemplates */\n"); 941 fprintf(file, "\t }\n"); 942 } 943 fprintf(file, "\t}\n"); 944 } 945 fprintf(file, "\n"); 946} 947 948/* 949 * argKPD_Pack discipline for out-of-line Port types. 950 */ 951static void 952WriteKPD_oolport(FILE *file, argument_t *arg) 953{ 954 ipc_type_t *it = arg->argType; 955 char *ref = arg->argByReferenceUser ? "*" : ""; 956 argument_t *count; 957 boolean_t VarArray; 958 string_t howstr; 959 u_int howmany; 960 char *subindex; 961 char firststring[MAX_STR_LEN]; 962 char string[MAX_STR_LEN]; 963 964 if (IS_MULTIPLE_KPD(it)) { 965 WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE); 966 (void)sprintf(firststring, "\t*ptr"); 967 (void)sprintf(string, "\tptr->"); 968 VarArray = it->itElement->itVarArray; 969 howmany = it->itElement->itNumber; 970 howstr = it->itElement->itInNameStr; 971 count = arg->argSubCount; 972 subindex = "[i]"; 973 } 974 else { 975 (void)sprintf(firststring, "InP->%s", arg->argMsgField); 976 (void)sprintf(string, "InP->%s.", arg->argMsgField); 977 VarArray = it->itVarArray; 978 howmany = it->itNumber; 979 howstr = it->itInNameStr; 980 count = arg->argCount; 981 subindex = ""; 982 } 983 984 fprintf(file, "#if\tUseStaticTemplates\n"); 985 986 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); 987 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); 988 if (VarArray) 989 fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex); 990 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { 991 argument_t *poly = arg->argPoly; 992 char *pref = poly->argByReferenceUser ? "*" : ""; 993 994 fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName); 995 } 996 if (arg->argDeallocate == d_MAYBE) 997 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); 998 999 fprintf(file, "#else\t/* UseStaticTemplates */\n"); 1000 1001 fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); 1002 if (VarArray) 1003 fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex); 1004 else 1005 fprintf(file, "\t%scount = %d;\n", string, howmany); 1006 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { 1007 argument_t *poly = arg->argPoly; 1008 char *pref = poly->argByReferenceUser ? "*" : ""; 1009 1010 fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName); 1011 } 1012 else 1013 fprintf(file, "\t%sdisposition = %s;\n", string, howstr); 1014 if (arg->argDeallocate == d_MAYBE) 1015 fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); 1016 else 1017 fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); 1018 fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string); 1019 1020 fprintf(file, "#endif\t/* UseStaticTemplates */\n"); 1021 fprintf(file, "\n"); 1022 1023 if (IS_MULTIPLE_KPD(it)) { 1024 fprintf(file, "\t }\n"); 1025 if (it->itVarArray) { 1026 fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number); 1027 /* fill the rest of the statically allocated KPD entries with size NULL */ 1028 fprintf(file, "#if\tUseStaticTemplates\n"); 1029 fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); 1030 if (!VarArray) 1031 fprintf(file, "\t%scount = 0;\n", string); 1032 /* otherwise the size in the template would be != 0! */ 1033 fprintf(file, "#else\t/* UseStaticTemplates */\n"); 1034 fprintf(file, "\t%scount = 0;\n", string); 1035 fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string); 1036 fprintf(file, "#endif\t/* UseStaticTemplates */\n"); 1037 fprintf(file, "\t }\n"); 1038 } 1039 fprintf(file, "\t}\n"); 1040 } 1041 fprintf(file, "\n"); 1042} 1043 1044static void 1045WriteOverwriteTemplate(FILE *file, routine_t *rt) 1046{ 1047 argument_t *arg; 1048 char string[MAX_STR_LEN]; 1049 char *subindex = ""; 1050 boolean_t finish = FALSE; 1051 1052 fprintf(file, "\t/* Initialize the template for overwrite */\n"); 1053 fprintf(file, "\tInOvTemplate->msgh_body.msgh_descriptor_count = %d;\n", rt->rtOverwriteKPDs); 1054 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1055 ipc_type_t *it = arg->argType; 1056 char *ref = arg->argByReferenceUser ? "*" : ""; 1057 argument_t *count; 1058 char *cref; 1059 boolean_t VarIndex; 1060 u_int howmany, howbig; 1061 1062 if (akCheck(arg->argKind, akbOverwrite)) { 1063 if (arg->argFlags & flOverwrite) { 1064 if (IS_MULTIPLE_KPD(it)) { 1065 WriteKPD_Iterator(file, FALSE, TRUE, it->itVarArray, arg, TRUE); 1066 if (it->itVarArray) 1067 finish = TRUE; 1068 sprintf(string, "\tptr->"); 1069 subindex = "[i]"; 1070 count = arg->argSubCount; 1071 VarIndex = it->itElement->itVarArray; 1072 howmany = it->itElement->itNumber; 1073 howbig = it->itElement->itSize; 1074 } 1075 else { 1076 sprintf(string, "InOvTemplate->%s.", arg->argMsgField); 1077 subindex = ""; 1078 count = arg->argCount; 1079 VarIndex = it->itVarArray; 1080 howmany = it->itNumber; 1081 howbig = it->itSize; 1082 } 1083 1084 fprintf(file, "\t%saddress = (void *) %s%s%s;\n", string, ref, arg->argVarName, subindex); 1085 1086 if (it->itPortType) { 1087 fprintf(file, "\t%scount = ", string); 1088 if (VarIndex) { 1089 cref = count->argByReferenceUser ? "*" : ""; 1090 fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex); 1091 } 1092 else 1093 fprintf(file, "%d;\n", howmany); 1094 } 1095 else { 1096 fprintf(file, "\t%ssize = ", string); 1097 if (VarIndex) { 1098 cref = count->argByReferenceUser ? "*" : ""; 1099 if (count->argMultiplier > 1 || howbig > 8) 1100 fprintf(file, "%s%s%s * %d;\n", cref, count->argVarName, subindex, count->argMultiplier * howbig / 8); 1101 else 1102 fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex); 1103 } 1104 else 1105 fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8); 1106 } 1107 fprintf(file, "\t%scopy = MACH_MSG_OVERWRITE;\n", string); 1108 fprintf(file, "\t%stype = MACH_MSG_OOL_%sDESCRIPTOR;\n", string, (it->itPortType) ? "PORTS_" : ""); 1109 if (IS_MULTIPLE_KPD(it)) 1110 fprintf(file, "\t }\n"); 1111 if (finish) { 1112 fprintf(file, "\t for (i = %s%s; i < %d; ptr++, i++) {\n", (arg->argCount->argByReferenceUser) ? "*" : "", arg->argCount->argVarName, it->itKPD_Number); 1113 fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n"); 1114 fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : ""); 1115 fprintf(file, "\t }\n"); 1116 } 1117 if (IS_MULTIPLE_KPD(it)) 1118 fprintf(file, "\t}\n"); 1119 } 1120 else { 1121 /* just a placeholder */ 1122 if (IS_MULTIPLE_KPD(it)) { 1123 WriteKPD_Iterator(file, FALSE, TRUE, FALSE, arg, TRUE); 1124 fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n"); 1125 fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : ""); 1126 fprintf(file, "\t }\n\t}\n"); 1127 } 1128 else { 1129 fprintf(file, "\tInOvTemplate->%s.copy = MACH_MSG_ALLOCATE;\n", arg->argMsgField); 1130 /* not sure whether this is needed */ 1131 fprintf(file, "\tInOvTemplate->%s.type = MACH_MSG_OOL_%sDESCRIPTOR;\n", arg->argMsgField, (it->itPortType) ? "PORTS_" : ""); 1132 } 1133 } 1134 } 1135 } 1136 fprintf(file, "\n"); 1137} 1138 1139/************************************************************* 1140 * Writes code to copy an argument into the request message. 1141 * Called by WriteRoutine for each argument that is to placed 1142 * in the request message. 1143 *************************************************************/ 1144 1145static void 1146WritePackArgValueNormal(FILE *file, argument_t *arg) 1147{ 1148 ipc_type_t *it = arg->argType; 1149 char *ref = (arg->argByReferenceUser || 1150 it->itNativePointer) ? "*" : ""; 1151 1152 if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) { 1153 if (it->itString) { 1154 /* 1155 * Copy variable-size C string with mig_strncpy. 1156 * Save the string length (+ 1 for trailing 0) 1157 * in the argument`s count field. 1158 */ 1159 fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); 1160 fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n"); 1161 fprintf(file, "\t\tInP->%s = (%s) mig_strncpy_zerofill(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber); 1162 fprintf(file, "\t} else {\n"); 1163 fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); 1164 1165 fprintf(file, "\t\tInP->%s = (%s) mig_strncpy(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber); 1166 1167 fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); 1168 fprintf(file, "\t}\n"); 1169 fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); 1170 1171 fprintf(file, "\tInP->%sOffset = 0;\n", arg->argMsgField); 1172 } 1173 else if (it->itNoOptArray) 1174 fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, %d);\n", arg->argMsgField, ref, arg->argVarName, it->itTypeSize); 1175 else { 1176 1177 /* 1178 * Copy in variable-size inline array with (void)memcpy, 1179 * after checking that number of elements doesn`t 1180 * exceed declared maximum. 1181 */ 1182 argument_t *count = arg->argCount; 1183 char *countRef = count->argByReferenceUser ? "*" : ""; 1184 ipc_type_t *btype = it->itElement; 1185 1186 /* Note btype->itNumber == count->argMultiplier */ 1187 1188 if (akIdent(arg->argKind) != akeSubCount) { 1189 /* we skip the SubCount case, as we have already taken care of */ 1190 fprintf(file, "\tif (%s%s > %d) {\n", countRef, count->argVarName, it->itNumber/btype->itNumber); 1191 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); 1192 fprintf(file, "\t}\n"); 1193 } 1194 1195 fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, ", arg->argMsgField, ref, arg->argVarName); 1196 if (btype->itTypeSize > 1) 1197 fprintf(file, "%d * ", btype->itTypeSize); 1198 fprintf(file, "%s%s);\n", countRef, count->argVarName); 1199 } 1200 } 1201 else if (IS_OPTIONAL_NATIVE(it)) { 1202 fprintf(file, "\tif ((InP->__Present__%s = (%s != %s))) {\n", arg->argMsgField, arg->argVarName, it->itBadValue); 1203 WriteCopyType(file, it, TRUE, "\tInP->%s.__Real__%s", "/* %s%s */ %s%s", arg->argMsgField, arg->argMsgField, ref, arg->argVarName); 1204 fprintf(file, "\t}\n"); 1205 } 1206 else 1207 WriteCopyType(file, it, TRUE, "InP->%s", "/* %s */ %s%s", arg->argMsgField, ref, arg->argVarName); 1208 1209 if (arg->argPadName != NULL && it->itPadSize != 0) { 1210 fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize); 1211 fprintf(file, "\t\t InP->%s[i] = 0;\n", arg->argPadName); 1212 } 1213 fprintf(file, "\n"); 1214} 1215 1216/* 1217 * Calculate the size of a variable-length message field. 1218 */ 1219static void 1220WriteArgSizeVariable(FILE *file, argument_t *arg, ipc_type_t *ptype) 1221{ 1222 int bsize = ptype->itElement->itTypeSize; 1223 argument_t *count = arg->argCount; 1224 1225 if (PackMsg == FALSE) { 1226 fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize); 1227 return; 1228 } 1229 1230 /* If the base type size of the data field isn`t a multiple of 4, 1231 we have to round up. */ 1232 if (bsize % itWordAlign != 0) 1233 fprintf(file, "_WALIGN_"); 1234 fprintf(file, "("); 1235 if (bsize > 1) 1236 fprintf(file, "%d * ", bsize); 1237 if (ptype->itString) 1238 /* get count from descriptor in message */ 1239 fprintf(file, "InP->%s", count->argMsgField); 1240 else 1241 /* get count from argument */ 1242 fprintf(file, "%s%s", count->argByReferenceUser ? "*" : "", count->argVarName); 1243 fprintf(file, ")"); 1244} 1245 1246static void 1247WriteArgSizeOptional(FILE *file, argument_t *arg, ipc_type_t *ptype) 1248{ 1249 fprintf(file, "(InP->__Present__%s ? _WALIGNSZ_(%s) : 0)", arg->argVarName, ptype->itUserType); 1250} 1251 1252static void 1253WriteArgSize(FILE *file, argument_t *arg) 1254 1255{ 1256 ipc_type_t *ptype = arg->argType; 1257 1258 if (IS_OPTIONAL_NATIVE(ptype)) 1259 WriteArgSizeOptional(file, arg, ptype); 1260 else 1261 WriteArgSizeVariable(file, arg, ptype); 1262} 1263 1264/* 1265 * Adjust message size and advance request pointer. 1266 * Called after packing a variable-length argument that 1267 * has more arguments following. 1268 */ 1269static void 1270WriteAdjustMsgSize(FILE *file, argument_t *arg) 1271{ 1272 ipc_type_t *ptype = arg->argType; 1273 1274 /* There are more In arguments. We need to adjust msgh_size 1275 and advance InP, so we save the size of the current field 1276 in msgh_size_delta. */ 1277 1278 fprintf(file, "\tmsgh_size_delta = "); 1279 WriteArgSize(file, arg); 1280 fprintf(file, ";\n"); 1281 1282 if (arg->argRequestPos == 0) { 1283 /* First variable-length argument. The previous msgh_size value 1284 is the minimum request size. */ 1285 1286 fprintf(file, "\tmsgh_size = "); 1287 rtMinRequestSize(file, arg->argRoutine, "Request"); 1288 fprintf(file, " + msgh_size_delta;\n"); 1289 } 1290 else 1291 fprintf(file, "\tmsgh_size += msgh_size_delta;\n"); 1292 1293 if (PackMsg == TRUE) { 1294 fprintf(file, "\tInP = (Request *) ((pointer_t) InP + msgh_size_delta - "); 1295 if (IS_OPTIONAL_NATIVE(ptype)) 1296 fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType); 1297 else 1298 fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize); 1299 fprintf(file, ");\n\n"); 1300 } 1301} 1302 1303/* 1304 * Calculate the size of the message. Called after the 1305 * last argument has been packed. 1306 */ 1307static void 1308WriteFinishMsgSize(FILE *file, argument_t *arg) 1309{ 1310 /* No more In arguments. If this is the only variable In 1311 argument, the previous msgh_size value is the minimum 1312 request size. */ 1313 1314 if (arg->argRequestPos == 0) { 1315 fprintf(file, "\tmsgh_size = "); 1316 rtMinRequestSize(file, arg->argRoutine, "Request"); 1317 fprintf(file, " + ("); 1318 WriteArgSize(file, arg); 1319 fprintf(file, ");\n"); 1320 } 1321 else { 1322 fprintf(file, "\tmsgh_size += "); 1323 WriteArgSize(file, arg); 1324 fprintf(file, ";\n"); 1325 } 1326} 1327 1328static void 1329WriteInitializeCount(FILE *file, argument_t *arg) 1330{ 1331 ipc_type_t *ptype = arg->argCInOut->argParent->argType; 1332 ipc_type_t *btype = ptype->itElement; 1333 1334 fprintf(file, "\tif (%s%s < %d)\n", arg->argByReferenceUser ? "*" : "", arg->argVarName, ptype->itNumber/btype->itNumber); 1335 fprintf(file, "\t\tInP->%s = %s%s;\n", arg->argMsgField, arg->argByReferenceUser ? "*" : "", arg->argVarName); 1336 fprintf(file, "\telse\n"); 1337 fprintf(file, "\t\tInP->%s = %d;\n", arg->argMsgField, ptype->itNumber/btype->itNumber); 1338 fprintf(file, "\n"); 1339} 1340 1341/* 1342 * Generate code to fill in all of the request arguments and their 1343 * message types. 1344 */ 1345static void 1346WriteRequestArgs(FILE *file, routine_t *rt) 1347{ 1348 argument_t *arg; 1349 argument_t *lastVarArg; 1350 1351 /* 1352 * 1. The Kernel Processed Data 1353 */ 1354 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 1355 if (akCheckAll(arg->argKind, akbSendSnd|akbSendKPD)) 1356 (*arg->argKPD_Pack)(file, arg); 1357 1358 /* 1359 * 2. The Data Stream 1360 */ 1361 lastVarArg = argNULL; 1362 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1363 /* 1364 * Adjust message size and advance message pointer if 1365 * the last request argument was variable-length and the 1366 * request position will change. 1367 */ 1368 if (lastVarArg != argNULL && 1369 lastVarArg->argRequestPos < arg->argRequestPos) { 1370 WriteAdjustMsgSize(file, lastVarArg); 1371 lastVarArg = argNULL; 1372 } 1373 1374 if ((akIdent(arg->argKind) == akeCountInOut) && 1375 akCheck(arg->argKind, akbSendSnd)) 1376 WriteInitializeCount(file, arg); 1377 else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody)) 1378 WritePackArgValueNormal(file, arg); 1379 /* 1380 * Remember whether this was variable-length. 1381 */ 1382 if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable)) 1383 lastVarArg = arg; 1384 } 1385 /* 1386 * Finish the message size. 1387 */ 1388 if (lastVarArg != argNULL) 1389 WriteFinishMsgSize(file, lastVarArg); 1390} 1391 1392/************************************************************* 1393 * Writes code to check that the return msgh_id is correct and that 1394 * the size of the return message is correct. Called by 1395 * WriteRoutine. 1396 *************************************************************/ 1397static void 1398WriteCheckIdentity(FILE *file, routine_t *rt) 1399{ 1400 fprintf(file, "\tif (Out0P->Head.msgh_id != %d) {\n", rt->rtNumber + SubsystemBase + 100); 1401 fprintf(file, "\t if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n"); 1402 fprintf(file, "\t\t{ return MIG_SERVER_DIED; }\n"); 1403 fprintf(file, "\t else\n"); 1404 fprintf(file, "\t\t{ return MIG_REPLY_MISMATCH; }\n"); 1405 fprintf(file, "\t}\n"); 1406 fprintf(file, "\n"); 1407 if (!rt->rtSimpleReply) 1408 fprintf(file, "\tmsgh_simple = !(Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n"); 1409 fprintf(file, "#if\t__MigTypeCheck\n"); 1410 1411 if (!rt->rtNoReplyArgs) 1412 fprintf(file, "\tmsgh_size = Out0P->Head.msgh_size;\n\n"); 1413 1414 if (rt->rtSimpleReply) { 1415 /* Expecting a simple message. We can factor out the check for 1416 * a simple message, since the error reply message is also simple. 1417 */ 1418 fprintf(file, "\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n"); 1419 if (rt->rtNoReplyArgs) 1420 fprintf(file, "\t (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n"); 1421 else { 1422 /* 1423 * We have an error iff: 1424 * 1) the message size is not the one expected AND 1425 * 2) the message size is also different from sizeof(mig_reply_error_t) 1426 * or the RetCode == KERN_SUCCESS 1427 */ 1428 if (rt->rtNumReplyVar > 0) { 1429 fprintf(file, "\t ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < "); 1430 rtMinReplySize(file, rt, "__Reply"); 1431 fprintf(file, ") &&\n"); 1432 } 1433 else 1434 fprintf(file, "\t ((msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n"); 1435 fprintf(file, "\t (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n"); 1436 fprintf(file, "\t Out0P->RetCode == KERN_SUCCESS)))\n"); 1437 } 1438 } 1439 else { 1440 /* Expecting a complex message. */ 1441 1442 fprintf(file, "\t" "if ((msgh_simple || Out0P->msgh_body.msgh_descriptor_count != %d ||\n", rt->rtReplyKPDs); 1443 if (rt->rtNumReplyVar > 0) { 1444 fprintf(file, "\t msgh_size < "); 1445 rtMinReplySize(file, rt, "__Reply"); 1446 fprintf(file, " || msgh_size > (mach_msg_size_t)sizeof(__Reply)) &&\n"); 1447 } 1448 else 1449 fprintf(file, "\t msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n"); 1450 fprintf(file, "\t (!msgh_simple || msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n"); 1451 fprintf(file, "\t ((mig_reply_error_t *)Out0P)->RetCode == KERN_SUCCESS))\n"); 1452 } 1453 fprintf(file, "\t\t{ return MIG_TYPE_ERROR ; }\n"); 1454 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 1455 fprintf(file, "\n"); 1456} 1457 1458/************************************************************* 1459 * Write code to generate error handling code if the RetCode 1460 * argument of a Routine is not KERN_SUCCESS. 1461 *************************************************************/ 1462static void 1463WriteRetCodeCheck(FILE *file, routine_t *rt) 1464{ 1465 if (rt->rtSimpleReply) 1466 fprintf(file, "\tif (Out0P->RetCode != KERN_SUCCESS) {\n"); 1467 else 1468 fprintf(file, "\tif (msgh_simple) {\n"); 1469 if (CheckNDR) { 1470 fprintf(file, "#ifdef\t__NDR_convert__mig_reply_error_t__defined\n"); 1471 fprintf(file, "\t\t__NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P);\n"); 1472 fprintf(file, "#endif\t/* __NDR_convert__mig_reply_error_t__defined */\n"); 1473 } 1474 fprintf(file, "\t\treturn ((mig_reply_error_t *)Out0P)->RetCode;\n"); 1475 fprintf(file, "\t}\n"); 1476 fprintf(file, "\n"); 1477} 1478 1479/* 1480 * argKPD_TypeCheck discipline for Port types. 1481 */ 1482static void 1483WriteTCheckKPD_port(FILE *file, argument_t *arg) 1484{ 1485 ipc_type_t *it = arg->argType; 1486 char *tab = ""; 1487 char string[MAX_STR_LEN]; 1488 boolean_t close = FALSE; 1489 1490 if (IS_MULTIPLE_KPD(it)) { 1491 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE); 1492 (void)sprintf(string, "ptr->"); 1493 tab = "\t"; 1494 close = TRUE; 1495 } 1496 else 1497 (void)sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField); 1498 fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string); 1499 if (arg->argPoly == argNULL && !it->itVarArray) 1500 /* we can't check disposition when poly or VarArray, 1501 (because some of the entries could be empty) */ 1502 fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr); 1503 fprintf(file, 1504 ") {\n" 1505 "\t\t%s" "return MIG_TYPE_ERROR;\n" 1506 "\t%s" "}\n" 1507 , tab, tab); 1508 if (close) 1509 fprintf(file, "\t }\n\t}\n"); 1510} 1511 1512/* 1513 * argKPD_TypeCheck discipline for out-of-line types. 1514 */ 1515static void 1516WriteTCheckKPD_ool(FILE *file, argument_t *arg) 1517{ 1518 ipc_type_t *it = arg->argType; 1519 char *tab, string[MAX_STR_LEN]; 1520 boolean_t test; 1521 u_int howmany, howbig; 1522 1523 if (IS_MULTIPLE_KPD(it)) { 1524 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE); 1525 tab = "\t"; 1526 sprintf(string, "ptr->"); 1527 howmany = it->itElement->itNumber; 1528 howbig = it->itElement->itSize; 1529 test = !it->itVarArray && !it->itElement->itVarArray; 1530 } 1531 else { 1532 tab = ""; 1533 sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField); 1534 howmany = it->itNumber; 1535 howbig = it->itSize; 1536 test = !it->itVarArray; 1537 } 1538 1539 fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string); 1540 if (test) 1541 /* if VarArray we may use no-op; if itElement->itVarArray size might change */ 1542 fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8); 1543 fprintf(file, 1544 ") {\n" 1545 "\t\t%s" "return MIG_TYPE_ERROR;\n" 1546 "\t%s" "}\n" 1547 , tab, tab); 1548 if (IS_MULTIPLE_KPD(it)) 1549 fprintf(file, "\t }\n\t}\n"); 1550} 1551 1552/* 1553 * argKPD_TypeCheck discipline for out-of-line Port types. 1554 */ 1555static void 1556WriteTCheckKPD_oolport(FILE *file, argument_t *arg) 1557{ 1558 ipc_type_t *it = arg->argType; 1559 char *tab, string[MAX_STR_LEN]; 1560 boolean_t test; 1561 u_int howmany; 1562 char *howstr; 1563 1564 if (IS_MULTIPLE_KPD(it)) { 1565 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE); 1566 tab = "\t"; 1567 sprintf(string, "ptr->"); 1568 howmany = it->itElement->itNumber; 1569 test = !it->itVarArray && !it->itElement->itVarArray; 1570 howstr = it->itElement->itOutNameStr; 1571 } 1572 else { 1573 tab = ""; 1574 sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField); 1575 howmany = it->itNumber; 1576 test = !it->itVarArray; 1577 howstr = it->itOutNameStr; 1578 } 1579 1580 fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string); 1581 if (test) 1582 /* if VarArray we may use no-op; if itElement->itVarArray size might change */ 1583 fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany); 1584 if (arg->argPoly == argNULL) 1585 fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr); 1586 fprintf(file, ") {\n" 1587 "\t\t%s" "return MIG_TYPE_ERROR;\n" 1588 "\t%s" "}\n" 1589 ,tab, tab); 1590 if (IS_MULTIPLE_KPD(it)) 1591 fprintf(file, "\t }\n\t}\n"); 1592} 1593 1594/************************************************************* 1595 * Writes code to check that the type of each of the arguments 1596 * in the reply message is what is expected. Called by 1597 * WriteRoutine for each out && typed argument in the reply message. 1598 *************************************************************/ 1599static void 1600WriteTypeCheck(FILE *file, argument_t *arg) 1601{ 1602 fprintf(file, "#if\t__MigTypeCheck\n"); 1603 (*arg->argKPD_TypeCheck)(file, arg); 1604 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 1605} 1606 1607 1608/* 1609 * argKPD_Extract discipline for Port types. 1610 */ 1611static void 1612WriteExtractKPD_port(FILE *file, argument_t *arg) 1613{ 1614 ipc_type_t *it = arg->argType; 1615 char *ref = arg->argByReferenceUser ? "*" : ""; 1616 char *subindex; 1617 char *recast = ""; 1618 ipc_type_t *real_it; 1619 1620 real_it = (IS_MULTIPLE_KPD(it)) ? it->itElement : it; 1621#ifdef MIG_KERNEL_PORT_CONVERSION 1622 if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t")) 1623 recast = "(mach_port_t)"; 1624#endif 1625 if (IS_MULTIPLE_KPD(it)) { 1626 WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE); 1627 1628 fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast); 1629 if (it->itVarArray) { 1630 argument_t *count = arg->argCount; 1631 char *cref = count->argByReferenceUser ? "*" : ""; 1632 1633 fprintf(file, "\t if (Out%dP->%s >",count->argReplyPos, count->argVarName); 1634 if (arg->argCountInOut) { 1635 fprintf(file, " %s%s)\n", cref, count->argVarName); 1636 } 1637 else { 1638 fprintf(file, " %d)\n", it->itNumber/it->itElement->itNumber); 1639 } 1640 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); 1641 } 1642 fprintf(file, "\t}\n"); 1643 subindex = "[0]"; 1644 } 1645 else { 1646 fprintf(file, "\t%s%s = %sOut%dP->%s.name;\n", ref, arg->argVarName, recast, arg->argReplyPos, arg->argMsgField); 1647 subindex = ""; 1648 } 1649 1650 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) { 1651 argument_t *poly = arg->argPoly; 1652 char *pref = poly->argByReferenceUser ? "*" : ""; 1653 1654 fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex); 1655 } 1656} 1657 1658/* 1659 * argKPD_Extract discipline for out-of-line types. 1660 */ 1661static void 1662WriteExtractKPD_ool(FILE *file, argument_t *arg) 1663{ 1664 char *ref = arg->argByReferenceUser ? "*" : ""; 1665 ipc_type_t *it = arg->argType; 1666 1667 if (IS_MULTIPLE_KPD(it)) { 1668 WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE); 1669 fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName); 1670 fprintf(file, "\t}\n"); 1671 } 1672 else 1673 fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField); 1674 /* 1675 * In case of variable sized arrays, 1676 * the count field will be retrieved from the untyped 1677 * section of the message 1678 */ 1679} 1680 1681/* 1682 * argKPD_Extract discipline for out-of-line Port types. 1683 */ 1684static void 1685WriteExtractKPD_oolport(FILE *file, argument_t *arg) 1686{ 1687 char *ref = arg->argByReferenceUser ? "*" : ""; 1688 ipc_type_t *it = arg->argType; 1689 char *subindex; 1690 1691 if (IS_MULTIPLE_KPD(it)) { 1692 WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE); 1693 fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName); 1694 fprintf(file, "\t}\n"); 1695 subindex = "[0]"; 1696 } 1697 else { 1698 fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField); 1699 subindex = ""; 1700 } 1701 /* 1702 * In case of variable sized arrays, 1703 * the count field will be retrieved from the untyped 1704 * section of the message 1705 */ 1706 if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) { 1707 argument_t *poly = arg->argPoly; 1708 char *pref = poly->argByReferenceUser ? "*" : ""; 1709 1710 fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex); 1711 } 1712} 1713 1714/************************************************************* 1715 * Write code to copy an argument from the reply message 1716 * to the parameter. Called by WriteRoutine for each argument 1717 * in the reply message. 1718 *************************************************************/ 1719 1720static void 1721WriteExtractArgValueNormal(FILE *file, argument_t *arg) 1722{ 1723 ipc_type_t *argType = arg->argType; 1724 char *ref = arg->argByReferenceUser ? "*" : ""; 1725 char who[20]; 1726 1727 if (akCheck(arg->argKind, akbUserImplicit)) 1728 sprintf(who, "TrailerP"); 1729 else 1730 sprintf(who, "Out%dP", arg->argReplyPos); 1731 1732 if (IS_VARIABLE_SIZED_UNTYPED(argType) || argType->itNoOptArray) { 1733 if (argType->itString) { 1734 /* 1735 * Copy out variable-size C string with mig_strncpy, not the zerofill variant. 1736 * We don't risk leaking process / kernel memory on this copy-out because 1737 * we've already zero-filled the buffer on copy-in. 1738 */ 1739 fprintf(file, "\t(void) mig_strncpy(%s%s, %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itNumber); 1740 } 1741 else if (argType->itNoOptArray) 1742 fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itTypeSize); 1743 else { 1744 1745 /* 1746 * Copy out variable-size inline array with (void)memcpy, 1747 * after checking that number of elements doesn`t 1748 * exceed user`s maximum. 1749 */ 1750 argument_t *count = arg->argCount; 1751 char *countRef = count->argByReferenceUser ? "*" : ""; 1752 ipc_type_t *btype = argType->itElement; 1753 1754 /* Note count->argMultiplier == btype->itNumber */ 1755 /* Note II: trailer logic isn't supported in this case */ 1756 fprintf(file, "\tif (Out%dP->%s", count->argReplyPos, count->argMsgField); 1757 if (arg->argCountInOut) { 1758 fprintf(file, " > %s%s) {\n", countRef, count->argVarName); 1759 } 1760 else { 1761 fprintf(file, " > %d) {\n", argType->itNumber/btype->itNumber); 1762 } 1763 1764 /* 1765 * If number of elements is too many for user receiving area, 1766 * fill user`s area as much as possible. Return the correct 1767 * number of elements. 1768 */ 1769 fprintf(file, "\t\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField); 1770 if (btype->itTypeSize > 1) 1771 fprintf(file, "%d * ", btype->itTypeSize); 1772 if (arg->argCountInOut) { 1773 fprintf(file, " %s%s);\n", countRef, count->argVarName); 1774 } 1775 else { 1776 fprintf(file, " %d);\n", argType->itNumber/btype->itNumber); 1777 } 1778 fprintf(file, "\t\t%s%s = Out%dP->%s", countRef, count->argVarName, count->argReplyPos, count->argMsgField); 1779 fprintf(file, ";\n"); 1780 WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); 1781 1782 fprintf(file, "\t}\n"); 1783 1784 fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField); 1785 if (btype->itTypeSize > 1) 1786 fprintf(file, "%d * ", btype->itTypeSize); 1787 fprintf(file, "Out%dP->%s);\n", count->argReplyPos, count->argMsgField); 1788 } 1789 } 1790 else 1791 WriteCopyType(file, argType, FALSE, "%s%s", "/* %s%s */ %s->%s", ref, arg->argVarName, who, arg->argMsgField); 1792 fprintf(file, "\n"); 1793} 1794 1795static void 1796WriteCalcArgSize(FILE *file, argument_t *arg) 1797{ 1798 ipc_type_t *ptype = arg->argType; 1799 ipc_type_t *btype = ptype->itElement; 1800 argument_t *count = arg->argCount; 1801 int multiplier = btype->itTypeSize; 1802 1803 /* If the base type size of the data field isn`t a multiple of 4, 1804 we have to round up. */ 1805 if (btype->itTypeSize % itWordAlign != 0) 1806 fprintf(file, "_WALIGN_("); 1807 1808 fprintf(file, "Out%dP->%s", count->argReplyPos, count->argMsgField); 1809 if (multiplier > 1) 1810 fprintf(file, " * %d", multiplier); 1811 1812 if (btype->itTypeSize % itWordAlign != 0) 1813 fprintf(file, ")"); 1814} 1815 1816static void 1817WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator) 1818{ 1819 ipc_type_t *ptype = arg->argType; 1820 ipc_type_t *btype = ptype->itElement; 1821 argument_t *count = arg->argCount; 1822 int multiplier = btype->itTypeSize; 1823 1824 fprintf(file, "\tif (((msgh_size - "); 1825 rtMinReplySize(file, rt, "__Reply"); 1826 fprintf(file, ")"); 1827 if (multiplier > 1) 1828 fprintf(file, " / %d", multiplier); 1829 fprintf(file, "< Out%dP->%s) ||\n", count->argReplyPos, count->argMsgField); 1830 fprintf(file, "\t (msgh_size %s ", comparator); 1831 rtMinReplySize(file, rt, "__Reply"); 1832 fprintf(file, " + "); 1833 WriteCalcArgSize(file, arg); 1834 fprintf(file, ")"); 1835 fprintf(file, ")\n\t\t{ return MIG_TYPE_ERROR ; }\n"); 1836} 1837 1838 1839/* NDR Conversion routines */ 1840 1841 1842void 1843WriteReplyNDRConvertIntRepArgCond(FILE *file, argument_t *arg) 1844{ 1845 routine_t *rt = arg->argRoutine; 1846 1847 fprintf(file, "defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField); 1848} 1849 1850void 1851WriteReplyNDRConvertCharRepArgCond(FILE *file, argument_t *arg) 1852{ 1853 routine_t *rt = arg->argRoutine; 1854 1855 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) 1856 fprintf(file, "defined(__NDR_convert__char_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField); 1857 else 1858 fprintf(file, "0"); 1859} 1860 1861void 1862WriteReplyNDRConvertFloatRepArgCond(FILE *file, argument_t *arg) 1863{ 1864 routine_t *rt = arg->argRoutine; 1865 1866 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) 1867 fprintf(file, "defined(__NDR_convert__float_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField); 1868 else 1869 fprintf(file, "0"); 1870} 1871 1872void 1873WriteReplyNDRConvertIntRepArgDecl(FILE *file, argument_t *arg) 1874{ 1875 WriteNDRConvertArgDecl(file, arg, "int_rep", "Reply"); 1876} 1877 1878void 1879WriteReplyNDRConvertCharRepArgDecl(FILE *file, argument_t *arg) 1880{ 1881 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) 1882 WriteNDRConvertArgDecl(file, arg, "char_rep", "Reply"); 1883} 1884 1885void 1886WriteReplyNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg) 1887{ 1888 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) 1889 WriteNDRConvertArgDecl(file, arg, "float_rep", "Reply"); 1890} 1891 1892 1893 1894void 1895WriteReplyNDRConvertArgUse(FILE *file, argument_t *arg, char *convert) 1896{ 1897 routine_t *rt = arg->argRoutine; 1898 argument_t *count = arg->argCount; 1899 char argname[MAX_STR_LEN]; 1900 1901 if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) && 1902 (arg->argParent && akCheck(arg->argParent->argKind, akbReturnNdr))) 1903 return; 1904 1905 if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { 1906 if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) { 1907 fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, count->argMsgField); 1908 fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argReplyPos, count->argMsgField, count->argReplyPos); 1909 fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, count->argMsgField); 1910 } 1911 1912 sprintf(argname, "(%s)(Out%dP->%s.address)", FetchServerType(arg->argType), arg->argReplyPos, arg->argMsgField); 1913 } 1914 else { 1915 sprintf(argname, "&Out%dP->%s", arg->argReplyPos, arg->argMsgField); 1916 } 1917 1918 fprintf(file, "#if defined(__NDR_convert__%s__Reply__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField); 1919 fprintf(file, "\t\t__NDR_convert__%s__Reply__%s_t__%s(%s, Out0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert); 1920 if (count) 1921 fprintf(file, ", Out%dP->%s", count->argReplyPos, count->argMsgField); 1922 fprintf(file, ");\n"); 1923 fprintf(file, "#endif /* __NDR_convert__%s__Reply__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField); 1924} 1925 1926void 1927WriteReplyNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg) 1928{ 1929 routine_t *rt = arg->argRoutine; 1930 1931 fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField); 1932 fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep)\n"); 1933 fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argReplyPos, arg->argMsgField, arg->argReplyPos); 1934 fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField); 1935} 1936 1937void 1938WriteReplyNDRConvertIntRepArgUse(FILE *file, argument_t *arg) 1939{ 1940 WriteReplyNDRConvertArgUse(file, arg, "int_rep"); 1941} 1942 1943void 1944WriteReplyNDRConvertCharRepArgUse(FILE *file, argument_t *arg) 1945{ 1946 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) 1947 WriteReplyNDRConvertArgUse(file, arg, "char_rep"); 1948} 1949 1950void 1951WriteReplyNDRConvertFloatRepArgUse(FILE *file, argument_t *arg) 1952{ 1953 if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) 1954 WriteReplyNDRConvertArgUse(file, arg, "float_rep"); 1955} 1956 1957static void 1958WriteCheckMsgSize(FILE *file, argument_t *arg) 1959{ 1960 routine_t *rt = arg->argRoutine; 1961 ipc_type_t *it = arg->argType; 1962 ipc_type_t *btype = it->itElement; 1963 1964 /* If there aren't any more Out args after this, then 1965 we can use the msgh_size_delta value directly in 1966 the TypeCheck conditional. */ 1967 1968 if (CheckNDR && arg->argCount && !arg->argSameCount) 1969 WriteReplyNDRConvertIntRepOneArgUse(file, arg->argCount); 1970 1971 if (arg->argReplyPos == rt->rtMaxReplyPos) { 1972 fprintf(file, "#if\t__MigTypeCheck\n"); 1973 1974 /* 1975 * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type. 1976 */ 1977 fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, 1978 arg->argCount->argMsgField, it->itNumber/btype->itNumber); 1979 fputs("\t\t" "return MIG_TYPE_ERROR;\n", file); 1980 /* ...end... */ 1981 1982 WriteCheckArgSize(file, rt, arg, "!="); 1983 1984 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 1985 } 1986 else { 1987 /* If there aren't any more variable-sized arguments after this, 1988 then we must check for exact msg-size and we don't need 1989 to update msgh_size. */ 1990 1991 boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar; 1992 1993 /* calculate the actual size in bytes of the data field. note 1994 that this quantity must be a multiple of four. hence, if 1995 the base type size isn't a multiple of four, we have to 1996 round up. note also that btype->itNumber must 1997 divide btype->itTypeSize (see itCalculateSizeInfo). */ 1998 1999 fprintf(file, "\tmsgh_size_delta = "); 2000 WriteCalcArgSize(file, arg); 2001 fprintf(file, ";\n"); 2002 fprintf(file, "#if\t__MigTypeCheck\n"); 2003 2004 /* 2005 * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type. 2006 */ 2007 fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, 2008 arg->argCount->argMsgField, it->itNumber/btype->itNumber); 2009 fputs("\t\t" "return MIG_TYPE_ERROR;\n", file); 2010 /* ...end... */ 2011 2012 WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<"); 2013 2014 if (!LastVarArg) 2015 fprintf(file, "\tmsgh_size -= msgh_size_delta;\n"); 2016 2017 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 2018 } 2019 fprintf(file, "\n"); 2020} 2021 2022void 2023WriteAdjustReplyMsgPtr(FILE *file, argument_t *arg) 2024{ 2025 ipc_type_t *ptype = arg->argType; 2026 2027 fprintf(file, "\t*Out%dPP = Out%dP = (__Reply *) ((pointer_t) Out%dP + msgh_size_delta - %d);\n\n", 2028 arg->argReplyPos+1, arg->argReplyPos +1, arg->argReplyPos, ptype->itTypeSize + ptype->itPadSize); 2029} 2030 2031static void 2032WriteReplyArgs(FILE *file, routine_t *rt) 2033{ 2034 argument_t *arg; 2035 2036 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2037 if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) { 2038 WriteExtractArgValueNormal(file, arg); 2039 } 2040 else if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnKPD)) { 2041 /* 2042 * KPDs have argReplyPos 0, therefore they escape the above logic 2043 */ 2044 (*arg->argKPD_Extract)(file, arg); 2045 } 2046 else if (akCheck(arg->argKind, akbUserImplicit)) { 2047 WriteExtractArgValueNormal(file, arg); 2048 } 2049 } 2050} 2051 2052/************************************************************* 2053 * Writes code to return the return value. Called by WriteRoutine 2054 * for routines and functions. 2055 *************************************************************/ 2056static void 2057WriteReturnValue(FILE *file, routine_t *rt) 2058{ 2059 /* If returning RetCode, we have already checked that it is KERN_SUCCESS */ 2060 WriteReturn(file, rt, "\t", "KERN_SUCCESS", "\n", TRUE); 2061} 2062 2063/************************************************************* 2064 * Writes the elements of the message type declaration: the 2065 * msg_type structure, the argument itself and any padding 2066 * that is required to make the argument a multiple of 4 bytes. 2067 * Called by WriteRoutine for all the arguments in the request 2068 * message first and then the reply message. 2069 *************************************************************/ 2070static void 2071WriteFieldDecl(FILE *file, argument_t *arg) 2072{ 2073 if (akCheck(arg->argKind, akbSendKPD) || 2074 akCheck(arg->argKind, akbReturnKPD)) 2075 WriteFieldDeclPrim(file, arg, FetchKPDType); 2076 else 2077 WriteFieldDeclPrim(file, arg, FetchUserType); 2078} 2079 2080/* Fill in the string with an expression that refers to the size 2081 * of the specified array: 2082 */ 2083static void 2084GetArraySize(argument_t *arg, char *size) 2085{ 2086 ipc_type_t *it = arg->argType; 2087 2088 if (it->itVarArray) { 2089 if (arg->argCount->argByReferenceUser) { 2090 sprintf(size, "*%s", arg->argCount->argVarName); 2091 } 2092 else 2093 sprintf(size, "%s", arg->argCount->argVarName); 2094 } 2095 else { 2096 sprintf(size, "%d", (it->itNumber * it->itSize + 7) / 8); 2097 } 2098} 2099 2100 2101static void 2102WriteRPCPortDisposition(FILE *file, argument_t *arg) 2103{ 2104 /* 2105 * According to the MIG specification, the port disposition could be different 2106 * on input and output. If we stay with this then a new bitfield will have 2107 * to be added. Right now the port disposition is the same for in and out cases. 2108 */ 2109 switch(arg->argType->itInName) { 2110 2111 case MACH_MSG_TYPE_MOVE_RECEIVE: 2112 fprintf(file, " | MACH_RPC_MOVE_RECEIVE"); 2113 break; 2114 2115 case MACH_MSG_TYPE_MOVE_SEND: 2116 fprintf(file, " | MACH_RPC_MOVE_SEND"); 2117 break; 2118 2119 case MACH_MSG_TYPE_MOVE_SEND_ONCE: 2120 fprintf(file, " | MACH_RPC_MOVE_SEND_ONCE"); 2121 break; 2122 2123 case MACH_MSG_TYPE_COPY_SEND: 2124 fprintf(file, " | MACH_RPC_COPY_SEND"); 2125 break; 2126 2127 case MACH_MSG_TYPE_MAKE_SEND: 2128 fprintf(file, " | MACH_RPC_MAKE_SEND"); 2129 break; 2130 2131 case MACH_MSG_TYPE_MAKE_SEND_ONCE: 2132 fprintf(file, " | MACH_RPC_MAKE_SEND_ONCE"); 2133 break; 2134 } 2135} 2136 2137static void 2138WriteRPCArgDescriptor(FILE *file, argument_t *arg, int offset) 2139{ 2140 fprintf(file, " {\n 0 "); 2141 if (RPCPort(arg)) { 2142 fprintf(file, "| MACH_RPC_PORT "); 2143 if (arg->argType->itNumber > 1) 2144 fprintf(file, "| MACH_RPC_ARRAY "); 2145 if (arg->argType->itVarArray) 2146 fprintf(file, "| MACH_RPC_VARIABLE "); 2147 WriteRPCPortDisposition(file, arg); 2148 } 2149 else if (RPCPortArray(arg)) { 2150 fprintf(file, "| MACH_RPC_PORT_ARRAY "); 2151 if (arg->argType->itVarArray) 2152 fprintf(file, "| MACH_RPC_VARIABLE "); 2153 WriteRPCPortDisposition(file, arg); 2154 } 2155 else if (RPCFixedArray(arg)) 2156 fprintf(file, "| MACH_RPC_ARRAY_FIXED "); 2157 else if (RPCVariableArray(arg)) 2158 fprintf(file, "| MACH_RPC_ARRAY_VARIABLE "); 2159 if (argIsIn(arg)) 2160 fprintf(file, " | MACH_RPC_IN "); 2161 if (argIsOut(arg)) 2162 fprintf(file, " | MACH_RPC_OUT "); 2163 if ((! arg->argType->itInLine) && (! arg->argType->itMigInLine)) 2164 fprintf(file, " | MACH_RPC_POINTER "); 2165 if (arg->argFlags & flDealloc) 2166 fprintf(file, " | MACH_RPC_DEALLOCATE "); 2167 if (arg->argFlags & flPhysicalCopy) 2168 fprintf(file, " | MACH_RPC_PHYSICAL_COPY "); 2169 fprintf(file, ",\n"); 2170 fprintf(file, " %d,\n", (arg->argType->itSize / 8)); 2171 fprintf(file, " %d,\n", arg->argType->itNumber); 2172 fprintf(file, " %d,\n },\n", offset); 2173} 2174 2175void 2176WriteRPCRoutineDescriptor(FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array) 2177{ 2178 fprintf(file, " { (mig_impl_routine_t) 0,\n\ 2179 (mig_stub_routine_t) %s, ", stub_routine); 2180 fprintf(file, "%d, %d, %s}", arg_count, descr_count, sig_array); 2181} 2182 2183void 2184WriteRPCRoutineArgDescriptor(FILE *file, routine_t *rt) 2185{ 2186 argument_t *arg; 2187 int offset = 0; 2188 int size = 0; 2189 2190 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2191 boolean_t compound = arg->argType->itStruct && arg->argType->itInLine; 2192 2193 if (RPCPort(arg) || RPCPortArray(arg) || 2194 RPCFixedArray(arg) || RPCVariableArray(arg)) { 2195 WriteRPCArgDescriptor(file, arg, offset); 2196 size = 4; 2197 } 2198 if (! size) { 2199 if (compound) 2200 size = arg->argType->itNumber * (arg->argType->itSize / 8); 2201 else 2202 size = (arg->argType->itSize / 8); 2203 } 2204 if (akCheck(arg->argKind, akbServerArg)) 2205 offset += size; 2206 size = 0; 2207 } 2208} 2209 2210 2211static void 2212WriteRPCSignature(FILE *file, routine_t *rt) 2213{ 2214 int arg_count = 0; 2215 int descr_count = 0; 2216 2217 fprintf(file, " kern_return_t rtn;\n"); 2218 descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count); 2219 fprintf(file, " const static struct\n {\n"); 2220 fprintf(file, " struct rpc_routine_descriptor rd;\n"); 2221 fprintf(file, " struct rpc_routine_arg_descriptor rad[%d];\n", descr_count); 2222 fprintf(file, " } sig =\n {\n"); 2223 WriteRPCRoutineDescriptor(file, rt, arg_count, descr_count, "0", "sig.rad, 0"); 2224 fprintf(file, ",\n"); 2225 fprintf(file, " {\n"); 2226 WriteRPCRoutineArgDescriptor(file, rt); 2227 fprintf(file, "\n }\n"); 2228 fprintf(file, "\n };\n\n"); 2229} 2230 2231static void 2232WriteRPCCall(FILE *file, routine_t *rt) 2233{ 2234 argument_t *arg; 2235 int i; 2236 2237 i = 0; 2238 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2239 if (akIdent(arg->argKind) == akeRequestPort) { 2240 fprintf(file, " rtn = (MACH_RPC(&sig, (mach_msg_size_t)sizeof(sig), %d, %s,\n", rt->rtNumber + SubsystemBase, arg->argVarName); 2241 fprintf(file, " (%s", arg->argVarName); 2242 } 2243 else if (akCheck(arg->argKind, akbServerArg)) { 2244 if (i && (i++ % 6 == 0)) 2245 fprintf(file, ",\n "); 2246 else 2247 fprintf(file, ", "); 2248 fprintf(file, "%s", arg->argVarName); 2249 } 2250 } 2251 fprintf(file, ")));\n"); 2252 fprintf(file, "\n"); 2253 fprintf(file, " if (rtn != KERN_NO_ACCESS) return rtn;\n\n"); 2254 fprintf(file, "/* The following message rpc code is generated for the network case */\n\n"); 2255} 2256 2257static int 2258CheckRPCCall(routine_t *rt) 2259{ 2260 argument_t *arg; 2261 int i; 2262 2263 i = 0; 2264 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2265 if (akCheck(arg->argKind, akbUserArg) && 2266 ((arg->argType->itOutName == -1) || (arg->argType->itInName == -1))) { 2267 return FALSE; 2268 } 2269 if (arg->argFlags & flMaybeDealloc) { 2270 return FALSE; 2271 } 2272 } 2273 return TRUE; 2274} 2275 2276static void 2277WriteRPCRoutine(FILE *file, routine_t *rt) 2278{ 2279 if (CheckRPCCall(rt)) { 2280 WriteRPCSignature(file, rt); 2281 WriteRPCCall(file, rt); 2282 } 2283} 2284 2285/********************** End UserRPCTrap Routines*************************/ 2286 2287/* Process an IN/INOUT arg before the short-circuited RPC */ 2288static void 2289WriteShortCircInArgBefore(FILE *file, argument_t *arg) 2290{ 2291 ipc_type_t *it = arg->argType; 2292 char size[128]; 2293 2294 fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName); 2295 2296 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { 2297 switch (arg->argKPD_Type) { 2298 2299 case MACH_MSG_PORT_DESCRIPTOR: 2300 break; 2301 2302 case MACH_MSG_OOL_DESCRIPTOR: 2303 /* Arg is an out-of-line array: */ 2304 if (!(arg->argFlags & flDealloc) && 2305 (!(arg->argFlags & flAuto) || !(arg->argFlags & flConst))) { 2306 /* Need to map a copy of the array: */ 2307 GetArraySize(arg, size); 2308 fprintf(file, "\t(void)vm_read(mach_task_self(),\n"); 2309 fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName); 2310 /* Point argument at the copy: */ 2311 fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName); 2312 } 2313 else if ((arg->argFlags & flDealloc) && 2314 ((arg->argFlags & flAuto) || it->itMigInLine)) { 2315 /* Point the temp var at the original argument: */ 2316 fprintf(file, "\t_%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName); 2317 } 2318 break; 2319 2320 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 2321 break; 2322 2323 default: 2324 printf("MiG internal error: type of kernel processed data unknown\n"); 2325 exit(1); 2326 } /* end of switch */ 2327 } 2328 else if (it->itNumber > 1) { 2329 if (it->itStruct) { 2330 /* Arg is a struct -- nothing to do. */ 2331 } 2332 else { 2333 /* Arg is a C string or an in-line array: */ 2334 if (!argIsOut(arg) && !(arg->argFlags & flConst)) { 2335 /* Have to copy it into a temp. Use a stack var, if this would 2336 * not overflow the -maxonstack specification: 2337 * Conservatively assume ILP32 thresholds 2338 */ 2339 if (it->itTypeSize <= sizeof(natural_t) || 2340 rtMessOnStack(arg->argRoutine) || 2341 arg->argRoutine->rtTempBytesOnStack + 2342 it->itTypeSize <= MaxMessSizeOnStack) { 2343 fprintf(file, "\t{ char _%sTemp_[%d];\n", arg->argVarName, it->itTypeSize); 2344 arg->argRoutine->rtTempBytesOnStack += it->itTypeSize; 2345 arg->argTempOnStack = TRUE; 2346 } 2347 else { 2348 fprintf(file, "\t{ _%sTemp_ = (char *) %s(%d);\n", arg->argVarName, MessAllocRoutine, it->itTypeSize); 2349 arg->argTempOnStack = FALSE; 2350 } 2351 WriteCopyArg(file, arg, TRUE, "_%sTemp_", "/* %s */ (char *) %s", arg->argVarName, arg->argVarName); 2352 /* Point argument at temp: */ 2353 fprintf(file, "\t *(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName); 2354 fprintf(file, "\t}\n"); 2355 } 2356 } 2357 } 2358} 2359 2360 2361/* Process an INOUT/OUT arg before the short-circuited RPC */ 2362static void 2363WriteShortCircOutArgBefore(FILE *file, argument_t *arg) 2364{ 2365 ipc_type_t *it = arg->argType; 2366 2367 fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName); 2368 2369 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { 2370 switch (arg->argKPD_Type) { 2371 2372 case MACH_MSG_PORT_DESCRIPTOR: 2373 break; 2374 2375 case MACH_MSG_OOL_DESCRIPTOR: 2376 /* Arg is an out-of-line array: */ 2377 if (!argIsIn(arg) && (arg->argFlags & flOverwrite)) { 2378 /* Point the temp var at the original argument: */ 2379 fprintf(file, "\t _%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName); 2380 } 2381 break; 2382 2383 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 2384 break; 2385 2386 default: 2387 printf("MiG internal error: type of kernel processed data unknown\n"); 2388 exit(1); 2389 } /* end of switch */ 2390 } 2391 else if (it->itNumber > 1) { 2392 /* Arg is an in-line array: */ 2393 } 2394} 2395 2396 2397 2398/* Process an IN arg after the short-circuited RPC */ 2399static void 2400WriteShortCircInArgAfter(FILE *file, argument_t *arg) 2401{ 2402 ipc_type_t *it = arg->argType; 2403 char size[128]; 2404 2405 fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName); 2406 2407 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { 2408 switch (arg->argKPD_Type) { 2409 2410 case MACH_MSG_PORT_DESCRIPTOR: 2411 break; 2412 2413 case MACH_MSG_OOL_DESCRIPTOR: 2414 /* Arg is an out-of-line array: */ 2415 GetArraySize(arg, size); 2416 if ((!(arg->argFlags & flAuto) && it->itMigInLine) || 2417 ((arg->argFlags & flAuto) && 2418 ((arg->argFlags & flDealloc) || 2419 !(arg->argFlags & flConst)) 2420 )) { 2421 /* Need to dealloc the temporary: */ 2422 fprintf(file, "\t(void)vm_deallocate(mach_task_self(),"); 2423 fprintf(file, " (vm_address_t *) _%sTemp_, %s);\n", arg->argVarName, size); 2424 } 2425 break; 2426 2427 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 2428 break; 2429 2430 default: 2431 printf("MiG internal error: type of kernel processed data unknown\n"); 2432 exit(1); 2433 } /* end of switch */ 2434 } 2435 else if (it->itNumber > 1) { 2436 if (it->itStruct) { 2437 /* Arg is a struct -- nothing to do. */ 2438 } 2439 else { 2440 /* Arg is a C string or an in-line array: */ 2441 if (!argIsOut(arg) && !(arg->argFlags & flConst)) { 2442 /* A temp needs to be deallocated, if not on stack: */ 2443 if (!arg->argTempOnStack) { 2444 fprintf(file, "\t%s(_%sTemp_, %d);\n", MessFreeRoutine, arg->argVarName, it->itTypeSize); 2445 } 2446 } 2447 } 2448 } 2449} 2450 2451static void 2452WriteShortCircOutArgAfter(FILE *file, argument_t *arg) 2453{ 2454 ipc_type_t *it = arg->argType; 2455 char size[128]; 2456 2457 fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName); 2458 2459 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { 2460 switch (arg->argKPD_Type) { 2461 2462 case MACH_MSG_PORT_DESCRIPTOR: 2463 break; 2464 2465 case MACH_MSG_OOL_DESCRIPTOR: 2466 /* Arg is an out-of-line array: */ 2467 2468 /* Calculate size of array: */ 2469 GetArraySize(arg, size); 2470 if (!(arg->argFlags & flDealloc) || (arg->argFlags & flOverwrite)) { 2471 /* Copy argument to vm_allocated Temp: */ 2472 fprintf(file, "\t(void)vm_read(mach_task_self(),\n"); 2473 fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName); 2474 if (!argIsIn(arg) && (arg->argFlags & flDealloc) && 2475 (arg->argFlags & flOverwrite)) { 2476 /* Deallocate argument returned by server */ 2477 fprintf(file, "\t(void)vm_deallocate(mach_task_self(),"); 2478 fprintf(file, " (vm_address_t *) %s%s, %s);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size); 2479 } 2480 /* Point argument at new temporary: */ 2481 fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName); 2482 } 2483 break; 2484 2485 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 2486 break; 2487 2488 default: 2489 printf("MiG internal error: type of kernel processed data unknown\n"); 2490 exit(1); 2491 } /* end of switch */ 2492 } 2493 else if (it->itNumber != 1) { 2494 /* Arg is an in-line array: */ 2495 } 2496} 2497 2498 2499static void 2500WriteShortCircRPC(FILE *file, routine_t *rt) 2501{ 2502 argument_t *arg; 2503 int server_argc, i; 2504 boolean_t ShortCircOkay = TRUE; 2505 boolean_t first_OOL_arg = TRUE; 2506 2507 fprintf(file, " if (0 /* Should be: !(%s & 0x3) XXX */) {\n", rt->rtRequestPort->argVarName); 2508 2509 if (rt->rtOneWay) { 2510 /* Do not short-circuit simple routines: */ 2511 ShortCircOkay = FALSE; 2512 } 2513 else { 2514 /* Scan for any types we can't yet handle. If found, give up on short- 2515 * circuiting and fall back to mach_msg: 2516 */ 2517 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2518 if (arg->argFlags & flMaybeDealloc) { 2519 ShortCircOkay = FALSE; 2520 break; 2521 } 2522 /* Can't yet handle ports: */ 2523 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && 2524 (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR || 2525 arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR)) { 2526 ShortCircOkay = FALSE; 2527 break; 2528 } 2529 } 2530 } 2531 2532 if (ShortCircOkay) { 2533 2534 fprintf(file," rpc_subsystem_t subsystem = ((rpc_port_t)%s)->rp_subsystem;\n", rt->rtRequestPort->argVarName); 2535 fprintf(file, "\n"); 2536 fprintf(file, " if (subsystem && subsystem->start == %d) {\n", SubsystemBase); 2537 fprintf(file, "\tkern_return_t rtn;\n"); 2538 fprintf(file, "\n"); 2539 2540 /* Declare temp vars for out-of-line array args, and for all array 2541 * args, if -maxonstack has forced us to allocate in-line arrays 2542 * off the stack: 2543 */ 2544 rt->rtTempBytesOnStack = 0; 2545 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2546 arg->argTempOnStack = FALSE; 2547 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && 2548 arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { 2549 if (first_OOL_arg) { 2550 /* Need a garbage temporary to hold the datacount 2551 * returned by vm_read, which we always ignore: 2552 */ 2553 fprintf(file, "\tmach_msg_type_number_t _MIG_Ignore_Count_;\n"); 2554 first_OOL_arg = FALSE; 2555 } 2556 } 2557 else if (!rtMessOnStack(rt) && 2558 arg->argType->itNumber > 1 && !arg->argType->itStruct) { 2559 } 2560 else 2561 continue; 2562 fprintf(file, "\tchar *_%sTemp_;\n", arg->argVarName); 2563 /* Conservatively assume ILP32 thresholds */ 2564 rt->rtTempBytesOnStack += sizeof(natural_t); 2565 } 2566 2567 /* Process the IN arguments, in order: */ 2568 2569 fprintf(file, "\t/* Pre-Process the IN arguments: */\n"); 2570 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2571 if (argIsIn(arg)) 2572 WriteShortCircInArgBefore(file, arg); 2573 if (argIsOut(arg)) 2574 WriteShortCircOutArgBefore(file, arg); 2575 } 2576 fprintf(file, "\n"); 2577 2578 /* Count the number of server args: */ 2579 server_argc = 0; 2580 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 2581 if (akCheck(arg->argKind, akbServerArg)) 2582 server_argc++; 2583 2584 /* Call RPC_SIMPLE to switch to server stack and function: */ 2585 i = 0; 2586 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2587 if (akIdent(arg->argKind) == akeRequestPort) { 2588 fprintf(file, "\trtn = RPC_SIMPLE(%s, %d, %d, (", arg->argVarName, rt->rtNumber + SubsystemBase, server_argc); 2589 fprintf(file, "%s", arg->argVarName); 2590 } 2591 else if (akCheck(arg->argKind, akbServerArg)) { 2592 if (i++ % 6 == 0) 2593 fprintf(file, ",\n\t\t"); 2594 else 2595 fprintf(file, ", "); 2596 fprintf(file, "%s", arg->argVarName); 2597 } 2598 } 2599 fprintf(file, "));\n"); 2600 fprintf(file, "\n"); 2601 2602 /* Process the IN and OUT arguments, in order: */ 2603 fprintf(file, "\t/* Post-Process the IN and OUT arguments: */\n"); 2604 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2605 if (argIsIn(arg)) 2606 WriteShortCircInArgAfter(file, arg); 2607 if (argIsOut(arg)) 2608 WriteShortCircOutArgAfter(file, arg); 2609 } 2610 fprintf(file, "\n"); 2611 2612 fprintf(file, "\treturn rtn;\n"); 2613 fprintf(file, " }\n"); 2614 } 2615 2616 /* In latest design, the following is not necessary, because in 2617 * kernel-loaded tasks, the Mach port name is the same as the handle 2618 * used by the RPC mechanism, namely a pointer to the ipc_port, and 2619 * in user-mode tasks, the Mach port name gets renamed to be a pointer 2620 * to the user-mode rpc_port_t struct. 2621 */ 2622#if 0 2623 if (IsKernelUser) 2624 fprintf(file, " %s = (ipc_port_t)%s->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName); 2625 else 2626 fprintf(file, " %s = ((rpc_port_t)%s)->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName); 2627#endif 2628 2629 fprintf(file, " }\n"); 2630} 2631 2632static void 2633WriteStubDecl(FILE *file, routine_t *rt) 2634{ 2635 fprintf(file, "\n"); 2636 fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName); 2637 fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName); 2638 if (BeAnsiC) { 2639 fprintf(file, "(\n"); 2640 WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); 2641 fprintf(file, ")\n"); 2642 } 2643 else { 2644 fprintf(file, "#if\t%s\n", NewCDecl); 2645 fprintf(file, "(\n"); 2646 WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); 2647 fprintf(file, ")\n"); 2648 fprintf(file, "#else\n"); 2649 fprintf(file, "\t("); 2650 WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", ""); 2651 fprintf(file, ")\n"); 2652 WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n"); 2653 fprintf(file, "#endif\t/* %s */\n", NewCDecl); 2654 } 2655 fprintf(file, "{\n"); 2656} 2657 2658static void 2659InitKPD_Disciplines(argument_t *args) 2660{ 2661 argument_t *arg; 2662 extern void KPD_noop(FILE *file, argument_t *arg); 2663 extern void KPD_error(FILE *file, argument_t *arg); 2664 extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in); 2665 extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in); 2666 extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in); 2667 2668 /* 2669 * WriteKPD_port, WriteExtractKPD_port, 2670 * WriteKPD_ool, WriteExtractKPD_ool, 2671 * WriteKPD_oolport, WriteExtractKPD_oolport 2672 * are local to this module (which is the reason why this initialization 2673 * takes place here rather than in utils.c). 2674 * Common routines for user and server will be established SOON, and 2675 * all of them (including the initialization) will be transfert to 2676 * utils.c 2677 * All the KPD disciplines are defaulted to be KPD_error(). 2678 * Note that akbSendKPD and akbReturnKPd are not exclusive, 2679 * because of inout type of parameters. 2680 */ 2681 for (arg = args; arg != argNULL; arg = arg->argNext) 2682 if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) 2683 switch (arg->argKPD_Type) { 2684 2685 case MACH_MSG_PORT_DESCRIPTOR: 2686 arg->argKPD_Init = KPD_noop; 2687 if akCheck(arg->argKind, akbSendKPD) { 2688 arg->argKPD_Template = WriteTemplateKPD_port; 2689 arg->argKPD_Pack = WriteKPD_port; 2690 } 2691 if akCheck(arg->argKind, akbReturnKPD) { 2692 arg->argKPD_Extract = WriteExtractKPD_port; 2693 arg->argKPD_TypeCheck = WriteTCheckKPD_port; 2694 } 2695 break; 2696 2697 case MACH_MSG_OOL_DESCRIPTOR: 2698 arg->argKPD_Init = KPD_noop; 2699 if akCheck(arg->argKind, akbSendKPD) { 2700 arg->argKPD_Template = WriteTemplateKPD_ool; 2701 arg->argKPD_Pack = WriteKPD_ool; 2702 } 2703 if akCheck(arg->argKind, akbReturnKPD) { 2704 arg->argKPD_TypeCheck = WriteTCheckKPD_ool; 2705 arg->argKPD_Extract = WriteExtractKPD_ool; 2706 } 2707 break; 2708 2709 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 2710 arg->argKPD_Init = KPD_noop; 2711 if akCheck(arg->argKind, akbSendKPD) { 2712 arg->argKPD_Template = WriteTemplateKPD_oolport; 2713 arg->argKPD_Pack = WriteKPD_oolport; 2714 } 2715 if akCheck(arg->argKind, akbReturnKPD) { 2716 arg->argKPD_TypeCheck = WriteTCheckKPD_oolport; 2717 arg->argKPD_Extract = WriteExtractKPD_oolport; 2718 } 2719 break; 2720 2721 default: 2722 printf("MiG internal error: type of kernel processed data unknown\n"); 2723 exit(1); 2724 } /* end of switch */ 2725} 2726 2727static void 2728WriteLimitCheck(FILE *file, routine_t *rt) 2729{ 2730 if (MaxMessSizeOnStack == -1 || UserTypeLimit == -1) 2731 return; 2732 if (!rt->rtRequestUsedLimit && !rt->rtReplyUsedLimit) 2733 return; 2734 fprintf(file, "#if LimitCheck\n"); 2735 if (rt->rtRequestUsedLimit) { 2736 if (rt->rtRequestFits) { 2737 fprintf(file, "\tif ((sizeof(Request) - %d) > %d)\n", rt->rtRequestSizeKnown, UserTypeLimit); 2738 fprintf(file, "\t __RequestOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); 2739 } 2740 else if (rt->rtReplyFits) { 2741 fprintf(file, "\tif (sizeof(Request) < %d)\n", MaxMessSizeOnStack); 2742 fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); 2743 } 2744 } 2745 if (rt->rtReplyUsedLimit) { 2746 if (rt->rtReplyFits) { 2747 fprintf(file, "\tif ((sizeof(Reply) - %d) > %d)\n", rt->rtReplySizeKnown, UserTypeLimit); 2748 fprintf(file, "\t __ReplyOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); 2749 } 2750 else if (rt->rtRequestFits) { 2751 fprintf(file, "\tif (sizeof(Reply) < %d)\n", MaxMessSizeOnStack); 2752 fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); 2753 } 2754 } 2755 if (rt->rtRequestUsedLimit && rt->rtReplyUsedLimit && 2756 ! (rt->rtRequestFits || rt->rtReplyFits)) { 2757 fprintf(file, "\tif (sizeof(Request) < %d \n", MaxMessSizeOnStack); 2758 fprintf(file, "&& sizeof(Reply) < %d)\n", MaxMessSizeOnStack); 2759 fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); 2760 } 2761 fprintf(file, "#endif /* LimitCheck */\n"); 2762} 2763 2764static void 2765WriteOOLSizeCheck(FILE *file, routine_t *rt) 2766{ 2767 /* Emit code to validate the actual size of ool data vs. the reported size */ 2768 argument_t *argPtr; 2769 boolean_t openedTypeCheckConditional = FALSE; 2770 2771 // scan through arguments to see if there are any ool data blocks 2772 for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) { 2773 if (akCheck(argPtr->argKind, akbReturnKPD)) { 2774 ipc_type_t *it = argPtr->argType; 2775 boolean_t multiple_kpd = IS_MULTIPLE_KPD(it); 2776 char string[MAX_STR_LEN]; 2777 boolean_t test; 2778 argument_t *argCountPtr; 2779 char *tab; 2780 2781 if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { 2782 2783 if (multiple_kpd) { 2784 if ( !openedTypeCheckConditional ) { 2785 openedTypeCheckConditional = TRUE; 2786 fputs("#if __MigTypeCheck\n", file); 2787 } 2788 2789 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE); 2790 tab = "\t"; 2791 sprintf(string, "ptr->"); 2792 test = !it->itVarArray && !it->itElement->itVarArray; 2793 it = it->itElement; // point to element descriptor, so size calculation is correct 2794 argCountPtr = argPtr->argSubCount; 2795 } else { 2796 tab = ""; 2797 sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField); 2798 test = !it->itVarArray; 2799 argCountPtr = argPtr->argCount; 2800 } 2801 2802 if (!test) { 2803 int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1; 2804 2805 if ( !openedTypeCheckConditional ) { 2806 openedTypeCheckConditional = TRUE; 2807 fputs("#if __MigTypeCheck\n", file); 2808 } 2809 2810 fprintf(file, "\t%s" "if (%ssize ", tab, string); 2811 if (multiplier > 1) 2812 fprintf(file, "/ %d ", multiplier); 2813 fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : ""); 2814 if (it->itOOL_Number) { 2815 fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos, 2816 argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number); 2817 } 2818 fprintf(file,")\n"); 2819 fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); 2820 } 2821 2822 if (multiple_kpd) 2823 fprintf(file, "\t }\n\t}\n"); 2824 } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) { 2825 if (multiple_kpd) { 2826 if ( !openedTypeCheckConditional ) { 2827 openedTypeCheckConditional = TRUE; 2828 fputs("#if __MigTypeCheck\n", file); 2829 } 2830 2831 WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE); 2832 tab = "\t"; 2833 sprintf(string, "ptr->"); 2834 test = !it->itVarArray && !it->itElement->itVarArray; 2835 it = it->itElement; // point to element descriptor, so size calculation is correct 2836 argCountPtr = argPtr->argSubCount; 2837 } else { 2838 tab = ""; 2839 sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField); 2840 test = !it->itVarArray; 2841 argCountPtr = argPtr->argCount; 2842 } 2843 2844 if (!test) { 2845 if ( !openedTypeCheckConditional ) { 2846 openedTypeCheckConditional = TRUE; 2847 fputs("#if __MigTypeCheck\n", file); 2848 } 2849 2850 fprintf(file, "\t%s" "if (%scount ", tab, string); 2851 fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : ""); 2852 if (it->itOOL_Number) { 2853 fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos, 2854 argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number); 2855 } 2856 fprintf(file,")\n"); 2857 fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); 2858 } 2859 2860 if (multiple_kpd) 2861 fprintf(file, "\t }\n\t}\n"); 2862 } 2863 } 2864 } 2865 2866 if ( openedTypeCheckConditional ) 2867 fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); 2868} 2869 2870static void 2871WriteCheckReply(FILE *file, routine_t *rt) 2872{ 2873 int i; 2874 2875 /* initialize the disciplines for the handling of KPDs */ 2876 InitKPD_Disciplines(rt->rtArgs); 2877 2878 if (rt->rtOneWay) 2879 return; 2880 2881 fprintf(file, "\n"); 2882 fprintf(file, "#if ( __MigTypeCheck "); 2883 if (CheckNDR) 2884 fprintf(file, "|| __NDR_convert__ "); 2885 fprintf(file, ")\n"); 2886 fprintf(file, "#if __MIG_check__Reply__%s_subsystem__\n", SubsystemName); 2887 fprintf(file, "#if !defined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName); 2888 fprintf(file, "#define __MIG_check__Reply__%s_t__defined\n", rt->rtName); 2889 if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) { 2890 WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgDecl, akbReturnNdr, "\n", "\n"); 2891 WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgDecl, akbReturnNdr, "\n", "\n"); 2892 WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgDecl, akbReturnNdr, "\n", "\n"); 2893 } 2894 fprintf(file, "\n"); 2895 fprintf(file, "mig_internal kern_return_t __MIG_check__Reply__%s_t(__Reply__%s_t *Out0P", rt->rtName, rt->rtName); 2896 for (i = 1; i <= rt->rtMaxReplyPos; i++) 2897 fprintf(file, ", __Reply__%s_t **Out%dPP", rt->rtName, i); 2898 fprintf(file, ")\n{\n"); 2899 2900 2901 fprintf(file, "\n\ttypedef __Reply__%s_t __Reply __attribute__((unused));\n", rt->rtName); 2902 for (i = 1; i <= rt->rtMaxReplyPos; i++) 2903 fprintf(file, "\t__Reply *Out%dP;\n", i); 2904 if (!rt->rtSimpleReply) 2905 fprintf(file, "\tboolean_t msgh_simple;\n"); 2906 if (!rt->rtNoReplyArgs) { 2907 fprintf(file, "#if\t__MigTypeCheck\n"); 2908 fprintf(file, "\tunsigned int msgh_size;\n"); 2909 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 2910 } 2911 if (rt->rtMaxReplyPos > 0) 2912 fprintf(file, "\tunsigned int msgh_size_delta;\n"); 2913 if (rt->rtNumReplyVar > 0 || rt->rtMaxReplyPos > 0) 2914 fprintf(file, "\n"); 2915 2916 /* Check the values that are returned in the reply message */ 2917 2918 WriteCheckIdentity(file, rt); 2919 2920 /* Check the remote port is NULL */ 2921 fprintf(file, "#if\t__MigTypeCheck\n"); 2922 fprintf(file, "\tif (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {\n"); 2923 fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n"); 2924 fprintf(file, "\t}\n"); 2925 fprintf(file, "#endif\t/* __MigTypeCheck */\n"); 2926 2927 /* If the reply message has no Out parameters or return values 2928 other than the return code, we can type-check it and 2929 return it directly. */ 2930 2931 if (rt->rtNoReplyArgs && !rt->rtUserImpl) { 2932 if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply) && rt->rtRetCode) 2933 WriteReplyNDRConvertIntRepOneArgUse(file, rt->rtRetCode); 2934 WriteReturn(file, rt, "\t", stRetCode, "\n", FALSE); 2935 } 2936 else { 2937 if (UseEventLogger) 2938 WriteLogMsg(file, rt, LOG_USER, LOG_REPLY); 2939 2940 WriteRetCodeCheck(file, rt); 2941 2942 /* Type Checking for the Out parameters which are typed */ 2943 WriteList(file, rt->rtArgs, WriteTypeCheck, akbReturnKPD, "\n", "\n"); 2944 2945 { 2946 argument_t *arg, *lastVarArg; 2947 2948 lastVarArg = argNULL; 2949 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 2950 /* 2951 * Advance message pointer if the last reply argument was 2952 * variable-length and the reply position will change. 2953 */ 2954 if (lastVarArg != argNULL && 2955 lastVarArg->argReplyPos < arg->argReplyPos) { 2956 WriteAdjustReplyMsgPtr(file, lastVarArg); 2957 lastVarArg = argNULL; 2958 } 2959 2960 if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) { 2961 if (akCheck(arg->argKind, akbVariable)) { 2962 WriteCheckMsgSize(file, arg); 2963 lastVarArg = arg; 2964 } 2965 } 2966 } 2967 } 2968 2969 if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) { 2970 fprintf(file, "#if\t"); 2971 WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgCond, akbReturnNdr, " || \\\n\t", "\n"); 2972 fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep) {\n"); 2973 WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgUse, akbReturnNdr, "", ""); 2974 fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n"); 2975 2976 WriteOOLSizeCheck(file, rt); 2977 2978 fprintf(file, "#if\t"); 2979 WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgCond, akbReturnNdr, " || \\\n\t", "\n"); 2980 fprintf(file, "\tif (Out0P->NDR.char_rep != NDR_record.char_rep) {\n"); 2981 WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgUse, akbReturnNdr, "", ""); 2982 fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n"); 2983 2984 fprintf(file, "#if\t"); 2985 WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgCond, akbReturnNdr, " || \\\n\t", "\n"); 2986 fprintf(file, "\tif (Out0P->NDR.float_rep != NDR_record.float_rep) {\n"); 2987 WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgUse, akbReturnNdr, "", ""); 2988 fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n"); 2989 } else { 2990 WriteOOLSizeCheck(file, rt); 2991 } 2992 fprintf(file, "\treturn MACH_MSG_SUCCESS;\n"); 2993 } 2994 fprintf(file, "}\n"); 2995 fprintf(file, "#endif /* !defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName); 2996 fprintf(file, "#endif /* __MIG_check__Reply__%s_subsystem__ */\n", SubsystemName); 2997 fprintf(file, "#endif /* ( __MigTypeCheck "); 2998 if (CheckNDR) 2999 fprintf(file, "|| __NDR_convert__ "); 3000 fprintf(file, ") */\n\n"); 3001} 3002 3003static void 3004WriteCheckReplyCall(FILE *file, routine_t *rt) 3005{ 3006 int i; 3007 3008 fprintf(file, "\n"); 3009 fprintf(file, "#if\tdefined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName); 3010 fprintf(file, "\tcheck_result = __MIG_check__Reply__%s_t((__Reply__%s_t *)Out0P", rt->rtName, rt->rtName); 3011 for (i = 1; i <= rt->rtMaxReplyPos; i++) 3012 fprintf(file, ", (__Reply__%s_t **)&Out%dP", rt->rtName, i); 3013 fprintf(file, ");\n"); 3014 fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS) {\n"); 3015 if (IsKernelUser) { 3016 fprintf(file, "#if\t__MigKernelSpecificCode\n"); 3017 fprintf(file, "\t\tmach_msg_destroy_from_kernel(&Out0P->Head);\n"); 3018 fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n"); 3019 } else { 3020 fprintf(file, "\t\tmach_msg_destroy(&Out0P->Head);\n"); 3021 } 3022 WriteReturnMsgError(file, rt, TRUE, argNULL, "check_result"); 3023 fprintf(file, "\t}\n"); 3024 fprintf(file, "#endif\t/* defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName); 3025 fprintf(file, "\n"); 3026} 3027 3028void 3029WriteCheckReplies(FILE *file, statement_t *stats) 3030{ 3031 statement_t *stat; 3032 3033 for (stat = stats; stat != stNULL; stat = stat->stNext) 3034 if (stat->stKind == skRoutine) 3035 WriteCheckReply(file, stat->stRoutine); 3036} 3037 3038static void 3039WriteCheckReplyTrailerArgs(FILE *file, routine_t *rt) 3040{ 3041 argument_t *arg; 3042 3043 if (rt->rtUserImpl) 3044 WriteCheckTrailerHead(file, rt, TRUE); 3045 3046 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 3047 if (akCheck(arg->argKind, akbUserImplicit)) 3048 WriteCheckTrailerSize(file, TRUE, arg); 3049 } 3050 if (rt->rtUserImpl) 3051 fprintf(file, "\n"); 3052} 3053 3054 3055/************************************************************* 3056 * Writes all the code comprising a routine body. Called by 3057 * WriteUser for each routine. 3058 *************************************************************/ 3059static void 3060WriteRoutine(FILE *file, routine_t *rt) 3061{ 3062 /* write the stub's declaration */ 3063 WriteStubDecl(file, rt); 3064 3065 /* Use the RPC trap for user-user and user-kernel RPC */ 3066 if (UseRPCTrap) 3067 WriteRPCRoutine(file, rt); 3068 3069 /* write the code for doing a short-circuited RPC: */ 3070 if (ShortCircuit) 3071 WriteShortCircRPC(file, rt); 3072 3073 /* typedef of structure for Request and Reply messages */ 3074 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, FALSE, FALSE, FALSE); 3075 if (!rt->rtOneWay) { 3076 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply", rt->rtSimpleReply, TRUE, rt->rtUserImpl, FALSE); 3077 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "__Reply", rt->rtSimpleReply, FALSE, FALSE, FALSE); 3078 } 3079 if (rt->rtOverwrite) 3080 WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply|akbOverwrite, "OverwriteTemplate", FALSE, TRUE, FALSE, TRUE); 3081 /* 3082 * Define a Minimal Reply structure to be used in case of errors 3083 */ 3084 fprintf(file, "\t/*\n"); 3085 fprintf(file, "\t * typedef struct {\n"); 3086 fprintf(file, "\t * \tmach_msg_header_t Head;\n"); 3087 fprintf(file, "\t * \tNDR_record_t NDR;\n"); 3088 fprintf(file, "\t * \tkern_return_t RetCode;\n"); 3089 fprintf(file, "\t * } mig_reply_error_t;\n"); 3090 fprintf(file, "\t */\n"); 3091 fprintf(file, "\n"); 3092 3093 3094 /* declarations for local vars: Union of Request and Reply messages, 3095 InP, OutP and return value */ 3096 3097 WriteVarDecls(file, rt); 3098 3099 /* declarations and initializations of the mach_msg_type_descriptor_t variables 3100 for each argument that is a Kernel Processed Data */ 3101 3102 WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbRequest | akbSendKPD, "\n", "\n"); 3103 3104 WriteLimitCheck(file, rt); 3105 WriteRetCodeArg(file, rt); 3106 3107 /* fill in the fields that are non related to parameters */ 3108 3109 if (!rt->rtSimpleRequest) 3110 fprintf(file, "\tInP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtRequestKPDs); 3111 3112 /* fill in all the request message types and then arguments */ 3113 3114 WriteRequestArgs(file, rt); 3115 3116 /* fill in request message head */ 3117 3118 WriteRequestHead(file, rt); 3119 fprintf(file, "\n"); 3120 3121 /* give the application a chance to do some stuff. */ 3122 WriteApplMacro(file, "Send", "Before", rt); 3123 3124 /* Write the send/receive or rpc call */ 3125 3126 if (UseEventLogger) 3127 WriteLogMsg(file, rt, LOG_USER, LOG_REQUEST); 3128 3129 3130 if (rt->rtOneWay) { 3131 WriteMsgSend(file, rt); 3132 } 3133 else { 3134 if (UseMsgRPC 3135#if USE_IMMEDIATE_SEND_TIMEOUT 3136 && (rt->rtWaitTime == argNULL) 3137#endif 3138 ) { 3139 /* overwrite mode meaningful only when UseMsgRPC is enabled */ 3140 if (rt->rtOverwrite) 3141 WriteOverwriteTemplate(file, rt); 3142 WriteMsgRPC(file, rt); 3143 } 3144 else 3145 WriteMsgSendReceive(file, rt); 3146 3147 WriteCheckReplyCall(file, rt); 3148 WriteCheckReplyTrailerArgs(file, rt); 3149 3150 if (UseEventLogger) 3151 WriteLogMsg(file, rt, LOG_USER, LOG_REPLY); 3152 3153 WriteReplyArgs(file, rt); 3154 } 3155 /* return the return value, if any */ 3156 if (!rt->rtOneWay) // WriteMsgSend() already wrote the 'return' 3157 WriteReturnValue(file, rt); 3158 fprintf(file, "}\n"); 3159} 3160 3161static void 3162WriteRPCClientFunctions(FILE *file, statement_t *stats) 3163{ 3164 statement_t *stat; 3165 char *fname; 3166 char *argfmt = "(mach_port_t, char *, mach_msg_type_number_t)"; 3167 3168 fprintf(file, "#ifdef AUTOTEST\n"); 3169 for (stat = stats; stat != stNULL; stat = stat->stNext) 3170 if (stat->stKind == skRoutine) { 3171 fname = stat->stRoutine->rtName; 3172 fprintf(file, "extern void client_%s%s;\n", fname, argfmt); 3173 } 3174 fprintf(file, "function_table_entry %s_client_functions[] =\n", SubsystemName); 3175 fprintf(file, "{\n"); 3176 for (stat = stats; stat != stNULL; stat = stat->stNext) 3177 if (stat->stKind == skRoutine) { 3178 fname = stat->stRoutine->rtName; 3179 fprintf(file, " { \"%s\", client_%s },\n", fname, fname); 3180 } 3181 fprintf(file, " { (char *) 0, (function_ptr_t) 0 }\n"); 3182 fprintf(file, "};\n"); 3183 fprintf(file, "#endif /* AUTOTEST */\n"); 3184} 3185 3186/************************************************************* 3187 * Writes out the xxxUser.c file. Called by mig.c 3188 *************************************************************/ 3189void 3190WriteUser(FILE *file, statement_t *stats) 3191{ 3192 statement_t *stat; 3193 3194 WriteProlog(file, stats); 3195 if (TestRPCTrap) 3196 WriteRPCClientFunctions(file, stats); 3197 for (stat = stats; stat != stNULL; stat = stat->stNext) 3198 switch (stat->stKind) { 3199 3200 case skRoutine: 3201 WriteCheckReply(file, stat->stRoutine); 3202 WriteRoutine(file, stat->stRoutine); 3203 break; 3204 3205 case skImport: 3206 case skUImport: 3207 case skSImport: 3208 case skDImport: 3209 case skIImport: 3210 break; 3211 3212 default: 3213 fatal("WriteUser(): bad statement_kind_t (%d)", (int) stat->stKind); 3214 } 3215 WriteEpilog(file); 3216} 3217 3218/************************************************************* 3219 * Writes out individual .c user files for each routine. Called by mig.c 3220 *************************************************************/ 3221void 3222WriteUserIndividual(statement_t *stats) 3223{ 3224 statement_t *stat; 3225 3226 for (stat = stats; stat != stNULL; stat = stat->stNext) 3227 switch (stat->stKind) { 3228 3229 case skRoutine: { 3230 FILE *file; 3231 char *filename; 3232 3233 filename = strconcat(UserFilePrefix, strconcat(stat->stRoutine->rtName, ".c")); 3234 file = fopen(filename, "w"); 3235 if (file == NULL) 3236 fatal("fopen(%s): %s", filename, strerror(errno)); 3237 WriteProlog(file, stats); 3238 WriteRoutine(file, stat->stRoutine); 3239 WriteEpilog(file); 3240 fclose(file); 3241 strfree(filename); 3242 } 3243 break; 3244 3245 case skImport: 3246 case skUImport: 3247 case skSImport: 3248 case skDImport: 3249 case skIImport: 3250 break; 3251 3252 default: 3253 fatal("WriteUserIndividual(): bad statement_kind_t (%d)", (int) stat->stKind); 3254 } 3255}