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