From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- bootstrap_cmds/.gitignore | 6 + bootstrap_cmds/APPLE_LICENSE | 335 +++ bootstrap_cmds/mig.xcodeproj/project.pbxproj | 310 +++ bootstrap_cmds/migcom.tproj/alloc.h | 54 + bootstrap_cmds/migcom.tproj/error.c | 111 + bootstrap_cmds/migcom.tproj/error.h | 61 + bootstrap_cmds/migcom.tproj/global.c | 151 ++ bootstrap_cmds/migcom.tproj/global.h | 113 + bootstrap_cmds/migcom.tproj/handler.c | 754 ++++++ bootstrap_cmds/migcom.tproj/header.c | 569 +++++ bootstrap_cmds/migcom.tproj/lexxer.h | 52 + bootstrap_cmds/migcom.tproj/lexxer.l | 314 +++ bootstrap_cmds/migcom.tproj/mig.1 | 88 + bootstrap_cmds/migcom.tproj/mig.c | 405 ++++ bootstrap_cmds/migcom.tproj/mig.sh | 218 ++ bootstrap_cmds/migcom.tproj/mig_errors.h | 84 + bootstrap_cmds/migcom.tproj/mig_machine.h | 16 + bootstrap_cmds/migcom.tproj/migcom.1 | 73 + bootstrap_cmds/migcom.tproj/parser.y | 803 +++++++ bootstrap_cmds/migcom.tproj/routine.c | 1844 +++++++++++++++ bootstrap_cmds/migcom.tproj/routine.h | 549 +++++ bootstrap_cmds/migcom.tproj/server.c | 2772 ++++++++++++++++++++++ bootstrap_cmds/migcom.tproj/statement.c | 68 + bootstrap_cmds/migcom.tproj/statement.h | 98 + bootstrap_cmds/migcom.tproj/strdefs.h | 93 + bootstrap_cmds/migcom.tproj/string.c | 132 ++ bootstrap_cmds/migcom.tproj/type.c | 899 +++++++ bootstrap_cmds/migcom.tproj/type.h | 270 +++ bootstrap_cmds/migcom.tproj/user.c | 3260 ++++++++++++++++++++++++++ bootstrap_cmds/migcom.tproj/utils.c | 1043 ++++++++ bootstrap_cmds/migcom.tproj/utils.h | 140 ++ bootstrap_cmds/migcom.tproj/write.h | 78 + bootstrap_cmds/xcodescripts/install-mig.sh | 8 + 33 files changed, 15771 insertions(+) create mode 100644 bootstrap_cmds/.gitignore create mode 100644 bootstrap_cmds/APPLE_LICENSE create mode 100644 bootstrap_cmds/mig.xcodeproj/project.pbxproj create mode 100644 bootstrap_cmds/migcom.tproj/alloc.h create mode 100644 bootstrap_cmds/migcom.tproj/error.c create mode 100644 bootstrap_cmds/migcom.tproj/error.h create mode 100644 bootstrap_cmds/migcom.tproj/global.c create mode 100644 bootstrap_cmds/migcom.tproj/global.h create mode 100644 bootstrap_cmds/migcom.tproj/handler.c create mode 100644 bootstrap_cmds/migcom.tproj/header.c create mode 100644 bootstrap_cmds/migcom.tproj/lexxer.h create mode 100644 bootstrap_cmds/migcom.tproj/lexxer.l create mode 100644 bootstrap_cmds/migcom.tproj/mig.1 create mode 100644 bootstrap_cmds/migcom.tproj/mig.c create mode 100644 bootstrap_cmds/migcom.tproj/mig.sh create mode 100644 bootstrap_cmds/migcom.tproj/mig_errors.h create mode 100644 bootstrap_cmds/migcom.tproj/mig_machine.h create mode 100644 bootstrap_cmds/migcom.tproj/migcom.1 create mode 100644 bootstrap_cmds/migcom.tproj/parser.y create mode 100644 bootstrap_cmds/migcom.tproj/routine.c create mode 100644 bootstrap_cmds/migcom.tproj/routine.h create mode 100644 bootstrap_cmds/migcom.tproj/server.c create mode 100644 bootstrap_cmds/migcom.tproj/statement.c create mode 100644 bootstrap_cmds/migcom.tproj/statement.h create mode 100644 bootstrap_cmds/migcom.tproj/strdefs.h create mode 100644 bootstrap_cmds/migcom.tproj/string.c create mode 100644 bootstrap_cmds/migcom.tproj/type.c create mode 100644 bootstrap_cmds/migcom.tproj/type.h create mode 100644 bootstrap_cmds/migcom.tproj/user.c create mode 100644 bootstrap_cmds/migcom.tproj/utils.c create mode 100644 bootstrap_cmds/migcom.tproj/utils.h create mode 100644 bootstrap_cmds/migcom.tproj/write.h create mode 100644 bootstrap_cmds/xcodescripts/install-mig.sh (limited to 'bootstrap_cmds') diff --git a/bootstrap_cmds/.gitignore b/bootstrap_cmds/.gitignore new file mode 100644 index 0000000..e073c02 --- /dev/null +++ b/bootstrap_cmds/.gitignore @@ -0,0 +1,6 @@ +BUILD/ +build/ +.DS_Store +/mig.xcodeproj/project.xcworkspace/ +/mig.xcodeproj/xcuserdata/ +*~ diff --git a/bootstrap_cmds/APPLE_LICENSE b/bootstrap_cmds/APPLE_LICENSE new file mode 100644 index 0000000..71fe6fd --- /dev/null +++ b/bootstrap_cmds/APPLE_LICENSE @@ -0,0 +1,335 @@ +APPLE PUBLIC SOURCE LICENSE +Version 2.0 - August 6, 2003 + +Please read this License carefully before downloading this software. By +downloading or using this software, you are agreeing to be bound by the terms +of this License. If you do not or cannot agree to the terms of this License, +please do not download or use the software. + +Apple Note: In January 2007, Apple changed its corporate name from "Apple +Computer, Inc." to "Apple Inc." This change has been reflected below and +copyright years updated, but no other changes have been made to the APSL 2.0. + +1. General; Definitions. This License applies to any program or other +work which Apple Inc. ("Apple") makes publicly available and which contains a +notice placed by Apple identifying such program or work as "Original Code" and +stating that it is subject to the terms of this Apple Public Source License +version 2.0 ("License"). As used in this License: + +1.1 "Applicable Patent Rights" mean: (a) in the case where Apple is the +grantor of rights, (i) claims of patents that are now or hereafter acquired, +owned by or assigned to Apple and (ii) that cover subject matter contained in +the Original Code, but only to the extent necessary to use, reproduce and/or +distribute the Original Code without infringement; and (b) in the case where +You are the grantor of rights, (i) claims of patents that are now or hereafter +acquired, owned by or assigned to You and (ii) that cover subject matter in +Your Modifications, taken alone or in combination with Original Code. + +1.2 "Contributor" means any person or entity that creates or contributes to +the creation of Modifications. + +1.3 "Covered Code" means the Original Code, Modifications, the combination +of Original Code and any Modifications, and/or any respective portions thereof. + +1.4 "Externally Deploy" means: (a) to sublicense, distribute or otherwise +make Covered Code available, directly or indirectly, to anyone other than You; +and/or (b) to use Covered Code, alone or as part of a Larger Work, in any way +to provide a service, including but not limited to delivery of content, through +electronic communication with a client other than You. + +1.5 "Larger Work" means a work which combines Covered Code or portions +thereof with code not governed by the terms of this License. + +1.6 "Modifications" mean any addition to, deletion from, and/or change to, +the substance and/or structure of the Original Code, any previous +Modifications, the combination of Original Code and any previous Modifications, +and/or any respective portions thereof. When code is released as a series of +files, a Modification is: (a) any addition to or deletion from the contents of +a file containing Covered Code; and/or (b) any new file or other representation +of computer program statements that contains any part of Covered Code. + +1.7 "Original Code" means (a) the Source Code of a program or other work as +originally made available by Apple under this License, including the Source +Code of any updates or upgrades to such programs or works made available by +Apple under this License, and that has been expressly identified by Apple as +such in the header file(s) of such work; and (b) the object code compiled from +such Source Code and originally made available by Apple under this License + +1.8 "Source Code" means the human readable form of a program or other work +that is suitable for making modifications to it, including all modules it +contains, plus any associated interface definition files, scripts used to +control compilation and installation of an executable (object code). + +1.9 "You" or "Your" means an individual or a legal entity exercising rights +under this License. For legal entities, "You" or "Your" includes any entity +which controls, is controlled by, or is under common control with, You, where +"control" means (a) the power, direct or indirect, to cause the direction or +management of such entity, whether by contract or otherwise, or (b) ownership +of fifty percent (50%) or more of the outstanding shares or beneficial +ownership of such entity. + +2. Permitted Uses; Conditions & Restrictions. Subject to the terms and +conditions of this License, Apple hereby grants You, effective on the date You +accept this License and download the Original Code, a world-wide, royalty-free, +non-exclusive license, to the extent of Apple's Applicable Patent Rights and +copyrights covering the Original Code, to do the following: + +2.1 Unmodified Code. You may use, reproduce, display, perform, internally +distribute within Your organization, and Externally Deploy verbatim, unmodified +copies of the Original Code, for commercial or non-commercial purposes, +provided that in each instance: + +(a) You must retain and reproduce in all copies of Original Code the +copyright and other proprietary notices and disclaimers of Apple as they appear +in the Original Code, and keep intact all notices in the Original Code that +refer to this License; and + +(b) You must include a copy of this License with every copy of Source Code +of Covered Code and documentation You distribute or Externally Deploy, and You +may not offer or impose any terms on such Source Code that alter or restrict +this License or the recipients' rights hereunder, except as permitted under +Section 6. + +2.2 Modified Code. You may modify Covered Code and use, reproduce, +display, perform, internally distribute within Your organization, and +Externally Deploy Your Modifications and Covered Code, for commercial or +non-commercial purposes, provided that in each instance You also meet all of +these conditions: + +(a) You must satisfy all the conditions of Section 2.1 with respect to the +Source Code of the Covered Code; + +(b) You must duplicate, to the extent it does not already exist, the notice +in Exhibit A in each file of the Source Code of all Your Modifications, and +cause the modified files to carry prominent notices stating that You changed +the files and the date of any change; and + +(c) If You Externally Deploy Your Modifications, You must make Source Code +of all Your Externally Deployed Modifications either available to those to whom +You have Externally Deployed Your Modifications, or publicly available. Source +Code of Your Externally Deployed Modifications must be released under the terms +set forth in this License, including the license grants set forth in Section 3 +below, for as long as you Externally Deploy the Covered Code or twelve (12) +months from the date of initial External Deployment, whichever is longer. You +should preferably distribute the Source Code of Your Externally Deployed +Modifications electronically (e.g. download from a web site). + +2.3 Distribution of Executable Versions. In addition, if You Externally +Deploy Covered Code (Original Code and/or Modifications) in object code, +executable form only, You must include a prominent notice, in the code itself +as well as in related documentation, stating that Source Code of the Covered +Code is available under the terms of this License with information on how and +where to obtain such Source Code. + +2.4 Third Party Rights. You expressly acknowledge and agree that although +Apple and each Contributor grants the licenses to their respective portions of +the Covered Code set forth herein, no assurances are provided by Apple or any +Contributor that the Covered Code does not infringe the patent or other +intellectual property rights of any other entity. Apple and each Contributor +disclaim any liability to You for claims brought by any other entity based on +infringement of intellectual property rights or otherwise. As a condition to +exercising the rights and licenses granted hereunder, You hereby assume sole +responsibility to secure any other intellectual property rights needed, if any. +For example, if a third party patent license is required to allow You to +distribute the Covered Code, it is Your responsibility to acquire that license +before distributing the Covered Code. + +3. Your Grants. In consideration of, and as a condition to, the licenses +granted to You under this License, You hereby grant to any person or entity +receiving or distributing Covered Code under this License a non-exclusive, +royalty-free, perpetual, irrevocable license, under Your Applicable Patent +Rights and other intellectual property rights (other than patent) owned or +controlled by You, to use, reproduce, display, perform, modify, sublicense, +distribute and Externally Deploy Your Modifications of the same scope and +extent as Apple's licenses under Sections 2.1 and 2.2 above. + +4. Larger Works. You may create a Larger Work by combining Covered Code +with other code not governed by the terms of this License and distribute the +Larger Work as a single product. In each such instance, You must make sure the +requirements of this License are fulfilled for the Covered Code or any portion +thereof. + +5. Limitations on Patent License. Except as expressly stated in Section +2, no other patent rights, express or implied, are granted by Apple herein. +Modifications and/or Larger Works may require additional patent licenses from +Apple which Apple may grant in its sole discretion. + +6. Additional Terms. You may choose to offer, and to charge a fee for, +warranty, support, indemnity or liability obligations and/or other rights +consistent with the scope of the license granted herein ("Additional Terms") to +one or more recipients of Covered Code. However, You may do so only on Your own +behalf and as Your sole responsibility, and not on behalf of Apple or any +Contributor. You must obtain the recipient's agreement that any such Additional +Terms are offered by You alone, and You hereby agree to indemnify, defend and +hold Apple and every Contributor harmless for any liability incurred by or +claims asserted against Apple or such Contributor by reason of any such +Additional Terms. + +7. Versions of the License. Apple may publish revised and/or new versions +of this License from time to time. Each version will be given a distinguishing +version number. Once Original Code has been published under a particular +version of this License, You may continue to use it under the terms of that +version. You may also choose to use such Original Code under the terms of any +subsequent version of this License published by Apple. No one other than Apple +has the right to modify the terms applicable to Covered Code created under this +License. + +8. NO WARRANTY OR SUPPORT. The Covered Code may contain in whole or in +part pre-release, untested, or not fully tested works. The Covered Code may +contain errors that could cause failures or loss of data, and may be incomplete +or contain inaccuracies. You expressly acknowledge and agree that use of the +Covered Code, or any portion thereof, is at Your sole and entire risk. THE +COVERED CODE IS PROVIDED "AS IS" AND WITHOUT WARRANTY, UPGRADES OR SUPPORT OF +ANY KIND AND APPLE AND APPLE'S LICENSOR(S) (COLLECTIVELY REFERRED TO AS "APPLE" +FOR THE PURPOSES OF SECTIONS 8 AND 9) AND ALL CONTRIBUTORS EXPRESSLY DISCLAIM +ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF +SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF +QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. APPLE AND EACH +CONTRIBUTOR DOES NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE +COVERED CODE, THAT THE FUNCTIONS CONTAINED IN THE COVERED CODE WILL MEET YOUR +REQUIREMENTS, THAT THE OPERATION OF THE COVERED CODE WILL BE UNINTERRUPTED OR +ERROR-FREE, OR THAT DEFECTS IN THE COVERED CODE WILL BE CORRECTED. NO ORAL OR +WRITTEN INFORMATION OR ADVICE GIVEN BY APPLE, AN APPLE AUTHORIZED +REPRESENTATIVE OR ANY CONTRIBUTOR SHALL CREATE A WARRANTY. You acknowledge +that the Covered Code is not intended for use in the operation of nuclear +facilities, aircraft navigation, communication systems, or air traffic control +machines in which case the failure of the Covered Code could lead to death, +personal injury, or severe physical or environmental damage. + +9. LIMITATION OF LIABILITY. TO THE EXTENT NOT PROHIBITED BY LAW, IN NO +EVENT SHALL APPLE OR ANY CONTRIBUTOR BE LIABLE FOR ANY INCIDENTAL, SPECIAL, +INDIRECT OR CONSEQUENTIAL DAMAGES ARISING OUT OF OR RELATING TO THIS LICENSE OR +YOUR USE OR INABILITY TO USE THE COVERED CODE, OR ANY PORTION THEREOF, WHETHER +UNDER A THEORY OF CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), PRODUCTS +LIABILITY OR OTHERWISE, EVEN IF APPLE OR SUCH CONTRIBUTOR HAS BEEN ADVISED OF +THE POSSIBILITY OF SUCH DAMAGES AND NOTWITHSTANDING THE FAILURE OF ESSENTIAL +PURPOSE OF ANY REMEDY. SOME JURISDICTIONS DO NOT ALLOW THE LIMITATION OF +LIABILITY OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS LIMITATION MAY NOT +APPLY TO YOU. In no event shall Apple's total liability to You for all damages +(other than as may be required by applicable law) under this License exceed the +amount of fifty dollars ($50.00). + +10. Trademarks. This License does not grant any rights to use the +trademarks or trade names "Apple", "Mac", "Mac OS", "QuickTime", "QuickTime +Streaming Server" or any other trademarks, service marks, logos or trade names +belonging to Apple (collectively "Apple Marks") or to any trademark, service +mark, logo or trade name belonging to any Contributor. You agree not to use +any Apple Marks in or as part of the name of products derived from the Original +Code or to endorse or promote products derived from the Original Code other +than as expressly permitted by and in strict compliance at all times with +Apple's third party trademark usage guidelines which are posted at +http://www.apple.com/legal/guidelinesfor3rdparties.html. + +11. Ownership. Subject to the licenses granted under this License, each +Contributor retains all rights, title and interest in and to any Modifications +made by such Contributor. Apple retains all rights, title and interest in and +to the Original Code and any Modifications made by or on behalf of Apple +("Apple Modifications"), and such Apple Modifications will not be automatically +subject to this License. Apple may, at its sole discretion, choose to license +such Apple Modifications under this License, or on different terms from those +contained in this License or may choose not to license them at all. + +12. Termination. + +12.1 Termination. This License and the rights granted hereunder will +terminate: + +(a) automatically without notice from Apple if You fail to comply with any +term(s) of this License and fail to cure such breach within 30 days of becoming +aware of such breach; +(b) immediately in the event of the circumstances described in Section +13.5(b); or +(c) automatically without notice from Apple if You, at any time during the +term of this License, commence an action for patent infringement against Apple; +provided that Apple did not first commence an action for patent infringement +against You in that instance. + +12.2 Effect of Termination. Upon termination, You agree to immediately stop +any further use, reproduction, modification, sublicensing and distribution of +the Covered Code. All sublicenses to the Covered Code which have been properly +granted prior to termination shall survive any termination of this License. +Provisions which, by their nature, should remain in effect beyond the +termination of this License shall survive, including but not limited to +Sections 3, 5, 8, 9, 10, 11, 12.2 and 13. No party will be liable to any other +for compensation, indemnity or damages of any sort solely as a result of +terminating this License in accordance with its terms, and termination of this +License will be without prejudice to any other right or remedy of any party. + +13. Miscellaneous. + +13.1 Government End Users. The Covered Code is a "commercial item" as +defined in FAR 2.101. Government software and technical data rights in the +Covered Code include only those rights customarily provided to the public as +defined in this License. This customary commercial license in technical data +and software is provided in accordance with FAR 12.211 (Technical Data) and +12.212 (Computer Software) and, for Department of Defense purchases, DFAR +252.227-7015 (Technical Data -- Commercial Items) and 227.7202-3 (Rights in +Commercial Computer Software or Computer Software Documentation). Accordingly, +all U.S. Government End Users acquire Covered Code with only those rights set +forth herein. + +13.2 Relationship of Parties. This License will not be construed as +creating an agency, partnership, joint venture or any other form of legal +association between or among You, Apple or any Contributor, and You will not +represent to the contrary, whether expressly, by implication, appearance or +otherwise. + +13.3 Independent Development. Nothing in this License will impair Apple's +right to acquire, license, develop, have others develop for it, market and/or +distribute technology or products that perform the same or similar functions +as, or otherwise compete with, Modifications, Larger Works, technology or +products that You may develop, produce, market or distribute. + +13.4 Waiver; Construction. Failure by Apple or any Contributor to enforce +any provision of this License will not be deemed a waiver of future enforcement +of that or any other provision. Any law or regulation which provides that the +language of a contract shall be construed against the drafter will not apply to +this License. + +13.5 Severability. (a) If for any reason a court of competent jurisdiction +finds any provision of this License, or portion thereof, to be unenforceable, +that provision of the License will be enforced to the maximum extent +permissible so as to effect the economic benefits and intent of the parties, +and the remainder of this License will continue in full force and effect. (b) +Notwithstanding the foregoing, if applicable law prohibits or restricts You +from fully and/or specifically complying with Sections 2 and/or 3 or prevents +the enforceability of either of those Sections, this License will immediately +terminate and You must immediately discontinue any use of the Covered Code and +destroy all copies of it that are in your possession or control. + +13.6 Dispute Resolution. Any litigation or other dispute resolution between +You and Apple relating to this License shall take place in the Northern +District of California, and You and Apple hereby consent to the personal +jurisdiction of, and venue in, the state and federal courts within that +District with respect to this License. The application of the United Nations +Convention on Contracts for the International Sale of Goods is expressly +excluded. + +13.7 Entire Agreement; Governing Law. This License constitutes the entire +agreement between the parties with respect to the subject matter hereof. This +License shall be governed by the laws of the United States and the State of +California, except that body of California law concerning conflicts of law. + +Where You are located in the province of Quebec, Canada, the following clause +applies: The parties hereby confirm that they have requested that this License +and all related documents be drafted in English. Les parties ont exigé que le +présent contrat et tous les documents connexes soient rédigés en anglais. + +EXHIBIT A. + +"Portions Copyright (c) 1999-2007 Apple Inc. All Rights Reserved. + +This file contains Original Code and/or Modifications of Original Code as +defined in and that are subject to the Apple Public Source License Version 2.0 +(the 'License'). You may not use this file except in compliance with the +License. Please obtain a copy of the License at +http://www.opensource.apple.com/apsl/ and read it before using this file. + +The Original Code and all software distributed under the License are +distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS +OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT +LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the +specific language governing rights and limitations under the License." + diff --git a/bootstrap_cmds/mig.xcodeproj/project.pbxproj b/bootstrap_cmds/mig.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8173f62 --- /dev/null +++ b/bootstrap_cmds/mig.xcodeproj/project.pbxproj @@ -0,0 +1,310 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + FC2E1879149BF95600349D18 /* mig.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCAD5337149BF58700CE0B4B /* mig.1 */; }; + FC2E187A149BF95600349D18 /* migcom.1 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCAD533C149BF58700CE0B4B /* migcom.1 */; }; + FCAD539C149BF58700CE0B4B /* error.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD532B149BF58700CE0B4B /* error.c */; }; + FCAD539D149BF58700CE0B4B /* global.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD532D149BF58700CE0B4B /* global.c */; }; + FCAD539F149BF58700CE0B4B /* header.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5330149BF58700CE0B4B /* header.c */; }; + FCAD53A0149BF58700CE0B4B /* lexxer.l in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5334149BF58700CE0B4B /* lexxer.l */; }; + FCAD53A2149BF58700CE0B4B /* mig.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5338149BF58700CE0B4B /* mig.c */; }; + FCAD53A3149BF58700CE0B4B /* parser.y in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5340149BF58700CE0B4B /* parser.y */; }; + FCAD53A4149BF58700CE0B4B /* routine.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5343149BF58700CE0B4B /* routine.c */; }; + FCAD53A5149BF58700CE0B4B /* server.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5345149BF58700CE0B4B /* server.c */; }; + FCAD53A6149BF58700CE0B4B /* statement.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5346149BF58700CE0B4B /* statement.c */; }; + FCAD53A7149BF58700CE0B4B /* string.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD5349149BF58700CE0B4B /* string.c */; }; + FCAD53A8149BF58700CE0B4B /* type.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD534A149BF58700CE0B4B /* type.c */; }; + FCAD53A9149BF58700CE0B4B /* user.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD534C149BF58700CE0B4B /* user.c */; }; + FCAD53AA149BF58700CE0B4B /* utils.c in Sources */ = {isa = PBXBuildFile; fileRef = FCAD534D149BF58700CE0B4B /* utils.c */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + FC2DBC52149BF01800EACA9D /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "$(DT_TOOLCHAIN_DIR)/usr/share/man/man1/"; + dstSubfolderSpec = 0; + files = ( + FC2E1879149BF95600349D18 /* mig.1 in CopyFiles */, + FC2E187A149BF95600349D18 /* migcom.1 in CopyFiles */, + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + FC2DBC54149BF01800EACA9D /* migcom */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = migcom; sourceTree = BUILT_PRODUCTS_DIR; }; + FC2E188C149C017900349D18 /* install-mig.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "install-mig.sh"; sourceTree = ""; }; + FCAD532A149BF58700CE0B4B /* alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alloc.h; sourceTree = ""; }; + FCAD532B149BF58700CE0B4B /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = ""; }; + FCAD532C149BF58700CE0B4B /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = ""; }; + FCAD532D149BF58700CE0B4B /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = global.c; sourceTree = ""; }; + FCAD532E149BF58700CE0B4B /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = global.h; sourceTree = ""; }; + FCAD532F149BF58700CE0B4B /* handler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = handler.c; sourceTree = ""; }; + FCAD5330149BF58700CE0B4B /* header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = header.c; sourceTree = ""; }; + FCAD5333149BF58700CE0B4B /* lexxer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lexxer.h; sourceTree = ""; }; + FCAD5334149BF58700CE0B4B /* lexxer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = lexxer.l; sourceTree = ""; }; + FCAD5337149BF58700CE0B4B /* mig.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mig.1; sourceTree = ""; }; + FCAD5338149BF58700CE0B4B /* mig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mig.c; sourceTree = ""; }; + FCAD5339149BF58700CE0B4B /* mig.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mig.sh; sourceTree = ""; }; + FCAD533A149BF58700CE0B4B /* mig_errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mig_errors.h; sourceTree = ""; }; + FCAD533B149BF58700CE0B4B /* mig_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mig_machine.h; sourceTree = ""; }; + FCAD533C149BF58700CE0B4B /* migcom.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = migcom.1; sourceTree = ""; }; + FCAD5340149BF58700CE0B4B /* parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = parser.y; sourceTree = ""; }; + FCAD5343149BF58700CE0B4B /* routine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = routine.c; sourceTree = ""; }; + FCAD5344149BF58700CE0B4B /* routine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = routine.h; sourceTree = ""; }; + FCAD5345149BF58700CE0B4B /* server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = ""; }; + FCAD5346149BF58700CE0B4B /* statement.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = statement.c; sourceTree = ""; }; + FCAD5347149BF58700CE0B4B /* statement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statement.h; sourceTree = ""; }; + FCAD5348149BF58700CE0B4B /* strdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdefs.h; sourceTree = ""; }; + FCAD5349149BF58700CE0B4B /* string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = string.c; sourceTree = ""; }; + FCAD534A149BF58700CE0B4B /* type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = type.c; sourceTree = ""; }; + FCAD534B149BF58700CE0B4B /* type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type.h; sourceTree = ""; }; + FCAD534C149BF58700CE0B4B /* user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = user.c; sourceTree = ""; }; + FCAD534D149BF58700CE0B4B /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = ""; }; + FCAD534E149BF58700CE0B4B /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = ""; }; + FCAD534F149BF58700CE0B4B /* write.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = write.h; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + FC2DBC51149BF01800EACA9D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + FC2DBC49149BF01800EACA9D = { + isa = PBXGroup; + children = ( + FCAD5329149BF58700CE0B4B /* migcom */, + FC2E188B149C017900349D18 /* xcodescripts */, + FC2DBC55149BF01800EACA9D /* Products */, + ); + sourceTree = ""; + }; + FC2DBC55149BF01800EACA9D /* Products */ = { + isa = PBXGroup; + children = ( + FC2DBC54149BF01800EACA9D /* migcom */, + ); + name = Products; + sourceTree = ""; + }; + FC2E188B149C017900349D18 /* xcodescripts */ = { + isa = PBXGroup; + children = ( + FC2E188C149C017900349D18 /* install-mig.sh */, + ); + path = xcodescripts; + sourceTree = ""; + }; + FCAD5329149BF58700CE0B4B /* migcom */ = { + isa = PBXGroup; + children = ( + FCAD532A149BF58700CE0B4B /* alloc.h */, + FCAD532B149BF58700CE0B4B /* error.c */, + FCAD532C149BF58700CE0B4B /* error.h */, + FCAD532D149BF58700CE0B4B /* global.c */, + FCAD532E149BF58700CE0B4B /* global.h */, + FCAD532F149BF58700CE0B4B /* handler.c */, + FCAD5330149BF58700CE0B4B /* header.c */, + FCAD5333149BF58700CE0B4B /* lexxer.h */, + FCAD5334149BF58700CE0B4B /* lexxer.l */, + FCAD5337149BF58700CE0B4B /* mig.1 */, + FCAD5338149BF58700CE0B4B /* mig.c */, + FCAD5339149BF58700CE0B4B /* mig.sh */, + FCAD533A149BF58700CE0B4B /* mig_errors.h */, + FCAD533B149BF58700CE0B4B /* mig_machine.h */, + FCAD533C149BF58700CE0B4B /* migcom.1 */, + FCAD5340149BF58700CE0B4B /* parser.y */, + FCAD5343149BF58700CE0B4B /* routine.c */, + FCAD5344149BF58700CE0B4B /* routine.h */, + FCAD5345149BF58700CE0B4B /* server.c */, + FCAD5346149BF58700CE0B4B /* statement.c */, + FCAD5347149BF58700CE0B4B /* statement.h */, + FCAD5348149BF58700CE0B4B /* strdefs.h */, + FCAD5349149BF58700CE0B4B /* string.c */, + FCAD534A149BF58700CE0B4B /* type.c */, + FCAD534B149BF58700CE0B4B /* type.h */, + FCAD534C149BF58700CE0B4B /* user.c */, + FCAD534D149BF58700CE0B4B /* utils.c */, + FCAD534E149BF58700CE0B4B /* utils.h */, + FCAD534F149BF58700CE0B4B /* write.h */, + ); + name = migcom; + path = migcom.tproj; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + FC2DBC53149BF01800EACA9D /* migcom */ = { + isa = PBXNativeTarget; + buildConfigurationList = FC2DBC5E149BF01800EACA9D /* Build configuration list for PBXNativeTarget "migcom" */; + buildPhases = ( + FC2DBC50149BF01800EACA9D /* Sources */, + FC2DBC51149BF01800EACA9D /* Frameworks */, + FC2DBC52149BF01800EACA9D /* CopyFiles */, + FC2E1884149BFF0900349D18 /* Run Script */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = migcom; + productName = mig; + productReference = FC2DBC54149BF01800EACA9D /* migcom */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + FC2DBC4B149BF01800EACA9D /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 1100; + ORGANIZATIONNAME = "Apple Inc."; + }; + buildConfigurationList = FC2DBC4E149BF01800EACA9D /* Build configuration list for PBXProject "mig" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + ); + mainGroup = FC2DBC49149BF01800EACA9D; + productRefGroup = FC2DBC55149BF01800EACA9D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + FC2DBC53149BF01800EACA9D /* migcom */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXShellScriptBuildPhase section */ + FC2E1884149BFF0900349D18 /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = ". \"$PROJECT_DIR\"/xcodescripts/install-mig.sh"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + FC2DBC50149BF01800EACA9D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + FCAD53A3149BF58700CE0B4B /* parser.y in Sources */, + FCAD53A0149BF58700CE0B4B /* lexxer.l in Sources */, + FCAD539C149BF58700CE0B4B /* error.c in Sources */, + FCAD539D149BF58700CE0B4B /* global.c in Sources */, + FCAD539F149BF58700CE0B4B /* header.c in Sources */, + FCAD53A2149BF58700CE0B4B /* mig.c in Sources */, + FCAD53A4149BF58700CE0B4B /* routine.c in Sources */, + FCAD53A5149BF58700CE0B4B /* server.c in Sources */, + FCAD53A6149BF58700CE0B4B /* statement.c in Sources */, + FCAD53A7149BF58700CE0B4B /* string.c in Sources */, + FCAD53A8149BF58700CE0B4B /* type.c in Sources */, + FCAD53A9149BF58700CE0B4B /* user.c in Sources */, + FCAD53AA149BF58700CE0B4B /* utils.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + FC2DBC5D149BF01800EACA9D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_ENABLE_OBJC_EXCEPTIONS = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + SDKROOT = macosx.internal; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = __; + WARNING_CFLAGS = "-Wall"; + }; + name = Release; + }; + FC2DBC60149BF01800EACA9D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + GCC_PREPROCESSOR_DEFINITIONS = "MIG_VERSION=\\\"$(RC_ProjectNameAndSourceVersion)\\\""; + INSTALL_PATH = "$(DT_TOOLCHAIN_DIR)/usr/libexec"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + FC2DBC4E149BF01800EACA9D /* Build configuration list for PBXProject "mig" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FC2DBC5D149BF01800EACA9D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + FC2DBC5E149BF01800EACA9D /* Build configuration list for PBXNativeTarget "migcom" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + FC2DBC60149BF01800EACA9D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = FC2DBC4B149BF01800EACA9D /* Project object */; +} diff --git a/bootstrap_cmds/migcom.tproj/alloc.h b/bootstrap_cmds/migcom.tproj/alloc.h new file mode 100644 index 0000000..87b9b5f --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/alloc.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1999, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef _ALLOC_H +#define _ALLOC_H + +#include + +#endif /* _ALLOC_H */ diff --git a/bootstrap_cmds/migcom.tproj/error.c b/bootstrap_cmds/migcom.tproj/error.c new file mode 100644 index 0000000..37bcae3 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/error.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1999, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include +#include +#include + +#include "global.h" +#include "error.h" + +extern int lineno; +extern char *yyinname; + +static char *program; +__private_extern__ +int mig_errors = 0; + +/*ARGSUSED*/ +/*VARARGS1*/ +void +fatal(char *format, ...) +{ + va_list pvar; + va_start(pvar, format); + fprintf(stderr, "%s: fatal: \"%s\", line %d: ", program, yyinname, lineno-1); + (void) vfprintf(stderr, format, pvar); + fprintf(stderr, "\n"); + va_end(pvar); + exit(1); +} + +__private_extern__ +/*ARGSUSED*/ +/*VARARGS1*/ +void +warn(char *format, ...) +{ + va_list pvar; + va_start(pvar, format); + if (!BeQuiet && (mig_errors == 0)) { + fprintf(stderr, "\"%s\", line %d: warning: ", yyinname, lineno-1); + (void) vfprintf(stderr, format, pvar); + fprintf(stderr, "\n"); + } + va_end(pvar); +} + +/*ARGSUSED*/ +/*VARARGS1*/ +void +error(char *format, ...) +{ + va_list pvar; + va_start(pvar, format); + fprintf(stderr, "\"%s\", line %d: ", yyinname, lineno-1); + (void) vfprintf(stderr, format, pvar); + fprintf(stderr, "\n"); + va_end(pvar); + mig_errors++; +} + +void +set_program_name(char *name) +{ + program = name; +} diff --git a/bootstrap_cmds/migcom.tproj/error.h b/bootstrap_cmds/migcom.tproj/error.h new file mode 100644 index 0000000..9ffd599 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/error.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1999, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef _ERROR_H +#define _ERROR_H + +#include + +extern void fatal(char *format, ...); +extern void warn(char *format, ...); +extern void error(char *format, ...); + +extern int mig_errors; +extern void set_program_name(char *name); + +#endif /* _ERROR_H */ diff --git a/bootstrap_cmds/migcom.tproj/global.c b/bootstrap_cmds/migcom.tproj/global.c new file mode 100644 index 0000000..15c26f5 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/global.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1999, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include "strdefs.h" +#include "global.h" +#include "error.h" +#include "mig_machine.h" + +boolean_t PrintVersion = FALSE; +boolean_t BeQuiet = FALSE; +boolean_t BeVerbose = FALSE; +boolean_t UseMsgRPC = TRUE; +boolean_t GenSymTab = FALSE; +boolean_t UseEventLogger = FALSE; +boolean_t BeLint = FALSE; +boolean_t BeAnsiC = TRUE; +boolean_t CheckNDR = FALSE; +boolean_t PackMsg = PACK_MESSAGES; +boolean_t UseSplitHeaders = FALSE; +boolean_t ShortCircuit = FALSE; +boolean_t UseRPCTrap = FALSE; +boolean_t TestRPCTrap= FALSE; +boolean_t IsVoucherCodeAllowed = TRUE; + +boolean_t IsKernelUser = FALSE; +boolean_t IsKernelServer = FALSE; +boolean_t UseSpecialReplyPort = FALSE; +boolean_t HasUseSpecialReplyPort = FALSE; +boolean_t HasConsumeOnSendError = FALSE; +u_int ConsumeOnSendError = 0; + +string_t RCSId = strNULL; + +string_t SubsystemName = strNULL; +u_int SubsystemBase = 0; + +string_t MsgOption = strNULL; +string_t WaitTime = strNULL; +string_t SendTime = strNULL; +string_t ErrorProc = "MsgError"; +string_t ServerPrefix = ""; +string_t UserPrefix = ""; +string_t ServerDemux = strNULL; +string_t ServerImpl = strNULL; +string_t ServerSubsys = strNULL; +int MaxMessSizeOnStack = -1; /* by default, always on stack */ +int UserTypeLimit = -1; /* by default, assume unlimited size. */ + +string_t yyinname; + +char NewCDecl[] = "(defined(__STDC__) || defined(c_plusplus))"; +char LintLib[] = "defined(LINTLIBRARY)"; + +void +init_global() +{ + yyinname = strmake(""); +} + +string_t UserFilePrefix = strNULL; +string_t UserHeaderFileName = strNULL; +string_t ServerHeaderFileName = strNULL; +string_t InternalHeaderFileName = strNULL; +string_t DefinesHeaderFileName = strNULL; +string_t UserFileName = strNULL; +string_t ServerFileName = strNULL; +string_t GenerationDate = strNULL; + +void +more_global() +{ + if (SubsystemName == strNULL) + fatal("no SubSystem declaration"); + + if (UserHeaderFileName == strNULL) + UserHeaderFileName = strconcat(SubsystemName, ".h"); + else if (streql(UserHeaderFileName, "/dev/null")) + UserHeaderFileName = strNULL; + + if (UserFileName == strNULL) + UserFileName = strconcat(SubsystemName, "User.c"); + else if (streql(UserFileName, "/dev/null")) + UserFileName = strNULL; + + if (ServerFileName == strNULL) + ServerFileName = strconcat(SubsystemName, "Server.c"); + else if (streql(ServerFileName, "/dev/null")) + ServerFileName = strNULL; + + if (ServerDemux == strNULL) + ServerDemux = strconcat(SubsystemName, "_server"); + + if (ServerImpl == strNULL) + ServerImpl = strconcat(SubsystemName, "_impl"); + + if (ServerSubsys == strNULL) { + if (ServerPrefix != strNULL) + ServerSubsys = strconcat(ServerPrefix, SubsystemName); + else + ServerSubsys = SubsystemName; + ServerSubsys = strconcat(ServerSubsys, "_subsystem"); + } + if (HasUseSpecialReplyPort && !BeAnsiC) { + fatal("Cannot use UseSpecialReplyPort in non ANSI mode\n"); + } +} diff --git a/bootstrap_cmds/migcom.tproj/global.h b/bootstrap_cmds/migcom.tproj/global.h new file mode 100644 index 0000000..39a133b --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/global.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#ifndef _GLOBAL_H +#define _GLOBAL_H + +#include "type.h" + +extern boolean_t PrintVersion; /* print bootstrap_cmds project version and exit */ +extern boolean_t BeQuiet; /* no warning messages */ +extern boolean_t BeVerbose; /* summarize types, routines */ +extern boolean_t BeDebug; /* enters in the debug mode */ +extern boolean_t UseMsgRPC; +extern boolean_t GenSymTab; +extern boolean_t UseEventLogger; +extern boolean_t BeLint; +extern boolean_t BeAnsiC; +extern boolean_t CheckNDR; +extern boolean_t PackMsg; +extern boolean_t UseSplitHeaders; +extern boolean_t ShortCircuit; +extern boolean_t UseRPCTrap; +extern boolean_t TestRPCTrap; +extern boolean_t IsVoucherCodeAllowed; + +extern boolean_t IsKernelUser; +extern boolean_t IsKernelServer; +extern boolean_t UseSpecialReplyPort; +extern boolean_t HasUseSpecialReplyPort; /* whether UseSpecialReplyPort has ever been set to TRUE */ +extern boolean_t HasConsumeOnSendError; /* whether ConsumeOnSendError has ever been set */ +extern u_int ConsumeOnSendError; + +extern string_t RCSId; + +extern string_t SubsystemName; +extern u_int SubsystemBase; + +extern string_t MsgOption; +extern string_t WaitTime; +extern string_t SendTime; +extern string_t ErrorProc; +extern string_t ServerPrefix; +extern string_t UserPrefix; +extern string_t ServerDemux; +extern string_t ServerImpl; +extern string_t ServerSubsys; +extern int MaxMessSizeOnStack; +extern int UserTypeLimit; + +extern int yylineno; +extern string_t yyinname; + +extern void init_global(void); + +extern string_t UserFilePrefix; +extern string_t UserHeaderFileName; +extern string_t ServerHeaderFileName; +extern string_t InternalHeaderFileName; +extern string_t DefinesHeaderFileName; +extern string_t UserFileName; +extern string_t ServerFileName; + +extern void more_global(void); + +extern char NewCDecl[]; +extern char LintLib[]; + +#endif /* _GLOBAL_H */ diff --git a/bootstrap_cmds/migcom.tproj/handler.c b/bootstrap_cmds/migcom.tproj/handler.c new file mode 100644 index 0000000..b5156aa --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/handler.c @@ -0,0 +1,754 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/******************************************************** + * Abstract: + * routines to write pieces of the Handler module. + * exports WriteHandler which directs the writing of + * the Handler module + * + * + * $Header: /Users/Shared/bootstrap_cmds/bootstrap_cmds/migcom.tproj/handler.c,v 1.2 2005/02/06 07:28:59 lindak Exp $ + * + * HISTORY + * 03-Jul-97 Daniel Wade (danielw) at Apple + * Generated code is now ANSI C compliant + * + * 10-Sep-91 Gregg Kellogg (gk) at NeXT + * Created. + *******************************************************/ + +#include +#include "write.h" +#include "utils.h" +#include "global.h" + +static void +WriteIncludes(FILE *file) +{ + fprintf(file, "#define EXPORT_BOOLEAN\n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + if (IsCamelot) { + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + } + fprintf(file, "#include \"%s\"\n", ServerHeaderFileName); + fprintf(file, "\n"); +} + +static void +WriteGlobalDecls(FILE *file) +{ + fprintf(file, "#define novalue void\n"); + fprintf(file, "\n"); + + if (RCSId != strNULL) + WriteRCSDecl(file, strconcat(SubsystemName, "_handler"), RCSId); + + /* Used for locations in the request message, *not* reply message. + Reply message locations aren't dependent on IsKernel. */ + + if (IsKernel) + { + fprintf(file, "#define msg_request_port\tmsg_remote_port\n"); + fprintf(file, "#define msg_reply_port\t\tmsg_local_port\n"); + } + else + { + fprintf(file, "#define msg_request_port\tmsg_local_port\n"); + fprintf(file, "#define msg_reply_port\t\tmsg_remote_port\n"); + } +} + +static void +WriteProlog(FILE *file) +{ + fprintf(file, "/* Module %s */\n", SubsystemName); + fprintf(file, "\n"); + + WriteIncludes(file); + WriteBogusDefines(file); + WriteGlobalDecls(file); +} + + +static void +WriteSymTabEntries(FILE *file statement_t *stats) +{ + statement_t *stat; + u_int current = 0; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + int num = stat->stRoutine->rtNumber; + char *name = stat->stRoutine->rtName; + while (++current <= num) + fprintf(file,"\t\t\t{ \"\", 0, 0 },\n"); + fprintf(file, "\t{ \"%s\", %d, _X%s },\n", + name, + SubsystemBase + current - 1, + name); + } + while (++current <= rtNumber) + fprintf(file,"\t{ \"\", 0, 0 },\n"); +} + +static void +WriteArrayEntries(FILE *file, statement_t *stats) +{ + u_int current = 0; + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) + { + routine_t *rt = stat->stRoutine; + + while (current++ < rt->rtNumber) + fprintf(file, "\t\t\t0,\n"); + fprintf(file, "\t\t\t_X%s,\n", rt->rtName); + } + while (current++ < rtNumber) + fprintf(file, "\t\t\t0,\n"); +} + +static void +WriteEpilog(FILE *file, statement_t *stats) +{ + statement_t *stat; + u_int MaxReply = 0; + + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind != skRoutine) + continue; + if (stat->stRoutine->rtMaxReplySize > MaxReply) + MaxReply = stat->stRoutine->rtMaxReplySize; + } + + fprintf(file, "\n"); + + fprintf(file, "kern_return_t %s (\n", ServerProcName); + fprintf(file, "\tmsg_header_t *InHeadP,\n\t%s_t *%s)\n", SubsystemName, SubsystemName); + + fprintf(file, "{\n"); + fprintf(file, "\tchar OutBuf[%d];\n", MaxReply); + fprintf(file, "\tmsg_header_t *InP = InHeadP;\n"); + + if (IsCamelot) + fprintf(file, "\tcamelot_death_pill_t *OutP = (camelot_death_pill_t *) OutBuf;\n"); + else + fprintf(file, "\tdeath_pill_t *OutP = (death_pill_t *) OutBuf;\n"); + + fprintf(file, "\n"); + + WriteStaticDecl(file, itRetCodeType, itRetCodeType->itDeallocate, itRetCodeType->itLongForm, "RetCodeType"); + fprintf(file, "\n"); + + if (IsCamelot) + { + WriteStaticDecl(file, itDummyType, itDummyType->itDeallocate, itDummyType->itLongForm, "DummyType"); + fprintf(file, "\n"); + WriteStaticDecl(file, itTidType, itTidType->itDeallocate, itTidType->itLongForm, "TidType"); + fprintf(file, "\n"); + } + + fprintf(file, "\tOutP->Head.msg_simple = TRUE;\n"); + fprintf(file, "\tOutP->Head.msg_size = (mach_msg_size_t)sizeof(*OutP);\n"); + fprintf(file, "\tOutP->Head.msg_type = InP->msg_type;\n"); + fprintf(file, "\tOutP->Head.msg_local_port = PORT_NULL;\n"); + fprintf(file, "\tOutP->Head.msg_remote_port = InP->msg_reply_port;\n"); + fprintf(file, "\tOutP->Head.msg_id = InP->msg_id + 100;\n"); + fprintf(file, "\n"); + WritePackMsgType(file, itRetCodeType, itRetCodeType->itDeallocate, itRetCodeType->itLongForm, "OutP->RetCodeType", "RetCodeType"); + fprintf(file, "\tOutP->RetCode = MIG_BAD_ID;\n"); + fprintf(file, "\n"); + + if (IsCamelot) + { + WritePackMsgType(file, itDummyType, itDummyType->itDeallocate, itDummyType->itLongForm, "OutP->DummyType", "DummyType"); + fprintf(file, "\t/* dummy doesn't need a value */\n"); + fprintf(file, "\n"); + WritePackMsgType(file, itTidType, itTidType->itDeallocate, itTidType->itLongForm, "OutP->TidType", "TidType"); + fprintf(file, "\tOutP->Tid = ((camelot_death_pill_t *)InP)->Tid;\n"); + fprintf(file, "\n"); + } + + fprintf(file, "\tif ((InP->msg_id > %d) || (InP->msg_id < %d))\n", SubsystemBase + rtNumber - 1, SubsystemBase); + fprintf(file, "\t\treturn OutP->RetCode;\n"); + fprintf(file, "\telse {\n"); + fprintf(file, "\t\ttypedef novalue (*SERVER_STUB_PROC) (\n"); + fprintf(file, "\t\t\tmsg_header_t *,\n" + "\t\t\tmsg_header_t *,\n" + "\t\t\t%s_t *);\n", SubsystemName); + fprintf(file, "\t\tstatic const SERVER_STUB_PROC routines[] = {\n"); + + WriteArrayEntries(file, stats); + + fprintf(file, "\t\t};\n"); + fprintf(file, "\n"); + + /* Call appropriate routine */ + fprintf(file, "\t\tif (routines[InP->msg_id - %d])\n", SubsystemBase); + fprintf(file, "\t\t\t(routines[InP->msg_id - %d]) (\n" + "\t\t\t\tInP, &OutP->Head, %s);\n", + SubsystemBase, SubsystemName); + fprintf(file, "\t\t else\n"); + fprintf(file, "\t\t\treturn MIG_BAD_ID;\n"); + + fprintf(file, "\t}\n"); + + fprintf(file, "\tif (OutP->RetCode == MIG_NO_REPLY)\n"); + fprintf(file, "\t\treturn KERN_SUCCESS;\n"); + fprintf(file, "\treturn msg_send(&OutP->Head,\n"); + fprintf(file, "\t\t%s->timeout >= 0 ? SEND_TIMEOUT : MSG_OPTION_NONE,\n", SubsystemName); + fprintf(file, "\t\t%s->timeout);\n", SubsystemName); + fprintf(file, "}\n"); + + /* symtab */ + + if (GenSymTab) { + fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName); + WriteSymTabEntries(file,stats); + fprintf(file,"};\n"); + fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase); + fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber); + } +} + +/* + * Returns the return type of the server-side work function. + * Suitable for "extern %s serverfunc()". + */ +static char * +HandlerSideType(routine_t *rt) +{ + if (rt->rtServerReturn == argNULL) + return "void"; + else + return rt->rtServerReturn->argType->itTransType; +} + +static void +WriteLocalVarDecl(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + if (it->itInLine && it->itVarArray) + { + ipc_type_t *btype = it->itElement; + + fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, it->itNumber/btype->itNumber); + } + else + fprintf(file, "\t%s %s", it->itTransType, arg->argVarName); +} + +static void +_WriteHandlerVarDecl(FILE *file, argument_t *arg) +{ + fprintf(file, "%s %s%s", arg->argType->itTransType, argByReferenceServer(arg) ? "*" : "", arg->argVarName); +} + +/* + * Writes the local variable declarations which are always + * present: InP, OutP, the server-side work function. + */ +static void +WriteVarDecls(FILE *file, routine_t *rt) +{ + int i; + + fprintf(file, "\tRequest *In0P = (Request *) InHeadP;\n"); + for (i = 1; i <= rt->rtMaxRequestPos; i++) + fprintf(file, "\tRequest *In%dP;\n", i); + fprintf(file, "\tReply *OutP = (Reply *) OutHeadP;\n"); + fprintf(file, "\n"); + + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tboolean_t msg_simple;\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + fprintf(file, "\n"); + + fprintf(file, "\tunsigned int msg_size;\n"); + + /* if either request or reply is variable, we need msg_size_delta */ + if ((rt->rtNumRequestVar > 0) || (rt->rtNumReplyVar > 0)) + fprintf(file, "\tunsigned int msg_size_delta;\n"); + + fprintf(file, "\n"); +} + +static void +WriteMsgError(FILE *file, argument_t *arg, char *error) +{ + if (arg == argNULL) + fprintf(file, "\t\t{ OutP->RetCode = %s; return; }\n", error); + else { + fprintf(file, "\t\t{ OutP->RetCode = %s; goto punt%d; }\n", error, arg->argPuntNum); + fprintf(file, "#define\tlabel_punt%d\n", arg->argPuntNum); + } +} + +static void +WriteReplyInit(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + fprintf(file, "\tmsg_size = %d;\t\n", rt->rtReplySize); + if (rt->rtNumReplyVar > 0) + fprintf(file, "\t/* Maximum reply size %d */\n", rt->rtMaxReplySize); +} + +static void +WriteReplyHead(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + if (rt->rtMaxReplyPos > 0) + fprintf(file, "\tOutP = (Reply *) OutHeadP;\n"); + + fprintf(file, "\tOutP->Head.msg_simple = %s;\n", strbool(rt->rtSimpleSendReply)); + fprintf(file, "\tOutP->Head.msg_size = msg_size;\n"); +} + +static void +WriteCheckHead(FILE *file, routine_t *rt) +{ + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tmsg_size = In0P->Head.msg_size;\n"); + fprintf(file, "\tmsg_simple = In0P->Head.msg_simple;\n"); + + if (rt->rtNumRequestVar > 0) { + fprintf(file, "\tif ((msg_size < %d)", rt->rtRequestSize); + fprintf(file, " || (msg_size > %d)", rt->rtMaxRequestSize); + } + else + fprintf(file, "\tif ((msg_size != %d)", rt->rtRequestSize); + if (rt->rtSimpleCheckRequest) + fprintf(file, " || (msg_simple != %s)", strbool(rt->rtSimpleReceiveRequest)); + fprintf(file, ")\n"); + WriteMsgError(file, argNULL, "MIG_BAD_ARGUMENTS"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + fprintf(file, "\n"); +} + +static void +WriteTypeCheck(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + routine_t *rt = arg->argRoutine; + + fprintf(file, "#if\t__MigTypeCheck\n"); + if (akCheck(arg->argKind, akbQuickCheck)) + { + fprintf(file, "#if\tUseStaticMsgType\n"); + fprintf(file, "\tif (* (int *) &In%dP->%s != * (int *) &%sCheck)\n", arg->argRequestPos, arg->argTTName, arg->argVarName); + fprintf(file, "#else\t/* UseStaticMsgType */\n"); + } + fprintf(file, "\tif ((In%dP->%s%s.msg_type_inline != %s) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? ".msg_type_header" : "", strbool(it->itInLine)); + fprintf(file, "\t (In%dP->%s%s.msg_type_longform != %s) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? ".msg_type_header" : "", strbool(arg->argLongForm)); + if (it->itOutName == MSG_TYPE_POLYMORPHIC) + { + if (!rt->rtSimpleCheckRequest) + fprintf(file, "\t (MSG_TYPE_PORT_ANY(In%dP->%s.msg_type_%sname) && msg_simple) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : ""); + } + else + fprintf(file, "\t (In%dP->%s.msg_type_%sname != %s) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "", it->itOutNameStr); + if (!it->itVarArray) + fprintf(file, "\t (In%dP->%s.msg_type_%snumber != %d) ||\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "", it->itNumber); + fprintf(file, "\t (In%dP->%s.msg_type_%ssize != %d))\n", arg->argRequestPos, arg->argTTName, arg->argLongForm ? "long_" : "", it->itSize); + if (akCheck(arg->argKind, akbQuickCheck)) + fprintf(file, "#endif\t/* UseStaticMsgType */\n"); + WriteMsgError(file, arg, "MIG_BAD_ARGUMENTS"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + fprintf(file, "\n"); +} + +static void +WriteCheckMsgSize(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + ipc_type_t *btype = arg->argType->itElement; + argument_t *count = arg->argCount; + boolean_t NoMoreArgs, LastVarArg; + + /* If there aren't any more In args after this, then + msg_size_delta value will only get used by TypeCheck code, + so put the assignment under the TypeCheck conditional. */ + + NoMoreArgs = arg->argRequestPos == rt->rtMaxRequestPos; + + /* If there aren't any more variable-sized arguments after this, + then we must check for exact msg-size and we don't need + to update msg_size. */ + + LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar; + + if (NoMoreArgs) + fprintf(file, "#if\t__MigTypeCheck\n"); + + /* calculate the actual size in bytes of the data field. note + that this quantity must be a multiple of four. hence, if + the base type size isn't a multiple of four, we have to + round up. note also that btype->itNumber must + divide btype->itTypeSize (see itCalculateSizeInfo). */ + + if (btype->itTypeSize % 4 != 0) + fprintf(file, "\tmsg_size_delta = (%d * In%dP->%s + 3) & ~3;\n", btype->itTypeSize/btype->itNumber, arg->argRequestPos, count->argMsgField); + else + fprintf(file, "\tmsg_size_delta = %d * In%dP->%s;\n", btype->itTypeSize/btype->itNumber, arg->argRequestPos, count->argMsgField); + + if (!NoMoreArgs) + fprintf(file, "#if\t__MigTypeCheck\n"); + + /* Don't decrement msg_size until we've checked it won't underflow. */ + + if (LastVarArg) + fprintf(file, "\tif (msg_size != %d + msg_size_delta)\n", rt->rtRequestSize); + else + fprintf(file, "\tif (msg_size < %d + msg_size_delta)\n", rt->rtRequestSize); + WriteMsgError(file, arg, "MIG_BAD_ARGUMENTS"); + + if (!LastVarArg) + fprintf(file, "\tmsg_size -= msg_size_delta;\n"); + + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + fprintf(file, "\n"); +} + +static void +WriteExtractArgValue(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + if (arg->argMultiplier > 1) + WriteCopyType(file, it, FALSE, "%s /* %d %s %d */", "/* %s */ In%dP->%s / %d", arg->argVarName, arg->argRequestPos, arg->argMsgField, arg->argMultiplier); + else if (it->itInTrans != strNULL) + WriteCopyType(file, it, FALSE, "%s /* %s %d %s */", "/* %s */ %s(In%dP->%s)", arg->argVarName, it->itInTrans, arg->argRequestPos, arg->argMsgField); + else + WriteCopyType(file, it, FALSE, "%s /* %d %s */", "/* %s */ In%dP->%s", arg->argVarName, arg->argRequestPos, arg->argMsgField); + fprintf(file, "\n"); +} + +static void +WriteInitializeCount(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argParent->argType; + ipc_type_t *btype = ptype->itElement; + + /* + * Initialize 'count' argument for variable-length inline OUT parameter + * with maximum allowed number of elements. + */ + + fprintf(file, "\t%s = %d;\n", arg->argVarName, ptype->itNumber/btype->itNumber); + fprintf(file, "\n"); +} + +static void +WriteExtractArg(FILE *file, argument_t *arg) +{ + if (akCheck(arg->argKind, akbRequest)) + WriteTypeCheck(file, arg); + + if (akCheckAll(arg->argKind, akbVariable|akbRequest)) + WriteCheckMsgSize(file, arg); + + if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded)) + WriteExtractArgValue(file, arg); + + if ((akIdent(arg->argKind) == akeCount) && akCheck(arg->argKind, akbReturnSnd)) { + ipc_type_t *ptype = arg->argParent->argType; + + if (ptype->itInLine && ptype->itVarArray) + WriteInitializeCount(file, arg); + } + + /* This assumes that the count argument directly follows the + associated variable-sized argument and any other implicit + arguments it may have. */ + + if ((akIdent(arg->argKind) == akeCount) && akCheck(arg->argKind, akbSendRcv) && (arg->argRequestPos < arg->argRoutine->rtMaxRequestPos)) { + ipc_type_t *ptype = arg->argParent->argType; + + if (ptype->itInLine && ptype->itVarArray) { + fprintf(file, "\tIn%dP = (Request *) ((char *) In%dP + msg_size_delta - %d);\n", arg->argRequestPos+1, arg->argRequestPos, ptype->itTypeSize + ptype->itPadSize); + fprintf(file, "\n"); + } + } +} + +static void +WriteHandlerCallArg(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + boolean_t NeedClose = FALSE; + + if (argByReferenceServer(arg)) + fprintf(file, "&"); + + if ((it->itInTrans != strNULL) && akCheck(arg->argKind, akbSendRcv) && !akCheck(arg->argKind, akbVarNeeded)) { + fprintf(file, "%s(", it->itInTrans); + NeedClose = TRUE; + } + + if (akCheck(arg->argKind, akbVarNeeded)) + fprintf(file, "%s", arg->argVarName); + else if (akCheck(arg->argKind, akbSendRcv)) + fprintf(file, "In%dP->%s", arg->argRequestPos, arg->argMsgField); + else + fprintf(file, "OutP->%s", arg->argMsgField); + + if (NeedClose) + fprintf(file, ")"); + + if (!argByReferenceServer(arg) && (arg->argMultiplier > 1)) + fprintf(file, " / %d", arg->argMultiplier); +} + +static void +WriteDestroyArg(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + fprintf(file, "#ifdef\tlabel_punt%d\n", arg->argPuntNum+1); + fprintf(file, "#undef\tlabel_punt%d\n", arg->argPuntNum+1); + fprintf(file, "punt%d:\n", arg->argPuntNum+1); + fprintf(file, "#endif\t/* label_punt%d */\n", arg->argPuntNum+1); + + if (akCheck(arg->argKind, akbVarNeeded)) + fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName); + else + fprintf(file, "\t%s(In%dP->%s);\n", it->itDestructor, arg->argRequestPos, arg->argMsgField); +} + +static void +WriteHandlerCall(FILE *file, routine_t *rt) +{ + boolean_t NeedClose = FALSE; + + fprintf(file, "\tif (%s->%s == 0)\n", SubsystemName, rt->rtName); + WriteMsgError(file, argNULL, "MIG_BAD_ID"); + + fprintf(file, "\t"); + if (rt->rtServerReturn != argNULL) { + argument_t *arg = rt->rtServerReturn; + ipc_type_t *it = arg->argType; + + if (rt->rtOneWay) + fprintf(file, "(void) "); + else + fprintf(file, "OutP->%s = ", arg->argMsgField); + if (it->itOutTrans != strNULL) { + fprintf(file, "%s(", it->itOutTrans); + NeedClose = TRUE; + } + } + fprintf(file, "(*%s->%s)(%s->arg", SubsystemName, rt->rtName, SubsystemName); + WriteListSkipFirst(file, rt->rtArgs, WriteHandlerCallArg, akbServerArg, + ", ", ""); + if (NeedClose) + fprintf(file, ")"); + fprintf(file, ");\n"); +} + +static void +WriteGetReturnValue(FILE *file, routine_t *rt) +{ + fprintf(file, "\t" "OutP->%s = %s;\n", rt->rtRetCode->argMsgField, rt->rtOneWay ? "MIG_NO_REPLY" : "KERN_SUCCESS"); +} + +static void +WriteCheckReturnValue(FILE *file, routine_t *rt) +{ + fprintf(file, "\tif (OutP->%s != KERN_SUCCESS)\n", rt->rtRetCode->argMsgField); + fprintf(file, "\t\treturn;\n"); +} + +static void +WritePackArgType(FILE *file, argument_t *arg) +{ + fprintf(file, "\n"); + + WritePackMsgType(file, arg->argType, arg->argDeallocate, arg->argLongForm, "OutP->%s", "%s", arg->argTTName); +} + +static void +WritePackArgValue(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + fprintf(file, "\n"); + + if (it->itInLine && it->itVarArray) { + argument_t *count = arg->argCount; + ipc_type_t *btype = it->itElement; + + /* Note btype->itNumber == count->argMultiplier */ + + fprintf(file, "\tbcopy((char *) %s, (char *) OutP->%s, ", arg->argVarName, arg->argMsgField); + fprintf(file, "%d * %s);\n", btype->itTypeSize, count->argVarName); + } + else if (arg->argMultiplier > 1) + WriteCopyType(file, it, TRUE, "OutP->%s /* %d %s */", "/* %s */ %d * %s", arg->argMsgField, arg->argMultiplier, arg->argVarName); + else if (it->itOutTrans != strNULL) + WriteCopyType(file, it, TRUE, "OutP->%s /* %s %s */", "/* %s */ %s(%s)", arg->argMsgField, it->itOutTrans, arg->argVarName); + else + WriteCopyType(file, it, TRUE, "OutP->%s /* %s */", "/* %s */ %s", arg->argMsgField, arg->argVarName); +} + +static void +WriteCopyArgValue(FILE *file, argument_t *arg) +{ + fprintf(file, "\n"); + WriteCopyType(file, arg->argType, TRUE, "/* %d */ OutP->%s", "In%dP->%s", arg->argRequestPos, arg->argMsgField); +} + +static void +WriteAdjustMsgSize(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argParent->argType; + ipc_type_t *btype = ptype->itElement; + + fprintf(file, "\n"); + + /* calculate the actual size in bytes of the data field. + note that this quantity must be a multiple of four. + hence, if the base type size isn't a multiple of four, + we have to round up. */ + + if (btype->itTypeSize % 4 != 0) + fprintf(file, "\tmsg_size_delta = (%d * %s + 3) & ~3;\n", btype->itTypeSize, arg->argVarName); + else + fprintf(file, "\tmsg_size_delta = %d * %s;\n", btype->itTypeSize, arg->argVarName); + + fprintf(file, "\tmsg_size += msg_size_delta;\n"); + + /* Don't bother moving OutP unless there are more Out arguments. */ + if (arg->argReplyPos < arg->argRoutine->rtMaxReplyPos) { + fprintf(file, "\tOutP = (Reply *) ((char *) OutP + "); + fprintf(file, "msg_size_delta - %d);\n", ptype->itTypeSize + ptype->itPadSize); + } +} + +static void +WritePackArg(FILE *file, argument_t *arg) +{ + if (akCheck(arg->argKind, akbReplyInit)) + WritePackArgType(file, arg); + + if (akCheckAll(arg->argKind, akbReturnSnd|akbVarNeeded)) + WritePackArgValue(file, arg); + + if (akCheck(arg->argKind, akbReplyCopy)) + WriteCopyArgValue(file, arg); + + if ((akIdent(arg->argKind) == akeCount) && akCheck(arg->argKind, akbReturnSnd)) { + ipc_type_t *ptype = arg->argParent->argType; + + if (ptype->itInLine && ptype->itVarArray) + WriteAdjustMsgSize(file, arg); + } +} + +static void +WriteFieldDecl(FILE *file, argument_t *arg) +{ + WriteFieldDeclPrim(file, arg, FetchServerType); +} + +static void +WriteRoutine(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + + fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName); + fprintf(file, "mig_internal novalue _X%s (\n", rt->rtName); + fprintf(file, "\tmsg_header_t *InHeadP,\n" + "\tmsg_header_t *OutHeadP,\n" + "\t%s_t *%s)\n", SubsystemName, SubsystemName); + + fprintf(file, "{\n"); + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request"); + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply"); + + WriteVarDecls(file, rt); + + WriteList(file, rt->rtArgs, WriteCheckDecl, akbQuickCheck|akbRequest, "\n", "\n"); + WriteList(file, rt->rtArgs, WriteTypeDecl, akbReplyInit, "\n", "\n"); + + WriteList(file, rt->rtArgs, WriteLocalVarDecl, akbVarNeeded, ";\n", ";\n\n"); + + WriteCheckHead(file, rt); + + WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", ""); + + WriteHandlerCall(file, rt); + WriteGetReturnValue(file, rt); + + /* In reverse order so we can jump into the middle. */ + + WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", ""); + fprintf(file, "#ifdef\tlabel_punt0\n"); + fprintf(file, "#undef\tlabel_punt0\n"); + fprintf(file, "punt0:\n"); + fprintf(file, "#endif\t/* label_punt0 */\n"); + + if (rt->rtOneWay) + fprintf(file, "\t;\n"); + else { + WriteCheckReturnValue(file, rt); + WriteReplyInit(file, rt); + WriteList(file, rt->rtArgs, WritePackArg, akbNone, "", ""); + WriteReplyHead(file, rt); + } + + fprintf(file, "}\n"); +} + +void +WriteHandler(FILE *file, statement_t *stats) +{ + statement_t *stat; + + WriteProlog(file); + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skRoutine: + WriteRoutine(file, stat->stRoutine); + break; + + case skImport: + case skSImport: + WriteImport(file, stat->stFileName); + break; + + case skUImport: + break; + + default: + fatal("WriteHandler(): bad statement_kind_t (%d)", (int) stat->stKind); + } + WriteEpilog(file, stats); +} + diff --git a/bootstrap_cmds/migcom.tproj/header.c b/bootstrap_cmds/migcom.tproj/header.c new file mode 100644 index 0000000..505cdd3 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/header.c @@ -0,0 +1,569 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include "write.h" +#include "utils.h" +#include "global.h" +#include "strdefs.h" +#include "error.h" +#include + +void +WriteIncludes(FILE *file, boolean_t isuser, boolean_t isdef) +{ + if (isdef) { + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + if (!isuser) + fprintf(file, "#include \n"); + } + else { + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); + + if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) { + fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n"); + fprintf(file, "#ifndef KERNEL\n"); + fprintf(file, "#if defined(__has_include)\n"); + fprintf(file, "#if __has_include()\n"); + fprintf(file, "#ifndef USING_VOUCHERS\n"); + fprintf(file, "#define USING_VOUCHERS\n"); + fprintf(file, "#endif\n"); + + + fprintf(file, "#ifndef __VOUCHER_FORWARD_TYPE_DECLS__\n"); + fprintf(file, "#define __VOUCHER_FORWARD_TYPE_DECLS__\n"); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "extern \"C\" {\n"); + fprintf(file, "#endif\n"); + + fprintf(file, "\textern boolean_t voucher_mach_msg_set(mach_msg_header_t *msg) __attribute__((weak_import));\n"); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "}\n"); + fprintf(file, "#endif\n"); + + fprintf(file, "#endif // __VOUCHER_FORWARD_TYPE_DECLS__\n"); + fprintf(file, "#endif // __has_include()\n"); + fprintf(file, "#endif // __has_include\n"); + fprintf(file, "#endif // !KERNEL\n"); + + fprintf(file, "\t\n/* END VOUCHER CODE */\n\n"); + } + + fprintf(file, "\t\n/* BEGIN MIG_STRNCPY_ZEROFILL CODE */\n\n"); + fprintf(file, "#if defined(__has_include)\n"); + fprintf(file, "#if __has_include()\n"); + fprintf(file, "#ifndef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "#define USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "#endif\n"); + + fprintf(file, "#ifndef __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n"); + fprintf(file, "#define __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__\n"); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "extern \"C\" {\n"); + fprintf(file, "#endif\n"); + + fprintf(file, "\textern int mig_strncpy_zerofill(char *dest, const char *src, int len) __attribute__((weak_import));\n"); + + fprintf(file, "#ifdef __cplusplus\n"); + fprintf(file, "}\n"); + fprintf(file, "#endif\n"); + + fprintf(file, "#endif /* __MIG_STRNCPY_ZEROFILL_FORWARD_TYPE_DECLS__ */\n"); + fprintf(file, "#endif /* __has_include() */\n"); + fprintf(file, "#endif /* __has_include */\n"); + fprintf(file, "\t\n/* END MIG_STRNCPY_ZEROFILL CODE */\n\n"); + + if (ShortCircuit) + fprintf(file, "#include \n"); + if (isuser && IsKernelUser) { + fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNEL_SPECIFIC_CODE_)\n"); + fprintf(file, "#include \n"); + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + } + fprintf(file, "\n"); +} + +static void +WriteETAPDefines(FILE *file) +{ + statement_t *stat; + int fnum; + char *fname; + int first = TRUE; + + fprintf(file, "\n#ifndef subsystem_to_name_map_%s\n", SubsystemName); + fprintf(file, "#define subsystem_to_name_map_%s \\\n", SubsystemName); + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + fnum = SubsystemBase + stat->stRoutine->rtNumber; + fname = stat->stRoutine->rtName; + if (! first) + fprintf(file, ",\\\n"); + fprintf(file, " { \"%s\", %d }", fname, fnum); + first = FALSE; + } + fprintf(file, "\n#endif\n"); +} + +static void +WriteProlog(FILE *file, char *protect, boolean_t more, boolean_t isuser) +{ + if (protect != strNULL) { + fprintf(file, "#ifndef\t_%s\n", protect); + fprintf(file, "#define\t_%s\n", protect); + fprintf(file, "\n"); + } + + fprintf(file, "/* Module %s */\n", SubsystemName); + fprintf(file, "\n"); + + if (more) { + WriteIncludes(file, isuser, UseSplitHeaders); + } + fprintf(file, "#ifdef AUTOTEST\n"); + fprintf(file, "#ifndef FUNCTION_PTR_T\n"); + fprintf(file, "#define FUNCTION_PTR_T\n"); + fprintf(file, "typedef void (*function_ptr_t)"); + fprintf(file, "(mach_port_t, char *, mach_msg_type_number_t);\n"); + fprintf(file, "typedef struct {\n"); + fprintf(file, " char *name;\n"); + fprintf(file, " function_ptr_t function;\n"); + fprintf(file, "} function_table_entry;\n"); + fprintf(file, "typedef function_table_entry *function_table_t;\n"); + fprintf(file, "#endif /* FUNCTION_PTR_T */\n"); + fprintf(file, "#endif /* AUTOTEST */\n"); + fprintf(file, "\n#ifndef\t%s_MSG_COUNT\n", SubsystemName); + fprintf(file, "#define\t%s_MSG_COUNT\t%d\n", SubsystemName, rtNumber); + fprintf(file, "#endif\t/* %s_MSG_COUNT */\n\n", SubsystemName); +} + +static void +WriteEpilog(FILE *file, char *protect, boolean_t isuser) +{ + char *defname = isuser ? "__AfterMigUserHeader" : "__AfterMigServerHeader"; + + WriteETAPDefines(file); + fprintf(file, "\n#ifdef %s\n%s\n#endif /* %s */\n", defname, defname, defname); + if (protect != strNULL) { + fprintf(file, "\n"); + fprintf(file, "#endif\t /* _%s */\n", protect); + } +} + +static void +WriteUserRoutine(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName); + WriteMigExternal(file); + fprintf(file, "%s %s\n", ReturnTypeStr(rt), rt->rtUserName); + if (BeLint) { + fprintf(file, "#if\t%s\n", LintLib); + fprintf(file, " ("); + WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", " , ""); + fprintf(file, ")\n"); + WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n"); + fprintf(file, "{ "); + fprintf(file, "return "); + fprintf(file, "%s(", rt->rtUserName); + WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", ""); + fprintf(file, "); }\n"); + fprintf(file, "#else\n"); + } + if (BeAnsiC) { + fprintf(file, "(\n"); + WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); + fprintf(file, ");\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "(\n"); + WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); + fprintf(file, ");\n"); + fprintf(file, "#else\n"); + + fprintf(file, " ();\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + if (BeLint) { + fprintf(file, "#endif\t/* %s */\n", LintLib); + } +} + +void +WriteUserRequestUnion(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "/* union of all requests */\n\n"); + fprintf(file, "#ifndef __RequestUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName); + fprintf(file, "#define __RequestUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName); + fprintf(file, "union __RequestUnion__%s%s_subsystem {\n", UserPrefix, SubsystemName); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) { + routine_t *rt; + + rt = stat->stRoutine; + fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtUserName); + } + } + fprintf(file, "};\n"); + fprintf(file, "#endif /* !__RequestUnion__%s%s_subsystem__defined */\n", UserPrefix, SubsystemName); +} + +void +WriteUserReplyUnion(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "/* union of all replies */\n\n"); + fprintf(file, "#ifndef __ReplyUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName); + fprintf(file, "#define __ReplyUnion__%s%s_subsystem__defined\n", UserPrefix, SubsystemName); + fprintf(file, "union __ReplyUnion__%s%s_subsystem {\n", UserPrefix, SubsystemName); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) { + routine_t *rt; + + rt = stat->stRoutine; + fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtUserName); + } + } + fprintf(file, "};\n"); + fprintf(file, "#endif /* !__RequestUnion__%s%s_subsystem__defined */\n", UserPrefix, SubsystemName); +} + +void +WriteUserHeader(FILE *file, statement_t *stats) +{ + statement_t *stat; + char *protect = strconcat(SubsystemName, "_user_"); + + WriteProlog(file, protect, TRUE, TRUE); + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skImport: + case skUImport: + case skDImport: + WriteImport(file, stat->stFileName); + break; + + case skRoutine: + case skSImport: + case skIImport: + break; + + default: + fatal("WriteHeader(): bad statement_kind_t (%d)", (int) stat->stKind); + } + fprintf(file, "\n"); + fprintf(file, "#ifdef __BeforeMigUserHeader\n"); + fprintf(file, "__BeforeMigUserHeader\n"); + fprintf(file, "#endif /* __BeforeMigUserHeader */\n"); + fprintf(file, "\n"); + fprintf(file, "#include \n"); + fprintf(file, "__BEGIN_DECLS\n"); + fprintf(file, "\n"); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) + WriteUserRoutine(file, stat->stRoutine); + } + fprintf(file, "\n"); + fprintf(file, "__END_DECLS\n"); + + fprintf(file, "\n"); + fprintf(file, "/********************** Caution **************************/\n"); + fprintf(file, "/* The following data types should be used to calculate */\n"); + fprintf(file, "/* maximum message sizes only. The actual message may be */\n"); + fprintf(file, "/* smaller, and the position of the arguments within the */\n"); + fprintf(file, "/* message layout may vary from what is presented here. */\n"); + fprintf(file, "/* For example, if any of the arguments are variable- */\n"); + fprintf(file, "/* sized, and less than the maximum is sent, the data */\n"); + fprintf(file, "/* will be packed tight in the actual message to reduce */\n"); + fprintf(file, "/* the presence of holes. */\n"); + fprintf(file, "/********************** Caution **************************/\n"); + fprintf(file, "\n"); + + WriteRequestTypes(file, stats); + WriteUserRequestUnion(file, stats); + + WriteReplyTypes(file, stats); + WriteUserReplyUnion(file, stats); + + WriteEpilog(file, protect, TRUE); +} + +static void +WriteDefinesRoutine(FILE *file, routine_t *rt) +{ + char *up = (char *)malloc(strlen(rt->rtName)+1); + + up = toupperstr(strcpy(up, rt->rtName)); + fprintf(file, "#define\tMACH_ID_%s\t\t%d\t/* %s() */\n", up, rt->rtNumber + SubsystemBase, rt->rtName); + if (rt->rtKind == rkRoutine) + fprintf(file, "#define\tMACH_ID_%s_REPLY\t\t%d\t/* %s() */\n", up, rt->rtNumber + SubsystemBase + 100, rt->rtName); + fprintf(file, "\n"); +} + +void +WriteServerRoutine(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName); + WriteMigExternal(file); + + // MIG_SERVER_ROUTINE can be defined by system headers to resolve to an attribute that + // tells the compiler that this is a MIG server routine. Useful for static analysis. + fprintf(file, "MIG_SERVER_ROUTINE\n%s %s\n", ReturnTypeStr(rt), rt->rtServerName); + + if (BeLint) { + fprintf(file, "#if\t%s\n", LintLib); + fprintf(file, " ("); + WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", " , ""); + fprintf(file, ")\n"); + WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ";\n", ";\n"); + fprintf(file, "{ "); + fprintf(file, "return "); + fprintf(file, "%s(", rt->rtServerName); + WriteList(file, rt->rtArgs, WriteNameDecl, akbServerArg, ", ", ""); + fprintf(file, "); }\n"); + fprintf(file, "#else /* %s */\n",LintLib); + } + if (BeAnsiC) { + fprintf(file, "(\n"); + WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ",\n", "\n"); + fprintf(file, ");\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "(\n"); + WriteList(file, rt->rtArgs, WriteServerVarDecl, akbServerArg, ",\n", "\n"); + fprintf(file, ");\n"); + fprintf(file, "#else\n"); + + fprintf(file, " ();\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + if (BeLint) { + fprintf(file, "#endif\t/* %s */\n", LintLib); + } +} + +static void +WriteDispatcher(FILE *file) +{ + statement_t *stat; + int descr_count = 0; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + routine_t *rt = stat->stRoutine; + descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0); + } + fprintf(file, "\n"); + + WriteMigExternal(file); + fprintf(file, "boolean_t %s(\n", ServerDemux); + fprintf(file, "\t\tmach_msg_header_t *InHeadP,\n"); + fprintf(file, "\t\tmach_msg_header_t *OutHeadP);\n\n"); + + WriteMigExternal(file); + fprintf(file, "mig_routine_t %s_routine(\n", ServerDemux); + fprintf(file, "\t\tmach_msg_header_t *InHeadP);\n\n"); + + fprintf(file, "\n/* Description of this subsystem, for use in direct RPC */\n"); + fprintf(file, "extern const struct %s {\n", ServerSubsys); + if (UseRPCTrap) { + fprintf(file, "\tstruct subsystem *\tsubsystem;\t/* Reserved for system use */\n"); + } + else { + fprintf(file, "\tmig_server_routine_t\tserver;\t/* Server routine */\n"); + } + fprintf(file, "\tmach_msg_id_t\tstart;\t/* Min routine number */\n"); + fprintf(file, "\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n"); + fprintf(file, "\tunsigned int\tmaxsize;\t/* Max msg size */\n"); + if (UseRPCTrap) { + fprintf(file, "\tvm_address_t\tbase_addr;\t/* Base address */\n"); + fprintf(file, "\tstruct rpc_routine_descriptor\t/*Array of routine descriptors */\n"); + } + else { + fprintf(file, "\tvm_address_t\treserved;\t/* Reserved */\n"); + fprintf(file, "\tstruct routine_descriptor\t/*Array of routine descriptors */\n"); + } + fprintf(file, "\t\troutine[%d];\n", rtNumber); + if (UseRPCTrap) { + fprintf(file, "\tstruct rpc_routine_arg_descriptor\t/*Array of arg descriptors */\n"); + fprintf(file, "\t\targ_descriptor[%d];\n", descr_count); + } + fprintf(file, "} %s;\n", ServerSubsys); + fprintf(file, "\n"); +} + +void +WriteBogusServerRoutineAnnotationDefine(FILE *file) { + // MIG_SERVER_ROUTINE can be defined by system headers to resolve to + // an attribute that tells the compiler that this is a MIG server routine. + // Useful for static analysis. + fprintf(file, "#ifndef MIG_SERVER_ROUTINE\n"); + fprintf(file, "#define MIG_SERVER_ROUTINE\n"); + fprintf(file, "#endif\n"); + fprintf(file, "\n"); +} + +void +WriteServerHeader(FILE *file, statement_t *stats) +{ + statement_t *stat; + char *protect = strconcat(SubsystemName, "_server_"); + + WriteProlog(file, protect, TRUE, FALSE); + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skImport: + case skSImport: + case skDImport: + WriteImport(file, stat->stFileName); + break; + + case skRoutine: + case skUImport: + case skIImport: + break; + + default: + fatal("WriteServerHeader(): bad statement_kind_t (%d)", (int) stat->stKind); + } + fprintf(file, "\n#ifdef __BeforeMigServerHeader\n"); + fprintf(file, "__BeforeMigServerHeader\n"); + fprintf(file, "#endif /* __BeforeMigServerHeader */\n\n"); + + WriteBogusServerRoutineAnnotationDefine(file); + + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) + WriteServerRoutine(file, stat->stRoutine); + } + WriteDispatcher(file); + + WriteRequestTypes(file, stats); + WriteServerRequestUnion(file, stats); + + WriteReplyTypes(file, stats); + WriteServerReplyUnion(file, stats); + + WriteEpilog(file, protect, FALSE); +} + +static void +WriteInternalRedefine(FILE *file, routine_t *rt) +{ + fprintf(file, "#define %s %s_external\n", rt->rtUserName, rt->rtUserName); +} + +void +WriteInternalHeader(FILE *file, statement_t *stats) +{ + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skRoutine: + WriteInternalRedefine(file, stat->stRoutine); + break; + + case skImport: + case skUImport: + case skSImport: + case skDImport: + case skIImport: + break; + + default: + fatal("WriteInternalHeader(): bad statement_kind_t (%d)", (int) stat->stKind); + } +} + +void +WriteDefinesHeader(FILE *file, statement_t *stats) +{ + statement_t *stat; + char *protect = strconcat(SubsystemName, "_defines"); + + WriteProlog(file, protect, FALSE, FALSE); + fprintf(file, "\n/*\tDefines related to the Subsystem %s\t*/\n\n", SubsystemName); + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skRoutine: + WriteDefinesRoutine(file, stat->stRoutine); + break; + + case skImport: + case skSImport: + case skUImport: + break; + + default: + fatal("WriteDefinesHeader(): bad statement_kind_t (%d)", (int) stat->stKind); + } + WriteEpilog(file, protect, FALSE); +} diff --git a/bootstrap_cmds/migcom.tproj/lexxer.h b/bootstrap_cmds/migcom.tproj/lexxer.h new file mode 100644 index 0000000..6f1cfa5 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/lexxer.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +extern void LookFileName(void); +extern void LookString(void); +extern void LookQString(void); +extern void LookNormal(void); diff --git a/bootstrap_cmds/migcom.tproj/lexxer.l b/bootstrap_cmds/migcom.tproj/lexxer.l new file mode 100644 index 0000000..82b32e5 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/lexxer.l @@ -0,0 +1,314 @@ +%k 10000 +%n 5000 +%a 20000 +%e 10000 +%p 25000 + +Ident ([A-Za-z_][A-Za-z_0-9]*) +Number ([0-9]+) +String ([-/._$A-Za-z0-9]+) +QString (\"[^"\n]*\") +AString (\<[^>\n]*\>) +FileName ({QString}|{AString}) + +/* new flex syntax to accomplish the same thing as #define YY_NO_UNPUT */ +%option nounput + +%{ +/* + * Copyright (c) 1999-2018 Apple, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999, 2008 Apple Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include "strdefs.h" +#include "type.h" +#include +#include +#include +#include "statement.h" +#include "global.h" +#include "y.tab.h" // was parser.h +#include "lexxer.h" +#include "mig_machine.h" + +#define PortSize (sizeof (mach_port_t) * NBBY) +#ifdef __STDC__ +#define stringize(x) #x +#else /* __STDC__ */ +#define stringize(x) "x" +#endif /* __STDC__ */ + +#ifdef LDEBUG +#define RETURN(sym) \ +{ \ + printf("yylex: returning '%s' (%d)\n", stringize(sym), (sym)); \ + return (sym); \ +} +#else /* LDEBUG */ +#define RETURN(sym) return (sym) +#endif /* LDEBUG */ + +#define TPRETURN(intype, outtype, tsize) \ +{ \ + yylval.symtype.innumber = (intype); \ + yylval.symtype.instr = stringize(intype); \ + yylval.symtype.outnumber = (outtype); \ + yylval.symtype.outstr = stringize(outtype); \ + yylval.symtype.size = (tsize); \ + RETURN(sySymbolicType); \ +} + +#define TRETURN(type, tsize) TPRETURN(type,type,tsize) + +#define SAVE(s) do {oldYYBegin = s; BEGIN s; } while (0) + +#define RESTORE BEGIN oldYYBegin + +#define FRETURN(val) \ +{ \ + yylval.flag = (val); \ + RETURN(syIPCFlag); \ +} + +#define YY_NO_UNPUT /* suppress yyunput generation */ + +static int oldYYBegin = 0; + +int lineno = 0; /* Replaces lex yylineno */ + +static void doSharp(char *); /* process body of # directives */ +extern void yyerror(char *); +%} + +%Start Normal String FileName QString SkipToEOL + +%% + +[Rr][Oo][Uu][Tt][Ii][Nn][Ee] RETURN(syRoutine); +[Ss][Ii][Mm][Pp][Ll][Ee][Rr][Oo][Uu][Tt][Ii][Nn][Ee] RETURN(sySimpleRoutine); +[Ss][Uu][Bb][Ss][Yy][Ss][Tt][Ee][Mm] RETURN(sySubsystem); +[Mm][Ss][Gg][Oo][Pp][Tt][Ii][Oo][Nn] RETURN(syMsgOption); +[Uu][Ss][Ee][Ss][Pp][Ee][Cc][Ii][Aa][Ll][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syUseSpecialReplyPort); +[Cc][Oo][Nn][Ss][Uu][Mm][Ee][Oo][Nn][Ss][Ee][Nn][Dd][Ee][Rr][Rr][Oo][Rr] RETURN(syConsumeOnSendError); +[Mm][Ss][Gg][Ss][Ee][Qq][Nn][Oo] RETURN(syMsgSeqno); +[Ww][Aa][Ii][Tt][Tt][Ii][Mm][Ee] RETURN(syWaitTime); +[Ss][Ee][Nn][Dd][Tt][Ii][Mm][Ee] RETURN(sySendTime); +[Nn][Oo][Ww][Aa][Ii][Tt][Tt][Ii][Mm][Ee] RETURN(syNoWaitTime); +[Nn][Oo][Ss][Ee][Nn][Dd][Tt][Ii][Mm][Ee] RETURN(syNoSendTime); +[Ii][Nn] RETURN(syIn); +[Oo][Uu][Tt] RETURN(syOut); +[Uu][Ss][Ee][Rr][Ii][Mm][Pp][Ll] RETURN(syUserImpl); +[Ss][Ee][Rr][Vv][Ee][Rr][Ii][Mm][Pp][Ll] RETURN(syServerImpl); +[Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(sySecToken); +[Ss][Ee][Rr][Vv][Ee][Rr][Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(syServerSecToken); +[Uu][Ss][Ee][Rr][Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(syUserSecToken); +[Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syAuditToken); +[Ss][Ee][Rr][Vv][Ee][Rr][Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syServerAuditToken); +[Uu][Ss][Ee][Rr][Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syUserAuditToken); +[Ss][Ee][Rr][Vv][Ee][Rr][Cc][Oo][Nn][Tt][Ee][Xx][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syServerContextToken); +[Ii][Nn][Oo][Uu][Tt] RETURN(syInOut); +[Rr][Ee][Qq][Uu][Ee][Ss][Tt][Pp][Oo][Rr][Tt] RETURN(syRequestPort); +[Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syReplyPort); +[Uu][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syUReplyPort); +[Ss][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(sySReplyPort); +[Aa][Rr][Rr][Aa][Yy] RETURN(syArray); +[Oo][Ff] RETURN(syOf); +[Ee][Rr][Rr][Oo][Rr] RETURN(syErrorProc); +[Ss][Ee][Rr][Vv][Ee][Rr][Pp][Rr][Ee][Ff][Ii][Xx] RETURN(syServerPrefix); +[Uu][Ss][Ee][Rr][Pp][Rr][Ee][Ff][Ii][Xx] RETURN(syUserPrefix); +[Ss][Ee][Rr][Vv][Ee][Rr][Dd][Ee][Mm][Uu][Xx] RETURN(syServerDemux); +[Rr][Cc][Ss][Ii][Dd] RETURN(syRCSId); +[Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syImport); +[Uu][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syUImport); +[Ss][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(sySImport); +[Dd][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syDImport); +[Ii][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syIImport); +[Tt][Yy][Pp][Ee] RETURN(syType); +[Kk][Ee][Rr][Nn][Ee][Ll][Ss][Ee][Rr][Vv][Ee][Rr] RETURN(syKernelServer); +[Kk][Ee][Rr][Nn][Ee][Ll][Uu][Ss][Ee][Rr] RETURN(syKernelUser); +[Ss][Kk][Ii][Pp] RETURN(sySkip); +[Ss][Tt][Rr][Uu][Cc][Tt] RETURN(syStruct); +[Ii][Nn][Tt][Rr][Aa][Nn] RETURN(syInTran); +[Oo][Uu][Tt][Tt][Rr][Aa][Nn] RETURN(syOutTran); +[Dd][Ee][Ss][Tt][Rr][Uu][Cc][Tt][Oo][Rr] RETURN(syDestructor); +[Cc][Tt][Yy][Pp][Ee] RETURN(syCType); +[Cc][Uu][Ss][Ee][Rr][Tt][Yy][Pp][Ee] RETURN(syCUserType); +[Cc][Ss][Ee][Rr][Vv][Ee][Rr][Tt][Yy][Pp][Ee] RETURN(syCServerType); +[Cc]_[Ss][Tt][Rr][Ii][Nn][Gg] RETURN(syCString); + +[Ss][Aa][Mm][Ee][Cc][Oo][Uu][Nn][Tt] FRETURN(flSameCount); +[Rr][Ee][Tt][Cc][Oo][Dd][Ee] FRETURN(flRetCode); +[Pp][Hh][Yy][Ss][Ii][Cc][Aa][Ll][Cc][Oo][Pp][Yy] FRETURN(flPhysicalCopy); +[Oo][Vv][Ee][Rr][Ww][Rr][Ii][Tt][Ee] FRETURN(flOverwrite); +[Dd][Ee][Aa][Ll][Ll][Oo][Cc] FRETURN(flDealloc); +[Nn][Oo][Tt][Dd][Ee][Aa][Ll][Ll][Oo][Cc] FRETURN(flNotDealloc); +[Cc][Oo][Uu][Nn][Tt][Ii][Nn][Oo][Uu][Tt] FRETURN(flCountInOut); +[Pp][Oo][Ll][Yy][Mm][Oo][Rr][Pp][Hh][Ii][Cc] TPRETURN(MACH_MSG_TYPE_POLYMORPHIC, MACH_MSG_TYPE_POLYMORPHIC, PortSize); +[Aa][Uu][Tt][Oo] FRETURN(flAuto); +[Cc][Oo][Nn][Ss][Tt] FRETURN(flConst); +"PointerTo" RETURN(syPointerTo); +"PointerToIfNot" RETURN(syPointerToIfNot); +"ValueOf" RETURN(syValueOf); +"UserTypeLimit" RETURN(syUserTypeLimit); +"OnStackLimit" RETURN(syOnStackLimit); + + +"MACH_MSG_TYPE_UNSTRUCTURED" TRETURN(MACH_MSG_TYPE_UNSTRUCTURED,0); +"MACH_MSG_TYPE_BIT" TRETURN(MACH_MSG_TYPE_BIT,1); +"MACH_MSG_TYPE_BOOLEAN" TRETURN(MACH_MSG_TYPE_BOOLEAN,32); +"MACH_MSG_TYPE_INTEGER_8" TRETURN(MACH_MSG_TYPE_INTEGER_8,8); +"MACH_MSG_TYPE_INTEGER_16" TRETURN(MACH_MSG_TYPE_INTEGER_16,16); +"MACH_MSG_TYPE_INTEGER_32" TRETURN(MACH_MSG_TYPE_INTEGER_32,32); +"MACH_MSG_TYPE_INTEGER_64" TRETURN(MACH_MSG_TYPE_INTEGER_64,64); +"MACH_MSG_TYPE_REAL_32" TRETURN(MACH_MSG_TYPE_REAL_32,32); +"MACH_MSG_TYPE_REAL_64" TRETURN(MACH_MSG_TYPE_REAL_64,64); +"MACH_MSG_TYPE_CHAR" TRETURN(MACH_MSG_TYPE_CHAR,8); +"MACH_MSG_TYPE_BYTE" TRETURN(MACH_MSG_TYPE_BYTE,8); + +"MACH_MSG_TYPE_MOVE_RECEIVE" TPRETURN(MACH_MSG_TYPE_MOVE_RECEIVE,MACH_MSG_TYPE_PORT_RECEIVE,PortSize); +"MACH_MSG_TYPE_COPY_SEND" TPRETURN(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize); +"MACH_MSG_TYPE_MAKE_SEND" TPRETURN(MACH_MSG_TYPE_MAKE_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize); +"MACH_MSG_TYPE_MOVE_SEND" TPRETURN(MACH_MSG_TYPE_MOVE_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize); +"MACH_MSG_TYPE_MAKE_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_MAKE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize); +"MACH_MSG_TYPE_MOVE_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_MOVE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize); + +"MACH_MSG_TYPE_PORT_NAME" TRETURN(MACH_MSG_TYPE_PORT_NAME,PortSize); +"MACH_MSG_TYPE_PORT_RECEIVE" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_RECEIVE,PortSize); +"MACH_MSG_TYPE_PORT_SEND" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_SEND,PortSize); +"MACH_MSG_TYPE_PORT_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize); +"MACH_MSG_TYPE_POLYMORPHIC" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC, MACH_MSG_TYPE_POLYMORPHIC, PortSize); + +":" RETURN(syColon); +";" RETURN(sySemi); +"," RETURN(syComma); +"+" RETURN(syPlus); +"-" RETURN(syMinus); +"*" RETURN(syStar); +"/" RETURN(syDiv); +"(" RETURN(syLParen); +")" RETURN(syRParen); +"=" RETURN(syEqual); +"^" RETURN(syCaret); +"~" RETURN(syTilde); +"<" RETURN(syLAngle); +">" RETURN(syRAngle); +"[" RETURN(syLBrack); +"]" RETURN(syRBrack); +"|" RETURN(syBar); + +{Ident} { yylval.identifier = strmake(yytext); + RETURN(syIdentifier); } +{Number} { yylval.number = atoi(yytext); RETURN(syNumber); } + +{String} { yylval.string = strmake(yytext); + SAVE(Normal); RETURN(syString); } +{FileName} { yylval.string = strmake(yytext); + SAVE(Normal); RETURN(syFileName); } +{QString} { yylval.string = strmake(yytext); + SAVE(Normal); RETURN(syQString); } + +^\#[ \t]*{Number}[ \t]*\"[^"]*\" { doSharp(yytext+1); + BEGIN SkipToEOL; } +^\#\ *{Number} { doSharp(yytext+1); + BEGIN SkipToEOL; } +^\#pragma { BEGIN SkipToEOL; } +^\# { yyerror("illegal # directive"); + BEGIN SkipToEOL; } + +\n { RESTORE; lineno++; } +. ; + +[ \t] ; +\n lineno++; +. { SAVE(Normal); RETURN(syError); } + +%% + +extern void +LookNormal() +{ + SAVE(Normal); +} + +extern void +LookString() +{ + SAVE(String); +} + +extern void +LookQString() +{ + SAVE(QString); +} + +extern void +LookFileName() +{ + SAVE(FileName); +} + +static void +doSharp(char *body) +{ + char *startName, *endName; + + lineno = atoi(body); + startName = strchr(body, '"'); + if (startName != NULL) { + endName = strrchr(body, '"'); + *endName = '\0'; + strfree(yyinname); + yyinname = strmake(startName+1); + } +} + +int +yywrap() +{ + return 1; +} diff --git a/bootstrap_cmds/migcom.tproj/mig.1 b/bootstrap_cmds/migcom.tproj/mig.1 new file mode 100644 index 0000000..6ab8cda --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/mig.1 @@ -0,0 +1,88 @@ +.TH MIG 1 "Nov 20, 2009" "Apple Computer, Inc." +.SH NAME +mig \- Mach Interface Generator +.SH SYNOPSIS +.B mig +[ +.I "option \&..." +] +.I "file" + +.SH DESCRIPTION +The +.I mig +command invokes the Mach Interface Generator to generate Remote Procedure Call (RPC) +code for client-server style Mach IPC from specification files. +.SH OPTIONS +.TP +.B \-q/-Q +Omit / +.I emit +warning messages. +.TP +.B \-v/-V +Verbose mode ( on / +.I off +) will summarize types and routines as they are processed. +.TP +.B \-l/-L +Controls ( +.I off +/ on ) whether or not generated code logs RPC events to system logs. +.TP +.B \-k/-K +Controls ( +.I on +/ off ) whether generated code complies with ANSI C standards. +.TP +.B \-s/-S +Controls ( on / +.I off +) whether generated server-side code includes a generated symbol table. +.TP +.BI \-i " prefix" +Specify User file prefix. +.TP +.BI \-user " path" +Specify name of user-side RPC generated source file. +.TP +.BI \-server " path" +Specify name of server-side RPC generated source file. +.TP +.BI \-header " path" +Specify name of user-side generated header file. +.TP +.BI \-sheader " path" +Specify name of server-side generated header file. +.TP +.BI \-iheader " path" +Specify internal header file name. +.TP +.BI \-dheader " path" +Specify defines generated header file. +.TP +.BI \-maxonstack " value" +Specify maximum size of message on stack. +.TP +.B \-split +Use split headers. +.TP +.BI \-arch " arch" +Specify machine architecture for target code. +.TP +.B \-MD +Option is passed to the C compiler for dependency generation. +.TP +.B \-cpp +This option is ignored. +.TP +.BI \-cc " path" +Specify pathname to specific C compiler to use as the preprocessor. +.TP +.BI \-migcom " path" +Specify pathname to specific migcom compiler to use for source code generation. +.TP +.BI \-isysroot " path" +Specify SDK root directory. +.TP +Additional options provided are passed along to the C compiler unchanged. diff --git a/bootstrap_cmds/migcom.tproj/mig.c b/bootstrap_cmds/migcom.tproj/mig.c new file mode 100644 index 0000000..9bdd304 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/mig.c @@ -0,0 +1,405 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +/* + * Switches are; + * -[v,Q] verbose or not quiet: prints out type + * and routine information as mig runs. + * -[V,q] not verbose or quiet : don't print + * information during compilation + * (this is the default) + * -[r,R] do or don't use rpc calls instead of + * send/receive pairs. Default is -r. + * -[s,S] generate symbol table or not: generate a + * table of rpc-name, number, routine triplets + * as an external data structure -- main use is + * for protection system's specification of rights + * and for protection dispatch code. Default is -s. + * -[l,L] -L generate code that insert code for logging + * the most important events that happen at the + * stub level (message conception, target routine + * calls). Default is -l. + * -[k,K] -K enforces MIG to generate K&R C language, with the + * addition of ANSI C syntax under #ifdef __STDC__. + * Default is -k. + * -[n,N] -n enforces NDR checking and conversion logic generation. + * Default is -N (no checking). + * -i + * Put each user routine in its own file. The + * file is named .c. + * -user + * Name the user-side file + * -server + * Name the server-side file + * -header + * Name the user-side header file + * -iheader + * Name the user-side internal header file + * -sheader + * Name the server-side header file + * -dheader + * Name the defines (msgh_ids) header file + * + * DESIGN: + * Mig uses a lexxer module created by lex from lexxer.l and + * a parser module created by yacc from parser.y to parse an + * interface definitions module for a mach server. + * The parser module calls routines in statement.c + * and routines.c to build a list of statement structures. + * The most interesting statements are the routine definitions + * which contain information about the name, type, characteristics + * of the routine, an argument list containing information for + * each argument type, and a list of special arguments. The + * argument type structures are build by routines in type.c + * Once parsing is completed, the three code generation modules: + * header.c user.c and server.c are called sequentially. These + * do some code generation directly and also call the routines + * in utils.c for common (parameterized) code generation. + * + */ + +#include +#include +#include +#include "error.h" +#include "lexxer.h" +#include "global.h" +#include "write.h" + +extern int yyparse(void); +static FILE *myfopen(const char *name, const char *mode); + +static void +parseArgs(int argc,char *argv[]) +{ + if (argc == 2 && streql(argv[1], "-version")) { + PrintVersion = TRUE; + return; + } + + while (--argc > 0) + if ((++argv)[0][0] == '-') { + switch (argv[0][1]) { + + case 'q': + BeQuiet = TRUE; + break; + + case 'Q': + BeQuiet = FALSE; + break; + + case 'v': + BeVerbose = TRUE; + break; + + case 'V': + BeVerbose = FALSE; + break; + + case 'r': + UseMsgRPC = TRUE; + break; + + case 'R': + UseMsgRPC = FALSE; + break; + + case 'l': + UseEventLogger = FALSE; + break; + + case 'L': + UseEventLogger = TRUE; + break; + + case 'k': + BeAnsiC = TRUE; + break; + + case 'K': + BeAnsiC = FALSE; + break; + + case 'n': + if (streql(argv[0], "-novouchers")) { + IsVoucherCodeAllowed = FALSE; + } else { + CheckNDR = TRUE; + } + break; + + case 'N': + CheckNDR = FALSE; + break; + + case 's': + if (streql(argv[0], "-server")) { + --argc; ++argv; + if (argc == 0) + fatal("missing name for -server option"); + ServerFileName = strmake(argv[0]); + } + else if (streql(argv[0], "-sheader")) { + --argc; ++argv; + if (argc == 0) + fatal ("missing name for -sheader option"); + ServerHeaderFileName = strmake(argv[0]); + } + else if (streql(argv[0], "-split")) + UseSplitHeaders = TRUE; + else + GenSymTab = TRUE; + break; + + case 'S': + GenSymTab = FALSE; + break; + + case 't': + warn("Mach RPC traps not fully supported"); + TestRPCTrap = TRUE; + UseRPCTrap = TRUE; + break; + + case 'T': + UseRPCTrap = FALSE; + break; + + case 'i': + if (streql(argv[0], "-iheader")) { + --argc; ++argv; + if (argc == 0) + fatal("missing name for -iheader option"); + InternalHeaderFileName = strmake(argv[0]); + } + else { + --argc; ++argv; + if (argc == 0) + fatal("missing prefix for -i option"); + UserFilePrefix = strmake(argv[0]); + } + break; + + case 'u': + if (streql(argv[0], "-user")) { + --argc; ++argv; + if (argc == 0) + fatal("missing name for -user option"); + UserFileName = strmake(argv[0]); + } + else + fatal("unknown flag: '%s'", argv[0]); + break; + + case 'h': + if (streql(argv[0], "-header")) { + --argc; ++argv; + if (argc == 0) + fatal("missing name for -header option"); + UserHeaderFileName = strmake(argv[0]); + } + else + fatal("unknown flag: '%s'", argv[0]); + break; + + case 'd': + if (streql(argv[0], "-dheader")) { + --argc; ++argv; + if (argc == 0) + fatal("missing name for -dheader option"); + DefinesHeaderFileName = strmake(argv[0]); + } + else + fatal("unknown flag: '%s'", argv[0]); + break; + + case 'm': + if (streql(argv[0], "-maxonstack")) { + --argc; ++argv; + if (argc == 0) + fatal("missing size for -maxonstack option"); + MaxMessSizeOnStack = atoi(argv[0]); + } + else + fatal("unknown flag: '%s'", argv[0]); + break; + + case 'X': + ShortCircuit = FALSE; + break; + + case 'x': + ShortCircuit = TRUE; + /* fall thru - no longer supported */ + + default: + fatal("unknown/unsupported flag: '%s'", argv[0]); + /*NOTREACHED*/ + } + } + else + fatal("bad argument: '%s'", *argv); +} + +FILE *uheader, *server, *user; + +int +main(int argc, char *argv[]) +{ + FILE *iheader = 0; + FILE *sheader = 0; + FILE *dheader = 0; + time_t loc; + extern string_t GenerationDate; + + set_program_name("mig"); + parseArgs(argc, argv); + if (PrintVersion) { + printf("%s\n", MIG_VERSION); + fflush(stdout); + exit(0); + } + init_global(); + init_type(); + loc = time((time_t *)0); + GenerationDate = ctime(&loc); + + LookNormal(); + (void) yyparse(); + + if (mig_errors > 0) + fatal("%d errors found. Abort.\n", mig_errors); + + more_global(); + + uheader = myfopen(UserHeaderFileName, "w"); + if (!UserFilePrefix) + user = myfopen(UserFileName, "w"); + server = myfopen(ServerFileName, "w"); + if (ServerHeaderFileName) + sheader = myfopen(ServerHeaderFileName, "w"); + if (IsKernelServer) { + iheader = myfopen(InternalHeaderFileName, "w"); + } + if (DefinesHeaderFileName) + dheader = myfopen(DefinesHeaderFileName, "w"); + if (BeVerbose) { + printf("Writing %s ... ", UserHeaderFileName); + fflush(stdout); + } + WriteUserHeader(uheader, stats); + fclose(uheader); + if (ServerHeaderFileName) { + if (BeVerbose) { + printf ("done.\nWriting %s ...", ServerHeaderFileName); + fflush (stdout); + } + WriteServerHeader(sheader, stats); + fclose(sheader); + } + if (IsKernelServer) { + if (BeVerbose) { + printf("done.\nWriting %s ... ", InternalHeaderFileName); + fflush(stdout); + } + WriteInternalHeader(iheader, stats); + fclose(iheader); + } + if (DefinesHeaderFileName) { + if (BeVerbose) { + printf ("done.\nWriting %s ...", DefinesHeaderFileName); + fflush (stdout); + } + WriteDefinesHeader(dheader, stats); + fclose(dheader); + } + if (UserFilePrefix) { + if (BeVerbose) { + printf("done.\nWriting individual user files ... "); + fflush(stdout); + } + WriteUserIndividual(stats); + } + else { + if (BeVerbose) { + printf("done.\nWriting %s ... ", UserFileName); + fflush(stdout); + } + WriteUser(user, stats); + fclose(user); + } + if (BeVerbose) { + printf("done.\nWriting %s ... ", ServerFileName); + fflush(stdout); + } + WriteServer(server, stats); + fclose(server); + if (BeVerbose) + printf("done.\n"); + + exit(0); +} + +static FILE * +myfopen(const char *name, const char *mode) +{ + const char *realname; + FILE *file; + + if (name == strNULL) + realname = "/dev/null"; + else + realname = name; + + file = fopen(realname, mode); + if (file == NULL) + fatal("fopen(%s): %s", realname, strerror(errno)); + + return file; +} diff --git a/bootstrap_cmds/migcom.tproj/mig.sh b/bootstrap_cmds/migcom.tproj/mig.sh new file mode 100644 index 0000000..85cf5a2 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/mig.sh @@ -0,0 +1,218 @@ +#!/bin/bash +# +# Copyright (c) 1999-2008 Apple Inc. All rights reserved. +# +# @APPLE_LICENSE_HEADER_START@ +# +# "Portions Copyright (c) 1999, 2008 Apple Inc. All Rights +# Reserved. This file contains Original Code and/or Modifications of +# Original Code as defined in and that are subject to the Apple Public +# Source License Version 1.0 (the 'License'). You may not use this file +# except in compliance with the License. Please obtain a copy of the +# License at http://www.apple.com/publicsource and read it before using +# this file. +# +# The Original Code and all software distributed under the License are +# distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER +# EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, +# INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the +# License for the specific language governing rights and limitations +# under the License." +# +# @APPLE_LICENSE_HEADER_END@ +# +# Mach Operating System +# Copyright (c) 1991,1990 Carnegie Mellon University +# All Rights Reserved. +# +# Permission to use, copy, modify and distribute this software and its +# documentation is hereby granted, provided that both the copyright +# notice and this permission notice appear in all copies of the +# software, derivative works or modified versions, and any portions +# thereof, and that both notices appear in supporting documentation. +# +# CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" +# CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR +# ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. +# +# Carnegie Mellon requests users of this software to return to +# +# Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU +# School of Computer Science +# Carnegie Mellon University +# Pittsburgh PA 15213-3890 +# +# any improvements or extensions that they make and grant Carnegie Mellon +# the rights to redistribute these changes. +# + +realpath() +{ + local FILE="$1" + local PARENT=$(dirname "$FILE") + local BASE=$(basename "$FILE") + pushd "$PARENT" >/dev/null 2>&1 || return 0 + local DIR=$(pwd -P) + popd >/dev/null + if [ "$DIR" == "/" ]; then + echo "/$BASE" + else + echo "$DIR/$BASE" + fi + return 1 +} + +scriptPath=$(realpath "$0") +scriptRoot=$(dirname "$scriptPath") +migcomPath=$(realpath "${scriptRoot}/../libexec/migcom") + +if [ -n "${SDKROOT}" ]; then + sdkRoot="${SDKROOT}"; +fi + +if [ -z "${MIGCC}" ]; then + xcrunPath="/usr/bin/xcrun" + if [ -x "${xcrunPath}" ]; then + MIGCC=`"${xcrunPath}" -sdk "$sdkRoot" -find cc` + else + MIGCC=$(realpath "${scriptRoot}/cc") + fi +fi + +C=${MIGCC} +M=${MIGCOM-${migcomPath}} + +if [ $# -eq 1 ] && [ "$1" = "-version" ] ; then + "$M" "$@" + exit $? +fi + +cppflags="-D__MACH30__" + +files= +arch=`/usr/bin/arch` + +WORKTMP=`/usr/bin/mktemp -d "${TMPDIR:-/tmp}/mig.XXXXXX"` +if [ $? -ne 0 ]; then + echo "Failure creating temporary work directory: ${WORKTMP}" + echo "Exiting..." + exit 1 +fi + +# parse out the arguments until we hit plain file name(s) + +until [ $# -eq 0 ] +do + case "$1" in + -[dtqkKQvVtTrRsSlLxXnN] ) migflags=( "${migflags[@]}" "$1" ); shift;; + -i ) sawI=1; migflags=( "${migflags[@]}" "$1" "$2" ); shift; shift;; + -user ) user="$2"; if [ ! "${sawI-}" ]; then migflags=( "${migflags[@]}" "$1" "$2" ); fi; shift; shift;; + -server ) server="$2"; migflags=( "${migflags[@]}" "$1" "$2" ); shift; shift;; + -header ) header="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;; + -sheader ) sheader="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;; + -iheader ) iheader="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;; + -dheader ) dheader="$2"; migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;; + -arch ) arch="$2"; shift; shift;; + -target ) target=( "$1" "$2"); shift; shift;; + -maxonstack ) migflags=( "${migflags[@]}" "$1" "$2"); shift; shift;; + -split ) migflags=( "${migflags[@]}" "$1" ); shift;; + -novouchers ) migflags=( "${migflags[@]}" "$1" ); shift;; + -MD ) sawMD=1; cppflags=( "${cppflags[@]}" "$1"); shift;; + -cpp) shift; shift;; + -cc) C="$2"; shift; shift;; + -migcom) M="$2"; shift; shift;; + -isysroot) sdkRoot=$(realpath "$2"); shift; shift;; + -* ) cppflags=( "${cppflags[@]}" "$1"); shift;; + * ) break;; + esac +done + +# process the rest as files +until [ $# -eq 0 ] +do + case "$1" in + -[dtqkKQvVtTrRsSlLxXnN] ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;; + -i ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -user ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -server ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -header ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -sheader ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -iheader ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -dheader ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -arch ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift ; shift; continue;; + -target ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift ; shift; continue;; + -maxonstack ) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -split ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;; + -novouchers ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;; + -MD ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;; + -cpp) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -cc) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -migcom) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -isysroot) echo "warning: option \"$1 $2\" after filename(s) ignored"; shift; shift; continue;; + -* ) echo "warning: option \"$1\" after filename(s) ignored"; shift; continue;; + * ) file="$1"; shift;; + esac + base="$(basename "${file}" .defs)" + temp="${WORKTMP}/${base}.$$" + sourcedir="$(dirname "${file}")" + if [ -n "${sdkRoot}" ] + then + iSysRootParm=( "-isysroot" "${sdkRoot}" ) + fi + if [ ! -r "${file}" ] + then + echo "error: cannot read file ${file}" + rm -rf ${WORKTMP} + exit 1 + fi + rm -f "${temp}.c" "${temp}.d" + (echo '#line 1 '\"${file}\" ; cat "${file}" ) > "${temp}.c" + "$C" -E -arch ${arch} "${target[@]}" "${cppflags[@]}" -I "${sourcedir}" "${iSysRootParm[@]}" "${temp}.c" | "$M" "${migflags[@]}" + if [ $? -ne 0 ] + then + rm -rf "${temp}.c" "${temp}.d" "${WORKTMP}" + exit 1 + fi + if [ "${sawMD}" -a -f "${temp}.d" ] + then + deps= + s= + rheader="${header-${base}.h}" + if [ "${rheader}" != /dev/null ]; then + deps="${deps}${s}${rheader}"; s=" " + fi + ruser="${user-${base}User.c}" + if [ "${ruser}" != /dev/null ]; then + deps="${deps}${s}${ruser}"; s=" " + fi + rserver="${server-${base}Server.c}" + if [ "${rserver}" != /dev/null ]; then + deps="${deps}${s}${rserver}"; s=" " + fi + rsheader="${sheader-/dev/null}" + if [ "${rsheader}" != /dev/null ]; then + deps="${deps}${s}${rsheader}"; s=" " + fi + riheader="${iheader-/dev/null}" + if [ "${riheader}" != /dev/null ]; then + deps="${deps}${s}${riheader}"; s=" " + fi + rdheader="${dheader-/dev/null}" + if [ "${rdheader}" != /dev/null ]; then + deps="${deps}${s}${rdheader}"; s=" " + fi + for target in "${deps}" + do + sed -e 's;^'"${temp}"'.o[ ]*:;'"${target}"':;' \ + -e 's;: '"${temp}"'.c;: '"$file"';' \ + < "${temp}.d" > "${target}.d" + done + rm -f "${temp}.d" + fi + rm -f "${temp}.c" +done + +/bin/rmdir "${WORKTMP}" +exit 0 + diff --git a/bootstrap_cmds/migcom.tproj/mig_errors.h b/bootstrap_cmds/migcom.tproj/mig_errors.h new file mode 100644 index 0000000..f951667 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/mig_errors.h @@ -0,0 +1,84 @@ +/* + * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1987 Carnegie-Mellon University + * All rights reserved. The CMU software License Agreement specifies + * the terms and conditions for use and redistribution. + */ +/* + * Mach Interface Generator errors + * + * $Header: /Users/Shared/bootstrap_cmds/bootstrap_cmds/migcom.tproj/mig_errors.h,v 1.1.1.2 2000/01/11 00:36:18 wsanchez Exp $ + * + * HISTORY + * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University + * Extensive revamping. Added polymorphic arguments. + * Allow multiple variable-sized inline arguments in messages. + * + * 28-Apr-88 Bennet Yee (bsy) at Carnegie-Mellon University + * Put mig_symtab back. + * + * 2-Dec-87 David Golub (dbg) at Carnegie-Mellon University + * Added MIG_ARRAY_TOO_LARGE. + * + * 25-May-87 Richard Draves (rpd) at Carnegie-Mellon University + * Added definition of death_pill_t. + * + * 31-Jul-86 Michael Young (mwyoung) at Carnegie-Mellon University + * Created. + */ +#ifndef _MIG_ERRORS_H +#define _MIG_ERRORS_H + +#include +#include + +#define MIG_TYPE_ERROR -300 /* Type check failure */ +#define MIG_REPLY_MISMATCH -301 /* Wrong return message ID */ +#define MIG_REMOTE_ERROR -302 /* Server detected error */ +#define MIG_BAD_ID -303 /* Bad message ID */ +#define MIG_BAD_ARGUMENTS -304 /* Server found wrong arguments */ +#define MIG_NO_REPLY -305 /* Server shouldn't reply */ +#define MIG_EXCEPTION -306 /* Server raised exception */ +#define MIG_ARRAY_TOO_LARGE -307 /* User specified array not large enough + to hold returned array */ + +typedef struct { + msg_header_t Head; + msg_type_t RetCodeType; + kern_return_t RetCode; +} death_pill_t; + +typedef struct mig_symtab { + char *ms_routine_name; + int ms_routine_number; +#ifdef hc + void +#else + int +#endif + (*ms_routine)(); +} mig_symtab_t; + +#endif _MIG_ERRORS_H diff --git a/bootstrap_cmds/migcom.tproj/mig_machine.h b/bootstrap_cmds/migcom.tproj/mig_machine.h new file mode 100644 index 0000000..aab5801 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/mig_machine.h @@ -0,0 +1,16 @@ +#if !defined(_MIG_MACHINE_H) +#define _MIG_MACHINE_H + +#define machine_alignment(SZ,ESZ) \ +(((SZ) = ((SZ) + 3) & ~3), (SZ) += (ESZ)) + +#define machine_padding(BYTES) \ +((BYTES & 3) ? (4 - (BYTES & 3)) : 0) + +#ifndef NBBY +#define NBBY 8 +#endif + +#define PACK_MESSAGES TRUE + +#endif diff --git a/bootstrap_cmds/migcom.tproj/migcom.1 b/bootstrap_cmds/migcom.tproj/migcom.1 new file mode 100644 index 0000000..3ade83b --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/migcom.1 @@ -0,0 +1,73 @@ +.TH MIGCOM 1 "Nov 20, 2009" "Apple Computer, Inc." +.SH NAME +migcom \- Mach Interface Generator COMpiler +.SH SYNOPSIS +.B migcom +[ +.I "option \&..." +] +.I " syNumber +%token sySymbolicType +%token syIdentifier +%token syString syQString +%token syFileName +%token syIPCFlag + +%left syPlus syMinus +%left syStar syDiv + + +%type ImportIndicant +%type VarArrayHead ArrayHead StructHead IntExp +%type NamedTypeSpec TransTypeSpec NativeTypeSpec TypeSpec +%type CStringSpec +%type BasicTypeSpec PrevTypeSpec ArgumentType +%type TypePhrase +%type PrimIPCType IPCType +%type RoutineDecl Routine SimpleRoutine +%type Direction TrImplKeyword +%type Argument Trailer Arguments ArgumentList +%type IPCFlags + +%{ + +#include +#include "lexxer.h" +#include "strdefs.h" +#include "type.h" +#include "routine.h" +#include "statement.h" +#include "global.h" +#include "error.h" + +static char *import_name(statement_kind_t sk); +extern int yylex(void); + +/* forward declaration */ +void yyerror(char *s); + +%} + +%union +{ + u_int number; + identifier_t identifier; + string_t string; + statement_kind_t statement_kind; + ipc_type_t *type; + struct + { + u_int innumber; /* msgt_name value, when sending */ + string_t instr; + u_int outnumber; /* msgt_name value, when receiving */ + string_t outstr; + u_int size; /* 0 means there is no default size */ + } symtype; + routine_t *routine; + arg_kind_t direction; + argument_t *argument; + ipc_flags_t flag; +} + +%% + +Statements : /* empty */ + | Statements Statement + ; + +Statement : Subsystem sySemi + | WaitTime sySemi + | SendTime sySemi + | MsgOption sySemi + | UseSpecialReplyPort sySemi + | ConsumeOnSendError sySemi + | UserTypeLimit sySemi + | OnStackLimit sySemi + | Error sySemi + | ServerPrefix sySemi + | UserPrefix sySemi + | ServerDemux sySemi + | TypeDecl sySemi + | RoutineDecl sySemi +{ + statement_t *st = stAlloc(); + + st->stKind = skRoutine; + st->stRoutine = $1; + rtCheckRoutine($1); + if (BeVerbose) + rtPrintRoutine($1); +} + | sySkip sySemi + { rtSkip(); } + | Import sySemi + | RCSDecl sySemi + | sySemi + | error sySemi + { yyerrok; } + ; + +Subsystem : SubsystemStart SubsystemMods + SubsystemName SubsystemBase +{ + if (BeVerbose) { + printf("Subsystem %s: base = %u%s%s\n\n", + SubsystemName, SubsystemBase, + IsKernelUser ? ", KernelUser" : "", + IsKernelServer ? ", KernelServer" : ""); + } +} + ; + +SubsystemStart : sySubsystem +{ + if (SubsystemName != strNULL) { + warn("previous Subsystem decl (of %s) will be ignored", SubsystemName); + IsKernelUser = FALSE; + IsKernelServer = FALSE; + strfree(SubsystemName); + } +} + ; + +SubsystemMods : /* empty */ + | SubsystemMods SubsystemMod + ; + +SubsystemMod : syKernelUser +{ + if (IsKernelUser) + warn("duplicate KernelUser keyword"); + if (!UseMsgRPC) { + warn("with KernelUser the -R option is meaningless"); + UseMsgRPC = TRUE; + } + IsKernelUser = TRUE; +} + | syKernelServer +{ + if (IsKernelServer) + warn("duplicate KernelServer keyword"); + IsKernelServer = TRUE; +} + ; + +SubsystemName : syIdentifier { SubsystemName = $1; } + ; + +SubsystemBase : syNumber { SubsystemBase = $1; } + ; + +MsgOption : LookString syMsgOption syString +{ + if (streql($3, "MACH_MSG_OPTION_NONE")) { + MsgOption = strNULL; + if (BeVerbose) + printf("MsgOption: canceled\n\n"); + } + else { + MsgOption = $3; + if (BeVerbose) + printf("MsgOption %s\n\n",$3); + } +} + ; + +UseSpecialReplyPort : syUseSpecialReplyPort syNumber +{ + UseSpecialReplyPort = ($2 != 0); + HasUseSpecialReplyPort |= UseSpecialReplyPort; +} + ; + +ConsumeOnSendError : LookString syConsumeOnSendError syString +{ + if (strcasecmp($3, "None") == 0) { + ConsumeOnSendError = ConsumeOnSendErrorNone; + } else if (strcasecmp($3, "Timeout") == 0) { + ConsumeOnSendError = ConsumeOnSendErrorTimeout; + HasConsumeOnSendError = TRUE; + } else if (strcasecmp($3, "Any") == 0) { + ConsumeOnSendError = ConsumeOnSendErrorAny; + HasConsumeOnSendError = TRUE; + } else { + error("syntax error"); + } +} + ; + +UserTypeLimit : syUserTypeLimit syNumber + {UserTypeLimit = $2; } + ; +OnStackLimit : syOnStackLimit syNumber + {MaxMessSizeOnStack = $2; } + ; + +WaitTime : LookString syWaitTime syString +{ + WaitTime = $3; + if (BeVerbose) + printf("WaitTime %s\n\n", WaitTime); +} + | syNoWaitTime +{ + WaitTime = strNULL; + if (BeVerbose) + printf("NoWaitTime\n\n"); +} + ; + +SendTime : LookString sySendTime syString +{ + SendTime = $3; + if (BeVerbose) + printf("SendTime %s\n\n", SendTime); +} + | syNoSendTime +{ + SendTime = strNULL; + if (BeVerbose) + printf("NoSendTime\n\n"); +} + ; + +Error : syErrorProc syIdentifier +{ + ErrorProc = $2; + if (BeVerbose) + printf("ErrorProc %s\n\n", ErrorProc); +} + ; + +ServerPrefix : syServerPrefix syIdentifier +{ + ServerPrefix = $2; + if (BeVerbose) + printf("ServerPrefix %s\n\n", ServerPrefix); +} + ; + +UserPrefix : syUserPrefix syIdentifier +{ + UserPrefix = $2; + if (BeVerbose) + printf("UserPrefix %s\n\n", UserPrefix); +} + ; + +ServerDemux : syServerDemux syIdentifier +{ + ServerDemux = $2; + if (BeVerbose) + printf("ServerDemux %s\n\n", ServerDemux); +} + ; + +Import : LookFileName ImportIndicant syFileName +{ + statement_t *st = stAlloc(); + st->stKind = $2; + st->stFileName = $3; + + if (BeVerbose) + printf("%s %s\n\n", import_name($2), $3); +} + ; + +ImportIndicant : syImport { $$ = skImport; } + | syUImport { $$ = skUImport; } + | sySImport { $$ = skSImport; } + | syIImport { $$ = skIImport; } + | syDImport { $$ = skDImport; } + ; + +RCSDecl : LookQString syRCSId syQString +{ + if (RCSId != strNULL) + warn("previous RCS decl will be ignored"); + if (BeVerbose) + printf("RCSId %s\n\n", $3); + RCSId = $3; +} + ; + +TypeDecl : syType NamedTypeSpec +{ + identifier_t name = $2->itName; + + if (itLookUp(name) != itNULL) + warn("overriding previous definition of %s", name); + itInsert(name, $2); +} + ; + +NamedTypeSpec : syIdentifier syEqual TransTypeSpec + { itTypeDecl($1, $$ = $3); } + ; + +TransTypeSpec : TypeSpec + { $$ = itResetType($1); } + | TransTypeSpec syInTran syColon syIdentifier + syIdentifier syLParen syIdentifier syRParen +{ + $$ = $1; + + if (($$->itTransType != strNULL) && !streql($$->itTransType, $4)) + warn("conflicting translation types (%s, %s)", $$->itTransType, $4); + $$->itTransType = $4; + + if (($$->itInTrans != strNULL) && !streql($$->itInTrans, $5)) + warn("conflicting in-translation functions (%s, %s)", $$->itInTrans, $5); + $$->itInTrans = $5; + + if (($$->itServerType != strNULL) && !streql($$->itServerType, $7)) + warn("conflicting server types (%s, %s)", $$->itServerType, $7); + $$->itServerType = $7; +} + | TransTypeSpec syOutTran syColon syIdentifier + syIdentifier syLParen syIdentifier syRParen +{ + $$ = $1; + + if (($$->itServerType != strNULL) && !streql($$->itServerType, $4)) + warn("conflicting server types (%s, %s)", $$->itServerType, $4); + $$->itServerType = $4; + + if (($$->itOutTrans != strNULL) && !streql($$->itOutTrans, $5)) + warn("conflicting out-translation functions (%s, %s)", $$->itOutTrans, $5); + $$->itOutTrans = $5; + + if (($$->itTransType != strNULL) && !streql($$->itTransType, $7)) + warn("conflicting translation types (%s, %s)", $$->itTransType, $7); + $$->itTransType = $7; +} + | TransTypeSpec syDestructor syColon syIdentifier + syLParen syIdentifier syRParen +{ + $$ = $1; + + if (($$->itDestructor != strNULL) && !streql($$->itDestructor, $4)) + warn("conflicting destructor functions (%s, %s)", $$->itDestructor, $4); + $$->itDestructor = $4; + + if (($$->itTransType != strNULL) && !streql($$->itTransType, $6)) + warn("conflicting translation types (%s, %s)", $$->itTransType, $6); + $$->itTransType = $6; +} + | TransTypeSpec syCType syColon syIdentifier +{ + $$ = $1; + + if (($$->itUserType != strNULL) && !streql($$->itUserType, $4)) + warn("conflicting user types (%s, %s)", $$->itUserType, $4); + $$->itUserType = $4; + + if (($$->itServerType != strNULL) && !streql($$->itServerType, $4)) + warn("conflicting server types (%s, %s)", $$->itServerType, $4); + $$->itServerType = $4; +} + | TransTypeSpec syCUserType syColon syIdentifier +{ + $$ = $1; + + if (($$->itUserType != strNULL) && !streql($$->itUserType, $4)) + warn("conflicting user types (%s, %s)", $$->itUserType, $4); + $$->itUserType = $4; +} + | TransTypeSpec syCServerType + syColon syIdentifier +{ + $$ = $1; + + if (($$->itServerType != strNULL) && !streql($$->itServerType, $4)) + warn("conflicting server types (%s, %s)", + $$->itServerType, $4); + $$->itServerType = $4; +} + ; + +TypeSpec : BasicTypeSpec + { $$ = $1; } + | PrevTypeSpec + { $$ = $1; } + | VarArrayHead TypeSpec + { $$ = itVarArrayDecl($1, $2); } + | ArrayHead TypeSpec + { $$ = itArrayDecl($1, $2); } + | syCaret TypeSpec + { $$ = itPtrDecl($2); } + | StructHead TypeSpec + { $$ = itStructDecl($1, $2); } + | CStringSpec + { $$ = $1; } + | NativeTypeSpec + { $$ = $1; } + ; + +NativeTypeSpec : syPointerTo syLParen TypePhrase syRParen + { $$ = itNativeType($3, TRUE, 0); } + | syPointerToIfNot syLParen TypePhrase syComma + TypePhrase syRParen + { $$ = itNativeType($3, TRUE, $5); } + | syValueOf syLParen TypePhrase syRParen + { $$ = itNativeType($3, FALSE, 0); } + ; + +BasicTypeSpec : IPCType +{ + $$ = itShortDecl($1.innumber, $1.instr, + $1.outnumber, $1.outstr, + $1.size); +} + | syLParen IPCType syComma IntExp + IPCFlags syRParen +{ + error("Long form type declarations aren't allowed any longer\n"); +} + ; + +PrimIPCType : syNumber +{ + $$.innumber = $$.outnumber = $1; + $$.instr = $$.outstr = strNULL; + $$.size = 0; +} + | sySymbolicType + { $$ = $1; } + ; + +IPCType : PrimIPCType + { $$ = $1; } + | PrimIPCType syBar PrimIPCType +{ + if ($1.size != $3.size) { + if ($1.size == 0) + $$.size = $3.size; + else if ($3.size == 0) + $$.size = $1.size; + else { + error("sizes in IPCTypes (%d, %d) aren't equal", + $1.size, $3.size); + $$.size = 0; + } + } + else + $$.size = $1.size; + $$.innumber = $1.innumber; + $$.instr = $1.instr; + $$.outnumber = $3.outnumber; + $$.outstr = $3.outstr; +} + ; + +PrevTypeSpec : syIdentifier + { $$ = itPrevDecl($1); } + ; + +VarArrayHead : syArray syLBrack syRBrack syOf + { $$ = 0; } + | syArray syLBrack syStar syRBrack syOf + { $$ = 0; } + | syArray syLBrack syStar syColon IntExp + syRBrack syOf + { $$ = $5; } + ; + +ArrayHead : syArray syLBrack IntExp syRBrack syOf + { $$ = $3; } + ; + +StructHead : syStruct syLBrack IntExp syRBrack syOf + { $$ = $3; } + ; + +CStringSpec : syCString syLBrack IntExp syRBrack + { $$ = itCStringDecl($3, FALSE); } + | syCString syLBrack syStar syColon + IntExp syRBrack + { $$ = itCStringDecl($5, TRUE); } + ; + +TypePhrase : syIdentifier + { $$ = $1; } + | TypePhrase syIdentifier + { $$ = strphrase($1, $2); strfree($2); } + ; + +IntExp : IntExp syPlus IntExp + { $$ = $1 + $3; } + | IntExp syMinus IntExp + { $$ = $1 - $3; } + | IntExp syStar IntExp + { $$ = $1 * $3; } + | IntExp syDiv IntExp + { $$ = $1 / $3; } + | syNumber + { $$ = $1; } + | syLParen IntExp syRParen + { $$ = $2; } + ; + + +RoutineDecl : Routine { $$ = $1; } + | SimpleRoutine { $$ = $1; } + ; + +Routine : syRoutine syIdentifier Arguments + { $$ = rtMakeRoutine($2, $3); } + ; + +SimpleRoutine : sySimpleRoutine syIdentifier Arguments + { $$ = rtMakeSimpleRoutine($2, $3); } + ; + +Arguments : syLParen syRParen + { $$ = argNULL; } + | syLParen ArgumentList syRParen + { $$ = $2; } + + ; + +ArgumentList : Argument + { $$ = $1; } + | Trailer + { $$ = $1; } + | Argument sySemi ArgumentList +{ + $$ = $1; + $$->argNext = $3; +} + | Trailer sySemi ArgumentList +{ + $$ = $1; + $$->argNext = $3; +} + ; + +Argument : Direction syIdentifier ArgumentType IPCFlags +{ + $$ = argAlloc(); + $$->argKind = $1; + $$->argName = $2; + $$->argType = $3; + $$->argFlags = $4; + if ($3 && $3->itNative) { + if ($1 != akIn && $1 != akOut && $1 != akInOut) + error("Illegal direction specified"); + + if (!($3->itNativePointer) && $1 != akIn) + error("ValueOf only valid for in"); + + if (($3->itBadValue) != NULL && $1 != akIn) + error("PointerToIfNot only valid for in"); + } +} + ; + +Trailer : TrImplKeyword syIdentifier ArgumentType +{ + $$ = argAlloc(); + $$->argKind = $1; + $$->argName = $2; + $$->argType = $3; +} + ; + + +Direction : /* empty */ { $$ = akNone; } + | syIn { $$ = akIn; } + | syOut { $$ = akOut; } + | syInOut { $$ = akInOut; } + | syRequestPort { $$ = akRequestPort; } + | syReplyPort { $$ = akReplyPort; } + | sySReplyPort { $$ = akSReplyPort; } + | syUReplyPort { $$ = akUReplyPort; } + | syWaitTime { $$ = akWaitTime; } + | sySendTime { $$ = akSendTime; } + | syMsgOption { $$ = akMsgOption; } + | sySecToken { $$ = akSecToken; } + | syServerSecToken { $$ = akServerSecToken; } + | syUserSecToken { $$ = akUserSecToken; } + | syAuditToken { $$ = akAuditToken; } + | syServerAuditToken { $$ = akServerAuditToken; } + | syUserAuditToken { $$ = akUserAuditToken; } + | syServerContextToken { $$ = akServerContextToken; } + | syMsgSeqno { $$ = akMsgSeqno; } + ; + + + +TrImplKeyword : syServerImpl { $$ = akServerImpl; } + | syUserImpl { $$ = akUserImpl; } + ; + + +ArgumentType : syColon syIdentifier +{ + $$ = itLookUp($2); + if ($$ == itNULL) + error("type '%s' not defined", $2); +} + | syColon NamedTypeSpec + { $$ = $2; } + | syColon NativeTypeSpec + { $$ = $2; } + ; + +IPCFlags : /* empty */ + { $$ = flNone; } + | IPCFlags syComma syIPCFlag +{ + if ($1 & $3) + warn("redundant IPC flag ignored"); + else + $$ = $1 | $3; +} + | IPCFlags syComma syIPCFlag syLBrack syRBrack +{ + if ($3 != flDealloc) + warn("only Dealloc is variable"); + else + $$ = $1 | flMaybeDealloc; +} + +LookString : /* empty */ + { LookString(); } + ; + +LookFileName : /* empty */ + { LookFileName(); } + ; + +LookQString : /* empty */ + { LookQString(); } + ; + +%% + +void +yyerror(char *s) +{ + error(s); +} + +static char * +import_name(statement_kind_t sk) +{ + switch (sk) { + + case skImport: + return "Import"; + + case skSImport: + return "SImport"; + + case skUImport: + return "UImport"; + + case skIImport: + return "IImport"; + + case skDImport: + return "DImport"; + + default: + fatal("import_name(%d): not import statement", (int) sk); + /*NOTREACHED*/ + return strNULL; + } +} diff --git a/bootstrap_cmds/migcom.tproj/routine.c b/bootstrap_cmds/migcom.tproj/routine.c new file mode 100644 index 0000000..f4c0778 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/routine.c @@ -0,0 +1,1844 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include "type.h" + +#include +#include +#include "mig_machine.h" +#include "error.h" +#include "alloc.h" +#include "global.h" +#include "routine.h" +#include "write.h" + +u_int rtNumber = 0; + +static void rtSizeDelta(FILE *file, u_int mask, routine_t *rt); + +routine_t * +rtAlloc(void) +{ + routine_t *new; + + new = (routine_t *) calloc(1, sizeof *new); + if (new == rtNULL) + fatal("rtAlloc(): %s", strerror(errno)); + new->rtNumber = rtNumber++; + new->rtName = strNULL; + new->rtErrorName = strNULL; + new->rtUserName = strNULL; + new->rtServerName = strNULL; + + return new; +} + +void +rtSkip(void) +{ + rtNumber++; +} + +argument_t * +argAlloc(void) +{ + extern void KPD_error(FILE *file, argument_t *arg); + + static argument_t prototype = + { + .argName = strNULL, + .argNext = argNULL, + .argKind = akNone, + .argType = itNULL, + .argKPD_Type = argKPD_NULL, + .argKPD_Template = (void(*)(FILE *, argument_t *, boolean_t))KPD_error, + .argKPD_Init = KPD_error, + .argKPD_Pack = KPD_error, + .argKPD_Extract = KPD_error, + .argKPD_TypeCheck = KPD_error, + .argVarName = strNULL, + .argMsgField = strNULL, + .argTTName = strNULL, + .argPadName = strNULL, + .argSuffix = strNULL, + .argFlags = flNone, + .argDeallocate = d_NO, + .argCountInOut = FALSE, + .argRoutine = rtNULL, + .argCount = argNULL, + .argSubCount = argNULL, + .argCInOut = argNULL, + .argPoly = argNULL, + .argDealloc = argNULL, + .argSameCount = argNULL, + .argParent = argNULL, + .argMultiplier = 1, + .argRequestPos = 0, + .argReplyPos = 0, + .argByReferenceUser = FALSE, + .argByReferenceServer = FALSE, + .argTempOnStack = FALSE + }; + argument_t *new; + + new = (argument_t *) malloc(sizeof *new); + if (new == argNULL) + fatal("argAlloc(): %s", strerror(errno)); + *new = prototype; + return new; +} + +routine_t * +rtMakeRoutine(identifier_t name, argument_t *args) +{ + routine_t *rt = rtAlloc(); + + rt->rtName = name; + rt->rtKind = rkRoutine; + rt->rtArgs = args; + + return rt; +} + +routine_t * +rtMakeSimpleRoutine(identifier_t name, argument_t *args) +{ + routine_t *rt = rtAlloc(); + + rt->rtName = name; + rt->rtKind = rkSimpleRoutine; + rt->rtArgs = args; + + return rt; +} + +char * +rtRoutineKindToStr(routine_kind_t rk) +{ + switch (rk) { + + case rkRoutine: + return "Routine"; + + case rkSimpleRoutine: + return "SimpleRoutine"; + + default: + fatal("rtRoutineKindToStr(%d): not a routine_kind_t", rk); + /*NOTREACHED*/ + return strNULL; + } +} + +static void +rtPrintArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + if (!akCheck(arg->argKind, akbUserArg|akbServerArg) || + (akIdent(arg->argKind) == akeCount) || + (akIdent(arg->argKind) == akeDealloc) || + (akIdent(arg->argKind) == akeNdrCode) || + (akIdent(arg->argKind) == akePoly)) + return; + + printf("\n\t"); + + switch (akIdent(arg->argKind)) { + + case akeRequestPort: + printf("RequestPort"); + break; + + case akeReplyPort: + printf("ReplyPort"); + break; + + case akeWaitTime: + printf("WaitTime"); + break; + + case akeSendTime: + printf("SendTime"); + break; + + case akeMsgOption: + printf("MsgOption"); + break; + + case akeMsgSeqno: + printf("MsgSeqno\t"); + break; + + case akeSecToken: + printf("SecToken\t"); + break; + + case akeAuditToken: + printf("AuditToken\t"); + break; + + case akeContextToken: + printf("ContextToken\t"); + break; + + case akeImplicit: + printf("Implicit\t"); + break; + + default: + if (akCheck(arg->argKind, akbRequest)) { + if (akCheck(arg->argKind, akbSend)) + printf("In"); + else + printf("(In)"); + } + if (akCheck(arg->argKind, akbReply)) { + if (akCheck(arg->argKind, akbReturn)) + printf("Out"); + else + printf("(Out)"); + } + printf("\t"); + } + + printf("\t%s: %s", arg->argName, it->itName); + + if (arg->argDeallocate == d_YES) + printf(", Dealloc"); + else if (arg->argDeallocate == d_MAYBE) + printf(", Dealloc[]"); + + if (arg->argCountInOut) + printf(", CountInOut"); + + if (arg->argFlags & flSameCount) + printf(", SameCount"); + + if (arg->argFlags & flPhysicalCopy) + printf(", PhysicalCopy"); + + if (arg->argFlags & flRetCode) + printf(", PhysicalCopy"); + + if (arg->argFlags & flOverwrite) + printf(", Overwrite"); + + if (arg->argFlags & flAuto) + printf(", Auto"); + + if (arg->argFlags & flConst) + printf(", Const"); +} + +void +rtPrintRoutine(routine_t *rt) +{ + argument_t *arg; + + printf("%s (%d) %s(", rtRoutineKindToStr(rt->rtKind), rt->rtNumber, rt->rtName); + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + rtPrintArg(arg); + + printf(")\n"); + printf("\n"); +} + +/* + * Determines appropriate value of msg-simple for the message. + * One version for both In & Out. + */ + +static void +rtCheckSimple(argument_t *args, u_int mask, boolean_t *simple) +{ + argument_t *arg; + boolean_t MustBeComplex = FALSE; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, mask)) { + ipc_type_t *it = arg->argType; + + if (IS_KERN_PROC_DATA(it)) + MustBeComplex = TRUE; + } + + *simple = !MustBeComplex; +} + +static void +rtCheckFit(routine_t *rt, u_int mask, boolean_t *fitp, boolean_t *uselimp, u_int *knownp) +{ + boolean_t uselim = FALSE; + argument_t *arg; + u_int size = sizeof(mach_msg_header_t); + + if (!rt->rtSimpleRequest) + machine_alignment(size,sizeof(mach_msg_body_t)); + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, mask)) { + ipc_type_t *it = arg->argType; + + machine_alignment(size, it->itMinTypeSize); + if (it->itNative) + uselim = TRUE; + else if (IS_VARIABLE_SIZED_UNTYPED(it)) { + machine_alignment(size, it->itTypeSize); + size += it->itPadSize; + } + } + *knownp = size; + if (MaxMessSizeOnStack == -1) { + *fitp = TRUE; + *uselimp = FALSE; + } + else if (size > MaxMessSizeOnStack) { + *fitp = FALSE; + *uselimp = FALSE; + } + else if (!uselim) { + *fitp = TRUE; + *uselimp = FALSE; + } + else if (UserTypeLimit == -1) { + *fitp = FALSE; + *uselimp = FALSE; + } + else if (size + UserTypeLimit > MaxMessSizeOnStack) { + *fitp = FALSE; + *uselimp = TRUE; + } + else { + *fitp = TRUE; + *uselimp = TRUE; + } +} + +static void +rtFindHowMany(routine_t *rt) +{ + argument_t *arg; + int multiplier = 1; + boolean_t test; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (IS_MULTIPLE_KPD(it)) { + if (!it->itVarArray) + multiplier = it->itKPD_Number; + test = !it->itVarArray && !it->itElement->itVarArray; + it = it->itElement; + } + else + test = !it->itVarArray; + + if (akCheck(arg->argKind, akbSendKPD)) { + + if (it->itInLine) + rt->rtCountPortsIn += it->itNumber * multiplier; + else if (it->itPortType) { + if (test) + rt->rtCountOolPortsIn += it->itNumber * multiplier; + } + else { + if (test) + rt->rtCountOolIn += (it->itNumber * it->itSize + 7)/8 * multiplier; + } + } + if (akCheckAll(arg->argKind, akbReturnKPD)) { + if (it->itInLine) + rt->rtCountPortsOut += it->itNumber * multiplier; + else if (it->itPortType) { + if (test) + rt->rtCountOolPortsOut += it->itNumber * multiplier; + } + else { + if (test) + rt->rtCountOolOut += ((it->itNumber * it->itSize + 7)/8) * multiplier; + } + } + } +} + +boolean_t +rtCheckMask(argument_t *args, u_int mask) +{ + argument_t *arg; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + return TRUE; + return FALSE; +} + +boolean_t +rtCheckMaskFunction(argument_t *args, u_int mask, boolean_t (*func)(argument_t *arg)) +{ + argument_t *arg; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + if ((*func)(arg)) + return TRUE; + return FALSE; +} + + +int +rtCountKPDs(argument_t *args, u_int mask) +{ + argument_t *arg; + int count = 0; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + count += arg->argType->itKPD_Number; + return count; +} + +int +rtCountFlags(argument_t *args, u_int flag) +{ + argument_t *arg; + int count = 0; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (arg->argFlags & flag) + count++; + return count; +} + +int +rtCountArgDescriptors(argument_t *args, int *argcount) +{ + argument_t *arg; + int count = 0; + + if (argcount) + *argcount = 0; + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbServerArg)) { + if (RPCFixedArray(arg) || + RPCPort(arg) || + RPCVariableArray(arg) || + RPCPortArray(arg)) { + count++; + if (argcount) + (*argcount)++; + } + else { + if (argcount) { + if (arg->argType->itStruct && arg->argType->itNumber && + (arg->argType->itSize >= 32)) + *argcount += arg->argType->itNumber * (arg->argType->itSize / 32); + else + (*argcount)++; + } + } + } + return count; +} + +int +rtCountMask(argument_t *args, u_int mask) +{ + argument_t *arg; + int count = 0; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) + count++; + return count; +} + +/* arg->argType may be NULL in this function */ + +static void +rtDefaultArgKind(routine_t *rt, argument_t *arg) +{ + if ((arg->argKind == akNone) && (rt->rtRequestPort == argNULL)) + arg->argKind = akRequestPort; + + if (arg->argKind == akNone) + arg->argKind = akIn; +} + +/* + * Initializes arg->argDeallocate, + * arg->argCountInOut from arg->argFlags + * and perform consistency check over the + * flags. + */ + +static ipc_flags_t +rtProcessDeallocFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, dealloc_t *what, string_t name) +{ + + /* only one of flDealloc, flNotDealloc, flMaybeDealloc */ + + if (flags & flMaybeDealloc) { + if (flags & (flDealloc|flNotDealloc)) { + warn("%s: Dealloc and NotDealloc ignored with Dealloc[]", name); + flags &= ~(flDealloc|flNotDealloc); + } + } + + if ((flags&(flDealloc|flNotDealloc)) == (flDealloc|flNotDealloc)) { + warn("%s: Dealloc and NotDealloc cancel out", name); + flags &= ~(flDealloc|flNotDealloc); + } + + if (((IsKernelServer && akCheck(kind, akbReturn)) || + (IsKernelUser && akCheck(kind, akbSend))) && + (flags & flDealloc)) { + /* + * For a KernelServer interface and an Out argument, + * or a KernelUser interface and an In argument, + * we avoid a possible spurious warning about the deallocate bit. + * For compatibility with Mach 2.5, the deallocate bit + * may need to be enabled on some inline arguments. + */ + + *what= d_YES; + } + else if (flags & (flMaybeDealloc|flDealloc)) { + /* only give semantic warnings if the user specified something */ + if (it->itInLine && !it->itPortType) { + warn("%s: Dealloc is ignored: it is meaningless for that type of argument", name); + flags &= ~(flMaybeDealloc|flDealloc); + } + else + *what = (flags & flMaybeDealloc) ? d_MAYBE : d_YES; + } + return flags; +} + +static void +rtProcessSameCountFlag(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + ipc_flags_t flags = arg->argFlags; + string_t name = arg->argVarName; + static argument_t *old_arg; + + if (flags & flSameCount) { + if (!it->itVarArray) { + warn("%s: SameCount is ignored - the argument is not variable", name); + flags &= ~flSameCount; + } + if (old_arg) { + if (old_arg->argParent) + old_arg = old_arg->argParent; + if (old_arg->argSameCount) + old_arg = old_arg->argSameCount; + + if (!old_arg->argType->itVarArray) { + warn("%s: SameCount is ignored - adjacent argument is not variable", name); + flags &= ~flSameCount; + } + +#define SAMECOUNT_MASK akeBITS|akbSend|akbReturn|akbRequest|akbReply|akbUserArg|akbServerArg + if (akCheck(old_arg->argKind, SAMECOUNT_MASK) != + akCheck(arg->argKind, SAMECOUNT_MASK) || + old_arg->argCountInOut != arg->argCountInOut) { + warn("%s: SameCount is ignored - inconsistencies with the adjacent argument\n", name); + flags &= ~flSameCount; + } + arg->argSameCount = old_arg; + } + arg->argFlags = flags; + } + old_arg = arg; +} + +static ipc_flags_t +rtProcessCountInOutFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, boolean_t *what, string_t name) +{ + if (flags & flCountInOut) { + if (!akCheck(kind, akbReply)) { + warn("%s: CountInOut is ignored: argument must be Out\n", name); + flags &= ~flCountInOut; + } + else if (!it->itVarArray || !it->itInLine) { + warn("%s: CountInOut is ignored: argument isn't variable or in-line\n", name); + flags &= ~flCountInOut; + } + else + *what = TRUE; + } + return flags; +} + +static ipc_flags_t +rtProcessPhysicalCopyFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name) +{ + if (flags & flPhysicalCopy) { + if (it->itInLine) { + warn("%s: PhysicalCopy is ignored, argument copied inline anyway", name); + flags &= ~flPhysicalCopy; + } + if (it->itPortType) { + warn("%s: PhysicalCopy is ignored, it does not apply to ports and array of ports", name); + flags &= ~flPhysicalCopy; + } + } + return flags; +} + +static void +rtProcessRetCodeFlag(argument_t *thisarg) +{ + ipc_type_t *it = thisarg->argType; + ipc_flags_t flags = thisarg->argFlags; + string_t name = thisarg->argVarName; + routine_t *thisrout = thisarg->argRoutine; + + if (flags & flRetCode) { + if (!it->itInLine || !it->itStruct || + it->itSize != 32 || it->itNumber != 1) { + warn("%s: RetCode is ignored - the type doesn't match a MIG RetCode", name); + flags &= ~flRetCode; + } + else if (thisrout->rtKind != rkSimpleRoutine) { + fatal("%s: RetCode is allowed only for SimpleRoutines", name); + } + else if (thisrout->rtRetCArg != argNULL) { + warn("%s: RetCode is ignored - only one argument can be flagged as RetCode", name); + flags &= ~flRetCode; + } + else { + thisrout->rtRetCArg = thisarg; + } + thisarg->argFlags = flags; + } +} + +static ipc_flags_t +rtProcessOverwriteFlag(ipc_type_t *it, ipc_flags_t flags, arg_kind_t kind, string_t name) +{ + if (flags & flOverwrite) + if (it->itInLine || it->itMigInLine || + /* among In, Out, InOut, we want only the Out! */ + !akCheck(kind, akbReturn) || akCheck(kind, akbSend)) { + warn("%s: Overwrite is ignored - it must be Out AND Ool!", name); + flags &= ~flOverwrite; + } + return flags; +} + +static void +rtDetectKPDArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *string; + + if (IS_KERN_PROC_DATA(it)) { + if (akCheck(arg->argKind, akbSendBody)) { + arg->argKind = akRemFeature(arg->argKind, akbSendBody); + arg->argKind = akAddFeature(arg->argKind, akbSendKPD); + } + if (akCheck(arg->argKind, akbReturnBody)) { + arg->argKind = akRemFeature(arg->argKind, akbReturnBody); + arg->argKind = akAddFeature(arg->argKind, akbReturnKPD); + } + if (it->itInLine) { + string = "mach_msg_port_descriptor_t"; + arg->argKPD_Type = MACH_MSG_PORT_DESCRIPTOR; + } + else if (it->itPortType) { + string = "mach_msg_ool_ports_descriptor_t"; + arg->argKPD_Type = MACH_MSG_OOL_PORTS_DESCRIPTOR; + } + else { + string = "mach_msg_ool_descriptor_t"; + arg->argKPD_Type = MACH_MSG_OOL_DESCRIPTOR; + } + it->itKPDType = string; + } +} + +static void +rtAugmentArgKind(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + /* akbVariable means variable-sized inline */ + + if (IS_VARIABLE_SIZED_UNTYPED(it)) { + if (akCheckAll(arg->argKind, akbRequest|akbReply)) + error("%s: Inline variable-sized arguments can't be InOut", arg->argName); + arg->argKind = akAddFeature(arg->argKind, akbVariable); + } + if (IS_OPTIONAL_NATIVE(it)) + arg->argKind = akAddFeature(arg->argKind, akbVariable); + + /* + * Need to use a local variable in the following cases: + * 1) There is a translate-out function & the argument is being + * returned. We need to translate it before it hits the message. + * 2) There is a translate-in function & the argument is + * sent and returned. We need a local variable for its address. + * 3) There is a destructor function, which will be used + * (SendRcv and not ReturnSnd), and there is a translate-in + * function whose value must be saved for the destructor. + * 4) This is Complex KPD (array of KPD), and as such it has to + * be copied to a local array in input and output + * 5) Both poly and dealloc generate warnings compile time, because + * we attempt to take address of bit-field structure member + */ + + if ( + ((it->itOutTrans != strNULL) && akCheck(arg->argKind, akbReturnSnd)) || + ((it->itInTrans != strNULL) && akCheckAll(arg->argKind, akbSendRcv|akbReturnSnd)) || + ((it->itDestructor != strNULL) && akCheck(arg->argKind, akbSendRcv) && !akCheck(arg->argKind, akbReturnSnd) && (it->itInTrans != strNULL)) || + (IS_MULTIPLE_KPD(it)) || + ((akIdent(arg->argKind) == akePoly) && akCheck(arg->argKind, akbReturnSnd)) || + ((akIdent(arg->argKind) == akeDealloc) && akCheck(arg->argKind, akbReturnSnd)) + ) { + arg->argKind = akRemFeature(arg->argKind, akbReplyCopy); + arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); + } +} + +/* + * The Suffix allows to handle KPDs as normal data. + * it is used in InArgMsgField. + */ +static void +rtSuffixExtArg(argument_t *args) +{ + argument_t *arg; + char *subindex; + char string[MAX_STR_LEN]; + + for (arg = args; arg != argNULL; arg = arg->argNext) { + if (akCheck(arg->argKind, akbSendKPD | akbReturnKPD)) { + if (IS_MULTIPLE_KPD(arg->argType)) + subindex = "[0]"; + else + subindex = ""; + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + (void)sprintf(string, "%s.name", subindex); + break; + + case MACH_MSG_OOL_DESCRIPTOR: + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + (void)sprintf(string, "%s.address", subindex); + break; + + default: + error("Type of kernel processed data unknown\n"); + } + arg->argSuffix = strconcat(arg->argMsgField, string); + /* see above the list of VarNeeded cases */ + /* + * argCount has been removed from the VarNeeded list, + * because VarSize arrays have their Count in the untyped + * section of the message, and because it is not possible + * to move anything in-line/out-of-line + */ + } + else if (akIdent(arg->argKind) == akePoly && + akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) { + argument_t *par_arg = arg->argParent; + + if (IS_MULTIPLE_KPD(par_arg->argType)) + subindex = "[0]"; + else + subindex = ""; + switch (par_arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + (void)sprintf(string, "%s.disposition", subindex); + arg->argSuffix = strconcat(par_arg->argMsgField, string); + break; + + default: + error("Type of kernel processed data inconsistent\n"); + } + } + else if (akIdent(arg->argKind) == akeDealloc && + akCheck(arg->argParent->argKind, akbSendKPD | akbReturnKPD)) { + argument_t *par_arg = arg->argParent; + + if (IS_MULTIPLE_KPD(par_arg->argType)) + subindex = "[0]"; + else + subindex = ""; + switch (par_arg->argKPD_Type) { + + case MACH_MSG_OOL_DESCRIPTOR: + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + (void)sprintf(string, "%s.deallocate", subindex); + arg->argSuffix = strconcat(par_arg->argMsgField, string); + break; + + default: + error("Type of kernel processed data inconsistent\n"); + } + } + } +} + +/* arg->argType may be NULL in this function */ + +static void +rtCheckRoutineArg(routine_t *rt, argument_t *arg) +{ + switch (akIdent(arg->argKind)) { + + case akeRequestPort: + if (rt->rtRequestPort != argNULL) + warn("multiple RequestPort args in %s; %s won't be used", rt->rtName, rt->rtRequestPort->argName); + rt->rtRequestPort = arg; + break; + + case akeReplyPort: + if (rt->rtReplyPort != argNULL) + warn("multiple ReplyPort args in %s; %s won't be used", rt->rtName, rt->rtReplyPort->argName); + rt->rtReplyPort = arg; + break; + + case akeWaitTime: + if (rt->rtWaitTime != argNULL) + warn("multiple WaitTime/SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName); + rt->rtWaitTime = arg; + break; + + case akeSendTime: + if (rt->rtWaitTime != argNULL) { + if (akIdent(rt->rtWaitTime->argKind) == akeWaitTime) { + warn("SendTime type argument after a WaitTime in %s; SendTime %s won't be used", rt->rtName, arg->argName); + break; + } else { + warn("multiple SendTime type args in %s; %s won't be used", rt->rtName, rt->rtWaitTime->argName); + } + } + rt->rtWaitTime = arg; + break; + + case akeMsgOption: + if (rt->rtMsgOption != argNULL) + warn("multiple MsgOption args in %s; %s won't be used", rt->rtName, rt->rtMsgOption->argName); + rt->rtMsgOption = arg; + break; + + default: + break; + } +} + +/* arg->argType may be NULL in this function */ + +static void +rtSetArgDefaults(routine_t *rt, argument_t *arg) +{ + arg->argRoutine = rt; + if (arg->argVarName == strNULL) + arg->argVarName = arg->argName; + if (arg->argMsgField == strNULL) + switch(akIdent(arg->argKind)) { + + case akeRequestPort: + arg->argMsgField = "Head.msgh_request_port"; + break; + + case akeReplyPort: + arg->argMsgField = "Head.msgh_reply_port"; + break; + + case akeNdrCode: + arg->argMsgField = "NDR"; + break; + + case akeSecToken: + arg->argMsgField = "msgh_sender"; + break; + + case akeAuditToken: + arg->argMsgField = "msgh_audit"; + break; + + case akeContextToken: + arg->argMsgField = "msgh_context"; + break; + + case akeMsgSeqno: + arg->argMsgField = "msgh_seqno"; + break; + + case akeImplicit: + /* the field is set directly by Yacc */ + break; + + default: + arg->argMsgField = arg->argName; + break; + } + + if (arg->argTTName == strNULL) + arg->argTTName = strconcat(arg->argName, "Template"); + if (arg->argPadName == strNULL) + arg->argPadName = strconcat(arg->argName, "Pad"); + + /* + * The poly args for the request and reply ports have special defaults, + * because their msg-type-name values aren't stored in normal fields. + */ + + if ((rt->rtRequestPort != argNULL) && + (rt->rtRequestPort->argPoly == arg) && + (arg->argType != itNULL)) { + arg->argMsgField = "Head.msgh_bits"; + arg->argType->itInTrans = "MACH_MSGH_BITS_REQUEST"; + } + + if ((rt->rtReplyPort != argNULL) && + (rt->rtReplyPort->argPoly == arg) && + (arg->argType != itNULL)) { + arg->argMsgField = "Head.msgh_bits"; + arg->argType->itInTrans = "MACH_MSGH_BITS_REPLY"; + } +} + +static void +rtAddCountArg(argument_t *arg) +{ + argument_t *count, *master; + ipc_type_t *it = arg->argType; + + count = argAlloc(); + + if (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray) { + count->argName = strconcat(arg->argName, "Subs"); + count->argType = itMakeSubCountType(it->itKPD_Number, it->itVarArray, arg->argVarName); + count->argKind = akeSubCount; + arg->argSubCount = count; + } + else { + count->argName = strconcat(arg->argName, "Cnt"); + count->argType = itMakeCountType(); + count->argKind = akeCount; + arg->argCount = count; + if (arg->argParent != argNULL) { + /* this is the case where we are at the second level of recursion: + we want the Parent to access it through argCount */ + arg->argParent->argCount = count; + } + } + master = (arg->argParent != argNULL) ? arg->argParent : arg; + if (IS_MULTIPLE_KPD(master->argType)) + count->argMultiplier = 1; + else + count->argMultiplier = it->itElement->itNumber; + count->argParent = arg; + count->argNext = arg->argNext; + arg->argNext = count; + + if (arg->argType->itString) { + /* C String gets no Count argument on either side, but are still in the msg */ + count->argKind = akAddFeature(count->argKind, akCheck(arg->argKind, akbSend) ? akbSendRcv : akbReturnRcv); + count->argVarName = (char *)0; + } + else { + /* + * Count arguments have to be present on the message body (NDR encoded) + * akbVariable has to be turned down, has it foul the algorithm + * for detecting the in-line variable sized arrays + */ + count->argKind |= akAddFeature(akbUserArg|akbServerArg, (arg->argKind) & ~akeBITS); + count->argKind = akRemFeature(count->argKind, akbVariable|akbVarNeeded); + if (IS_VARIABLE_SIZED_UNTYPED(arg->argType)) + /* + * Count arguments for the above types are explicitly declared + * BEFORE the variable (with those bits, they would come afterwards) + */ + count->argKind = akRemFeature(count->argKind, akbRequest|akbReply); + } +} + +static void +rtAddCountInOutArg(argument_t *arg) +{ + argument_t *count; + + /* + * The user sees a single count variable. However, to get the + * count passed from user to server for variable-sized inline OUT + * arrays, we need two count arguments internally. This is + * because the count value lives in different message fields (and + * is scaled differently) in the request and reply messages. + * + * The two variables have the same name to simplify code generation. + * + * This variable has a null argParent field because it has akbRequest. + * For example, see rtCheckVariable. + */ + + count = argAlloc(); + count->argName = strconcat(arg->argName, "Cnt"); + count->argType = itMakeCountType(); + count->argParent = argNULL; + count->argNext = arg->argNext; + arg->argNext = count; + (count->argCInOut = arg->argCount)->argCInOut = count; + count->argKind = akCountInOut; +} + +static void +rtAddPolyArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + argument_t *poly; + arg_kind_t akbsend, akbreturn; + + poly = argAlloc(); + poly->argName = strconcat(arg->argName, "Poly"); + poly->argType = itMakePolyType(); + poly->argParent = arg; + poly->argNext = arg->argNext; + arg->argNext = poly; + arg->argPoly = poly; + + /* + * akbsend is bits added if the arg is In; + * akbreturn is bits added if the arg is Out. + * The mysterious business with KernelServer subsystems: + * when packing Out arguments, they use OutNames instead + * of InNames, and the OutName determines if they are poly-in + * as well as poly-out. + */ + + akbsend = akbSend; + akbreturn = akbReturn; + + if (it->itInName == MACH_MSG_TYPE_POLYMORPHIC) { + akbsend |= akbUserArg|akbSendSnd; + if (!IsKernelServer) + akbreturn |= akbServerArg|akbReturnSnd; + } + if (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC) { + akbsend |= akbServerArg|akbSendRcv; + akbreturn |= akbUserArg|akbReturnRcv; + if (IsKernelServer) + akbreturn |= akbServerArg|akbReturnSnd; + } + + poly->argKind = akPoly; + if (akCheck(arg->argKind, akbSend)) + poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbsend)); + if (akCheck(arg->argKind, akbReturn)) + poly->argKind = akAddFeature(poly->argKind, akCheck(arg->argKind, akbreturn)); +} + +static void +rtAddDeallocArg(argument_t *arg) +{ + argument_t *dealloc; + + dealloc = argAlloc(); + dealloc->argName = strconcat(arg->argName, "Dealloc"); + dealloc->argType = itMakeDeallocType(); + dealloc->argParent = arg; + dealloc->argNext = arg->argNext; + arg->argNext = dealloc; + arg->argDealloc = dealloc; + + /* + * Dealloc flag can only be associated to KPDs. + */ + + dealloc->argKind = akeDealloc; + if (akCheck(arg->argKind, akbSend)) + dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbUserArg|akbSend|akbSendSnd)); + if (akCheck(arg->argKind, akbReturn)) { + dealloc->argKind = akAddFeature(dealloc->argKind, akCheck(arg->argKind, akbServerArg|akbReturn|akbReturnSnd)); + dealloc->argByReferenceServer = TRUE; + } +} + +static void +rtCheckRoutineArgs(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + rtDefaultArgKind(rt, arg); + rtCheckRoutineArg(rt, arg); + + /* need to set argTTName before adding implicit args */ + rtSetArgDefaults(rt, arg); + + /* the arg may not have a type (if there was some error in parsing it), + in which case we don't want to do these steps. */ + + if (it != itNULL) { + arg->argFlags = rtProcessDeallocFlag(it, arg->argFlags, arg->argKind, &arg->argDeallocate, arg->argVarName); + arg->argFlags = rtProcessCountInOutFlag(it, arg->argFlags, arg->argKind, &arg->argCountInOut, arg->argVarName); + rtProcessSameCountFlag(arg); + arg->argFlags = rtProcessPhysicalCopyFlag(it, arg->argFlags, arg->argKind, arg->argVarName); + rtProcessRetCodeFlag(arg); + arg->argFlags = rtProcessOverwriteFlag(it, arg->argFlags, arg->argKind, arg->argVarName); + rtAugmentArgKind(arg); + + /* args added here will get processed in later iterations */ + /* order of args is 'arg poly countinout count dealloc' */ + + if (arg->argDeallocate == d_MAYBE) + rtAddDeallocArg(arg); + if (it->itVarArray || (IS_MULTIPLE_KPD(it) && it->itElement->itVarArray)) + rtAddCountArg(arg); + if (arg->argCountInOut) + rtAddCountInOutArg(arg); + if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) + rtAddPolyArg(arg); + /* + * Detects whether the arg has to become part of the + * Kernel Processed Data section; if yes, define the proper + * itUserKPDType, itServerKPDType + */ + rtDetectKPDArg(arg); + } + } +} + +boolean_t +rtCheckTrailerType(argument_t *arg) +{ + if (akIdent(arg->argKind) == akeSecToken || + akIdent(arg->argKind) == akeAuditToken || + akIdent(arg->argKind) == akeContextToken ) + itCheckTokenType(arg->argVarName, arg->argType); + + if (akIdent(arg->argKind) == akeMsgSeqno) + itCheckIntType(arg->argVarName, arg->argType); + /* + * if the built-in are not used, we cannot match + * the type/size of the desciption provided by the user + * with the one defined in message.h. + */ + + return TRUE; +} + +static void +rtCheckArgTypes(routine_t *rt) +{ + if (rt->rtRequestPort == argNULL) + error("%s %s doesn't have a server port argument", rtRoutineKindToStr(rt->rtKind), rt->rtName); + + if ((rt->rtRequestPort != argNULL) && + (rt->rtRequestPort->argType != itNULL)) + itCheckRequestPortType(rt->rtRequestPort->argName, rt->rtRequestPort->argType); + + if ((rt->rtReplyPort != argNULL) && + (rt->rtReplyPort->argType != itNULL)) + itCheckReplyPortType(rt->rtReplyPort->argName, rt->rtReplyPort->argType); + + if ((rt->rtWaitTime != argNULL) && + (rt->rtWaitTime->argType != itNULL)) + itCheckIntType(rt->rtWaitTime->argName, rt->rtWaitTime->argType); + + if ((rt->rtMsgOption != argNULL) && + (rt->rtMsgOption->argType != itNULL)) + itCheckIntType(rt->rtMsgOption->argName, rt->rtMsgOption->argType); + + if ((IsKernelServer && rt->rtServerImpl) || + (IsKernelUser && rt->rtUserImpl)) + fatal("Implicit data is not supported in the KernelUser and KernelServer modes"); + /* rtCheckTrailerType will hit a fatal() if something goes wrong */ + if (rt->rtServerImpl) + rtCheckMaskFunction(rt->rtArgs, akbServerImplicit, rtCheckTrailerType); + if (rt->rtUserImpl) + rtCheckMaskFunction(rt->rtArgs, akbUserImplicit, rtCheckTrailerType); +} + +/* + * Check for arguments which are missing seemingly needed functions. + * We make this check here instead of in itCheckDecl, because here + * we can take into account what kind of argument the type is + * being used with. + * + * These are warnings, not hard errors, because mig will generate + * reasonable code in any case. The generated code will work fine + * if the ServerType and TransType are really the same, even though + * they have different names. + */ + +static void +rtCheckArgTrans(routine_t *rt) +{ + argument_t *arg; + + /* the arg may not have a type (if there was some error in parsing it) */ + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if ((it != itNULL) && !streql(it->itServerType, it->itTransType)) { + if (akCheck(arg->argKind, akbSendRcv) && (it->itInTrans == strNULL)) + warn("%s: argument has no in-translation function", arg->argName); + + if (akCheck(arg->argKind, akbReturnSnd) && (it->itOutTrans == strNULL)) + warn("%s: argument has no out-translation function", arg->argName); + } + } +} + +/* + * Adds an implicit return-code argument. It exists in the reply message, + * where it is the first piece of data (After the NDR format label).. + */ + +static void +rtAddRetCode(routine_t *rt) +{ + argument_t *arg = argAlloc(); + + arg->argName = "RetCode"; + arg->argType = itRetCodeType; + arg->argKind = akRetCode; + rt->rtRetCode = arg; + + arg->argNext = rt->rtArgs; + rt->rtArgs = arg; +} + +/* + * Process the Return Code. + * The MIG protocol says that RetCode != 0 are only sent through + * mig_reply_error_t structures. Therefore, there is no need + * for reserving a RetCode in a complex Reply message. + */ +static void +rtProcessRetCode(routine_t *rt) +{ + if (!rt->rtOneWay && !rt->rtSimpleReply) { + argument_t *arg = rt->rtRetCode; + + arg->argKind = akRemFeature(arg->argKind, akbReply); + /* we want the RetCode to be a local variable instead */ + arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); + } + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + argument_t *arg = rt->rtRetCArg; + + arg->argKind = akeRetCode|akbUserArg|akbServerArg|akbSendRcv; + } +} + +/* + * Adds an implicit NDR argument. It exists in the reply message, + * where it is the first piece of data. + */ + +static void +rtAddNdrCode(routine_t *rt) +{ + argument_t *arg = argAlloc(); + + arg->argName = "NDR_record"; + arg->argType = itNdrCodeType; + arg->argKind = akeNdrCode; + rt->rtNdrCode = arg; + + /* add at beginning, so ndr-code is first in the reply message */ + arg->argNext = rt->rtArgs; + rt->rtArgs = arg; +} + +/* + * Process the NDR Code. + * We stick a NDR format label iff there is untyped data + */ +static void +rtProcessNdrCode(routine_t *rt) +{ + argument_t *ndr = rt->rtNdrCode; + argument_t *arg; + boolean_t found; + + /* akbSendSnd|akbSendBody initialize the NDR format label */ +#define ndr_send akbRequest|akbSend|akbSendSnd|akbSendBody + /* akbReplyInit initializes the NDR format label */ +#define ndr_rcv akbReply|akbReplyInit|akbReturn|akbReturnBody + + ndr->argKind = akAddFeature(ndr->argKind, ndr_send|ndr_rcv); + + for (found = FALSE, arg = ndr->argNext; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbSendRcv|akbSendBody) && + !akCheck(arg->argKind, akbServerImplicit) && !arg->argType->itPortType && + (!arg->argParent || akIdent(arg->argKind) == akeCount || + akIdent(arg->argKind) == akeCountInOut)) { + arg->argKind = akAddFeature(arg->argKind, akbSendNdr); + found = TRUE; + } + if (!found) + ndr->argKind = akRemFeature(ndr->argKind, ndr_send); + + found = FALSE; + if (!rt->rtOneWay) + for (arg = ndr->argNext; arg != argNULL; arg = arg->argNext) + if ((arg == rt->rtRetCode && akCheck(arg->argKind, akbReply)) || + (arg != rt->rtRetCode && + akCheck(arg->argKind, akbReturnRcv|akbReturnBody) && + !akCheck(arg->argKind, akbUserImplicit) && !arg->argType->itPortType && + (!arg->argParent || akIdent(arg->argKind) == akeCount || + akIdent(arg->argKind) == akeCountInOut))) { + arg->argKind = akAddFeature(arg->argKind, akbReturnNdr); + found = TRUE; + } + if (!found && !akCheck(rt->rtRetCode->argKind, akbReply)) + ndr->argKind = akRemFeature(ndr->argKind, ndr_rcv); +} + +/* + * Adds a dummy WaitTime argument to the function. + * This argument doesn't show up in any C argument lists; + * it implements the global WaitTime statement. + */ + +static void +rtAddWaitTime(routine_t *rt, identifier_t name, arg_kind_t kind) +{ + argument_t *arg = argAlloc(); + argument_t **loc; + + arg->argName = "dummy WaitTime arg"; + arg->argVarName = name; + arg->argType = itWaitTimeType; + arg->argKind = kind; + rt->rtWaitTime = arg; + + /* add wait-time after msg-option, if possible */ + + if (rt->rtMsgOption != argNULL) + loc = &rt->rtMsgOption->argNext; + else + loc = &rt->rtArgs; + + arg->argNext = *loc; + *loc = arg; + + rtSetArgDefaults(rt, arg); +} + +/* + * Adds a dummy MsgOption argument to the function. + * This argument doesn't show up in any C argument lists; + * it implements the global MsgOption statement. + */ + +static void +rtAddMsgOption(routine_t *rt, identifier_t name) +{ + argument_t *arg = argAlloc(); + argument_t **loc; + + arg->argName = "dummy MsgOption arg"; + arg->argVarName = name; + arg->argType = itMsgOptionType; + arg->argKind = akeMsgOption; + rt->rtMsgOption = arg; + + /* add msg-option after msg-seqno */ + + loc = &rt->rtArgs; + + arg->argNext = *loc; + *loc = arg; + + rtSetArgDefaults(rt, arg); +} + +/* + * Process the MsgOption Code. + * We must add the information to post a receive with the right + * Trailer options. + */ +static void +rtProcessMsgOption(routine_t *rt) +{ + argument_t *msgop = rt->rtMsgOption; + argument_t *arg; + boolean_t sectoken = FALSE; + boolean_t audittoken = FALSE; + boolean_t contexttoken = FALSE; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, akbReturn|akbUserImplicit)) { + if (akIdent(arg->argKind) == akeSecToken) + sectoken = TRUE; + else if (akIdent(arg->argKind) == akeAuditToken) + audittoken = TRUE; + else if (akIdent(arg->argKind) == akeContextToken) + contexttoken = TRUE; + } + + if (contexttoken == TRUE) + msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX)"); + else if (audittoken == TRUE) + msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT)"); + else if (sectoken == TRUE) + msgop->argVarName = strconcat(msgop->argVarName, "|MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_SENDER)"); + /* other implicit data received by the user will be handled here */ +} + +static void +rtProcessUseSpecialReplyPort(routine_t *rt) +{ + if (IsKernelUser || IsKernelServer) { + fatal("UseSpecialReplyPort option cannot be used with KernelUser / KernelServer\n"); + } + rt->rtMsgOption->argVarName = strconcat(rt->rtMsgOption->argVarName, "|__MigSpecialReplyPortMsgOption"); +} + +/* + * Adds a dummy reply port argument to the function. + */ + +static void +rtAddDummyReplyPort(routine_t *rt, ipc_type_t *type) +{ + argument_t *arg = argAlloc(); + argument_t **loc; + + arg->argName = "dummy ReplyPort arg"; + arg->argVarName = "dummy ReplyPort arg"; + arg->argType = type; + arg->argKind = akeReplyPort; + rt->rtReplyPort = arg; + + /* add the reply port after the request port */ + + if (rt->rtRequestPort != argNULL) + loc = &rt->rtRequestPort->argNext; + else + loc = &rt->rtArgs; + + arg->argNext = *loc; + *loc = arg; + + rtSetArgDefaults(rt, arg); +} + + +/* + * At least one overwrite keyword has been detected: + * we tag all the OOL entries (ports + data) with + * akbOverwrite which will tell us that we have to + * fill a KPD entry in the message-template + */ +static void +rtCheckOverwrite(routine_t *rt) +{ + argument_t *arg; + int howmany = rt->rtOverwrite; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (akCheck(arg->argKind, akbReturnKPD) && !it->itInLine) { + /* among OUT args, we want OOL, OOL ports and MigInLine */ + arg->argKind = akAddFeature(arg->argKind, akbOverwrite); + if (arg->argFlags & flOverwrite) + howmany--; + if (!howmany) + return; + } + } +} + +/* + * Initializes argRequestPos, argReplyPos, rtMaxRequestPos, rtMaxReplyPos, + * rtNumRequestVar, rtNumReplyVar, and adds akbVarNeeded to those arguments + * that need it because of variable-sized inline considerations. + * + * argRequestPos and argReplyPos get -1 if the value shouldn't be used. + */ +static void +rtCheckVariable(routine_t *rt) +{ + argument_t *arg; + int NumRequestVar = 0; + int NumReplyVar = 0; + int MaxRequestPos = 0; + int MaxReplyPos = 0; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + argument_t *parent = arg->argParent; + + /* + * We skip KPDs. We have to make sure that the KPDs count + * present in the message body follow the RequestPos/ReplyPos logic + * The rest of the parameters are defaulted to have + * Arg{Request, Reply}Pos = 0 + */ + if (parent == argNULL || akCheck(parent->argKind, akbSendKPD|akbReturnKPD)) { + if (akCheckAll(arg->argKind, akbSend|akbSendBody)) { + arg->argRequestPos = NumRequestVar; + MaxRequestPos = NumRequestVar; + if (akCheck(arg->argKind, akbVariable)) + NumRequestVar++; + } + if (akCheckAll(arg->argKind, akbReturn|akbReturnBody)) { + arg->argReplyPos = NumReplyVar; + MaxReplyPos = NumReplyVar; + if (akCheck(arg->argKind, akbVariable)) + NumReplyVar++; + } + } + else { + arg->argRequestPos = parent->argRequestPos; + arg->argReplyPos = parent->argReplyPos; + } + /* + printf("Var %s Kind %x RequestPos %d\n", arg->argVarName, arg->argKind, arg->argRequestPos); + printf("* Var %s Kind %x ReplyPos %d\n", arg->argVarName, arg->argKind, arg->argReplyPos); + */ + + /* Out variables that follow a variable-sized field + need VarNeeded or ReplyCopy; they can't be stored + directly into the reply message. */ + + if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody) && + !akCheck(arg->argKind, akbReplyCopy|akbVarNeeded) && + (arg->argReplyPos > 0)) + arg->argKind = akAddFeature(arg->argKind, akbVarNeeded); + } + + rt->rtNumRequestVar = NumRequestVar; + rt->rtNumReplyVar = NumReplyVar; + rt->rtMaxRequestPos = MaxRequestPos; + rt->rtMaxReplyPos = MaxReplyPos; +} + +/* + * Adds akbDestroy where needed. + */ + +static void +rtCheckDestroy(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if(akCheck(arg->argKind, akbSendRcv) && + !akCheck(arg->argKind, akbReturnSnd) && + (it->itDestructor != strNULL || IS_MIG_INLINE_EMUL(it))) { + arg->argKind = akAddFeature(arg->argKind, akbDestroy); + } + if (argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && + arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR && + (arg->argFlags & flAuto)) + arg->argKind = akAddFeature(arg->argKind, akbDestroy); + } +} + +/* + * Sets ByReferenceUser and ByReferenceServer. + */ + +static void +rtAddByReference(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (akCheck(arg->argKind, akbReturnRcv) && it->itStruct) { + arg->argByReferenceUser = TRUE; + + /* + * A CountInOut arg itself is not akbReturnRcv, + * so we need to set argByReferenceUser specially. + */ + + if (arg->argCInOut != argNULL) + arg->argCInOut->argByReferenceUser = TRUE; + } + + if ((akCheck(arg->argKind, akbReturnSnd) || + (akCheck(arg->argKind, akbServerImplicit) && + akCheck(arg->argKind, akbReturnRcv) && + akCheck(arg->argKind, akbSendRcv))) + && it->itStruct) { + arg->argByReferenceServer = TRUE; + } + } +} + +/* + * This procedure can be executed only when all the akb* and ake* have + * been set properly (when rtAddCountArg is executed, akbVarNeeded + * might not be set yet - see rtCheckVariable) + */ +void +rtAddSameCount(routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (arg->argFlags & flSameCount) { + ipc_type_t *it = arg->argType; + argument_t *tmp_count; + argument_t *my_count = arg->argCount; + argument_t *ref_count = arg->argSameCount->argCount; + + tmp_count = argAlloc(); + *tmp_count = *ref_count; + /* + * if our count is a akbVarNeeded, we need to copy this + * attribute to the master count! + */ + tmp_count->argKind = akeSameCount; + ref_count->argKind = akAddFeature(ref_count->argKind, akCheck(my_count->argKind, akbVarNeeded)); + tmp_count->argKind = akAddFeature(tmp_count->argKind, akCheck(my_count->argKind, akbVarNeeded)); + tmp_count->argNext = my_count->argNext; + tmp_count->argMultiplier = my_count->argMultiplier; + tmp_count->argType = my_count->argType; + tmp_count->argParent = arg; + /* we don't need more */ + arg->argCount = tmp_count; + arg->argNext = tmp_count; + /* for these args, Cnt is not akbRequest, and therefore size is embedded */ + if (IS_VARIABLE_SIZED_UNTYPED(it)) + it->itMinTypeSize = 0; + tmp_count->argType->itMinTypeSize = 0; + tmp_count->argType->itTypeSize = 0; + } +} + +void +rtCheckRoutine(routine_t *rt) +{ + /* Initialize random fields. */ + + rt->rtErrorName = ErrorProc; + rt->rtOneWay = (rt->rtKind == rkSimpleRoutine); + rt->rtServerName = strconcat(ServerPrefix, rt->rtName); + rt->rtUserName = strconcat(UserPrefix, rt->rtName); + rt->rtUseSpecialReplyPort = UseSpecialReplyPort && !rt->rtOneWay; + rt->rtConsumeOnSendError = ConsumeOnSendError; + + /* Add implicit arguments. */ + + rtAddRetCode(rt); + rtAddNdrCode(rt); + + /* Check out the arguments and their types. Add count, poly + implicit args. Any arguments added after rtCheckRoutineArgs + should have rtSetArgDefaults called on them. */ + + rtCheckRoutineArgs(rt); + + /* Add dummy WaitTime and MsgOption arguments, if the routine + doesn't have its own args and the user specified global values. */ + + if (rt->rtReplyPort == argNULL) { + if (rt->rtOneWay) + rtAddDummyReplyPort(rt, itZeroReplyPortType); + else + rtAddDummyReplyPort(rt, itRealReplyPortType); + } else if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) { + /* If an explicit ReplyPort is used, we can't assume it will be the SRP */ + rt->rtUseSpecialReplyPort = FALSE; + } + if (rt->rtMsgOption == argNULL) { + if (MsgOption == strNULL) + rtAddMsgOption(rt, "MACH_MSG_OPTION_NONE"); + else + rtAddMsgOption(rt, MsgOption); + } + if (rt->rtWaitTime == argNULL) { + if (WaitTime != strNULL) + rtAddWaitTime(rt, WaitTime, akeWaitTime); + else if (SendTime != strNULL) + rtAddWaitTime(rt, SendTime, akeSendTime); + } + if (rt->rtWaitTime && rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) { + warn("%s %s specifies a SendTime/WaitTime which may leak resources, " + "adopt \"ConsumeOnSendError Timeout\"", + rtRoutineKindToStr(rt->rtKind), rt->rtName); + } + + + /* Now that all the arguments are in place, do more checking. */ + + rtCheckArgTypes(rt); + rtCheckArgTrans(rt); + + if (rt->rtOneWay) { + if (rtCheckMask(rt->rtArgs, akbReturn) || rt->rtUserImpl) + error("%s %s has OUT argument", rtRoutineKindToStr(rt->rtKind), rt->rtName); + } + + /* If there were any errors, don't bother calculating more info + that is only used in code generation anyway. Therefore, + the following functions don't have to worry about null types. */ + + if (mig_errors > 0) + fatal("%d errors found. Abort.\n", mig_errors); + + rt->rtServerImpl = rtCountMask(rt->rtArgs, akbServerImplicit); + rt->rtUserImpl = rtCountMask(rt->rtArgs, akbUserImplicit); + /* + * ASSUMPTION: + * kernel cannot change a message from simple to complex, + * therefore SimpleSendReply and SimpleRcvReply become SimpleReply + */ + rtCheckSimple(rt->rtArgs, akbRequest, &rt->rtSimpleRequest); + rtCheckSimple(rt->rtArgs, akbReply, &rt->rtSimpleReply); + + rt->rtRequestKPDs = rtCountKPDs(rt->rtArgs, akbSendKPD); + rt->rtReplyKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD); + /* + * Determine how many overwrite parameters we have: + * # of Overwrite args -> rt->rtOverwrite + * flOverwrite -> the arg has to be overwritten + * akbOverwrite -> the arg has to be declared in the message-template + * (only as a placeholder if !flOverwrite). + */ + if ((rt->rtOverwrite = rtCountFlags(rt->rtArgs, flOverwrite))) { + rtCheckOverwrite(rt); + rt->rtOverwriteKPDs = rtCountKPDs(rt->rtArgs, akbReturnKPD|akbOverwrite); + if (IsKernelUser) + fatal("Overwrite option(s) do not match with the KernelUser personality\n"); + } + + rtCheckFit(rt, akbRequest, &rt->rtRequestFits, &rt->rtRequestUsedLimit, &rt->rtRequestSizeKnown); + rtCheckFit(rt, akbReply, &rt->rtReplyFits, &rt->rtReplyUsedLimit, &rt->rtReplySizeKnown); + + rtCheckVariable(rt); + rtCheckDestroy(rt); + rtAddByReference(rt); + rtSuffixExtArg(rt->rtArgs); + rtAddSameCount(rt); + rtProcessRetCode(rt); + rtProcessNdrCode(rt); + if (rt->rtUserImpl) + rtProcessMsgOption(rt); + if (rt->rtUseSpecialReplyPort) + rtProcessUseSpecialReplyPort(rt); + + rt->rtNoReplyArgs = !rtCheckMask(rt->rtArgs, akbReturnSnd); + + if (UseEventLogger) + /* some more info's are needed for Event logging/Stats */ + rtFindHowMany(rt); +} + +void +rtMinRequestSize(FILE *file, routine_t *rt, char *str) +{ + fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); + rtSizeDelta(file, akbRequest, rt); + fprintf(file, ")"); +} + +void +rtMinReplySize(FILE *file, routine_t *rt, char *str) +{ + fprintf(file, "(mach_msg_size_t)(sizeof(%s)", str); + rtSizeDelta(file, akbReply, rt); + fprintf(file, ")"); +} + +static void +rtSizeDelta(FILE *file, u_int mask, routine_t *rt) +{ + argument_t *arg; + u_int min_size = sizeof(mach_msg_header_t); + u_int max_size; + boolean_t output = FALSE; + + if (!rt->rtSimpleRequest) + machine_alignment(min_size, sizeof(mach_msg_body_t)); + max_size = min_size; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, mask)) { + ipc_type_t *it = arg->argType; + + machine_alignment(min_size, it->itMinTypeSize); + machine_alignment(max_size, it->itMinTypeSize); + + if (IS_VARIABLE_SIZED_UNTYPED(it)) { + machine_alignment(max_size, it->itTypeSize); + max_size += it->itPadSize; + } + if (IS_OPTIONAL_NATIVE(it)) { + if (output) + fprintf(file, " + "); + else { + output = TRUE; + fprintf(file, " - ("); + } + fprintf(file, "_WALIGNSZ_(%s)", it->itUserType); + } + } + if (min_size != max_size) { + if (output) + fprintf(file, " + "); + else + fprintf(file, " - "); + fprintf(file, "%d", max_size - min_size); + } + if (output) + fprintf(file, ")"); +} + diff --git a/bootstrap_cmds/migcom.tproj/routine.h b/bootstrap_cmds/migcom.tproj/routine.h new file mode 100644 index 0000000..1b63a03 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/routine.h @@ -0,0 +1,549 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include + +#ifndef _ROUTINE_H +#define _ROUTINE_H + +#include "type.h" +#include +#include +#include +#include + +/* base kind arg */ +#define akeNone (0) +#define akeNormal (1) /* a normal, user-defined argument */ +#define akeRequestPort (2) /* pointed at by rtRequestPort */ +#define akeWaitTime (3) /* pointed at by rtWaitTime */ +#define akeReplyPort (4) /* pointed at by rtReplyPort */ +#define akeMsgOption (5) /* pointed at by rtMsgOption */ +#define akeMsgSeqno (6) /* pointed at by rtMsgSeqno */ +#define akeRetCode (7) /* pointed at by rtRetCode */ +#define akeNdrCode (8) /* pointed at by rtNdrCode */ +#define akeCount (9) /* a count arg for argParent */ +#define akePoly (10) /* a poly arg for argParent */ +#define akeDealloc (11) /* a deallocate arg for argParent */ +#define akeCountInOut (12) /* a count-in-out arg */ +#define akeSameCount (13) /* a samecount case: in fact, a no count! */ +#define akeSubCount (14) /* a array of array case: subordinate arrays count */ +#define akeImplicit (15) /* an implicit argument, from the trailer */ +#define akeSecToken (16) /* an argument from the trailer: the security token */ +#define akeAuditToken (17) /* an argument from the trailer: the audit token */ +#define akeContextToken (18) /* an argument from the trailer: the context token */ +#define akeSendTime (19) /* pointed at by rtWaitTime */ + +#define akeBITS (0x0000003f) +#define akbRequest (0x00000040) /* has a msg_type in request */ +#define akbReply (0x00000080) /* has a msg_type in reply */ +#define akbUserArg (0x00000100) /* an arg on user-side */ +#define akbServerArg (0x00000200) /* an arg on server-side */ +#define akbSend (0x00000400) /* value carried in request */ +#define akbSendBody (0x00000800) /* value carried in request body */ +#define akbSendSnd (0x00001000) /* value stuffed into request */ +#define akbSendRcv (0x00002000) /* value grabbed from request */ +#define akbReturn (0x00004000) /* value carried in reply */ +#define akbReturnBody (0x00008000) /* value carried in reply body */ +#define akbReturnSnd (0x00010000) /* value stuffed into reply */ +#define akbReturnRcv (0x00020000) /* value grabbed from reply */ +#define akbReturnNdr (0x00040000) /* needs NDR conversion in reply */ +#define akbReplyInit (0x00080000) /* reply value doesn't come from target routine */ +#define akbReplyCopy (0x00200000) /* copy reply value from request */ +#define akbVarNeeded (0x00400000) /* may need local var in server */ +#define akbDestroy (0x00800000) /* call destructor function */ +#define akbVariable (0x01000000) /* variable size inline data */ +#define akbSendNdr (0x04000000) /* needs NDR conversion in request */ +#define akbSendKPD (0x08000000) /* the arg is sent in the Kernel Processed Data + section of the Request message */ +#define akbReturnKPD (0x10000000) /* the arg is sent in the Kernel Processed Data + section of the Reply message */ +#define akbUserImplicit (0x20000000) /* the arg is Impl */ +#define akbServerImplicit (0x40000000) /* the arg is Impl */ +#define akbOverwrite (0x80000000) +/* be careful, there aren't many bits left */ + +typedef u_int arg_kind_t; + +/* + * akbRequest means msg_type/data fields are allocated in the request + * msg. akbReply means msg_type/data fields are allocated in the + * reply msg. These bits * control msg structure declarations packing, + * and checking of mach_msg_type_t fields. + * + * akbUserArg means this argument is an argument to the user-side stub. + * akbServerArg means this argument is an argument to + * the server procedure called by the server-side stub. + * + * The akbSend* and akbReturn* bits control packing/extracting values + * in the request and reply messages. + * + * akbSend means the argument's value is carried in the request msg. + * akbSendBody implies akbSend; the value is carried in the msg body. + * akbSendKPD is the equivalent of akbSendBody for Kernel Processed Data. + * akbSendSnd implies akbSend; the value is stuffed into the request. + * akbSendRcv implies akbSend; the value is pulled out of the request. + * + * akbReturn, akbReturnBody, akbReturnSnd, akbReturnRcv are defined + * similarly but apply to the reply message. + * + * User-side code generation (header.c, user.c) and associated code + * should use akbSendSnd and akbReturnRcv, but not akbSendRcv and + * akbReturnSnd. Server-side code generation (server.c) is reversed. + * Code generation should use the more specific akb{Send,Return}{Snd,Rcv} + * bits when possible, instead of akb{Send,Return}. + * + * Note that akRetCode and akReturn lack any Return bits, although + * there is a value in the msg. These guys are packed/unpacked + * with special code, unlike other arguments. + * + * akbReplyInit implies akbReply. It means the server-side stub + * should initialize the field, because its value does not come + * from the execution of the target routine: the setting of the + * NDR record is the sole example (at the moment) of use of this flag. + * + * akbVariable means the argument has variable-sized inline data. + * It isn't currently used for code generation, but routine.c + * does use it internally. It is added in rtAugmentArgKind. + * + * akbReplyCopy and akbVarNeeded help control code generation in the + * server-side stub. The preferred method of handling data in the + * server-side stub avoids copying into/out-of local variables. In + * arguments get passed directly to the server proc from the request msg. + * Out arguments get stuffed directly into the reply msg by the server proc. + * For InOut arguments, the server proc gets the address of the data in + * the request msg, and the resulting data gets copied to the reply msg. + * Some arguments need a local variable in the server-side stub. The + * code extracts the data from the request msg into the variable, and + * stuff the reply msg from the variable. + * + * akbReplyCopy implies akbReply. It means the data should get copied + * from the request msg to the reply msg after the server proc is called. + * It is only used by akInOut. akTid doesn't need it because the tid + * data in the reply msg is initialized in the server demux function. + * + * akbVarNeeded means the argument needs a local variable in the + * server-side stub. It is added in rtAugmentArgKind and + * rtCheckVariable. An argument shouldn't have all three of + * akbReturnSnd, akbVarNeeded and akbReplyCopy, because this indicates + * the reply msg should be stuffed both ways. + * + * akbDestroy helps control code generation in the server-side stub. + * It means this argument has a destructor function which should be called. + * + * akbOverwrite is used to identify the arguments that have to put an entry in + * the scatter list (the message-template used by the User stub to specify + * where the out-of-line data sent by server has to land). + * + * akbUserImplicit (akbServerImplicit) is used to mark the arguments that + * correspond to implicit data (data generated by the kernel and inserted in + * the trailer). + * + * Header file generation (header.c) uses: + * akbUserArg + * + * User stub generation (user.c) uses: + * akbUserArg, akbRequest, akbReply, akbSendSnd, + * akbSendBody, akbSendKPD, akbReturnRcv, akbOverwrite, akbUserImplicit + * + * Server stub generation (server.c) uses: + * akbServerArg, akbRequest, akbReply, akbSendRcv, akbReturnSnd, + * akbReplyCopy, akbVarNeeded, akbSendBody, akbServerImplicit + * + * + * During code generation, the routine, argument, and type data structures + * are read-only. The code generation functions' output is their only + * side-effect. + * + * + * Style note: + * Code can use logical operators (|, &, ~) on akb values. + * ak values should be manipulated with the ak functions. + */ + +/* various useful combinations */ + +#define akbNone (0) +#define akbAll (~akbNone) +#define akbAllBits (~akeBITS) + +#define akbSendBits (akbSend|akbSendBody|akbSendSnd|akbSendRcv) +#define akbReturnBits (akbReturn|akbReturnBody|akbReturnSnd|akbReturnRcv) +#define akbSendReturnBits (akbSendBits|akbReturnBits) + +#define akNone akeNone + +#define akIn akAddFeature(akeNormal, \ + akbUserArg|akbServerArg|akbRequest|akbSendBits) + +#define akOut akAddFeature(akeNormal, \ + akbUserArg|akbServerArg|akbReply|akbReturnBits) + +#define akServerImpl akAddFeature(akeImplicit, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv) +#define akUserImpl akAddFeature(akeImplicit, \ + akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv) + +#define akServerSecToken akAddFeature(akeSecToken, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv) +#define akUserSecToken akAddFeature(akeSecToken, \ + akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv) +#define akSecToken akAddFeature(akeSecToken, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv| \ + akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv) + +#define akServerAuditToken akAddFeature(akeAuditToken, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv) +#define akUserAuditToken akAddFeature(akeAuditToken, \ + akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv) +#define akAuditToken akAddFeature(akeAuditToken, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv| \ + akbUserArg|akbUserImplicit|akbReturn|akbReturnRcv) + +#define akServerContextToken akAddFeature(akeContextToken, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv) + +#define akMsgSeqno akAddFeature(akeMsgSeqno, \ + akbServerArg|akbServerImplicit|akbSend|akbSendRcv) + +#define akInOut akAddFeature(akeNormal, \ + akbUserArg|akbServerArg|akbRequest|akbReply| \ + akbSendBits|akbReturnBits|akbReplyCopy) + +#define akRequestPort akAddFeature(akeRequestPort, \ + akbUserArg|akbServerArg|akbSend|akbSendSnd|akbSendRcv) + +#define akWaitTime akAddFeature(akeWaitTime, akbUserArg) + +#define akSendTime akAddFeature(akeSendTime, akbUserArg) + +#define akMsgOption akAddFeature(akeMsgOption, akbUserArg) + +#define akReplyPort akAddFeature(akeReplyPort, \ + akbUserArg|akbServerArg|akbSend|akbSendSnd|akbSendRcv) + +#define akUReplyPort akAddFeature(akeReplyPort, \ + akbUserArg|akbSend|akbSendSnd|akbSendRcv) + +#define akSReplyPort akAddFeature(akeReplyPort, \ + akbServerArg|akbSend|akbSendSnd|akbSendRcv) + +#define akRetCode akAddFeature(akeRetCode, akbReply|akbReturnBody) + +#define akCount akAddFeature(akeCount, \ + akbUserArg|akbServerArg) + +#define akPoly akePoly + +#define akDealloc akAddFeature(akeDealloc, akbUserArg) + +#define akCountInOut akAddFeature(akeCountInOut, akbRequest|akbSendBits) + +#define akCheck(ak, bits) ((ak) & (bits)) +#define akCheckAll(ak, bits) (akCheck(ak, bits) == (bits)) +#define akAddFeature(ak, bits) ((ak)|(bits)) +#define akRemFeature(ak, bits) ((ak)&~(bits)) +#define akIdent(ak) ((ak) & akeBITS) + +#define argIsIn(arg) (akIdent(arg->argKind) == akeNormal && \ + akCheck(arg->argKind, akbRequest)) +#define argIsOut(arg) (akIdent(arg->argKind) == akeNormal && \ + akCheck(arg->argKind, akbReply)) + +/* + * The arguments to a routine/function are linked in left-to-right order. + * argName is used for error messages and pretty-printing, + * not code generation. Code generation shouldn't make any assumptions + * about the order of arguments, esp. count and poly arguments. + * (Unfortunately, code generation for inline variable-sized arguments + * does make such assumptions.) + * + * argVarName is the name used in generated code for function arguments + * and local variable names. argMsgField is the name used in generated + * code for the field in msgs where the argument's value lives. + * argTTName is the name used in generated code for msg-type fields and + * static variables used to initialize those fields. argPadName is the + * name used in generated code for a padding field in msgs. + * + * argFlags can be used to override the deallocate bits + * in the argument's type. rtProcessArgFlags sets argDeallocate + * from it and the type. Code generation shouldn't use + * argFlags. + * + * argCount, argPoly, and argDealloc get to the implicit count, poly, + * and dealloc arguments associated with the argument; they should be + * used instead of argNext. In these implicit arguments, argParent is + * a pointer to the "real" arg. + * + * In count arguments, argMultiplier is a scaling factor applied to + * the count arg's value to get msg-type-number. It is equal to + * argParent->argType->itElement->itNumber + * + */ + +typedef struct argument +{ + /* if argKind == akReturn, then argName is name of the function */ + identifier_t argName; + struct argument *argNext; + + arg_kind_t argKind; + ipc_type_t *argType; + /* Kernel Processed Data */ + mach_msg_descriptor_type_t argKPD_Type; /* KPD type: port, ool, port+ool */ + void (* argKPD_Template)(FILE *file, struct argument *arg, boolean_t in); /* KPD discipline for static templates */ + void (* argKPD_Init)(FILE *file, struct argument *arg); /* KPD discipline for initializing */ + void (* argKPD_Pack)(FILE *file, struct argument *ar); /* KPD discipline for packing */ + void (* argKPD_Extract)(FILE *file, struct argument *arg); /* KPD discipline for extracting */ + void (* argKPD_TypeCheck)(FILE *file, struct argument *ar); /* KPD discipline for type checking */ + + string_t argVarName; /* local variable and argument names */ + string_t argMsgField; /* message field's name */ + string_t argTTName; /* name for msg_type fields, static vars */ + string_t argPadName; /* name for pad field in msg */ + string_t argSuffix; /* name extension for KPDs */ + + ipc_flags_t argFlags; + dealloc_t argDeallocate; /* overrides argType->itDeallocate */ + boolean_t argCountInOut; + + struct routine *argRoutine; /* routine we are part of */ + + struct argument *argCount; /* our count arg, if present */ + struct argument *argSubCount; /* our sub-count arg, if present (variable subordinate arrays) */ + struct argument *argCInOut; /* our CountInOut arg, if present */ + struct argument *argPoly; /* our poly arg, if present */ + struct argument *argDealloc; /* our dealloc arg, if present */ + struct argument *argSameCount; /* the arg to take the count from, if present */ + struct argument *argParent; /* in a count or poly arg, the base arg */ + u_int argMultiplier; /* for Count argument: parent is a multiple + of a basic IPC type. Argument must be + multiplied by Multiplier to get IPC + number-of-elements. */ + + /* how variable/inline args precede this one, in request and reply */ + u_int argRequestPos; + u_int argReplyPos; + /* whether argument is by reference, on user and server side */ + boolean_t argByReferenceUser; + boolean_t argByReferenceServer; + + boolean_t argTempOnStack; /* A temporary for the short-circuiting + * code when -maxonstack is used. + */ +} argument_t; + +/* + * The various routine kinds' peculiarities are abstracted by rtCheckRoutine + * into attributes like rtOneWay, etc. These are what + * code generation should use. It is Bad Form for code generation to + * test rtKind. + */ + +typedef enum +{ + rkRoutine, + rkSimpleRoutine +} routine_kind_t; + +typedef struct routine +{ + identifier_t rtName; + routine_kind_t rtKind; + argument_t *rtArgs; + u_int rtNumber; /* used for making msg ids */ + + identifier_t rtUserName; /* user-visible name (UserPrefix + Name) */ + identifier_t rtServerName; /* server-side name (ServerPrefix + Name) */ + + identifier_t rtErrorName; /* error-handler name */ + + boolean_t rtOneWay; /* SimpleRoutine */ + + boolean_t rtSimpleRequest; + boolean_t rtSimpleReply; + boolean_t rtUseSpecialReplyPort; + u_int rtConsumeOnSendError; + + u_int rtNumRequestVar; /* number of variable/inline args in request */ + u_int rtNumReplyVar; /* number of variable/inline args in reply */ + + u_int rtMaxRequestPos; /* maximum of argRequestPos */ + u_int rtMaxReplyPos; /* maximum of argReplyPos */ + + u_int rtRequestKPDs; /* number of Kernel Processed Data entries */ + u_int rtReplyKPDs; /* number of Kernel Processed Data entries */ + u_int rtOverwrite; /* number of Overwrite entries */ + u_int rtOverwriteKPDs; /* number of entries in the Overwrite template */ + + boolean_t rtNoReplyArgs; /* if so, no reply message arguments beyond + what the server dispatch routine inserts */ + + boolean_t rtRequestFits; /* Request fits within onstack limit */ + boolean_t rtReplyFits; /* Reply fits within onstack limit */ + boolean_t rtRequestUsedLimit;/* User type limit used in deciding whether + request fits within onstack limit */ + boolean_t rtReplyUsedLimit; /* User type limit used in deciding whether + reply fits within onstack limit */ + u_int rtRequestSizeKnown; /* Max size of known portion of request */ + u_int rtReplySizeKnown; /* Max size of known portion of request */ + + u_int rtServerImpl; /* Implicit data requested */ + u_int rtUserImpl; /* Implicit data requested */ + + /* distinguished arguments */ + argument_t *rtRetCArg; /* the Routine has this argument tagged as RetCode */ + argument_t *rtRequestPort; /* always non-NULL, defaults to first arg */ + argument_t *rtReplyPort; /* always non-NULL, defaults to Mig-supplied */ + argument_t *rtRetCode; /* always non-NULL */ + argument_t *rtNdrCode; /* always non-NULL */ + argument_t *rtWaitTime; /* if non-NULL, will use MACH_RCV_TIMEOUT */ + argument_t *rtMsgOption; /* always non-NULL, defaults to NONE */ + + /* more info's used only when UseEventLogger is turned on */ + u_int rtCountPortsIn; /* how many in-line Ports are sent */ + u_int rtCountOolPortsIn; /* how many out_of-line Ports are sent */ + u_int rtCountOolIn; /* how many bytes out_of-line are sent */ + + u_int rtCountPortsOut; /* how many in-line Ports are rcv'd */ + u_int rtCountOolPortsOut; /* how many out_of-line Ports are rcv'd */ + u_int rtCountOolOut; /* how many bytes out_of-line are rcv'd */ + + u_int rtTempBytesOnStack; /* A temporary for the short-circuiting + * code when -maxonstack is used. + */ + +} routine_t; + +#define rtNULL ((routine_t *) 0) +#define argNULL ((argument_t *) 0) +#define argKPD_NULL ((mach_msg_descriptor_type_t) -1) + +#define rtMessOnStack(rt) ((rt)->rtRequestFits && (rt)->rtReplyFits) + +/* + * These are the ways MiG organizes stub parameters + */ +#define IS_VARIABLE_SIZED_UNTYPED(x) ((x)->itVarArray && \ + (x)->itInLine && \ + !(x)->itPortType) +#define IS_KERN_PROC_DATA(x) (!(x)->itInLine || (x)->itPortType) +#define IS_OPTIONAL_NATIVE(x) ((x)->itNative && \ + (x)->itNativePointer && \ + (x)->itBadValue != NULL) + +/* + * I consider the case of fixed/variable bounded arrays of ports or ool or oolport + */ +#define IS_MULTIPLE_KPD(x) ((x)->itKPD_Number > 1) +/* + * I consider the case of MiG presenting data as it is inLine, even + * if it is sent/rcvd as out-of-line + */ +#define IS_MIG_INLINE_EMUL(x) ((x)->itMigInLine) + +extern u_int rtNumber; +/* rt->rtNumber will be initialized */ +extern routine_t *rtAlloc(void); +/* skip a number */ +extern void rtSkip(void); + +extern argument_t *argAlloc(void); + +extern boolean_t +rtCheckMask(argument_t *args, u_int mask); + +extern boolean_t +rtCheckMaskFunction(argument_t *args, u_int mask, + boolean_t (*func)(argument_t *arg)); + +extern routine_t * +rtMakeRoutine(identifier_t name, argument_t *args); +extern routine_t * +rtMakeSimpleRoutine(identifier_t name, argument_t *args); + +extern void rtPrintRoutine(routine_t *rt); +extern void rtCheckRoutine(routine_t *rt); + +extern char *rtRoutineKindToStr(routine_kind_t rk); + +extern int rtCountArgDescriptors(argument_t *args, int *argcount); + +extern void rtMinRequestSize(FILE *file, routine_t *rt, char *str); +extern void rtMinReplySize(FILE *file, routine_t *rt, char *str); + +#define RPCUserStruct(arg) (arg->argType->itStruct && arg->argType->itInLine) + +#define RPCString(arg) (arg->argType->itString && arg->argType->itInLine) + +#define RPCOutStruct(arg) (arg->argType->itStruct &&\ + argIsOut(arg) && (! arg->argType->itVarArray)) +#define RPCOutWord(arg) (RPCUserStruct(arg) &&\ + (arg->argType->itSize <= 32) &&\ + (arg->argType->itNumber == 1) && argIsOut(arg)) + +#define RPCPort(arg) (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR) + +#define RPCPortArray(arg) (arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) + +#define RPCVariableArray(arg) ((arg->argType->itVarArray) &&\ + !RPCPort(arg) && !RPCPortArray(arg)) + +#define RPCFixedArray(arg) (((! arg->argType->itVarArray) &&\ + !RPCPort(arg) && !RPCPortArray(arg) &&\ + (arg->argType->itNumber > 1) &&\ + !RPCUserStruct(arg)) ||\ + RPCString(arg) ||\ + RPCOutWord(arg) ||\ + RPCOutStruct(arg)) + + +#endif /* _ROUTINE_H */ + + + diff --git a/bootstrap_cmds/migcom.tproj/server.c b/bootstrap_cmds/migcom.tproj/server.c new file mode 100644 index 0000000..7bbed53 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/server.c @@ -0,0 +1,2772 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * @OSF_COPYRIGHT@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include + +#include +#include "write.h" +#include "utils.h" +#include "global.h" +#include "error.h" + +#ifndef max +#define max(a,b) (((a) > (b)) ? (a) : (b)) +#endif /* max */ + +void WriteLogDefines(FILE *file, string_t who); +void WriteIdentificationString(FILE *file); +static void WriteFieldDecl(FILE *file, argument_t *arg); + +static void +WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t varying, argument_t *arg, boolean_t bracket) +{ + ipc_type_t *it = arg->argType; + char string[MAX_STR_LEN]; + + fprintf(file, "\t{\n"); + fprintf(file, "\t %s\t*ptr;\n", it->itKPDType); + fprintf(file, "\t int\ti"); + if (varying && !in) + fprintf(file, ", j"); + fprintf(file, ";\n\n"); + + if (in) + sprintf(string, "In%dP", arg->argRequestPos); + else + sprintf(string, "OutP"); + + fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField); + + if (varying) { + argument_t *count = arg->argCount; + + if (in) + fprintf(file, "\t for (i = 0; i < In%dP->%s; ptr++, i++) %s\n", count->argRequestPos, count->argMsgField, (bracket) ? "{" : ""); + else { + fprintf(file, "\t j = min(%d, ", it->itKPD_Number); + if (akCheck(count->argKind, akbVarNeeded)) + fprintf(file, "%s);\n", count->argName); + else + fprintf(file, "%s->%s);\n", string, count->argMsgField); + fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n", (bracket) ? "{" : ""); + } +} + else + fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : ""); +} + +static void +WriteMyIncludes(FILE *file, statement_t *stats) +{ + if (ServerHeaderFileName == strNULL || UseSplitHeaders) + WriteIncludes(file, FALSE, FALSE); + if (ServerHeaderFileName != strNULL) + { + char *cp; + + /* Strip any leading path from ServerHeaderFileName. */ + cp = strrchr(ServerHeaderFileName, '/'); + if (cp == 0) + cp = ServerHeaderFileName; + else + cp++; /* skip '/' */ + fprintf(file, "#include \"%s\"\n", cp); + } + if (ServerHeaderFileName == strNULL || UseSplitHeaders) + WriteImplImports(file, stats, FALSE); + if (UseEventLogger) { + if (IsKernelServer) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + fprintf(file, "#include \n"); + fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n"); + } + fprintf(file, "#if MIG_DEBUG\n"); + fprintf(file, "#include \n"); + fprintf(file, "#endif /* MIG_DEBUG */\n"); + } + + fprintf(file, "\n"); +} + +static void +WriteGlobalDecls(FILE *file) +{ + if (BeAnsiC) { + fprintf(file, "#define novalue void\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "#define novalue void\n"); + fprintf(file, "#else\n"); + fprintf(file, "#define novalue int\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + fprintf(file, "\n"); + + if (RCSId != strNULL) + WriteRCSDecl(file, strconcat(SubsystemName, "_server"), RCSId); + + /* Used for locations in the request message, *not* reply message. + Reply message locations aren't dependent on IsKernelServer. */ + + if (IsKernelServer) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n"); + fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)"); + fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n"); + fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n"); + fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)"); + fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n"); + fprintf(file, "#else\n"); + } + fprintf(file, "#define msgh_request_port\tmsgh_local_port\n"); + fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)"); + fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n"); + fprintf(file, "#define msgh_reply_port\t\tmsgh_remote_port\n"); + fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)"); + fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n"); + if (IsKernelServer) { + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + fprintf(file, "\n"); + if (UseEventLogger) + WriteLogDefines(file, "MACH_MSG_LOG_SERVER"); + fprintf(file, "#define MIG_RETURN_ERROR(X, code)\t{\\\n"); + fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->RetCode = code;\\\n"); + fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->NDR = NDR_record;\\\n"); + fprintf(file, "\t\t\t\treturn;\\\n"); + fprintf(file, "\t\t\t\t}\n"); + fprintf(file, "\n"); +} + + +static void +WriteForwardDeclarations(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "/* Forward Declarations */\n\n"); + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + fprintf(file, "\nmig_internal novalue _X%s\n", stat->stRoutine->rtName); + fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);\n"); + } + fprintf(file, "\n"); +} + +static void +WriteMIGCheckDefines(FILE *file) +{ + fprintf(file, "#define\t__MIG_check__Request__%s_subsystem__ 1\n", SubsystemName); + fprintf(file, "\n"); +} + +static void +WriteNDRDefines(FILE *file) +{ + fprintf(file, "#define\t__NDR_convert__Request__%s_subsystem__ 1\n", SubsystemName); + fprintf(file, "\n"); +} + +static void +WriteProlog(FILE *file, statement_t *stats) +{ + WriteIdentificationString(file); + fprintf(file, "\n"); + fprintf(file, "/* Module %s */\n", SubsystemName); + fprintf(file, "\n"); + WriteMIGCheckDefines(file); + if (CheckNDR) + WriteNDRDefines(file); + WriteMyIncludes(file, stats); + WriteBogusDefines(file); + WriteApplDefaults(file, "Rcv"); + WriteGlobalDecls(file); + if (ServerHeaderFileName == strNULL) { + WriteRequestTypes(file, stats); + WriteReplyTypes(file, stats); + WriteServerReplyUnion(file, stats); + } +} + +static void +WriteSymTabEntries(FILE *file, statement_t *stats) +{ + statement_t *stat; + u_int current = 0; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + int num = stat->stRoutine->rtNumber; + char *name = stat->stRoutine->rtName; + while (++current <= num) + fprintf(file,"\t\t\t{ \"\", 0, 0 },\n"); + fprintf(file, "\t{ \"%s\", %d, _X%s },\n", name, SubsystemBase + current - 1, name); + } + while (++current <= rtNumber) + fprintf(file,"\t{ \"\", 0, 0 },\n"); +} + +static void +WriteRoutineEntries(FILE *file, statement_t *stats) +{ + u_int current = 0; + statement_t *stat; + char *sig_array, *rt_name; + int arg_count, descr_count; + int offset = 0; + size_t serverSubsysNameLen = strlen(ServerSubsys); + + fprintf(file, "\t{\n"); + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + routine_t *rt = stat->stRoutine; + size_t rtNameLen = strlen(rt->rtName); + + // Include length of rt->rtName in calculation of necessary buffer size, since that string + // is actually written into the buffer along with the Server Subsystem name. + sig_array = (char *) malloc(serverSubsysNameLen + rtNameLen + 80); + rt_name = (char *) malloc(rtNameLen + 5); + while (current++ < rt->rtNumber) + fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n"); + // NOTE: if either of the two string constants in the sprintf() function calls below get + // much longer, be sure to increase the constant '80' (in the first malloc() call) to ensure + // that the allocated buffer is large enough. (Currently, I count 66 characters in the first + // string constant, 65 in the second. 80 ought to be enough for now...) + if (UseRPCTrap) { + sprintf(sig_array, "&%s.arg_descriptor[%d], (mach_msg_size_t)sizeof(__Reply__%s_t)", ServerSubsys, offset, rt->rtName); + } + else { + sprintf(sig_array, "(routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__%s_t)", rt->rtName); + } + sprintf(rt_name, "_X%s", rt->rtName); + descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count); + offset += descr_count; + WriteRPCRoutineDescriptor(file, rt, arg_count, (UseRPCTrap) ? descr_count : 0, rt_name, sig_array); + fprintf(file, ",\n"); + free(sig_array); + free(rt_name); + } + while (current++ < rtNumber) + fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n"); + + fprintf(file, "\t}"); +} + +static void +WriteArgDescriptorEntries(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, ",\n\n\t{\n"); + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + routine_t *rt = stat->stRoutine; + + /* For each arg of the routine, write an arg descriptor: + */ + WriteRPCRoutineArgDescriptor(file, rt); + } + fprintf(file, "\t},\n\n"); +} + + +/* + * Write out the description of this subsystem, for use in direct RPC + */ +static void +WriteSubsystem(FILE *file, statement_t *stats) +{ + statement_t *stat; + int descr_count = 0; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + routine_t *rt = stat->stRoutine; + descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0); + } + fprintf(file, "\n"); + if (ServerHeaderFileName == strNULL) { + WriteMigExternal(file); + fprintf(file, "boolean_t %s(", ServerDemux); + if (BeAnsiC) { + fprintf(file, "\n\t\tmach_msg_header_t *InHeadP,"); + fprintf(file, "\n\t\tmach_msg_header_t *OutHeadP"); + } + fprintf(file, ");\n\n"); + + WriteMigExternal(file); + fprintf(file, "mig_routine_t %s_routine(", ServerDemux); + if (BeAnsiC) { + fprintf(file, "\n\t\tmach_msg_header_t *InHeadP"); + } + fprintf(file, ");\n\n"); + } + fprintf(file, "\n/* Description of this subsystem, for use in direct RPC */\n"); + if (ServerHeaderFileName == strNULL) { + fprintf(file, "const struct %s {\n", ServerSubsys); + if (UseRPCTrap) { + fprintf(file, "\tstruct subsystem *\tsubsystem;\t/* Reserved for system use */\n"); + } + else { + fprintf(file, "\tmig_server_routine_t \tserver;\t/* Server routine */\n"); + } + fprintf(file, "\tmach_msg_id_t\tstart;\t/* Min routine number */\n"); + fprintf(file, "\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n"); + fprintf(file, "\tunsigned int\tmaxsize;\t/* Max msg size */\n"); + if (UseRPCTrap) { + fprintf(file, "\tvm_address_t\tbase_addr;\t/* Base address */\n"); + fprintf(file, "\tstruct rpc_routine_descriptor\t/*Array of routine descriptors */\n"); + } + else { + fprintf(file, "\tvm_address_t\treserved;\t/* Reserved */\n"); + fprintf(file, "\tstruct routine_descriptor\t/*Array of routine descriptors */\n"); + } + fprintf(file, "\t\troutine[%d];\n", rtNumber); + if (UseRPCTrap) { + fprintf(file, "\tstruct rpc_routine_arg_descriptor\t/*Array of arg descriptors */\n"); + fprintf(file, "\t\targ_descriptor[%d];\n", descr_count); + } + fprintf(file, "} %s = {\n", ServerSubsys); + } + else { + fprintf(file, "const struct %s %s = {\n", ServerSubsys, ServerSubsys); + } + if (UseRPCTrap) { + fprintf(file, "\t0,\n"); + } + else { + fprintf(file, "\t%s_routine,\n", ServerDemux); + } + fprintf(file, "\t%d,\n", SubsystemBase); + fprintf(file, "\t%d,\n", SubsystemBase + rtNumber); + fprintf(file, "\t(mach_msg_size_t)sizeof(union __ReplyUnion__%s),\n", ServerSubsys); + if (UseRPCTrap) { + fprintf(file, "\t(vm_address_t)&%s,\n", ServerSubsys); + } + else { + fprintf(file, "\t(vm_address_t)0,\n"); + } + WriteRoutineEntries(file, stats); + + if (UseRPCTrap) + WriteArgDescriptorEntries(file, stats); + else + fprintf(file, "\n"); + + fprintf(file, "};\n\n"); +} + +#if NOT_CURRENTLY_USED + +static void +WriteArraySizes(FILE *file, statement_t *stats) +{ + u_int current = 0; + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + routine_t *rt = stat->stRoutine; + + while (current++ < rt->rtNumber) + fprintf(file, "\t\t0,\n"); + fprintf(file, "\t\t(mach_msg_size_t)sizeof(__Reply__%s_t),\n", rt->rtName); + } + while (current++ < rtNumber) + fprintf(file, "\t\t\t0,\n"); +} + +#endif /* NOT_CURRENTLY_USED */ + +void +WriteServerRequestUnion(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "\n"); + fprintf(file, "/* union of all requests */\n\n"); + fprintf(file, "#ifndef __RequestUnion__%s__defined\n", ServerSubsys); + fprintf(file, "#define __RequestUnion__%s__defined\n", ServerSubsys); + fprintf(file, "union __RequestUnion__%s {\n", ServerSubsys); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) { + routine_t *rt; + + rt = stat->stRoutine; + fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtName); + } + } + fprintf(file, "};\n"); + fprintf(file, "#endif /* __RequestUnion__%s__defined */\n", ServerSubsys); +} + +void +WriteServerReplyUnion(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "\n"); + fprintf(file, "/* union of all replies */\n\n"); + fprintf(file, "#ifndef __ReplyUnion__%s__defined\n", ServerSubsys); + fprintf(file, "#define __ReplyUnion__%s__defined\n", ServerSubsys); + fprintf(file, "union __ReplyUnion__%s {\n", ServerSubsys); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) { + routine_t *rt; + + rt = stat->stRoutine; + fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtName); + } + } + fprintf(file, "};\n"); + fprintf(file, "#endif /* __ReplyUnion__%s__defined */\n", ServerSubsys); +} + +static void +WriteDispatcher(FILE *file, statement_t *stats) +{ + /* + * Write the subsystem stuff. + */ + fprintf(file, "\n"); + WriteSubsystem(file, stats); + + /* + * Then, the server routine + */ + fprintf(file, "mig_external boolean_t %s\n", ServerDemux); + if (BeAnsiC) { + fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n"); + fprintf(file, "#else\n"); + fprintf(file, "\t(InHeadP, OutHeadP)\n"); + fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + + fprintf(file, "{\n"); + fprintf(file, "\t/*\n"); + fprintf(file, "\t * typedef struct {\n"); + fprintf(file, "\t * \tmach_msg_header_t Head;\n"); + fprintf(file, "\t * \tNDR_record_t NDR;\n"); + fprintf(file, "\t * \tkern_return_t RetCode;\n"); + fprintf(file, "\t * } mig_reply_error_t;\n"); + fprintf(file, "\t */\n"); + fprintf(file, "\n"); + + fprintf(file, "\tmig_routine_t routine;\n"); + fprintf(file, "\n"); + + fprintf(file, "\tOutHeadP->msgh_bits = "); + fprintf(file, "MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);\n"); + fprintf(file, "\tOutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;\n"); + fprintf(file, "\t/* Minimal size: routine() will update it if different */\n"); + fprintf(file, "\tOutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);\n"); + fprintf(file, "\tOutHeadP->msgh_local_port = MACH_PORT_NULL;\n"); + fprintf(file, "\tOutHeadP->msgh_id = InHeadP->msgh_id + 100;\n"); + fprintf(file, "\tOutHeadP->msgh_reserved = 0;\n"); + fprintf(file, "\n"); + + fprintf(file, "\tif ((InHeadP->msgh_id > %d) || (InHeadP->msgh_id < %d) ||\n", SubsystemBase + rtNumber - 1, SubsystemBase); + fprintf(file, "\t ((routine = %s.routine[InHeadP->msgh_id - %d].stub_routine) == 0)) {\n", ServerSubsys, SubsystemBase); + fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;\n"); + fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;\n"); + if (UseEventLogger) { + fprintf(file, "#if MIG_DEBUG\n"); + fprintf(file, "\t\tLOG_ERRORS(MACH_MSG_LOG_SERVER, MACH_MSG_ERROR_UNKNOWN_ID,\n"); + fprintf(file, "\t\t\t&InHeadP->msgh_id, __FILE__, __LINE__);\n"); + fprintf(file, "#endif /* MIG_DEBUG */\n"); + } + fprintf(file, "\t\treturn FALSE;\n"); + fprintf(file, "\t}\n"); + + /* Call appropriate routine */ + fprintf(file, "\t(*routine) (InHeadP, OutHeadP);\n"); + fprintf(file, "\treturn TRUE;\n"); + fprintf(file, "}\n"); + fprintf(file, "\n"); + + /* + * Then, the _server_routine routine + */ + fprintf(file, "mig_external mig_routine_t %s_routine\n", ServerDemux); + if (BeAnsiC) { + fprintf(file, "\t(mach_msg_header_t *InHeadP)\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "\t(mach_msg_header_t *InHeadP)\n"); + fprintf(file, "#else\n"); + fprintf(file, "\t(InHeadP)\n"); + fprintf(file, "\tmach_msg_header_t *InHeadP;\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + + fprintf(file, "{\n"); + fprintf(file, "\tint msgh_id;\n"); + fprintf(file, "\n"); + fprintf(file, "\tmsgh_id = InHeadP->msgh_id - %d;\n", SubsystemBase); + fprintf(file, "\n"); + fprintf(file, "\tif ((msgh_id > %d) || (msgh_id < 0))\n", rtNumber - 1); + fprintf(file, "\t\treturn 0;\n"); + fprintf(file, "\n"); + fprintf(file, "\treturn %s.routine[msgh_id].stub_routine;\n", ServerSubsys); + fprintf(file, "}\n"); + + /* symtab */ + + if (GenSymTab) { + fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName); + WriteSymTabEntries(file,stats); + fprintf(file,"};\n"); + fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase); + fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber); + } +} + +#if NOT_CURRENTLY_USED +/* + * Returns the return type of the server-side work function. + * Suitable for "extern %s serverfunc()". + */ +static char * +ServerSideType(routine_t *rt) +{ + return rt->rtRetCode->argType->itTransType; +} +#endif /* NOT_CURRENTLY_USED */ + +static void +WriteRetCode(FILE *file, argument_t *ret) +{ + ipc_type_t *it = ret->argType; + + if (akCheck(ret->argKind, akbVarNeeded)) { + fprintf(file, "\t%s %s;\n", it->itTransType, ret->argVarName); + } +} + +static void +WriteLocalVarDecl(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + ipc_type_t *btype = it->itElement; + + if (IS_VARIABLE_SIZED_UNTYPED(it)) + fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, btype->itNumber ? it->itNumber/btype->itNumber : 0); + else if (IS_MULTIPLE_KPD(it)) { + if (btype->itTransType != strNULL) + fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, it->itKPD_Number); + else + /* arrays of ool or oolport */ + fprintf(file, "\tvoid *%s[%d]", arg->argVarName, it->itKPD_Number); + } + else + fprintf(file, "\t%s %s", it->itTransType, arg->argVarName); +} + +#if NOT_CURRENTLY_USED +static void +WriteServerArgDecl(FILE *file, argument_t *arg) +{ + fprintf(file, "%s %s%s", arg->argType->itTransType, arg->argByReferenceServer ? "*" : "", arg->argVarName); +} +#endif /* NOT_CURRENTLY_USED */ + +/* + * Writes the local variable declarations which are always + * present: InP, OutP, the server-side work function. + */ +static void +WriteVarDecls(FILE *file, routine_t *rt) +{ + int i; + + fprintf(file, "\tRequest *In0P = (Request *) InHeadP;\n"); + for (i = 1; i <= rt->rtMaxRequestPos; i++) + fprintf(file, "\tRequest *In%dP;\n", i); + fprintf(file, "\tReply *OutP = (Reply *) OutHeadP;\n"); + + /* if reply is variable, we may need msgh_size_delta and msgh_size */ + if (rt->rtNumReplyVar > 1) + fprintf(file, "\tunsigned int msgh_size;\n"); + if (rt->rtMaxReplyPos > 0) + fprintf(file, "\tunsigned int msgh_size_delta;\n"); + if (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos > 0) + fprintf(file, "\n"); + + if (rt->rtServerImpl) { + fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n"); + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + fprintf(file, "#ifdef\t__MIG_check__Request__%s_t__defined\n", rt->rtName); + fprintf(file, "\tkern_return_t check_result;\n"); + fprintf(file, "#endif\t/* __MIG_check__Request__%s_t__defined */\n", rt->rtName); + fprintf(file, "\n"); +} + +static void +WriteReplyInit(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + if (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos) + /* WritheAdjustMsgSize() has been executed at least once! */ + fprintf(file, "\tOutP = (Reply *) OutHeadP;\n"); + + if (!rt->rtSimpleReply) /* complex reply message */ + fprintf(file, "\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n"); + + if (rt->rtNumReplyVar == 0) { + fprintf(file, "\tOutP->Head.msgh_size = "); + rtMinReplySize(file, rt, "Reply"); + fprintf(file, ";\n"); + } + else if (rt->rtNumReplyVar > 1) + fprintf(file, "\tOutP->Head.msgh_size = msgh_size;\n"); + /* the case rt->rtNumReplyVar = 1 is taken care of in WriteAdjustMsgSize() */ +} + +static void +WriteRetCArgCheckError(FILE *file, routine_t *rt) +{ + fprintf(file, "\tif (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&\n"); + fprintf(file, "\t (In0P->Head.msgh_size == (mach_msg_size_t)sizeof(mig_reply_error_t)))\n"); + fprintf(file, "\t{\n"); +} + +static void +WriteRetCArgFinishError(FILE *file, routine_t *rt) +{ + argument_t *retcode = rt->rtRetCArg; + + fprintf(file, "\treturn;\n"); + fprintf(file, "\t}\n"); + retcode->argMsgField = "KERN_SUCCESS"; +} + +static void +WriteCheckHead(FILE *file, routine_t *rt) +{ + fprintf(file, "#if\t__MigTypeCheck\n"); + if (rt->rtNumRequestVar > 0) + fprintf(file, "\tmsgh_size = In0P->Head.msgh_size;\n"); + + if (rt->rtSimpleRequest) { + /* Expecting a simple message. */ + fprintf(file, "\tif ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n"); + if (rt->rtNumRequestVar > 0) { + fprintf(file, "\t (msgh_size < "); + rtMinRequestSize(file, rt, "__Request"); + fprintf(file, ") || (msgh_size > (mach_msg_size_t)sizeof(__Request)))\n"); + } + else + fprintf(file, "\t (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request)))\n"); + } + else { + /* Expecting a complex message. */ + + fprintf(file, "\tif ("); + if (rt->rtRetCArg != argNULL) + fprintf(file, "("); + fprintf(file, "!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n"); + fprintf(file, "\t (In0P->msgh_body.msgh_descriptor_count != %d) ||\n", rt->rtRequestKPDs); + if (rt->rtNumRequestVar > 0) { + fprintf(file, "\t (msgh_size < "); + rtMinRequestSize(file, rt, "__Request"); + fprintf(file, ") || (msgh_size > (mach_msg_size_t)sizeof(__Request))"); + } + else + fprintf(file, "\t (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request))"); + if (rt->rtRetCArg == argNULL) + fprintf(file, ")\n"); + else { + fprintf(file, ") &&\n"); + fprintf(file, "\t ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n"); + fprintf(file, "\t In0P->Head.msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n"); + fprintf(file, "\t ((mig_reply_error_t *)In0P)->RetCode == KERN_SUCCESS))\n"); + } + } + fprintf(file, "\t\treturn MIG_BAD_ARGUMENTS;\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + fprintf(file, "\n"); +} + +void +WriteRequestNDRConvertIntRepArgCond(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + fprintf(file, "defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField); +} + +void +WriteRequestNDRConvertCharRepArgCond(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut) + fprintf(file, "defined(__NDR_convert__char_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField); + else + fprintf(file, "0"); +} + +void +WriteRequestNDRConvertFloatRepArgCond(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut) + fprintf(file, "defined(__NDR_convert__float_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField); + else + fprintf(file, "0"); +} + +void +WriteRequestNDRConvertIntRepArgDecl(FILE *file, argument_t *arg) +{ + WriteNDRConvertArgDecl(file, arg, "int_rep", "Request"); +} + +void +WriteRequestNDRConvertCharRepArgDecl(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut) + WriteNDRConvertArgDecl(file, arg, "char_rep", "Request"); +} + +void +WriteRequestNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut) + WriteNDRConvertArgDecl(file, arg, "float_rep", "Request"); +} + +void +WriteRequestNDRConvertArgUse(FILE *file, argument_t *arg, char *convert) +{ + routine_t *rt = arg->argRoutine; + argument_t *count = arg->argCount; + char argname[MAX_STR_LEN]; + + if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) && + (arg->argParent && akCheck(arg->argParent->argKind, akbSendNdr))) + return; + + if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { + if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) { + fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, count->argMsgField); + fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argRequestPos, count->argMsgField, count->argRequestPos); + fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, count->argMsgField); + } + + sprintf(argname, "(%s)(In%dP->%s.address)", FetchServerType(arg->argType), arg->argRequestPos, arg->argMsgField); + } + else { + sprintf(argname, "&In%dP->%s", arg->argRequestPos, arg->argMsgField); + } + + fprintf(file, "#if defined(__NDR_convert__%s__Request__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField); + fprintf(file, "\t\t__NDR_convert__%s__Request__%s_t__%s(%s, In0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert); + if (count) + fprintf(file, ", In%dP->%s", count->argRequestPos, count->argMsgField); + fprintf(file, ");\n"); + fprintf(file, "#endif\t/* __NDR_convert__%s__Request__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField); +} + +void +WriteRequestNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField); + fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep)\n"); + fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argRequestPos, arg->argMsgField, arg->argRequestPos); + fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField); +} + +void +WriteRequestNDRConvertIntRepArgUse(FILE *file, argument_t *arg) +{ + WriteRequestNDRConvertArgUse(file, arg, "int_rep"); +} + +void +WriteRequestNDRConvertCharRepArgUse(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut) + WriteRequestNDRConvertArgUse(file, arg, "char_rep"); +} + +void +WriteRequestNDRConvertFloatRepArgUse(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut) + WriteRequestNDRConvertArgUse(file, arg, "float_rep"); +} + +static void +WriteCalcArgSize(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argType; + + if (PackMsg == FALSE) { + fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize); + return; + } + + if (IS_OPTIONAL_NATIVE(ptype)) + fprintf(file, "(In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0)" , arg->argRequestPos, arg->argMsgField, ptype->itServerType); + else { + ipc_type_t *btype = ptype->itElement; + argument_t *count = arg->argCount; + int multiplier = btype->itTypeSize; + + if (btype->itTypeSize % itWordAlign != 0) + fprintf(file, "_WALIGN_"); + fprintf(file, "("); + + if (multiplier > 1) + fprintf(file, "%d * ", multiplier); + fprintf(file, "In%dP->%s", count->argRequestPos, count->argMsgField); + fprintf(file, ")"); + } +} + +static void +WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator) +{ + ipc_type_t *ptype = arg->argType; + + + fprintf(file, "\tif (((msgh_size - "); + rtMinRequestSize(file, rt, "__Request"); + fprintf(file, ") "); + if (PackMsg == FALSE) { + fprintf(file, "%s %d)", comparator, ptype->itTypeSize + ptype->itPadSize); + } else if (IS_OPTIONAL_NATIVE(ptype)) { + fprintf(file, "%s (In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0))" , comparator, arg->argRequestPos, arg->argMsgField, ptype->itServerType); + } else { + ipc_type_t *btype = ptype->itElement; + argument_t *count = arg->argCount; + int multiplier = btype->itTypeSize; + + if (multiplier > 1) + fprintf(file, "/ %d ", multiplier); + fprintf(file, "< In%dP->%s) ||\n", count->argRequestPos, count->argMsgField); + fprintf(file, "\t (msgh_size %s ", comparator); + rtMinRequestSize(file, rt, "__Request"); + fprintf(file, " + "); + WriteCalcArgSize(file, arg); + fprintf(file, ")"); + } + fprintf(file, ")\n\t\treturn MIG_BAD_ARGUMENTS;\n"); +} + +static void +WriteCheckMsgSize(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + if (arg->argCount && !arg->argSameCount) + WriteRequestNDRConvertIntRepOneArgUse(file, arg->argCount); + if (arg->argRequestPos == rt->rtMaxRequestPos) { + fprintf(file, "#if\t__MigTypeCheck\n"); + + /* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */ + fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber); + fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file); + /* ...end... */ + + WriteCheckArgSize(file, rt, arg, "!="); + + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + else { + /* If there aren't any more variable-sized arguments after this, + then we must check for exact msg-size and we don't need to + update msgh_size. */ + + boolean_t LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar; + + /* calculate the actual size in bytes of the data field. note + that this quantity must be a multiple of four. hence, if + the base type size isn't a multiple of four, we have to + round up. note also that btype->itNumber must + divide btype->itTypeSize (see itCalculateSizeInfo). */ + + fprintf(file, "\tmsgh_size_delta = "); + WriteCalcArgSize(file, arg); + fprintf(file, ";\n"); + fprintf(file, "#if\t__MigTypeCheck\n"); + + /* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */ + fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber); + fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file); + /* ...end... */ + + /* Don't decrement msgh_size until we've checked that + it won't underflow. */ + WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<"); + + if (!LastVarArg) + fprintf(file, "\tmsgh_size -= msgh_size_delta;\n"); + + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + fprintf(file, "\n"); +} + +static char * +InArgMsgField(argument_t *arg, char *str) +{ + static char buffer[MAX_STR_LEN]; + char who[20] = {0}; + + /* + * Inside the kernel, the request and reply port fields + * really hold ipc_port_t values, not mach_port_t values. + * Hence we must cast the values. + */ + + if (!(arg->argFlags & flRetCode)) { + if (akCheck(arg->argKind, akbServerImplicit)) + sprintf(who, "TrailerP->"); + else + sprintf(who, "In%dP->", arg->argRequestPos); + } + +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelServer && + ((akIdent(arg->argKind) == akeRequestPort) || + (akIdent(arg->argKind) == akeReplyPort))) + sprintf(buffer, "(ipc_port_t) %s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField); + else +#endif + sprintf(buffer, "%s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField); + + return buffer; +} + +static void +WriteExtractArgValue(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + string_t recast; + +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelServer && it->itPortType && streql(it->itServerType, "ipc_port_t") + && akIdent(arg->argKind) != akeRequestPort + && akIdent(arg->argKind) != akeReplyPort) + recast = "(mach_port_t)"; + else +#endif + recast = ""; + if (it->itInTrans != strNULL) + WriteCopyType(file, it, FALSE, "%s", "/* %s */ %s(%s%s)", arg->argVarName, it->itInTrans, recast, InArgMsgField(arg, "")); + else + WriteCopyType(file, it, FALSE, "%s", "/* %s */ %s%s", arg->argVarName, recast, InArgMsgField(arg, "")); + + fprintf(file, "\n"); +} + +/* + * argKPD_Extract discipline for Port types. + */ +static void +WriteExtractKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *recast = ""; + + WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE); + /* translation function do not apply to complex types */ +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelServer) + recast = "(mach_port_t)"; +#endif + fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast); + fprintf(file, "\t}\n"); +} + +/* + * argKPD_Extract discipline for out-of-line types. + */ +static void +WriteExtractKPD_ool(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE); + fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName); + fprintf(file, "\t}\n"); +} + +/* + * argKPD_Extract discipline for out-of-line Port types. + */ +static void +WriteExtractKPD_oolport(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE); + fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName); + fprintf(file, "\t}\n"); + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendRcv)) { + argument_t *poly = arg->argPoly; + char *pref = poly->argByReferenceServer ? "*" : ""; + + fprintf(file, "\t%s%s = In%dP->%s[0].disposition;\n", pref, poly->argVarName, arg->argRequestPos, arg->argMsgField); + } +} + + +static void +WriteInitializeCount(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argParent->argType; + ipc_type_t *btype = ptype->itElement; + identifier_t newstr; + + /* + * Initialize 'count' argument for variable-length inline OUT parameter + * with maximum allowed number of elements. + */ + + if (akCheck(arg->argKind, akbVarNeeded)) + newstr = arg->argMsgField; + else + newstr = (identifier_t)strconcat("OutP->", arg->argMsgField); + + fprintf(file, "\t%s = ", newstr); + if (IS_MULTIPLE_KPD(ptype)) + fprintf(file, "%d;\n", ptype->itKPD_Number); + else + fprintf(file, "%d;\n", btype->itNumber? ptype->itNumber/btype->itNumber : 0); + + /* + * If the user passed in a count, then we use the minimum. + * We can't let the user completely override our maximum, + * or the user might convince the server to overwrite the buffer. + */ + + if (arg->argCInOut != argNULL) { + char *msgfield = InArgMsgField(arg->argCInOut, ""); + + fprintf(file, "\tif (%s < %s)\n", msgfield, newstr); + fprintf(file, "\t\t%s = %s;\n", newstr, msgfield); + } + + fprintf(file, "\n"); +} + +static void +WriteAdjustRequestMsgPtr(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argType; + + if (PackMsg == FALSE) { + fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP);\n\n", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos); + return; + } + + fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP + msgh_size_delta - ", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos); + if (IS_OPTIONAL_NATIVE(ptype)) + fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType); + else + fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize); + fprintf(file, ");\n\n"); +} + +static void +WriteCheckRequestTrailerArgs(FILE *file, routine_t *rt) +{ + argument_t *arg; + + if (rt->rtServerImpl) + WriteCheckTrailerHead(file, rt, FALSE); + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (akCheck(arg->argKind, akbServerImplicit)) + WriteCheckTrailerSize(file, FALSE, arg); + } +} + +static void +WriteExtractArg(FILE *file, argument_t *arg) +{ + if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded)) { + if (akCheck(arg->argKind, akbSendKPD)) + (*arg->argKPD_Extract)(file, arg); + else + WriteExtractArgValue(file, arg); + } + + if ((akIdent(arg->argKind) == akeCount) && + akCheck(arg->argKind, akbReturnSnd)) { + + ipc_type_t *ptype = arg->argParent->argType; + /* + * the count will be initialized to 0 in the case of + * unbounded arrays (MigInLine = TRUE): this is because + * the old interface used to pass to the target procedure + * the maximum in-line size (it was 2048 bytes) + */ + if (IS_VARIABLE_SIZED_UNTYPED(ptype) || + IS_MIG_INLINE_EMUL(ptype) || + (IS_MULTIPLE_KPD(ptype) && ptype->itVarArray)) + WriteInitializeCount(file, arg); + } +} + +static void +WriteServerCallArg(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + boolean_t NeedClose = FALSE; + u_int elemsize = 0; + string_t at = (arg->argByReferenceServer || + it->itNativePointer) ? "&" : ""; + string_t star = (arg->argByReferenceServer) ? " *" : ""; + string_t msgfield = + (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField; + + if ((it->itInTrans != strNULL) && + akCheck(arg->argKind, akbSendRcv) && + !akCheck(arg->argKind, akbVarNeeded)) { + fprintf(file, "%s%s(", at, it->itInTrans); + NeedClose = TRUE; + } + + if (akCheckAll(arg->argKind, akbVarNeeded|akbServerArg)) + fprintf(file, "%s%s", at, arg->argVarName); + else if (akCheckAll(arg->argKind, akbSendRcv|akbSendKPD)) { + if (!it->itInLine) + /* recast the void *, although it is not necessary */ + fprintf(file, "(%s%s)%s(%s)", it->itTransType, star, at, InArgMsgField(arg, "")); + else +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelServer && streql(it->itServerType, "ipc_port_t")) + /* recast the port to the kernel internal form value */ + fprintf(file, "(ipc_port_t%s)%s(%s)", star, at, InArgMsgField(arg, "")); + else +#endif + fprintf(file, "%s%s", at, InArgMsgField(arg, "")); + } + else if (akCheck(arg->argKind, akbSendRcv)) { + if (IS_OPTIONAL_NATIVE(it)) { + fprintf(file, "(%s ? ", InArgMsgField(arg, "__Present__")); + fprintf(file, "%s%s.__Real__%s : %s)", at, InArgMsgField(arg, ""), arg->argMsgField, it->itBadValue); + } + else { + if (akIdent(arg->argKind) == akeCount && arg->argParent) { + char *suffix = arg->argParent->argSuffix; + ipc_type_t *elemType = arg->argParent->argType->itElement; + /* temporarily squash any name suffix such as ".address" (we'll be adding our own) */ + arg->argParent->argSuffix = NULL; + switch (arg->argParent->argKPD_Type) { + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + /* count of the number of descriptors */ + fprintf(file, "%s%s.count", at, InArgMsgField(arg->argParent, "")); + break; + case MACH_MSG_OOL_DESCRIPTOR: + /* descriptor buffer size / element size */ + if (!(arg->argByReferenceServer || it->itNativePointer)) { + fprintf(file, "%s%s.size", at, InArgMsgField(arg->argParent, "")); + elemsize = ((elemType->itNumber * elemType->itSize) + 7) / 8; + if (elemsize > 1) { + fprintf(file, " / %d", elemsize); + } + } else { + fprintf(file, "%s%s", at, InArgMsgField(arg, "")); + } + break; + default: + fprintf(file, "%s%s", at, InArgMsgField(arg, "")); + break; + } + arg->argParent->argSuffix = suffix; + } else { + fprintf(file, "%s%s", at, InArgMsgField(arg, "")); + } + } + } + else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD)) { + if (!it->itInLine) + /* recast the void *, although it is not necessary */ + fprintf(file, "(%s%s)%s(OutP->%s)", it->itTransType, star, at, msgfield); + else +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelServer && streql(it->itServerType, "ipc_port_t")) + /* recast the port to the kernel internal form value */ + fprintf(file, "(mach_port_t%s)%s(OutP->%s)", star, at, msgfield); + else +#endif + fprintf(file, "%sOutP->%s", at, msgfield); + + } + else if (akCheck(arg->argKind, akbReturnSnd)) + fprintf(file, "%sOutP->%s", at, msgfield); + + if (NeedClose) + fprintf(file, ")"); +} + +/* + * Shrunk version of WriteServerCallArg, to implement the RetCode functionality: + * we have received a mig_reply_error_t, therefore we want to call the target + * routine with all 0s except for the error code (and the implicit data). + * We know that we are a SimpleRoutine. + */ +static void +WriteConditionalCallArg(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + boolean_t NeedClose = FALSE; + + if ((it->itInTrans != strNULL) && + akCheck(arg->argKind, akbSendRcv) && + !akCheck(arg->argKind, akbVarNeeded)) { + fprintf(file, "%s(", it->itInTrans); + NeedClose = TRUE; + } + + if (akCheck(arg->argKind, akbSendRcv)) { + if (akIdent(arg->argKind) == akeRequestPort || + akCheck(arg->argKind, akbServerImplicit)) + fprintf(file, "%s", InArgMsgField(arg, "")); + else if (akIdent(arg->argKind) == akeRetCode) + fprintf(file, "((mig_reply_error_t *)In0P)->RetCode"); + else + fprintf(file, "(%s)(0)", it->itTransType); + } + + if (NeedClose) + fprintf(file, ")"); +} + +static void +WriteDestroyArg(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + /* + * Deallocate IN/INOUT out-of-line args if specified by "auto" flag. + * + * We also have to deallocate in the cases where the target routine + * is given a itInLine semantic whereas the underlying transmission + * was out-of-line + */ + if ((argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && + arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR && + (arg->argFlags & flAuto)) + || + IS_MIG_INLINE_EMUL(it) + ) { + /* + * Deallocate only if out-of-line. + */ + argument_t *count = arg->argCount; + ipc_type_t *btype = it->itElement; + int multiplier = btype->itNumber ? btype->itSize / (8 * btype->itNumber) : 0; + + if (IsKernelServer) { + fprintf(file, "#if __MigKernelSpecificCode\n"); + fprintf(file, "\tvm_map_copy_discard(%s);\n", InArgMsgField(arg, "")); + fprintf(file, "#else\n"); + } + fprintf(file, "\tmig_deallocate((vm_offset_t) %s, ", InArgMsgField(arg, "")); + if (it->itVarArray) { + char *suffix = arg->argSuffix; + /* + * temporarily squash any name suffix such as ".address" + * (we'll be adding our own) + */ + arg->argSuffix = NULL; + switch (arg->argKPD_Type) { + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + if (multiplier > 1) { + fprintf(file, "%d * ", multiplier); + } + fprintf(file, "%s.count);\n", InArgMsgField(arg, "")); + break; + case MACH_MSG_OOL_DESCRIPTOR: + fprintf(file, "%s.size);\n", InArgMsgField(arg, "")); + break; + default: + if (multiplier > 1) { + fprintf(file, "%d * ", multiplier); + } + fprintf(file, "%s);\n", InArgMsgField(count, "")); + break; + } + arg->argSuffix = suffix; + } + else + fprintf(file, "%d);\n", (it->itNumber * it->itSize + 7) / 8); + if (IsKernelServer) { + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + fprintf(file, "\t%s = (void *) 0;\n", InArgMsgField(arg, "")); + fprintf(file, "\tIn%dP->%s.%s = (mach_msg_size_t) 0;\n", arg->argRequestPos, arg->argMsgField, (RPCPortArray(arg) ? "count" : "size")); + } + else { + if (akCheck(arg->argKind, akbVarNeeded)) + fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName); + else + fprintf(file, "\t%s(%s);\n", it->itDestructor, InArgMsgField(arg, "")); + } +} + +static void +WriteDestroyPortArg(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + /* + * If a translated port argument occurs in the body of a request + * message, and the message is successfully processed, then the + * port right should be deallocated. However, the called function + * didn't see the port right; it saw the translation. So we have + * to release the port right for it. + * + * The test over it->itInTrans will exclude any complex type + * made out of ports + */ + if ((it->itInTrans != strNULL) && + (it->itOutName == MACH_MSG_TYPE_PORT_SEND)) { + fprintf(file, "\n"); + fprintf(file, "\tif (IP_VALID((ipc_port_t)%s))\n", InArgMsgField(arg, "")); + fprintf(file, "\t\tipc_port_release_send((ipc_port_t)%s);\n", InArgMsgField(arg, "")); + } +} + +/* + * Check whether WriteDestroyPortArg would generate any code for arg. + */ +boolean_t +CheckDestroyPortArg(argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + if ((it->itInTrans != strNULL) && + (it->itOutName == MACH_MSG_TYPE_PORT_SEND)) { + return TRUE; + } + return FALSE; +} + +static void +WriteServerCall(FILE *file, routine_t *rt, void (*func)(FILE *, argument_t *)) +{ + argument_t *arg = rt->rtRetCode; + ipc_type_t *it = arg->argType; + boolean_t NeedClose = FALSE; + + fprintf(file, "\t"); + if (akCheck(arg->argKind, akbVarNeeded)) + fprintf(file, "%s = ", arg->argMsgField); + else + fprintf(file, "OutP->%s = ", arg->argMsgField); + if (it->itOutTrans != strNULL) { + fprintf(file, "%s(", it->itOutTrans); + NeedClose = TRUE; + } + fprintf(file, "%s(", rt->rtServerName); + WriteList(file, rt->rtArgs, func, akbServerArg, ", ", ""); + if (NeedClose) + fprintf(file, ")"); + fprintf(file, ");\n"); +} + +static void +WriteCheckReturnValue(FILE *file, routine_t *rt) +{ + argument_t *arg = rt->rtRetCode; + char string[MAX_STR_LEN]; + + if (akCheck(arg->argKind, akbVarNeeded)) + sprintf(string, "%s", arg->argMsgField); + else + sprintf(string, "OutP->%s", arg->argMsgField); + fprintf(file, "\tif (%s != KERN_SUCCESS) {\n", string); + fprintf(file, "\t\tMIG_RETURN_ERROR(OutP, %s);\n", string); + fprintf(file, "\t}\n"); +} + +/* + * WriteInitKPD_port, WriteInitKPD_ool, WriteInitKPD_oolport + * initializes the OutP KPD fields (this job cannot be done once + * the target routine has been called, otherwise informations + * would be lost) + */ +/* + * argKPD_Init discipline for Port types. + */ +static void +WriteInitKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *subindex = ""; + boolean_t close = FALSE; + char firststring[MAX_STR_LEN]; + char string[MAX_STR_LEN]; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE); + (void)sprintf(firststring, "\t*ptr"); + (void)sprintf(string, "\tptr->"); + subindex = "[i]"; + close = TRUE; + } + else { + (void)sprintf(firststring, "OutP->%s", arg->argMsgField); + (void)sprintf(string, "OutP->%s.", arg->argMsgField); + } + + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + if (IS_MULTIPLE_KPD(it) && it->itVarArray) + fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string); + if (arg->argPoly == argNULL) { + if (IsKernelServer) { + fprintf(file, "#if __MigKernelSpecificCode\n"); + fprintf(file, "\t%sdisposition = %s;\n", string, it->itOutNameStr); + fprintf(file, "#else\n"); + } + fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr); + if (IsKernelServer) + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + fprintf(file, "#if !(defined(KERNEL) && defined(__LP64__))\n"); + fprintf(file, "\t%spad1 = 0;\n", string); + fprintf(file, "#endif\n"); + fprintf(file, "\t%spad2 = 0;\n", string); + fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string); + fprintf(file, "#if defined(KERNEL)\n"); + fprintf(file, "\t%spad_end = 0;\n", string); + fprintf(file, "#endif\n"); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + if (close) + fprintf(file, "\t }\n\t}\n"); + fprintf(file, "\n"); +} + +/* + * argKPD_Init discipline for out-of-line types. + */ +static void +WriteInitKPD_ool(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char firststring[MAX_STR_LEN]; + char string[MAX_STR_LEN]; + boolean_t VarArray; + u_int howmany, howbig; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE); + (void)sprintf(firststring, "\t*ptr"); + (void)sprintf(string, "\tptr->"); + VarArray = it->itElement->itVarArray; + howmany = it->itElement->itNumber; + howbig = it->itElement->itSize; + } + else { + (void)sprintf(firststring, "OutP->%s", arg->argMsgField); + (void)sprintf(string, "OutP->%s.", arg->argMsgField); + VarArray = it->itVarArray; + howmany = it->itNumber; + howbig = it->itSize; + } + + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + if (!VarArray) + fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8); + if (arg->argDeallocate != d_MAYBE) + fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); + fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY"); +#ifdef ALIGNMENT + fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, arg->argMsgField, (howbig < 8) ? 1 : howbig / 8); +#endif + fprintf(file, "\t%spad1 = 0;\n", string); + fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string); + fprintf(file, "#if defined(KERNEL) && !defined(__LP64__)\n"); + fprintf(file, "\t%spad_end = 0;\n", string); + fprintf(file, "#endif\n"); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n\t}\n"); + fprintf(file, "\n"); +} + +/* + * argKPD_Init discipline for out-of-line Port types. + */ +static void +WriteInitKPD_oolport(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + boolean_t VarArray; + ipc_type_t *howit; + u_int howmany; + char firststring[MAX_STR_LEN]; + char string[MAX_STR_LEN]; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE); + (void)sprintf(firststring, "\t*ptr"); + (void)sprintf(string, "\tptr->"); + VarArray = it->itElement->itVarArray; + howmany = it->itElement->itNumber; + howit = it->itElement; + } + else { + (void)sprintf(firststring, "OutP->%s", arg->argMsgField); + (void)sprintf(string, "OutP->%s.", arg->argMsgField); + VarArray = it->itVarArray; + howmany = it->itNumber; + howit = it; + } + + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + + if (!VarArray) + fprintf(file, "\t%scount = %d;\n", string, howmany); + if (arg->argPoly == argNULL) { + if (IsKernelServer) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + fprintf(file, "\t%sdisposition = %s;\n", string, howit->itOutNameStr); + fprintf(file, "#else\n"); + } + fprintf(file, "\t%sdisposition = %s;\n", string, howit->itInNameStr); + if (IsKernelServer) + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + if (arg->argDeallocate != d_MAYBE) + fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); + fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n\t}\n"); + fprintf(file, "\n"); +} + +static void +WriteInitKPDValue(FILE *file, argument_t *arg) +{ + (*arg->argKPD_Init)(file, arg); +} + +static void +WriteAdjustMsgCircular(FILE *file, argument_t *arg) +{ + fprintf(file, "\n"); + + fprintf(file,"#if\t__MigKernelSpecificCode\n"); + if (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC) + fprintf(file, "\tif (%s == MACH_MSG_TYPE_PORT_RECEIVE)\n", arg->argPoly->argVarName); + + /* + * The carried port right can be accessed in OutP->XXXX. Normally + * the server function stuffs it directly there. If it is InOut, + * then it has already been copied into the reply message. + * If the server function deposited it into a variable (perhaps + * because the reply message is variable-sized) then it has already + * been copied into the reply message. + * + * The old MiG does not check for circularity in the case of + * array of ports. So do I ... + */ + + fprintf(file, "\t if (IP_VALID((ipc_port_t) In0P->Head.msgh_reply_port) &&\n"); + fprintf(file, "\t IP_VALID((ipc_port_t) OutP->%s.name) &&\n", arg->argMsgField); + fprintf(file, "\t ipc_port_check_circularity((ipc_port_t) OutP->%s.name, (ipc_port_t) In0P->Head.msgh_reply_port))\n", arg->argMsgField); + fprintf(file, "\t\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;\n"); + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); +} + +/* + * argKPD_Pack discipline for Port types. + */ +static void +WriteKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *subindex = ""; + char *recast = ""; + boolean_t close = FALSE; + char string[MAX_STR_LEN]; + ipc_type_t *real_it; + + if (akCheck(arg->argKind, akbVarNeeded)) { + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE); + (void)sprintf(string, "\tptr->"); + subindex = "[i]"; + close = TRUE; + real_it = it->itElement; + } + else { + (void)sprintf(string, "OutP->%s.", arg->argMsgField); + real_it = it; + } +#ifdef MIG_KERNEL_PORT_CONVERSIONS + if (IsKernelServer && streql(real_it->itTransType, "ipc_port_t")) + recast = "(mach_port_t)"; +#endif + + if (it->itOutTrans != strNULL && !close) + fprintf(file, "\t%sname = (mach_port_t)%s(%s);\n", string, it->itOutTrans, arg->argVarName); + else + fprintf(file, "\t%sname = %s%s%s;\n", string, recast, arg->argVarName, subindex); + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd)) { + argument_t *poly = arg->argPoly; + + if (akCheck(arg->argPoly->argKind, akbVarNeeded)) + fprintf(file, "\t%sdisposition = %s;\n", string, poly->argVarName); + else if (close) + fprintf(file, "\t%sdisposition = OutP->%s;\n", string, poly->argSuffix); + } + if (close) + fprintf(file, "\t }\n\t}\n"); + fprintf(file, "\n"); + } + else if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd|akbVarNeeded)) + fprintf(file, "\tOutP->%s.disposition = %s;\n", arg->argMsgField, arg->argPoly->argVarName); + /* + * If this is a KernelServer, and the reply message contains + * a receive right, we must check for the possibility of a + * port/message circularity. If queueing the reply message + * would cause a circularity, we mark the reply message + * with the circular bit. + */ + if (IsKernelServer && !(IS_MULTIPLE_KPD(it)) && + ((arg->argType->itOutName == MACH_MSG_TYPE_PORT_RECEIVE) || + (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC))) + WriteAdjustMsgCircular(file, arg); +} + +/* + * argKPD_Pack discipline for out-of-line types. + */ +static void +WriteKPD_ool(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char string[MAX_STR_LEN]; + boolean_t VarArray; + argument_t *count; + u_int howbig; + char *subindex; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE); + (void)sprintf(string, "\tptr->"); + VarArray = it->itElement->itVarArray; + count = arg->argSubCount; + howbig = it->itElement->itSize; + subindex = "[i]"; + } + else { + (void)sprintf(string, "OutP->%s.", arg->argMsgField); + VarArray = it->itVarArray; + count = arg->argCount; + howbig = it->itSize; + subindex = ""; + } + + if (akCheck(arg->argKind, akbVarNeeded)) + fprintf(file, "\t%saddress = (void *)%s%s;\n", string, arg->argMsgField, subindex); + if (arg->argDealloc != argNULL) + if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it)) + fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); + if (VarArray) { + fprintf(file, "\t%ssize = ", string); + if (akCheck(count->argKind, akbVarNeeded)) + fprintf(file, "%s%s", count->argName, subindex); + else + fprintf(file, "OutP->%s%s", count->argMsgField, subindex); + + if (count->argMultiplier > 1 || howbig > 8) + fprintf(file, " * %d;\n", count->argMultiplier * howbig / 8); + else + fprintf(file, ";\n"); + } + + if (IS_MULTIPLE_KPD(it)) { + fprintf(file, "\t }\n"); + if (it->itVarArray && !it->itElement->itVarArray) { + fprintf(file, "\t for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number); + /* since subordinate arrays aren't variable, they are initialized from template: + here we must no-op 'em */ + fprintf(file, "\t\tptr->size = 0;\n"); + } + fprintf(file, "\t}\n"); + } + fprintf(file, "\n"); +} + +/* + * argKPD_Pack discipline for out-of-line Port types. + */ +static void +WriteKPD_oolport(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + boolean_t VarArray; + argument_t *count; + char *subindex, string[MAX_STR_LEN]; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE); + (void)sprintf(string, "\tptr->"); + VarArray = it->itElement->itVarArray; + count = arg->argSubCount; + subindex = "[i]"; + } + else { + (void)sprintf(string, "OutP->%s.", arg->argMsgField); + VarArray = it->itVarArray; + count = arg->argCount; + subindex = ""; + } + + if (akCheck(arg->argKind, akbVarNeeded)) + fprintf(file, "\t%saddress = (void *)%s%s;\n", string, arg->argMsgField, subindex); + if (arg->argDealloc != argNULL) + if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it)) + fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); + if (VarArray) { + fprintf(file, "\t%scount = ", string); + if (akCheck(count->argKind, akbVarNeeded)) + fprintf(file, "%s%s;\n", count->argName, subindex); + else + fprintf(file, "OutP->%s%s;\n", count->argMsgField, subindex); + } + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd)) + if (akCheck(arg->argPoly->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it)) + fprintf(file, "\t%sdisposition = %s;\n", string, arg->argPoly->argVarName); + if (IS_MULTIPLE_KPD(it)) { + fprintf(file, "\t }\n"); + if (it->itVarArray && !it->itElement->itVarArray) { + fprintf(file, "\t for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number); + /* since subordinate arrays aren't variable, they are initialized from template: + here we must no-op 'em */ + fprintf(file, "\t%scount = 0;\n", string); + } + fprintf(file, "\t}\n"); + } + fprintf(file, "\n"); +} + +/* + * argKPD_TypeCheck discipline for Port types. + */ +static void +WriteTCheckKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *tab = ""; + char string[MAX_STR_LEN]; + boolean_t close = FALSE; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE); + (void)sprintf(string, "ptr->"); + tab = "\t"; + close = TRUE; + } + else + (void)sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField); + + fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string); + /* + * We can't check disposition on varArray + * (because some of the entries could be empty). + */ + if (!it->itVarArray) { + if (arg->argPoly != argNULL) { + switch (it->itOutName) { + + case MACH_MSG_TYPE_MOVE_RECEIVE: + fprintf(file, " || \n\t%s %sdisposition != MACH_MSG_TYPE_MOVE_RECEIVE", tab, string); + break; + + case MACH_MSG_TYPE_MOVE_SEND_ONCE: + fprintf(file, " || (\n\t%s %sdisposition != MACH_MSG_TYPE_MOVE_SEND_ONCE", tab, string); + fprintf(file, " && \n\t%s %sdisposition != MACH_MSG_TYPE_MAKE_SEND_ONCE)", tab, string); + break; + + case MACH_MSG_TYPE_MOVE_SEND: + fprintf(file, " || (\n\t%s %sdisposition != MACH_MSG_TYPE_MOVE_SEND", tab, string); + fprintf(file, " && \n\t%s %sdisposition != MACH_MSG_TYPE_MAKE_SEND", tab, string); + fprintf(file, " && \n\t%s %sdisposition != MACH_MSG_TYPE_COPY_SEND)", tab, string); + break; + } + } + else { + fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr); + } + } + fprintf(file, ")\n"); + fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n"); + if (close) + fprintf(file, "\t }\n\t}\n"); +} + +/* + * argKPD_TypeCheck discipline for out-of-line types. + */ +static void +WriteTCheckKPD_ool(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *tab, string[MAX_STR_LEN]; + boolean_t test; + u_int howmany, howbig; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE); + tab = "\t\t\t"; + sprintf(string, "ptr->"); + howmany = it->itElement->itNumber; + howbig = it->itElement->itSize; + test = !it->itVarArray && !it->itElement->itVarArray; + } + else { + tab = ""; + sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField); + howmany = it->itNumber; + howbig = it->itSize; + test = !it->itVarArray; + } + + fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string); + if (test) { + /* if VarArray we may use no-op; if itElement->itVarArray size might change */ + fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8); + } + + fprintf(file, ")\n"); + fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); + + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n\t}\n"); +} + +/* + * argKPD_TypeCheck discipline for out-of-line Port types. + */ +static void +WriteTCheckKPD_oolport(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *tab, string[MAX_STR_LEN]; + boolean_t test; + u_int howmany; + char *howstr; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + howmany = it->itElement->itNumber; + test = !it->itVarArray && !it->itElement->itVarArray; + howstr = it->itElement->itOutNameStr; + } + else { + tab = ""; + sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField); + howmany = it->itNumber; + test = !it->itVarArray; + howstr = it->itOutNameStr; + } + + fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string); + if (test) + /* if VarArray we may use no-op; if itElement->itVarArray size might change */ + fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany); + if (arg->argPoly == argNULL) + fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr); + fprintf(file, ")\n"); + fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n"); + + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n\t}\n"); +} + +/************************************************************* + * Writes code to check that the type of each of the arguments + * in the reply message is what is expected. Called by + * WriteRoutine for each in && typed argument in the request message. + *************************************************************/ +static void +WriteTypeCheck(FILE *file, argument_t *arg) +{ + fprintf(file, "#if\t__MigTypeCheck\n"); + (*arg->argKPD_TypeCheck)(file, arg); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); +} + +static void +WritePackArgValueNormal(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) { + if (it->itString) { + /* + * Copy variable-size C string with mig_strncpy. + * Save the string length (+ 1 for trailing 0) + * in the argument`s count field. + */ + fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n"); + fprintf(file, "\t\tOutP->%s = (%s) mig_strncpy_zerofill(OutP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber); + fprintf(file, "\t} else {\n"); + fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); + + fprintf(file, "\t\tOutP->%s = (%s) mig_strncpy(OutP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber); + + fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "\t}\n"); + fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); + + fprintf(file, "\tOutP->%sOffset = 0;\n", arg->argMsgField); + } + else if (it->itNoOptArray) + fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, %d);\n", arg->argMsgField, arg->argVarName, it->itTypeSize); + else { + argument_t *count = arg->argCount; + ipc_type_t *btype = it->itElement; + identifier_t newstr; + + /* Note btype->itNumber == count->argMultiplier */ + + fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, ", arg->argMsgField, arg->argVarName); + if (btype->itTypeSize > 1) + fprintf(file, "%d * ", btype->itTypeSize); + /* count is a akbVarNeeded if arg is akbVarNeeded */ + if (akCheck(count->argKind, akbVarNeeded)) + newstr = count->argVarName; + else + newstr = (identifier_t)strconcat("OutP->", count->argMsgField); + fprintf(file, "%s);\n", newstr); + } + } + else if (it->itOutTrans != strNULL) + WriteCopyType(file, it, TRUE, "OutP->%s", "/* %s */ %s(%s)", arg->argMsgField, it->itOutTrans, arg->argVarName); + else + WriteCopyType(file, it, TRUE, "OutP->%s", "/* %s */ %s", arg->argMsgField, arg->argVarName); + + if (arg->argPadName != NULL && it->itPadSize != 0) { + fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize); + fprintf(file, "\t\t OutP->%s[i] = 0;\n", arg->argPadName); + } +} + +static void +WritePackArgValueVariable(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + /* + * only itString are treated here so far + */ + if (it->itString) { + /* + * Emit logic to call strlen to calculate the size of the argument, and ensure that it fits within the 32-bit result field + * in the Reply, when targeting a 64-bit architecture. If a 32-bit architecture is the target, we emit code to just call + * strlen() directly (since it'll return a 32-bit value that is guaranteed to fit). + */ + fputs("#ifdef __LP64__\n", file); + fprintf(file, "\t{\n" + "\t\t" "size_t strLength = strlen(OutP->%s) + 1;\n", arg->argMsgField); + fputs( "\t\t" "if (strLength > 0xffffffff)\n" + "\t\t\t" "MIG_RETURN_ERROR(OutP, MIG_BAD_ARGUMENTS);\n", file); + fprintf(file, "\t\t" "OutP->%s = (mach_msg_type_number_t) strLength;\n" + "\t}\n", arg->argCount->argMsgField); + fputs("#else\n", file); + fprintf(file, "\tOutP->%s = (mach_msg_type_number_t) strlen(OutP->%s) + 1;\n", arg->argCount->argMsgField, arg->argMsgField); + fputs("#endif /* __LP64__ */\n", file); + + } +} + +static void +WriteCopyArgValue(FILE *file, argument_t *arg) +{ + fprintf(file, "\n"); + WriteCopyType(file, arg->argType, TRUE, "/* %d */ OutP->%s", "In%dP->%s", arg->argRequestPos, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField); +} + +static void +WriteInitArgValue(FILE *file, argument_t *arg) +{ + fprintf(file, "\n"); + fprintf(file, "\tOutP->%s = %s;\n\n", arg->argMsgField, arg->argVarName); +} + +/* + * Calculate the size of a variable-length message field. + */ +static void +WriteArgSize(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argType; + int bsize = ptype->itElement->itTypeSize; + argument_t *count = arg->argCount; + + /* If the base type size of the data field isn`t a multiple of 4, + we have to round up. */ + if (bsize % itWordAlign != 0) + fprintf(file, "_WALIGN_"); + + /* Here, we generate ((value + %d) & ~%d). We have to put two (( at the + * the beginning. + */ + fprintf(file, "(("); + if (bsize > 1) + fprintf(file, "%d * ", bsize); + if (ptype->itString || !akCheck(count->argKind, akbVarNeeded)) + /* get count from descriptor in message */ + fprintf(file, "OutP->%s", count->argMsgField); + else + /* get count from argument */ + fprintf(file, "%s", count->argVarName); + + /* + * If the base type size is not a multiple of sizeof(natural_t), + * we have to round up. + */ + if (bsize % sizeof(natural_t) != 0) + fprintf(file, " + %d) & ~%d)", (int)sizeof(natural_t)-1, (int)sizeof(natural_t)-1); + else + fprintf(file, "))"); +} + +/* + * Adjust message size and advance reply pointer. + * Called after packing a variable-length argument that + * has more arguments following. + */ +static void +WriteAdjustMsgSize(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + ipc_type_t *ptype = arg->argType; + + /* There are more Out arguments. We need to adjust msgh_size + and advance OutP, so we save the size of the current field + in msgh_size_delta. */ + + fprintf(file, "\tmsgh_size_delta = "); + WriteArgSize(file, arg); + fprintf(file, ";\n"); + + if (rt->rtNumReplyVar == 1) { + /* We can still address the message header directly. Fill + in the size field. */ + + fprintf(file, "\tOutP->Head.msgh_size = "); + rtMinReplySize(file, rt, "Reply"); + fprintf(file, " + msgh_size_delta;\n"); + } + else if (arg->argReplyPos == 0) { + /* First variable-length argument. The previous msgh_size value + is the minimum reply size. */ + + fprintf(file, "\tmsgh_size = "); + rtMinReplySize(file, rt, "Reply"); + fprintf(file, " + msgh_size_delta;\n"); + } + else + fprintf(file, "\tmsgh_size += msgh_size_delta;\n"); + + fprintf(file, "\tOutP = (Reply *) ((pointer_t) OutP + msgh_size_delta - %d);\n", ptype->itTypeSize + ptype->itPadSize); +} + +/* + * Calculate the size of the message. Called after the + * last argument has been packed. + */ +static void +WriteFinishMsgSize(FILE *file, argument_t *arg) +{ + /* No more Out arguments. If this is the only variable Out + argument, we can assign to msgh_size directly. */ + + if (arg->argReplyPos == 0) { + fprintf(file, "\tOutP->Head.msgh_size = "); + rtMinReplySize(file, arg->argRoutine, "Reply"); + fprintf(file, " + ("); + WriteArgSize(file, arg); + fprintf(file, ");\n"); + } + else { + fprintf(file, "\tmsgh_size += "); + WriteArgSize(file, arg); + fprintf(file, ";\n"); + } +} + +/* + * Handle reply arguments - fill in message types and copy arguments + * that need to be copied. + */ +static void +WriteReplyArgs(FILE *file, routine_t *rt) +{ + argument_t *arg; + argument_t *lastVarArg; + + /* + * 1. The Kernel Processed Data + */ + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD)) + (*arg->argKPD_Pack)(file, arg); + /* + * 2. The Data Stream + */ + lastVarArg = argNULL; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + /* + * Adjust message size and advance message pointer if + * the last request argument was variable-length and the + * request position will change. + */ + if (lastVarArg != argNULL && + lastVarArg->argReplyPos < arg->argReplyPos) { + WriteAdjustMsgSize(file, lastVarArg); + lastVarArg = argNULL; + } + + if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVarNeeded)) + WritePackArgValueNormal(file, arg); + else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable)) + WritePackArgValueVariable(file, arg); + + if (akCheck(arg->argKind, akbReplyCopy)) + WriteCopyArgValue(file, arg); + if (akCheck(arg->argKind, akbReplyInit)) + WriteInitArgValue(file, arg); + /* + * Remember whether this was variable-length. + */ + if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable)) + lastVarArg = arg; + } + /* + * Finish the message size. + */ + if (lastVarArg != argNULL) + WriteFinishMsgSize(file, lastVarArg); +} + +static void +WriteFieldDecl(FILE *file, argument_t *arg) +{ + if (akCheck(arg->argKind, akbSendKPD) || + akCheck(arg->argKind, akbReturnKPD)) + WriteFieldDeclPrim(file, arg, FetchKPDType); + else + WriteFieldDeclPrim(file, arg, FetchServerType); +} + +static void +InitKPD_Disciplines(argument_t *args) +{ + argument_t *arg; + extern void KPD_noop(FILE *file, argument_t *arg); + extern void KPD_error(FILE *file, argument_t *arg); + extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in); + extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in); + extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in); + + /* + * WriteInitKPD_port, WriteKPD_port, WriteExtractKPD_port, + * WriteInitKPD_ool, WriteKPD_ool, WriteExtractKPD_ool, + * WriteInitKPD_oolport, WriteKPD_oolport, WriteExtractKPD_oolport + * are local to this module (which is the reason why this initialization + * takes place here rather than in utils.c). + * Common routines for user and server will be established SOON, and + * all of them (including the initialization) will be transfert to + * utils.c + * All the KPD disciplines are defaulted to be KPD_error(). + * Note that akbSendKPD and akbReturnKPd are not exclusive, + * because of inout type of parameters. + */ + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + if akCheck(arg->argKind, akbSendKPD) { + arg->argKPD_Extract = + (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_port : WriteExtractArgValue; + arg->argKPD_TypeCheck = WriteTCheckKPD_port; + } + if akCheck(arg->argKind, akbReturnKPD) { + arg->argKPD_Template = WriteTemplateKPD_port; + arg->argKPD_Init = WriteInitKPD_port; + arg->argKPD_Pack = WriteKPD_port; + } + break; + + case MACH_MSG_OOL_DESCRIPTOR: + if akCheck(arg->argKind, akbSendKPD) { + arg->argKPD_Extract = + (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_ool : WriteExtractArgValue; + arg->argKPD_TypeCheck = WriteTCheckKPD_ool; + } + if akCheck(arg->argKind, akbReturnKPD) { + arg->argKPD_Template = WriteTemplateKPD_ool; + arg->argKPD_Init = WriteInitKPD_ool; + arg->argKPD_Pack = WriteKPD_ool; + } + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + if akCheck(arg->argKind, akbSendKPD) { + arg->argKPD_Extract = + (IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_oolport : WriteExtractArgValue; + arg->argKPD_TypeCheck = WriteTCheckKPD_oolport; + } + if akCheck(arg->argKind, akbReturnKPD) { + arg->argKPD_Template = WriteTemplateKPD_oolport; + arg->argKPD_Init = WriteInitKPD_oolport; + arg->argKPD_Pack = WriteKPD_oolport; + } + break; + + default: + printf("MiG internal error: type of kernel processed data unknown\n"); + exit(1); + } /* end of switch */ +} + +static void WriteStringTerminatorCheck(FILE *file, routine_t *rt) +{ + // generate code to verify that the length of a C string is not greater than the size of the + // buffer in which it is stored. + argument_t *argPtr; + int msg_limit_calculated = FALSE; + int found_string_argument = FALSE; + int variable_length_args_present = (rt->rtMaxRequestPos > 0); + + // scan through arguments to see if there are any strings + for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) { + if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) { + found_string_argument = TRUE; + break; + } + } + + if (found_string_argument) { + // create a new scope, for local variables + fputs("#if __MigTypeCheck\n" "\t" "{" "\n", file); + + for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) { + if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) { + //fprintf(stderr, "### found itString: variable name = %s, max length = %d\n", argPtr->argName, argPtr->argType->itNumber); + + if (!msg_limit_calculated) { + msg_limit_calculated = TRUE; // only need to do this once + fputs("\t\t" "char * msg_limit = ((char *) In0P) + In0P->Head.msgh_size;\n", file); + if (IsKernelServer) { + fputs("#if __MigKernelSpecificCode\n", file); + fputs("\t\t" "size_t strnlen_limit;" "\n", file); + fputs("#else\n", file); + } + fputs("\t\t" "size_t memchr_limit;" "\n", file); + if (IsKernelServer) { + fputs("#endif /* __MigKernelSpecificCode */" "\n", file); + } + fputc('\n', file); + } + + // I would really prefer to use strnlen() here, to ensure that the byte scanning logic does not extend beyond + // the end of the buffer, but it's not necessarily guaranteed to be available. Instead, I'll use memchr(), + // and let it look for the terminating null byte. + // (later...) + // It turns out that the kernel does not have memchr() available, but strnlen() IS available, so we'll just + // have to emit some conditional code to use the appropriate runtime environment scanning function. + // + if (IsKernelServer) { + fputs("#if __MigKernelSpecificCode\n", file); + fputs("\t\t" "strnlen_limit = min((msg_limit - ", file); + // If there are variable-length arguments within the message, the proper (adjusted) + // pointers must be used to access those strings + fprintf(file, "In%dP->%s), %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber); + fputs("\t\t" "if (", file); + fprintf(file, "( strnlen(In%dP->%s, strnlen_limit) >= %d + 1 )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber); + fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file); + fputs("#else\n", file); + } + // If there are variable-length arguments within the message, the proper (adjusted) + // pointers must be used to access those strings + fprintf(file, "\t\t" "memchr_limit = min((msg_limit - In%dP->%s), %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber); + fputs("\t\t" "if (", file); + fprintf(file, "( memchr(In%dP->%s, '\\0', memchr_limit) == NULL )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName); + fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file); + if (IsKernelServer) { + fputs("#endif /* __MigKernelSpecificCode */" "\n", file); + } + } + } + fputs("\t" "}" "\n" "#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); // terminate new scope + } + + return; +} + +static void +WriteOOLSizeCheck(FILE *file, routine_t *rt) +{ + /* Emit code to validate the actual size of ool data vs. the reported size */ + + argument_t *argPtr; + boolean_t openedTypeCheckConditional = FALSE; + + // scan through arguments to see if there are any ool data blocks + for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) { + if (akCheck(argPtr->argKind, akbSendKPD)) { + ipc_type_t *it = argPtr->argType; + boolean_t multiple_kpd = IS_MULTIPLE_KPD(it); + char string[MAX_STR_LEN]; + boolean_t test; + argument_t *argCountPtr; + char *tab; + + if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { + + if (multiple_kpd) { + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + WriteKPD_Iterator(file, TRUE, FALSE, argPtr, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + test = !it->itVarArray && !it->itElement->itVarArray; + it = it->itElement; // point to element descriptor, so size calculation is correct + argCountPtr = argPtr->argSubCount; + } else { + tab = ""; + sprintf(string, "In%dP->%s.", argPtr->argRequestPos, argPtr->argMsgField); + test = !it->itVarArray; + argCountPtr = argPtr->argCount; + } + + if (!test) { + int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1; + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + + fprintf(file, "\t%s" "if (%ssize ", tab, string); + if (multiplier > 1) + fprintf(file, "/ %d ", multiplier); + fprintf(file,"!= In%dP->%s%s", argCountPtr->argRequestPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : ""); + if (it->itOOL_Number) { + fprintf(file," || In%dP->%s%s > %d", argCountPtr->argRequestPos, + argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number); + } + + fprintf(file,")\n"); + fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); + } + + if (multiple_kpd) + fprintf(file, "\t }\n\t}\n"); + } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) { + if (multiple_kpd) { + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + WriteKPD_Iterator(file, TRUE, FALSE, argPtr, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + test = !it->itVarArray && !it->itElement->itVarArray; + it = it->itElement; // point to element descriptor, so size calculation is correct + argCountPtr = argPtr->argSubCount; + } else { + tab = ""; + sprintf(string, "In%dP->%s.", argPtr->argRequestPos, argPtr->argMsgField); + test = !it->itVarArray; + argCountPtr = argPtr->argCount; + } + + if (!test) { + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + + fprintf(file, "\t%s" "if (%scount ", tab, string); + fprintf(file,"!= In%dP->%s%s", argCountPtr->argRequestPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : ""); + if (it->itOOL_Number) { + fprintf(file," || In%dP->%s%s > %d", argCountPtr->argRequestPos, + argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number); + } + fprintf(file,")\n"); + fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); + } + + if (multiple_kpd) + fprintf(file, "\t }\n\t}\n"); + } + } + } + + if ( openedTypeCheckConditional ) + fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); +} + + +void +WriteCheckRequest(FILE *file, routine_t *rt) +{ + int i; + + /* initialize the disciplines for the handling of KPDs */ + InitKPD_Disciplines(rt->rtArgs); + + fprintf(file, "\n"); + fprintf(file, "#if ( __MigTypeCheck "); + if (CheckNDR) + fprintf(file, "|| __NDR_convert__ "); + fprintf(file, ")\n"); + fprintf(file, "#if __MIG_check__Request__%s_subsystem__\n", SubsystemName); + fprintf(file, "#if !defined(__MIG_check__Request__%s_t__defined)\n", rt->rtName); + fprintf(file, "#define __MIG_check__Request__%s_t__defined\n", rt->rtName); + if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) { + WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgDecl, akbSendNdr, "", ""); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgDecl, akbSendNdr, "", ""); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgDecl, akbSendNdr, "", ""); + } + fprintf(file, "\n"); + fprintf(file, "mig_internal kern_return_t __MIG_check__Request__%s_t(__attribute__((__unused__)) __Request__%s_t *In0P", rt->rtName, rt->rtName); + for (i = 1; i <= rt->rtMaxRequestPos; i++) + fprintf(file, ", __attribute__((__unused__)) __Request__%s_t **In%dPP", rt->rtName, i); + fprintf(file, ")\n{\n"); + + fprintf(file, "\n\ttypedef __Request__%s_t __Request;\n", rt->rtName); + for (i = 1; i <= rt->rtMaxRequestPos; i++) + fprintf(file, "\t__Request *In%dP;\n", i); + if (rt->rtNumRequestVar > 0) { + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tunsigned int msgh_size;\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + if (rt->rtMaxRequestPos > 0) + fprintf(file, "\tunsigned int msgh_size_delta;\n"); + if (rt->rtNumRequestVar > 0 || rt->rtMaxRequestPos > 0) + fprintf(file, "\n"); + + WriteCheckHead(file, rt); + + WriteList(file, rt->rtArgs, WriteTypeCheck, akbSendKPD, "\n", "\n"); + + { + argument_t *arg, *lastVarArg; + + lastVarArg = argNULL; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (lastVarArg != argNULL && + lastVarArg->argRequestPos < arg->argRequestPos) { + WriteAdjustRequestMsgPtr(file, lastVarArg); + lastVarArg = argNULL; + } + if (akCheckAll(arg->argKind, akbSendRcv|akbSendBody)) { + if (akCheck(arg->argKind, akbVariable)) { + WriteCheckMsgSize(file, arg); + lastVarArg = arg; + } + } + } + } + + if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) { + fprintf(file, "#if\t"); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgCond, akbSendNdr, " || \\\n\t", "\n"); + fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep) {\n"); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgUse, akbSendNdr, "", ""); + fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n"); + + WriteOOLSizeCheck(file, rt); + + fprintf(file, "#if\t"); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgCond, akbSendNdr, " || \\\n\t", "\n"); + fprintf(file, "\tif (In0P->NDR.char_rep != NDR_record.char_rep) {\n"); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgUse, akbSendNdr, "", ""); + fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n"); + + fprintf(file, "#if\t"); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgCond, akbSendNdr, " || \\\n\t", "\n"); + fprintf(file, "\tif (In0P->NDR.float_rep != NDR_record.float_rep) {\n"); + WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgUse, akbSendNdr, "", ""); + fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n"); + } else { + WriteOOLSizeCheck(file, rt); + } + + WriteStringTerminatorCheck(file, rt); + + fprintf(file, "\treturn MACH_MSG_SUCCESS;\n"); + fprintf(file, "}\n"); + fprintf(file, "#endif /* !defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName); + fprintf(file, "#endif /* __MIG_check__Request__%s_subsystem__ */\n", SubsystemName); + fprintf(file, "#endif /* ( __MigTypeCheck "); + if (CheckNDR) + fprintf(file, "|| __NDR_convert__ "); + fprintf(file, ") */\n"); + fprintf(file, "\n"); +} + +void +WriteCheckRequestCall(FILE *file, routine_t *rt) +{ + int i; + + fprintf(file, "\n"); + fprintf(file, "#if\tdefined(__MIG_check__Request__%s_t__defined)\n", rt->rtName); + fprintf(file, "\tcheck_result = __MIG_check__Request__%s_t((__Request *)In0P", rt->rtName); + for (i = 1; i <= rt->rtMaxRequestPos; i++) + fprintf(file, ", (__Request **)&In%dP", i); + fprintf(file, ");\n"); + fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS)\n"); + fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, check_result); }\n"); + fprintf(file, "#endif\t/* defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName); + fprintf(file, "\n"); +} + +void +WriteCheckRequests(FILE *file, statement_t *stats) +{ + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) + WriteCheckRequest(file, stat->stRoutine); +} + +static void +WriteRoutine(FILE *file, routine_t *rt) +{ + /* Declare the server work function: */ + if (ServerHeaderFileName == strNULL) + WriteServerRoutine(file, rt); + + fprintf(file, "\n"); + + fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName); + fprintf(file, "mig_internal novalue _X%s\n", rt->rtName); + if (BeAnsiC) { + fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n"); + fprintf(file, "#else\n"); + fprintf(file, "\t(InHeadP, OutHeadP)\n"); + fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + + fprintf(file, "{\n"); + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, TRUE, rt->rtServerImpl, FALSE); + fprintf(file, "\ttypedef __Request__%s_t __Request;\n", rt->rtName); + fprintf(file, "\ttypedef __Reply__%s_t Reply __attribute__((unused));\n\n", rt->rtName); + + /* + * Define a Minimal Reply structure to be used in case of errors + */ + fprintf(file, "\t/*\n"); + fprintf(file, "\t * typedef struct {\n"); + fprintf(file, "\t * \tmach_msg_header_t Head;\n"); + fprintf(file, "\t * \tNDR_record_t NDR;\n"); + fprintf(file, "\t * \tkern_return_t RetCode;\n"); + fprintf(file, "\t * } mig_reply_error_t;\n"); + fprintf(file, "\t */\n"); + fprintf(file, "\n"); + + WriteVarDecls(file, rt); + + if (IsKernelServer) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + WriteList(file, rt->rtArgs, WriteTemplateDeclOut, akbReturnKPD, "\n", "\n"); + fprintf(file, "#else\n"); + } + WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbReturnKPD, "\n", "\n"); + if (IsKernelServer) { + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + WriteRetCode(file, rt->rtRetCode); + WriteList(file, rt->rtArgs, WriteLocalVarDecl, akbVarNeeded | akbServerArg, ";\n", ";\n\n"); + WriteApplMacro(file, "Rcv", "Declare", rt); + WriteApplMacro(file, "Rcv", "Before", rt); + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + WriteRetCArgCheckError(file, rt); + if (rt->rtServerImpl) + WriteCheckTrailerHead(file, rt, FALSE); + WriteServerCall(file, rt, WriteConditionalCallArg); + WriteRetCArgFinishError(file, rt); + } + + WriteCheckRequestCall(file, rt); + WriteCheckRequestTrailerArgs(file, rt); + + /* + * Initialize the KPD records in the Reply structure with the + * templates. We do this beforehand because the call to the procedure + * will overwrite some of the values (after the call it would be impossible + * to initialize the KPD records from the static Templates, because we + * would lose data). + */ + WriteList(file, rt->rtArgs, WriteInitKPDValue, akbReturnKPD, "\n", "\n"); + + WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", ""); + + if (UseEventLogger) + WriteLogMsg(file, rt, LOG_SERVER, LOG_REQUEST); + + WriteServerCall(file, rt, WriteServerCallArg); + + WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", ""); + + /* + * For one-way routines, it doesn`t make sense to check the return + * code, because we return immediately afterwards. However, + * kernel servers may want to deallocate port arguments - and the + * deallocation must not be done if the return code is not KERN_SUCCESS. + */ + if (rt->rtOneWay || rt->rtNoReplyArgs) { + if (IsKernelServer) { + fprintf(file,"#if\t__MigKernelSpecificCode\n"); + if (rtCheckMaskFunction(rt->rtArgs, akbSendKPD, CheckDestroyPortArg)) { + WriteCheckReturnValue(file, rt); + } + WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", ""); + fprintf(file,"#endif /* __MigKernelSpecificCode */\n"); + } + /* although we have an empty reply, we still have to make sure that + some fields such as NDR get properly initialized */ + if (!rt->rtOneWay) + WriteList(file, rt->rtArgs, WriteInitArgValue, akbReplyInit, "\n", "\n"); + } + else { + WriteCheckReturnValue(file, rt); + + if (IsKernelServer) { + fprintf(file,"#if\t__MigKernelSpecificCode\n"); + WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", ""); + fprintf(file,"#endif /* __MigKernelSpecificCode */\n"); + } + WriteReplyArgs(file, rt); + WriteReplyInit(file, rt); + if (!rt->rtSimpleReply) + fprintf(file, "\tOutP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtReplyKPDs); + } + if (UseEventLogger) + WriteLogMsg(file, rt, LOG_SERVER, LOG_REPLY); + + WriteApplMacro(file, "Rcv", "After", rt); + fprintf(file, "}\n"); +} + +void +WriteServer(FILE *file, statement_t *stats) +{ + statement_t *stat; + + WriteProlog(file, stats); + if (BeAnsiC) + WriteForwardDeclarations(file, stats); + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skRoutine: + WriteCheckRequest(file, stat->stRoutine); + WriteRoutine(file, stat->stRoutine); + break; + + case skIImport: + case skImport: + case skSImport: + case skDImport: + case skUImport: + break; + + default: + fatal("WriteServer(): bad statement_kind_t (%d)", + (int) stat->stKind); + } + WriteDispatcher(file, stats); +} diff --git a/bootstrap_cmds/migcom.tproj/statement.c b/bootstrap_cmds/migcom.tproj/statement.c new file mode 100644 index 0000000..5a2476d --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/statement.c @@ -0,0 +1,68 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include "error.h" +#include "alloc.h" +#include "statement.h" + +statement_t *stats = stNULL; +static statement_t **last = &stats; + +statement_t * +stAlloc(void) +{ + statement_t *new; + + new = (statement_t *) malloc(sizeof *new); + if (new == stNULL) + fatal("stAlloc(): %s", strerror(errno)); + *last = new; + last = &new->stNext; + new->stNext = stNULL; + return new; +} diff --git a/bootstrap_cmds/migcom.tproj/statement.h b/bootstrap_cmds/migcom.tproj/statement.h new file mode 100644 index 0000000..ca3f5ba --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/statement.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University + * Extensive revamping. Added polymorphic arguments. + * Allow multiple variable-sized inline arguments in messages. + * + * 27-May-87 Richard Draves (rpd) at Carnegie-Mellon University + * Created. + */ + +#ifndef _STATEMENT_H +#define _STATEMENT_H + +#include "routine.h" + +typedef enum statement_kind +{ + skRoutine, + skImport, + skUImport, + skSImport, + skDImport, + skIImport, + skRCSDecl +} statement_kind_t; + +typedef struct statement +{ + statement_kind_t stKind; + struct statement *stNext; + union + { + /* when stKind == skRoutine */ + routine_t *_stRoutine; + /* when stKind == skImport, skUImport, skSImport, skDImport, skIImport */ + string_t _stFileName; + } data; +} statement_t; + +#define stRoutine data._stRoutine +#define stFileName data._stFileName + +#define stNULL ((statement_t *) 0) + +/* stNext will be initialized to put the statement in the list */ +extern statement_t *stAlloc(void); + +/* list of statements, in order they occur in the .defs file */ +extern statement_t *stats; + +#endif /* _STATEMENT_H */ diff --git a/bootstrap_cmds/migcom.tproj/strdefs.h b/bootstrap_cmds/migcom.tproj/strdefs.h new file mode 100644 index 0000000..00a386d --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/strdefs.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 1999, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * 91/02/05 17:55:57 mrt + * Changed to new Mach copyright + * [91/02/01 17:56:03 mrt] + * + * 90/06/02 15:05:49 rpd + * Created for new IPC. + * [90/03/26 21:13:56 rpd] + * + * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University + * Extensive revamping. Added polymorphic arguments. + * Allow multiple variable-sized inline arguments in messages. + * + * 15-Jun-87 David Black (dlb) at Carnegie-Mellon University + * Fixed strNULL to be the null string instead of the null string + * pointer. + * + * 27-May-87 Richard Draves (rpd) at Carnegie-Mellon University + * Created. + */ + +#ifndef STRDEFS_H +#define STRDEFS_H + +#include +#include + +typedef char *string_t; +typedef string_t identifier_t; + +#define MAX_STR_LEN 200 + +#define strNULL ((string_t) 0) + +extern string_t strmake( char *string ); +extern string_t strconcat( string_t left, string_t right ); +extern string_t strphrase( string_t left, string_t right ); +extern void strfree( string_t string ); + +#define streql(a, b) (strcmp((a), (b)) == 0) + +extern char *strbool( boolean_t bool ); +extern char *strstring( string_t string ); +extern char *toupperstr( char *string ); + +#endif /* STRDEFS_H */ diff --git a/bootstrap_cmds/migcom.tproj/string.c b/bootstrap_cmds/migcom.tproj/string.c new file mode 100644 index 0000000..b7e0355 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/string.c @@ -0,0 +1,132 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include +#include +#include "error.h" +#include "alloc.h" +#include "strdefs.h" + +string_t +strmake(char *string) +{ + string_t saved; + + saved = malloc(strlen(string) + 1); + if (saved == strNULL) + fatal("strmake('%s'): %s", string, strerror(errno)); + return strcpy(saved, string); +} + +string_t +strconcat(string_t left, string_t right) +{ + string_t saved; + + saved = malloc(strlen(left) + strlen(right) + 1); + if (saved == strNULL) + fatal("strconcat('%s', '%s'): %s", left, right, strerror(errno)); + return strcat(strcpy(saved, left), right); +} + +string_t +strphrase(string_t left, string_t right) +{ + string_t saved; + string_t current; + size_t llen; + + llen = strlen(left); + saved = malloc(llen + strlen(right) + 2); + if (saved == strNULL) + fatal("strphrase('%s', '%s'): %s", left, right, strerror(errno)); + strcpy(saved, left); + current = saved + llen; + *(current++) = ' '; + strcpy(current, right); + free(left); + return(saved); +} + +void +strfree(string_t string) +{ + free(string); +} + +char * +strbool(boolean_t bool) +{ + if (bool) + return "TRUE"; + else + return "FALSE"; +} + +char * +strstring(string_t string) +{ + if (string == strNULL) + return "NULL"; + else + return string; +} + +char * +toupperstr(char *p) +{ + char *s = p; + char c; + + while ((c = *s)) { + if (islower(c)) + *s = toupper(c); + s++; + } + return(p); +} diff --git a/bootstrap_cmds/migcom.tproj/type.c b/bootstrap_cmds/migcom.tproj/type.c new file mode 100644 index 0000000..db9473f --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/type.c @@ -0,0 +1,899 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include "type.h" +#include +#include +#include +#include +#include "mig_machine.h" +#include "routine.h" +#include "error.h" +#include "alloc.h" +#include "global.h" +#include + +#define PortSize (sizeof (mach_port_t) * NBBY) + +ipc_type_t *itRetCodeType; /* used for return codes */ +ipc_type_t *itNdrCodeType; /* used for NDR format labels */ +ipc_type_t *itDummyType; /* used for camelot dummy args */ +ipc_type_t *itTidType; /* used for camelot tids */ +ipc_type_t *itRequestPortType; /* used for default Request port arg */ +ipc_type_t *itZeroReplyPortType;/* used for dummy Reply port arg */ +ipc_type_t *itRealReplyPortType;/* used for default Reply port arg */ +ipc_type_t *itWaitTimeType; /* used for dummy WaitTime args */ +ipc_type_t *itMsgOptionType; /* used for dummy MsgOption args */ + +static ipc_type_t *list = itNULL; + +static char *machine_integer_name; +static u_int machine_integer_size; +static u_int machine_integer_bits; + +/* + * Searches for a named type. We use a simple + * self-organizing linked list. + */ +ipc_type_t * +itLookUp(identifier_t name) +{ + ipc_type_t *it, **last; + + for (it = *(last = &list); it != itNULL; it = *(last = &it->itNext)) + if (streql(name, it->itName)) { + /* move this type to the front of the list */ + *last = it->itNext; + it->itNext = list; + list = it; + + return it; + } + + return itNULL; +} + +/* + * Enters a new name-type association into + * our self-organizing linked list. + */ +void +itInsert(identifier_t name, ipc_type_t *it) +{ + it->itName = name; + it->itNext = list; + list = it; +} + +static ipc_type_t * +itAlloc(void) +{ + static ipc_type_t prototype = + { + strNULL, /* identifier_t itName */ + 0, /* ipc_type_t *itNext */ + 0, /* u_int itTypeSize */ + 0, /* u_int itPadSize */ + 0, /* u_int itMinTypeSize */ + 0, /* u_int itInName */ + 0, /* u_int itOutName */ + 0, /* u_int itSize */ + 1, /* u_int itNumber */ + 0, /* u_int itKPD_Number */ + TRUE, /* boolean_t itInLine */ + FALSE, /* boolean_t itMigInLine */ + FALSE, /* boolean_t itPortType */ + strNULL, /* string_t itInNameStr */ + strNULL, /* string_t itOutNameStr */ + TRUE, /* boolean_t itStruct */ + FALSE, /* boolean_t itString */ + FALSE, /* boolean_t itVarArray */ + FALSE, /* boolean_t itNoOptArray */ + FALSE, /* boolean_t itNative */ + FALSE, /* boolean_t itNativePointer */ + itNULL, /* ipc_type_t *itElement */ + strNULL, /* identifier_t itUserType */ + strNULL, /* identifier_t itServerType */ + strNULL, /* identifier_t itTransType */ + strNULL, /* identifier_t itUserKPDType */ + strNULL, /* identifier_t itServerKPDType */ + strNULL, /* identifier_t itInTrans */ + strNULL, /* identifier_t itOutTrans */ + strNULL, /* identifier_t itDestructor */ + }; + ipc_type_t *new; + + new = (ipc_type_t *) malloc(sizeof *new); + if (new == itNULL) + fatal("itAlloc(): %s", strerror(errno)); + *new = prototype; + return new; +} + +/* + * Convert an IPC type-name into a string. + */ +static char * +itNameToString(u_int name) +{ + char buffer[100]; + + (void) sprintf(buffer, "%u", name); + return strmake(buffer); +} + +/* + * Calculate itTypeSize, itPadSize, itMinTypeSize + * Every type needs this info; it is recalculated + * when itInLine, itNumber, or itSize changes. + */ +static void +itCalculateSizeInfo(ipc_type_t *it) +{ + if (!IS_KERN_PROC_DATA(it)) + { + u_int bytes = (it->itNumber * it->itSize + 7) / 8; + u_int padding = machine_padding(bytes); + + it->itTypeSize = bytes; + it->itPadSize = padding; + if (IS_VARIABLE_SIZED_UNTYPED(it)) { + /* + * for these arrays, the argCount is not a akbRequest|akbReply, + * therefore we need to account here for the space of the count + * (itMinTypeSize is used only in rtFindSize) + */ + it->itMinTypeSize = sizeof (mach_msg_type_number_t); + /* + * NDR encoded VarString carry the extra offset 4-bytes fields + * for MIG, it should be always 0; + */ + if (it->itString) + it->itMinTypeSize += sizeof (mach_msg_type_number_t); + } + else + it->itMinTypeSize = bytes + padding; + } + else { + /* + * 1) ports 2) OOL 3) ports OOL + * all have the same size = sizeof(mach_msg_descriptor_t) + */ + u_int bytes; + if (IS_MULTIPLE_KPD(it)) + bytes = it->itKPD_Number * 12 /* sizeof(mach_msg_descriptor_t) */; + else + bytes = 12 /* sizeof(mach_msg_descriptor_t) */; + + it->itTypeSize = bytes; + it->itPadSize = 0; + it->itMinTypeSize = bytes; + } + + /* Unfortunately, these warning messages can't give a type name; + we haven't seen a name yet (it might stay anonymous.) */ + + if ((it->itTypeSize == 0) && !it->itVarArray && !it->itNative) + warn("sizeof(%s) == 0"); +} + +/* + * Fill in default values for some fields used in code generation: + * itInNameStr, itOutNameStr, itUserType, itServerType, itTransType + * Every argument's type should have these values filled in. + */ +static void +itCalculateNameInfo(ipc_type_t *it) +{ + if (it->itInNameStr == strNULL) + it->itInNameStr = strmake(itNameToString(it->itInName)); + if (it->itOutNameStr == strNULL) + it->itOutNameStr = strmake(itNameToString(it->itOutName)); + + if (it->itUserType == strNULL) + it->itUserType = it->itName; + if (it->itServerType == strNULL) + it->itServerType = it->itName; +#if 0 + /* + * KernelServer and KernelUser interfaces get special treatment here. + * On the kernel side of the interface, ports are really internal + * port pointers (ipc_port_t), not port names (mach_port_t). + * At this point, we don't know if the argument is in or out, + * so we don't know if we should look at itInName or itOutName. + * Looking at both should be OK. + * + * This is definitely a hack, but I think it is cleaner than + * mucking with type declarations throughout the kernel .def files, + * hand-conditionalizing on KERNEL_SERVER and KERNEL_USER. + */ + + if (IsKernelServer && + streql(it->itServerType, "mach_port_t") && + (((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) && + (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) || + MACH_MSG_TYPE_PORT_ANY(it->itInName) || + MACH_MSG_TYPE_PORT_ANY(it->itOutName))) + it->itServerType = "ipc_port_t"; + + if (IsKernelUser && + streql(it->itUserType, "mach_port_t") && + (((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) && + (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) || + MACH_MSG_TYPE_PORT_ANY(it->itInName) || + MACH_MSG_TYPE_PORT_ANY(it->itOutName))) + it->itUserType = "ipc_port_t"; +#endif /* 0 */ + + if (it->itTransType == strNULL) + it->itTransType = it->itServerType; +} + +/****************************************************** + * Checks for non-implemented types, conflicting type + * flags and whether the long or short form of msg type + * descriptor is appropriate. Called after each type statement + * is parsed. + ******************************************************/ +static void +itCheckDecl(identifier_t name, ipc_type_t *it) +{ + it->itName = name; + + itCalculateNameInfo(it); + + /* do a bit of error checking, mostly necessary because of + limitations in Mig */ + + if (it->itVarArray) { + if ((it->itInTrans != strNULL) || (it->itOutTrans != strNULL)) + error("%s: can't translate variable-sized arrays", name); + + if (it->itDestructor != strNULL) + error("%s: can't destroy variable-sized array", name); + } +} + +/* + * Pretty-prints translation/destruction/type information. + */ +static void +itPrintTrans(ipc_type_t *it) +{ + if (!streql(it->itName, it->itUserType)) + printf("\tCUserType:\t%s\n", it->itUserType); + + if (!streql(it->itName, it->itServerType)) + printf("\tCServerType:\t%s\n", it->itServerType); + + if (it->itInTrans != strNULL) + printf("\tInTran:\t\t%s %s(%s)\n", it->itTransType, it->itInTrans, it->itServerType); + + if (it->itOutTrans != strNULL) + printf("\tOutTran:\t%s %s(%s)\n", it->itServerType, it->itOutTrans, it->itTransType); + + if (it->itDestructor != strNULL) + printf("\tDestructor:\t%s(%s)\n", it->itDestructor, it->itTransType); +} + +/* + * Pretty-prints type declarations. + */ +static void +itPrintDecl(identifier_t name, ipc_type_t *it) +{ + printf("Type %s = ", name); + if (!it->itInLine) + printf("^ "); + if (it->itVarArray) + if (it->itNumber == 0 || it->itMigInLine) + printf("array [] of "); + else + printf("array [*:%d] of ", it->itNumber); + else if (it->itStruct && ((it->itNumber != 1) || + (it->itInName == MACH_MSG_TYPE_STRING_C))) + printf("struct [%d] of ", it->itNumber); + else if (it->itNumber != 1) + printf("array [%d] of ", it->itNumber); + + if (streql(it->itInNameStr, it->itOutNameStr)) + printf("(%s,", it->itInNameStr); + else + printf("(%s|%s", it->itInNameStr, it->itOutNameStr); + + printf(" %d)\n", it->itSize); + + itPrintTrans(it); + + printf("\n"); +} + +/* + * Handles named type-specs, which can occur in type + * declarations or in argument lists. For example, + * type foo = type-spec; // itInsert will get called later + * routine foo(arg : bar = type-spec); // itInsert won't get called + */ +void +itTypeDecl(identifier_t name, ipc_type_t *it) +{ + itCheckDecl(name, it); + + if (BeVerbose) + itPrintDecl(name, it); +} + +/* + * Handles declarations like + * type new = name; + * type new = inname|outname; + */ +ipc_type_t * +itShortDecl(u_int inname, string_t instr, u_int outname, string_t outstr, u_int defsize) +{ + ipc_type_t *it; + + if (defsize == 0) + error("must use full IPC type decl"); + + it = itAlloc(); + it->itInName = inname; + it->itInNameStr = instr; + it->itOutName = outname; + it->itOutNameStr = outstr; + it->itSize = defsize; + if (inname == MACH_MSG_TYPE_STRING_C) + { + it->itStruct = FALSE; + it->itString = TRUE; + } + /* + * I check only inname, because outname + * has to be a port as well (polymorphic types + * are now restricted to port rights) + */ + if (MACH_MSG_TYPE_PORT_ANY(inname) || + inname == MACH_MSG_TYPE_POLYMORPHIC) { + it->itPortType = TRUE; + it->itKPD_Number = 1; + } + + itCalculateSizeInfo(it); + return it; +} + +static ipc_type_t * +itCopyType(ipc_type_t *old) +{ + ipc_type_t *new = itAlloc(); + + *new = *old; + new->itName = strNULL; + new->itNext = itNULL; + new->itElement = old; + + /* size info still valid */ + return new; +} + +/* + * A call to itCopyType is almost always followed with itResetType. + * The exception is itPrevDecl. Also called before adding any new + * translation/destruction/type info (see parser.y). + * + * type new = old; // new doesn't get old's info + * type new = array[*:10] of old; + * // new doesn't get old's info, but new->itElement does + * type new = array[*:10] of struct[3] of old; + * // new and new->itElement don't get old's info + */ + +ipc_type_t * +itResetType(ipc_type_t *old) +{ + /* reset all special translation/destruction/type info */ + + old->itInTrans = strNULL; + old->itOutTrans = strNULL; + old->itDestructor = strNULL; + old->itUserType = strNULL; + old->itServerType = strNULL; + old->itTransType = strNULL; + return old; +} + +/* + * Handles the declaration + * type new = old; + */ +ipc_type_t * +itPrevDecl(identifier_t name) +{ + ipc_type_t *old; + + old = itLookUp(name); + if (old == itNULL) { + error("type '%s' not defined", name); + return itAlloc(); + } + else + return itCopyType(old); +} + +/* + * Handles the declarations + * type new = array[] of old; // number is oo + * type new = array[*] of old; // number is oo + * type new = array[*:number] of old; + */ +ipc_type_t * +itVarArrayDecl(u_int number, ipc_type_t *old) +{ + ipc_type_t *it = itResetType(itCopyType(old)); + + if (!it->itInLine) { + /* already an initialized KPD */ + if (it->itKPD_Number != 1 || !number) + error("IPC type decl is too complicated for Kernel Processed Data"); + it->itKPD_Number *= number; + it->itNumber = 1; + it->itInLine = FALSE; + it->itStruct = FALSE; + it->itOOL_Number = number; + } + else if (it->itVarArray) + error("IPC type decl is too complicated"); + else if (number) { + it->itNumber *= number; + /* + * Bounded [Scalar, Port] VarArray: in-line! + */ + it->itInLine = TRUE; + it->itStruct = FALSE; + if (it->itPortType) + it->itKPD_Number *= number; + it->itOOL_Number = number; + } + else { + it->itNumber = 0; + /* + * UnBounded [Scalar, Port] VarArray: always in-line + * interface and out-of-line mechanism! + */ + it->itMigInLine = TRUE; + it->itInLine = FALSE; + it->itStruct = TRUE; + it->itKPD_Number = 1; + it->itOOL_Number = 0; + } + + it->itVarArray = TRUE; + it->itString = FALSE; + + itCalculateSizeInfo(it); + return it; +} + +/* + * Handles the declaration + * type new = array[number] of old; + */ +ipc_type_t * +itArrayDecl(u_int number, ipc_type_t *old) +{ + ipc_type_t *it = itResetType(itCopyType(old)); + + if (!it->itInLine) { + /* already an initialized KPD */ + if (it->itKPD_Number != 1) + error("IPC type decl is too complicated for Kernel Processed Data"); + it->itKPD_Number *= number; + it->itNumber = 1; + it->itStruct = FALSE; + it->itString = FALSE; + it->itVarArray = FALSE; + } + else if (it->itVarArray) + error("IPC type decl is too complicated"); + else { + it->itNumber *= number; + it->itStruct = FALSE; + it->itString = FALSE; + if (it->itPortType) + it->itKPD_Number *= number; + } + + itCalculateSizeInfo(it); + return it; +} + +/* + * Handles the declaration + * type new = ^ old; + */ +ipc_type_t * +itPtrDecl(ipc_type_t *it) +{ + if (!it->itInLine && !it->itMigInLine) + error("IPC type decl is already defined to be Out-Of-Line"); + it->itInLine = FALSE; + it->itStruct = TRUE; + it->itString = FALSE; + it->itMigInLine = FALSE; + it->itKPD_Number = 1; + + itCalculateSizeInfo(it); + return it; +} + +/* + * Handles the declaration + * type new = struct[number] of old; + */ +ipc_type_t * +itStructDecl(u_int number, ipc_type_t *old) +{ + ipc_type_t *it = itResetType(itCopyType(old)); + + if (!it->itInLine || it->itVarArray) + error("IPC type decl is too complicated"); + it->itNumber *= number; + it->itStruct = TRUE; + it->itString = FALSE; + + itCalculateSizeInfo(it); + return it; +} + +/* + * Treat 'c_string[n]' as + * 'array[n] of (MSG_TYPE_STRING_C, 8)' + */ +ipc_type_t * +itCStringDecl(int count, boolean_t varying) +{ + ipc_type_t *it; + ipc_type_t *itElement; + + itElement = itShortDecl(MACH_MSG_TYPE_STRING_C, "MACH_MSG_TYPE_STRING_C", MACH_MSG_TYPE_STRING_C, "MACH_MSG_TYPE_STRING_C", 8); + itCheckDecl("char", itElement); + + it = itResetType(itCopyType(itElement)); + it->itNumber = count; + it->itVarArray = varying; + it->itStruct = FALSE; + it->itString = TRUE; + + itCalculateSizeInfo(it); + return it; +} + +extern ipc_type_t * +itMakeSubCountType(int count, boolean_t varying, string_t name) +{ + ipc_type_t *it; + ipc_type_t *itElement; + + itElement = itShortDecl(machine_integer_size, machine_integer_name, machine_integer_size, machine_integer_name, machine_integer_bits); + itCheckDecl("mach_msg_type_number_t", itElement); + + it = itResetType(itCopyType(itElement)); + it->itNumber = count; + /* + * I cannot consider it as a Fixed array, otherwise MiG will try + * to follow the path for efficient copy of arrays + */ + it->itVarArray = FALSE; + it->itStruct = FALSE; + it->itString = FALSE; + it->itInLine = TRUE; + it->itName = "mach_msg_type_number_t *"; + if (varying) + it->itVarArray = TRUE; + else + /* to skip the optimized copy of fixed array: in fact we need to + * reference each element and we also miss a user type for it */ + it->itNoOptArray = TRUE; + + itCalculateSizeInfo(it); + itCalculateNameInfo(it); + return it; +} + +extern ipc_type_t * +itMakeCountType(void) +{ + ipc_type_t *it = itAlloc(); + + it->itName = "mach_msg_type_number_t"; + it->itInName = machine_integer_size; + it->itInNameStr = machine_integer_name; + it->itOutName = machine_integer_size; + it->itOutNameStr = machine_integer_name; + it->itSize = machine_integer_bits; + + itCalculateSizeInfo(it); + itCalculateNameInfo(it); + return it; +} + +extern ipc_type_t * +itMakePolyType(void) +{ + ipc_type_t *it = itAlloc(); + + it->itName = "mach_msg_type_name_t"; + it->itInName = machine_integer_size; + it->itInNameStr = machine_integer_name; + it->itOutName = machine_integer_size; + it->itOutNameStr = machine_integer_name; + it->itSize = machine_integer_bits; + + itCalculateSizeInfo(it); + itCalculateNameInfo(it); + return it; +} + +extern ipc_type_t * +itMakeDeallocType(void) +{ + ipc_type_t *it = itAlloc(); + + it->itName = "boolean_t"; + it->itInName = MACH_MSG_TYPE_BOOLEAN; + it->itInNameStr = "MACH_MSG_TYPE_BOOLEAN"; + it->itOutName = MACH_MSG_TYPE_BOOLEAN; + it->itOutNameStr = "MACH_MSG_TYPE_BOOLEAN"; + it->itSize = machine_integer_bits; + + itCalculateSizeInfo(it); + itCalculateNameInfo(it); + return it; +} + +extern ipc_type_t * +itNativeType(identifier_t id, boolean_t ptr, identifier_t badval) +{ + ipc_type_t *it = itAlloc(); + + it->itInName = MACH_MSG_TYPE_BYTE; + it->itInNameStr = "MACH_MSG_TYPE_BYTE"; + it->itOutName = MACH_MSG_TYPE_BYTE; + it->itOutNameStr = "MACH_MSG_TYPE_BYTE"; + it->itInLine = TRUE; + it->itNative = TRUE; + it->itNativePointer = ptr; + it->itServerType = id; + it->itUserType = id; + it->itTransType = id; + it->itBadValue = badval; + + itCalculateSizeInfo(it); + itCalculateNameInfo(it); + return it; +} + +/* + * Initializes the pre-defined types. + */ +void +init_type(void) +{ + u_int size; + + size = NBBY * sizeof (natural_t); + if (size == 32) { + machine_integer_name = "MACH_MSG_TYPE_INTEGER_32"; + machine_integer_size = MACH_MSG_TYPE_INTEGER_32; + } + else if (size == 64) { + machine_integer_name = "MACH_MSG_TYPE_INTEGER_64"; + machine_integer_size = MACH_MSG_TYPE_INTEGER_64; + } + else + error("init_type unknown size %d", size); + + machine_integer_bits = size; + + itRetCodeType = itAlloc(); + itRetCodeType->itName = "kern_return_t"; + itRetCodeType->itInName = machine_integer_size; + itRetCodeType->itInNameStr = machine_integer_name; + itRetCodeType->itOutName = machine_integer_size; + itRetCodeType->itOutNameStr = machine_integer_name; + itRetCodeType->itSize = machine_integer_bits; + itCalculateSizeInfo(itRetCodeType); + itCalculateNameInfo(itRetCodeType); + + itNdrCodeType = itAlloc(); + itNdrCodeType->itName = "NDR_record_t"; + itNdrCodeType->itInName = 0; + itNdrCodeType->itInNameStr = "NDR_record_t"; + itNdrCodeType->itOutName = 0; + itNdrCodeType->itOutNameStr = "NDR_record_t"; + itNdrCodeType->itSize = sizeof(NDR_record_t) * 8; + itCalculateSizeInfo(itNdrCodeType); + itCalculateNameInfo(itNdrCodeType); + + itDummyType = itAlloc(); + itDummyType->itName = "char *"; + itDummyType->itInName = MACH_MSG_TYPE_UNSTRUCTURED; + itDummyType->itInNameStr = "MACH_MSG_TYPE_UNSTRUCTURED"; + itDummyType->itOutName = MACH_MSG_TYPE_UNSTRUCTURED; + itDummyType->itOutNameStr = "MACH_MSG_TYPE_UNSTRUCTURED"; + itDummyType->itSize = PortSize; + itCalculateSizeInfo(itDummyType); + itCalculateNameInfo(itDummyType); + + itTidType = itAlloc(); + itTidType->itName = "tid_t"; + itTidType->itInName = machine_integer_size; + itTidType->itInNameStr = machine_integer_name; + itTidType->itOutName = machine_integer_size; + itTidType->itOutNameStr = machine_integer_name; + itTidType->itSize = machine_integer_bits; + itTidType->itNumber = 6; + itCalculateSizeInfo(itTidType); + itCalculateNameInfo(itTidType); + + itRequestPortType = itAlloc(); + itRequestPortType->itName = "mach_port_t"; + itRequestPortType->itInName = MACH_MSG_TYPE_COPY_SEND; + itRequestPortType->itInNameStr = "MACH_MSG_TYPE_COPY_SEND"; + itRequestPortType->itOutName = MACH_MSG_TYPE_PORT_SEND; + itRequestPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND"; + itRequestPortType->itSize = PortSize; + itCalculateSizeInfo(itRequestPortType); + itCalculateNameInfo(itRequestPortType); + + itZeroReplyPortType = itAlloc(); + itZeroReplyPortType->itName = "mach_port_t"; + itZeroReplyPortType->itInName = 0; + itZeroReplyPortType->itInNameStr = "0"; + itZeroReplyPortType->itOutName = 0; + itZeroReplyPortType->itOutNameStr = "0"; + itZeroReplyPortType->itSize = PortSize; + itCalculateSizeInfo(itZeroReplyPortType); + itCalculateNameInfo(itZeroReplyPortType); + + itRealReplyPortType = itAlloc(); + itRealReplyPortType->itName = "mach_port_t"; + itRealReplyPortType->itInName = MACH_MSG_TYPE_MAKE_SEND_ONCE; + itRealReplyPortType->itInNameStr = "MACH_MSG_TYPE_MAKE_SEND_ONCE"; + itRealReplyPortType->itOutName = MACH_MSG_TYPE_PORT_SEND_ONCE; + itRealReplyPortType->itOutNameStr = "MACH_MSG_TYPE_PORT_SEND_ONCE"; + itRealReplyPortType->itSize = PortSize; + itCalculateSizeInfo(itRealReplyPortType); + itCalculateNameInfo(itRealReplyPortType); + + itWaitTimeType = itMakeCountType(); + itMsgOptionType = itMakeCountType(); +} + +/****************************************************** + * Make sure return values of functions are assignable. + ******************************************************/ +void +itCheckReturnType(identifier_t name, ipc_type_t *it) +{ + if (!it->itStruct) + error("type of %s is too complicated", name); + if ((it->itInName == MACH_MSG_TYPE_POLYMORPHIC) || + (it->itOutName == MACH_MSG_TYPE_POLYMORPHIC)) + error("type of %s can't be polymorphic", name); +} + + +/****************************************************** + * Called by routine.c to check that request ports are + * simple and correct ports with send rights. + ******************************************************/ +void +itCheckRequestPortType(identifier_t name, ipc_type_t *it) +{ + /* error("Port size = %d %d name = %s\n", PortSize, it->itSize, it->itName); + error("server = %s user = %x\n",it->itServerType, it->itUserType); + */ + if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) && + (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) && + (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC)) || + (it->itNumber != 1) || + (it->itSize != PortSize) || + !it->itInLine || + !it->itStruct || + it->itVarArray) + error("argument %s isn't a proper request port", name); +} + + +/****************************************************** + * Called by routine.c to check that reply ports are + * simple and correct ports with send rights. + ******************************************************/ +void +itCheckReplyPortType(identifier_t name, ipc_type_t *it) +{ + if (((it->itOutName != MACH_MSG_TYPE_PORT_SEND) && + (it->itOutName != MACH_MSG_TYPE_PORT_SEND_ONCE) && + (it->itOutName != MACH_MSG_TYPE_POLYMORPHIC) && + (it->itOutName != 0)) || + (it->itNumber != 1) || + (it->itSize != PortSize) || + !it->itInLine || + !it->itStruct || + it->itVarArray) + error("argument %s isn't a proper reply port", name); +} + + +/****************************************************** + * Used by routine.c to check that WaitTime is a + * simple bit machine_integer_bits integer. + ******************************************************/ +void +itCheckIntType(identifier_t name, ipc_type_t *it) +{ + if ((it->itInName != machine_integer_size) || + (it->itOutName != machine_integer_size) || + (it->itNumber != 1) || + (it->itSize != machine_integer_bits) || + !it->itInLine || + !it->itStruct || + it->itVarArray) + error("argument %s isn't a proper integer", name); +} + +void +itCheckTokenType(identifier_t name, ipc_type_t *it) +{ + if (it->itMigInLine || it->itNoOptArray || it->itString || + it->itTypeSize != 8 || !it->itInLine || !it->itStruct || + it->itVarArray || it->itPortType) + error("argument %s isn't a proper Token", name); + +} diff --git a/bootstrap_cmds/migcom.tproj/type.h b/bootstrap_cmds/migcom.tproj/type.h new file mode 100644 index 0000000..b1b514b --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/type.h @@ -0,0 +1,270 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* HISTORY + * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University + * Extensive revamping. Added polymorphic arguments. + * Allow multiple variable-sized inline arguments in messages. + * + * 16-Nov-87 David Golub (dbg) at Carnegie-Mellon University + * Changed itVarArrayDecl to take a 'max' parameter. + * Added itDestructor. + * + * 18-Aug-87 Mary Thompson @ Carnegie Mellon + * Added itPortType + * Added itTidType + */ + +#ifndef _TYPE_H +#define _TYPE_H + +#include +#include "strdefs.h" + +#ifdef linux +#include +#else /* linux */ +#include +#endif /* linux */ +typedef u_int ipc_flags_t; + +/* + * MIG built-in types + */ +#define MACH_MSG_TYPE_UNSTRUCTURED 0 +#define MACH_MSG_TYPE_BIT 0 +#define MACH_MSG_TYPE_BOOLEAN 0 +#define MACH_MSG_TYPE_INTEGER_8 9 +#define MACH_MSG_TYPE_INTEGER_16 1 +#define MACH_MSG_TYPE_INTEGER_32 2 +#define MACH_MSG_TYPE_INTEGER_64 3 +#define MACH_MSG_TYPE_CHAR 8 +#define MACH_MSG_TYPE_BYTE 9 +#define MACH_MSG_TYPE_REAL_32 10 +#define MACH_MSG_TYPE_REAL_64 11 +#define MACH_MSG_TYPE_STRING 12 +#define MACH_MSG_TYPE_STRING_C 12 + +#define flNone (0x00) +#define flPhysicalCopy (0x01) /* Physical Copy specified */ +#define flOverwrite (0x02) /* Overwrite mode specified */ +#define flDealloc (0x04) /* Dealloc specified */ +#define flNotDealloc (0x08) /* NotDealloc specified */ +#define flMaybeDealloc (0x10) /* Dealloc[] specified */ +#define flSameCount (0x20) /* SamCount specified, used by co-bounded arrays */ +#define flCountInOut (0x40) /* CountInOut specified */ +#define flRetCode (0x80) /* RetCode specified */ +#define flAuto (0x100) /* Will not be referenced by server after RPC */ +#define flConst (0x200) /* Will not be modified by server during RPC */ + +typedef enum dealloc { + d_NO, /* do not deallocate */ + d_YES, /* always deallocate */ + d_MAYBE /* deallocate according to parameter */ +} dealloc_t; + +/* Convert dealloc_t to TRUE/FALSE */ +#define strdealloc(d) (strbool(d == d_YES)) + +/* + * itName and itNext are internal fields (not used for code generation). + * They are only meaningful for types entered into the symbol table. + * The symbol table is a simple self-organizing linked list. + * + * The function itCheckDecl checks & fills in computed information. + * Every type actually used (pointed at by argType) is so processed. + * + * The itInName, itOutName, itSize, itNumber, fields correspond directly + * to mach_msg_type_t fields. + * For out-of-line variable sized types, itNumber is zero. For + * in-line variable sized types, itNumber is the maximum size of the + * array. itInName is the name value supplied to the kernel, + * and itOutName is the name value received from the kernel. + * When the type describes a MACH port, either or both may be + * MACH_MSG_TYPE_POLYMORPHIC, indicating a "polymorphic" name. + * For itInName, this means the user supplies the value with an argument. + * For itOutName, this means the value is returned in an argument. + * + * The itInNameStr and itOutNameStr fields contain "printing" versions + * of the itInName and itOutName values. The mapping from number->string + * is not into (eg, MACH_MSG_TYPE_UNSTRUCTURED/MACH_MSG_TYPE_BOOLEAN/ + * MACH_MSG_TYPE_BIT). These fields are used for code-generation and + * pretty-printing. + * + * itTypeSize is the calculated size of the C type, in bytes. + * itPadSize is the size of any padded needed after the data field. + * itMinTypeSize is the minimum size of the data field, including padding. + * For variable-length inline data, it is zero. + * + * itUserType, itServerType, itTransType are the C types used in + * code generation. itUserType is the C type passed to the user-side stub + * and used for msg declarations in the user-side stub. itServerType + * is the C type used for msg declarations in the server-side stub. + * itTransType is the C type passed to the server function by the + * server-side stub. Normally it differs from itServerType only when + * translation functions are defined. + * + * itInTrans and itOutTrans are translation functions. itInTrans + * takes itServerType values and returns itTransType values. itOutTrans + * takes itTransType vaulues and returns itServerType values. + * itDestructor is a finalization function applied to In arguments + * after the server-side stub calls the server function. It takes + * itTransType values. Any combination of these may be defined. + * + * The following type specification syntax modifies these values: + * type new = old + * ctype: name // itUserType and itServerType + * cusertype: itUserType + * cservertype: itServerType + * intran: itTransType itInTrans(itServerType) + * outtran: itServerType itOutTrans(itTransType) + * destructor: itDestructor(itTransType); + * + * At most one of itStruct and itString should be TRUE. If both are + * false, then this is assumed to be an array type (msg data is passed + * by reference). If itStruct is TRUE, then msg data is passed by value + * and can be assigned with =. If itString is TRUE, then the msg_data + * is a null-terminated string, assigned with strncpy. The itNumber + * value is a maximum length for the string; the msg field always + * takes up this much space. + * NoOptArray has been introduced for the cases where the special + * code generated for array assignments would not work (either because + * there is not a ctype (array of automagically generated MiG variables) + * or because we need to reference the single elements of the array + * (array of variable sized ool regions). + * + * itVarArray means this is a variable-sized array. If it is inline, + * then itStruct and itString are FALSE. If it is out-of-line, then + * itStruct is TRUE (because pointers can be assigned). + * + * itMigInLine means this is an indefinite-length array. Although the + * argument was not specified as out-of-line, MIG will send it anyway + * os an out-of-line. + * + * itUserKPDType (itServerKPDType) identify the type of Kernel Processed + * Data that we must deal with: it can be either "mach_msg_port_descriptor_t" + * or "mach_msg_ool_ports_descriptor_t" or "mach_msg_ool_descriptor_t". + * + * itKPD_Number is used any time a single argument require more than + * one Kernel Processed Data entry: i.e., an in-line array of ports, an array + * of pointers (out-of-line data) + * + * itElement points to any substructure that the type may have. + * It is only used with variable-sized array types. + */ + +typedef struct ipc_type + { + identifier_t itName; /* Mig's name for this type */ + struct ipc_type *itNext; /* next type in symbol table */ + + u_int itTypeSize; /* size of the C type */ + u_int itPadSize; /* amount of padding after data */ + u_int itMinTypeSize; /* minimal amount of space occupied by data */ + + u_int itInName; /* name supplied to kernel in sent msg */ + u_int itOutName; /* name in received msg */ + u_int itSize; + u_int itNumber; + u_int itKPD_Number; /* number of Kernel Processed Data entries */ + boolean_t itInLine; + boolean_t itMigInLine; /* MiG presents data as InLine, although it is sent OOL */ + boolean_t itPortType; + + string_t itInNameStr; /* string form of itInName */ + string_t itOutNameStr; /* string form of itOutName */ + + boolean_t itStruct; + boolean_t itString; + boolean_t itVarArray; + boolean_t itNoOptArray; + boolean_t itNative; /* User specified a native (C) type. */ + boolean_t itNativePointer;/* The user will pass a pointer to the */ + /* native C type. */ + + struct ipc_type *itElement; /* may be NULL */ + + identifier_t itUserType; + identifier_t itServerType; + identifier_t itTransType; + + identifier_t itKPDType; /* descriptors for KPD type of arguments */ + + identifier_t itInTrans; /* may be NULL */ + identifier_t itOutTrans; /* may be NULL */ + identifier_t itDestructor;/* may be NULL */ + identifier_t itBadValue; /* Excluded value for PointerToIfNot. May + be NULL. */ + u_int itOOL_Number; + } ipc_type_t; + +enum { + ConsumeOnSendErrorNone, + ConsumeOnSendErrorTimeout, + ConsumeOnSendErrorAny, +}; + + +#define itNULL ((ipc_type_t *) 0) + +#define itWordAlign sizeof(natural_t) + +extern ipc_type_t *itLookUp(identifier_t name); +extern void itInsert(identifier_t name, ipc_type_t *it); +extern void itTypeDecl(identifier_t name, ipc_type_t *it); + +extern ipc_type_t *itShortDecl(u_int inname, string_t instr, + u_int outname, string_t outstr, + u_int dfault); +extern ipc_type_t *itPrevDecl(identifier_t name); +extern ipc_type_t *itResetType(ipc_type_t *it); +extern ipc_type_t *itVarArrayDecl(u_int number, ipc_type_t *it); +extern ipc_type_t *itArrayDecl(u_int number, ipc_type_t *it); +extern ipc_type_t *itPtrDecl(ipc_type_t *it); +extern ipc_type_t *itStructDecl(u_int number, ipc_type_t *it); +extern ipc_type_t *itCStringDecl(int count, boolean_t varying); +extern ipc_type_t *itNativeType(identifier_t CType, boolean_t pointer, + identifier_t NotVal); + +extern ipc_type_t *itRetCodeType; +extern ipc_type_t *itNdrCodeType; +extern ipc_type_t *itDummyType; +extern ipc_type_t *itTidType; +extern ipc_type_t *itRequestPortType; +extern ipc_type_t *itZeroReplyPortType; +extern ipc_type_t *itRealReplyPortType; +extern ipc_type_t *itWaitTimeType; +extern ipc_type_t *itMsgOptionType; +extern ipc_type_t *itMakeCountType(void); +extern ipc_type_t *itMakeSubCountType(int count, boolean_t varying, string_t name); +extern ipc_type_t *itMakePolyType(void); +extern ipc_type_t *itMakeDeallocType(void); + +extern void init_type(void); + +extern void itCheckReturnType(identifier_t name, ipc_type_t *it); +extern void itCheckRequestPortType(identifier_t name, ipc_type_t *it); +extern void itCheckReplyPortType(identifier_t name, ipc_type_t *it); +extern void itCheckIntType(identifier_t name, ipc_type_t *it); +extern void itCheckTokenType(identifier_t name, ipc_type_t *it); + +#endif /* _TYPE_H */ diff --git a/bootstrap_cmds/migcom.tproj/user.c b/bootstrap_cmds/migcom.tproj/user.c new file mode 100644 index 0000000..839732d --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/user.c @@ -0,0 +1,3260 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ + +#include +#include + +#include +#include "write.h" +#include "error.h" +#include "utils.h" +#include "global.h" + +#ifndef DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT +#define DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT 1 +#endif + +#ifndef DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR +#define DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR 1 +#endif + +#ifndef USE_IMMEDIATE_SEND_TIMEOUT +#define USE_IMMEDIATE_SEND_TIMEOUT 0 +#endif + +char *MessAllocRoutine = "mig_user_allocate"; +char *MessFreeRoutine = "mig_user_deallocate"; + +char stRetCode[] = "ReturnValue"; +char stRetNone[] = ""; + +void WriteLogDefines(FILE *file, string_t who); +void WriteIdentificationString(FILE *file); + +static void +WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t overwrite, boolean_t varying, argument_t *arg, boolean_t bracket) +{ + ipc_type_t *it = arg->argType; + char string[MAX_STR_LEN]; + + fprintf(file, "\t{\n"); + fprintf(file, "\t %s\t*ptr;\n", it->itKPDType); + fprintf(file, "\t int\ti"); + if (varying && !in) + fprintf(file, ", j"); + fprintf(file, ";\n\n"); + + if (in) + sprintf(string, "InP"); + else if (overwrite) + sprintf(string, "InOvTemplate"); + else + sprintf(string, "Out%dP", arg->argRequestPos); + + fprintf(file, "\t ptr = &%s->%s[0];\n", string, arg->argMsgField); + + if (varying) { + argument_t *count = arg->argCount; + char *cref = count->argByReferenceUser ? "*" : ""; + + if (in || overwrite) { + fprintf(file, "\t if (%s%s > %d)\n", cref, count->argVarName, it->itKPD_Number); + WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); + fprintf(file, "\t for (i = 0; i < %s%s; ptr++, i++) %s\n", cref, count->argVarName, (bracket) ? "{" : ""); + } + else { + fprintf(file, "\t j = min(Out%dP->%s, %s%s);\n", count->argReplyPos, count->argVarName, cref, count->argVarName); + fprintf(file, "\t for (i = 0; i < j; ptr++, i++) %s\n",(bracket) ? "{" : ""); +} + } + else + fprintf(file, "\t for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number, (bracket) ? "{" : ""); +} + +/************************************************************* + * Writes the standard includes. The subsystem specific + * includes are in .h and writen by + * header:WriteHeader. Called by WriteProlog. + *************************************************************/ +static void +WriteMyIncludes(FILE *file, statement_t *stats) +{ +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelServer) + { + /* + * We want to get the user-side definitions of types + * like task_t, ipc_space_t, etc. in mach/mach_types.h. + */ + + fprintf(file, "#undef\tMACH_KERNEL\n"); + + if (InternalHeaderFileName != strNULL) + { + char *cp; + + /* Strip any leading path from InternalHeaderFileName. */ + cp = strrchr(InternalHeaderFileName, '/'); + if (cp == 0) + cp = InternalHeaderFileName; + else + cp++; /* skip '/' */ + fprintf(file, "#include \"%s\"\n", cp); + } + } +#endif + + if (UserHeaderFileName == strNULL || UseSplitHeaders) + WriteIncludes(file, TRUE, FALSE); + if (UserHeaderFileName != strNULL) + { + char *cp; + + /* Strip any leading path from UserHeaderFileName. */ + cp = strrchr(UserHeaderFileName, '/'); + if (cp == 0) + cp = UserHeaderFileName; + else + cp++; /* skip '/' */ + fprintf(file, "#include \"%s\"\n", cp); + } + if (UseSplitHeaders) + WriteImplImports(file, stats, TRUE); + + if (UseEventLogger) { + if (IsKernelUser) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + fprintf(file, "#include \n"); + fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n"); + } + fprintf(file, "#if MIG_DEBUG\n"); + fprintf(file, "#include \n"); + fprintf(file, "#endif /* MIG_DEBUG */\n"); + } + if (HasConsumeOnSendError && !IsKernelUser) { + fprintf(file, "#include \n"); + } + if (BeLint) { + fprintf(file, "/* LINTLIBRARY */\n"); + } + fprintf(file, "\n"); + if (!BeAnsiC) { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "#else\t/* %s */\n", NewCDecl); + fprintf(file, "extern mach_port_t mig_get_reply_port();\n"); + fprintf(file, "extern void mig_dealloc_reply_port();\n"); + fprintf(file, "extern char *%s();\n", MessAllocRoutine); + fprintf(file, "extern void %s();\n", MessFreeRoutine); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + if (HasUseSpecialReplyPort) { + fprintf(file, "\n"); + fprintf(file, "#include \n"); + fprintf(file, "#include \n"); +#if DISABLE_SPECIAL_REPLY_PORT_IN_SIMULATOR + fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n"); + fprintf(file, "#if TARGET_OS_SIMULATOR\n"); + fprintf(file, "#define __MigCanUseSpecialReplyPort 0\n"); + fprintf(file, "#define mig_get_special_reply_port() MACH_PORT_DEAD\n"); + fprintf(file, "#define mig_dealloc_special_reply_port(port) __builtin_trap()\n"); + fprintf(file, "#endif\n"); + fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n"); +#endif +#if DISABLE_SPECIAL_REPLY_PORT_IN_CHROOT + fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n"); + fprintf(file, "#if TARGET_OS_OSX\n"); + fprintf(file, "extern _Bool _os_xbs_chrooted;\n"); + fprintf(file, "#define __MigCanUseSpecialReplyPort (!_os_xbs_chrooted)\n"); + fprintf(file, "#endif\n"); + fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n"); +#endif + fprintf(file, "#ifndef __MigCanUseSpecialReplyPort\n"); + fprintf(file, "#define __MigCanUseSpecialReplyPort 1\n"); + fprintf(file, "#endif /* __MigCanUseSpecialReplyPort */\n"); + fprintf(file, "#ifndef __MigSpecialReplyPortMsgOption\n"); + fprintf(file, "#define __MigSpecialReplyPortMsgOption (__MigCanUseSpecialReplyPort ? " + "(MACH_SEND_SYNC_OVERRIDE|MACH_SEND_SYNC_USE_THRPRI|MACH_RCV_SYNC_WAIT) : MACH_MSG_OPTION_NONE)\n"); + fprintf(file, "#endif /* __MigSpecialReplyPortMsgOption */\n"); + } + /* + * extern the definition of mach_msg_destroy + * (to avoid inserting mach/mach.h everywhere) + */ + fprintf(file, "/* TODO: #include */\n"); + fprintf(file, "#ifdef __cplusplus\nextern \"C\" {\n#endif /* __cplusplus */\n"); + fprintf(file, "extern void mach_msg_destroy(mach_msg_header_t *);\n"); + fprintf(file, "#ifdef __cplusplus\n}\n#endif /* __cplusplus */\n"); + + fprintf(file, "\n"); +} + +static void +WriteGlobalDecls(FILE *file) +{ + if (RCSId != strNULL) + WriteRCSDecl(file, strconcat(SubsystemName, "_user"), RCSId); + + fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n"); + fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n"); + fprintf(file, "\n"); + if (UseEventLogger) + WriteLogDefines(file, "MACH_MSG_LOG_USER"); + fprintf(file, "\n"); +} + +static void +WriteOneMachErrorDefine(FILE *file, char *name, boolean_t timeout, boolean_t SpecialReplyPort) +{ + fprintf(file, "#ifndef\t%s\n", name); + fprintf(file, "#define\t%s(_R_) { \\\n", name); + fprintf(file, "\tswitch (_R_) { \\\n"); + fprintf(file, "\tcase MACH_SEND_INVALID_DATA: \\\n"); + fprintf(file, "\tcase MACH_SEND_INVALID_DEST: \\\n"); + fprintf(file, "\tcase MACH_SEND_INVALID_HEADER: \\\n"); + if (SpecialReplyPort) { + fprintf(file, "\t\tif (!__MigCanUseSpecialReplyPort) { \\\n"); + fprintf(file, "\t\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n"); + fprintf(file, "\t\t} \\\n"); + } else { + fprintf(file, "\t\tmig_put_reply_port(InP->Head.msgh_reply_port); \\\n"); + } + fprintf(file, "\t\tbreak; \\\n"); + if (timeout) { + fprintf(file, "\tcase MACH_SEND_TIMED_OUT: \\\n"); + fprintf(file, "\tcase MACH_RCV_TIMED_OUT: \\\n"); + } + fprintf(file, "\tdefault: \\\n"); + if (SpecialReplyPort) { + fprintf(file, "\t\tif (__MigCanUseSpecialReplyPort) { \\\n"); + fprintf(file, "\t\t\tmig_dealloc_special_reply_port(InP->Head.msgh_reply_port); \\\n"); + fprintf(file, "\t\t} else { \\\n"); + fprintf(file, "\t\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n"); + fprintf(file, "\t\t} \\\n"); + } else { + fprintf(file, "\t\tmig_dealloc_reply_port(InP->Head.msgh_reply_port); \\\n"); + } + fprintf(file, "\t} \\\n}\n"); + fprintf(file, "#endif\t/* %s */\n", name); + fprintf(file, "\n"); +} + +static void +WriteMachErrorDefines(FILE *file) +{ + WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeout", TRUE, FALSE); + WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeout", FALSE, FALSE); + if (HasUseSpecialReplyPort) { + WriteOneMachErrorDefine(file, "__MachMsgErrorWithTimeoutSRP", TRUE, TRUE); + WriteOneMachErrorDefine(file, "__MachMsgErrorWithoutTimeoutSRP", FALSE, TRUE); + } +} + +static void +WriteMIGCheckDefines(FILE *file) +{ + fprintf(file, "#define\t__MIG_check__Reply__%s_subsystem__ 1\n", SubsystemName); + fprintf(file, "\n"); +} + +static void +WriteNDRDefines(FILE *file) +{ + fprintf(file, "#define\t__NDR_convert__Reply__%s_subsystem__ 1\n", SubsystemName); + fprintf(file, "#define\t__NDR_convert__mig_reply_error_subsystem__ 1\n"); + fprintf(file, "\n"); +} + +/************************************************************* + * Writes the standard #includes, #defines, and + * RCS declaration. Called by WriteUser. + *************************************************************/ +static void +WriteProlog(FILE *file, statement_t *stats) +{ + WriteIdentificationString(file); + WriteMIGCheckDefines(file); + if (CheckNDR) + WriteNDRDefines(file); + WriteMyIncludes(file, stats); + WriteBogusDefines(file); + WriteMachErrorDefines(file); + WriteApplDefaults(file, "Send"); + WriteGlobalDecls(file); +} + +/*ARGSUSED*/ +static void +WriteEpilog(FILE *file) +{ + /* nothing to see here, move along... */ +} + +static string_t +WriteHeaderPortType(argument_t *arg) +{ + if (arg->argType->itInName == MACH_MSG_TYPE_POLYMORPHIC) + return arg->argPoly->argVarName; + else + return arg->argType->itInNameStr; +} + +static void +WriteRequestHead(FILE *file, routine_t *rt) +{ + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) + fprintf(file, "ready_to_send:\n"); + + if (rt->rtMaxRequestPos > 0) { + if (rt->rtOverwrite) + fprintf(file, "\tInP = &MessRequest;\n"); + else + fprintf(file, "\tInP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->")); + } + + fprintf(file, "\tInP->Head.msgh_bits ="); + if (rt->rtRetCArg == argNULL && !rt->rtSimpleRequest) + fprintf(file, " MACH_MSGH_BITS_COMPLEX|"); + fprintf(file, "\n"); + fprintf(file, "\t\tMACH_MSGH_BITS(%s, %s);\n", WriteHeaderPortType(rt->rtRequestPort), WriteHeaderPortType(rt->rtReplyPort)); + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + fprintf(file, "\tif (!%s)\n", rt->rtRetCArg->argVarName); + fprintf(file, "\t\tInP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n"); + } + + + fprintf(file, "\t/* msgh_size passed as argument */\n"); + + /* + * KernelUser stubs need to cast the request and reply ports + * from ipc_port_t to mach_port_t. + */ + +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelUser) + fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName); + else +#endif + fprintf(file, "\tInP->%s = %s;\n", rt->rtRequestPort->argMsgField, rt->rtRequestPort->argVarName); + + if (akCheck(rt->rtReplyPort->argKind, akbUserArg)) { +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelUser) + fprintf(file, "\tInP->%s = (mach_port_t) %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName); + else +#endif + fprintf(file, "\tInP->%s = %s;\n", rt->rtReplyPort->argMsgField, rt->rtReplyPort->argVarName); + } + else if (rt->rtOneWay) + fprintf(file, "\tInP->%s = MACH_PORT_NULL;\n", rt->rtReplyPort->argMsgField); + else if (rt->rtUseSpecialReplyPort) + fprintf(file, "\tInP->%s = __MigCanUseSpecialReplyPort ? mig_get_special_reply_port() : mig_get_reply_port();\n", rt->rtReplyPort->argMsgField); + else + fprintf(file, "\tInP->%s = mig_get_reply_port();\n", rt->rtReplyPort->argMsgField); + + fprintf(file, "\tInP->Head.msgh_id = %d;\n", rt->rtNumber + SubsystemBase); + fprintf(file, "\tInP->Head.msgh_reserved = 0;\n"); + + + if (IsVoucherCodeAllowed && !IsKernelUser && !IsKernelServer) { + fprintf(file, "\t\n/* BEGIN VOUCHER CODE */\n\n"); + fprintf(file, "#ifdef USING_VOUCHERS\n"); + fprintf(file, "\tif (voucher_mach_msg_set != NULL) {\n"); + fprintf(file, "\t\tvoucher_mach_msg_set(&InP->Head);\n"); + fprintf(file, "\t}\n"); + fprintf(file, "#endif // USING_VOUCHERS\n"); + fprintf(file, "\t\n/* END VOUCHER CODE */\n"); + } +} + +/************************************************************* + * Writes declarations for the message types, variables + * and return variable if needed. Called by WriteRoutine. + *************************************************************/ +static void +WriteVarDecls(FILE *file, routine_t *rt) +{ + int i; + + if (rt->rtOverwrite) { + fprintf(file, "\tRequest MessRequest;\n"); + fprintf(file, "\tRequest *InP = &MessRequest;\n\n"); + + fprintf(file, "\tunion {\n"); + fprintf(file, "\t\tOverwriteTemplate In;\n"); + fprintf(file, "\t\tReply Out;\n"); + fprintf(file, "\t} MessReply;\n"); + + fprintf(file, "\tOverwriteTemplate *InOvTemplate = &MessReply.In;\n"); + fprintf(file, "\tReply *Out0P = &MessReply.Out;\n"); + for (i = 1; i <= rt->rtMaxReplyPos; i++) + fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i); + } + else { + if (rtMessOnStack(rt)) + fprintf(file, "\tunion {\n"); + else + fprintf(file, "\tunion %sMessU {\n", rt->rtName); + fprintf(file, "\t\tRequest In;\n"); + if (!rt->rtOneWay) + fprintf(file, "\t\tReply Out;\n"); + if (rtMessOnStack(rt)) + fprintf(file, "\t} Mess;\n"); + else + fprintf(file, "\t} *Mess = (union %sMessU *) %s(sizeof(*Mess));\n", + rt->rtName, MessAllocRoutine); + fprintf(file, "\n"); + + fprintf(file, "\tRequest *InP = &Mess%sIn;\n", (rtMessOnStack(rt) ? "." : "->")); + if (!rt->rtOneWay) { + fprintf(file, "\tReply *Out0P = &Mess%sOut;\n", (rtMessOnStack(rt) ? "." : "->")); + for (i = 1; i <= rt->rtMaxReplyPos; i++) + fprintf(file, "\t" "Reply *Out%dP = NULL;\n", i); + } + } + + fprintf(file, "\n"); + + fprintf(file, "\tmach_msg_return_t msg_result;\n"); + + /* if request is variable, we need msgh_size_delta and msgh_size */ + if (rt->rtNumRequestVar > 0) + fprintf(file, "\tunsigned int msgh_size;\n"); + if (rt->rtMaxRequestPos > 0) + fprintf(file, "\tunsigned int msgh_size_delta;\n"); + if (rt->rtNumRequestVar > 1 || rt->rtMaxRequestPos > 0) + fprintf(file, "\n"); + + if (rt->rtUserImpl) { + fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n"); + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tunsigned int trailer_size __attribute__((unused));\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + fprintf(file, "\n"); + fprintf(file, "#ifdef\t__MIG_check__Reply__%s_t__defined\n", rt->rtName); + fprintf(file, "\tkern_return_t check_result;\n"); + fprintf(file, "#endif\t/* __MIG_check__Reply__%s_t__defined */\n", rt->rtName); + fprintf(file, "\n"); + WriteApplMacro(file, "Send", "Declare", rt); + fprintf(file, "\n"); +} + +static void +WriteReturn(FILE *file, routine_t *rt, char *before, char *value, char *after, boolean_t deallocate_mess) +{ + if (rtMessOnStack(rt)) { + if (value != stRetCode) { + /* get the easy case (no braces needed) out of the way */ + fprintf(file, "%sreturn%s%s;%s", before, (*value ? " " : ""), value, after); + return; + } + else { + fprintf(file, "%s{\n", before); + fprintf(file, "%s\treturn Out0P->RetCode;\n%s}%s", before, before, after); + return; + } + } + + if (value == stRetCode) { + fprintf(file, "%s{\n%s\t%s ReturnValue;\n", before, before, ReturnTypeStr(rt)); + fprintf(file, "%s\tReturnValue = Out0P->RetCode;\n%s\t", before, before); + } + else { + fprintf(file, "%s{ ", before); + } + + if (deallocate_mess) { + fprintf(file, "%s((char *) Mess, sizeof(*Mess)); ", MessFreeRoutine); + } + + if (value == stRetCode) + fprintf(file, "return ReturnValue;\n%s}%s", before, after); + else if (value == stRetNone) + fprintf(file, "return; }%s", after); + else + fprintf(file, "return %s; }%s", value, after); +} + +static void +WriteRetCodeArg(FILE *file, routine_t *rt) +{ + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + argument_t *arg = rt->rtRetCArg; + + fprintf(file, "\tif (%s) {\n", arg->argVarName); + fprintf(file, "\t\t((mig_reply_error_t *)InP)->RetCode = %s;\n", arg->argVarName); + fprintf(file, "\t\t((mig_reply_error_t *)InP)->NDR = NDR_record;\n"); + fprintf(file, "\t\tgoto ready_to_send;\n"); + fprintf(file, "\t}\n\n"); + } +} + +/************************************************************* + * Writes the logic to check for a message send timeout, and + * deallocate any relocated ool data so as not to leak. + *************************************************************/ +static void +WriteMsgCheckForSendErrors(FILE *file, routine_t *rt) +{ + if (rt->rtConsumeOnSendError != ConsumeOnSendErrorAny && rt->rtWaitTime == argNULL) { + return; + } + + if (rt->rtConsumeOnSendError == ConsumeOnSendErrorAny) { + // other errors mean the kernel consumed some of the rights + // and we can't possibly know if there's something left to destroy + fputs("\n" + "\t" "if (msg_result == MACH_SEND_INVALID_DEST ||" "\n" + "\t\t" "msg_result == MACH_SEND_TIMED_OUT) {" "\n", file); + } else { + fputs("\n" + "\t" "if (msg_result == MACH_SEND_TIMED_OUT) {" "\n", file); + } + + if (rt->rtConsumeOnSendError == ConsumeOnSendErrorNone) { + argument_t *arg_ptr; + + // iterate over arg list + for (arg_ptr = rt->rtArgs; arg_ptr != NULL; arg_ptr = arg_ptr->argNext) { + + // if argument contains ool data + if (akCheck(arg_ptr->argKind, akbSendKPD) && arg_ptr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { + // generate code to test current arg address vs. address before the msg_send call + // if not at the same address, mig_deallocate the argument + fprintf(file, "\t\t" "if((vm_offset_t) InP->%s.address != (vm_offset_t) %s)\n", + arg_ptr->argVarName, arg_ptr->argVarName); + fprintf(file, "\t\t\t" "mig_deallocate((vm_offset_t) InP->%s.address, " + "(vm_size_t) InP->%s.size);\n", arg_ptr->argVarName, arg_ptr->argVarName); + } + } + } else { + /* + * The original MIG would leak most resources on send timeout without + * leaving a chance for callers to know how to dispose of most of the + * resources, as the caller can't possibly guess the new names + * picked during pseudo-receive. + */ + if (IsKernelUser) { + fputs("#if\t__MigKernelSpecificCode" "\n", file); + fputs("\t\t" "mach_msg_destroy_from_kernel(&InP->Head);" "\n", file); + fputs("#endif\t/* __MigKernelSpecificCode */" "\n", file); + } else { + fputs("\t\t" "/* mach_msg_destroy doesn't handle the local port */" "\n", file); + fputs("\t\t" "switch (MACH_MSGH_BITS_LOCAL(InP->Head.msgh_bits)) {" "\n", file); + fputs("\t\t" "case MACH_MSG_TYPE_MOVE_SEND:" "\n", file); + fputs("\t\t\t" "mach_port_deallocate(mach_task_self(), InP->Head.msgh_local_port);" "\n", file); + fputs("\t\t\t" "break;" "\n", file); + fputs("\t\t" "}" "\n", file); + fputs("\t\t" "mach_msg_destroy(&InP->Head);" "\n", file); + } + } + + fputs("\t" "}" "\n\n", file); + return; +} + +/************************************************************* + * Writes the send call when there is to be no subsequent + * receive. Called by WriteRoutine SimpleRoutines + *************************************************************/ +static void +WriteMsgSend(FILE *file, routine_t *rt) +{ + char *SendSize = ""; + char string[MAX_STR_LEN]; + + if (rt->rtNumRequestVar == 0) + SendSize = "(mach_msg_size_t)sizeof(Request)"; + else + SendSize = "msgh_size"; + + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName); + SendSize = strconcat(string, SendSize); + } + + if (IsKernelUser) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + fprintf(file, "\tmsg_result = mach_msg_send_from_kernel("); + fprintf(file, "&InP->Head, %s);\n", SendSize); + fprintf(file, "#else\n"); + } + fprintf(file, "\tmsg_result = mach_msg(" + "&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, MACH_PORT_NULL, %s, MACH_PORT_NULL);\n", + rt->rtWaitTime !=argNULL ? "MACH_SEND_TIMEOUT|" : "", + rt->rtMsgOption->argVarName, + SendSize, + rt->rtWaitTime != argNULL ? rt->rtWaitTime->argVarName:"MACH_MSG_TIMEOUT_NONE"); + + if (IsKernelUser) { + fprintf(file, "#endif /* __MigKernelSpecificCode */\n"); + } + + WriteApplMacro(file, "Send", "After", rt); + + WriteMsgCheckForSendErrors(file, rt); + + WriteReturn(file, rt, "\t", "msg_result", "\n", TRUE); +} + +/************************************************************* + * Writes to code to check for error returns from receive. + * Called by WriteMsgSendReceive and WriteMsgRPC + *************************************************************/ +static void +WriteMsgCheckReceiveCleanupMigReplyPort(FILE *file, routine_t *rt, char *success) +{ + if (!akCheck(rt->rtReplyPort->argKind, akbUserArg)) + { + /* If we aren't using a user-supplied reply port, then + deallocate the reply port when it is invalid or + for TIMED_OUT errors. */ + fprintf(file, "\tif (msg_result != %s) {\n", success); + if (rt->rtWaitTime != argNULL) { + fprintf(file, "\t\t__MachMsgErrorWithTimeout%s(msg_result);\n", + rt->rtUseSpecialReplyPort ? "SRP" : ""); + } else { + fprintf(file, "\t\t__MachMsgErrorWithoutTimeout%s(msg_result);\n", + rt->rtUseSpecialReplyPort ? "SRP" : ""); + } + fprintf(file, "\t}\n"); + } +} + +static void +WriteMsgCheckReceive(FILE *file, routine_t *rt, char *success) +{ + fprintf(file, "\tif (msg_result != %s) {\n", success); + WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result"); + fprintf(file, "\t}\n"); +} + +/************************************************************* + * Writes the send and receive calls and code to check + * for errors. Normally the rpc code is generated instead + * although, the subsytem can be compiled with the -R option + * which will cause this code to be generated. Called by + * WriteRoutine if UseMsgRPC option is false. + *************************************************************/ +static void +WriteMsgSendReceive(FILE *file, routine_t *rt) +{ + char *SendSize = ""; + char string[MAX_STR_LEN]; + + if (rt->rtNumRequestVar == 0) + SendSize = "(mach_msg_size_t)sizeof(Request)"; + else + SendSize = "msgh_size"; + + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName); + SendSize = strconcat(string, SendSize); + } + + /* IsKernelUser to be done! */ + fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|%s%s, %s, 0, ", rt->rtWaitTime != argNULL ? "MACH_SEND_TIMEOUT|" : "", rt->rtMsgOption->argVarName, SendSize); + fprintf(file, " MACH_PORT_NULL, %s, MACH_PORT_NULL);\n", +#if !USE_IMMEDIATE_SEND_TIMEOUT + (rt->rtWaitTime != argNULL) ? rt->rtWaitTime->argVarName : +#endif + "MACH_MSG_TIMEOUT_NONE"); + fprintf(file, "\tif (msg_result != MACH_MSG_SUCCESS)\n"); + WriteReturnMsgError(file, rt, TRUE, argNULL, "msg_result"); + fprintf(file, "\n"); + + fprintf(file, "\tmsg_result = mach_msg(&Out0P->Head, MACH_RCV_MSG|%s%s%s, 0, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_local_port, %s, MACH_PORT_NULL);\n", + rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "", + (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? "MACH_RCV_TIMEOUT|" : "", + rt->rtMsgOption->argVarName, + (rt->rtWaitTime != argNULL && akIdent(rt->rtWaitTime->argKind) == akeWaitTime) ? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); + WriteApplMacro(file, "Send", "After", rt); + WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS"); + WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS"); + fprintf(file, "\n"); +} + +/************************************************************* + * Writes the rpc call and the code to check for errors. + * This is the default code to be generated. Called by WriteRoutine + * for all routine types except SimpleRoutine. + *************************************************************/ +static void +WriteMsgRPC(FILE *file, routine_t *rt) +{ + char *SendSize = ""; + char string[MAX_STR_LEN]; + + if (rt->rtNumRequestVar == 0) + SendSize = "(mach_msg_size_t)sizeof(Request)"; + else + SendSize = "msgh_size"; + + if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) { + sprintf(string, "(%s) ? (mach_msg_size_t)sizeof(mig_reply_error_t) : ", rt->rtRetCArg->argVarName); + SendSize = strconcat(string, SendSize); + } + + if (IsKernelUser) { + fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNELSPECIFIC_CODE_)\n"); + fprintf(file, "\tmsg_result = mach_msg_rpc_from_kernel(&InP->Head, %s, (mach_msg_size_t)sizeof(Reply));\n", SendSize); + fprintf(file, "#else\n"); + } + if (rt->rtOverwrite) { + fprintf(file, "\tmsg_result = mach_msg_overwrite(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|MACH_RCV_OVERWRITE|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL, ", + rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "", + rt->rtWaitTime != argNULL ? + (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "", + rt->rtMsgOption->argVarName, + SendSize, + rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); + fprintf(file, " &InOvTemplate->Head, (mach_msg_size_t)sizeof(OverwriteTemplate));\n"); + } + else { + fprintf(file, "\tmsg_result = mach_msg(&InP->Head, MACH_SEND_MSG|MACH_RCV_MSG|%s%s%s, %s, (mach_msg_size_t)sizeof(Reply), InP->Head.msgh_reply_port, %s, MACH_PORT_NULL);\n", + rt->rtUserImpl != 0 ? "MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0)|" : "", + rt->rtWaitTime != argNULL ? + (akIdent(rt->rtWaitTime->argKind) == akeWaitTime ? "MACH_SEND_TIMEOUT|MACH_RCV_TIMEOUT|" : "MACH_SEND_TIMEOUT|") : "", + rt->rtMsgOption->argVarName, + SendSize, + rt->rtWaitTime != argNULL? rt->rtWaitTime->argVarName : "MACH_MSG_TIMEOUT_NONE"); + } + if (IsKernelUser) + fprintf(file,"#endif /* __MigKernelSpecificCode */\n"); + WriteApplMacro(file, "Send", "After", rt); + + WriteMsgCheckReceiveCleanupMigReplyPort(file, rt, "MACH_MSG_SUCCESS"); + WriteMsgCheckForSendErrors(file, rt); + + WriteMsgCheckReceive(file, rt, "MACH_MSG_SUCCESS"); + fprintf(file, "\n"); +} + +/* + * argKPD_Pack discipline for Port types. + */ +static void +WriteKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *subindex = ""; + char *recast = ""; + char firststring[MAX_STR_LEN]; + char string[MAX_STR_LEN]; + char *ref = arg->argByReferenceUser ? "*" : ""; + ipc_type_t *real_it; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE); + (void)sprintf(firststring, "\t*ptr"); + (void)sprintf(string, "\tptr->"); + subindex = "[i]"; + real_it = it->itElement; + } + else { + (void)sprintf(firststring, "InP->%s", arg->argMsgField); + (void)sprintf(string, "InP->%s.", arg->argMsgField); + real_it = it; + } + +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t")) + recast = "(mach_port_t)"; +#endif + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + /* ref is required also in the Request part, because of inout parameters */ + fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex); + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { + argument_t *poly = arg->argPoly; + + fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName); + } + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + fprintf(file, "\t%sname = %s%s%s%s;\n", string, recast, ref, arg->argVarName, subindex); + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { + argument_t *poly = arg->argPoly; + + fprintf(file, "\t%sdisposition = %s%s;\n", string, poly->argByReferenceUser ? "*" : "", poly->argVarName); + } + else + fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr); + fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + if (IS_MULTIPLE_KPD(it)) { + fprintf(file, "\t }\n"); + if (it->itVarArray) { + fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number); + /* fill the rest of the statically allocated KPD entries with MACH_PORT_NULL */ + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string); + fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + fprintf(file, "\t }\n"); + } + fprintf(file, "\t}\n"); + } + fprintf(file, "\n"); +} + +static void +WriteKPD_ool_varsize(FILE *file, argument_t *arg, char *who, char *where, boolean_t iscomplex) +{ + ipc_type_t *it = arg->argType; + argument_t *count; + char *cref; + + if (iscomplex) { + it = it->itElement; + count = arg->argSubCount; + } + else + count = arg->argCount; + cref = count->argByReferenceUser ? "*" : ""; + + /* size has to be expressed in bytes! */ + if (count->argMultiplier > 1 || it->itSize > 8) + fprintf(file, "\t%s->%s = %s%s%s * %d;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : "", count->argMultiplier * it->itSize / 8); + else + fprintf(file, "\t%s->%s = %s%s%s;\n", who, where, cref, count->argVarName, (iscomplex)? "[i]" : ""); +} + +/* + * argKPD_Pack discipline for out-of-line types. + */ +static void +WriteKPD_ool(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *ref = arg->argByReferenceUser ? "*" : ""; + char firststring[MAX_STR_LEN]; + char string[MAX_STR_LEN]; + boolean_t VarArray; + u_int howmany, howbig; + char *subindex; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE); + (void)sprintf(firststring, "\t*ptr"); + (void)sprintf(string, "\tptr->"); + VarArray = it->itElement->itVarArray; + howmany = it->itElement->itNumber; + howbig = it->itElement->itSize; + subindex = "[i]"; + } + else { + (void)sprintf(firststring, "InP->%s", arg->argMsgField); + (void)sprintf(string, "InP->%s.", arg->argMsgField); + VarArray = it->itVarArray; + howmany = it->itNumber; + howbig = it->itSize; + subindex = ""; + } + + fprintf(file, "#if\tUseStaticTemplates\n"); + + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); + if (VarArray) { + if (IS_MULTIPLE_KPD(it)) + WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE); + else + WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE); + } + + if (arg->argDeallocate == d_MAYBE) + fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); + + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + + fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); + if (VarArray) + if (IS_MULTIPLE_KPD(it)) + WriteKPD_ool_varsize(file, arg, "\tptr", "size", TRUE); + else + WriteKPD_ool_varsize(file, arg, "InP", strconcat(arg->argMsgField, ".size"), FALSE); + else + fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8); + if (arg->argDeallocate == d_MAYBE) + fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); + else + fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); + fprintf(file, "\t%scopy = %s;\n", string, (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY"); +#ifdef ALIGNMENT + fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, (it->itElement->itSize < 8) ? 1 : it->itElement->itSize / 8); +#endif + fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string); + + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + if (IS_MULTIPLE_KPD(it)) { + fprintf(file, "\t }\n"); + if (it->itVarArray) { + fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number); + /* fill the rest of the statically allocated KPD entries with size NULL */ + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + if (!VarArray) + fprintf(file, "\t%ssize = 0;\n", string); + /* otherwise the size in the template would be != 0! */ + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + fprintf(file, "\t%ssize = 0;\n", string); + fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + fprintf(file, "\t }\n"); + } + fprintf(file, "\t}\n"); + } + fprintf(file, "\n"); +} + +/* + * argKPD_Pack discipline for out-of-line Port types. + */ +static void +WriteKPD_oolport(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *ref = arg->argByReferenceUser ? "*" : ""; + argument_t *count; + boolean_t VarArray; + string_t howstr; + u_int howmany; + char *subindex; + char firststring[MAX_STR_LEN]; + char string[MAX_STR_LEN]; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, TRUE, FALSE, it->itVarArray, arg, TRUE); + (void)sprintf(firststring, "\t*ptr"); + (void)sprintf(string, "\tptr->"); + VarArray = it->itElement->itVarArray; + howmany = it->itElement->itNumber; + howstr = it->itElement->itInNameStr; + count = arg->argSubCount; + subindex = "[i]"; + } + else { + (void)sprintf(firststring, "InP->%s", arg->argMsgField); + (void)sprintf(string, "InP->%s.", arg->argMsgField); + VarArray = it->itVarArray; + howmany = it->itNumber; + howstr = it->itInNameStr; + count = arg->argCount; + subindex = ""; + } + + fprintf(file, "#if\tUseStaticTemplates\n"); + + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); + if (VarArray) + fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex); + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { + argument_t *poly = arg->argPoly; + char *pref = poly->argByReferenceUser ? "*" : ""; + + fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName); + } + if (arg->argDeallocate == d_MAYBE) + fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); + + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + + fprintf(file, "\t%saddress = (void *)(%s%s%s);\n", string, ref, arg->argVarName, subindex); + if (VarArray) + fprintf(file, "\t%scount = %s%s%s;\n", string, count->argByReferenceUser ? "*" : "", count->argVarName, subindex); + else + fprintf(file, "\t%scount = %d;\n", string, howmany); + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendSnd)) { + argument_t *poly = arg->argPoly; + char *pref = poly->argByReferenceUser ? "*" : ""; + + fprintf(file, "\t%sdisposition = %s%s;\n", string, pref, poly->argVarName); + } + else + fprintf(file, "\t%sdisposition = %s;\n", string, howstr); + if (arg->argDeallocate == d_MAYBE) + fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName); + else + fprintf(file, "\t%sdeallocate = %s;\n", string, (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); + fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string); + + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + fprintf(file, "\n"); + + if (IS_MULTIPLE_KPD(it)) { + fprintf(file, "\t }\n"); + if (it->itVarArray) { + fprintf(file, "\t for (i = %s; i < %d; ptr++, i++) {\n", arg->argCount->argVarName, it->itKPD_Number); + /* fill the rest of the statically allocated KPD entries with size NULL */ + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName); + if (!VarArray) + fprintf(file, "\t%scount = 0;\n", string); + /* otherwise the size in the template would be != 0! */ + fprintf(file, "#else\t/* UseStaticTemplates */\n"); + fprintf(file, "\t%scount = 0;\n", string); + fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + fprintf(file, "\t }\n"); + } + fprintf(file, "\t}\n"); + } + fprintf(file, "\n"); +} + +static void +WriteOverwriteTemplate(FILE *file, routine_t *rt) +{ + argument_t *arg; + char string[MAX_STR_LEN]; + char *subindex = ""; + boolean_t finish = FALSE; + + fprintf(file, "\t/* Initialize the template for overwrite */\n"); + fprintf(file, "\tInOvTemplate->msgh_body.msgh_descriptor_count = %d;\n", rt->rtOverwriteKPDs); + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + char *ref = arg->argByReferenceUser ? "*" : ""; + argument_t *count; + char *cref; + boolean_t VarIndex; + u_int howmany, howbig; + + if (akCheck(arg->argKind, akbOverwrite)) { + if (arg->argFlags & flOverwrite) { + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, TRUE, it->itVarArray, arg, TRUE); + if (it->itVarArray) + finish = TRUE; + sprintf(string, "\tptr->"); + subindex = "[i]"; + count = arg->argSubCount; + VarIndex = it->itElement->itVarArray; + howmany = it->itElement->itNumber; + howbig = it->itElement->itSize; + } + else { + sprintf(string, "InOvTemplate->%s.", arg->argMsgField); + subindex = ""; + count = arg->argCount; + VarIndex = it->itVarArray; + howmany = it->itNumber; + howbig = it->itSize; + } + + fprintf(file, "\t%saddress = (void *) %s%s%s;\n", string, ref, arg->argVarName, subindex); + + if (it->itPortType) { + fprintf(file, "\t%scount = ", string); + if (VarIndex) { + cref = count->argByReferenceUser ? "*" : ""; + fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex); + } + else + fprintf(file, "%d;\n", howmany); + } + else { + fprintf(file, "\t%ssize = ", string); + if (VarIndex) { + cref = count->argByReferenceUser ? "*" : ""; + if (count->argMultiplier > 1 || howbig > 8) + fprintf(file, "%s%s%s * %d;\n", cref, count->argVarName, subindex, count->argMultiplier * howbig / 8); + else + fprintf(file, "%s%s%s;\n", cref, count->argVarName, subindex); + } + else + fprintf(file, "\t%ssize = %d;\n", string, (howmany * howbig + 7)/8); + } + fprintf(file, "\t%scopy = MACH_MSG_OVERWRITE;\n", string); + fprintf(file, "\t%stype = MACH_MSG_OOL_%sDESCRIPTOR;\n", string, (it->itPortType) ? "PORTS_" : ""); + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n"); + if (finish) { + fprintf(file, "\t for (i = %s%s; i < %d; ptr++, i++) {\n", (arg->argCount->argByReferenceUser) ? "*" : "", arg->argCount->argVarName, it->itKPD_Number); + fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n"); + fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : ""); + fprintf(file, "\t }\n"); + } + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t}\n"); + } + else { + /* just a placeholder */ + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, TRUE, FALSE, arg, TRUE); + fprintf(file, "\t\tptr->copy = MACH_MSG_ALLOCATE;\n"); + fprintf(file, "\t\tptr->type = MACH_MSG_OOL_%sDESCRIPTOR;\n", (it->itPortType) ? "PORTS_" : ""); + fprintf(file, "\t }\n\t}\n"); + } + else { + fprintf(file, "\tInOvTemplate->%s.copy = MACH_MSG_ALLOCATE;\n", arg->argMsgField); + /* not sure whether this is needed */ + fprintf(file, "\tInOvTemplate->%s.type = MACH_MSG_OOL_%sDESCRIPTOR;\n", arg->argMsgField, (it->itPortType) ? "PORTS_" : ""); + } + } + } + } + fprintf(file, "\n"); +} + +/************************************************************* + * Writes code to copy an argument into the request message. + * Called by WriteRoutine for each argument that is to placed + * in the request message. + *************************************************************/ + +static void +WritePackArgValueNormal(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *ref = (arg->argByReferenceUser || + it->itNativePointer) ? "*" : ""; + + if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) { + if (it->itString) { + /* + * Copy variable-size C string with mig_strncpy. + * Save the string length (+ 1 for trailing 0) + * in the argument`s count field. + */ + fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n"); + fprintf(file, "\t\tInP->%s = (%s) mig_strncpy_zerofill(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber); + fprintf(file, "\t} else {\n"); + fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); + + fprintf(file, "\t\tInP->%s = (%s) mig_strncpy(InP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argCount->argType->itTransType, arg->argMsgField, arg->argVarName, it->itNumber); + + fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "\t}\n"); + fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); + + fprintf(file, "\tInP->%sOffset = 0;\n", arg->argMsgField); + } + else if (it->itNoOptArray) + fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, %d);\n", arg->argMsgField, ref, arg->argVarName, it->itTypeSize); + else { + + /* + * Copy in variable-size inline array with (void)memcpy, + * after checking that number of elements doesn`t + * exceed declared maximum. + */ + argument_t *count = arg->argCount; + char *countRef = count->argByReferenceUser ? "*" : ""; + ipc_type_t *btype = it->itElement; + + /* Note btype->itNumber == count->argMultiplier */ + + if (akIdent(arg->argKind) != akeSubCount) { + /* we skip the SubCount case, as we have already taken care of */ + fprintf(file, "\tif (%s%s > %d) {\n", countRef, count->argVarName, it->itNumber/btype->itNumber); + WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); + fprintf(file, "\t}\n"); + } + + fprintf(file, "\t(void)memcpy((char *) InP->%s, (const char *) %s%s, ", arg->argMsgField, ref, arg->argVarName); + if (btype->itTypeSize > 1) + fprintf(file, "%d * ", btype->itTypeSize); + fprintf(file, "%s%s);\n", countRef, count->argVarName); + } + } + else if (IS_OPTIONAL_NATIVE(it)) { + fprintf(file, "\tif ((InP->__Present__%s = (%s != %s))) {\n", arg->argMsgField, arg->argVarName, it->itBadValue); + WriteCopyType(file, it, TRUE, "\tInP->%s.__Real__%s", "/* %s%s */ %s%s", arg->argMsgField, arg->argMsgField, ref, arg->argVarName); + fprintf(file, "\t}\n"); + } + else + WriteCopyType(file, it, TRUE, "InP->%s", "/* %s */ %s%s", arg->argMsgField, ref, arg->argVarName); + + if (arg->argPadName != NULL && it->itPadSize != 0) { + fprintf(file, "\t for (int i = 0; i < %d; i++)\n", it->itPadSize); + fprintf(file, "\t\t InP->%s[i] = 0;\n", arg->argPadName); + } + fprintf(file, "\n"); +} + +/* + * Calculate the size of a variable-length message field. + */ +static void +WriteArgSizeVariable(FILE *file, argument_t *arg, ipc_type_t *ptype) +{ + int bsize = ptype->itElement->itTypeSize; + argument_t *count = arg->argCount; + + if (PackMsg == FALSE) { + fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize); + return; + } + + /* If the base type size of the data field isn`t a multiple of 4, + we have to round up. */ + if (bsize % itWordAlign != 0) + fprintf(file, "_WALIGN_"); + fprintf(file, "("); + if (bsize > 1) + fprintf(file, "%d * ", bsize); + if (ptype->itString) + /* get count from descriptor in message */ + fprintf(file, "InP->%s", count->argMsgField); + else + /* get count from argument */ + fprintf(file, "%s%s", count->argByReferenceUser ? "*" : "", count->argVarName); + fprintf(file, ")"); +} + +static void +WriteArgSizeOptional(FILE *file, argument_t *arg, ipc_type_t *ptype) +{ + fprintf(file, "(InP->__Present__%s ? _WALIGNSZ_(%s) : 0)", arg->argVarName, ptype->itUserType); +} + +static void +WriteArgSize(FILE *file, argument_t *arg) + +{ + ipc_type_t *ptype = arg->argType; + + if (IS_OPTIONAL_NATIVE(ptype)) + WriteArgSizeOptional(file, arg, ptype); + else + WriteArgSizeVariable(file, arg, ptype); +} + +/* + * Adjust message size and advance request pointer. + * Called after packing a variable-length argument that + * has more arguments following. + */ +static void +WriteAdjustMsgSize(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argType; + + /* There are more In arguments. We need to adjust msgh_size + and advance InP, so we save the size of the current field + in msgh_size_delta. */ + + fprintf(file, "\tmsgh_size_delta = "); + WriteArgSize(file, arg); + fprintf(file, ";\n"); + + if (arg->argRequestPos == 0) { + /* First variable-length argument. The previous msgh_size value + is the minimum request size. */ + + fprintf(file, "\tmsgh_size = "); + rtMinRequestSize(file, arg->argRoutine, "Request"); + fprintf(file, " + msgh_size_delta;\n"); + } + else + fprintf(file, "\tmsgh_size += msgh_size_delta;\n"); + + if (PackMsg == TRUE) { + fprintf(file, "\tInP = (Request *) ((pointer_t) InP + msgh_size_delta - "); + if (IS_OPTIONAL_NATIVE(ptype)) + fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType); + else + fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize); + fprintf(file, ");\n\n"); + } +} + +/* + * Calculate the size of the message. Called after the + * last argument has been packed. + */ +static void +WriteFinishMsgSize(FILE *file, argument_t *arg) +{ + /* No more In arguments. If this is the only variable In + argument, the previous msgh_size value is the minimum + request size. */ + + if (arg->argRequestPos == 0) { + fprintf(file, "\tmsgh_size = "); + rtMinRequestSize(file, arg->argRoutine, "Request"); + fprintf(file, " + ("); + WriteArgSize(file, arg); + fprintf(file, ");\n"); + } + else { + fprintf(file, "\tmsgh_size += "); + WriteArgSize(file, arg); + fprintf(file, ";\n"); + } +} + +static void +WriteInitializeCount(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argCInOut->argParent->argType; + ipc_type_t *btype = ptype->itElement; + + fprintf(file, "\tif (%s%s < %d)\n", arg->argByReferenceUser ? "*" : "", arg->argVarName, ptype->itNumber/btype->itNumber); + fprintf(file, "\t\tInP->%s = %s%s;\n", arg->argMsgField, arg->argByReferenceUser ? "*" : "", arg->argVarName); + fprintf(file, "\telse\n"); + fprintf(file, "\t\tInP->%s = %d;\n", arg->argMsgField, ptype->itNumber/btype->itNumber); + fprintf(file, "\n"); +} + +/* + * Generate code to fill in all of the request arguments and their + * message types. + */ +static void +WriteRequestArgs(FILE *file, routine_t *rt) +{ + argument_t *arg; + argument_t *lastVarArg; + + /* + * 1. The Kernel Processed Data + */ + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, akbSendSnd|akbSendKPD)) + (*arg->argKPD_Pack)(file, arg); + + /* + * 2. The Data Stream + */ + lastVarArg = argNULL; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + /* + * Adjust message size and advance message pointer if + * the last request argument was variable-length and the + * request position will change. + */ + if (lastVarArg != argNULL && + lastVarArg->argRequestPos < arg->argRequestPos) { + WriteAdjustMsgSize(file, lastVarArg); + lastVarArg = argNULL; + } + + if ((akIdent(arg->argKind) == akeCountInOut) && + akCheck(arg->argKind, akbSendSnd)) + WriteInitializeCount(file, arg); + else if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody)) + WritePackArgValueNormal(file, arg); + /* + * Remember whether this was variable-length. + */ + if (akCheckAll(arg->argKind, akbSendSnd|akbSendBody|akbVariable)) + lastVarArg = arg; + } + /* + * Finish the message size. + */ + if (lastVarArg != argNULL) + WriteFinishMsgSize(file, lastVarArg); +} + +/************************************************************* + * Writes code to check that the return msgh_id is correct and that + * the size of the return message is correct. Called by + * WriteRoutine. + *************************************************************/ +static void +WriteCheckIdentity(FILE *file, routine_t *rt) +{ + fprintf(file, "\tif (Out0P->Head.msgh_id != %d) {\n", rt->rtNumber + SubsystemBase + 100); + fprintf(file, "\t if (Out0P->Head.msgh_id == MACH_NOTIFY_SEND_ONCE)\n"); + fprintf(file, "\t\t{ return MIG_SERVER_DIED; }\n"); + fprintf(file, "\t else\n"); + fprintf(file, "\t\t{ return MIG_REPLY_MISMATCH; }\n"); + fprintf(file, "\t}\n"); + fprintf(file, "\n"); + if (!rt->rtSimpleReply) + fprintf(file, "\tmsgh_simple = !(Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX);\n"); + fprintf(file, "#if\t__MigTypeCheck\n"); + + if (!rt->rtNoReplyArgs) + fprintf(file, "\tmsgh_size = Out0P->Head.msgh_size;\n\n"); + + if (rt->rtSimpleReply) { + /* Expecting a simple message. We can factor out the check for + * a simple message, since the error reply message is also simple. + */ + fprintf(file, "\tif ((Out0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n"); + if (rt->rtNoReplyArgs) + fprintf(file, "\t (Out0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Reply)))\n"); + else { + /* + * We have an error iff: + * 1) the message size is not the one expected AND + * 2) the message size is also different from sizeof(mig_reply_error_t) + * or the RetCode == KERN_SUCCESS + */ + if (rt->rtNumReplyVar > 0) { + fprintf(file, "\t ((msgh_size > (mach_msg_size_t)sizeof(__Reply) || msgh_size < "); + rtMinReplySize(file, rt, "__Reply"); + fprintf(file, ") &&\n"); + } + else + fprintf(file, "\t ((msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n"); + fprintf(file, "\t (msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n"); + fprintf(file, "\t Out0P->RetCode == KERN_SUCCESS)))\n"); + } + } + else { + /* Expecting a complex message. */ + + fprintf(file, "\t" "if ((msgh_simple || Out0P->msgh_body.msgh_descriptor_count != %d ||\n", rt->rtReplyKPDs); + if (rt->rtNumReplyVar > 0) { + fprintf(file, "\t msgh_size < "); + rtMinReplySize(file, rt, "__Reply"); + fprintf(file, " || msgh_size > (mach_msg_size_t)sizeof(__Reply)) &&\n"); + } + else + fprintf(file, "\t msgh_size != (mach_msg_size_t)sizeof(__Reply)) &&\n"); + fprintf(file, "\t (!msgh_simple || msgh_size != (mach_msg_size_t)sizeof(mig_reply_error_t) ||\n"); + fprintf(file, "\t ((mig_reply_error_t *)Out0P)->RetCode == KERN_SUCCESS))\n"); + } + fprintf(file, "\t\t{ return MIG_TYPE_ERROR ; }\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + fprintf(file, "\n"); +} + +/************************************************************* + * Write code to generate error handling code if the RetCode + * argument of a Routine is not KERN_SUCCESS. + *************************************************************/ +static void +WriteRetCodeCheck(FILE *file, routine_t *rt) +{ + if (rt->rtSimpleReply) + fprintf(file, "\tif (Out0P->RetCode != KERN_SUCCESS) {\n"); + else + fprintf(file, "\tif (msgh_simple) {\n"); + if (CheckNDR) { + fprintf(file, "#ifdef\t__NDR_convert__mig_reply_error_t__defined\n"); + fprintf(file, "\t\t__NDR_convert__mig_reply_error_t((mig_reply_error_t *)Out0P);\n"); + fprintf(file, "#endif\t/* __NDR_convert__mig_reply_error_t__defined */\n"); + } + fprintf(file, "\t\treturn ((mig_reply_error_t *)Out0P)->RetCode;\n"); + fprintf(file, "\t}\n"); + fprintf(file, "\n"); +} + +/* + * argKPD_TypeCheck discipline for Port types. + */ +static void +WriteTCheckKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *tab = ""; + char string[MAX_STR_LEN]; + boolean_t close = FALSE; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE); + (void)sprintf(string, "ptr->"); + tab = "\t"; + close = TRUE; + } + else + (void)sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField); + fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string); + if (arg->argPoly == argNULL && !it->itVarArray) + /* we can't check disposition when poly or VarArray, + (because some of the entries could be empty) */ + fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, it->itOutNameStr); + fprintf(file, + ") {\n" + "\t\t%s" "return MIG_TYPE_ERROR;\n" + "\t%s" "}\n" + , tab, tab); + if (close) + fprintf(file, "\t }\n\t}\n"); +} + +/* + * argKPD_TypeCheck discipline for out-of-line types. + */ +static void +WriteTCheckKPD_ool(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *tab, string[MAX_STR_LEN]; + boolean_t test; + u_int howmany, howbig; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + howmany = it->itElement->itNumber; + howbig = it->itElement->itSize; + test = !it->itVarArray && !it->itElement->itVarArray; + } + else { + tab = ""; + sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField); + howmany = it->itNumber; + howbig = it->itSize; + test = !it->itVarArray; + } + + fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string); + if (test) + /* if VarArray we may use no-op; if itElement->itVarArray size might change */ + fprintf(file, " ||\n\t%s %ssize != %d", tab, string, (howmany * howbig + 7)/8); + fprintf(file, + ") {\n" + "\t\t%s" "return MIG_TYPE_ERROR;\n" + "\t%s" "}\n" + , tab, tab); + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n\t}\n"); +} + +/* + * argKPD_TypeCheck discipline for out-of-line Port types. + */ +static void +WriteTCheckKPD_oolport(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *tab, string[MAX_STR_LEN]; + boolean_t test; + u_int howmany; + char *howstr; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, FALSE, arg, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + howmany = it->itElement->itNumber; + test = !it->itVarArray && !it->itElement->itVarArray; + howstr = it->itElement->itOutNameStr; + } + else { + tab = ""; + sprintf(string, "Out%dP->%s.", arg->argReplyPos, arg->argMsgField); + howmany = it->itNumber; + test = !it->itVarArray; + howstr = it->itOutNameStr; + } + + fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string); + if (test) + /* if VarArray we may use no-op; if itElement->itVarArray size might change */ + fprintf(file, " ||\n\t%s %scount != %d", tab, string, howmany); + if (arg->argPoly == argNULL) + fprintf(file, " ||\n\t%s %sdisposition != %s", tab, string, howstr); + fprintf(file, ") {\n" + "\t\t%s" "return MIG_TYPE_ERROR;\n" + "\t%s" "}\n" + ,tab, tab); + if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t }\n\t}\n"); +} + +/************************************************************* + * Writes code to check that the type of each of the arguments + * in the reply message is what is expected. Called by + * WriteRoutine for each out && typed argument in the reply message. + *************************************************************/ +static void +WriteTypeCheck(FILE *file, argument_t *arg) +{ + fprintf(file, "#if\t__MigTypeCheck\n"); + (*arg->argKPD_TypeCheck)(file, arg); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); +} + + +/* + * argKPD_Extract discipline for Port types. + */ +static void +WriteExtractKPD_port(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char *ref = arg->argByReferenceUser ? "*" : ""; + char *subindex; + char *recast = ""; + ipc_type_t *real_it; + + real_it = (IS_MULTIPLE_KPD(it)) ? it->itElement : it; +#ifdef MIG_KERNEL_PORT_CONVERSION + if (IsKernelUser && streql(real_it->itUserType, "ipc_port_t")) + recast = "(mach_port_t)"; +#endif + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE); + + fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast); + if (it->itVarArray) { + argument_t *count = arg->argCount; + char *cref = count->argByReferenceUser ? "*" : ""; + + fprintf(file, "\t if (Out%dP->%s >",count->argReplyPos, count->argVarName); + if (arg->argCountInOut) { + fprintf(file, " %s%s)\n", cref, count->argVarName); + } + else { + fprintf(file, " %d)\n", it->itNumber/it->itElement->itNumber); + } + WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); + } + fprintf(file, "\t}\n"); + subindex = "[0]"; + } + else { + fprintf(file, "\t%s%s = %sOut%dP->%s.name;\n", ref, arg->argVarName, recast, arg->argReplyPos, arg->argMsgField); + subindex = ""; + } + + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) { + argument_t *poly = arg->argPoly; + char *pref = poly->argByReferenceUser ? "*" : ""; + + fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex); + } +} + +/* + * argKPD_Extract discipline for out-of-line types. + */ +static void +WriteExtractKPD_ool(FILE *file, argument_t *arg) +{ + char *ref = arg->argByReferenceUser ? "*" : ""; + ipc_type_t *it = arg->argType; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE); + fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName); + fprintf(file, "\t}\n"); + } + else + fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField); + /* + * In case of variable sized arrays, + * the count field will be retrieved from the untyped + * section of the message + */ +} + +/* + * argKPD_Extract discipline for out-of-line Port types. + */ +static void +WriteExtractKPD_oolport(FILE *file, argument_t *arg) +{ + char *ref = arg->argByReferenceUser ? "*" : ""; + ipc_type_t *it = arg->argType; + char *subindex; + + if (IS_MULTIPLE_KPD(it)) { + WriteKPD_Iterator(file, FALSE, FALSE, it->itVarArray, arg, FALSE); + fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName); + fprintf(file, "\t}\n"); + subindex = "[0]"; + } + else { + fprintf(file, "\t%s%s = (%s)(Out%dP->%s.address);\n", ref, arg->argVarName, arg->argType->itUserType, arg->argReplyPos, arg->argMsgField); + subindex = ""; + } + /* + * In case of variable sized arrays, + * the count field will be retrieved from the untyped + * section of the message + */ + if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnRcv)) { + argument_t *poly = arg->argPoly; + char *pref = poly->argByReferenceUser ? "*" : ""; + + fprintf(file, "\t%s%s = Out%dP->%s%s.disposition;\n", pref, poly->argVarName, arg->argReplyPos, arg->argMsgField, subindex); + } +} + +/************************************************************* + * Write code to copy an argument from the reply message + * to the parameter. Called by WriteRoutine for each argument + * in the reply message. + *************************************************************/ + +static void +WriteExtractArgValueNormal(FILE *file, argument_t *arg) +{ + ipc_type_t *argType = arg->argType; + char *ref = arg->argByReferenceUser ? "*" : ""; + char who[20]; + + if (akCheck(arg->argKind, akbUserImplicit)) + sprintf(who, "TrailerP"); + else + sprintf(who, "Out%dP", arg->argReplyPos); + + if (IS_VARIABLE_SIZED_UNTYPED(argType) || argType->itNoOptArray) { + if (argType->itString) { + /* + * Copy out variable-size C string with mig_strncpy, not the zerofill variant. + * We don't risk leaking process / kernel memory on this copy-out because + * we've already zero-filled the buffer on copy-in. + */ + fprintf(file, "\t(void) mig_strncpy(%s%s, %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itNumber); + } + else if (argType->itNoOptArray) + fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) %s->%s, %d);\n", ref, arg->argVarName, who, arg->argMsgField, argType->itTypeSize); + else { + + /* + * Copy out variable-size inline array with (void)memcpy, + * after checking that number of elements doesn`t + * exceed user`s maximum. + */ + argument_t *count = arg->argCount; + char *countRef = count->argByReferenceUser ? "*" : ""; + ipc_type_t *btype = argType->itElement; + + /* Note count->argMultiplier == btype->itNumber */ + /* Note II: trailer logic isn't supported in this case */ + fprintf(file, "\tif (Out%dP->%s", count->argReplyPos, count->argMsgField); + if (arg->argCountInOut) { + fprintf(file, " > %s%s) {\n", countRef, count->argVarName); + } + else { + fprintf(file, " > %d) {\n", argType->itNumber/btype->itNumber); + } + + /* + * If number of elements is too many for user receiving area, + * fill user`s area as much as possible. Return the correct + * number of elements. + */ + fprintf(file, "\t\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField); + if (btype->itTypeSize > 1) + fprintf(file, "%d * ", btype->itTypeSize); + if (arg->argCountInOut) { + fprintf(file, " %s%s);\n", countRef, count->argVarName); + } + else { + fprintf(file, " %d);\n", argType->itNumber/btype->itNumber); + } + fprintf(file, "\t\t%s%s = Out%dP->%s", countRef, count->argVarName, count->argReplyPos, count->argMsgField); + fprintf(file, ";\n"); + WriteReturnMsgError(file, arg->argRoutine, TRUE, arg, "MIG_ARRAY_TOO_LARGE"); + + fprintf(file, "\t}\n"); + + fprintf(file, "\t(void)memcpy((char *) %s%s, (const char *) Out%dP->%s, ", ref, arg->argVarName, arg->argReplyPos, arg->argMsgField); + if (btype->itTypeSize > 1) + fprintf(file, "%d * ", btype->itTypeSize); + fprintf(file, "Out%dP->%s);\n", count->argReplyPos, count->argMsgField); + } + } + else + WriteCopyType(file, argType, FALSE, "%s%s", "/* %s%s */ %s->%s", ref, arg->argVarName, who, arg->argMsgField); + fprintf(file, "\n"); +} + +static void +WriteCalcArgSize(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argType; + ipc_type_t *btype = ptype->itElement; + argument_t *count = arg->argCount; + int multiplier = btype->itTypeSize; + + /* If the base type size of the data field isn`t a multiple of 4, + we have to round up. */ + if (btype->itTypeSize % itWordAlign != 0) + fprintf(file, "_WALIGN_("); + + fprintf(file, "Out%dP->%s", count->argReplyPos, count->argMsgField); + if (multiplier > 1) + fprintf(file, " * %d", multiplier); + + if (btype->itTypeSize % itWordAlign != 0) + fprintf(file, ")"); +} + +static void +WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator) +{ + ipc_type_t *ptype = arg->argType; + ipc_type_t *btype = ptype->itElement; + argument_t *count = arg->argCount; + int multiplier = btype->itTypeSize; + + fprintf(file, "\tif (((msgh_size - "); + rtMinReplySize(file, rt, "__Reply"); + fprintf(file, ")"); + if (multiplier > 1) + fprintf(file, " / %d", multiplier); + fprintf(file, "< Out%dP->%s) ||\n", count->argReplyPos, count->argMsgField); + fprintf(file, "\t (msgh_size %s ", comparator); + rtMinReplySize(file, rt, "__Reply"); + fprintf(file, " + "); + WriteCalcArgSize(file, arg); + fprintf(file, ")"); + fprintf(file, ")\n\t\t{ return MIG_TYPE_ERROR ; }\n"); +} + + +/* NDR Conversion routines */ + + +void +WriteReplyNDRConvertIntRepArgCond(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + fprintf(file, "defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField); +} + +void +WriteReplyNDRConvertCharRepArgCond(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) + fprintf(file, "defined(__NDR_convert__char_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField); + else + fprintf(file, "0"); +} + +void +WriteReplyNDRConvertFloatRepArgCond(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) + fprintf(file, "defined(__NDR_convert__float_rep__Reply__%s_t__%s__defined)", rt->rtName, arg->argMsgField); + else + fprintf(file, "0"); +} + +void +WriteReplyNDRConvertIntRepArgDecl(FILE *file, argument_t *arg) +{ + WriteNDRConvertArgDecl(file, arg, "int_rep", "Reply"); +} + +void +WriteReplyNDRConvertCharRepArgDecl(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) + WriteNDRConvertArgDecl(file, arg, "char_rep", "Reply"); +} + +void +WriteReplyNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) + WriteNDRConvertArgDecl(file, arg, "float_rep", "Reply"); +} + + + +void +WriteReplyNDRConvertArgUse(FILE *file, argument_t *arg, char *convert) +{ + routine_t *rt = arg->argRoutine; + argument_t *count = arg->argCount; + char argname[MAX_STR_LEN]; + + if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) && + (arg->argParent && akCheck(arg->argParent->argKind, akbReturnNdr))) + return; + + if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { + if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) { + fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, count->argMsgField); + fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argReplyPos, count->argMsgField, count->argReplyPos); + fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, count->argMsgField); + } + + sprintf(argname, "(%s)(Out%dP->%s.address)", FetchServerType(arg->argType), arg->argReplyPos, arg->argMsgField); + } + else { + sprintf(argname, "&Out%dP->%s", arg->argReplyPos, arg->argMsgField); + } + + fprintf(file, "#if defined(__NDR_convert__%s__Reply__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField); + fprintf(file, "\t\t__NDR_convert__%s__Reply__%s_t__%s(%s, Out0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert); + if (count) + fprintf(file, ", Out%dP->%s", count->argReplyPos, count->argMsgField); + fprintf(file, ");\n"); + fprintf(file, "#endif /* __NDR_convert__%s__Reply__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField); +} + +void +WriteReplyNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + fprintf(file, "#if defined(__NDR_convert__int_rep__Reply__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField); + fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep)\n"); + fprintf(file, "\t\t__NDR_convert__int_rep__Reply__%s_t__%s(&Out%dP->%s, Out%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argReplyPos, arg->argMsgField, arg->argReplyPos); + fprintf(file, "#endif\t/* __NDR_convert__int_rep__Reply__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField); +} + +void +WriteReplyNDRConvertIntRepArgUse(FILE *file, argument_t *arg) +{ + WriteReplyNDRConvertArgUse(file, arg, "int_rep"); +} + +void +WriteReplyNDRConvertCharRepArgUse(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) + WriteReplyNDRConvertArgUse(file, arg, "char_rep"); +} + +void +WriteReplyNDRConvertFloatRepArgUse(FILE *file, argument_t *arg) +{ + if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) !=akeCountInOut && akIdent(arg->argKind) != akeRetCode) + WriteReplyNDRConvertArgUse(file, arg, "float_rep"); +} + +static void +WriteCheckMsgSize(FILE *file, argument_t *arg) +{ + routine_t *rt = arg->argRoutine; + + /* If there aren't any more Out args after this, then + we can use the msgh_size_delta value directly in + the TypeCheck conditional. */ + + if (CheckNDR && arg->argCount && !arg->argSameCount) + WriteReplyNDRConvertIntRepOneArgUse(file, arg->argCount); + + if (arg->argReplyPos == rt->rtMaxReplyPos) { + fprintf(file, "#if\t__MigTypeCheck\n"); + + /* + * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type. + */ + fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, arg->argCount->argMsgField, arg->argType->itNumber); + fputs("\t\t" "return MIG_TYPE_ERROR;\n", file); + /* ...end... */ + + WriteCheckArgSize(file, rt, arg, "!="); + + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + else { + /* If there aren't any more variable-sized arguments after this, + then we must check for exact msg-size and we don't need + to update msgh_size. */ + + boolean_t LastVarArg = arg->argReplyPos+1 == rt->rtNumReplyVar; + + /* calculate the actual size in bytes of the data field. note + that this quantity must be a multiple of four. hence, if + the base type size isn't a multiple of four, we have to + round up. note also that btype->itNumber must + divide btype->itTypeSize (see itCalculateSizeInfo). */ + + fprintf(file, "\tmsgh_size_delta = "); + WriteCalcArgSize(file, arg); + fprintf(file, ";\n"); + fprintf(file, "#if\t__MigTypeCheck\n"); + + /* + * emit code to verify that the server-code-provided count does not exceed the maximum count allowed by the type. + */ + fprintf(file, "\t" "if ( Out%dP->%s > %d )\n", arg->argCount->argReplyPos, arg->argCount->argMsgField, arg->argType->itNumber); + fputs("\t\t" "return MIG_TYPE_ERROR;\n", file); + /* ...end... */ + + WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<"); + + if (!LastVarArg) + fprintf(file, "\tmsgh_size -= msgh_size_delta;\n"); + + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + fprintf(file, "\n"); +} + +void +WriteAdjustReplyMsgPtr(FILE *file, argument_t *arg) +{ + ipc_type_t *ptype = arg->argType; + + fprintf(file, "\t*Out%dPP = Out%dP = (__Reply *) ((pointer_t) Out%dP + msgh_size_delta - %d);\n\n", + arg->argReplyPos+1, arg->argReplyPos +1, arg->argReplyPos, ptype->itTypeSize + ptype->itPadSize); +} + +static void +WriteReplyArgs(FILE *file, routine_t *rt) +{ + argument_t *arg; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) { + WriteExtractArgValueNormal(file, arg); + } + else if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnKPD)) { + /* + * KPDs have argReplyPos 0, therefore they escape the above logic + */ + (*arg->argKPD_Extract)(file, arg); + } + else if (akCheck(arg->argKind, akbUserImplicit)) { + WriteExtractArgValueNormal(file, arg); + } + } +} + +/************************************************************* + * Writes code to return the return value. Called by WriteRoutine + * for routines and functions. + *************************************************************/ +static void +WriteReturnValue(FILE *file, routine_t *rt) +{ + /* If returning RetCode, we have already checked that it is KERN_SUCCESS */ + WriteReturn(file, rt, "\t", "KERN_SUCCESS", "\n", TRUE); +} + +/************************************************************* + * Writes the elements of the message type declaration: the + * msg_type structure, the argument itself and any padding + * that is required to make the argument a multiple of 4 bytes. + * Called by WriteRoutine for all the arguments in the request + * message first and then the reply message. + *************************************************************/ +static void +WriteFieldDecl(FILE *file, argument_t *arg) +{ + if (akCheck(arg->argKind, akbSendKPD) || + akCheck(arg->argKind, akbReturnKPD)) + WriteFieldDeclPrim(file, arg, FetchKPDType); + else + WriteFieldDeclPrim(file, arg, FetchUserType); +} + +/* Fill in the string with an expression that refers to the size + * of the specified array: + */ +static void +GetArraySize(argument_t *arg, char *size) +{ + ipc_type_t *it = arg->argType; + + if (it->itVarArray) { + if (arg->argCount->argByReferenceUser) { + sprintf(size, "*%s", arg->argCount->argVarName); + } + else + sprintf(size, "%s", arg->argCount->argVarName); + } + else { + sprintf(size, "%d", (it->itNumber * it->itSize + 7) / 8); + } +} + + +static void +WriteRPCPortDisposition(FILE *file, argument_t *arg) +{ + /* + * According to the MIG specification, the port disposition could be different + * on input and output. If we stay with this then a new bitfield will have + * to be added. Right now the port disposition is the same for in and out cases. + */ + switch(arg->argType->itInName) { + + case MACH_MSG_TYPE_MOVE_RECEIVE: + fprintf(file, " | MACH_RPC_MOVE_RECEIVE"); + break; + + case MACH_MSG_TYPE_MOVE_SEND: + fprintf(file, " | MACH_RPC_MOVE_SEND"); + break; + + case MACH_MSG_TYPE_MOVE_SEND_ONCE: + fprintf(file, " | MACH_RPC_MOVE_SEND_ONCE"); + break; + + case MACH_MSG_TYPE_COPY_SEND: + fprintf(file, " | MACH_RPC_COPY_SEND"); + break; + + case MACH_MSG_TYPE_MAKE_SEND: + fprintf(file, " | MACH_RPC_MAKE_SEND"); + break; + + case MACH_MSG_TYPE_MAKE_SEND_ONCE: + fprintf(file, " | MACH_RPC_MAKE_SEND_ONCE"); + break; + } +} + +static void +WriteRPCArgDescriptor(FILE *file, argument_t *arg, int offset) +{ + fprintf(file, " {\n 0 "); + if (RPCPort(arg)) { + fprintf(file, "| MACH_RPC_PORT "); + if (arg->argType->itNumber > 1) + fprintf(file, "| MACH_RPC_ARRAY "); + if (arg->argType->itVarArray) + fprintf(file, "| MACH_RPC_VARIABLE "); + WriteRPCPortDisposition(file, arg); + } + else if (RPCPortArray(arg)) { + fprintf(file, "| MACH_RPC_PORT_ARRAY "); + if (arg->argType->itVarArray) + fprintf(file, "| MACH_RPC_VARIABLE "); + WriteRPCPortDisposition(file, arg); + } + else if (RPCFixedArray(arg)) + fprintf(file, "| MACH_RPC_ARRAY_FIXED "); + else if (RPCVariableArray(arg)) + fprintf(file, "| MACH_RPC_ARRAY_VARIABLE "); + if (argIsIn(arg)) + fprintf(file, " | MACH_RPC_IN "); + if (argIsOut(arg)) + fprintf(file, " | MACH_RPC_OUT "); + if ((! arg->argType->itInLine) && (! arg->argType->itMigInLine)) + fprintf(file, " | MACH_RPC_POINTER "); + if (arg->argFlags & flDealloc) + fprintf(file, " | MACH_RPC_DEALLOCATE "); + if (arg->argFlags & flPhysicalCopy) + fprintf(file, " | MACH_RPC_PHYSICAL_COPY "); + fprintf(file, ",\n"); + fprintf(file, " %d,\n", (arg->argType->itSize / 8)); + fprintf(file, " %d,\n", arg->argType->itNumber); + fprintf(file, " %d,\n },\n", offset); +} + +void +WriteRPCRoutineDescriptor(FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array) +{ + fprintf(file, " { (mig_impl_routine_t) 0,\n\ + (mig_stub_routine_t) %s, ", stub_routine); + fprintf(file, "%d, %d, %s}", arg_count, descr_count, sig_array); +} + +void +WriteRPCRoutineArgDescriptor(FILE *file, routine_t *rt) +{ + argument_t *arg; + int offset = 0; + int size = 0; + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + boolean_t compound = arg->argType->itStruct && arg->argType->itInLine; + + if (RPCPort(arg) || RPCPortArray(arg) || + RPCFixedArray(arg) || RPCVariableArray(arg)) { + WriteRPCArgDescriptor(file, arg, offset); + size = 4; + } + if (! size) { + if (compound) + size = arg->argType->itNumber * (arg->argType->itSize / 8); + else + size = (arg->argType->itSize / 8); + } + if (akCheck(arg->argKind, akbServerArg)) + offset += size; + size = 0; + } +} + + +static void +WriteRPCSignature(FILE *file, routine_t *rt) +{ + int arg_count = 0; + int descr_count = 0; + + fprintf(file, " kern_return_t rtn;\n"); + descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count); + fprintf(file, " const static struct\n {\n"); + fprintf(file, " struct rpc_routine_descriptor rd;\n"); + fprintf(file, " struct rpc_routine_arg_descriptor rad[%d];\n", descr_count); + fprintf(file, " } sig =\n {\n"); + WriteRPCRoutineDescriptor(file, rt, arg_count, descr_count, "0", "sig.rad, 0"); + fprintf(file, ",\n"); + fprintf(file, " {\n"); + WriteRPCRoutineArgDescriptor(file, rt); + fprintf(file, "\n }\n"); + fprintf(file, "\n };\n\n"); +} + +static void +WriteRPCCall(FILE *file, routine_t *rt) +{ + argument_t *arg; + int i; + + i = 0; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (akIdent(arg->argKind) == akeRequestPort) { + fprintf(file, " rtn = (MACH_RPC(&sig, (mach_msg_size_t)sizeof(sig), %d, %s,\n", rt->rtNumber + SubsystemBase, arg->argVarName); + fprintf(file, " (%s", arg->argVarName); + } + else if (akCheck(arg->argKind, akbServerArg)) { + if (i && (i++ % 6 == 0)) + fprintf(file, ",\n "); + else + fprintf(file, ", "); + fprintf(file, "%s", arg->argVarName); + } + } + fprintf(file, ")));\n"); + fprintf(file, "\n"); + fprintf(file, " if (rtn != KERN_NO_ACCESS) return rtn;\n\n"); + fprintf(file, "/* The following message rpc code is generated for the network case */\n\n"); +} + +static int +CheckRPCCall(routine_t *rt) +{ + argument_t *arg; + int i; + + i = 0; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (akCheck(arg->argKind, akbUserArg) && + ((arg->argType->itOutName == -1) || (arg->argType->itInName == -1))) { + return FALSE; + } + if (arg->argFlags & flMaybeDealloc) { + return FALSE; + } + } + return TRUE; +} + +static void +WriteRPCRoutine(FILE *file, routine_t *rt) +{ + if (CheckRPCCall(rt)) { + WriteRPCSignature(file, rt); + WriteRPCCall(file, rt); + } +} + +/********************** End UserRPCTrap Routines*************************/ + +/* Process an IN/INOUT arg before the short-circuited RPC */ +static void +WriteShortCircInArgBefore(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char size[128]; + + fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName); + + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + break; + + case MACH_MSG_OOL_DESCRIPTOR: + /* Arg is an out-of-line array: */ + if (!(arg->argFlags & flDealloc) && + (!(arg->argFlags & flAuto) || !(arg->argFlags & flConst))) { + /* Need to map a copy of the array: */ + GetArraySize(arg, size); + fprintf(file, "\t(void)vm_read(mach_task_self(),\n"); + fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName); + /* Point argument at the copy: */ + fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName); + } + else if ((arg->argFlags & flDealloc) && + ((arg->argFlags & flAuto) || it->itMigInLine)) { + /* Point the temp var at the original argument: */ + fprintf(file, "\t_%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName); + } + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + break; + + default: + printf("MiG internal error: type of kernel processed data unknown\n"); + exit(1); + } /* end of switch */ + } + else if (it->itNumber > 1) { + if (it->itStruct) { + /* Arg is a struct -- nothing to do. */ + } + else { + /* Arg is a C string or an in-line array: */ + if (!argIsOut(arg) && !(arg->argFlags & flConst)) { + /* Have to copy it into a temp. Use a stack var, if this would + * not overflow the -maxonstack specification: + * Conservatively assume ILP32 thresholds + */ + if (it->itTypeSize <= sizeof(natural_t) || + rtMessOnStack(arg->argRoutine) || + arg->argRoutine->rtTempBytesOnStack + + it->itTypeSize <= MaxMessSizeOnStack) { + fprintf(file, "\t{ char _%sTemp_[%d];\n", arg->argVarName, it->itTypeSize); + arg->argRoutine->rtTempBytesOnStack += it->itTypeSize; + arg->argTempOnStack = TRUE; + } + else { + fprintf(file, "\t{ _%sTemp_ = (char *) %s(%d);\n", arg->argVarName, MessAllocRoutine, it->itTypeSize); + arg->argTempOnStack = FALSE; + } + WriteCopyArg(file, arg, TRUE, "_%sTemp_", "/* %s */ (char *) %s", arg->argVarName, arg->argVarName); + /* Point argument at temp: */ + fprintf(file, "\t *(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName); + fprintf(file, "\t}\n"); + } + } + } +} + + +/* Process an INOUT/OUT arg before the short-circuited RPC */ +static void +WriteShortCircOutArgBefore(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + + fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName); + + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + break; + + case MACH_MSG_OOL_DESCRIPTOR: + /* Arg is an out-of-line array: */ + if (!argIsIn(arg) && (arg->argFlags & flOverwrite)) { + /* Point the temp var at the original argument: */ + fprintf(file, "\t _%sTemp_ = (char *) %s%s;\n", arg->argVarName, (arg->argByReferenceUser ? "*" : ""), arg->argVarName); + } + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + break; + + default: + printf("MiG internal error: type of kernel processed data unknown\n"); + exit(1); + } /* end of switch */ + } + else if (it->itNumber > 1) { + /* Arg is an in-line array: */ + } +} + + + +/* Process an IN arg after the short-circuited RPC */ +static void +WriteShortCircInArgAfter(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char size[128]; + + fprintf(file, "\n\t/* IN %s: */\n", arg->argVarName); + + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + break; + + case MACH_MSG_OOL_DESCRIPTOR: + /* Arg is an out-of-line array: */ + GetArraySize(arg, size); + if ((!(arg->argFlags & flAuto) && it->itMigInLine) || + ((arg->argFlags & flAuto) && + ((arg->argFlags & flDealloc) || + !(arg->argFlags & flConst)) + )) { + /* Need to dealloc the temporary: */ + fprintf(file, "\t(void)vm_deallocate(mach_task_self(),"); + fprintf(file, " (vm_address_t *) _%sTemp_, %s);\n", arg->argVarName, size); + } + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + break; + + default: + printf("MiG internal error: type of kernel processed data unknown\n"); + exit(1); + } /* end of switch */ + } + else if (it->itNumber > 1) { + if (it->itStruct) { + /* Arg is a struct -- nothing to do. */ + } + else { + /* Arg is a C string or an in-line array: */ + if (!argIsOut(arg) && !(arg->argFlags & flConst)) { + /* A temp needs to be deallocated, if not on stack: */ + if (!arg->argTempOnStack) { + fprintf(file, "\t%s(_%sTemp_, %d);\n", MessFreeRoutine, arg->argVarName, it->itTypeSize); + } + } + } + } +} + +static void +WriteShortCircOutArgAfter(FILE *file, argument_t *arg) +{ + ipc_type_t *it = arg->argType; + char size[128]; + + fprintf(file, "\n\t/* OUT %s: */\n", arg->argVarName); + + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) { + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + break; + + case MACH_MSG_OOL_DESCRIPTOR: + /* Arg is an out-of-line array: */ + + /* Calculate size of array: */ + GetArraySize(arg, size); + if (!(arg->argFlags & flDealloc) || (arg->argFlags & flOverwrite)) { + /* Copy argument to vm_allocated Temp: */ + fprintf(file, "\t(void)vm_read(mach_task_self(),\n"); + fprintf(file, "\t\t (vm_address_t) %s%s, %s, (vm_address_t *) &_%sTemp_, &_MIG_Ignore_Count_);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size, arg->argVarName); + if (!argIsIn(arg) && (arg->argFlags & flDealloc) && + (arg->argFlags & flOverwrite)) { + /* Deallocate argument returned by server */ + fprintf(file, "\t(void)vm_deallocate(mach_task_self(),"); + fprintf(file, " (vm_address_t *) %s%s, %s);\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, size); + } + /* Point argument at new temporary: */ + fprintf(file, "\t*(char **)&%s%s = _%sTemp_;\n", (arg->argByReferenceUser ? "*" : ""), arg->argVarName, arg->argVarName); + } + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + break; + + default: + printf("MiG internal error: type of kernel processed data unknown\n"); + exit(1); + } /* end of switch */ + } + else if (it->itNumber != 1) { + /* Arg is an in-line array: */ + } +} + + +static void +WriteShortCircRPC(FILE *file, routine_t *rt) +{ + argument_t *arg; + int server_argc, i; + boolean_t ShortCircOkay = TRUE; + boolean_t first_OOL_arg = TRUE; + + fprintf(file, " if (0 /* Should be: !(%s & 0x3) XXX */) {\n", rt->rtRequestPort->argVarName); + + if (rt->rtOneWay) { + /* Do not short-circuit simple routines: */ + ShortCircOkay = FALSE; + } + else { + /* Scan for any types we can't yet handle. If found, give up on short- + * circuiting and fall back to mach_msg: + */ + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (arg->argFlags & flMaybeDealloc) { + ShortCircOkay = FALSE; + break; + } + /* Can't yet handle ports: */ + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && + (arg->argKPD_Type == MACH_MSG_PORT_DESCRIPTOR || + arg->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR)) { + ShortCircOkay = FALSE; + break; + } + } + } + + if (ShortCircOkay) { + + fprintf(file," rpc_subsystem_t subsystem = ((rpc_port_t)%s)->rp_subsystem;\n", rt->rtRequestPort->argVarName); + fprintf(file, "\n"); + fprintf(file, " if (subsystem && subsystem->start == %d) {\n", SubsystemBase); + fprintf(file, "\tkern_return_t rtn;\n"); + fprintf(file, "\n"); + + /* Declare temp vars for out-of-line array args, and for all array + * args, if -maxonstack has forced us to allocate in-line arrays + * off the stack: + */ + rt->rtTempBytesOnStack = 0; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + arg->argTempOnStack = FALSE; + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD) && + arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { + if (first_OOL_arg) { + /* Need a garbage temporary to hold the datacount + * returned by vm_read, which we always ignore: + */ + fprintf(file, "\tmach_msg_type_number_t _MIG_Ignore_Count_;\n"); + first_OOL_arg = FALSE; + } + } + else if (!rtMessOnStack(rt) && + arg->argType->itNumber > 1 && !arg->argType->itStruct) { + } + else + continue; + fprintf(file, "\tchar *_%sTemp_;\n", arg->argVarName); + /* Conservatively assume ILP32 thresholds */ + rt->rtTempBytesOnStack += sizeof(natural_t); + } + + /* Process the IN arguments, in order: */ + + fprintf(file, "\t/* Pre-Process the IN arguments: */\n"); + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (argIsIn(arg)) + WriteShortCircInArgBefore(file, arg); + if (argIsOut(arg)) + WriteShortCircOutArgBefore(file, arg); + } + fprintf(file, "\n"); + + /* Count the number of server args: */ + server_argc = 0; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbServerArg)) + server_argc++; + + /* Call RPC_SIMPLE to switch to server stack and function: */ + i = 0; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (akIdent(arg->argKind) == akeRequestPort) { + fprintf(file, "\trtn = RPC_SIMPLE(%s, %d, %d, (", arg->argVarName, rt->rtNumber + SubsystemBase, server_argc); + fprintf(file, "%s", arg->argVarName); + } + else if (akCheck(arg->argKind, akbServerArg)) { + if (i++ % 6 == 0) + fprintf(file, ",\n\t\t"); + else + fprintf(file, ", "); + fprintf(file, "%s", arg->argVarName); + } + } + fprintf(file, "));\n"); + fprintf(file, "\n"); + + /* Process the IN and OUT arguments, in order: */ + fprintf(file, "\t/* Post-Process the IN and OUT arguments: */\n"); + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (argIsIn(arg)) + WriteShortCircInArgAfter(file, arg); + if (argIsOut(arg)) + WriteShortCircOutArgAfter(file, arg); + } + fprintf(file, "\n"); + + fprintf(file, "\treturn rtn;\n"); + fprintf(file, " }\n"); + } + + /* In latest design, the following is not necessary, because in + * kernel-loaded tasks, the Mach port name is the same as the handle + * used by the RPC mechanism, namely a pointer to the ipc_port, and + * in user-mode tasks, the Mach port name gets renamed to be a pointer + * to the user-mode rpc_port_t struct. + */ +#if 0 + if (IsKernelUser) + fprintf(file, " %s = (ipc_port_t)%s->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName); + else + fprintf(file, " %s = ((rpc_port_t)%s)->rp_receiver_name;\n", rt->rtRequestPort->argVarName, rt->rtRequestPort->argVarName); +#endif + + fprintf(file, " }\n"); +} + +static void +WriteStubDecl(FILE *file, routine_t *rt) +{ + fprintf(file, "\n"); + fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName); + fprintf(file, "mig_external %s %s\n", ReturnTypeStr(rt), rt->rtUserName); + if (BeAnsiC) { + fprintf(file, "(\n"); + WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); + fprintf(file, ")\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "(\n"); + WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ",\n", "\n"); + fprintf(file, ")\n"); + fprintf(file, "#else\n"); + fprintf(file, "\t("); + WriteList(file, rt->rtArgs, WriteNameDecl, akbUserArg, ", ", ""); + fprintf(file, ")\n"); + WriteList(file, rt->rtArgs, WriteUserVarDecl, akbUserArg, ";\n", ";\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + fprintf(file, "{\n"); +} + +static void +InitKPD_Disciplines(argument_t *args) +{ + argument_t *arg; + extern void KPD_noop(FILE *file, argument_t *arg); + extern void KPD_error(FILE *file, argument_t *arg); + extern void WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in); + extern void WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in); + extern void WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in); + + /* + * WriteKPD_port, WriteExtractKPD_port, + * WriteKPD_ool, WriteExtractKPD_ool, + * WriteKPD_oolport, WriteExtractKPD_oolport + * are local to this module (which is the reason why this initialization + * takes place here rather than in utils.c). + * Common routines for user and server will be established SOON, and + * all of them (including the initialization) will be transfert to + * utils.c + * All the KPD disciplines are defaulted to be KPD_error(). + * Note that akbSendKPD and akbReturnKPd are not exclusive, + * because of inout type of parameters. + */ + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD)) + switch (arg->argKPD_Type) { + + case MACH_MSG_PORT_DESCRIPTOR: + arg->argKPD_Init = KPD_noop; + if akCheck(arg->argKind, akbSendKPD) { + arg->argKPD_Template = WriteTemplateKPD_port; + arg->argKPD_Pack = WriteKPD_port; + } + if akCheck(arg->argKind, akbReturnKPD) { + arg->argKPD_Extract = WriteExtractKPD_port; + arg->argKPD_TypeCheck = WriteTCheckKPD_port; + } + break; + + case MACH_MSG_OOL_DESCRIPTOR: + arg->argKPD_Init = KPD_noop; + if akCheck(arg->argKind, akbSendKPD) { + arg->argKPD_Template = WriteTemplateKPD_ool; + arg->argKPD_Pack = WriteKPD_ool; + } + if akCheck(arg->argKind, akbReturnKPD) { + arg->argKPD_TypeCheck = WriteTCheckKPD_ool; + arg->argKPD_Extract = WriteExtractKPD_ool; + } + break; + + case MACH_MSG_OOL_PORTS_DESCRIPTOR: + arg->argKPD_Init = KPD_noop; + if akCheck(arg->argKind, akbSendKPD) { + arg->argKPD_Template = WriteTemplateKPD_oolport; + arg->argKPD_Pack = WriteKPD_oolport; + } + if akCheck(arg->argKind, akbReturnKPD) { + arg->argKPD_TypeCheck = WriteTCheckKPD_oolport; + arg->argKPD_Extract = WriteExtractKPD_oolport; + } + break; + + default: + printf("MiG internal error: type of kernel processed data unknown\n"); + exit(1); + } /* end of switch */ +} + +static void +WriteLimitCheck(FILE *file, routine_t *rt) +{ + if (MaxMessSizeOnStack == -1 || UserTypeLimit == -1) + return; + if (!rt->rtRequestUsedLimit && !rt->rtReplyUsedLimit) + return; + fprintf(file, "#if LimitCheck\n"); + if (rt->rtRequestUsedLimit) { + if (rt->rtRequestFits) { + fprintf(file, "\tif ((sizeof(Request) - %d) > %d)\n", rt->rtRequestSizeKnown, UserTypeLimit); + fprintf(file, "\t __RequestOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); + } + else if (rt->rtReplyFits) { + fprintf(file, "\tif (sizeof(Request) < %d)\n", MaxMessSizeOnStack); + fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); + } + } + if (rt->rtReplyUsedLimit) { + if (rt->rtReplyFits) { + fprintf(file, "\tif ((sizeof(Reply) - %d) > %d)\n", rt->rtReplySizeKnown, UserTypeLimit); + fprintf(file, "\t __ReplyOnStackAbort(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); + } + else if (rt->rtRequestFits) { + fprintf(file, "\tif (sizeof(Reply) < %d)\n", MaxMessSizeOnStack); + fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); + } + } + if (rt->rtRequestUsedLimit && rt->rtReplyUsedLimit && + ! (rt->rtRequestFits || rt->rtReplyFits)) { + fprintf(file, "\tif (sizeof(Request) < %d \n", MaxMessSizeOnStack); + fprintf(file, "&& sizeof(Reply) < %d)\n", MaxMessSizeOnStack); + fprintf(file, "\t __MessageOffStackNote(%d, \"%s\");\n", SubsystemBase + rt->rtNumber, rt->rtName); + } + fprintf(file, "#endif /* LimitCheck */\n"); +} + +static void +WriteOOLSizeCheck(FILE *file, routine_t *rt) +{ + /* Emit code to validate the actual size of ool data vs. the reported size */ + argument_t *argPtr; + boolean_t openedTypeCheckConditional = FALSE; + + // scan through arguments to see if there are any ool data blocks + for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) { + if (akCheck(argPtr->argKind, akbReturnKPD)) { + ipc_type_t *it = argPtr->argType; + boolean_t multiple_kpd = IS_MULTIPLE_KPD(it); + char string[MAX_STR_LEN]; + boolean_t test; + argument_t *argCountPtr; + char *tab; + + if (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) { + + if (multiple_kpd) { + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + + WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + test = !it->itVarArray && !it->itElement->itVarArray; + it = it->itElement; // point to element descriptor, so size calculation is correct + argCountPtr = argPtr->argSubCount; + } else { + tab = ""; + sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField); + test = !it->itVarArray; + argCountPtr = argPtr->argCount; + } + + if (!test) { + int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1; + + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + + fprintf(file, "\t%s" "if (%ssize ", tab, string); + if (multiplier > 1) + fprintf(file, "/ %d ", multiplier); + fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : ""); + if (it->itOOL_Number) { + fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos, + argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number); + } + fprintf(file,")\n"); + fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); + } + + if (multiple_kpd) + fprintf(file, "\t }\n\t}\n"); + } else if (argPtr->argKPD_Type == MACH_MSG_OOL_PORTS_DESCRIPTOR) { + if (multiple_kpd) { + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + + WriteKPD_Iterator(file, FALSE, FALSE, FALSE, argPtr, TRUE); + tab = "\t"; + sprintf(string, "ptr->"); + test = !it->itVarArray && !it->itElement->itVarArray; + it = it->itElement; // point to element descriptor, so size calculation is correct + argCountPtr = argPtr->argSubCount; + } else { + tab = ""; + sprintf(string, "Out%dP->%s.", argPtr->argReplyPos, argPtr->argMsgField); + test = !it->itVarArray; + argCountPtr = argPtr->argCount; + } + + if (!test) { + if ( !openedTypeCheckConditional ) { + openedTypeCheckConditional = TRUE; + fputs("#if __MigTypeCheck\n", file); + } + + fprintf(file, "\t%s" "if (%scount ", tab, string); + fprintf(file,"!= Out%dP->%s%s", argCountPtr->argReplyPos, argCountPtr->argVarName, multiple_kpd ? "[i]" : ""); + if (it->itOOL_Number) { + fprintf(file," || Out%dP->%s%s > %d", argCountPtr->argReplyPos, + argCountPtr->argVarName, multiple_kpd ? "[i]" : "", it->itOOL_Number); + } + fprintf(file,")\n"); + fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab); + } + + if (multiple_kpd) + fprintf(file, "\t }\n\t}\n"); + } + } + } + + if ( openedTypeCheckConditional ) + fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); +} + +static void +WriteCheckReply(FILE *file, routine_t *rt) +{ + int i; + + /* initialize the disciplines for the handling of KPDs */ + InitKPD_Disciplines(rt->rtArgs); + + if (rt->rtOneWay) + return; + + fprintf(file, "\n"); + fprintf(file, "#if ( __MigTypeCheck "); + if (CheckNDR) + fprintf(file, "|| __NDR_convert__ "); + fprintf(file, ")\n"); + fprintf(file, "#if __MIG_check__Reply__%s_subsystem__\n", SubsystemName); + fprintf(file, "#if !defined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName); + fprintf(file, "#define __MIG_check__Reply__%s_t__defined\n", rt->rtName); + if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) { + WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgDecl, akbReturnNdr, "\n", "\n"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgDecl, akbReturnNdr, "\n", "\n"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgDecl, akbReturnNdr, "\n", "\n"); + } + fprintf(file, "\n"); + fprintf(file, "mig_internal kern_return_t __MIG_check__Reply__%s_t(__Reply__%s_t *Out0P", rt->rtName, rt->rtName); + for (i = 1; i <= rt->rtMaxReplyPos; i++) + fprintf(file, ", __Reply__%s_t **Out%dPP", rt->rtName, i); + fprintf(file, ")\n{\n"); + + + fprintf(file, "\n\ttypedef __Reply__%s_t __Reply __attribute__((unused));\n", rt->rtName); + for (i = 1; i <= rt->rtMaxReplyPos; i++) + fprintf(file, "\t__Reply *Out%dP;\n", i); + if (!rt->rtSimpleReply) + fprintf(file, "\tboolean_t msgh_simple;\n"); + if (!rt->rtNoReplyArgs) { + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tunsigned int msgh_size;\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + } + if (rt->rtMaxReplyPos > 0) + fprintf(file, "\tunsigned int msgh_size_delta;\n"); + if (rt->rtNumReplyVar > 0 || rt->rtMaxReplyPos > 0) + fprintf(file, "\n"); + + /* Check the values that are returned in the reply message */ + + WriteCheckIdentity(file, rt); + + /* Check the remote port is NULL */ + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\tif (Out0P->Head.msgh_request_port != MACH_PORT_NULL) {\n"); + fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n"); + fprintf(file, "\t}\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); + + /* If the reply message has no Out parameters or return values + other than the return code, we can type-check it and + return it directly. */ + + if (rt->rtNoReplyArgs && !rt->rtUserImpl) { + if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply) && rt->rtRetCode) + WriteReplyNDRConvertIntRepOneArgUse(file, rt->rtRetCode); + WriteReturn(file, rt, "\t", stRetCode, "\n", FALSE); + } + else { + if (UseEventLogger) + WriteLogMsg(file, rt, LOG_USER, LOG_REPLY); + + WriteRetCodeCheck(file, rt); + + /* Type Checking for the Out parameters which are typed */ + WriteList(file, rt->rtArgs, WriteTypeCheck, akbReturnKPD, "\n", "\n"); + + { + argument_t *arg, *lastVarArg; + + lastVarArg = argNULL; + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + /* + * Advance message pointer if the last reply argument was + * variable-length and the reply position will change. + */ + if (lastVarArg != argNULL && + lastVarArg->argReplyPos < arg->argReplyPos) { + WriteAdjustReplyMsgPtr(file, lastVarArg); + lastVarArg = argNULL; + } + + if (akCheckAll(arg->argKind, akbReturnRcv|akbReturnBody)) { + if (akCheck(arg->argKind, akbVariable)) { + WriteCheckMsgSize(file, arg); + lastVarArg = arg; + } + } + } + } + + if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbReply)) { + fprintf(file, "#if\t"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgCond, akbReturnNdr, " || \\\n\t", "\n"); + fprintf(file, "\tif (Out0P->NDR.int_rep != NDR_record.int_rep) {\n"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertIntRepArgUse, akbReturnNdr, "", ""); + fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n"); + + WriteOOLSizeCheck(file, rt); + + fprintf(file, "#if\t"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgCond, akbReturnNdr, " || \\\n\t", "\n"); + fprintf(file, "\tif (Out0P->NDR.char_rep != NDR_record.char_rep) {\n"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertCharRepArgUse, akbReturnNdr, "", ""); + fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n"); + + fprintf(file, "#if\t"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgCond, akbReturnNdr, " || \\\n\t", "\n"); + fprintf(file, "\tif (Out0P->NDR.float_rep != NDR_record.float_rep) {\n"); + WriteList(file, rt->rtArgs, WriteReplyNDRConvertFloatRepArgUse, akbReturnNdr, "", ""); + fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n"); + } else { + WriteOOLSizeCheck(file, rt); + } + fprintf(file, "\treturn MACH_MSG_SUCCESS;\n"); + } + fprintf(file, "}\n"); + fprintf(file, "#endif /* !defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName); + fprintf(file, "#endif /* __MIG_check__Reply__%s_subsystem__ */\n", SubsystemName); + fprintf(file, "#endif /* ( __MigTypeCheck "); + if (CheckNDR) + fprintf(file, "|| __NDR_convert__ "); + fprintf(file, ") */\n\n"); +} + +static void +WriteCheckReplyCall(FILE *file, routine_t *rt) +{ + int i; + + fprintf(file, "\n"); + fprintf(file, "#if\tdefined(__MIG_check__Reply__%s_t__defined)\n", rt->rtName); + fprintf(file, "\tcheck_result = __MIG_check__Reply__%s_t((__Reply__%s_t *)Out0P", rt->rtName, rt->rtName); + for (i = 1; i <= rt->rtMaxReplyPos; i++) + fprintf(file, ", (__Reply__%s_t **)&Out%dP", rt->rtName, i); + fprintf(file, ");\n"); + fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS) {\n"); + if (IsKernelUser) { + fprintf(file, "#if\t__MigKernelSpecificCode\n"); + fprintf(file, "\t\tmach_msg_destroy_from_kernel(&Out0P->Head);\n"); + fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n"); + } else { + fprintf(file, "\t\tmach_msg_destroy(&Out0P->Head);\n"); + } + WriteReturnMsgError(file, rt, TRUE, argNULL, "check_result"); + fprintf(file, "\t}\n"); + fprintf(file, "#endif\t/* defined(__MIG_check__Reply__%s_t__defined) */\n", rt->rtName); + fprintf(file, "\n"); +} + +void +WriteCheckReplies(FILE *file, statement_t *stats) +{ + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) + WriteCheckReply(file, stat->stRoutine); +} + +static void +WriteCheckReplyTrailerArgs(FILE *file, routine_t *rt) +{ + argument_t *arg; + + if (rt->rtUserImpl) + WriteCheckTrailerHead(file, rt, TRUE); + + for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) { + if (akCheck(arg->argKind, akbUserImplicit)) + WriteCheckTrailerSize(file, TRUE, arg); + } + if (rt->rtUserImpl) + fprintf(file, "\n"); +} + + +/************************************************************* + * Writes all the code comprising a routine body. Called by + * WriteUser for each routine. + *************************************************************/ +static void +WriteRoutine(FILE *file, routine_t *rt) +{ + /* write the stub's declaration */ + WriteStubDecl(file, rt); + + /* Use the RPC trap for user-user and user-kernel RPC */ + if (UseRPCTrap) + WriteRPCRoutine(file, rt); + + /* write the code for doing a short-circuited RPC: */ + if (ShortCircuit) + WriteShortCircRPC(file, rt); + + /* typedef of structure for Request and Reply messages */ + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, FALSE, FALSE, FALSE); + if (!rt->rtOneWay) { + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "Reply", rt->rtSimpleReply, TRUE, rt->rtUserImpl, FALSE); + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply, "__Reply", rt->rtSimpleReply, FALSE, FALSE, FALSE); + } + if (rt->rtOverwrite) + WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbReply|akbOverwrite, "OverwriteTemplate", FALSE, TRUE, FALSE, TRUE); + /* + * Define a Minimal Reply structure to be used in case of errors + */ + fprintf(file, "\t/*\n"); + fprintf(file, "\t * typedef struct {\n"); + fprintf(file, "\t * \tmach_msg_header_t Head;\n"); + fprintf(file, "\t * \tNDR_record_t NDR;\n"); + fprintf(file, "\t * \tkern_return_t RetCode;\n"); + fprintf(file, "\t * } mig_reply_error_t;\n"); + fprintf(file, "\t */\n"); + fprintf(file, "\n"); + + + /* declarations for local vars: Union of Request and Reply messages, + InP, OutP and return value */ + + WriteVarDecls(file, rt); + + /* declarations and initializations of the mach_msg_type_descriptor_t variables + for each argument that is a Kernel Processed Data */ + + WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbRequest | akbSendKPD, "\n", "\n"); + + WriteLimitCheck(file, rt); + WriteRetCodeArg(file, rt); + + /* fill in the fields that are non related to parameters */ + + if (!rt->rtSimpleRequest) + fprintf(file, "\tInP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtRequestKPDs); + + /* fill in all the request message types and then arguments */ + + WriteRequestArgs(file, rt); + + /* fill in request message head */ + + WriteRequestHead(file, rt); + fprintf(file, "\n"); + + /* give the application a chance to do some stuff. */ + WriteApplMacro(file, "Send", "Before", rt); + + /* Write the send/receive or rpc call */ + + if (UseEventLogger) + WriteLogMsg(file, rt, LOG_USER, LOG_REQUEST); + + + if (rt->rtOneWay) { + WriteMsgSend(file, rt); + } + else { + if (UseMsgRPC +#if USE_IMMEDIATE_SEND_TIMEOUT + && (rt->rtWaitTime == argNULL) +#endif + ) { + /* overwrite mode meaningful only when UseMsgRPC is enabled */ + if (rt->rtOverwrite) + WriteOverwriteTemplate(file, rt); + WriteMsgRPC(file, rt); + } + else + WriteMsgSendReceive(file, rt); + + WriteCheckReplyCall(file, rt); + WriteCheckReplyTrailerArgs(file, rt); + + if (UseEventLogger) + WriteLogMsg(file, rt, LOG_USER, LOG_REPLY); + + WriteReplyArgs(file, rt); + } + /* return the return value, if any */ + if (!rt->rtOneWay) // WriteMsgSend() already wrote the 'return' + WriteReturnValue(file, rt); + fprintf(file, "}\n"); +} + +static void +WriteRPCClientFunctions(FILE *file, statement_t *stats) +{ + statement_t *stat; + char *fname; + char *argfmt = "(mach_port_t, char *, mach_msg_type_number_t)"; + + fprintf(file, "#ifdef AUTOTEST\n"); + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + fname = stat->stRoutine->rtName; + fprintf(file, "extern void client_%s%s;\n", fname, argfmt); + } + fprintf(file, "function_table_entry %s_client_functions[] =\n", SubsystemName); + fprintf(file, "{\n"); + for (stat = stats; stat != stNULL; stat = stat->stNext) + if (stat->stKind == skRoutine) { + fname = stat->stRoutine->rtName; + fprintf(file, " { \"%s\", client_%s },\n", fname, fname); + } + fprintf(file, " { (char *) 0, (function_ptr_t) 0 }\n"); + fprintf(file, "};\n"); + fprintf(file, "#endif /* AUTOTEST */\n"); +} + +/************************************************************* + * Writes out the xxxUser.c file. Called by mig.c + *************************************************************/ +void +WriteUser(FILE *file, statement_t *stats) +{ + statement_t *stat; + + WriteProlog(file, stats); + if (TestRPCTrap) + WriteRPCClientFunctions(file, stats); + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skRoutine: + WriteCheckReply(file, stat->stRoutine); + WriteRoutine(file, stat->stRoutine); + break; + + case skImport: + case skUImport: + case skSImport: + case skDImport: + case skIImport: + break; + + default: + fatal("WriteUser(): bad statement_kind_t (%d)", (int) stat->stKind); + } + WriteEpilog(file); +} + +/************************************************************* + * Writes out individual .c user files for each routine. Called by mig.c + *************************************************************/ +void +WriteUserIndividual(statement_t *stats) +{ + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skRoutine: { + FILE *file; + char *filename; + + filename = strconcat(UserFilePrefix, strconcat(stat->stRoutine->rtName, ".c")); + file = fopen(filename, "w"); + if (file == NULL) + fatal("fopen(%s): %s", filename, strerror(errno)); + WriteProlog(file, stats); + WriteRoutine(file, stat->stRoutine); + WriteEpilog(file); + fclose(file); + strfree(filename); + } + break; + + case skImport: + case skUImport: + case skSImport: + case skDImport: + case skIImport: + break; + + default: + fatal("WriteUserIndividual(): bad statement_kind_t (%d)", (int) stat->stKind); + } +} diff --git a/bootstrap_cmds/migcom.tproj/utils.c b/bootstrap_cmds/migcom.tproj/utils.c new file mode 100644 index 0000000..7a609a4 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/utils.c @@ -0,0 +1,1043 @@ +/* + * Copyright (c) 1999-2018 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include +#include +#include +#include "routine.h" +#include "write.h" +#include "global.h" +#include "utils.h" +#include "error.h" + +extern char *MessFreeRoutine; + +void +WriteIdentificationString(FILE *file) +{ + extern char * GenerationDate; + + fprintf(file, "/*\n"); + fprintf(file, " * IDENTIFICATION:\n"); + fprintf(file, " * stub generated %s", GenerationDate); + fprintf(file, " * with a MiG generated by " MIG_VERSION "\n"); + fprintf(file, " * OPTIONS: \n"); + if (IsKernelUser) + fprintf(file, " *\tKernelUser\n"); + if (IsKernelServer) + fprintf(file, " *\tKernelServer\n"); + if (!UseMsgRPC) + fprintf(file, " *\t-R (no RPC calls)\n"); + fprintf(file, " */\n"); +} + +void +WriteMigExternal(FILE *file) +{ + fprintf(file, "#ifdef\tmig_external\n"); + fprintf(file, "mig_external\n"); + fprintf(file, "#else\n"); + fprintf(file, "extern\n"); + fprintf(file, "#endif\t/* mig_external */\n"); +} + +void +WriteMigInternal(FILE *file) +{ + fprintf(file, "#ifdef\tmig_internal\n"); + fprintf(file, "mig_internal\n"); + fprintf(file, "#else\n"); + fprintf(file, "static\n"); + fprintf(file, "#endif\t/* mig_internal */\n"); +} + +void +WriteImport(FILE *file, string_t filename) +{ + fprintf(file, "#include %s\n", filename); +} + +void +WriteImplImports(FILE *file, statement_t *stats, boolean_t isuser) +{ + statement_t *stat; + + for (stat = stats; stat != stNULL; stat = stat->stNext) + switch (stat->stKind) { + + case skImport: + case skIImport: + WriteImport(file, stat->stFileName); + break; + + case skSImport: + if (!isuser) + WriteImport(file, stat->stFileName); + break; + + case skUImport: + if (isuser) + WriteImport(file, stat->stFileName); + break; + + case skRoutine: + case skDImport: + break; + + default: + fatal("WriteImplImport(): bad statement_kind_t (%d)", (int) stat->stKind); + } +} + +void +WriteRCSDecl(FILE *file, identifier_t name, string_t rcs) +{ + fprintf(file, "#ifndef\tlint\n"); + fprintf(file, "#if\tUseExternRCSId\n"); + fprintf(file, "%s char %s_rcsid[] = %s;\n", (BeAnsiC) ? "const" : "", name, rcs); + fprintf(file, "#else\t/* UseExternRCSId */\n"); + fprintf(file, "static %s char rcsid[] = %s;\n", (BeAnsiC) ? "const" : "", rcs); + fprintf(file, "#endif\t/* UseExternRCSId */\n"); + fprintf(file, "#endif\t/* lint */\n"); + fprintf(file, "\n"); +} + +static void +WriteOneApplDefault(FILE *file, char *word1, char *word2, char *word3) +{ + char buf[50]; + + sprintf(buf, "__%s%s%s", word1, word2, word3); + fprintf(file, "#ifndef\t%s\n", buf); + fprintf(file, "#define\t%s(_NUM_, _NAME_)\n", buf); + fprintf(file, "#endif\t/* %s */\n", buf); + fprintf(file, "\n"); +} + +void +WriteApplDefaults(FILE *file, char *dir) +{ + WriteOneApplDefault(file, "Declare", dir, "Rpc"); + WriteOneApplDefault(file, "Before", dir, "Rpc"); + WriteOneApplDefault(file, "After", dir, "Rpc"); + WriteOneApplDefault(file, "Declare", dir, "Simple"); + WriteOneApplDefault(file, "Before", dir, "Simple"); + WriteOneApplDefault(file, "After", dir, "Simple"); +} + +void +WriteApplMacro(FILE *file, char *dir, char *when, routine_t *rt) +{ + char *what = (rt->rtOneWay) ? "Simple" : "Rpc"; + + fprintf(file, "\t__%s%s%s(%d, \"%s\")\n", when, dir, what, SubsystemBase + rt->rtNumber, rt->rtName); +} + + +void +WriteBogusDefines(FILE *file) +{ + fprintf(file, "#ifndef\tmig_internal\n"); + fprintf(file, "#define\tmig_internal\tstatic __inline__\n"); + fprintf(file, "#endif\t/* mig_internal */\n"); + fprintf(file, "\n"); + + fprintf(file, "#ifndef\tmig_external\n"); + fprintf(file, "#define mig_external\n"); + fprintf(file, "#endif\t/* mig_external */\n"); + fprintf(file, "\n"); + + fprintf(file, "#if\t!defined(__MigTypeCheck) && defined(TypeCheck)\n"); + fprintf(file, "#define\t__MigTypeCheck\t\tTypeCheck\t/* Legacy setting */\n"); + fprintf(file, "#endif\t/* !defined(__MigTypeCheck) */\n"); + fprintf(file, "\n"); + + fprintf(file, "#if\t!defined(__MigKernelSpecificCode) && defined(_MIG_KERNEL_SPECIFIC_CODE_)\n"); + fprintf(file, "#define\t__MigKernelSpecificCode\t_MIG_KERNEL_SPECIFIC_CODE_\t/* Legacy setting */\n"); + fprintf(file, "#endif\t/* !defined(__MigKernelSpecificCode) */\n"); + fprintf(file, "\n"); + + fprintf(file, "#ifndef\tLimitCheck\n"); + fprintf(file, "#define\tLimitCheck 0\n"); + fprintf(file, "#endif\t/* LimitCheck */\n"); + fprintf(file, "\n"); + + fprintf(file, "#ifndef\tmin\n"); + fprintf(file, "#define\tmin(a,b) ( ((a) < (b))? (a): (b) )\n"); + fprintf(file, "#endif\t/* min */\n"); + fprintf(file, "\n"); + + fprintf(file, "#if !defined(_WALIGN_)\n"); + fprintf(file, "#define _WALIGN_(x) (((x) + %d) & ~%d)\n", (int)(itWordAlign - 1), (int)(itWordAlign - 1)); + fprintf(file, "#endif /* !defined(_WALIGN_) */\n"); + fprintf(file, "\n"); + + fprintf(file, "#if !defined(_WALIGNSZ_)\n"); + fprintf(file, "#define _WALIGNSZ_(x) _WALIGN_(sizeof(x))\n"); + fprintf(file, "#endif /* !defined(_WALIGNSZ_) */\n"); + fprintf(file, "\n"); + + fprintf(file, "#ifndef\tUseStaticTemplates\n"); + if (BeAnsiC) { + fprintf(file, "#define\tUseStaticTemplates\t0\n"); + } + else { + fprintf(file, "#if\t%s\n", NewCDecl); + fprintf(file, "#define\tUseStaticTemplates\t0\n"); + fprintf(file, "#endif\t/* %s */\n", NewCDecl); + } + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); + fprintf(file, "\n"); + + WriteBogusServerRoutineAnnotationDefine(file); +} + +void +WriteList(FILE *file, argument_t *args, void (*func)(FILE *, argument_t *), u_int mask, char *between, char *after) +{ + argument_t *arg; + boolean_t sawone = FALSE; + + for (arg = args; arg != argNULL; arg = arg->argNext) + if (akCheckAll(arg->argKind, mask)) { + if (sawone) + fprintf(file, "%s", between); + sawone = TRUE; + + (*func)(file, arg); + } + + if (sawone) + fprintf(file, "%s", after); +} + + +static boolean_t +WriteReverseListPrim(FILE *file, argument_t *arg, void (*func)(FILE *, argument_t *), u_int mask, char *between) +{ + boolean_t sawone = FALSE; + + if (arg != argNULL) { + sawone = WriteReverseListPrim(file, arg->argNext, func, mask, between); + + if (akCheckAll(arg->argKind, mask)) { + if (sawone) + fprintf(file, "%s", between); + sawone = TRUE; + + (*func)(file, arg); + } + } + + return sawone; +} + +void +WriteReverseList(FILE *file, argument_t *args, void (*func)(FILE *file, argument_t *args), u_int mask, char *between, char *after) +{ + boolean_t sawone; + + sawone = WriteReverseListPrim(file, args, func, mask, between); + + if (sawone) + fprintf(file, "%s", after); +} + +void +WriteNameDecl(FILE *file, argument_t *arg) +{ + fprintf(file, "%s", arg->argVarName); +} + +void +WriteUserVarDecl(FILE *file, argument_t *arg) +{ + boolean_t pointer = (arg->argByReferenceUser ||arg->argType->itNativePointer); + char *ref = (pointer) ? "*" : ""; + char *cnst = ((arg->argFlags & flConst) && + (IS_VARIABLE_SIZED_UNTYPED(arg->argType) || + arg->argType->itNoOptArray || arg->argType->itString)) ? "const " : ""; + + fprintf(file, "\t%s%s %s%s", cnst, arg->argType->itUserType, ref, arg->argVarName); +} + +void +WriteServerVarDecl(FILE *file, argument_t *arg) +{ + char *ref = (arg->argByReferenceServer || + arg->argType->itNativePointer) ? "*" : ""; + char *cnst = ((arg->argFlags & flConst) && + (IS_VARIABLE_SIZED_UNTYPED(arg->argType) || + arg->argType->itNoOptArray || arg->argType->itString)) ? "const " : ""; + + fprintf(file, "\t%s%s %s%s", cnst, arg->argType->itTransType, ref, arg->argVarName); +} + +char * +ReturnTypeStr(routine_t *rt) +{ + return rt->rtRetCode->argType->itUserType; +} + +char * +FetchUserType(ipc_type_t *it) +{ + return it->itUserType; +} + +char * +FetchServerType(ipc_type_t *it) +{ + return it->itServerType; +} + +char * +FetchKPDType(ipc_type_t *it) +{ + return it->itKPDType; +} + +void +WriteTrailerDecl(FILE *file, boolean_t trailer) +{ + if (trailer) + fprintf(file, "\t\tmach_msg_max_trailer_t trailer;\n"); + else + fprintf(file, "\t\tmach_msg_trailer_t trailer;\n"); +} + +void +WriteFieldDeclPrim(FILE *file, argument_t *arg, char *(*tfunc)(ipc_type_t *it)) +{ + ipc_type_t *it = arg->argType; + + if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) { + argument_t *count = arg->argCount; + ipc_type_t *btype = it->itElement; + + /* + * Build our own declaration for a varying array: + * use the element type and maximum size specified. + * Note arg->argCount->argMultiplier == btype->itNumber. + */ + /* + * NDR encoded VarStrings requires the offset field. + * Since it is not used, it wasn't worthwhile to create an extra + * parameter + */ + if (it->itString) + fprintf(file, "\t\t%s %sOffset; /* MiG doesn't use it */\n", (*tfunc)(count->argType), arg->argName); + + if (!(arg->argFlags & flSameCount) && !it->itNoOptArray) + /* in these cases we would have a count, which we don't want */ + fprintf(file, "\t\t%s %s;\n", (*tfunc)(count->argType), count->argMsgField); + fprintf(file, "\t\t%s %s[%d];", (*tfunc)(btype), arg->argMsgField, it->itNumber/btype->itNumber); + } + else if (IS_MULTIPLE_KPD(it)) + fprintf(file, "\t\t%s %s[%d];", (*tfunc)(it), arg->argMsgField, it->itKPD_Number); + else if (IS_OPTIONAL_NATIVE(it)) { + fprintf(file, "\t\tboolean_t __Present__%s;\n", arg->argMsgField); + fprintf(file, "\t\tunion {\n"); + fprintf(file, "\t\t %s __Real__%s;\n", (*tfunc)(it), arg->argMsgField); + fprintf(file, "\t\t char __Phony__%s[_WALIGNSZ_(%s)];\n", arg->argMsgField, (*tfunc)(it)); + fprintf(file, "\t\t} %s;", arg->argMsgField); + } + else { + /* either simple KPD or simple in-line */ + fprintf(file, "\t\t%s %s;", (*tfunc)(it), arg->argMsgField); + } + + /* Kernel Processed Data has always PadSize = 0 */ + if (it->itPadSize != 0) + fprintf(file, "\n\t\tchar %s[%d];", arg->argPadName, it->itPadSize); +} + +void +WriteKPDFieldDecl(FILE *file, argument_t *arg) +{ + if (akCheck(arg->argKind, akbSendKPD) || + akCheck(arg->argKind, akbReturnKPD)) + WriteFieldDeclPrim(file, arg, FetchKPDType); + else + WriteFieldDeclPrim(file, arg, FetchServerType); +} + +void +WriteStructDecl( + FILE *file, + argument_t *args, + void (*func)(FILE *, argument_t *), + u_int mask, + char *name, + boolean_t simple, + boolean_t trailer, + boolean_t trailer_t, + boolean_t template_only) +{ + fprintf(file, "\n#ifdef __MigPackStructs\n#pragma pack(push, %lu)\n#endif\n",sizeof(natural_t)); + fprintf(file, "\ttypedef struct {\n"); + fprintf(file, "\t\tmach_msg_header_t Head;\n"); + if (simple == FALSE) { + fprintf(file, "\t\t/* start of the kernel processed data */\n"); + fprintf(file, "\t\tmach_msg_body_t msgh_body;\n"); + if (mask == akbRequest) + WriteList(file, args, func, mask | akbSendKPD, "\n", "\n"); + else + WriteList(file, args, func, mask | akbReturnKPD, "\n", "\n"); + fprintf(file, "\t\t/* end of the kernel processed data */\n"); + } + if (!template_only) { + if (mask == akbRequest) + WriteList(file, args, func, mask | akbSendBody, "\n", "\n"); + + else + WriteList(file, args, func, mask | akbReturnBody, "\n", "\n"); + if (trailer) + WriteTrailerDecl(file, trailer_t); + } + fprintf(file, "\t} %s __attribute__((unused));\n", name); + fprintf(file, "#ifdef __MigPackStructs\n#pragma pack(pop)\n#endif\n"); +} + +void +WriteTemplateDeclIn(FILE *file, argument_t *arg) +{ + (*arg->argKPD_Template)(file, arg, TRUE); +} + +void +WriteTemplateDeclOut(FILE *file, argument_t *arg) +{ + (*arg->argKPD_Template)(file, arg, FALSE); +} + +void +WriteTemplateKPD_port(FILE *file, argument_t *arg, boolean_t in) +{ + ipc_type_t *it = arg->argType; + + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName); + + fprintf(file, "\t\t/* name = */\t\tMACH_PORT_NULL,\n"); + fprintf(file, "\t\t/* pad1 = */\t\t0,\n"); + fprintf(file, "\t\t/* pad2 = */\t\t0,\n"); + fprintf(file, "\t\t/* disp = */\t\t%s,\n", in ? it->itInNameStr: it->itOutNameStr); + fprintf(file, "\t\t/* type = */\t\tMACH_MSG_PORT_DESCRIPTOR,\n"); + + fprintf(file, "\t};\n"); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); +} + +void +WriteTemplateKPD_ool(FILE *file, argument_t *arg, boolean_t in) +{ + ipc_type_t *it = arg->argType; + + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName); + + if (IS_MULTIPLE_KPD(it)) + it = it->itElement; + + fprintf(file, "\t\t/* addr = */\t\t(void *)0,\n"); + if (it->itVarArray) + fprintf(file, "\t\t/* size = */\t\t0,\n"); + else + fprintf(file, "\t\t/* size = */\t\t%d,\n", (it->itNumber * it->itSize + 7)/8); + fprintf(file, "\t\t/* deal = */\t\t%s,\n", (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); + /* the d_MAYBE case will be fixed runtime */ + fprintf(file, "\t\t/* copy = */\t\t%s,\n", (arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY"); + /* the PHYSICAL COPY flag has not been established yet */ + fprintf(file, "\t\t/* pad2 = */\t\t0,\n"); + fprintf(file, "\t\t/* type = */\t\tMACH_MSG_OOL_DESCRIPTOR,\n"); + + fprintf(file, "\t};\n"); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); +} + +void +WriteTemplateKPD_oolport(FILE *file, argument_t *arg, boolean_t in) +{ + ipc_type_t *it = arg->argType; + + fprintf(file, "#if\tUseStaticTemplates\n"); + fprintf(file, "\tconst static %s %s = {\n", it->itKPDType, arg->argTTName); + + if (IS_MULTIPLE_KPD(it)) + it = it->itElement; + + fprintf(file, "\t\t/* addr = */\t\t(void *)0,\n"); + if (!it->itVarArray) + fprintf(file, "\t\t/* coun = */\t\t%d,\n", it->itNumber); + else + fprintf(file, "\t\t/* coun = */\t\t0,\n"); + fprintf(file, "\t\t/* deal = */\t\t%s,\n", (arg->argDeallocate == d_YES) ? "TRUE" : "FALSE"); + fprintf(file, "\t\t/* copy is meaningful only in overwrite mode */\n"); + fprintf(file, "\t\t/* copy = */\t\tMACH_MSG_PHYSICAL_COPY,\n"); + fprintf(file, "\t\t/* disp = */\t\t%s,\n", in ? it->itInNameStr: it->itOutNameStr); + fprintf(file, "\t\t/* type = */\t\tMACH_MSG_OOL_PORTS_DESCRIPTOR,\n"); + + fprintf(file, "\t};\n"); + fprintf(file, "#endif\t/* UseStaticTemplates */\n"); +} + +void +WriteReplyTypes(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "/* typedefs for all replies */\n\n"); + fprintf(file, "#ifndef __Reply__%s_subsystem__defined\n", SubsystemName); + fprintf(file, "#define __Reply__%s_subsystem__defined\n", SubsystemName); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) { + routine_t *rt; + char str[MAX_STR_LEN]; + + rt = stat->stRoutine; + sprintf(str, "__Reply__%s_t", rt->rtName); + WriteStructDecl(file, rt->rtArgs, WriteKPDFieldDecl, akbReply, str, rt->rtSimpleReply, FALSE, FALSE, FALSE); + } + } + fprintf(file, "#endif /* !__Reply__%s_subsystem__defined */\n", SubsystemName); + fprintf(file, "\n"); +} + +void +WriteRequestTypes(FILE *file, statement_t *stats) +{ + statement_t *stat; + + fprintf(file, "/* typedefs for all requests */\n\n"); + fprintf(file, "#ifndef __Request__%s_subsystem__defined\n", SubsystemName); + fprintf(file, "#define __Request__%s_subsystem__defined\n", SubsystemName); + for (stat = stats; stat != stNULL; stat = stat->stNext) { + if (stat->stKind == skRoutine) { + routine_t *rt; + char str[MAX_STR_LEN]; + + rt = stat->stRoutine; + sprintf(str, "__Request__%s_t", rt->rtName); + WriteStructDecl(file, rt->rtArgs, WriteKPDFieldDecl, akbRequest, str, rt->rtSimpleRequest, FALSE, FALSE, FALSE); + } + } + fprintf(file, "#endif /* !__Request__%s_subsystem__defined */\n", SubsystemName); + fprintf(file, "\n"); +} + +void +WriteNDRConvertArgDecl(FILE *file, argument_t *arg, char *convert, char *dir) +{ + argument_t *count = arg->argCount; + argument_t *parent = arg->argParent; + char *carg = (count) ? ", c" : ""; + routine_t *rt = arg->argRoutine; + ipc_type_t *ptype = arg->argType; + ipc_type_t *btype; + int multi, array; + char domain[MAX_STR_LEN]; + + fprintf(file, "#ifndef __NDR_convert__%s__%s__%s_t__%s__defined\n#", convert, dir, rt->rtName, arg->argMsgField); + + for (btype = ptype, multi = (!parent) ? arg->argMultiplier : 1, array = 0; + btype; + ptype = btype, array += ptype->itVarArray, btype = btype->itElement) { + char *bttype; + + if (btype->itNumber < ptype->itNumber && !ptype->itVarArray && !parent) { + multi *= ptype->itNumber / btype->itNumber; + if (!btype->itString) + continue; + } + else if (array && ptype->itVarArray) + continue; + if (btype != ptype) + fprintf(file, "#el"); + + bttype = (multi > 1 && btype->itString) ? "string" : FetchServerType(btype); + sprintf(domain, "__%s", SubsystemName); + do { + fprintf(file, "if\tdefined(__NDR_convert__%s%s__%s__defined)\n", convert, domain, bttype); + fprintf(file, "#define\t__NDR_convert__%s__%s__%s_t__%s__defined\n", convert, dir, rt->rtName, arg->argMsgField); + fprintf(file, "#define\t__NDR_convert__%s__%s__%s_t__%s(a, f%s) \\\n\t", convert, dir, rt->rtName, arg->argMsgField, carg); + if (multi > 1) { + if (array) { + if (btype->itString) + fprintf(file, "__NDR_convert__2DARRAY((%s *)(a), f, %d, c, ", bttype, multi); + else + fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, %d * (c), ", bttype, multi); + } + else if (!btype->itString) + fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, %d, ", bttype, multi); + } + else if (array) + fprintf(file, "__NDR_convert__ARRAY((%s *)(a), f, c, ", bttype); + fprintf(file, "__NDR_convert__%s%s__%s", convert, domain, bttype); + if (multi > 1) { + if (!array && btype->itString) + fprintf(file, "(a, f, %d", multi); + } + else if (!array) + fprintf(file, "((%s *)(a), f%s", bttype, carg); + fprintf(file, ")\n"); + } while (strcmp(domain, "") && ((void)(domain[0] = '\0'), fprintf(file, "#el"))); + } + fprintf(file, "#endif /* defined(__NDR_convert__*__defined) */\n"); + fprintf(file, "#endif /* __NDR_convert__%s__%s__%s_t__%s__defined */\n\n", convert, dir, rt->rtName, arg->argMsgField); +} + +/* + * Like vfprintf, but omits a leading comment in the format string + * and skips the items that would be printed by it. Only %s, %d, + * and %f are recognized. + */ +void +SkipVFPrintf(FILE *file, char *fmt, va_list pvar) +{ + if (*fmt == 0) + return; /* degenerate case */ + + if (fmt[0] == '/' && fmt[1] == '*') { + /* Format string begins with C comment. Scan format + string until end-comment delimiter, skipping the + items in pvar that the enclosed format items would + print. */ + + int c; + + fmt += 2; + for (;;) { + c = *fmt++; + if (c == 0) + return; /* nothing to format */ + if (c == '*') { + if (*fmt == '/') { + break; + } + } + else if (c == '%') { + /* Field to skip */ + c = *fmt++; + switch (c) { + + case 's': + (void) va_arg(pvar, char *); + break; + + case 'd': + (void) va_arg(pvar, int); + break; + + case 'f': + (void) va_arg(pvar, double); + break; + + case '\0': + return; /* error - fmt ends with '%' */ + + default: + break; + } + } + } + /* End of comment. To be pretty, skip + the space that follows. */ + fmt++; + if (*fmt == ' ') + fmt++; + } + + /* Now format the string. */ + (void) vfprintf(file, fmt, pvar); +} + +static void +vWriteCopyType(FILE *file, ipc_type_t *it, boolean_t mig_allocated_buf, char *left, char *right, va_list pvar) +{ + va_list pvar2; + va_copy(pvar2, pvar); + + if (it->itStruct) { + + fprintf(file, "\t"); + (void) SkipVFPrintf(file, left, pvar); + fprintf(file, " = "); + (void) SkipVFPrintf(file, right, pvar2); + fprintf(file, ";\n"); + } + else if (it->itString) { + va_list pvar3, pvar4; + va_copy(pvar3, pvar); + va_copy(pvar4, pvar); + + if (mig_allocated_buf) { + /* + * zero-fill MIG allocated buffers: we control the size so there's + * no risk of buffer overrun, and we avoid leaking process/kernel + * memory on the copy-out + */ + fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "\tif (mig_strncpy_zerofill != NULL) {\n"); + fprintf(file, "\t\t(void) mig_strncpy_zerofill("); + (void) SkipVFPrintf(file, left, pvar); + fprintf(file, ", "); + (void) SkipVFPrintf(file, right, pvar2); + fprintf(file, ", %d);\n", it->itTypeSize); + fprintf(file, "\t} else {\n"); + fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n\t"); + } + fprintf(file, "\t(void) mig_strncpy("); + + (void) SkipVFPrintf(file, left, pvar3); + fprintf(file, ", "); + (void) SkipVFPrintf(file, right, pvar4); + fprintf(file, ", %d);\n", it->itTypeSize); + + if (mig_allocated_buf) { + fprintf(file, "#ifdef USING_MIG_STRNCPY_ZEROFILL\n"); + fprintf(file, "\t}\n"); + fprintf(file, "#endif /* USING_MIG_STRNCPY_ZEROFILL */\n"); + } + + va_end(pvar3); + va_end(pvar4); + } + else { + fprintf(file, "\t{ typedef struct { char data[%d]; } *sp;\n", it->itTypeSize); + fprintf(file, "\t * (sp) "); + (void) SkipVFPrintf(file, left, pvar); + fprintf(file, " = * (sp) "); + (void) SkipVFPrintf(file, right, pvar2); + fprintf(file, ";\n\t}\n"); + } + + va_end(pvar2); +} + + +/*ARGSUSED*/ +/*VARARGS4*/ +void +WriteCopyType(FILE *file, ipc_type_t *it, boolean_t mig_allocated_buf, char *left, char *right, ...) +{ + va_list pvar; + va_start(pvar, right); + + vWriteCopyType(file, it, mig_allocated_buf, left, right, pvar); + + va_end(pvar); +} + + +/*ARGSUSED*/ +/*VARARGS4*/ +void +WriteCopyArg(FILE *file, argument_t *arg, boolean_t mig_allocated_buf, char *left, char *right, ...) +{ + va_list pvar; + va_start(pvar, right); + + { + ipc_type_t *it = arg->argType; + if (it->itVarArray && !it->itString) { + fprintf(file, "\t (void)memcpy("); + (void) SkipVFPrintf(file, left, pvar); + va_end(pvar); + fprintf(file, ", "); + va_start(pvar, right); + (void) SkipVFPrintf(file, right, pvar); + fprintf(file, ", %s);\n", arg->argCount->argVarName); + } + else + vWriteCopyType(file, it, mig_allocated_buf, left, right, pvar); + } + + va_end(pvar); +} + + +/* + * Global KPD disciplines + */ +void +KPD_error(FILE *file, argument_t *arg) +{ + printf("MiG internal error: argument is %s\n", arg->argVarName); + exit(1); +} + +void +KPD_noop(FILE *file, argument_t *arg) +{ + /* Nothing to see here, people. Move it along... */ +} + +static void +WriteStringDynArgs(argument_t *args, u_int mask, string_t InPOutP, string_t *str_oolports, string_t *str_ool) +{ + argument_t *arg; + char loc[100], sub[20]; + string_t tmp_str1 = ""; + string_t tmp_str2 = ""; + int cnt, multiplier = 1; + boolean_t test, complex = FALSE; + + for (arg = args; arg != argNULL; arg = arg->argNext) { + ipc_type_t *it = arg->argType; + + if (IS_MULTIPLE_KPD(it)) { + test = it->itVarArray || it->itElement->itVarArray; + if (test) { + multiplier = it->itKPD_Number; + it = it->itElement; + complex = TRUE; + } + } + else + test = it->itVarArray; + + cnt = multiplier; + while (cnt) { + if (complex) + sprintf(sub, "[%d]", multiplier - cnt); + if (akCheck(arg->argKind, mask) && + it->itPortType && !it->itInLine && test) { + sprintf(loc, " + %s->%s%s.count", InPOutP, arg->argMsgField, complex ? sub : ""); + tmp_str1 = strconcat(tmp_str1, loc); + } + if (akCheck(arg->argKind, mask) && + !it->itInLine && !it->itPortType && test) { + sprintf(loc, " + %s->%s%s.size", InPOutP, arg->argMsgField, complex ? sub : ""); + tmp_str2 = strconcat(tmp_str2, loc); + } + cnt--; + } + } + *str_oolports = tmp_str1; + *str_ool = tmp_str2; +} + +/* + * Utilities for Logging Events that happen at the stub level + */ +void +WriteLogMsg(FILE *file, routine_t *rt, int where, int what) +{ + string_t ptr_str; + string_t StringOolPorts = strNULL; + string_t StringOOL = strNULL; + u_int ports, oolports, ool; + string_t event; + + fprintf(file, "\n#if MIG_DEBUG\n"); + if (where == LOG_USER) + fprintf(file, "\tLOG_TRACE(MACH_MSG_LOG_USER,\n"); + else + fprintf(file, "\tLOG_TRACE(MACH_MSG_LOG_SERVER,\n"); + if (where == LOG_USER && what == LOG_REQUEST) { + ptr_str = "InP"; + event = "MACH_MSG_REQUEST_BEING_SENT"; + } + else if (where == LOG_USER && what == LOG_REPLY) { + ptr_str = "Out0P"; + event = "MACH_MSG_REPLY_BEING_RCVD"; + } + else if (where == LOG_SERVER && what == LOG_REQUEST) { + ptr_str = "In0P"; + event = "MACH_MSG_REQUEST_BEING_RCVD"; + } + else { + ptr_str = "OutP"; + event = "MACH_MSG_REPLY_BEING_SENT"; + } + WriteStringDynArgs(rt->rtArgs, (what == LOG_REQUEST) ? akbSendKPD : akbReturnKPD, ptr_str, &StringOolPorts, &StringOOL); + fprintf(file, "\t\t%s,\n", event); + fprintf(file, "\t\t%s->Head.msgh_id,\n", ptr_str); + if (where == LOG_USER && what == LOG_REQUEST) { + if (rt->rtNumRequestVar) + fprintf(file, "\t\tmsgh_size,\n"); + else + fprintf(file, "\t\t(mach_msg_size_t)sizeof(Request),\n"); + } + else + fprintf(file, "\t\t%s->Head.msgh_size,\n", ptr_str); + if ((what == LOG_REQUEST && rt->rtSimpleRequest == FALSE) || + (what == LOG_REPLY && rt->rtSimpleReply == FALSE)) + fprintf(file, "\t\t%s->msgh_body.msgh_descriptor_count,\n", ptr_str); + else + fprintf(file, "\t\t0, /* Kernel Proc. Data entries */\n"); + if (what == LOG_REQUEST) { + fprintf(file, "\t\t0, /* RetCode */\n"); + ports = rt->rtCountPortsIn; + oolports = rt->rtCountOolPortsIn; + ool = rt->rtCountOolIn; + } + else { + if (akCheck(rt->rtRetCode->argKind, akbReply)) + fprintf(file, "\t\t%s->RetCode,\n", ptr_str); + else + fprintf(file, "\t\t0, /* RetCode */\n"); + ports = rt->rtCountPortsOut; + oolports = rt->rtCountOolPortsOut; + ool = rt->rtCountOolOut; + } + fprintf(file, "\t\t/* Ports */\n"); + fprintf(file, "\t\t%d,\n", ports); + fprintf(file, "\t\t/* Out-of-Line Ports */\n"); + fprintf(file, "\t\t%d", oolports); + if (StringOolPorts != strNULL) + fprintf(file, "%s,\n", StringOolPorts); + else + fprintf(file, ",\n"); + fprintf(file, "\t\t/* Out-of-Line Bytes */\n"); + fprintf(file, "\t\t%d", ool); + if (StringOOL != strNULL) + fprintf(file, "%s,\n", StringOOL); + else + fprintf(file, ",\n"); + fprintf(file, "\t\t__FILE__, __LINE__);\n"); + fprintf(file, "#endif /* MIG_DEBUG */\n\n"); +} + +void +WriteLogDefines(FILE *file, string_t who) +{ + fprintf(file, "#if MIG_DEBUG\n"); + fprintf(file, "#define LOG_W_E(X)\tLOG_ERRORS(%s, \\\n", who); + fprintf(file, "\t\t\tMACH_MSG_ERROR_WHILE_PARSING, (void *)(X), __FILE__, __LINE__)\n"); + fprintf(file, "#else /* MIG_DEBUG */\n"); + fprintf(file, "#define LOG_W_E(X)\n"); + fprintf(file, "#endif /* MIG_DEBUG */\n"); + fprintf(file, "\n"); +} + +/* common utility to report errors */ +void +WriteReturnMsgError(FILE *file, routine_t *rt, boolean_t isuser, argument_t *arg, string_t error) +{ + char space[MAX_STR_LEN]; + string_t string = &space[0]; + + if (UseEventLogger && arg != argNULL) + sprintf(string, "LOG_W_E(\"%s\"); ", arg->argVarName); + else + string = ""; + + fprintf(file, "\t\t{ "); + + if (isuser) { + if (! rtMessOnStack(rt)) + fprintf(file, "%s((char *) Mess, (mach_msg_size_t)sizeof(*Mess)); ", MessFreeRoutine); + + fprintf(file, "%sreturn %s; }\n", string, error); + } + else + fprintf(file, "%sMIG_RETURN_ERROR(OutP, %s); }\n", string, error); +} + +/* executed iff elements are defined */ +void +WriteCheckTrailerHead(FILE *file, routine_t *rt, boolean_t isuser) +{ + string_t who = (isuser) ? "Out0P" : "In0P"; + + fprintf(file, "\tTrailerP = (mach_msg_max_trailer_t *)((vm_offset_t)%s +\n", who); + fprintf(file, "\t\tround_msg(%s->Head.msgh_size));\n", who); + fprintf(file, "\tif (TrailerP->msgh_trailer_type != MACH_MSG_TRAILER_FORMAT_0)\n"); + if (isuser) + fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n"); + else + fprintf(file, "\t\t{ MIG_RETURN_ERROR(%s, MIG_TRAILER_ERROR); }\n", who); + + fprintf(file, "#if\t__MigTypeCheck\n"); + fprintf(file, "\ttrailer_size = TrailerP->msgh_trailer_size -\n"); + fprintf(file, "\t\t(mach_msg_size_t)(sizeof(mach_msg_trailer_type_t) - sizeof(mach_msg_trailer_size_t));\n"); + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); +} + +/* executed iff elements are defined */ +void +WriteCheckTrailerSize(FILE *file, boolean_t isuser, argument_t *arg) +{ + fprintf(file, "#if\t__MigTypeCheck\n"); + if (akIdent(arg->argKind) == akeMsgSeqno) { + fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(mach_port_seqno_t))\n"); + if (isuser) + fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n"); + else + fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n"); + fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(mach_port_seqno_t);\n"); + } + else if (akIdent(arg->argKind) == akeSecToken) { + fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(security_token_t))\n"); + if (isuser) + fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n"); + else + fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n"); + fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(security_token_t);\n"); + } + else if (akIdent(arg->argKind) == akeAuditToken) { + fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(audit_token_t))\n"); + if (isuser) + fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n"); + else + fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n"); + fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(audit_token_t);\n"); + } + else if (akIdent(arg->argKind) == akeContextToken) { + fprintf(file, "\tif (trailer_size < (mach_msg_size_t)sizeof(mach_vm_address_t))\n"); + if (isuser) + fprintf(file, "\t\t{ return MIG_TRAILER_ERROR ; }\n"); + else + fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, MIG_TRAILER_ERROR); }\n"); + fprintf(file, "\ttrailer_size -= (mach_msg_size_t)sizeof(mach_vm_address_t);\n"); + } + fprintf(file, "#endif\t/* __MigTypeCheck */\n"); +} + diff --git a/bootstrap_cmds/migcom.tproj/utils.h b/bootstrap_cmds/migcom.tproj/utils.h new file mode 100644 index 0000000..a804920 --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/utils.h @@ -0,0 +1,140 @@ +/* + * Copyright (c) 1999-2002, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University + * Extensive revamping. Added polymorphic arguments. + * Allow multiple variable-sized inline arguments in messages. + * + * 28-May-87 Richard Draves (rpd) at Carnegie-Mellon University + * Created. + */ + +#ifndef _UTILS_H +#define _UTILS_H + +/* definitions used by the Event Logger */ + +#define LOG_USER 0 +#define LOG_SERVER 1 + +#define LOG_REQUEST 0 +#define LOG_REPLY 1 + +/* stuff used by more than one of header.c, user.c, server.c */ + +extern void WriteMigExternal(FILE *file); +extern void WriteMigInternal(FILE *file); + +extern void WriteImport(FILE *file, string_t filename); +extern void WriteRCSDecl( FILE *file, identifier_t name, string_t rcs ); +extern void WriteBogusDefines( FILE *file ); + +extern void WriteList( FILE *file, argument_t *args, + void (*func)(FILE *file, argument_t *arg), + u_int mask, char *between, char *after ); + +extern void WriteReverseList( FILE *file, argument_t *args, + void (*func)(FILE *file, argument_t *arg), + u_int mask, char *between, char *after ); + +/* good as arguments to WriteList */ +extern void WriteNameDecl( FILE *file, argument_t *arg ); +extern void WriteUserVarDecl( FILE *file, argument_t *arg ); +extern void WriteServerVarDecl( FILE *file, argument_t *arg ); +extern void WriteTemplateDeclIn( FILE *file, argument_t *arg ); +extern void WriteTemplateDeclOut( FILE *file, argument_t *arg ); +extern void WriteCheckDecl( FILE *file, argument_t *arg ); + +extern char *ReturnTypeStr( routine_t *rt ); + +extern char *FetchUserType( ipc_type_t *it ); +extern char *FetchServerType( ipc_type_t *it ); +extern char *FetchKPDType( ipc_type_t *it ); +extern void WriteKPDFieldDecl(FILE *file, argument_t *arg); + +extern void WriteFieldDeclPrim( FILE *file, argument_t *arg, char *(*tfunc)(ipc_type_t *it) ); + +extern void WriteStructDecl( FILE *file, argument_t *args, + void (*func)(FILE *file, argument_t *arg), + u_int mask, char *name, + boolean_t simple, boolean_t trailer, + boolean_t isuser, + boolean_t template_only ); + +extern void WriteStaticDecl( FILE *file, argument_t *arg ); + +extern void WriteCopyType(FILE *file, ipc_type_t *it, boolean_t mig_allocated_buf, char *left, char *right, ...); + +extern void WriteCopyArg(FILE *file, argument_t *arg, boolean_t mig_allocated_buf, char *left, char *right, ...); + +extern void WriteLogMsg( FILE *file, routine_t *rt, int where, int what ); + +extern void WriteCheckTrailerHead( FILE *file, routine_t *rt, boolean_t isuser ); + +extern void WriteCheckTrailerSize( FILE *file, boolean_t isuser, argument_t *arg ); + +extern void WriteReturnMsgError( FILE *file, routine_t *rt, boolean_t isuser, argument_t *arg, string_t error ); + +extern void WriteRPCRoutineDescriptor( FILE *file, routine_t *rt, int arg_count, int descr_count, string_t stub_routine, string_t sig_array ); + +extern void WriteRPCRoutineArgDescriptor( FILE *file, routine_t *rt ); + +extern void WriteRequestTypes( FILE *file, statement_t *stats); +extern void WriteCheckRequests( FILE *file, statement_t *stats); +extern void WriteUserRequestUnion( FILE *file, statement_t *stats ); +extern void WriteServerRequestUnion( FILE *file, statement_t *stats ); + +extern void WriteReplyTypes( FILE *file, statement_t *stats); +extern void WriteCheckReplies( FILE *file, statement_t *stats); +extern void WriteUserReplyUnion( FILE *file, statement_t *stats ); +extern void WriteServerReplyUnion( FILE *file, statement_t *stats ); + +extern void WriteNDRConvertArgDecl( FILE *file, argument_t *arg, char *convert, char *dir); + +#endif /* _UTILS_H */ diff --git a/bootstrap_cmds/migcom.tproj/write.h b/bootstrap_cmds/migcom.tproj/write.h new file mode 100644 index 0000000..0e935aa --- /dev/null +++ b/bootstrap_cmds/migcom.tproj/write.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1999, 2008 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * This file contains Original Code and/or Modifications of Original Code + * as defined in and that are subject to the Apple Public Source License + * Version 2.0 (the 'License'). You may not use this file except in + * compliance with the License. Please obtain a copy of the License at + * http://www.opensource.apple.com/apsl/ and read it before using this + * file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. + * Please see the License for the specific language governing rights and + * limitations under the License. + * + * @APPLE_LICENSE_HEADER_END@ + */ +/* + * Mach Operating System + * Copyright (c) 1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie the + * rights to redistribute these changes. + */ +/* + * HISTORY + * 07-Apr-89 Richard Draves (rpd) at Carnegie-Mellon University + * Extensive revamping. Added polymorphic arguments. + * Allow multiple variable-sized inline arguments in messages. + * + * 27-May-87 Richard Draves (rpd) at Carnegie-Mellon University + * Created. + */ + +#ifndef _WRITE_H +#define _WRITE_H + +#include +#include "statement.h" + +extern void WriteUserHeader( FILE *file, statement_t *stats ); +extern void WriteServerHeader( FILE *file, statement_t *stats ); +extern void WriteServerRoutine( FILE *file, routine_t *rt ); +extern void WriteInternalHeader( FILE *file, statement_t *stats ); +extern void WriteDefinesHeader( FILE *file, statement_t *stats ); +extern void WriteUser( FILE *file, statement_t *stats ); +extern void WriteUserIndividual( statement_t *stats ); +extern void WriteServer( FILE *file, statement_t *stats ); +extern void WriteIncludes( FILE *file, boolean_t isuser, boolean_t is_def ); +extern void WriteImplImports( FILE *file, statement_t *stats, boolean_t isuser ); +extern void WriteApplDefaults( FILE *file, char *dir ); +extern void WriteApplMacro( FILE *file, char *dir, char *when, routine_t *rt ); +extern void WriteBogusServerRoutineAnnotationDefine( FILE *file ); + +#endif /* _WRITE_H */ diff --git a/bootstrap_cmds/xcodescripts/install-mig.sh b/bootstrap_cmds/xcodescripts/install-mig.sh new file mode 100644 index 0000000..f0f742e --- /dev/null +++ b/bootstrap_cmds/xcodescripts/install-mig.sh @@ -0,0 +1,8 @@ +set -e -x + +BINDIR="$DSTROOT/$DT_TOOLCHAIN_DIR/usr/bin" + +install -d -o root -g wheel -m 0755 "$BINDIR" +install -c -o root -g wheel -m 0755 \ + "$PROJECT_DIR/migcom.tproj/mig.sh" \ + "$BINDIR"/mig -- cgit v1.2.3-56-ge451