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