bootstrap_cmds/migcom.tproj/routine.c

bootstrap_cmds source @ c71d2d7 2025-04-30 · 1892 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 "AS IS" 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 Mellon 46 * the rights to redistribute these changes. 47 */ 48 49#include "type.h" 50 51#include <mach/message.h> 52#include <mach/kern_return.h> 53#include "mig_machine.h" 54#include "error.h" 55#include "alloc.h" 56#include "global.h" 57#include "routine.h" 58#include "write.h" 59 60u_int rtNumber = 0; 61 62static void rtSizeDelta(FILE *file, u_int mask, routine_t *rt); 63 64routine_t * 65rtAlloc(void) 66{ 67 routine_t *new; 68 69 new = (routine_t *) calloc(1, sizeof *new); 70 if (new == rtNULL) 71 fatal("rtAlloc(): %s", strerror(errno)); 72 new->rtNumber = rtNumber++; 73 new->rtName = strNULL; 74 new->rtErrorName = strNULL; 75 new->rtUserName = strNULL; 76 new->rtServerName = strNULL; 77 78 return new; 79} 80 81void 82rtSkip(void) 83{ 84 rtNumber++; 85} 86 87argument_t * 88argAlloc(void) 89{ 90 extern void KPD_error(FILE *file, argument_t *arg); 91 92 static argument_t prototype = 93 { 94 .argName = strNULL, 95 .argNext = argNULL, 96 .argKind = akNone, 97 .argType = itNULL, 98 .argKPD_Type = argKPD_NULL, 99 .argKPD_Template = (void(*)(FILE *, argument_t *, boolean_t))KPD_error, 100 .argKPD_Init = KPD_error, 101 .argKPD_Pack = KPD_error, 102 .argKPD_Extract = KPD_error, 103 .argKPD_TypeCheck = KPD_error, 104 .argVarName = strNULL, 105 .argMsgField = strNULL, 106 .argTTName = strNULL, 107 .argPadName = strNULL, 108 .argSuffix = strNULL, 109 .argFlags = flNone, 110 .argDeallocate = d_NO, 111 .argCountInOut = FALSE, 112 .argRoutine = rtNULL, 113 .argCount = argNULL, 114 .argSubCount = argNULL, 115 .argCInOut = argNULL, 116 .argPoly = argNULL, 117 .argDealloc = argNULL, 118 .argSameCount = argNULL, 119 .argParent = argNULL, 120 .argMultiplier = 1, 121 .argRequestPos = 0, 122 .argReplyPos = 0, 123 .argByReferenceUser = FALSE, 124 .argByReferenceServer = FALSE, 125 .argTempOnStack = FALSE, 126 .argInSegment = NULL, 127 .argOutSegment = NULL, 128 }; 129 argument_t *new; 130 131 new = (argument_t *) malloc(sizeof *new); 132 if (new == argNULL) 133 fatal("argAlloc(): %s", strerror(errno)); 134 *new = prototype; 135 return new; 136} 137 138routine_t * 139rtMakeRoutine(identifier_t name, argument_t *args) 140{ 141 routine_t *rt = rtAlloc(); 142 143 rt->rtName = name; 144 rt->rtKind = rkRoutine; 145 rt->rtArgs = args; 146 147 return rt; 148} 149 150routine_t * 151rtMakeSimpleRoutine(identifier_t name, argument_t *args) 152{ 153 routine_t *rt = rtAlloc(); 154 155 rt->rtName = name; 156 rt->rtKind = rkSimpleRoutine; 157 rt->rtArgs = args; 158 159 return rt; 160} 161 162char * 163rtRoutineKindToStr(routine_kind_t rk) 164{ 165 switch (rk) { 166 167 case rkRoutine: 168 return "Routine"; 169 170 case rkSimpleRoutine: 171 return "SimpleRoutine"; 172 173 default: 174 fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk); 175 /*NOTREACHED*/ 176 return strNULL; 177 } 178} 179 180static void 181rtPrintArg(argument_t *arg) 182{ 183 ipc_type_t *it = arg->argType; 184 185 if (!akCheck(arg->argKind, akbUserArg|akbServerArg) || 186 (akIdent(arg->argKind) == akeCount) || 187 (akIdent(arg->argKind) == akeDealloc) || 188 (akIdent(arg->argKind) == akeNdrCode) || 189 (akIdent(arg->argKind) == akePoly)) 190 return; 191 192 printf("\n\t"); 193 194 switch (akIdent(arg->argKind)) { 195 196 case akeRequestPort: 197 printf("RequestPort"); 198 break; 199 200 case akeReplyPort: 201 printf("ReplyPort"); 202 break; 203 204 case akeWaitTime: 205 printf("WaitTime"); 206 break; 207 208 case akeSendTime: 209 printf("SendTime"); 210 break; 211 212 case akeMsgOption: 213 printf("MsgOption"); 214 break; 215 216 case akeMsgSeqno: 217 printf("MsgSeqno\t"); 218 break; 219 220 case akeSecToken: 221 printf("SecToken\t"); 222 break; 223 224 case akeAuditToken: 225 printf("AuditToken\t"); 226 break; 227 228 case akeContextToken: 229 printf("ContextToken\t"); 230 break; 231 232 case akeImplicit: 233 printf("Implicit\t"); 234 break; 235 236 default: 237 if (akCheck(arg->argKind, akbRequest)) { 238 if (akCheck(arg->argKind, akbSend)) 239 printf("In"); 240 else 241 printf("(In)"); 242 } 243 if (akCheck(arg->argKind, akbReply)) { 244 if (akCheck(arg->argKind, akbReturn)) 245 printf("Out"); 246 else 247 printf("(Out)"); 248 } 249 printf("\t"); 250 } 251 252 printf("\t%s: %s", arg->argName, it->itName); 253 254 if (arg->argDeallocate == d_YES) 255 printf(", Dealloc"); 256 else if (arg->argDeallocate == d_MAYBE) 257 printf(", Dealloc[]"); 258 259 if (arg->argCountInOut) 260 printf(", CountInOut"); 261 262 if (arg->argFlags & flSameCount) 263 printf(", SameCount"); 264 265 if (arg->argFlags & flPhysicalCopy) 266 printf(", PhysicalCopy"); 267 268 if (arg->argFlags & flRetCode) 269 printf(", PhysicalCopy"); 270 271 if (arg->argFlags & flOverwrite) 272 printf(", Overwrite"); 273 274 if (arg->argFlags & flAuto) 275 printf(", Auto"); 276 277 if (arg->argFlags & flConst) 278 printf(", Const"); 279} 280 281void 282rtPrintRoutine(routine_t *rt) 283{ 284 argument_t *arg; 285 286 printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind), rt->rtNumber, rt->rtName); 287 288 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 289 rtPrintArg(arg); 290 291 printf(")\n"); 292 printf("\n"); 293} 294 295/* 296 * Determines appropriate value of msg-simple for the message. 297 * One version for both In & Out. 298 */ 299 300static void 301rtCheckSimple(argument_t *args, u_int mask, boolean_t *simple) 302{ 303 argument_t *arg; 304 boolean_t MustBeComplex = FALSE; 305 306 for (arg = args; arg != argNULL; arg = arg->argNext) 307 if (akCheck(arg->argKind, mask)) { 308 ipc_type_t *it = arg->argType; 309 310 if (IS_KERN_PROC_DATA(it)) 311 MustBeComplex = TRUE; 312 } 313 314 *simple = !MustBeComplex; 315} 316 317static void 318rtCheckFit(routine_t *rt, u_int mask, boolean_t *fitp, boolean_t *uselimp, u_int *knownp) 319{ 320 boolean_t uselim = FALSE; 321 argument_t *arg; 322 u_int size = sizeof(mach_msg_header_t); 323 324 if (!rt->rtSimpleRequest) 325 machine_alignment(size,sizeof(mach_msg_body_t)); 326 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 327 if (akCheck(arg->argKind, mask)) { 328 ipc_type_t *it = arg->argType; 329 330 machine_alignment(size, it->itMinTypeSize); 331 if (it->itNative) 332 uselim = TRUE; 333 else if (IS_VARIABLE_SIZED_UNTYPED(it)) { 334 machine_alignment(size, it->itTypeSize); 335 size += it->itPadSize; 336 } 337 } 338 *knownp = size; 339 if (MaxMessSizeOnStack == -1) { 340 *fitp = TRUE; 341 *uselimp = FALSE; 342 } 343 else if (size > MaxMessSizeOnStack) { 344 *fitp = FALSE; 345 *uselimp = FALSE; 346 } 347 else if (!uselim) { 348 *fitp = TRUE; 349 *uselimp = FALSE; 350 } 351 else if (UserTypeLimit == -1) { 352 *fitp = FALSE; 353 *uselimp = FALSE; 354 } 355 else if (size + UserTypeLimit > MaxMessSizeOnStack) { 356 *fitp = FALSE; 357 *uselimp = TRUE; 358 } 359 else { 360 *fitp = TRUE; 361 *uselimp = TRUE; 362 } 363} 364 365static void 366rtFindHowMany(routine_t *rt) 367{ 368 argument_t *arg; 369 int multiplier = 1; 370 boolean_t test; 371 372 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 373 ipc_type_t *it = arg->argType; 374 375 if (IS_MULTIPLE_KPD(it)) { 376 if (!it->itVarArray) 377 multiplier = it->itKPD_Number; 378 test = !it->itVarArray && !it->itElement->itVarArray; 379 it = it->itElement; 380 } 381 else 382 test = !it->itVarArray; 383 384 if (akCheck(arg->argKind, akbSendKPD)) { 385 386 if (it->itInLine) 387 rt->rtCountPortsIn += it->itNumber * multiplier; 388 else if (it->itPortType) { 389 if (test) 390 rt->rtCountOolPortsIn += it->itNumber * multiplier; 391 } 392 else { 393 if (test) 394 rt->rtCountOolIn += (it->itNumber * it->itSize + 7)/8 * multiplier; 395 } 396 } 397 if (akCheckAll(arg->argKind, akbReturnKPD)) { 398 if (it->itInLine) 399 rt->rtCountPortsOut += it->itNumber * multiplier; 400 else if (it->itPortType) { 401 if (test) 402 rt->rtCountOolPortsOut += it->itNumber * multiplier; 403 } 404 else { 405 if (test) 406 rt->rtCountOolOut += ((it->itNumber * it->itSize + 7)/8) * multiplier; 407 } 408 } 409 } 410} 411 412boolean_t 413rtCheckMask(argument_t *args, u_int mask) 414{ 415 argument_t *arg; 416 417 for (arg = args; arg != argNULL; arg = arg->argNext) 418 if (akCheckAll(arg->argKind, mask)) 419 return TRUE; 420 return FALSE; 421} 422 423boolean_t 424rtCheckMaskFunction(argument_t *args, u_int mask, boolean_t (*func)(argument_t *arg)) 425{ 426 argument_t *arg; 427 428 for (arg = args; arg != argNULL; arg = arg->argNext) 429 if (akCheckAll(arg->argKind, mask)) 430 if ((*func)(arg)) 431 return TRUE; 432 return FALSE; 433} 434 435 436int 437rtCountKPDs(argument_t *args, u_int mask) 438{ 439 argument_t *arg; 440 int count = 0; 441 442 for (arg = args; arg != argNULL; arg = arg->argNext) 443 if (akCheckAll(arg->argKind, mask)) 444 count += arg->argType->itKPD_Number; 445 return count; 446} 447 448int 449rtCountFlags(argument_t *args, u_int flag) 450{ 451 argument_t *arg; 452 int count = 0; 453 454 for (arg = args; arg != argNULL; arg = arg->argNext) 455 if (arg->argFlags & flag) 456 count++; 457 return count; 458} 459 460int 461rtCountArgDescriptors(argument_t *args, int *argcount) 462{ 463 argument_t *arg; 464 int count = 0; 465 466 if (argcount) 467 *argcount = 0; 468 for (arg = args; arg != argNULL; arg = arg->argNext) 469 if (akCheck(arg->argKind, akbServerArg)) { 470 if (RPCFixedArray(arg) || 471 RPCPort(arg) || 472 RPCVariableArray(arg) || 473 RPCPortArray(arg)) { 474 count++; 475 if (argcount) 476 (*argcount)++; 477 } 478 else { 479 if (argcount) { 480 if (arg->argType->itStruct && arg->argType->itNumber && 481 (arg->argType->itSize >= 32)) 482 *argcount += arg->argType->itNumber * (arg->argType->itSize / 32); 483 else 484 (*argcount)++; 485 } 486 } 487 } 488 return count; 489} 490 491int 492rtCountMask(argument_t *args, u_int mask) 493{ 494 argument_t *arg; 495 int count = 0; 496 497 for (arg = args; arg != argNULL; arg = arg->argNext) 498 if (akCheckAll(arg->argKind, mask)) 499 count++; 500 return count; 501} 502 503/* arg->argType may be NULL in this function */ 504 505static void 506rtDefaultArgKind(routine_t *rt, argument_t *arg) 507{ 508 if ((arg->argKind == akNone) && (rt->rtRequestPort == argNULL)) 509 arg->argKind = akRequestPort; 510 511 if (arg->argKind == akNone) 512 arg->argKind = akIn; 513} 514 515/* 516 * Initializes arg->argDeallocate, 517 * arg->argCountInOut from arg->argFlags 518 * and perform consistency check over the 519 * flags. 520 */ 521 522static ipc_flags_t 523rtProcessDeallocFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, dealloc_t *what, string_t name) 524{ 525 526 /* only one of flDealloc, flNotDealloc, flMaybeDealloc */ 527 528 if (flags & flMaybeDealloc) { 529 if (flags & (flDealloc|flNotDealloc)) { 530 warn("%s: Dealloc and NotDealloc ignored with Dealloc[]", name); 531 flags &= ~(flDealloc|flNotDealloc); 532 } 533 } 534 535 if ((flags&(flDealloc|flNotDealloc)) == (flDealloc|flNotDealloc)) { 536 warn("%s: Dealloc and NotDealloc cancel out", name); 537 flags &= ~(flDealloc|flNotDealloc); 538 } 539 540 if (((IsKernelServer && akCheck(kind, akbReturn)) || 541 (IsKernelUser && akCheck(kind, akbSend))) && 542 (flags & flDealloc)) { 543 /* 544 * For a KernelServer interface and an Out argument, 545 * or a KernelUser interface and an In argument, 546 * we avoid a possible spurious warning about the deallocate bit. 547 * For compatibility with Mach 2.5, the deallocate bit 548 * may need to be enabled on some inline arguments. 549 */ 550 551 *what= d_YES; 552 } 553 else if (flags & (flMaybeDealloc|flDealloc)) { 554 /* only give semantic warnings if the user specified something */ 555 if (it->itInLine && !it->itPortType) { 556 warn("%s: Dealloc is ignored: it is meaningless for that type of argument", name); 557 flags &= ~(flMaybeDealloc|flDealloc); 558 } 559 else 560 *what = (flags & flMaybeDealloc) ? d_MAYBE : d_YES; 561 } 562 return flags; 563} 564 565static void 566rtProcessSameCountFlag(argument_t *arg) 567{ 568 ipc_type_t *it = arg->argType; 569 ipc_flags_t flags = arg->argFlags; 570 string_t name = arg->argVarName; 571 static argument_t *old_arg; 572 573 if (flags & flSameCount) { 574 if (!it->itVarArray) { 575 warn("%s: SameCount is ignored - the argument is not variable", name); 576 flags &= ~flSameCount; 577 } 578 if (old_arg) { 579 if (old_arg->argParent) 580 old_arg = old_arg->argParent; 581 if (old_arg->argSameCount) 582 old_arg = old_arg->argSameCount; 583 584 if (!old_arg->argType->itVarArray) { 585 warn("%s: SameCount is ignored - adjacent argument is not variable", name); 586 flags &= ~flSameCount; 587 } 588 589#define SAMECOUNT_MASK akeBITS|akbSend|akbReturn|akbRequest|akbReply|akbUserArg|akbServerArg 590 if (akCheck(old_arg->argKind, SAMECOUNT_MASK) != 591 akCheck(arg->argKind, SAMECOUNT_MASK) || 592 old_arg->argCountInOut != arg->argCountInOut) { 593 warn("%s: SameCount is ignored - inconsistencies with the adjacent argument\n", name); 594 flags &= ~flSameCount; 595 } 596 arg->argSameCount = old_arg; 597 } 598 arg->argFlags = flags; 599 } 600 old_arg = arg; 601} 602 603static ipc_flags_t 604rtProcessCountInOutFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, boolean_t *what, string_t name) 605{ 606 if (flags & flCountInOut) { 607 if (!akCheck(kind, akbReply)) { 608 warn("%s: CountInOut is ignored: argument must be Out\n", name); 609 flags &= ~flCountInOut; 610 } 611 else if (!it->itVarArray || !it->itInLine) { 612 warn("%s: CountInOut is ignored: argument isn't variable or in-line\n", name); 613 flags &= ~flCountInOut; 614 } 615 else 616 *what = TRUE; 617 } 618 return flags; 619} 620 621static ipc_flags_t 622rtProcessPhysicalCopyFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name) 623{ 624 if (flags & flPhysicalCopy) { 625 if (it->itInLine) { 626 warn("%s: PhysicalCopy is ignored, argument copied inline anyway", name); 627 flags &= ~flPhysicalCopy; 628 } 629 if (it->itPortType) { 630 warn("%s: PhysicalCopy is ignored, it does not apply to ports and array of ports", name); 631 flags &= ~flPhysicalCopy; 632 } 633 } 634 return flags; 635} 636 637static void 638rtProcessRetCodeFlag(argument_t *thisarg) 639{ 640 ipc_type_t *it = thisarg->argType; 641 ipc_flags_t flags = thisarg->argFlags; 642 string_t name = thisarg->argVarName; 643 routine_t *thisrout = thisarg->argRoutine; 644 645 if (flags & flRetCode) { 646 if (!it->itInLine || !it->itStruct || 647 it->itSize != 32 || it->itNumber != 1) { 648 warn("%s: RetCode is ignored - the type doesn't match a MIG RetCode", name); 649 flags &= ~flRetCode; 650 } 651 else if (thisrout->rtKind != rkSimpleRoutine) { 652 fatal("%s: RetCode is allowed only for SimpleRoutines", name); 653 } 654 else if (thisrout->rtRetCArg != argNULL) { 655 warn("%s: RetCode is ignored - only one argument can be flagged as RetCode", name); 656 flags &= ~flRetCode; 657 } 658 else { 659 thisrout->rtRetCArg = thisarg; 660 } 661 thisarg->argFlags = flags; 662 } 663} 664 665static ipc_flags_t 666rtProcessOverwriteFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name) 667{ 668 if (flags & flOverwrite) 669 if (it->itInLine || it->itMigInLine || 670 /* among In, Out, InOut, we want only the Out! */ 671 !akCheck(kind, akbReturn) || akCheck(kind, akbSend)) { 672 warn("%s: Overwrite is ignored - it must be Out AND Ool!", name); 673 flags &= ~flOverwrite; 674 } 675 return flags; 676} 677 678static void 679rtDetectKPDArg(argument_t *arg) 680{ 681 ipc_type_t *it = arg->argType; 682 char *string; 683 684 if (IS_KERN_PROC_DATA(it)) { 685 if (akCheck(arg->argKind, akbSendBody)) { 686 arg->argKind = akRemFeature(arg->argKind, akbSendBody); 687 arg->argKind = akAddFeature(arg->argKind, akbSendKPD); 688 } 689 if (akCheck(arg->argKind, akbReturnBody)) { 690 arg->argKind = akRemFeature(arg->argKind, akbReturnBody); 691 arg->argKind = akAddFeature(arg->argKind, akbReturnKPD); 692 } 693 if (it->itInLine) { 694 string = "mach_msg_port_descriptor_t"; 695 arg->argKPD_Type = MACH_MSG_PORT_DESCRIPTOR; 696 } 697 else if (it->itPortType) { 698 string = "mach_msg_ool_ports_descriptor_t"; 699 arg->argKPD_Type = MACH_MSG_OOL_PORTS_DESCRIPTOR; 700 } 701 else { 702 string = "mach_msg_ool_descriptor_t"; 703 arg->argKPD_Type = MACH_MSG_OOL_DESCRIPTOR; 704 } 705 it->itKPDType = string; 706 } 707} 708 709static void 710rtAugmentArgKind(argument_t *arg) 711{ 712 ipc_type_t *it = arg->argType; 713 714 /* akbVariable means variable-sized inline */ 715 716 if (IS_VARIABLE_SIZED_UNTYPED(it)) { 717 if (akCheckAll(arg->argKind, akbRequest|akbReply)) 718 error("%s: Inline variable-sized arguments can't be InOut", arg->argName); 719 arg->argKind = akAddFeature(arg->argKind, akbVariable); 720 } 721 if (IS_OPTIONAL_NATIVE(it)) 722 arg->argKind = akAddFeature(arg->argKind, akbVariable); 723 724 /* 725 * Need to use a local variable in the following cases: 726 * 1) There is a translate-out function & the argument is being 727 * returned. We need to translate it before it hits the message. 728 * 2) There is a translate-in function & the argument is 729 * sent and returned. We need a local variable for its address. 730 * 3) There is a destructor function, which will be used 731 * (SendRcv and not ReturnSnd), and there is a translate-in 732 * function whose value must be saved for the destructor. 733 * 4) This is Complex KPD (array of KPD), and as such it has to 734 * be copied to a local array in input and output 735 * 5) Both poly and dealloc generate warnings compile time, because 736 * we attempt to take address of bit-field structure member 737 */ 738 739 if ( 740 ((it->itOutTrans != strNULL) && akCheck(arg->argKind, akbReturnSnd)) || 741 ((it->itInTrans != strNULL) && akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) || 742 ((it->itDestructor != strNULL) && akCheck(arg->argKind, akbSendRcv) && !akCheck(arg->argKind, akbReturnSnd) && (it->itInTrans != strNULL)) || 743 (IS_MULTIPLE_KPD(it)) || 744 ((akIdent(arg->argKind) == akePoly) && akCheck(arg->argKind, akbReturnSnd)) || 745 ((akIdent(arg->argKind) == akeDealloc) && akCheck(arg->argKind, akbReturnSnd)) 746 ) { 747 arg->argKind = akRemFeature(arg->argKind, akbReplyCopy); 748 arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); 749 } 750} 751 752/* 753 * The Suffix allows to handle KPDs as normal data. 754 * it is used in InArgMsgField. 755 */ 756static void 757rtSuffixExtArg(argument_t *args) 758{ 759 argument_t *arg; 760 char *subindex; 761 char string[MAX_STR_LEN]; 762 763 for (arg = args; arg != argNULL; arg = arg->argNext) { 764 if (akCheck(arg->argKind, akbSendKPD | akbReturnKPD)) { 765 if (IS_MULTIPLE_KPD(arg->argType)) 766 subindex = "[0]"; 767 else 768 subindex = ""; 769 switch (arg->argKPD_Type) { 770 771 case MACH_MSG_PORT_DESCRIPTOR: 772 (void)sprintf(string, "%s.name", subindex); 773 break; 774 775 case MACH_MSG_OOL_DESCRIPTOR: 776 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 777 (void)sprintf(string, "%s.address", subindex); 778 break; 779 780 default: 781 error("Type of kernel processed data unknown\n"); 782 } 783 arg->argSuffix = strconcat(arg->argMsgField, string); 784 /* see above the list of VarNeeded cases */ 785 /* 786 * argCount has been removed from the VarNeeded list, 787 * because VarSize arrays have their Count in the untyped 788 * section of the message, and because it is not possible 789 * to move anything in-line/out-of-line 790 */ 791 } 792 else if (akIdent(arg->argKind) == akePoly && 793 akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) { 794 argument_t *par_arg = arg->argParent; 795 796 if (IS_MULTIPLE_KPD(par_arg->argType)) 797 subindex = "[0]"; 798 else 799 subindex = ""; 800 switch (par_arg->argKPD_Type) { 801 802 case MACH_MSG_PORT_DESCRIPTOR: 803 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 804 (void)sprintf(string, "%s.disposition", subindex); 805 arg->argSuffix = strconcat(par_arg->argMsgField, string); 806 break; 807 808 default: 809 error("Type of kernel processed data inconsistent\n"); 810 } 811 } 812 else if (akIdent(arg->argKind) == akeDealloc && 813 akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) { 814 argument_t *par_arg = arg->argParent; 815 816 if (IS_MULTIPLE_KPD(par_arg->argType)) 817 subindex = "[0]"; 818 else 819 subindex = ""; 820 switch (par_arg->argKPD_Type) { 821 822 case MACH_MSG_OOL_DESCRIPTOR: 823 case MACH_MSG_OOL_PORTS_DESCRIPTOR: 824 (void)sprintf(string, "%s.deallocate", subindex); 825 arg->argSuffix = strconcat(par_arg->argMsgField, string); 826 break; 827 828 default: 829 error("Type of kernel processed data inconsistent\n"); 830 } 831 } 832 } 833} 834 835/* arg->argType may be NULL in this function */ 836 837static void 838rtCheckRoutineArg(routine_t *rt, argument_t *arg) 839{ 840 switch (akIdent(arg->argKind)) { 841 842 case akeRequestPort: 843 if (rt->rtRequestPort != argNULL) 844 warn("multiple RequestPort args in %s; %s won't be used", rt->rtName, rt->rtRequestPort->argName); 845 rt->rtRequestPort = arg; 846 break; 847 848 case akeReplyPort: 849 if (rt->rtReplyPort != argNULL) 850 warn("multiple ReplyPort args in %s; %s won't be used", rt->rtName, rt->rtReplyPort->argName); 851 rt->rtReplyPort = arg; 852 break; 853 854 case akeWaitTime: 855 if (rt->rtWaitTime != argNULL) 856 warn("multiple WaitTime/SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName); 857 rt->rtWaitTime = arg; 858 break; 859 860 case akeSendTime: 861 if (rt->rtWaitTime != argNULL) { 862 if (akIdent(rt->rtWaitTime->argKind) == akeWaitTime) { 863 warn("SendTime type argument after a WaitTime in %s; SendTime %s won't be used", rt->rtName, arg->argName); 864 break; 865 } else { 866 warn("multiple SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName); 867 } 868 } 869 rt->rtWaitTime = arg; 870 break; 871 872 case akeMsgOption: 873 if (rt->rtMsgOption != argNULL) 874 warn("multiple MsgOption args in %s; %s won't be used", rt->rtName, rt->rtMsgOption->argName); 875 rt->rtMsgOption = arg; 876 break; 877 878 default: 879 break; 880 } 881} 882 883/* arg->argType may be NULL in this function */ 884 885static void 886rtSetArgDefaults(routine_t *rt, argument_t *arg) 887{ 888 arg->argRoutine = rt; 889 if (arg->argVarName == strNULL) 890 arg->argVarName = arg->argName; 891 if (arg->argMsgField == strNULL) 892 switch(akIdent(arg->argKind)) { 893 894 case akeRequestPort: 895 arg->argMsgField = "Head.msgh_request_port"; 896 break; 897 898 case akeReplyPort: 899 arg->argMsgField = "Head.msgh_reply_port"; 900 break; 901 902 case akeNdrCode: 903 arg->argMsgField = "NDR"; 904 break; 905 906 case akeSecToken: 907 arg->argMsgField = "msgh_sender"; 908 break; 909 910 case akeAuditToken: 911 arg->argMsgField = "msgh_audit"; 912 break; 913 914 case akeContextToken: 915 arg->argMsgField = "msgh_context"; 916 break; 917 918 case akeMsgSeqno: 919 arg->argMsgField = "msgh_seqno"; 920 break; 921 922 case akeImplicit: 923 /* the field is set directly by Yacc */ 924 break; 925 926 default: 927 arg->argMsgField = arg->argName; 928 break; 929 } 930 931 if (arg->argTTName == strNULL) 932 arg->argTTName = strconcat(arg->argName, "Template"); 933 if (arg->argPadName == strNULL) 934 arg->argPadName = strconcat(arg->argName, "Pad"); 935 936 /* 937 * The poly args for the request and reply ports have special defaults, 938 * because their msg-type-name values aren't stored in normal fields. 939 */ 940 941 if ((rt->rtRequestPort != argNULL) && 942 (rt->rtRequestPort->argPoly == arg) && 943 (arg->argType != itNULL)) { 944 arg->argMsgField = "Head.msgh_bits"; 945 arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST"; 946 } 947 948 if ((rt->rtReplyPort != argNULL) && 949 (rt->rtReplyPort->argPoly == arg) && 950 (arg->argType != itNULL)) { 951 arg->argMsgField = "Head.msgh_bits"; 952 arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; 953 } 954} 955 956static void 957rtAddCountArg(argument_t *arg) 958{ 959 argument_t *count, *master; 960 ipc_type_t *it = arg->argType; 961 962 count = argAlloc(); 963 964 if (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray) { 965 count->argName = strconcat(arg->argName, "Subs"); 966 count->argType = itMakeSubCountType(it->itKPD_Number, it->itVarArray, arg->argVarName); 967 count->argKind = akeSubCount; 968 arg->argSubCount = count; 969 } 970 else { 971 count->argName = strconcat(arg->argName, "Cnt"); 972 count->argType = itMakeCountType(); 973 count->argKind = akeCount; 974 arg->argCount = count; 975 if (arg->argParent != argNULL) { 976 /* this is the case where we are at the second level of recursion: 977 we want the Parent to access it through argCount */ 978 arg->argParent->argCount = count; 979 } 980 } 981 master = (arg->argParent != argNULL) ? arg->argParent : arg; 982 if (IS_MULTIPLE_KPD(master->argType)) 983 count->argMultiplier = 1; 984 else 985 count->argMultiplier = it->itElement->itNumber; 986 count->argParent = arg; 987 count->argNext = arg->argNext; 988 arg->argNext = count; 989 990 if (arg->argType->itString) { 991 /* C String gets no Count argument on either side, but are still in the msg */ 992 count->argKind = akAddFeature(count->argKind, akCheck(arg->argKind, akbSend) ? akbSendRcv : akbReturnRcv); 993 count->argVarName = (char *)0; 994 } 995 else { 996 /* 997 * Count arguments have to be present on the message body (NDR encoded) 998 * akbVariable has to be turned down, has it foul the algorithm 999 * for detecting the in-line variable sized arrays 1000 */ 1001 count->argKind |= akAddFeature(akbUserArg|akbServerArg, (arg->argKind) & ~akeBITS); 1002 count->argKind = akRemFeature(count->argKind, akbVariable|akbVarNeeded); 1003 if (IS_VARIABLE_SIZED_UNTYPED(arg->argType)) 1004 /* 1005 * Count arguments for the above types are explicitly declared 1006 * BEFORE the variable (with those bits, they would come afterwards) 1007 */ 1008 count->argKind = akRemFeature(count->argKind, akbRequest|akbReply); 1009 } 1010} 1011 1012static void 1013rtAddCountInOutArg(argument_t *arg) 1014{ 1015 argument_t *count; 1016 1017 /* 1018 * The user sees a single count variable. However, to get the 1019 * count passed from user to server for variable-sized inline OUT 1020 * arrays, we need two count arguments internally. This is 1021 * because the count value lives in different message fields (and 1022 * is scaled differently) in the request and reply messages. 1023 * 1024 * The two variables have the same name to simplify code generation. 1025 * 1026 * This variable has a null argParent field because it has akbRequest. 1027 * For example, see rtCheckVariable. 1028 */ 1029 1030 count = argAlloc(); 1031 count->argName = strconcat(arg->argName, "Cnt"); 1032 count->argType = itMakeCountType(); 1033 count->argParent = argNULL; 1034 count->argNext = arg->argNext; 1035 arg->argNext = count; 1036 (count->argCInOut = arg->argCount)->argCInOut = count; 1037 count->argKind = akCountInOut; 1038} 1039 1040static void 1041rtAddPolyArg(argument_t *arg) 1042{ 1043 ipc_type_t *it = arg->argType; 1044 argument_t *poly; 1045 arg_kind_t akbsend, akbreturn; 1046 1047 poly = argAlloc(); 1048 poly->argName = strconcat(arg->argName, "Poly"); 1049 poly->argType = itMakePolyType(); 1050 poly->argParent = arg; 1051 poly->argNext = arg->argNext; 1052 arg->argNext = poly; 1053 arg->argPoly = poly; 1054 1055 /* 1056 * akbsend is bits added if the arg is In; 1057 * akbreturn is bits added if the arg is Out. 1058 * The mysterious business with KernelServer subsystems: 1059 * when packing Out arguments, they use OutNames instead 1060 * of InNames, and the OutName determines if they are poly-in 1061 * as well as poly-out. 1062 */ 1063 1064 akbsend = akbSend; 1065 akbreturn = akbReturn; 1066 1067 if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) { 1068 akbsend |= akbUserArg|akbSendSnd; 1069 if (!IsKernelServer) 1070 akbreturn |= akbServerArg|akbReturnSnd; 1071 } 1072 if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) { 1073 akbsend |= akbServerArg|akbSendRcv; 1074 akbreturn |= akbUserArg|akbReturnRcv; 1075 if (IsKernelServer) 1076 akbreturn |= akbServerArg|akbReturnSnd; 1077 } 1078 1079 poly->argKind = akPoly; 1080 if (akCheck(arg->argKind, akbSend)) 1081 poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbsend)); 1082 if (akCheck(arg->argKind, akbReturn)) 1083 poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbreturn)); 1084} 1085 1086static void 1087rtAddDeallocArg(argument_t *arg) 1088{ 1089 argument_t *dealloc; 1090 1091 dealloc = argAlloc(); 1092 dealloc->argName = strconcat(arg->argName, "Dealloc"); 1093 dealloc->argType = itMakeDeallocType(); 1094 dealloc->argParent = arg; 1095 dealloc->argNext = arg->argNext; 1096 arg->argNext = dealloc; 1097 arg->argDealloc = dealloc; 1098 1099 /* 1100 * Dealloc flag can only be associated to KPDs. 1101 */ 1102 1103 dealloc->argKind = akeDealloc; 1104 if (akCheck(arg->argKind, akbSend)) 1105 dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbUserArg|akbSend|akbSendSnd)); 1106 if (akCheck(arg->argKind, akbReturn)) { 1107 dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbServerArg|akbReturn|akbReturnSnd)); 1108 dealloc->argByReferenceServer = TRUE; 1109 } 1110} 1111 1112static void 1113rtCheckRoutineArgs(routine_t *rt) 1114{ 1115 argument_t *arg; 1116 1117 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1118 ipc_type_t *it = arg->argType; 1119 1120 rtDefaultArgKind(rt, arg); 1121 rtCheckRoutineArg(rt, arg); 1122 1123 /* need to set argTTName before adding implicit args */ 1124 rtSetArgDefaults(rt, arg); 1125 1126 /* the arg may not have a type (if there was some error in parsing it), 1127 in which case we don't want to do these steps. */ 1128 1129 if (it != itNULL) { 1130 arg->argFlags = rtProcessDeallocFlag(it, arg->argFlags, arg->argKind, &arg->argDeallocate, arg->argVarName); 1131 arg->argFlags = rtProcessCountInOutFlag(it, arg->argFlags, arg->argKind, &arg->argCountInOut, arg->argVarName); 1132 rtProcessSameCountFlag(arg); 1133 arg->argFlags = rtProcessPhysicalCopyFlag(it, arg->argFlags, arg->argKind, arg->argVarName); 1134 rtProcessRetCodeFlag(arg); 1135 arg->argFlags = rtProcessOverwriteFlag(it, arg->argFlags, arg->argKind, arg->argVarName); 1136 rtAugmentArgKind(arg); 1137 1138 /* args added here will get processed in later iterations */ 1139 /* order of args is 'arg poly countinout count dealloc' */ 1140 1141 if (arg->argDeallocate == d_MAYBE) 1142 rtAddDeallocArg(arg); 1143 if (it->itVarArray || (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray)) 1144 rtAddCountArg(arg); 1145 if (arg->argCountInOut) 1146 rtAddCountInOutArg(arg); 1147 if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) 1148 rtAddPolyArg(arg); 1149 /* 1150 * Detects whether the arg has to become part of the 1151 * Kernel Processed Data section; if yes, define the proper 1152 * itUserKPDType, itServerKPDType 1153 */ 1154 rtDetectKPDArg(arg); 1155 } 1156 } 1157} 1158 1159boolean_t 1160rtCheckTrailerType(argument_t *arg) 1161{ 1162 if (akIdent(arg->argKind) == akeSecToken || 1163 akIdent(arg->argKind) == akeAuditToken || 1164 akIdent(arg->argKind) == akeContextToken ) 1165 itCheckTokenType(arg->argVarName, arg->argType); 1166 1167 if (akIdent(arg->argKind) == akeMsgSeqno) 1168 itCheckIntType(arg->argVarName, arg->argType); 1169 /* 1170 * if the built-in are not used, we cannot match 1171 * the type/size of the desciption provided by the user 1172 * with the one defined in message.h. 1173 */ 1174 1175 return TRUE; 1176} 1177 1178static void 1179rtCheckArgTypes(routine_t *rt) 1180{ 1181 if (rt->rtRequestPort == argNULL) 1182 error("%s %s doesn't have a server port argument", rtRoutineKindToStr(rt->rtKind), rt->rtName); 1183 1184 if ((rt->rtRequestPort != argNULL) && 1185 (rt->rtRequestPort->argType != itNULL)) 1186 itCheckRequestPortType(rt->rtRequestPort->argName, rt->rtRequestPort->argType); 1187 1188 if ((rt->rtReplyPort != argNULL) && 1189 (rt->rtReplyPort->argType != itNULL)) 1190 itCheckReplyPortType(rt->rtReplyPort->argName, rt->rtReplyPort->argType); 1191 1192 if ((rt->rtWaitTime != argNULL) && 1193 (rt->rtWaitTime->argType != itNULL)) 1194 itCheckIntType(rt->rtWaitTime->argName, rt->rtWaitTime->argType); 1195 1196 if ((rt->rtMsgOption != argNULL) && 1197 (rt->rtMsgOption->argType != itNULL)) 1198 itCheckIntType(rt->rtMsgOption->argName, rt->rtMsgOption->argType); 1199 1200 if ((IsKernelServer && rt->rtServerImpl) || 1201 (IsKernelUser && rt->rtUserImpl)) 1202 fatal("Implicit data is not supported in the KernelUser and KernelServer modes"); 1203 /* rtCheckTrailerType will hit a fatal() if something goes wrong */ 1204 if (rt->rtServerImpl) 1205 rtCheckMaskFunction(rt->rtArgs, akbServerImplicit, rtCheckTrailerType); 1206 if (rt->rtUserImpl) 1207 rtCheckMaskFunction(rt->rtArgs, akbUserImplicit, rtCheckTrailerType); 1208} 1209 1210/* 1211 * Check for arguments which are missing seemingly needed functions. 1212 * We make this check here instead of in itCheckDecl, because here 1213 * we can take into account what kind of argument the type is 1214 * being used with. 1215 * 1216 * These are warnings, not hard errors, because mig will generate 1217 * reasonable code in any case. The generated code will work fine 1218 * if the ServerType and TransType are really the same, even though 1219 * they have different names. 1220 */ 1221 1222static void 1223rtCheckArgTrans(routine_t *rt) 1224{ 1225 argument_t *arg; 1226 1227 /* the arg may not have a type (if there was some error in parsing it) */ 1228 1229 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1230 ipc_type_t *it = arg->argType; 1231 1232 if ((it != itNULL) && !streql(it->itServerType, it->itTransType)) { 1233 if (akCheck(arg->argKind, akbSendRcv) && (it->itInTrans == strNULL)) 1234 warn("%s: argument has no in-translation function", arg->argName); 1235 1236 if (akCheck(arg->argKind, akbReturnSnd) && (it->itOutTrans == strNULL)) 1237 warn("%s: argument has no out-translation function", arg->argName); 1238 } 1239 } 1240} 1241 1242/* 1243 * Adds an implicit return-code argument. It exists in the reply message, 1244 * where it is the first piece of data (After the NDR format label).. 1245 */ 1246 1247static void 1248rtAddRetCode(routine_t *rt) 1249{ 1250 argument_t *arg = argAlloc(); 1251 1252 arg->argName = "RetCode"; 1253 arg->argType = itRetCodeType; 1254 arg->argKind = akRetCode; 1255 rt->rtRetCode = arg; 1256 1257 arg->argNext = rt->rtArgs; 1258 rt->rtArgs = arg; 1259} 1260 1261/* 1262 * Process the Return Code. 1263 * The MIG protocol says that RetCode != 0 are only sent through 1264 * mig_reply_error_t structures. Therefore, there is no need 1265 * for reserving a RetCode in a complex Reply message. 1266 */ 1267static void 1268rtProcessRetCode(routine_t *rt) 1269{ 1270 if (!rt->rtOneWay && !rt->rtSimpleReply) { 1271 argument_t *arg = rt->rtRetCode; 1272 1273 arg->argKind = akRemFeature(arg->argKind, akbReply); 1274 /* we want the RetCode to be a local variable instead */ 1275 arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); 1276 } 1277 if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { 1278 argument_t *arg = rt->rtRetCArg; 1279 1280 arg->argKind = akeRetCode|akbUserArg|akbServerArg|akbSendRcv; 1281 } 1282} 1283 1284/* 1285 * Adds an implicit NDR argument. It exists in the reply message, 1286 * where it is the first piece of data. 1287 */ 1288 1289static void 1290rtAddNdrCode(routine_t *rt) 1291{ 1292 argument_t *arg = argAlloc(); 1293 1294 arg->argName = "NDR_record"; 1295 arg->argType = itNdrCodeType; 1296 arg->argKind = akeNdrCode; 1297 rt->rtNdrCode = arg; 1298 1299 /* add at beginning, so ndr-code is first in the reply message */ 1300 arg->argNext = rt->rtArgs; 1301 rt->rtArgs = arg; 1302} 1303 1304/* 1305 * Process the NDR Code. 1306 * We stick a NDR format label iff there is untyped data 1307 */ 1308static void 1309rtProcessNdrCode(routine_t *rt) 1310{ 1311 argument_t *ndr = rt->rtNdrCode; 1312 argument_t *arg; 1313 boolean_t found; 1314 1315 /* akbSendSnd|akbSendBody initialize the NDR format label */ 1316#define ndr_send akbRequest|akbSend|akbSendSnd|akbSendBody 1317 /* akbReplyInit initializes the NDR format label */ 1318#define ndr_rcv akbReply|akbReplyInit|akbReturn|akbReturnBody 1319 1320 ndr->argKind = akAddFeature(ndr->argKind, ndr_send|ndr_rcv); 1321 1322 for (found = FALSE, arg = ndr->argNext; arg != argNULL; arg = arg->argNext) 1323 if (akCheck(arg->argKind, akbSendRcv|akbSendBody) && 1324 !akCheck(arg->argKind, akbServerImplicit) && !arg->argType->itPortType && 1325 (!arg->argParent || akIdent(arg->argKind) == akeCount || 1326 akIdent(arg->argKind) == akeCountInOut)) { 1327 arg->argKind = akAddFeature(arg->argKind, akbSendNdr); 1328 found = TRUE; 1329 } 1330 if (!found) 1331 ndr->argKind = akRemFeature(ndr->argKind, ndr_send); 1332 1333 found = FALSE; 1334 if (!rt->rtOneWay) 1335 for (arg = ndr->argNext; arg != argNULL; arg = arg->argNext) 1336 if ((arg == rt->rtRetCode && akCheck(arg->argKind, akbReply)) || 1337 (arg != rt->rtRetCode && 1338 akCheck(arg->argKind, akbReturnRcv|akbReturnBody) && 1339 !akCheck(arg->argKind, akbUserImplicit) && !arg->argType->itPortType && 1340 (!arg->argParent || akIdent(arg->argKind) == akeCount || 1341 akIdent(arg->argKind) == akeCountInOut))) { 1342 arg->argKind = akAddFeature(arg->argKind, akbReturnNdr); 1343 found = TRUE; 1344 } 1345 if (!found && !akCheck(rt->rtRetCode->argKind, akbReply)) 1346 ndr->argKind = akRemFeature(ndr->argKind, ndr_rcv); 1347} 1348 1349/* 1350 * Adds a dummy WaitTime argument to the function. 1351 * This argument doesn't show up in any C argument lists; 1352 * it implements the global WaitTime statement. 1353 */ 1354 1355static void 1356rtAddWaitTime(routine_t *rt, identifier_t name, arg_kind_t kind) 1357{ 1358 argument_t *arg = argAlloc(); 1359 argument_t **loc; 1360 1361 arg->argName = "dummy WaitTime arg"; 1362 arg->argVarName = name; 1363 arg->argType = itWaitTimeType; 1364 arg->argKind = kind; 1365 rt->rtWaitTime = arg; 1366 1367 /* add wait-time after msg-option, if possible */ 1368 1369 if (rt->rtMsgOption != argNULL) 1370 loc = &rt->rtMsgOption->argNext; 1371 else 1372 loc = &rt->rtArgs; 1373 1374 arg->argNext = *loc; 1375 *loc = arg; 1376 1377 rtSetArgDefaults(rt, arg); 1378} 1379 1380/* 1381 * Adds a dummy MsgOption argument to the function. 1382 * This argument doesn't show up in any C argument lists; 1383 * it implements the global MsgOption statement. 1384 */ 1385 1386static void 1387rtAddMsgOption(routine_t *rt, identifier_t name) 1388{ 1389 argument_t *arg = argAlloc(); 1390 argument_t **loc; 1391 1392 arg->argName = "dummy MsgOption arg"; 1393 arg->argVarName = name; 1394 arg->argType = itMsgOptionType; 1395 arg->argKind = akeMsgOption; 1396 rt->rtMsgOption = arg; 1397 1398 /* add msg-option after msg-seqno */ 1399 1400 loc = &rt->rtArgs; 1401 1402 arg->argNext = *loc; 1403 *loc = arg; 1404 1405 rtSetArgDefaults(rt, arg); 1406} 1407 1408/* 1409 * Process the MsgOption Code. 1410 * We must add the information to post a receive with the right 1411 * Trailer options. 1412 */ 1413static void 1414rtProcessMsgOption(routine_t *rt) 1415{ 1416 argument_t *msgop = rt->rtMsgOption; 1417 argument_t *arg; 1418 boolean_t sectoken = FALSE; 1419 boolean_t audittoken = FALSE; 1420 boolean_t contexttoken = FALSE; 1421 1422 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 1423 if (akCheckAll(arg->argKind, akbReturn|akbUserImplicit)) { 1424 if (akIdent(arg->argKind) == akeSecToken) 1425 sectoken = TRUE; 1426 else if (akIdent(arg->argKind) == akeAuditToken) 1427 audittoken = TRUE; 1428 else if (akIdent(arg->argKind) == akeContextToken) 1429 contexttoken = TRUE; 1430 } 1431 1432 if (contexttoken == TRUE) 1433 msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX)"); 1434 else if (audittoken == TRUE) 1435 msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)"); 1436 else if (sectoken == TRUE) 1437 msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)"); 1438 /* other implicit data received by the user will be handled here */ 1439} 1440 1441static void 1442rtProcessUseSpecialReplyPort(routine_t *rt) 1443{ 1444 if (IsKernelUser || IsKernelServer) { 1445 fatal("UseSpecialReplyPort option cannot be used with KernelUser / KernelServer\n"); 1446 } 1447 rt->rtMsgOption->argVarName = strconcat(rt->rtMsgOption->argVarName, "|__MigSpecialReplyPortMsgOption"); 1448} 1449 1450/* 1451 * Adds a dummy reply port argument to the function. 1452 */ 1453 1454static void 1455rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type) 1456{ 1457 argument_t *arg = argAlloc(); 1458 argument_t **loc; 1459 1460 arg->argName = "dummy ReplyPort arg"; 1461 arg->argVarName = "dummy ReplyPort arg"; 1462 arg->argType = type; 1463 arg->argKind = akeReplyPort; 1464 rt->rtReplyPort = arg; 1465 1466 /* add the reply port after the request port */ 1467 1468 if (rt->rtRequestPort != argNULL) 1469 loc = &rt->rtRequestPort->argNext; 1470 else 1471 loc = &rt->rtArgs; 1472 1473 arg->argNext = *loc; 1474 *loc = arg; 1475 1476 rtSetArgDefaults(rt, arg); 1477} 1478 1479 1480/* 1481 * At least one overwrite keyword has been detected: 1482 * we tag all the OOL entries (ports + data) with 1483 * akbOverwrite which will tell us that we have to 1484 * fill a KPD entry in the message-template 1485 */ 1486static void 1487rtCheckOverwrite(routine_t *rt) 1488{ 1489 argument_t *arg; 1490 int howmany = rt->rtOverwrite; 1491 1492 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1493 ipc_type_t *it = arg->argType; 1494 1495 if (akCheck(arg->argKind, akbReturnKPD) && !it->itInLine) { 1496 /* among OUT args, we want OOL, OOL ports and MigInLine */ 1497 arg->argKind = akAddFeature(arg->argKind, akbOverwrite); 1498 if (arg->argFlags & flOverwrite) 1499 howmany--; 1500 if (!howmany) 1501 return; 1502 } 1503 } 1504} 1505 1506/* 1507 * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos, 1508 * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments 1509 * that need it because of variable-sized inline considerations. 1510 * 1511 * argRequestPos and argReplyPos get -1 if the value shouldn't be used. 1512 */ 1513static void 1514rtCheckVariable(routine_t *rt) 1515{ 1516 argument_t *arg; 1517 int NumRequestVar = 0; 1518 int NumReplyVar = 0; 1519 int MaxRequestPos = 0; 1520 int MaxReplyPos = 0; 1521 1522 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1523 argument_t *parent = arg->argParent; 1524 1525 /* 1526 * We skip KPDs. We have to make sure that the KPDs count 1527 * present in the message body follow the RequestPos/ReplyPos logic 1528 * The rest of the parameters are defaulted to have 1529 * Arg{Request, Reply}Pos = 0 1530 */ 1531 if (parent == argNULL || akCheck(parent->argKind, akbSendKPD|akbReturnKPD)) { 1532 if (akCheckAll(arg->argKind, akbSend|akbSendBody)) { 1533 arg->argRequestPos = NumRequestVar; 1534 MaxRequestPos = NumRequestVar; 1535 if (akCheck(arg->argKind, akbVariable)) 1536 NumRequestVar++; 1537 } 1538 if (akCheckAll(arg->argKind, akbReturn|akbReturnBody)) { 1539 arg->argReplyPos = NumReplyVar; 1540 MaxReplyPos = NumReplyVar; 1541 if (akCheck(arg->argKind, akbVariable)) 1542 NumReplyVar++; 1543 } 1544 } 1545 else { 1546 arg->argRequestPos = parent->argRequestPos; 1547 arg->argReplyPos = parent->argReplyPos; 1548 } 1549 1550 if (UseMachMsg2) { 1551 /* Kernel processed data must have Request/Reply pos of 0 */ 1552 if (akCheck(arg->argKind, akbSendKPD)) { 1553 assert(arg->argRequestPos == 0); 1554 } 1555 if (akCheck(arg->argKind, akbReturnKPD)) { 1556 assert(arg->argReplyPos == 0); 1557 } 1558 } 1559 /* 1560 printf("Var %s Kind %x RequestPos %d\n", arg->argVarName, arg->argKind, arg->argRequestPos); 1561 printf("* Var %s Kind %x ReplyPos %d\n", arg->argVarName, arg->argKind, arg->argReplyPos); 1562 */ 1563 1564 /* Out variables that follow a variable-sized field 1565 need VarNeeded or ReplyCopy; they can't be stored 1566 directly into the reply message. */ 1567 1568 if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody) && 1569 !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) && 1570 (arg->argReplyPos > 0)) 1571 arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); 1572 } 1573 1574 rt->rtNumRequestVar = NumRequestVar; 1575 rt->rtNumReplyVar = NumReplyVar; 1576 rt->rtMaxRequestPos = MaxRequestPos; 1577 rt->rtMaxReplyPos = MaxReplyPos; 1578} 1579 1580/* 1581 * Adds akbDestroy where needed. 1582 */ 1583 1584static void 1585rtCheckDestroy(routine_t *rt) 1586{ 1587 argument_t *arg; 1588 1589 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1590 ipc_type_t *it = arg->argType; 1591 1592 if(akCheck(arg->argKind, akbSendRcv) && 1593 !akCheck(arg->argKind, akbReturnSnd) && 1594 (it->itDestructor != strNULL || IS_MIG_INLINE_EMUL(it))) { 1595 arg->argKind = akAddFeature(arg->argKind, akbDestroy); 1596 } 1597 if (argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && 1598 arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR && 1599 (arg->argFlags & flAuto)) 1600 arg->argKind = akAddFeature(arg->argKind, akbDestroy); 1601 } 1602} 1603 1604/* 1605 * Sets ByReferenceUser and ByReferenceServer. 1606 */ 1607 1608static void 1609rtAddByReference(routine_t *rt) 1610{ 1611 argument_t *arg; 1612 1613 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1614 ipc_type_t *it = arg->argType; 1615 1616 if (akCheck(arg->argKind, akbReturnRcv) && it->itStruct) { 1617 arg->argByReferenceUser = TRUE; 1618 1619 /* 1620 * A CountInOut arg itself is not akbReturnRcv, 1621 * so we need to set argByReferenceUser specially. 1622 */ 1623 1624 if (arg->argCInOut != argNULL) 1625 arg->argCInOut->argByReferenceUser = TRUE; 1626 } 1627 1628 if ((akCheck(arg->argKind, akbReturnSnd) || 1629 (akCheck(arg->argKind, akbServerImplicit) && 1630 akCheck(arg->argKind, akbReturnRcv) && 1631 akCheck(arg->argKind, akbSendRcv))) 1632 && it->itStruct) { 1633 arg->argByReferenceServer = TRUE; 1634 if (IsKernelServer && IS_KERN_PROC_DATA(it)) { 1635 /* because of PAC we can't take the address of a signed pointer */ 1636 arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); 1637 } 1638 } 1639 } 1640} 1641 1642/* 1643 * This procedure can be executed only when all the akb* and ake* have 1644 * been set properly (when rtAddCountArg is executed, akbVarNeeded 1645 * might not be set yet - see rtCheckVariable) 1646 */ 1647void 1648rtAddSameCount(routine_t *rt) 1649{ 1650 argument_t *arg; 1651 1652 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 1653 if (arg->argFlags & flSameCount) { 1654 ipc_type_t *it = arg->argType; 1655 argument_t *tmp_count; 1656 argument_t *my_count = arg->argCount; 1657 argument_t *ref_count = arg->argSameCount->argCount; 1658 1659 tmp_count = argAlloc(); 1660 *tmp_count = *ref_count; 1661 /* 1662 * if our count is a akbVarNeeded, we need to copy this 1663 * attribute to the master count! 1664 */ 1665 tmp_count->argKind = akeSameCount; 1666 ref_count->argKind = akAddFeature(ref_count->argKind, akCheck(my_count->argKind, akbVarNeeded)); 1667 tmp_count->argKind = akAddFeature(tmp_count->argKind, akCheck(my_count->argKind, akbVarNeeded)); 1668 tmp_count->argNext = my_count->argNext; 1669 tmp_count->argMultiplier = my_count->argMultiplier; 1670 tmp_count->argType = my_count->argType; 1671 tmp_count->argParent = arg; 1672 /* we don't need more */ 1673 arg->argCount = tmp_count; 1674 arg->argNext = tmp_count; 1675 /* for these args, Cnt is not akbRequest, and therefore size is embedded */ 1676 if (IS_VARIABLE_SIZED_UNTYPED(it)) 1677 it->itMinTypeSize = 0; 1678 tmp_count->argType->itMinTypeSize = 0; 1679 tmp_count->argType->itTypeSize = 0; 1680 } 1681} 1682 1683static void 1684rtAddArgSegment(routine_t *rt) 1685{ 1686 argument_t *arg; 1687 1688 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { 1689 ipc_type_t *it = arg->argType; 1690 if (!UseMachMsg2) { 1691 char *segIn = malloc(16); 1692 if (!segIn) 1693 fatal("Unable to allocate argInSegment"); 1694 sprintf(segIn, "In%dP", arg->argRequestPos); 1695 arg->argInSegment = segIn; 1696 arg->argOutSegment = "OutP"; 1697 } else if (IS_KERN_PROC_DATA(it) || 1698 (akIdent(arg->argKind) == akePoly && 1699 IS_KERN_PROC_DATA(arg->argParent->argType))) { 1700 arg->argInSegment = "InKP"; 1701 arg->argOutSegment = "OutKP"; 1702 } else { 1703 char *segIn = malloc(16); 1704 if (!segIn) 1705 fatal("Unable to allocate argInSegment"); 1706 sprintf(segIn, "In%dUP", arg->argRequestPos); 1707 arg->argInSegment = segIn; 1708 arg->argOutSegment = "OutUP"; 1709 } 1710 } 1711} 1712 1713void 1714rtCheckRoutine(routine_t *rt) 1715{ 1716 /* Initialize random fields. */ 1717 1718 rt->rtErrorName = ErrorProc; 1719 rt->rtOneWay = (rt->rtKind == rkSimpleRoutine); 1720 rt->rtServerName = strconcat(ServerPrefix, rt->rtName); 1721 rt->rtUserName = strconcat(UserPrefix, rt->rtName); 1722 rt->rtUseSpecialReplyPort = UseSpecialReplyPort && !rt->rtOneWay; 1723 rt->rtConsumeOnSendError = ConsumeOnSendError; 1724 1725 /* Add implicit arguments. */ 1726 1727 rtAddRetCode(rt); 1728 rtAddNdrCode(rt); 1729 1730 /* Check out the arguments and their types. Add count, poly 1731 implicit args. Any arguments added after rtCheckRoutineArgs 1732 should have rtSetArgDefaults called on them. */ 1733 1734 rtCheckRoutineArgs(rt); 1735 1736 /* Add dummy WaitTime and MsgOption arguments, if the routine 1737 doesn't have its own args and the user specified global values. */ 1738 1739 if (rt->rtReplyPort == argNULL) { 1740 if (rt->rtOneWay) 1741 rtAddDummyReplyPort(rt, itZeroReplyPortType); 1742 else 1743 rtAddDummyReplyPort(rt, itRealReplyPortType); 1744 } else if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) { 1745 /* If an explicit ReplyPort is used, we can't assume it will be the SRP */ 1746 rt->rtUseSpecialReplyPort = FALSE; 1747 } 1748 if (rt->rtMsgOption == argNULL) { 1749 if (MsgOption == strNULL) 1750 rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE"); 1751 else 1752 rtAddMsgOption(rt, MsgOption); 1753 } 1754 if (rt->rtWaitTime == argNULL) { 1755 if (WaitTime != strNULL) 1756 rtAddWaitTime(rt, WaitTime, akeWaitTime); 1757 else if (SendTime != strNULL) 1758 rtAddWaitTime(rt, SendTime, akeSendTime); 1759 } 1760 if (rt->rtWaitTime && rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) { 1761 warn("%s %s specifies a SendTime/WaitTime which may leak resources, " 1762 "adopt \"ConsumeOnSendError Timeout\"", 1763 rtRoutineKindToStr(rt->rtKind), rt->rtName); 1764 } 1765 1766 1767 /* Now that all the arguments are in place, do more checking. */ 1768 1769 rtCheckArgTypes(rt); 1770 rtCheckArgTrans(rt); 1771 1772 if (rt->rtOneWay) { 1773 if (rtCheckMask(rt->rtArgs, akbReturn) || rt->rtUserImpl) 1774 error("%s %s has OUT argument", rtRoutineKindToStr(rt->rtKind), rt->rtName); 1775 } 1776 1777 /* If there were any errors, don't bother calculating more info 1778 that is only used in code generation anyway. Therefore, 1779 the following functions don't have to worry about null types. */ 1780 1781 if (mig_errors > 0) 1782 fatal("%d errors found. Abort.\n", mig_errors); 1783 1784 rt->rtServerImpl = rtCountMask(rt->rtArgs, akbServerImplicit); 1785 rt->rtUserImpl = rtCountMask(rt->rtArgs, akbUserImplicit); 1786 /* 1787 * ASSUMPTION: 1788 * kernel cannot change a message from simple to complex, 1789 * therefore SimpleSendReply and SimpleRcvReply become SimpleReply 1790 */ 1791 rtCheckSimple(rt->rtArgs, akbRequest, &rt->rtSimpleRequest); 1792 rtCheckSimple(rt->rtArgs, akbReply, &rt->rtSimpleReply); 1793 1794 rt->rtRequestKPDs = rtCountKPDs(rt->rtArgs, akbSendKPD); 1795 rt->rtReplyKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD); 1796 /* 1797 * Determine how many overwrite parameters we have: 1798 * # of Overwrite args -> rt->rtOverwrite 1799 * flOverwrite -> the arg has to be overwritten 1800 * akbOverwrite -> the arg has to be declared in the message-template 1801 * (only as a placeholder if !flOverwrite). 1802 */ 1803 if ((rt->rtOverwrite = rtCountFlags(rt->rtArgs, flOverwrite))) { 1804 rtCheckOverwrite(rt); 1805 rt->rtOverwriteKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD|akbOverwrite); 1806 if (IsKernelUser) 1807 fatal("Overwrite option(s) do not match with the KernelUser personality\n"); 1808 } 1809 1810 rtCheckFit(rt, akbRequest, &rt->rtRequestFits, &rt->rtRequestUsedLimit, &rt->rtRequestSizeKnown); 1811 rtCheckFit(rt, akbReply, &rt->rtReplyFits, &rt->rtReplyUsedLimit, &rt->rtReplySizeKnown); 1812 1813 rtCheckVariable(rt); 1814 rtCheckDestroy(rt); 1815 rtAddByReference(rt); 1816 rtSuffixExtArg(rt->rtArgs); 1817 rtAddSameCount(rt); 1818 rtProcessRetCode(rt); 1819 rtProcessNdrCode(rt); 1820 if (rt->rtUserImpl) 1821 rtProcessMsgOption(rt); 1822 if (rt->rtUseSpecialReplyPort) 1823 rtProcessUseSpecialReplyPort(rt); 1824 1825 rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd); 1826 1827 rtAddArgSegment(rt); 1828 1829 if (UseEventLogger) 1830 /* some more info's are needed for Event logging/Stats */ 1831 rtFindHowMany(rt); 1832} 1833 1834void 1835rtMinRequestSize(FILE *file, routine_t *rt, char *str) 1836{ 1837 fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); 1838 rtSizeDelta(file, akbRequest, rt); 1839 fprintf(file, ")"); 1840} 1841 1842void 1843rtMinReplySize(FILE *file, routine_t *rt, char *str) 1844{ 1845 fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); 1846 rtSizeDelta(file, akbReply, rt); 1847 fprintf(file, ")"); 1848} 1849 1850static void 1851rtSizeDelta(FILE *file, u_int mask, routine_t *rt) 1852{ 1853 argument_t *arg; 1854 u_int min_size = sizeof(mach_msg_header_t); 1855 u_int max_size; 1856 boolean_t output = FALSE; 1857 1858 if (!rt->rtSimpleRequest) 1859 machine_alignment(min_size, sizeof(mach_msg_body_t)); 1860 max_size = min_size; 1861 for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) 1862 if (akCheck(arg->argKind, mask)) { 1863 ipc_type_t *it = arg->argType; 1864 1865 machine_alignment(min_size, it->itMinTypeSize); 1866 machine_alignment(max_size, it->itMinTypeSize); 1867 1868 if (IS_VARIABLE_SIZED_UNTYPED(it)) { 1869 machine_alignment(max_size, it->itTypeSize); 1870 max_size += it->itPadSize; 1871 } 1872 if (IS_OPTIONAL_NATIVE(it)) { 1873 if (output) 1874 fprintf(file, " + "); 1875 else { 1876 output = TRUE; 1877 fprintf(file, " - ("); 1878 } 1879 fprintf(file, "_WALIGNSZ_(%s)", it->itUserType); 1880 } 1881 } 1882 if (min_size != max_size) { 1883 if (output) 1884 fprintf(file, " + "); 1885 else 1886 fprintf(file, " - "); 1887 fprintf(file, "%d", max_size - min_size); 1888 } 1889 if (output) 1890 fprintf(file, ")"); 1891} 1892