aboutsummaryrefslogtreecommitdiffstats
path: root/bootstrap_cmds
diff options
context:
space:
mode:
authorCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
committerCameron Katri <me@cameronkatri.com>2021-05-09 14:20:58 -0400
commit5fd83771641d15c418f747bd343ba6738d3875f7 (patch)
tree5abf0f78f680d9837dbd93d4d4c3933bb7509599 /bootstrap_cmds
downloadapple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.gz
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.tar.zst
apple_cmds-5fd83771641d15c418f747bd343ba6738d3875f7.zip
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
Diffstat (limited to 'bootstrap_cmds')
-rw-r--r--bootstrap_cmds/.gitignore6
-rw-r--r--bootstrap_cmds/APPLE_LICENSE335
-rw-r--r--bootstrap_cmds/mig.xcodeproj/project.pbxproj310
-rw-r--r--bootstrap_cmds/migcom.tproj/alloc.h54
-rw-r--r--bootstrap_cmds/migcom.tproj/error.c111
-rw-r--r--bootstrap_cmds/migcom.tproj/error.h61
-rw-r--r--bootstrap_cmds/migcom.tproj/global.c151
-rw-r--r--bootstrap_cmds/migcom.tproj/global.h113
-rw-r--r--bootstrap_cmds/migcom.tproj/handler.c754
-rw-r--r--bootstrap_cmds/migcom.tproj/header.c569
-rw-r--r--bootstrap_cmds/migcom.tproj/lexxer.h52
-rw-r--r--bootstrap_cmds/migcom.tproj/lexxer.l314
-rw-r--r--bootstrap_cmds/migcom.tproj/mig.188
-rw-r--r--bootstrap_cmds/migcom.tproj/mig.c405
-rw-r--r--bootstrap_cmds/migcom.tproj/mig.sh218
-rw-r--r--bootstrap_cmds/migcom.tproj/mig_errors.h84
-rw-r--r--bootstrap_cmds/migcom.tproj/mig_machine.h16
-rw-r--r--bootstrap_cmds/migcom.tproj/migcom.173
-rw-r--r--bootstrap_cmds/migcom.tproj/parser.y803
-rw-r--r--bootstrap_cmds/migcom.tproj/routine.c1844
-rw-r--r--bootstrap_cmds/migcom.tproj/routine.h549
-rw-r--r--bootstrap_cmds/migcom.tproj/server.c2772
-rw-r--r--bootstrap_cmds/migcom.tproj/statement.c68
-rw-r--r--bootstrap_cmds/migcom.tproj/statement.h98
-rw-r--r--bootstrap_cmds/migcom.tproj/strdefs.h93
-rw-r--r--bootstrap_cmds/migcom.tproj/string.c132
-rw-r--r--bootstrap_cmds/migcom.tproj/type.c899
-rw-r--r--bootstrap_cmds/migcom.tproj/type.h270
-rw-r--r--bootstrap_cmds/migcom.tproj/user.c3260
-rw-r--r--bootstrap_cmds/migcom.tproj/utils.c1043
-rw-r--r--bootstrap_cmds/migcom.tproj/utils.h140
-rw-r--r--bootstrap_cmds/migcom.tproj/write.h78
-rw-r--r--bootstrap_cmds/xcodescripts/install-mig.sh8
33 files changed, 15771 insertions, 0 deletions
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 = "<group>"; };
+ FCAD532A149BF58700CE0B4B /* alloc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = alloc.h; sourceTree = "<group>"; };
+ FCAD532B149BF58700CE0B4B /* error.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = error.c; sourceTree = "<group>"; };
+ FCAD532C149BF58700CE0B4B /* error.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = error.h; sourceTree = "<group>"; };
+ FCAD532D149BF58700CE0B4B /* global.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = global.c; sourceTree = "<group>"; };
+ FCAD532E149BF58700CE0B4B /* global.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = global.h; sourceTree = "<group>"; };
+ FCAD532F149BF58700CE0B4B /* handler.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = handler.c; sourceTree = "<group>"; };
+ FCAD5330149BF58700CE0B4B /* header.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = header.c; sourceTree = "<group>"; };
+ FCAD5333149BF58700CE0B4B /* lexxer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lexxer.h; sourceTree = "<group>"; };
+ FCAD5334149BF58700CE0B4B /* lexxer.l */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.lex; path = lexxer.l; sourceTree = "<group>"; };
+ FCAD5337149BF58700CE0B4B /* mig.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = mig.1; sourceTree = "<group>"; };
+ FCAD5338149BF58700CE0B4B /* mig.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mig.c; sourceTree = "<group>"; };
+ FCAD5339149BF58700CE0B4B /* mig.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = mig.sh; sourceTree = "<group>"; };
+ FCAD533A149BF58700CE0B4B /* mig_errors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mig_errors.h; sourceTree = "<group>"; };
+ FCAD533B149BF58700CE0B4B /* mig_machine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mig_machine.h; sourceTree = "<group>"; };
+ FCAD533C149BF58700CE0B4B /* migcom.1 */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.man; path = migcom.1; sourceTree = "<group>"; };
+ FCAD5340149BF58700CE0B4B /* parser.y */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.yacc; path = parser.y; sourceTree = "<group>"; };
+ FCAD5343149BF58700CE0B4B /* routine.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = routine.c; sourceTree = "<group>"; };
+ FCAD5344149BF58700CE0B4B /* routine.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = routine.h; sourceTree = "<group>"; };
+ FCAD5345149BF58700CE0B4B /* server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = server.c; sourceTree = "<group>"; };
+ FCAD5346149BF58700CE0B4B /* statement.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = statement.c; sourceTree = "<group>"; };
+ FCAD5347149BF58700CE0B4B /* statement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = statement.h; sourceTree = "<group>"; };
+ FCAD5348149BF58700CE0B4B /* strdefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = strdefs.h; sourceTree = "<group>"; };
+ FCAD5349149BF58700CE0B4B /* string.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = string.c; sourceTree = "<group>"; };
+ FCAD534A149BF58700CE0B4B /* type.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = type.c; sourceTree = "<group>"; };
+ FCAD534B149BF58700CE0B4B /* type.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = type.h; sourceTree = "<group>"; };
+ FCAD534C149BF58700CE0B4B /* user.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = user.c; sourceTree = "<group>"; };
+ FCAD534D149BF58700CE0B4B /* utils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = utils.c; sourceTree = "<group>"; };
+ FCAD534E149BF58700CE0B4B /* utils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = utils.h; sourceTree = "<group>"; };
+ FCAD534F149BF58700CE0B4B /* write.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = write.h; sourceTree = "<group>"; };
+/* 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 = "<group>";
+ };
+ FC2DBC55149BF01800EACA9D /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ FC2DBC54149BF01800EACA9D /* migcom */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ FC2E188B149C017900349D18 /* xcodescripts */ = {
+ isa = PBXGroup;
+ children = (
+ FC2E188C149C017900349D18 /* install-mig.sh */,
+ );
+ path = xcodescripts;
+ sourceTree = "<group>";
+ };
+ 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 = "<group>";
+ };
+/* 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 <stdlib.h>
+
+#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 <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#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 <errno.h>
+
+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("<no name yet>");
+}
+
+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 <mach/message.h>
+#include "write.h"
+#include "utils.h"
+#include "global.h"
+
+static void
+WriteIncludes(FILE *file)
+{
+ fprintf(file, "#define EXPORT_BOOLEAN\n");
+ fprintf(file, "#include <mach/boolean.h>\n");
+ fprintf(file, "#include <mach/message.h>\n");
+ fprintf(file, "#include <mach/mig_errors.h>\n");
+ if (IsCamelot) {
+ fprintf(file, "#include <cam/camelot_types.h>\n");
+ fprintf(file, "#include <mach/msg_type.h>\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 <stdlib.h>
+
+void
+WriteIncludes(FILE *file, boolean_t isuser, boolean_t isdef)
+{
+ if (isdef) {
+ fprintf(file, "#include <mach/port.h>\n");
+ fprintf(file, "#include <mach/machine/kern_return.h>\n");
+ if (!isuser)
+ fprintf(file, "#include <mach/mig_errors.h>\n");
+ }
+ else {
+ fprintf(file, "#include <string.h>\n");
+ fprintf(file, "#include <mach/ndr.h>\n");
+ fprintf(file, "#include <mach/boolean.h>\n");
+ fprintf(file, "#include <mach/kern_return.h>\n");
+ fprintf(file, "#include <mach/notify.h>\n");
+ fprintf(file, "#include <mach/mach_types.h>\n");
+ fprintf(file, "#include <mach/message.h>\n");
+ fprintf(file, "#include <mach/mig_errors.h>\n");
+ fprintf(file, "#include <mach/port.h>\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(<mach/mig_voucher_support.h>)\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(<mach/mach_voucher_types.h>)\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(<mach/mig_strncpy_zerofill_support.h>)\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(<mach/mig_strncpy_zerofill_support.h>) */\n");
+ fprintf(file, "#endif /* __has_include */\n");
+ fprintf(file, "\t\n/* END MIG_STRNCPY_ZEROFILL CODE */\n\n");
+
+ if (ShortCircuit)
+ fprintf(file, "#include <mach/rpc.h>\n");
+ if (isuser && IsKernelUser) {
+ fprintf(file, "#if\t(__MigKernelSpecificCode) || (_MIG_KERNEL_SPECIFIC_CODE_)\n");
+ fprintf(file, "#include <kern/ipc_mig.h>\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 <sys/cdefs.h>\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 <sys/types.h>
+#include <mach/message.h>
+#include <mach/std_types.h>
+#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
+
+%%
+
+<Normal>[Rr][Oo][Uu][Tt][Ii][Nn][Ee] RETURN(syRoutine);
+<Normal>[Ss][Ii][Mm][Pp][Ll][Ee][Rr][Oo][Uu][Tt][Ii][Nn][Ee] RETURN(sySimpleRoutine);
+<Normal>[Ss][Uu][Bb][Ss][Yy][Ss][Tt][Ee][Mm] RETURN(sySubsystem);
+<Normal>[Mm][Ss][Gg][Oo][Pp][Tt][Ii][Oo][Nn] RETURN(syMsgOption);
+<Normal>[Uu][Ss][Ee][Ss][Pp][Ee][Cc][Ii][Aa][Ll][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syUseSpecialReplyPort);
+<Normal>[Cc][Oo][Nn][Ss][Uu][Mm][Ee][Oo][Nn][Ss][Ee][Nn][Dd][Ee][Rr][Rr][Oo][Rr] RETURN(syConsumeOnSendError);
+<Normal>[Mm][Ss][Gg][Ss][Ee][Qq][Nn][Oo] RETURN(syMsgSeqno);
+<Normal>[Ww][Aa][Ii][Tt][Tt][Ii][Mm][Ee] RETURN(syWaitTime);
+<Normal>[Ss][Ee][Nn][Dd][Tt][Ii][Mm][Ee] RETURN(sySendTime);
+<Normal>[Nn][Oo][Ww][Aa][Ii][Tt][Tt][Ii][Mm][Ee] RETURN(syNoWaitTime);
+<Normal>[Nn][Oo][Ss][Ee][Nn][Dd][Tt][Ii][Mm][Ee] RETURN(syNoSendTime);
+<Normal>[Ii][Nn] RETURN(syIn);
+<Normal>[Oo][Uu][Tt] RETURN(syOut);
+<Normal>[Uu][Ss][Ee][Rr][Ii][Mm][Pp][Ll] RETURN(syUserImpl);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Ii][Mm][Pp][Ll] RETURN(syServerImpl);
+<Normal>[Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(sySecToken);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(syServerSecToken);
+<Normal>[Uu][Ss][Ee][Rr][Ss][Ee][Cc][Tt][Oo][Kk][Ee][Nn] RETURN(syUserSecToken);
+<Normal>[Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syAuditToken);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syServerAuditToken);
+<Normal>[Uu][Ss][Ee][Rr][Aa][Uu][Dd][Ii][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syUserAuditToken);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Cc][Oo][Nn][Tt][Ee][Xx][Tt][Tt][Oo][Kk][Ee][Nn] RETURN(syServerContextToken);
+<Normal>[Ii][Nn][Oo][Uu][Tt] RETURN(syInOut);
+<Normal>[Rr][Ee][Qq][Uu][Ee][Ss][Tt][Pp][Oo][Rr][Tt] RETURN(syRequestPort);
+<Normal>[Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syReplyPort);
+<Normal>[Uu][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(syUReplyPort);
+<Normal>[Ss][Rr][Ee][Pp][Ll][Yy][Pp][Oo][Rr][Tt] RETURN(sySReplyPort);
+<Normal>[Aa][Rr][Rr][Aa][Yy] RETURN(syArray);
+<Normal>[Oo][Ff] RETURN(syOf);
+<Normal>[Ee][Rr][Rr][Oo][Rr] RETURN(syErrorProc);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Pp][Rr][Ee][Ff][Ii][Xx] RETURN(syServerPrefix);
+<Normal>[Uu][Ss][Ee][Rr][Pp][Rr][Ee][Ff][Ii][Xx] RETURN(syUserPrefix);
+<Normal>[Ss][Ee][Rr][Vv][Ee][Rr][Dd][Ee][Mm][Uu][Xx] RETURN(syServerDemux);
+<Normal>[Rr][Cc][Ss][Ii][Dd] RETURN(syRCSId);
+<Normal>[Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syImport);
+<Normal>[Uu][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syUImport);
+<Normal>[Ss][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(sySImport);
+<Normal>[Dd][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syDImport);
+<Normal>[Ii][Ii][Mm][Pp][Oo][Rr][Tt] RETURN(syIImport);
+<Normal>[Tt][Yy][Pp][Ee] RETURN(syType);
+<Normal>[Kk][Ee][Rr][Nn][Ee][Ll][Ss][Ee][Rr][Vv][Ee][Rr] RETURN(syKernelServer);
+<Normal>[Kk][Ee][Rr][Nn][Ee][Ll][Uu][Ss][Ee][Rr] RETURN(syKernelUser);
+<Normal>[Ss][Kk][Ii][Pp] RETURN(sySkip);
+<Normal>[Ss][Tt][Rr][Uu][Cc][Tt] RETURN(syStruct);
+<Normal>[Ii][Nn][Tt][Rr][Aa][Nn] RETURN(syInTran);
+<Normal>[Oo][Uu][Tt][Tt][Rr][Aa][Nn] RETURN(syOutTran);
+<Normal>[Dd][Ee][Ss][Tt][Rr][Uu][Cc][Tt][Oo][Rr] RETURN(syDestructor);
+<Normal>[Cc][Tt][Yy][Pp][Ee] RETURN(syCType);
+<Normal>[Cc][Uu][Ss][Ee][Rr][Tt][Yy][Pp][Ee] RETURN(syCUserType);
+<Normal>[Cc][Ss][Ee][Rr][Vv][Ee][Rr][Tt][Yy][Pp][Ee] RETURN(syCServerType);
+<Normal>[Cc]_[Ss][Tt][Rr][Ii][Nn][Gg] RETURN(syCString);
+
+<Normal>[Ss][Aa][Mm][Ee][Cc][Oo][Uu][Nn][Tt] FRETURN(flSameCount);
+<Normal>[Rr][Ee][Tt][Cc][Oo][Dd][Ee] FRETURN(flRetCode);
+<Normal>[Pp][Hh][Yy][Ss][Ii][Cc][Aa][Ll][Cc][Oo][Pp][Yy] FRETURN(flPhysicalCopy);
+<Normal>[Oo][Vv][Ee][Rr][Ww][Rr][Ii][Tt][Ee] FRETURN(flOverwrite);
+<Normal>[Dd][Ee][Aa][Ll][Ll][Oo][Cc] FRETURN(flDealloc);
+<Normal>[Nn][Oo][Tt][Dd][Ee][Aa][Ll][Ll][Oo][Cc] FRETURN(flNotDealloc);
+<Normal>[Cc][Oo][Uu][Nn][Tt][Ii][Nn][Oo][Uu][Tt] FRETURN(flCountInOut);
+<Normal>[Pp][Oo][Ll][Yy][Mm][Oo][Rr][Pp][Hh][Ii][Cc] TPRETURN(MACH_MSG_TYPE_POLYMORPHIC, MACH_MSG_TYPE_POLYMORPHIC, PortSize);
+<Normal>[Aa][Uu][Tt][Oo] FRETURN(flAuto);
+<Normal>[Cc][Oo][Nn][Ss][Tt] FRETURN(flConst);
+<Normal>"PointerTo" RETURN(syPointerTo);
+<Normal>"PointerToIfNot" RETURN(syPointerToIfNot);
+<Normal>"ValueOf" RETURN(syValueOf);
+<Normal>"UserTypeLimit" RETURN(syUserTypeLimit);
+<Normal>"OnStackLimit" RETURN(syOnStackLimit);
+
+
+<Normal>"MACH_MSG_TYPE_UNSTRUCTURED" TRETURN(MACH_MSG_TYPE_UNSTRUCTURED,0);
+<Normal>"MACH_MSG_TYPE_BIT" TRETURN(MACH_MSG_TYPE_BIT,1);
+<Normal>"MACH_MSG_TYPE_BOOLEAN" TRETURN(MACH_MSG_TYPE_BOOLEAN,32);
+<Normal>"MACH_MSG_TYPE_INTEGER_8" TRETURN(MACH_MSG_TYPE_INTEGER_8,8);
+<Normal>"MACH_MSG_TYPE_INTEGER_16" TRETURN(MACH_MSG_TYPE_INTEGER_16,16);
+<Normal>"MACH_MSG_TYPE_INTEGER_32" TRETURN(MACH_MSG_TYPE_INTEGER_32,32);
+<Normal>"MACH_MSG_TYPE_INTEGER_64" TRETURN(MACH_MSG_TYPE_INTEGER_64,64);
+<Normal>"MACH_MSG_TYPE_REAL_32" TRETURN(MACH_MSG_TYPE_REAL_32,32);
+<Normal>"MACH_MSG_TYPE_REAL_64" TRETURN(MACH_MSG_TYPE_REAL_64,64);
+<Normal>"MACH_MSG_TYPE_CHAR" TRETURN(MACH_MSG_TYPE_CHAR,8);
+<Normal>"MACH_MSG_TYPE_BYTE" TRETURN(MACH_MSG_TYPE_BYTE,8);
+
+<Normal>"MACH_MSG_TYPE_MOVE_RECEIVE" TPRETURN(MACH_MSG_TYPE_MOVE_RECEIVE,MACH_MSG_TYPE_PORT_RECEIVE,PortSize);
+<Normal>"MACH_MSG_TYPE_COPY_SEND" TPRETURN(MACH_MSG_TYPE_COPY_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_MAKE_SEND" TPRETURN(MACH_MSG_TYPE_MAKE_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_MOVE_SEND" TPRETURN(MACH_MSG_TYPE_MOVE_SEND,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_MAKE_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_MAKE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize);
+<Normal>"MACH_MSG_TYPE_MOVE_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_MOVE_SEND_ONCE,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize);
+
+<Normal>"MACH_MSG_TYPE_PORT_NAME" TRETURN(MACH_MSG_TYPE_PORT_NAME,PortSize);
+<Normal>"MACH_MSG_TYPE_PORT_RECEIVE" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_RECEIVE,PortSize);
+<Normal>"MACH_MSG_TYPE_PORT_SEND" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_SEND,PortSize);
+<Normal>"MACH_MSG_TYPE_PORT_SEND_ONCE" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC,MACH_MSG_TYPE_PORT_SEND_ONCE,PortSize);
+<Normal>"MACH_MSG_TYPE_POLYMORPHIC" TPRETURN(MACH_MSG_TYPE_POLYMORPHIC, MACH_MSG_TYPE_POLYMORPHIC, PortSize);
+
+<Normal>":" RETURN(syColon);
+<Normal>";" RETURN(sySemi);
+<Normal>"," RETURN(syComma);
+<Normal>"+" RETURN(syPlus);
+<Normal>"-" RETURN(syMinus);
+<Normal>"*" RETURN(syStar);
+<Normal>"/" RETURN(syDiv);
+<Normal>"(" RETURN(syLParen);
+<Normal>")" RETURN(syRParen);
+<Normal>"=" RETURN(syEqual);
+<Normal>"^" RETURN(syCaret);
+<Normal>"~" RETURN(syTilde);
+<Normal>"<" RETURN(syLAngle);
+<Normal>">" RETURN(syRAngle);
+<Normal>"[" RETURN(syLBrack);
+<Normal>"]" RETURN(syRBrack);
+<Normal>"|" RETURN(syBar);
+
+<Normal>{Ident} { yylval.identifier = strmake(yytext);
+ RETURN(syIdentifier); }
+<Normal>{Number} { yylval.number = atoi(yytext); RETURN(syNumber); }
+
+<String>{String} { yylval.string = strmake(yytext);
+ SAVE(Normal); RETURN(syString); }
+<FileName>{FileName} { yylval.string = strmake(yytext);
+ SAVE(Normal); RETURN(syFileName); }
+<QString>{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; }
+
+<SkipToEOL>\n { RESTORE; lineno++; }
+<SkipToEOL>. ;
+
+[ \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 <prefix>
+ * Put each user routine in its own file. The
+ * file is named <prefix><routine-name>.c.
+ * -user <name>
+ * Name the user-side file <name>
+ * -server <name>
+ * Name the server-side file <name>
+ * -header <name>
+ * Name the user-side header file <name>
+ * -iheader <name>
+ * Name the user-side internal header file <name>
+ * -sheader <name>
+ * Name the server-side header file <name>
+ * -dheader <name>
+ * Name the defines (msgh_ids) header file <name>
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#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 <mach/kern_return.h>
+#include <mach/message.h>
+
+#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 "<file"
+
+.SH DESCRIPTION
+.I migcom
+is the actual compiler used by the
+.I mig
+command to generate Remote Procedure Call (RPC) source code for
+client-server style Mach IPC from specification files. It is not normally
+used independently. Rather, it is invoked by the
+.I mig
+command after pre-processing the provided specifications file with the C
+preprocessor. It is only documented here for the sake of completeness.
+.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.
diff --git a/bootstrap_cmds/migcom.tproj/parser.y b/bootstrap_cmds/migcom.tproj/parser.y
new file mode 100644
index 0000000..1df43e4
--- /dev/null
+++ b/bootstrap_cmds/migcom.tproj/parser.y
@@ -0,0 +1,803 @@
+/*
+ * 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.
+ */
+
+%token sySkip
+%token syRoutine
+%token sySimpleRoutine
+
+%token sySubsystem
+%token syKernelUser
+%token syKernelServer
+
+%token syMsgOption
+%token syUseSpecialReplyPort
+%token syConsumeOnSendError
+%token syMsgSeqno
+%token syWaitTime
+%token sySendTime
+%token syNoWaitTime
+%token syNoSendTime
+%token syErrorProc
+%token syServerPrefix
+%token syUserPrefix
+%token syServerDemux
+%token syRCSId
+
+%token syImport
+%token syUImport
+%token sySImport
+%token syIImport
+%token syDImport
+
+%token syIn
+%token syOut
+%token syInOut
+%token syUserImpl
+%token syServerImpl
+%token syRequestPort
+%token syReplyPort
+%token sySReplyPort
+%token syUReplyPort
+
+%token syType
+%token syArray
+%token syStruct
+%token syOf
+
+%token syInTran
+%token syOutTran
+%token syDestructor
+%token syCType
+%token syCUserType
+%token syUserTypeLimit
+%token syOnStackLimit
+%token syCServerType
+%token syPointerTo
+%token syPointerToIfNot
+%token syValueOf
+
+%token syCString
+%token sySecToken
+%token syUserSecToken
+%token syServerSecToken
+%token syAuditToken
+%token syUserAuditToken
+%token syServerAuditToken
+%token syServerContextToken
+
+%token syColon
+%token sySemi
+%token syComma
+%token syPlus
+%token syMinus
+%token syStar
+%token syDiv
+%token syLParen
+%token syRParen
+%token syEqual
+%token syCaret
+%token syTilde
+%token syLAngle
+%token syRAngle
+%token syLBrack
+%token syRBrack
+%token syBar
+
+%token syError /* lex error */
+
+%token <number> syNumber
+%token <symtype> sySymbolicType
+%token <identifier> syIdentifier
+%token <string> syString syQString
+%token <string> syFileName
+%token <flag> syIPCFlag
+
+%left syPlus syMinus
+%left syStar syDiv
+
+
+%type <statement_kind> ImportIndicant
+%type <number> VarArrayHead ArrayHead StructHead IntExp
+%type <type> NamedTypeSpec TransTypeSpec NativeTypeSpec TypeSpec
+%type <type> CStringSpec
+%type <type> BasicTypeSpec PrevTypeSpec ArgumentType
+%type <identifier> TypePhrase
+%type <symtype> PrimIPCType IPCType
+%type <routine> RoutineDecl Routine SimpleRoutine
+%type <direction> Direction TrImplKeyword
+%type <argument> Argument Trailer Arguments ArgumentList
+%type <flag> IPCFlags
+
+%{
+
+#include <stdio.h>
+#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 <mach/message.h>
+#include <mach/kern_return.h>
+#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 <assert.h>
+
+#ifndef _ROUTINE_H
+#define _ROUTINE_H
+
+#include "type.h"
+#include <stdio.h>
+#include <mach/message.h>
+#include <mach/boolean.h>
+#include <sys/types.h>
+
+/* 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 <assert.h>
+#include <stdlib.h>
+
+#include <mach/message.h>
+#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 <mig_debug.h>\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "#include <mach/mig_log.h>\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 <subsystem>_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 <string.h>
+#include <mach/boolean.h>
+
+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 <mach/boolean.h>
+#include <ctype.h>
+#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 <sys/types.h>
+#include <mach/message.h>
+#include <mach/std_types.h>
+#include <mach/ndr.h>
+#include "mig_machine.h"
+#include "routine.h"
+#include "error.h"
+#include "alloc.h"
+#include "global.h"
+#include <stdio.h>
+
+#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 <mach/boolean.h>
+#include "strdefs.h"
+
+#ifdef linux
+#include <linux/types.h>
+#else /* linux */
+#include <sys/types.h>
+#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 <stdlib.h>
+#include <assert.h>
+
+#include <mach/message.h>
+#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 <SubsystemName>.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 <mig_debug.h>\n");
+ fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
+ }
+ fprintf(file, "#if MIG_DEBUG\n");
+ fprintf(file, "#include <mach/mig_log.h>\n");
+ fprintf(file, "#endif /* MIG_DEBUG */\n");
+ }
+ if (HasConsumeOnSendError && !IsKernelUser) {
+ fprintf(file, "#include <mach/mach.h>\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 <TargetConditionals.h>\n");
+ fprintf(file, "#include <mach/mach_sync_ipc.h>\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 <mach/mach.h> */\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 <mach/message.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#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 <stdio.h>
+#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