xref: /trueos/usr.bin/migcom/server.c (revision b063ab74d6b9065ef5cbfe3606224c8e7a302b34)
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 "AS IS"
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 Mellon
73  * the rights to redistribute these changes.
74  */
75 /*
76  * 92/03/03  16:25:17  jeffreyh
77  * 	Changes from TRUNK
78  * 	[92/02/26  12:32:30  jeffreyh]
79  *
80  * 92/01/14  16:46:39  rpd
81  * 	Modified WriteInitializeCount, WriteExtractArg
82  * 	for the revised CountInOut implementation.
83  * 	Fixed Indefinite code generation, to allow short type descriptors.
84  * 	Added deallocate bit handling to Indefinite code generation.
85  * 	[92/01/08            rpd]
86  *
87  * 92/01/03  20:30:09  dbg
88  * 	Generate <subsystem>_server_routine to return unpacking function
89  * 	pointer.
90  * 	[91/11/11            dbg]
91  *
92  * 	For inline variable-length arrays that are Out parameters, allow
93  * 	passing the user's count argument to the server as an InOut
94  * 	parameter.
95  * 	[91/11/11            dbg]
96  *
97  * 	Redo handling of OUT arrays that are passed in-line or
98  * 	out-of-line.  Treat more like out-of-line arrays:
99  * 	user allocates buffer and pointer
100  * 	fills in pointer with buffer address
101  * 	passes pointer to stub
102  * 	stub copies data to *pointer, or changes pointer
103  * 	User can always use *pointer.
104  *
105  * 	Change argByReferenceUser to a field in argument_t.
106  * 	[91/09/04            dbg]
107  *
108  * 91/08/28  11:17:21  jsb
109  * 	Replaced ServerProcName with ServerDemux.
110  * 	[91/08/13            rpd]
111  *
112  * 	Removed Camelot and TrapRoutine support.
113  * 	Changed MsgKind to MsgSeqno.
114  * 	[91/08/12            rpd]
115  *
116  * 91/07/31  18:10:51  dbg
117  * 	Allow indefinite-length variable arrays.  They may be copied
118  * 	either in-line or out-of-line, depending on size.
119  *
120  * 	Copy variable-length C Strings with mig_strncpy, to combine
121  * 	'strcpy' and 'strlen' operations.
122  *
123  * 	New method for advancing request message pointer past
124  * 	variable-length arguments.  We no longer have to know the order
125  * 	of variable-length arguments and their count arguments.
126  *
127  * 	Remove redundant assignments (to msgh_simple, msgh_size) in
128  * 	generated code.
129  * 	[91/07/17            dbg]
130  *
131  * 91/06/25  10:31:51  rpd
132  * 	Cast request and reply ports to ipc_port_t in KernelServer stubs.
133  * 	[91/05/27            rpd]
134  *
135  * 91/02/05  17:55:37  mrt
136  * 	Changed to new Mach copyright
137  * 	[91/02/01  17:55:30  mrt]
138  *
139  * 90/06/02  15:05:29  rpd
140  * 	Created for new IPC.
141  * 	[90/03/26  21:13:12  rpd]
142  *
143  * 07-Apr-89  Richard Draves (rpd) at Carnegie-Mellon University
144  *	Extensive revamping.  Added polymorphic arguments.
145  *	Allow multiple variable-sized inline arguments in messages.
146  *
147  * 18-Oct-88  Mary Thompson (mrt) at Carnegie-Mellon University
148  *	Set the local port in the server reply message to
149  *	MACH_PORT_NULL for greater efficiency and to make Camelot
150  *	happy.
151  *
152  * 18-Apr-88  Mary Thompson (mrt) at Carnegie-Mellon University
153  *	Changed call to WriteLocalVarDecl in WriteMsgVarDecl
154  *	to write out the parameters for the C++ code to a call
155  *	a new routine WriteServerVarDecl which includes the *
156  *	for reference variable, but uses the transType if it
157  *	exists.
158  *
159  * 27-Feb-88  Richard Draves (rpd) at Carnegie-Mellon University
160  *	Changed reply message initialization for camelot interfaces.
161  *	Now we assume camelot interfaces are all camelotroutines and
162  *	always initialize the dummy field & tid field.  This fixes
163  *	the wrapper-server-call bug in distributed transactions.
164  *
165  * 23-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
166  *	Changed the include of camelot_types.h to cam/camelot_types.h
167  *
168  * 19-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
169  *	Fixed WriteDestroyArg to not call the destructor
170  *	function on any in/out args.
171  *
172  *  4-Feb-88  Mary Thompson (mrt) at Carnegie-Mellon University
173  *	Fixed dld's code to write out parameter list to
174  *	use WriteLocalVarDecl to get transType or ServType if
175  *	they exist.
176  *
177  * 19-Jan-88  David Golub (dbg) at Carnegie-Mellon University
178  *	Change variable-length inline array declarations to use
179  *	maximum size specified to Mig.  Make message variable
180  *	length if the last item in the message is variable-length
181  *	and inline.  Use argMultipler field to convert between
182  *	argument and IPC element counts.
183  *
184  * 18-Jan-88  David Detlefs (dld) at Carnegie-Mellon University
185  *	Modified to produce C++ compatible code via #ifdefs.
186  *	All changes have to do with argument declarations.
187  *
188  *  2-Dec-87  David Golub (dbg) at Carnegie-Mellon University
189  *	Added destructor function for IN arguments to server.
190  *
191  * 18-Nov-87  Jeffrey Eppinger (jle) at Carnegie-Mellon University
192  *	Changed to typedef "novalue" as "void" if we're using hc.
193  *
194  * 17-Sep-87  Bennet Yee (bsy) at Carnegie-Mellon University
195  *	Added _<system>SymTab{Base|End} for use with security
196  *	dispatch routine.  It is neccessary for the authorization
197  *	system to know the operations by symbolic names.
198  *	It is harmless to user code as it only means an extra
199  *	array if it is accidentally turned on.
200  *
201  * 24-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
202  *	Corrected the setting of retcode for CamelotRoutines.
203  *
204  * 21-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
205  *	Added deallocflag to call to WritePackArgType.
206  *
207  * 14-Aug-87  Mary Thompson (mrt) at Carnegie-Mellon University
208  *	Moved type declarations and assignments for DummyType
209  *	and tidType to server demux routine. Automatically
210  *	include camelot_types.h and msg_types.h for interfaces
211  *	containing camelotRoutines.
212  *
213  *  8-Jun-87  Mary Thompson (mrt) at Carnegie-Mellon University
214  *	Removed #include of sys/types.h and strings.h from WriteIncludes.
215  *	Changed the KERNEL include from ../h to sys/
216  *	Removed extern from WriteServer to make hi-c happy
217  *
218  * 28-May-87  Richard Draves (rpd) at Carnegie-Mellon University
219  *	Created.
220  */
221 
222 #include <assert.h>
223 #include <stdlib.h>
224 
225 #include <mach/message.h>
226 #include "write.h"
227 #include "utils.h"
228 #include "global.h"
229 #include "error.h"
230 
231 #ifndef max
232 #define max(a,b) (((a) > (b)) ? (a) : (b))
233 #endif  /* max */
234 
235 void WriteLogDefines();
236 void WriteIdentificationString();
237 static void WriteFieldDecl();
238 
239 static void
WriteKPD_Iterator(FILE * file,boolean_t in,boolean_t varying,argument_t * arg,boolean_t bracket)240 WriteKPD_Iterator(FILE *file, boolean_t in, boolean_t varying, argument_t *arg, boolean_t bracket)
241 {
242 	register ipc_type_t *it = arg->argType;
243 	char string[MAX_STR_LEN];
244 
245 	fprintf(file, "\t{\n");
246 	fprintf(file, "\t    register\t%s\t*ptr;\n", it->itKPDType);
247 	fprintf(file, "\t    register int\ti");
248 	if (varying && !in)
249 		fprintf(file, ", j");
250 	fprintf(file, ";\n\n");
251 
252 	if (in)
253 		sprintf(string, "In%dP", arg->argRequestPos);
254 	else
255 		sprintf(string, "OutP");
256 
257 	fprintf(file, "\t    ptr = &%s->%s[0];\n", string, arg->argMsgField);
258 
259 	if (varying) {
260 		register argument_t *count = arg->argCount;
261 
262 		if (in)
263             fprintf(file, "\t    for (i = 0; i < In%dP->%s; ptr++, i++) %s\n",
264 					count->argRequestPos, count->argMsgField,
265 					(bracket) ? "{" : "");
266 		else {
267 			fprintf(file, "\t    j = min(%d, ", it->itKPD_Number);
268 			if (akCheck(count->argKind, akbVarNeeded))
269 				fprintf(file, "%s);\n", count->argName);
270 			else
271 				fprintf(file, "%s->%s);\n", string, count->argMsgField);
272             fprintf(file, "\t    for (i = 0; i < j; ptr++, i++) %s\n",
273 					(bracket) ? "{" : "");
274 		}
275     } else
276         fprintf(file, "\t    for (i = 0; i < %d; ptr++, i++) %s\n", it->itKPD_Number,
277 				(bracket) ? "{" : "");
278 }
279 
280 static void
WriteMyIncludes(FILE * file,statement_t * stats)281 WriteMyIncludes(FILE *file, statement_t *stats)
282 {
283 	if (ServerHeaderFileName == strNULL || UseSplitHeaders)
284 		WriteIncludes(file, FALSE, FALSE);
285 	if (ServerHeaderFileName != strNULL)
286 	{
287         register const char *cp;
288 
289 		/* Strip any leading path from ServerHeaderFileName. */
290 		cp = strrchr(ServerHeaderFileName, '/');
291 		if (cp == 0)
292 			cp = ServerHeaderFileName;
293 		else
294 			cp++;       /* skip '/' */
295 		fprintf(file, "#include \"%s\"\n", cp);
296 	}
297 	if (ServerHeaderFileName == strNULL || UseSplitHeaders)
298 		WriteImplImports(file, stats, FALSE);
299 	if (UseEventLogger) {
300 		if (IsKernelServer) {
301 			fprintf(file, "#if\t__MigKernelSpecificCode\n");
302 			fprintf(file, "#include <mig_debug.h>\n");
303 			fprintf(file, "#endif\t/* __MigKernelSpecificCode */\n");
304 		}
305 		fprintf(file, "#if  MIG_DEBUG\n");
306 		fprintf(file, "#include <mach/mig_log.h>\n");
307 		fprintf(file, "#endif /* MIG_DEBUG */\n");
308 	}
309 	fprintf(file, "\n");
310 }
311 
312 static void
WriteGlobalDecls(FILE * file)313 WriteGlobalDecls(FILE *file)
314 {
315 	if (BeAnsiC) {
316 		fprintf(file, "#define novalue void\n");
317     } else {
318 		fprintf(file, "#if\t%s\n", NewCDecl);
319 		fprintf(file, "#define novalue void\n");
320 		fprintf(file, "#else\n");
321 		fprintf(file, "#define novalue int\n");
322 		fprintf(file, "#endif\t/* %s */\n", NewCDecl);
323 		WriteRCSDecl(file, strconcat(SubsystemName, "_server"), RCSId);
324 	}
325 	/* Used for locations in the request message, *not* reply message.
326 	   Reply message locations aren't dependent on IsKernelServer. */
327 
328 	if (IsKernelServer) {
329 		fprintf(file, "#if\t__MigKernelSpecificCode\n");
330 		fprintf(file, "#define msgh_request_port\tmsgh_remote_port\n");
331 		fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
332 		fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
333 		fprintf(file, "#define msgh_reply_port\t\tmsgh_local_port\n");
334 		fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
335 		fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
336 		fprintf(file, "#else\n");
337 	}
338 	fprintf(file, "#define msgh_request_port\tmsgh_local_port\n");
339 	fprintf(file, "#define MACH_MSGH_BITS_REQUEST(bits)");
340 	fprintf(file, "\tMACH_MSGH_BITS_LOCAL(bits)\n");
341 	fprintf(file, "#define msgh_reply_port\t\tmsgh_remote_port\n");
342 	fprintf(file, "#define MACH_MSGH_BITS_REPLY(bits)");
343 	fprintf(file, "\tMACH_MSGH_BITS_REMOTE(bits)\n");
344 	if (IsKernelServer) {
345 		fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
346 	}
347 	fprintf(file, "\n");
348 	if (UseEventLogger)
349 		WriteLogDefines(file, "MACH_MSG_LOG_SERVER");
350 	fprintf(file, "#define MIG_RETURN_ERROR(X, code)\t{\\\n");
351 	fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->RetCode = code;\\\n");
352 	fprintf(file, "\t\t\t\t((mig_reply_error_t *)X)->NDR = NDR_record;\\\n");
353 	fprintf(file, "\t\t\t\treturn;\\\n");
354 	fprintf(file, "\t\t\t\t}\n");
355 	fprintf(file, "\n");
356 }
357 
358 static void
WriteForwardDeclarations(FILE * file,statement_t * stats)359 WriteForwardDeclarations(FILE *file, statement_t *stats)
360 {
361 	register statement_t *stat;
362 
363 	fprintf(file, "/* Forward Declarations */\n\n");
364 	for (stat = stats; stat != stNULL; stat = stat->stNext)
365 		if (stat->stKind == skRoutine) {
366 			fprintf(file, "\nmig_internal novalue _X%s\n", stat->stRoutine->rtName);
367 			fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP);\n");
368 		}
369 	fprintf(file, "\n");
370 }
371 
372 static void
WriteMIGCheckDefines(FILE * file)373 WriteMIGCheckDefines(FILE *file)
374 {
375 	fprintf(file, "#define\t__MIG_check__Request__%s_subsystem__ 1\n", SubsystemName);
376 	fprintf(file, "\n");
377 }
378 
379 static void
WriteNDRDefines(FILE * file)380 WriteNDRDefines(FILE *file)
381 {
382 	fprintf(file, "#define\t__NDR_convert__Request__%s_subsystem__ 1\n", SubsystemName);
383 	fprintf(file, "\n");
384 }
385 
386 static void
WriteProlog(FILE * file,statement_t * stats)387 WriteProlog(FILE *file, statement_t *stats)
388 {
389 	WriteIdentificationString(file);
390 	fprintf(file, "\n");
391 	fprintf(file, "/* Module %s */\n", SubsystemName);
392 	fprintf(file, "\n");
393 	WriteMIGCheckDefines(file);
394 	if (CheckNDR)
395 		WriteNDRDefines(file);
396 	WriteMyIncludes(file, stats);
397 	WriteBogusDefines(file);
398 	WriteApplDefaults(file, "Rcv");
399 	WriteGlobalDecls(file);
400 	if (ServerHeaderFileName == strNULL) {
401 		WriteRequestTypes(file, stats);
402 		WriteReplyTypes(file, stats);
403 		WriteServerReplyUnion(file, stats);
404 	}
405 }
406 
407 static void
WriteSymTabEntries(FILE * file,statement_t * stats)408 WriteSymTabEntries(FILE *file, statement_t *stats)
409 {
410 	register statement_t *stat;
411 	register u_int current = 0;
412 
413 	for (stat = stats; stat != stNULL; stat = stat->stNext)
414 		if (stat->stKind == skRoutine) {
415 			register u_int num = stat->stRoutine->rtNumber;
416 			const char	*name = stat->stRoutine->rtName;
417 			while (++current <= num)
418 				fprintf(file,"\t\t\t{ \"\", 0, 0 },\n");
419 			fprintf(file, "\t{ \"%s\", %d, _X%s },\n", name, SubsystemBase + current - 1, name);
420 		}
421 	while (++current <= rtNumber)
422 		fprintf(file,"\t{ \"\", 0, 0 },\n");
423 }
424 
425 static void
WriteRoutineEntries(FILE * file,statement_t * stats)426 WriteRoutineEntries(FILE *file, statement_t *stats)
427 {
428 	register u_int current = 0;
429 	register statement_t *stat;
430 	char *sig_array, *rt_name;
431 	int arg_count, descr_count;
432 	int offset = 0;
433 	size_t serverSubsysNameLen = strlen(ServerSubsys);
434 
435 	fprintf(file, "\t{\n");
436 	for (stat = stats; stat != stNULL; stat = stat->stNext)
437 		if (stat->stKind == skRoutine)
438 		{
439 			register  routine_t *rt = stat->stRoutine;
440 			size_t       rtNameLen = strlen(rt->rtName);
441 
442 			// Include length of rt->rtName in calculation of necessary buffer size, since that string
443 			// is actually written into the buffer along with the Server Subsystem name.
444 			sig_array = (char *) malloc(serverSubsysNameLen + rtNameLen + 80);
445 			rt_name = (char *) malloc(rtNameLen + 5);
446 			while (current++ < rt->rtNumber)
447 				fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n");
448 			// NOTE: if either of the two string constants in the sprintf() function calls below get
449 			// much longer, be sure to increase the constant '80' (in the first malloc() call) to ensure
450 			// that the allocated buffer is large enough. (Currently, I count 66 characters in the first
451 			// string constant, 65 in the second. 80 ought to be enough for now...)
452 			if (UseRPCTrap) {
453 				sprintf(sig_array, "&%s.arg_descriptor[%d], (mach_msg_size_t)sizeof(__Reply__%s_t)", ServerSubsys, offset, rt->rtName);
454 			}
455 			else {
456 				sprintf(sig_array, "(routine_arg_descriptor_t)0, (mach_msg_size_t)sizeof(__Reply__%s_t)", rt->rtName);
457 			}
458 			sprintf(rt_name, "_X%s", rt->rtName);
459 			descr_count = rtCountArgDescriptors(rt->rtArgs, &arg_count);
460 			offset += descr_count;
461 			WriteRPCRoutineDescriptor(file, rt, arg_count, (UseRPCTrap) ? descr_count : 0, rt_name, sig_array);
462 			fprintf(file, ",\n");
463 			free(sig_array);
464 			free(rt_name);
465 		}
466 	while (current++ < rtNumber)
467 		fprintf(file, "\t\t{0, 0, 0, 0, 0, 0},\n");
468 
469 	fprintf(file, "\t}");
470 }
471 
472 static void
WriteArgDescriptorEntries(FILE * file,statement_t * stats)473 WriteArgDescriptorEntries(FILE *file, statement_t *stats)
474 {
475 	register statement_t *stat;
476 
477 	fprintf(file, ",\n\n\t{\n");
478 	for (stat = stats; stat != stNULL; stat = stat->stNext)
479 		if (stat->stKind == skRoutine)
480 		{
481 			register routine_t *rt = stat->stRoutine;
482 
483 			/* For each arg of the routine, write an arg descriptor:
484 			 */
485 			WriteRPCRoutineArgDescriptor(file, rt);
486 		}
487 	fprintf(file, "\t},\n\n");
488 }
489 
490 
491 /*
492  * Write out the description of this subsystem, for use in direct RPC
493  */
494 static void
WriteSubsystem(FILE * file,statement_t * stats)495 WriteSubsystem(FILE *file, statement_t *stats)
496 {
497 	register statement_t *stat;
498 	int descr_count = 0;
499 
500 	for (stat = stats; stat != stNULL; stat = stat->stNext)
501 		if (stat->stKind == skRoutine)
502 		{
503 			register routine_t *rt = stat->stRoutine;
504 			descr_count += rtCountArgDescriptors(rt->rtArgs, (int *) 0);
505 		}
506 	fprintf(file, "\n");
507 	if (ServerHeaderFileName == strNULL) {
508 		WriteMigExternal(file);
509 		fprintf(file, "boolean_t %s(", ServerDemux);
510 		if (BeAnsiC) {
511 			fprintf(file, "\n\t\tmach_msg_header_t *InHeadP,");
512 			fprintf(file, "\n\t\tmach_msg_header_t *OutHeadP");
513 		}
514 		fprintf(file, ");\n\n");
515 
516 		WriteMigExternal(file);
517 		fprintf(file, "mig_routine_t %s_routine(", ServerDemux);
518 		if (BeAnsiC) {
519 			fprintf(file, "\n\t\tmach_msg_header_t *InHeadP");
520 		}
521 		fprintf(file, ");\n\n");
522 	}
523 	fprintf(file, "\n/* Description of this subsystem, for use in direct RPC */\n");
524 	if (ServerHeaderFileName == strNULL) {
525 		fprintf(file, "extern const struct %s %s;\n", ServerSubsys, ServerSubsys);
526 		fprintf(file, "const struct %s {\n", ServerSubsys);
527 		if (UseRPCTrap) {
528 			fprintf(file, "\tstruct subsystem *\tsubsystem;\t/* Reserved for system use */\n");
529 		}
530 		else {
531 			fprintf(file, "\tmig_server_routine_t \tserver;\t/* Server routine */\n");
532 		}
533 		fprintf(file, "\tmach_msg_id_t\tstart;\t/* Min routine number */\n");
534 		fprintf(file, "\tmach_msg_id_t\tend;\t/* Max routine number + 1 */\n");
535 		fprintf(file, "\tunsigned int\tmaxsize;\t/* Max msg size */\n");
536 		if (UseRPCTrap) {
537 			fprintf(file, "\tvm_address_t\tbase_addr;\t/* Base address */\n");
538 			fprintf(file, "\tstruct rpc_routine_descriptor\t/*Array of routine descriptors */\n");
539 		}
540 		else {
541 			fprintf(file, "\tvm_address_t\treserved;\t/* Reserved */\n");
542 			fprintf(file, "\tstruct routine_descriptor\t/*Array of routine descriptors */\n");
543 		}
544 		fprintf(file, "\t\troutine[%d];\n", rtNumber);
545 		if (UseRPCTrap) {
546 			fprintf(file, "\tstruct rpc_routine_arg_descriptor\t/*Array of arg descriptors */\n");
547 			fprintf(file, "\t\targ_descriptor[%d];\n", descr_count);
548 		}
549 		fprintf(file, "} %s = {\n", ServerSubsys);
550 	}
551 	else {
552 		fprintf(file, "const struct %s %s = {\n", ServerSubsys, ServerSubsys);
553 	}
554 	if (UseRPCTrap) {
555 		fprintf(file, "\t0,\n");
556 	}
557 	else {
558 		fprintf(file, "\t%s_routine,\n", ServerDemux);
559 	}
560 	fprintf(file, "\t%d,\n", SubsystemBase);
561 	fprintf(file, "\t%d,\n", SubsystemBase + rtNumber);
562 	fprintf(file, "\t(mach_msg_size_t)sizeof(union __ReplyUnion__%s),\n", ServerSubsys);
563 	if (UseRPCTrap) {
564 		fprintf(file, "\t(vm_address_t)&%s,\n", ServerSubsys);
565 	}
566 	else {
567 		fprintf(file, "\t(vm_address_t)0,\n");
568 	}
569 	WriteRoutineEntries(file, stats);
570 
571 	if (UseRPCTrap)
572 		WriteArgDescriptorEntries(file, stats);
573 	else
574 		fprintf(file, "\n");
575 
576 	fprintf(file, "};\n\n");
577 }
578 #if 0
579 static void
580 WriteArraySizes(file, stats)
581     FILE *file;
582     statement_t *stats;
583 {
584 	register u_int current = 0;
585 	register statement_t *stat;
586 
587 	for (stat = stats; stat != stNULL; stat = stat->stNext)
588 		if (stat->stKind == skRoutine)
589 		{
590 			register routine_t *rt = stat->stRoutine;
591 
592 			while (current++ < rt->rtNumber)
593 				fprintf(file, "\t\t0,\n");
594 			fprintf(file, "\t\tsizeof(__Reply__%s_t),\n", rt->rtName);
595 		}
596 	while (current++ < rtNumber)
597 		fprintf(file, "\t\t\t0,\n");
598 }
599 
600 #endif /* NOT_CURRENTLY_USED */
601 
602 void
WriteServerRequestUnion(FILE * file,statement_t * stats)603 WriteServerRequestUnion(FILE *file, statement_t *stats)
604 {
605 	register statement_t *stat;
606 
607 	fprintf(file, "\n");
608 	fprintf(file, "/* union of all requests */\n\n");
609 	fprintf(file, "#ifndef __RequestUnion__%s__defined\n", ServerSubsys);
610 	fprintf(file, "#define __RequestUnion__%s__defined\n", ServerSubsys);
611 	fprintf(file, "union __RequestUnion__%s {\n", ServerSubsys);
612 	for (stat = stats; stat != stNULL; stat = stat->stNext) {
613 		if (stat->stKind == skRoutine) {
614 			register routine_t *rt;
615 
616 			rt = stat->stRoutine;
617 			fprintf(file, "\t__Request__%s_t Request_%s;\n", rt->rtName, rt->rtName);
618 		}
619 	}
620 	fprintf(file, "};\n");
621 	fprintf(file, "#endif /* __RequestUnion__%s__defined */\n", ServerSubsys);
622 }
623 
624 void
WriteServerReplyUnion(FILE * file,statement_t * stats)625 WriteServerReplyUnion(FILE *file, statement_t *stats)
626 {
627 	register statement_t *stat;
628 
629 	fprintf(file, "\n");
630 	fprintf(file, "/* union of all replies */\n\n");
631 	fprintf(file, "#ifndef __ReplyUnion__%s__defined\n", ServerSubsys);
632 	fprintf(file, "#define __ReplyUnion__%s__defined\n", ServerSubsys);
633 	fprintf(file, "union __ReplyUnion__%s {\n", ServerSubsys);
634 	for (stat = stats; stat != stNULL; stat = stat->stNext) {
635 		if (stat->stKind == skRoutine) {
636 			register routine_t *rt;
637 
638 			rt = stat->stRoutine;
639 			fprintf(file, "\t__Reply__%s_t Reply_%s;\n", rt->rtName, rt->rtName);
640 		}
641 	}
642 	fprintf(file, "};\n");
643 	fprintf(file, "#endif /* __RequestUnion__%s__defined */\n", ServerSubsys);
644 }
645 
646 static void
WriteDispatcher(FILE * file,statement_t * stats)647 WriteDispatcher(FILE *file, statement_t *stats)
648 {
649 	/*
650 	 * Write the subsystem stuff.
651 	 */
652 	fprintf(file, "\n");
653 	WriteSubsystem(file, stats);
654 
655 	/*
656 	 * Then, the server routine
657 	 */
658 	fprintf(file, "mig_external boolean_t %s\n", ServerDemux);
659 	if (BeAnsiC) {
660 		fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
661     } else {
662 		fprintf(file, "#if\t%s\n", NewCDecl);
663 		fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
664 		fprintf(file, "#else\n");
665 		fprintf(file, "\t(InHeadP, OutHeadP)\n");
666 		fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
667 		fprintf(file, "#endif\t/* %s */\n", NewCDecl);
668 	}
669 
670 	fprintf(file, "{\n");
671 	fprintf(file, "\t/*\n");
672 	fprintf(file, "\t * typedef struct {\n");
673 	fprintf(file, "\t * \tmach_msg_header_t Head;\n");
674 	fprintf(file, "\t * \tNDR_record_t NDR;\n");
675 	fprintf(file, "\t * \tkern_return_t RetCode;\n");
676 	fprintf(file, "\t * } mig_reply_error_t;\n");
677 	fprintf(file, "\t */\n");
678 	fprintf(file, "\n");
679 
680 	fprintf(file, "\tregister mig_routine_t routine;\n");
681 	fprintf(file, "\n");
682 
683 	fprintf(file, "\tOutHeadP->msgh_bits = ");
684 	fprintf(file, "MACH_MSGH_BITS(MACH_MSGH_BITS_REPLY(InHeadP->msgh_bits), 0);\n");
685 	fprintf(file, "\tOutHeadP->msgh_remote_port = InHeadP->msgh_reply_port;\n");
686 	fprintf(file, "\t/* Minimal size: routine() will update it if different */\n");
687 	fprintf(file, "\tOutHeadP->msgh_size = (mach_msg_size_t)sizeof(mig_reply_error_t);\n");
688 	fprintf(file, "\tOutHeadP->msgh_local_port = MACH_PORT_NULL;\n");
689 	fprintf(file, "\tOutHeadP->msgh_id = InHeadP->msgh_id + 100;\n");
690 	fprintf(file, "\n");
691 
692 	fprintf(file, "\tif ((InHeadP->msgh_id > %d) || (InHeadP->msgh_id < %d) ||\n", SubsystemBase + rtNumber - 1, SubsystemBase);
693 	fprintf(file, "\t    ((routine = %s.routine[InHeadP->msgh_id - %d].stub_routine) == 0)) {\n", ServerSubsys, SubsystemBase);
694 	fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->NDR = NDR_record;\n");
695 	fprintf(file, "\t\t((mig_reply_error_t *)OutHeadP)->RetCode = MIG_BAD_ID;\n");
696 	if (UseEventLogger) {
697 		fprintf(file, "#if  MIG_DEBUG\n");
698 		fprintf(file, "\t\tLOG_ERRORS(MACH_MSG_LOG_SERVER, MACH_MSG_ERROR_UNKNOWN_ID,\n");
699 		fprintf(file, "\t\t\t&InHeadP->msgh_id, __FILE__, __LINE__);\n");
700 		fprintf(file, "#endif /* MIG_DEBUG */\n");
701 	}
702 	fprintf(file, "\t\treturn FALSE;\n");
703 	fprintf(file, "\t}\n");
704 
705 	/* Call appropriate routine */
706 	fprintf(file, "\t(*routine) (InHeadP, OutHeadP);\n");
707 	fprintf(file, "\treturn TRUE;\n");
708 	fprintf(file, "}\n");
709 	fprintf(file, "\n");
710 
711 	/*
712 	 * Then, the <subsystem>_server_routine routine
713 	 */
714 	fprintf(file, "mig_external mig_routine_t %s_routine\n", ServerDemux);
715 	if (BeAnsiC) {
716 		fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
717     } else {
718 		fprintf(file, "#if\t%s\n", NewCDecl);
719 		fprintf(file, "\t(mach_msg_header_t *InHeadP)\n");
720 		fprintf(file, "#else\n");
721 		fprintf(file, "\t(InHeadP)\n");
722 		fprintf(file, "\tmach_msg_header_t *InHeadP;\n");
723 		fprintf(file, "#endif\t/* %s */\n", NewCDecl);
724 	}
725 
726 	fprintf(file, "{\n");
727 	fprintf(file, "\tregister int msgh_id;\n");
728 	fprintf(file, "\n");
729 	fprintf(file, "\tmsgh_id = InHeadP->msgh_id - %d;\n", SubsystemBase);
730 	fprintf(file, "\n");
731 	fprintf(file, "\tif ((msgh_id > %d) || (msgh_id < 0))\n", rtNumber - 1);
732 	fprintf(file, "\t\treturn 0;\n");
733 	fprintf(file, "\n");
734 	fprintf(file, "\treturn %s.routine[msgh_id].stub_routine;\n", ServerSubsys);
735 	fprintf(file, "}\n");
736 
737 	/* symtab */
738 
739 	if (GenSymTab) {
740 		fprintf(file,"\nmig_symtab_t _%sSymTab[] = {\n",SubsystemName);
741 		WriteSymTabEntries(file,stats);
742 		fprintf(file,"};\n");
743 		fprintf(file,"int _%sSymTabBase = %d;\n",SubsystemName,SubsystemBase);
744 		fprintf(file,"int _%sSymTabEnd = %d;\n",SubsystemName,SubsystemBase+rtNumber);
745 	}
746 }
747 
748 /*
749  *  Returns the return type of the server-side work function.
750  *  Suitable for "extern %s serverfunc()".
751  */
752 #if 0
753 static const char *
754 ServerSideType(rt)
755     routine_t *rt;
756 {
757 	return rt->rtRetCode->argType->itTransType;
758 }
759 #endif
760 static void
WriteRetCode(file,ret)761 WriteRetCode(file, ret)
762     FILE *file;
763     register argument_t *ret;
764 {
765 	register ipc_type_t *it = ret->argType;
766 
767 	if (akCheck(ret->argKind, akbVarNeeded)) {
768 		fprintf(file, "\t%s %s;\n", it->itTransType, ret->argVarName);
769 	}
770 }
771 
772 static void
WriteLocalVarDecl(FILE * file,register argument_t * arg)773 WriteLocalVarDecl(FILE *file, register argument_t *arg)
774 {
775 	register ipc_type_t *it = arg->argType;
776 	register ipc_type_t *btype = it->itElement;
777 
778 	if (IS_VARIABLE_SIZED_UNTYPED(it))
779 		fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, btype->itNumber ? it->itNumber/btype->itNumber : 0);
780 	else if (IS_MULTIPLE_KPD(it)) {
781 		if (btype->itTransType != strNULL)
782 			fprintf(file, "\t%s %s[%d]", btype->itTransType, arg->argVarName, it->itKPD_Number);
783 		else
784 			/* arrays of ool or oolport */
785 			fprintf(file, "\tvoid *%s[%d]", arg->argVarName, it->itKPD_Number);
786 	} else
787 		fprintf(file, "\t%s %s", it->itTransType, arg->argVarName);
788 }
789 
790 #if 0
791 static void
792 WriteServerArgDecl(file, arg)
793     FILE *file;
794     argument_t *arg;
795 {
796     fprintf(file, "%s %s%s",
797 			arg->argType->itTransType,
798 			arg->argByReferenceServer ? "*" : "",
799 			arg->argVarName);
800 }
801 #endif
802 /*
803  *  Writes the local variable declarations which are always
804  *  present:  InP, OutP, the server-side work function.
805  */
806 static void
WriteVarDecls(FILE * file,routine_t * rt)807 WriteVarDecls(FILE *file, routine_t *rt)
808 {
809 	u_int i;
810 
811 	fprintf(file, "\tRequest *In0P = (Request *) InHeadP;\n");
812 	for (i = 1; i <= rt->rtMaxRequestPos; i++)
813 		fprintf(file, "\tRequest *In%dP = NULL;\n", i);
814 	fprintf(file, "\tReply *OutP = (Reply *) OutHeadP;\n");
815 
816 	/* if reply is variable, we may need msgh_size_delta and msgh_size */
817 	if (rt->rtNumReplyVar > 1)
818 		fprintf(file, "\tunsigned int msgh_size;\n");
819 	if (rt->rtMaxReplyPos > 0)
820 		fprintf(file, "\tunsigned int msgh_size_delta;\n");
821 	if (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos > 0)
822 		fprintf(file, "\n");
823 
824 	if (rt->rtServerImpl) {
825 		fprintf(file, "\tmach_msg_max_trailer_t *TrailerP;\n");
826 		fprintf(file, "#if\t__MigTypeCheck\n");
827 		fprintf(file, "\tunsigned int trailer_size;\n");
828 		fprintf(file, "#endif\t/* __MigTypeCheck */\n");
829 	}
830 	fprintf(file, "#ifdef\t__MIG_check__Request__%s_t__defined\n", rt->rtName);
831 	fprintf(file, "\tkern_return_t check_result;\n");
832 	fprintf(file, "#endif\t/* __MIG_check__Request__%s_t__defined */\n", rt->rtName);
833 	fprintf(file, "\n");
834 }
835 
836 static void
WriteReplyInit(FILE * file,routine_t * rt)837 WriteReplyInit(FILE *file, routine_t *rt)
838 {
839 	fprintf(file, "\n");
840 	if  (rt->rtNumReplyVar > 1 || rt->rtMaxReplyPos)
841 		/* WritheAdjustMsgSize() has been executed at least once! */
842 		fprintf(file, "\tOutP = (Reply *) OutHeadP;\n");
843 
844 	if (!rt->rtSimpleReply)  /* complex reply message */
845 		fprintf(file,
846 				"\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;\n");
847 
848 	if (rt->rtNumReplyVar == 0) {
849 		fprintf(file, "\tOutP->Head.msgh_size = ");
850 		rtMinReplySize(file, rt, "Reply");
851 		fprintf(file, ";\n");
852     } else if (rt->rtNumReplyVar > 1)
853 		fprintf(file, "\tOutP->Head.msgh_size = msgh_size;\n");
854 	/* the case rt->rtNumReplyVar = 1 is taken care of in WriteAdjustMsgSize() */
855 }
856 
857 static void
WriteRetCArgCheckError(FILE * file,routine_t * rt __unused)858 WriteRetCArgCheckError(FILE *file, routine_t *rt __unused)
859 {
860 	fprintf(file, "\tif (!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) &&\n");
861     fprintf(file, "\t    (In0P->Head.msgh_size == sizeof(mig_reply_error_t)))\n");
862 	fprintf(file, "\t{\n");
863 }
864 
865 static void
WriteRetCArgFinishError(FILE * file,routine_t * rt)866 WriteRetCArgFinishError(FILE *file, routine_t *rt)
867 {
868 	argument_t *retcode = rt->rtRetCArg;
869 
870 	fprintf(file, "\treturn;\n");
871 	fprintf(file, "\t}\n");
872 	retcode->argMsgField = "KERN_SUCCESS";
873 }
874 
875 static void
WriteCheckHead(FILE * file,routine_t * rt)876 WriteCheckHead(FILE *file, routine_t *rt)
877 {
878 	fprintf(file, "#if\t__MigTypeCheck\n");
879 	if (rt->rtNumRequestVar > 0)
880 		fprintf(file, "\tmsgh_size = In0P->Head.msgh_size;\n");
881 
882 	if (rt->rtSimpleRequest) {
883 		/* Expecting a simple message. */
884 		fprintf(file, "\tif ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
885 		if (rt->rtNumRequestVar > 0) {
886 			fprintf(file, "\t    (msgh_size < ");
887 			rtMinRequestSize(file, rt, "__Request");
888 			fprintf(file, ") ||  (msgh_size > (mach_msg_size_t)sizeof(__Request)))\n");
889 		}
890 		else
891 			fprintf(file, "\t    (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request)))\n");
892 	}
893 	else {
894 		/* Expecting a complex message. */
895 
896 		fprintf(file, "\tif (");
897 		if (rt->rtRetCArg != argNULL)
898 			fprintf(file, "(");
899 		fprintf(file, "!(In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
900 		fprintf(file, "\t    (In0P->msgh_body.msgh_descriptor_count != %d) ||\n", rt->rtRequestKPDs);
901 		if (rt->rtNumRequestVar > 0) {
902 			fprintf(file, "\t    (msgh_size < ");
903 			rtMinRequestSize(file, rt, "__Request");
904 			fprintf(file, ") ||  (msgh_size > (mach_msg_size_t)sizeof(__Request))");
905 		}
906 		else
907 			fprintf(file, "\t    (In0P->Head.msgh_size != (mach_msg_size_t)sizeof(__Request))");
908 		if (rt->rtRetCArg == argNULL)
909 			fprintf(file, ")\n");
910 		else {
911 			fprintf(file, ") &&\n");
912 			fprintf(file, "\t    ((In0P->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||\n");
913 			fprintf(file, "\t    In0P->Head.msgh_size != sizeof(mig_reply_error_t) ||\n");
914 			fprintf(file, "\t    ((mig_reply_error_t *)In0P)->RetCode == KERN_SUCCESS))\n");
915 		}
916 	}
917 	fprintf(file, "\t\treturn MIG_BAD_ARGUMENTS;\n");
918 	fprintf(file, "#endif\t/* __MigTypeCheck */\n");
919 	fprintf(file, "\n");
920 }
921 
922 static void
WriteRequestNDRConvertIntRepArgCond(FILE * file,argument_t * arg)923 WriteRequestNDRConvertIntRepArgCond(FILE *file, argument_t *arg)
924 {
925 	routine_t *rt = arg->argRoutine;
926 
927 	fprintf(file, "defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
928 }
929 
930 static void
WriteRequestNDRConvertCharRepArgCond(FILE * file,argument_t * arg)931 WriteRequestNDRConvertCharRepArgCond(FILE *file, argument_t *arg)
932 {
933 	routine_t *rt = arg->argRoutine;
934 
935 	if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
936 		fprintf(file, "defined(__NDR_convert__char_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
937 	else
938 		fprintf(file, "0");
939 }
940 
941 static void
WriteRequestNDRConvertFloatRepArgCond(FILE * file,argument_t * arg)942 WriteRequestNDRConvertFloatRepArgCond(FILE *file, argument_t *arg)
943 {
944 	routine_t *rt = arg->argRoutine;
945 
946 	if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
947 		fprintf(file, "defined(__NDR_convert__float_rep__Request__%s_t__%s__defined)", rt->rtName, arg->argMsgField);
948 	else
949 		fprintf(file, "0");
950 }
951 
952 static void
WriteRequestNDRConvertIntRepArgDecl(FILE * file,argument_t * arg)953 WriteRequestNDRConvertIntRepArgDecl(FILE *file, argument_t *arg)
954 {
955 	WriteNDRConvertArgDecl(file, arg, "int_rep", "Request");
956 }
957 
958 static void
WriteRequestNDRConvertCharRepArgDecl(FILE * file,argument_t * arg)959 WriteRequestNDRConvertCharRepArgDecl(FILE *file, argument_t *arg)
960 {
961 	if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
962 		WriteNDRConvertArgDecl(file, arg, "char_rep", "Request");
963 }
964 
965 static void
WriteRequestNDRConvertFloatRepArgDecl(FILE * file,argument_t * arg)966 WriteRequestNDRConvertFloatRepArgDecl(FILE *file, argument_t *arg)
967 {
968 	if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
969 		WriteNDRConvertArgDecl(file, arg, "float_rep", "Request");
970 }
971 
972 static void
WriteRequestNDRConvertArgUse(FILE * file,argument_t * arg,const char * convert)973 WriteRequestNDRConvertArgUse(FILE *file, argument_t *arg, const char *convert)
974 {
975 	routine_t *rt = arg->argRoutine;
976 	argument_t *count = arg->argCount;
977 	char argname[MAX_STR_LEN];
978 
979 	if ((akIdent(arg->argKind) == akeCount || akIdent(arg->argKind) == akeCountInOut) &&
980 		(arg->argParent && akCheck(arg->argParent->argKind, akbSendNdr)))
981 		return;
982 
983 	if (arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR) {
984 		if (count && !arg->argSameCount && !strcmp(convert, "int_rep")) {
985 			fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, count->argMsgField);
986 			fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, count->argMsgField, count->argRequestPos, count->argMsgField, count->argRequestPos);
987 			fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, count->argMsgField);
988 		}
989 
990 		sprintf(argname, "(%s)(In%dP->%s.address)", FetchServerType(arg->argType), arg->argRequestPos, arg->argMsgField);
991 	}
992 	else {
993 		sprintf(argname, "&In%dP->%s", arg->argRequestPos, arg->argMsgField);
994 	}
995 
996 	fprintf(file, "#if defined(__NDR_convert__%s__Request__%s_t__%s__defined)\n", convert, rt->rtName, arg->argMsgField);
997 	fprintf(file, "\t\t__NDR_convert__%s__Request__%s_t__%s(%s, In0P->NDR.%s", convert, rt->rtName, arg->argMsgField, argname, convert);
998 	if (count)
999 		fprintf(file, ", In%dP->%s", count->argRequestPos, count->argMsgField);
1000 	fprintf(file, ");\n");
1001 	fprintf(file, "#endif\t/* __NDR_convert__%s__Request__%s_t__%s__defined */\n", convert, rt->rtName, arg->argMsgField);
1002 }
1003 
1004 static void
WriteRequestNDRConvertIntRepOneArgUse(FILE * file,argument_t * arg)1005 WriteRequestNDRConvertIntRepOneArgUse(FILE *file, argument_t *arg)
1006 {
1007 	routine_t *rt = arg->argRoutine;
1008 
1009 	fprintf(file, "#if defined(__NDR_convert__int_rep__Request__%s_t__%s__defined)\n", rt->rtName, arg->argMsgField);
1010 	fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep)\n");
1011 	fprintf(file, "\t\t__NDR_convert__int_rep__Request__%s_t__%s(&In%dP->%s, In%dP->NDR.int_rep);\n", rt->rtName, arg->argMsgField, arg->argRequestPos, arg->argMsgField, arg->argRequestPos);
1012 	fprintf(file, "#endif\t/* __NDR_convert__int_rep__Request__%s_t__%s__defined */\n", rt->rtName, arg->argMsgField);
1013 }
1014 
1015 static void
WriteRequestNDRConvertIntRepArgUse(FILE * file,argument_t * arg)1016 WriteRequestNDRConvertIntRepArgUse(FILE *file, argument_t *arg)
1017 {
1018 	WriteRequestNDRConvertArgUse(file, arg, "int_rep");
1019 }
1020 
1021 static void
WriteRequestNDRConvertCharRepArgUse(FILE * file,argument_t * arg)1022 WriteRequestNDRConvertCharRepArgUse(FILE *file, argument_t *arg)
1023 {
1024 	if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
1025 		WriteRequestNDRConvertArgUse(file, arg, "char_rep");
1026 }
1027 
1028 static void
WriteRequestNDRConvertFloatRepArgUse(FILE * file,argument_t * arg)1029 WriteRequestNDRConvertFloatRepArgUse(FILE *file, argument_t *arg)
1030 {
1031 	if (akIdent(arg->argKind) != akeCount && akIdent(arg->argKind) != akeCountInOut)
1032 		WriteRequestNDRConvertArgUse(file, arg, "float_rep");
1033 }
1034 
1035 static void
WriteCalcArgSize(FILE * file,register argument_t * arg)1036 WriteCalcArgSize(FILE *file, register argument_t *arg)
1037 {
1038 	register ipc_type_t *ptype = arg->argType;
1039 
1040 	if (PackMsg == FALSE) {
1041 		fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
1042 		return;
1043 	}
1044 
1045 	if (IS_OPTIONAL_NATIVE(ptype))
1046         fprintf(file, "(In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0)" ,
1047 				arg->argRequestPos, arg->argMsgField, ptype->itServerType);
1048     else
1049     {
1050 		register ipc_type_t *btype = ptype->itElement;
1051 		argument_t *count = arg->argCount;
1052 		int multiplier = btype->itTypeSize;
1053 
1054 		if (btype->itTypeSize % itWordAlign != 0)
1055 			fprintf(file, "_WALIGN_");
1056 		fprintf(file, "(");
1057 
1058 		if (multiplier > 1)
1059 			fprintf(file, "%d * ", multiplier);
1060 		fprintf(file, "In%dP->%s", count->argRequestPos, count->argMsgField);
1061 		fprintf(file, ")");
1062 	}
1063 }
1064 
1065 static void
WriteCheckArgSize(FILE * file,routine_t * rt,argument_t * arg,const char * comparator)1066 WriteCheckArgSize(FILE *file, routine_t *rt, argument_t *arg, const char *comparator)
1067 {
1068 	register ipc_type_t *ptype = arg->argType;
1069 
1070 
1071 	fprintf(file, "\tif (((msgh_size - ");
1072 	rtMinRequestSize(file, rt, "__Request");
1073 	fprintf(file, ") ");
1074 	if (PackMsg == FALSE) {
1075 		fprintf(file, "%s %d)", comparator, ptype->itTypeSize + ptype->itPadSize);
1076 	} else if (IS_OPTIONAL_NATIVE(ptype)) {
1077 		fprintf(file, "%s (In%dP->__Present__%s ? _WALIGNSZ_(%s) : 0))" , comparator, arg->argRequestPos, arg->argMsgField, ptype->itServerType);
1078 	} else {
1079 		register ipc_type_t *btype = ptype->itElement;
1080 		argument_t *count = arg->argCount;
1081 		int multiplier = btype->itTypeSize;
1082 
1083 		if (multiplier > 1)
1084 			fprintf(file, "/ %d ", multiplier);
1085 		fprintf(file, "< In%dP->%s) ||\n", count->argRequestPos, count->argMsgField);
1086 		fprintf(file, "\t    (msgh_size %s ", comparator);
1087 		rtMinRequestSize(file, rt, "__Request");
1088 		fprintf(file, " + ");
1089 		WriteCalcArgSize(file, arg);
1090 		fprintf(file, ")");
1091 	}
1092 	fprintf(file, ")\n\t\treturn MIG_BAD_ARGUMENTS;\n");
1093 }
1094 
1095 static void
WriteCheckMsgSize(FILE * file,register argument_t * arg)1096 WriteCheckMsgSize(FILE *file, register argument_t *arg)
1097 {
1098 	register routine_t *rt = arg->argRoutine;
1099 
1100 	if (arg->argCount && !arg->argSameCount)
1101 		WriteRequestNDRConvertIntRepOneArgUse(file, arg->argCount);
1102 	if (arg->argRequestPos == rt->rtMaxRequestPos)  {
1103 		fprintf(file, "#if\t__MigTypeCheck\n");
1104 
1105 		/* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */
1106 		fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber);
1107 		fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file);
1108 		/* ...end... */
1109 
1110 		WriteCheckArgSize(file, rt, arg, "!=");
1111 
1112 		fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1113 	}
1114 	else {
1115 		/* If there aren't any more variable-sized arguments after this,
1116 		   then we must check for exact msg-size and we don't need to
1117 		   update msgh_size. */
1118 
1119 		boolean_t LastVarArg = arg->argRequestPos+1 == rt->rtNumRequestVar;
1120 
1121 		/* calculate the actual size in bytes of the data field.  note
1122 		   that this quantity must be a multiple of four.  hence, if
1123 		   the base type size isn't a multiple of four, we have to
1124 		   round up.  note also that btype->itNumber must
1125 		   divide btype->itTypeSize (see itCalculateSizeInfo). */
1126 
1127 		fprintf(file, "\tmsgh_size_delta = ");
1128 		WriteCalcArgSize(file, arg);
1129 		fprintf(file, ";\n");
1130 		fprintf(file, "#if\t__MigTypeCheck\n");
1131 
1132 		/* verify that the user-code-provided count does not exceed the maximum count allowed by the type. */
1133 		fprintf(file, "\t" "if ( In%dP->%s > %d )\n", arg->argCount->argRequestPos, arg->argCount->argMsgField, arg->argType->itNumber);
1134 		fputs("\t\t" "return MIG_BAD_ARGUMENTS;\n", file);
1135 		/* ...end... */
1136 
1137 		/* Don't decrement msgh_size until we've checked that
1138 		   it won't underflow. */
1139 		WriteCheckArgSize(file, rt, arg, LastVarArg ? "!=" : "<");
1140 
1141 		if (!LastVarArg)
1142 			fprintf(file, "\tmsgh_size -= msgh_size_delta;\n");
1143 
1144 		fprintf(file, "#endif\t/* __MigTypeCheck */\n");
1145 	}
1146 	fprintf(file, "\n");
1147 }
1148 
1149 static char *
InArgMsgField(register argument_t * arg,const char * str)1150 InArgMsgField(register argument_t *arg,  const char *str)
1151 {
1152 	static char buffer[MAX_STR_LEN];
1153 	char who[20] = {0};
1154 
1155 	/*
1156 	 * Inside the kernel, the request and reply port fields
1157 	 * really hold ipc_port_t values, not mach_port_t values.
1158 	 * Hence we must cast the values.
1159 	 */
1160 
1161 	if (!(arg->argFlags & flRetCode)) {
1162 		if (akCheck(arg->argKind, akbServerImplicit))
1163 			sprintf(who, "TrailerP->");
1164 		else
1165 			sprintf(who, "In%dP->", arg->argRequestPos);
1166 	}
1167 
1168 #ifdef MIG_KERNEL_PORT_CONVERSION
1169 	if (IsKernelServer &&
1170 		((akIdent(arg->argKind) == akeRequestPort) ||
1171 		 (akIdent(arg->argKind) == akeReplyPort)))
1172 		sprintf(buffer, "(ipc_port_t) %s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
1173 	else
1174 #endif
1175 		sprintf(buffer, "%s%s%s", who, str, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
1176 
1177 	return buffer;
1178 }
1179 
1180 static void
WriteExtractArgValue(FILE * file,register argument_t * arg)1181 WriteExtractArgValue(FILE *file, register argument_t *arg)
1182 {
1183 	register ipc_type_t *it = arg->argType;
1184 	string_t recast;
1185 
1186 #ifdef MIG_KERNEL_PORT_CONVERSION
1187 	if (IsKernelServer && it->itPortType && streql(it->itServerType, "ipc_port_t")
1188 		&& akIdent(arg->argKind) != akeRequestPort
1189 		&& akIdent(arg->argKind) != akeReplyPort)
1190 		recast = "(mach_port_t)";
1191 	else
1192 #endif
1193 		recast = "";
1194 	if (it->itInTrans != strNULL)
1195 		WriteCopyType(file, it, "%s", "/* %s */ %s(%s%s)", arg->argVarName, it->itInTrans, recast, InArgMsgField(arg, ""));
1196 	else
1197 		WriteCopyType(file, it, "%s", "/* %s */ %s%s", arg->argVarName, recast, InArgMsgField(arg, ""));
1198 
1199 	fprintf(file, "\n");
1200 }
1201 
1202 /*
1203  * argKPD_Extract discipline for Port types.
1204  */
1205 static void
WriteExtractKPD_port(FILE * file,register argument_t * arg)1206 WriteExtractKPD_port(FILE *file,  register argument_t *arg)
1207 {
1208 	register ipc_type_t *it = arg->argType;
1209     const char *recast = "";
1210 
1211 	WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
1212 	/* translation function do not apply to complex types */
1213 #ifdef MIG_KERNEL_PORT_CONVERSION
1214 	if (IsKernelServer)
1215 		recast = "(mach_port_t)";
1216 #endif
1217 	fprintf(file, "\t\t%s[i] = %sptr->name;\n", arg->argVarName, recast);
1218 	fprintf(file, "\t}\n");
1219 }
1220 
1221 /*
1222  * argKPD_Extract discipline for out-of-line types.
1223  */
1224 static void
WriteExtractKPD_ool(FILE * file,register argument_t * arg)1225 WriteExtractKPD_ool(FILE *file, register argument_t *arg)
1226 {
1227 	register ipc_type_t *it = arg->argType;
1228 
1229 	WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
1230 	fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
1231 	fprintf(file, "\t}\n");
1232 }
1233 
1234 /*
1235  * argKPD_Extract discipline for out-of-line Port types.
1236  */
1237 static void
WriteExtractKPD_oolport(FILE * file,register argument_t * arg)1238 WriteExtractKPD_oolport(FILE *file, register argument_t *arg)
1239 {
1240 	register ipc_type_t *it = arg->argType;
1241 
1242 	WriteKPD_Iterator(file, TRUE, it->itVarArray, arg, FALSE);
1243 	fprintf(file, "\t\t%s[i] = ptr->address;\n", arg->argVarName);
1244 	fprintf(file, "\t}\n");
1245 	if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbSendRcv)) {
1246 		register argument_t *poly = arg->argPoly;
1247         register const char *pref = poly->argByReferenceServer ? "*" : "";
1248 
1249         fprintf(file, "\t%s%s = In%dP->%s[0].disposition;\n",
1250 				pref, poly->argVarName, arg->argRequestPos, arg->argMsgField);
1251 	}
1252 }
1253 
1254 static void
WriteInitializeCount(FILE * file,register argument_t * arg)1255 WriteInitializeCount(FILE *file, register argument_t *arg)
1256 {
1257 	register ipc_type_t *ptype = arg->argParent->argType;
1258 	register ipc_type_t *btype = ptype->itElement;
1259 	identifier_t newstr;
1260 
1261 	/*
1262 	 * Initialize 'count' argument for variable-length inline OUT parameter
1263 	 * with maximum allowed number of elements.
1264 	 */
1265 
1266 	if (akCheck(arg->argKind, akbVarNeeded))
1267 		newstr = arg->argMsgField;
1268 	else
1269 		newstr = (identifier_t)strconcat("OutP->", arg->argMsgField);
1270 
1271 	fprintf(file, "\t%s = ", newstr);
1272 	if (IS_MULTIPLE_KPD(ptype))
1273 		fprintf(file, "%d;\n", ptype->itKPD_Number);
1274 	else
1275 		fprintf(file, "%d;\n", btype->itNumber? ptype->itNumber/btype->itNumber : 0);
1276 
1277 	/*
1278 	 * If the user passed in a count, then we use the minimum.
1279 	 * We can't let the user completely override our maximum,
1280 	 * or the user might convince the server to overwrite the buffer.
1281 	 */
1282 
1283 	if (arg->argCInOut != argNULL) {
1284 		const char *msgfield = InArgMsgField(arg->argCInOut, "");
1285 
1286 		fprintf(file, "\tif (%s < %s)\n", msgfield, newstr);
1287 		fprintf(file, "\t\t%s = %s;\n", newstr, msgfield);
1288 	}
1289 
1290 	fprintf(file, "\n");
1291 }
1292 
1293 static void
WriteAdjustRequestMsgPtr(FILE * file,register argument_t * arg)1294 WriteAdjustRequestMsgPtr(FILE *file, register argument_t *arg)
1295 {
1296 	register ipc_type_t *ptype = arg->argType;
1297 
1298 	if (PackMsg == FALSE) {
1299 		fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP);\n\n", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos);
1300 		return;
1301 	}
1302 
1303 	fprintf(file, "\t*In%dPP = In%dP = (__Request *) ((pointer_t) In%dP + msgh_size_delta - ", arg->argRequestPos+1, arg->argRequestPos+1, arg->argRequestPos);
1304 	if (IS_OPTIONAL_NATIVE(ptype))
1305 		fprintf(file, "_WALIGNSZ_(%s)", ptype->itUserType);
1306 	else
1307 		fprintf(file, "%d", ptype->itTypeSize + ptype->itPadSize);
1308 	fprintf(file, ");\n\n");
1309 }
1310 
1311 static void
WriteCheckRequestTrailerArgs(FILE * file,routine_t * rt)1312 WriteCheckRequestTrailerArgs(FILE *file, routine_t *rt)
1313 {
1314 	register argument_t *arg;
1315 
1316 	if (rt->rtServerImpl)
1317 		WriteCheckTrailerHead(file, rt, FALSE);
1318 
1319 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
1320 		if (akCheck(arg->argKind, akbServerImplicit))
1321 			WriteCheckTrailerSize(file, FALSE, arg);
1322 	}
1323 }
1324 
1325 static void
WriteExtractArg(FILE * file,register argument_t * arg)1326 WriteExtractArg(FILE *file, register argument_t *arg)
1327 {
1328 	if (akCheckAll(arg->argKind, akbSendRcv|akbVarNeeded)) {
1329 		if (akCheck(arg->argKind, akbSendKPD))
1330 			(*arg->argKPD_Extract)(file, arg);
1331 		else
1332 			WriteExtractArgValue(file, arg);
1333 	}
1334 
1335 	if ((akIdent(arg->argKind) == akeCount) &&
1336 		akCheck(arg->argKind, akbReturnSnd)) {
1337 
1338 		register ipc_type_t *ptype = arg->argParent->argType;
1339 		/*
1340 		 * the count will be initialized to 0 in the case of
1341 		 * unbounded arrays (MigInLine = TRUE): this is because
1342 		 * the old interface used to pass to the target procedure
1343 		 * the maximum in-line size (it was 2048 bytes)
1344 		 */
1345 		if (IS_VARIABLE_SIZED_UNTYPED(ptype) ||
1346 			IS_MIG_INLINE_EMUL(ptype) ||
1347 			(IS_MULTIPLE_KPD(ptype) && ptype->itVarArray))
1348 			WriteInitializeCount(file, arg);
1349 	}
1350 }
1351 
1352 static void
WriteServerCallArg(FILE * file,register argument_t * arg)1353 WriteServerCallArg(FILE *file, register argument_t *arg)
1354 {
1355 	ipc_type_t *it = arg->argType;
1356 	boolean_t NeedClose = FALSE;
1357 	string_t  at = (arg->argByReferenceServer ||
1358 					it->itNativePointer) ? "&" : "";
1359 	string_t  star = (arg->argByReferenceServer) ? " *" : "";
1360 	string_t  msgfield =
1361 		(arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField;
1362 
1363 	if (BeVerbose)
1364 		fprintf(file, "\n/* begin WriteServerCallArg */\n");
1365 	if ((it->itInTrans != strNULL) &&
1366 		akCheck(arg->argKind, akbSendRcv) &&
1367 		!akCheck(arg->argKind, akbVarNeeded)) {
1368 		fprintf(file, "%s%s(", at, it->itInTrans);
1369 		NeedClose = TRUE;
1370 	}
1371 
1372 	if (akCheckAll(arg->argKind, akbVarNeeded|akbServerArg)) {
1373 		fprintf(file, "%s%s", at, arg->argVarName);
1374 	} else if (akCheckAll(arg->argKind, akbSendRcv|akbSendKPD)) {
1375 		if (!it->itInLine)
1376 			/* recast the void *, although it is not necessary */
1377 			fprintf(file, "(%s%s)%s(%s)", it->itTransType, star, at, InArgMsgField(arg, ""));
1378 		else
1379 #ifdef MIG_KERNEL_PORT_CONVERSION
1380 			if (IsKernelServer && streql(it->itServerType, "ipc_port_t"))
1381 				/* recast the port to the kernel internal form value */
1382 				fprintf(file, "(ipc_port_t%s)%s(%s)", star, at, InArgMsgField(arg, ""));
1383 			else
1384 #endif
1385 			{
1386 				fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
1387 			}
1388 	}
1389 	else if (akCheck(arg->argKind, akbSendRcv)) {
1390 		if (IS_OPTIONAL_NATIVE(it)) {
1391 			fprintf(file, "(%s ? ", InArgMsgField(arg, "__Present__"));
1392 			fprintf(file, "%s%s.__Real__%s : %s)", at, InArgMsgField(arg, ""), arg->argMsgField, it->itBadValue);
1393 		}
1394 		else {
1395 			fprintf(file, "%s%s", at, InArgMsgField(arg, ""));
1396 		}
1397 	}
1398 	else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD)) {
1399 		if (!it->itInLine)
1400 			/* recast the void *, although it is not necessary */
1401 			fprintf(file, "(%s%s)%s(OutP->%s)", it->itTransType, star, at, msgfield);
1402 		else
1403 #ifdef MIG_KERNEL_PORT_CONVERSION
1404 			if (IsKernelServer && streql(it->itServerType, "ipc_port_t"))
1405 				/* recast the port to the kernel internal form value */
1406 				fprintf(file, "(mach_port_t%s)%s(OutP->%s)", star, at, msgfield);
1407 			else
1408 #endif
1409 				fprintf(file, "%sOutP->%s", at, msgfield);
1410 
1411 	}
1412 	else  if (akCheck(arg->argKind, akbReturnSnd))
1413 		fprintf(file, "%sOutP->%s", at, msgfield);
1414 
1415 	if (NeedClose)
1416 		fprintf(file, ")");
1417 	if (BeVerbose)
1418 		fprintf(file, "\n/* end WriteServerCallArg */\n");
1419 }
1420 
1421 /*
1422  * Shrunk version of WriteServerCallArg, to implement the RetCode functionality:
1423  * we have received a mig_reply_error_t, therefore we want to call the target
1424  * routine with all 0s except for the error code (and the implicit data).
1425  * We know that we are a SimpleRoutine.
1426  */
1427 static void
WriteConditionalCallArg(FILE * file,register argument_t * arg)1428 WriteConditionalCallArg(FILE *file, register argument_t *arg)
1429 {
1430 	ipc_type_t *it = arg->argType;
1431 	boolean_t NeedClose = FALSE;
1432 
1433 	if (BeVerbose)
1434 		fprintf(file, "/* begin WriteConditionalCallArg */\n");
1435 	if ((it->itInTrans != strNULL) &&
1436 		akCheck(arg->argKind, akbSendRcv) &&
1437 		!akCheck(arg->argKind, akbVarNeeded))
1438     {
1439 		fprintf(file, "%s(", it->itInTrans);
1440 		NeedClose = TRUE;
1441 	}
1442 
1443 	if (akCheck(arg->argKind, akbSendRcv)) {
1444 		if (akIdent(arg->argKind) == akeRequestPort ||
1445 			akCheck(arg->argKind, akbServerImplicit))
1446 			fprintf(file, "%s", InArgMsgField(arg, ""));
1447 		else if (akIdent(arg->argKind) == akeRetCode)
1448 			fprintf(file, "((mig_reply_error_t *)In0P)->RetCode");
1449 		else
1450 			fprintf(file, "(%s)(0)", it->itTransType);
1451 	}
1452 
1453 	if (NeedClose)
1454 		fprintf(file, ")");
1455 	if (BeVerbose)
1456 		fprintf(file, "/* end WriteConditionalCallArg */\n");
1457 }
1458 
1459 static void
WriteDestroyArg(FILE * file,register argument_t * arg)1460 WriteDestroyArg(FILE *file, register argument_t *arg)
1461 {
1462 	register ipc_type_t *it = arg->argType;
1463 
1464 	/*
1465 	 * Deallocate IN/INOUT out-of-line args if specified by "auto" flag.
1466 	 *
1467 	 * We also have to deallocate in the cases where the target routine
1468 	 * is given a itInLine semantic whereas the underlying transmission
1469 	 * was out-of-line
1470 	 */
1471 	if ((argIsIn(arg) && akCheck(arg->argKind, akbSendKPD|akbReturnKPD) &&
1472 		 arg->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR &&
1473 		 (arg->argFlags & flAuto))
1474 		||
1475 		IS_MIG_INLINE_EMUL(it)
1476 		) {
1477 		/*
1478 		 * Deallocate only if out-of-line.
1479 		 */
1480 		argument_t *count = arg->argCount;
1481 		ipc_type_t *btype = it->itElement;
1482 		int multiplier = btype->itNumber ? btype->itSize / (8 * btype->itNumber) : 0;
1483 
1484 		if (IsKernelServer) {
1485 			fprintf(file, "#if __MigKernelSpecificCode\n");
1486 			fprintf(file, "\tvm_map_copy_discard(%s);\n", InArgMsgField(arg, ""));
1487 			fprintf(file, "#else\n");
1488 		}
1489 		fprintf(file, "\tmig_deallocate((vm_offset_t) %s, ", InArgMsgField(arg, ""));
1490 		if (it->itVarArray) {
1491 			if (multiplier > 1)
1492 				fprintf(file, "%d * ", multiplier);
1493 			fprintf(file, "%s);\n", InArgMsgField(count, ""));
1494 	    } else
1495 			fprintf(file, "%d);\n", (it->itNumber * it->itSize + 7) / 8);
1496 		if (IsKernelServer) {
1497 			fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1498 		}
1499 		fprintf(file, "\t%s = (void *) 0;\n", InArgMsgField(arg, ""));
1500 		fprintf(file, "\tIn%dP->%s.%s = (mach_msg_size_t) 0;\n", arg->argRequestPos, arg->argMsgField, (RPCPortArray(arg) ? "count" : "size"));
1501 	}
1502 	else {
1503 		if (akCheck(arg->argKind, akbVarNeeded))
1504 			fprintf(file, "\t%s(%s);\n", it->itDestructor, arg->argVarName);
1505 		else
1506 			fprintf(file, "\t%s(%s);\n", it->itDestructor, InArgMsgField(arg, ""));
1507 	}
1508 }
1509 
1510 static void
WriteDestroyPortArg(FILE * file,register argument_t * arg)1511 WriteDestroyPortArg(FILE *file, register argument_t *arg)
1512 {
1513 	register ipc_type_t *it = arg->argType;
1514 
1515 	/*
1516 	 * If a translated port argument occurs in the body of a request
1517 	 * message, and the message is successfully processed, then the
1518 	 * port right should be deallocated.  However, the called function
1519 	 * didn't see the port right; it saw the translation.  So we have
1520 	 * to release the port right for it.
1521 	 *
1522 	 *  The test over it->itInTrans will exclude any complex type
1523 	 *  made out of ports
1524 	 */
1525 	if ((it->itInTrans != strNULL) &&
1526 		(it->itOutName == MACH_MSG_TYPE_PORT_SEND)) {
1527 		fprintf(file, "\n");
1528 		fprintf(file, "\tif (IP_VALID((ipc_port_t)%s))\n", InArgMsgField(arg, ""));
1529 		fprintf(file, "\t\tipc_port_release_send((ipc_port_t)%s);\n", InArgMsgField(arg, ""));
1530 	}
1531 }
1532 
1533 /*
1534  * Check whether WriteDestroyPortArg would generate any code for arg.
1535  */
1536 static boolean_t
CheckDestroyPortArg(argument_t * arg)1537 CheckDestroyPortArg(argument_t *arg)
1538 {
1539 	register ipc_type_t *it = arg->argType;
1540 
1541 	if ((it->itInTrans != strNULL) &&
1542 		(it->itOutName == MACH_MSG_TYPE_PORT_SEND))
1543     {
1544 		return TRUE;
1545 	}
1546 	return FALSE;
1547 }
1548 
1549 static void
WriteServerCall(FILE * file,routine_t * rt,void (* func)())1550 WriteServerCall(FILE *file, routine_t *rt,  void (*func)())
1551 {
1552 	argument_t *arg = rt->rtRetCode;
1553 	ipc_type_t *it = arg->argType;
1554 	boolean_t NeedClose = FALSE;
1555 
1556 	fprintf(file, "\t");
1557 	if (akCheck(arg->argKind, akbVarNeeded))
1558 		fprintf(file, "%s = ", arg->argMsgField);
1559 	else
1560 		fprintf(file, "OutP->%s = ", arg->argMsgField);
1561 	if (it->itOutTrans != strNULL) {
1562 		fprintf(file, "%s(", it->itOutTrans);
1563 		NeedClose = TRUE;
1564 	}
1565 	fprintf(file, "%s(", rt->rtServerName);
1566 	if (BeVerbose)
1567 		fprintf(file, "\n/* before WriteServerCall's WriteList func=%p mask=%x */\n", func, akbServerArg);
1568 	WriteList(file, rt->rtArgs, func, akbServerArg, ", ", "");
1569 	if (BeVerbose)
1570 		fprintf(file, "\n/* after WriteServerCall's WriteList */\n");
1571 	if (NeedClose)
1572 		fprintf(file, ")");
1573 	fprintf(file, ");\n");
1574 }
1575 
1576 static void
WriteCheckReturnValue(FILE * file,register routine_t * rt)1577 WriteCheckReturnValue(FILE *file, register routine_t *rt)
1578 {
1579 	argument_t *arg = rt->rtRetCode;
1580 	char string[MAX_STR_LEN];
1581 
1582 	if (akCheck(arg->argKind, akbVarNeeded))
1583 		sprintf(string, "%s", arg->argMsgField);
1584 	else
1585 		sprintf(string, "OutP->%s", arg->argMsgField);
1586 	fprintf(file, "\tif (%s != KERN_SUCCESS) {\n", string);
1587 	fprintf(file, "\t\tMIG_RETURN_ERROR(OutP, %s);\n", string);
1588 	fprintf(file, "\t}\n");
1589 }
1590 
1591 /*
1592  * WriteInitKPD_port, WriteInitKPD_ool, WriteInitKPD_oolport
1593  * initializes the OutP KPD fields (this job cannot be done once
1594  * the target routine has been called, otherwise informations
1595  * would be lost)
1596  */
1597 /*
1598  * argKPD_Init discipline for Port types.
1599  */
1600 static void
WriteInitKPD_port(FILE * file,register argument_t * arg)1601 WriteInitKPD_port(FILE *file, register argument_t *arg)
1602 {
1603 	register ipc_type_t *it = arg->argType;
1604     const char *subindex = "";
1605 	boolean_t close = FALSE;
1606 	char firststring[MAX_STR_LEN];
1607 	char string[MAX_STR_LEN];
1608 
1609 	if (IS_MULTIPLE_KPD(it)) {
1610 		WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
1611 		(void)sprintf(firststring, "\t*ptr");
1612 		(void)sprintf(string, "\tptr->");
1613 		subindex = "[i]";
1614 		close = TRUE;
1615     } else {
1616 		(void)sprintf(firststring, "OutP->%s", arg->argMsgField);
1617 		(void)sprintf(string, "OutP->%s.", arg->argMsgField);
1618 	}
1619 
1620 	fprintf(file, "#if\tUseStaticTemplates\n");
1621 	fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1622 	fprintf(file, "#else\t/* UseStaticTemplates */\n");
1623 	if (IS_MULTIPLE_KPD(it) && it->itVarArray)
1624 		fprintf(file, "\t%sname = MACH_PORT_NULL;\n", string);
1625 	if (arg->argPoly == argNULL) {
1626 		if (IsKernelServer) {
1627 			fprintf(file, "#if __MigKernelSpecificCode\n");
1628 			fprintf(file, "\t%sdisposition = %s;\n", string, it->itOutNameStr);
1629 			fprintf(file, "#else\n");
1630 		}
1631 		fprintf(file, "\t%sdisposition = %s;\n", string, it->itInNameStr);
1632 		if (IsKernelServer)
1633 			fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1634 	}
1635 	fprintf(file, "\t%stype = MACH_MSG_PORT_DESCRIPTOR;\n", string);
1636 	fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1637 	if (close)
1638 		fprintf(file, "\t    }\n\t}\n");
1639 	fprintf(file, "\n");
1640 }
1641 
1642 /*
1643  * argKPD_Init discipline for out-of-line types.
1644  */
1645 static void
WriteInitKPD_ool(FILE * file,register argument_t * arg)1646 WriteInitKPD_ool(FILE *file, register argument_t *arg)
1647 {
1648 	register ipc_type_t *it = arg->argType;
1649 	char firststring[MAX_STR_LEN];
1650 	char string[MAX_STR_LEN];
1651 	boolean_t VarArray;
1652 	u_int howmany, howbig;
1653 
1654 	if (IS_MULTIPLE_KPD(it)) {
1655 		WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
1656 		(void)sprintf(firststring, "\t*ptr");
1657 		(void)sprintf(string, "\tptr->");
1658 		VarArray = it->itElement->itVarArray;
1659 		howmany = it->itElement->itNumber;
1660 		howbig = it->itElement->itSize;
1661     } else {
1662 		(void)sprintf(firststring, "OutP->%s", arg->argMsgField);
1663 		(void)sprintf(string, "OutP->%s.", arg->argMsgField);
1664 		VarArray = it->itVarArray;
1665 		howmany = it->itNumber;
1666 		howbig = it->itSize;
1667 	}
1668 
1669 	fprintf(file, "#if\tUseStaticTemplates\n");
1670 	fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1671 	fprintf(file, "#else\t/* UseStaticTemplates */\n");
1672 	if (!VarArray)
1673         fprintf(file, "\t%ssize = %d;\n", string,
1674 				(howmany * howbig + 7)/8);
1675 	if (arg->argDeallocate != d_MAYBE)
1676 		fprintf(file, "\t%sdeallocate =  %s;\n", string,
1677 				(arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
1678     fprintf(file, "\t%scopy = %s;\n", string,
1679 			(arg->argFlags & flPhysicalCopy) ? "MACH_MSG_PHYSICAL_COPY" : "MACH_MSG_VIRTUAL_COPY");
1680 #ifdef ALIGNMENT
1681     fprintf(file, "\t%salignment = MACH_MSG_ALIGN_%d;\n", string, arg->argMsgField,
1682 			(howbig < 8) ? 1 : howbig / 8);
1683 #endif
1684 	fprintf(file, "\t%stype = MACH_MSG_OOL_DESCRIPTOR;\n", string);
1685 	fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1686 
1687 	if (IS_MULTIPLE_KPD(it))
1688 		fprintf(file, "\t    }\n\t}\n");
1689 	fprintf(file, "\n");
1690 }
1691 
1692 /*
1693  * argKPD_Init discipline for out-of-line Port types.
1694  */
1695 static void
WriteInitKPD_oolport(FILE * file,register argument_t * arg)1696 WriteInitKPD_oolport(FILE *file, register argument_t *arg)
1697 {
1698 	register ipc_type_t *it = arg->argType;
1699 	boolean_t VarArray;
1700 	ipc_type_t *howit;
1701 	u_int howmany;
1702 	char firststring[MAX_STR_LEN];
1703 	char string[MAX_STR_LEN];
1704 
1705 	if (IS_MULTIPLE_KPD(it)) {
1706 		WriteKPD_Iterator(file, FALSE, FALSE, arg, TRUE);
1707 		(void)sprintf(firststring, "\t*ptr");
1708 		(void)sprintf(string, "\tptr->");
1709 		VarArray = it->itElement->itVarArray;
1710 		howmany = it->itElement->itNumber;
1711 		howit = it->itElement;
1712     } else {
1713 		(void)sprintf(firststring, "OutP->%s", arg->argMsgField);
1714 		(void)sprintf(string, "OutP->%s.", arg->argMsgField);
1715 		VarArray = it->itVarArray;
1716 		howmany = it->itNumber;
1717 		howit = it;
1718 	}
1719 
1720 	fprintf(file, "#if\tUseStaticTemplates\n");
1721 	fprintf(file, "\t%s = %s;\n", firststring, arg->argTTName);
1722 	fprintf(file, "#else\t/* UseStaticTemplates */\n");
1723 
1724 	if (!VarArray)
1725 		fprintf(file, "\t%scount = %d;\n", string, howmany);
1726 	if (arg->argPoly == argNULL) {
1727 		if (IsKernelServer) {
1728 			fprintf(file, "#if\t__MigKernelSpecificCode\n");
1729 			fprintf(file, "\t%sdisposition = %s;\n", string, howit->itOutNameStr);
1730 			fprintf(file, "#else\n");
1731 		}
1732 		fprintf(file, "\t%sdisposition = %s;\n", string, howit->itInNameStr);
1733 		if (IsKernelServer)
1734 			fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1735 	}
1736 	if (arg->argDeallocate != d_MAYBE)
1737         fprintf(file, "\t%sdeallocate =  %s;\n", string,
1738 				(arg->argDeallocate == d_YES) ? "TRUE" : "FALSE");
1739 	fprintf(file, "\t%stype = MACH_MSG_OOL_PORTS_DESCRIPTOR;\n", string);
1740 	fprintf(file, "#endif\t/* UseStaticTemplates */\n");
1741 
1742 	if (IS_MULTIPLE_KPD(it))
1743 		fprintf(file, "\t    }\n\t}\n");
1744 	fprintf(file, "\n");
1745 }
1746 
1747 static void
WriteInitKPDValue(FILE * file,register argument_t * arg)1748 WriteInitKPDValue(FILE *file, register argument_t *arg)
1749 {
1750 	(*arg->argKPD_Init)(file, arg);
1751 }
1752 
1753 static void
WriteAdjustMsgCircular(FILE * file,register argument_t * arg)1754 WriteAdjustMsgCircular(FILE *file, register argument_t *arg)
1755 {
1756 	fprintf(file, "\n");
1757 
1758 	fprintf(file,"#if\t__MigKernelSpecificCode\n");
1759 	if (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)
1760 		fprintf(file, "\tif (%s == MACH_MSG_TYPE_PORT_RECEIVE)\n",
1761 				arg->argPoly->argVarName);
1762 
1763 	/*
1764 	 * The carried port right can be accessed in OutP->XXXX.  Normally
1765 	 * the server function stuffs it directly there.  If it is InOut,
1766 	 * then it has already been copied into the reply message.
1767 	 * If the server function deposited it into a variable (perhaps
1768 	 * because the reply message is variable-sized) then it has already
1769 	 * been copied into the reply message.
1770 	 *
1771 	 *  The old MiG does not check for circularity in the case of
1772 	 *  array of ports. So do I ...
1773 	 */
1774 
1775 	fprintf(file, "\t  if (IP_VALID((ipc_port_t) In0P->Head.msgh_reply_port) &&\n");
1776 	fprintf(file, "\t    IP_VALID((ipc_port_t) OutP->%s.name) &&\n", arg->argMsgField);
1777 	fprintf(file, "\t    ipc_port_check_circularity((ipc_port_t) OutP->%s.name, (ipc_port_t) In0P->Head.msgh_reply_port))\n", arg->argMsgField);
1778 	fprintf(file, "\t\tOutP->Head.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;\n");
1779 	fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
1780 }
1781 
1782 /*
1783  * argKPD_Pack discipline for Port types.
1784  */
1785 static void
WriteKPD_port(FILE * file,register argument_t * arg)1786 WriteKPD_port(FILE *file, register argument_t *arg)
1787 {
1788 	register ipc_type_t *it = arg->argType;
1789     const char *subindex = "";
1790     const char *recast = "";
1791 	boolean_t close = FALSE;
1792 	char string[MAX_STR_LEN];
1793 	ipc_type_t *real_it;
1794 
1795 	if (akCheck(arg->argKind, akbVarNeeded)) {
1796 		if (IS_MULTIPLE_KPD(it)) {
1797 			WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
1798 			(void)sprintf(string, "\tptr->");
1799 			subindex = "[i]";
1800 			close = TRUE;
1801 			real_it = it->itElement;
1802 		} else {
1803 			(void)sprintf(string, "OutP->%s.", arg->argMsgField);
1804 			real_it = it;
1805 		}
1806 #ifdef MIG_KERNEL_PORT_CONVERSIONS
1807 		if (IsKernelServer && streql(real_it->itTransType, "ipc_port_t"))
1808 			recast = "(mach_port_t)";
1809 #endif
1810 
1811 		if (it->itOutTrans != strNULL && !close)
1812 			fprintf(file, "\t%sname = (mach_port_t)%s(%s);\n", string, it->itOutTrans, arg->argVarName);
1813 		else
1814 			fprintf(file, "\t%sname = %s%s%s;\n", string, recast, arg->argVarName, subindex);
1815 		if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd)) {
1816 			register argument_t *poly = arg->argPoly;
1817 
1818 			if  (akCheck(arg->argPoly->argKind, akbVarNeeded))
1819 				fprintf(file, "\t%sdisposition = %s;\n", string, poly->argVarName);
1820 			else if (close)
1821 				fprintf(file, "\t%sdisposition = OutP->%s;\n", string, poly->argSuffix);
1822 		}
1823 		if (close)
1824 			fprintf(file, "\t    }\n\t}\n");
1825 		fprintf(file, "\n");
1826 	}
1827 	else  if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd|akbVarNeeded))
1828 		fprintf(file, "\tOutP->%s.disposition = %s;\n", arg->argMsgField, arg->argPoly->argVarName);
1829 	/*
1830 	 * If this is a KernelServer, and the reply message contains
1831 	 * a receive right, we must check for the possibility of a
1832 	 * port/message circularity.  If queueing the reply message
1833 	 * would cause a circularity, we mark the reply message
1834 	 * with the circular bit.
1835 	 */
1836 	if (IsKernelServer && !(IS_MULTIPLE_KPD(it)) &&
1837 		((arg->argType->itOutName == MACH_MSG_TYPE_PORT_RECEIVE) ||
1838 		 (arg->argType->itOutName == MACH_MSG_TYPE_POLYMORPHIC)))
1839 		WriteAdjustMsgCircular(file, arg);
1840 }
1841 
1842 /*
1843  * argKPD_Pack discipline for out-of-line types.
1844  */
1845 static void
WriteKPD_ool(FILE * file,register argument_t * arg)1846 WriteKPD_ool(FILE *file, register argument_t *arg)
1847 {
1848 	register ipc_type_t *it = arg->argType;
1849 	char string[MAX_STR_LEN];
1850 	boolean_t VarArray;
1851 	argument_t *count;
1852 	u_int howbig;
1853     const char *subindex;
1854 
1855 	if (IS_MULTIPLE_KPD(it)) {
1856 		WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
1857 		(void)sprintf(string, "\tptr->");
1858 		VarArray = it->itElement->itVarArray;
1859 		count = arg->argSubCount;
1860 		howbig = it->itElement->itSize;
1861 		subindex = "[i]";
1862     } else {
1863 		(void)sprintf(string, "OutP->%s.", arg->argMsgField);
1864 		VarArray = it->itVarArray;
1865 		count = arg->argCount;
1866 		howbig = it->itSize;
1867 		subindex = "";
1868 	}
1869 
1870 	if (akCheck(arg->argKind, akbVarNeeded))
1871 		fprintf(file, "\t%saddress = (void *)%s%s;\n", string,
1872 				arg->argMsgField, subindex);
1873 	if (arg->argDealloc != argNULL)
1874 		if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
1875 			fprintf(file, "\t%sdeallocate = %s;\n", string, arg->argDealloc->argVarName);
1876 	if (VarArray) {
1877 		fprintf(file, "\t%ssize = ", string);
1878 		if (akCheck(count->argKind, akbVarNeeded))
1879 			fprintf(file, "%s%s", count->argName, subindex);
1880 		else
1881 			fprintf(file, "OutP->%s%s", count->argMsgField, subindex);
1882 
1883 		if (count->argMultiplier > 1 || howbig > 8)
1884 			fprintf(file, " * %d;\n", count->argMultiplier * howbig / 8);
1885 		else
1886 			fprintf(file, ";\n");
1887 	}
1888 
1889 	if (IS_MULTIPLE_KPD(it)) {
1890 		fprintf(file, "\t    }\n");
1891 		if (it->itVarArray && !it->itElement->itVarArray) {
1892 			fprintf(file, "\t    for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number);
1893 			/* since subordinate arrays aren't variable, they are initialized from template:
1894 			   here we must no-op 'em */
1895 			fprintf(file, "\t\tptr->size = 0;\n");
1896 		}
1897 		fprintf(file, "\t}\n");
1898 	}
1899 	fprintf(file, "\n");
1900 }
1901 
1902 /*
1903  * argKPD_Pack discipline for out-of-line Port types.
1904  */
1905 static void
WriteKPD_oolport(FILE * file,register argument_t * arg)1906 WriteKPD_oolport(FILE *file, register argument_t *arg)
1907 {
1908 	register ipc_type_t *it = arg->argType;
1909 	boolean_t VarArray;
1910 	argument_t *count;
1911     const char *subindex;
1912 	char string[MAX_STR_LEN];
1913 
1914 	if (IS_MULTIPLE_KPD(it)) {
1915 		WriteKPD_Iterator(file, FALSE, it->itVarArray, arg, TRUE);
1916 		(void)sprintf(string, "\tptr->");
1917 		VarArray = it->itElement->itVarArray;
1918 		count = arg->argSubCount;
1919 		subindex = "[i]";
1920     } else {
1921 		(void)sprintf(string, "OutP->%s.", arg->argMsgField);
1922 		VarArray = it->itVarArray;
1923 		count = arg->argCount;
1924 		subindex = "";
1925 	}
1926 
1927 	if (akCheck(arg->argKind, akbVarNeeded))
1928         fprintf(file, "\t%saddress = (void *)%s%s;\n", string,
1929 				arg->argMsgField, subindex);
1930 	if (arg->argDealloc != argNULL)
1931 		if (akCheck(arg->argDealloc->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
1932             fprintf(file, "\t%sdeallocate = %s;\n", string,
1933 					arg->argDealloc->argVarName);
1934 	if (VarArray) {
1935 		fprintf(file, "\t%scount = ", string);
1936 		if (akCheck(count->argKind, akbVarNeeded))
1937 			fprintf(file, "%s%s;\n", count->argName, subindex);
1938 		else
1939 			fprintf(file, "OutP->%s%s;\n", count->argMsgField, subindex);
1940 	}
1941 	if (arg->argPoly != argNULL && akCheckAll(arg->argPoly->argKind, akbReturnSnd))
1942 		if (akCheck(arg->argPoly->argKind, akbVarNeeded) || IS_MULTIPLE_KPD(it))
1943             fprintf(file, "\t%sdisposition = %s;\n", string,
1944 					arg->argPoly->argVarName);
1945 	if (IS_MULTIPLE_KPD(it)) {
1946 		fprintf(file, "\t    }\n");
1947 		if (it->itVarArray && !it->itElement->itVarArray) {
1948 			fprintf(file, "\t    for (i = j; i < %d; ptr++, i++)\n", it->itKPD_Number);
1949 			/* since subordinate arrays aren't variable, they are initialized from template:
1950 			   here we must no-op 'em */
1951 			fprintf(file, "\t%scount = 0;\n", string);
1952 		}
1953 		fprintf(file, "\t}\n");
1954 	}
1955 	fprintf(file, "\n");
1956 }
1957 
1958 /*
1959  * argKPD_TypeCheck discipline for Port types.
1960  */
1961 static void
WriteTCheckKPD_port(FILE * file,register argument_t * arg)1962 WriteTCheckKPD_port(FILE *file, register argument_t *arg)
1963 {
1964 	register ipc_type_t *it = arg->argType;
1965     const char *tab = "";
1966 	char string[MAX_STR_LEN];
1967 	boolean_t close = FALSE;
1968 
1969 	if (IS_MULTIPLE_KPD(it)) {
1970 		WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
1971 		(void)sprintf(string, "ptr->");
1972 		tab = "\t";
1973 		close = TRUE;
1974     } else
1975 		(void)sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
1976 
1977 	fprintf(file, "\t%sif (%stype != MACH_MSG_PORT_DESCRIPTOR", tab, string);
1978 	/*
1979 	 * We can't check disposition on varArray
1980 	 * (because some of the entries could be empty).
1981 	 */
1982 	if (!it->itVarArray) {
1983 		if (arg->argPoly != argNULL) {
1984 			switch (it->itOutName) {
1985 
1986 			case MACH_MSG_TYPE_MOVE_RECEIVE:
1987 				fprintf(file, " || \n\t%s    %sdisposition != MACH_MSG_TYPE_MOVE_RECEIVE", tab, string);
1988 				break;
1989 
1990 			case MACH_MSG_TYPE_MOVE_SEND_ONCE:
1991 				fprintf(file, " || (\n\t%s    %sdisposition != MACH_MSG_TYPE_MOVE_SEND_ONCE", tab, string);
1992 				fprintf(file, " &&  \n\t%s    %sdisposition != MACH_MSG_TYPE_MAKE_SEND_ONCE)", tab, string);
1993 				break;
1994 
1995 			case MACH_MSG_TYPE_MOVE_SEND:
1996 				fprintf(file, " || (\n\t%s    %sdisposition != MACH_MSG_TYPE_MOVE_SEND", tab, string);
1997 				fprintf(file, " &&  \n\t%s    %sdisposition != MACH_MSG_TYPE_MAKE_SEND", tab, string);
1998 				fprintf(file, " &&  \n\t%s    %sdisposition != MACH_MSG_TYPE_COPY_SEND)", tab, string);
1999 				break;
2000 			}
2001 		}
2002 		else {
2003 			fprintf(file, " ||\n\t%s    %sdisposition != %s", tab, string, it->itOutNameStr);
2004 		}
2005 	}
2006 	fprintf(file, ")\n");
2007 	fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
2008 	if (close)
2009 		fprintf(file, "\t    }\n\t}\n");
2010 }
2011 
2012 /*
2013  * argKPD_TypeCheck discipline for out-of-line types.
2014  */
2015 static void
WriteTCheckKPD_ool(FILE * file,register argument_t * arg)2016 WriteTCheckKPD_ool(FILE *file, register argument_t *arg)
2017 {
2018 	register ipc_type_t *it = arg->argType;
2019     const char *tab;
2020 	char string[MAX_STR_LEN];
2021 	boolean_t test;
2022 	u_int howmany, howbig;
2023 
2024 	if (IS_MULTIPLE_KPD(it)) {
2025 		WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
2026 		tab = "\t\t\t";
2027 		sprintf(string, "ptr->");
2028 		howmany = it->itElement->itNumber;
2029 		howbig = it->itElement->itSize;
2030 		test = !it->itVarArray && !it->itElement->itVarArray;
2031     } else {
2032 		tab = "";
2033 		sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
2034 		howmany = it->itNumber;
2035 		howbig = it->itSize;
2036 		test = !it->itVarArray;
2037 	}
2038 
2039 	fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_DESCRIPTOR", tab, string);
2040     if (test)
2041 		/* if VarArray we may use no-op; if itElement->itVarArray size might change */
2042 		fprintf(file, " ||\n\t%s    %ssize != %d", tab, string,
2043 				(howmany * howbig + 7)/8);
2044 	fprintf(file, ")\n");
2045 	fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
2046 
2047 	if (IS_MULTIPLE_KPD(it))
2048 		fprintf(file, "\t    }\n\t}\n");
2049 }
2050 
2051 /*
2052  * argKPD_TypeCheck discipline for out-of-line Port types.
2053  */
2054 static void
WriteTCheckKPD_oolport(FILE * file,register argument_t * arg)2055 WriteTCheckKPD_oolport(FILE *file, register argument_t *arg)
2056 {
2057 	register ipc_type_t *it = arg->argType;
2058     const char *tab;
2059 	char string[MAX_STR_LEN];
2060 	boolean_t test;
2061 	u_int howmany;
2062     const char *howstr;
2063 
2064 	if (IS_MULTIPLE_KPD(it)) {
2065 		WriteKPD_Iterator(file, TRUE, FALSE, arg, TRUE);
2066 		tab = "\t";
2067 		sprintf(string, "ptr->");
2068 		howmany = it->itElement->itNumber;
2069 		test = !it->itVarArray && !it->itElement->itVarArray;
2070 		howstr = it->itElement->itOutNameStr;
2071     } else {
2072 		tab = "";
2073 		sprintf(string, "In%dP->%s.", arg->argRequestPos, arg->argMsgField);
2074 		howmany = it->itNumber;
2075 		test = !it->itVarArray;
2076 		howstr = it->itOutNameStr;
2077 	}
2078 
2079 	fprintf(file, "\t%sif (%stype != MACH_MSG_OOL_PORTS_DESCRIPTOR", tab, string);
2080 	if (test)
2081 		/* if VarArray we may use no-op; if itElement->itVarArray size might change */
2082         fprintf(file, " ||\n\t%s    %scount != %d", tab, string,
2083 				howmany);
2084 	if (arg->argPoly == argNULL)
2085         fprintf(file, " ||\n\t%s    %sdisposition != %s", tab, string,
2086 				howstr);
2087 	fprintf(file, ")\n");
2088 	fprintf(file, "\t\treturn MIG_TYPE_ERROR;\n");
2089 
2090 	if (IS_MULTIPLE_KPD(it))
2091 		fprintf(file, "\t    }\n\t}\n");
2092 }
2093 
2094 /*************************************************************
2095  *  Writes code to check that the type of each of the arguments
2096  *  in the reply message is what is expected. Called by
2097  *  WriteRoutine for each in && typed argument in the request message.
2098  *************************************************************/
2099 static void
WriteTypeCheck(FILE * file,register argument_t * arg)2100 WriteTypeCheck(FILE *file, register argument_t *arg)
2101 {
2102 	fprintf(file, "#if\t__MigTypeCheck\n");
2103 	(*arg->argKPD_TypeCheck)(file, arg);
2104 	fprintf(file, "#endif\t/* __MigTypeCheck */\n");
2105 }
2106 
2107 static void
WritePackArgValueNormal(FILE * file,register argument_t * arg)2108 WritePackArgValueNormal(FILE *file, register argument_t *arg)
2109 {
2110 	register ipc_type_t *it = arg->argType;
2111 
2112 	if (IS_VARIABLE_SIZED_UNTYPED(it) || it->itNoOptArray) {
2113 		if (it->itString) {
2114 			/*
2115 			 * Copy variable-size C string with mig_strncpy.
2116 			 * Save the string length (+ 1 for trailing 0)
2117 			 * in the argument`s count field.
2118 			 */
2119 			fprintf(file, "\tOutP->%s = mig_strncpy(OutP->%s, %s, %d);\n", arg->argCount->argMsgField, arg->argMsgField, arg->argVarName, it->itNumber);
2120 		}
2121 		else if (it->itNoOptArray)
2122 			fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, %d);\n", arg->argMsgField, arg->argVarName, it->itTypeSize);
2123 		else {
2124 			register argument_t *count = arg->argCount;
2125 			register ipc_type_t *btype = it->itElement;
2126 			identifier_t newstr;
2127 
2128 			/* Note btype->itNumber == count->argMultiplier */
2129 
2130 			fprintf(file, "\t(void)memcpy((char *) OutP->%s, (const char *) %s, ", arg->argMsgField, arg->argVarName);
2131 			if (btype->itTypeSize > 1)
2132 				fprintf(file, "%d * ", btype->itTypeSize);
2133 			/* count is a akbVarNeeded if arg is akbVarNeeded */
2134 			if (akCheck(count->argKind, akbVarNeeded))
2135 				newstr = count->argVarName;
2136 			else
2137 				newstr = (identifier_t)strconcat("OutP->", count->argMsgField);
2138 			fprintf(file, "%s);\n", newstr);
2139 		}
2140 	}
2141 	else if (it->itOutTrans != strNULL)
2142 		WriteCopyType(file, it, "OutP->%s", "/* %s */ %s(%s)", arg->argMsgField, it->itOutTrans, arg->argVarName);
2143 	else
2144 		WriteCopyType(file, it, "OutP->%s", "/* %s */ %s", arg->argMsgField, arg->argVarName);
2145 }
2146 
2147 static void
WritePackArgValueVariable(FILE * file,register argument_t * arg)2148 WritePackArgValueVariable(FILE *file, register argument_t *arg)
2149 {
2150 	register ipc_type_t *it = arg->argType;
2151 
2152 	/*
2153 	 * only itString are treated here so far
2154 	 */
2155 	if (it->itString) {
2156 		/*
2157 		 * Emit logic to call strlen to calculate the size of the argument, and ensure that it fits within the 32-bit result field
2158 		 * in the Reply, when targeting a 64-bit architecture. If a 32-bit architecture is the target, we emit code to just call
2159 		 * strlen() directly (since it'll return a 32-bit value that is guaranteed to fit).
2160 		 */
2161 		fputs("#ifdef __LP64__\n", file);
2162 		fprintf(file, "\t{\n"
2163 				"\t\t" "size_t strLength = strlen(OutP->%s) + 1;\n", arg->argMsgField);
2164 		fputs(        "\t\t" "if (strLength > 0xffffffff)\n"
2165 					  "\t\t\t"  "MIG_RETURN_ERROR(OutP, MIG_BAD_ARGUMENTS);\n", file);
2166 		fprintf(file, "\t\t" "OutP->%s = (mach_msg_type_number_t) strLength;\n"
2167 				"\t}\n", arg->argCount->argMsgField);
2168 		fputs("#else\n", file);
2169 		fprintf(file, "\tOutP->%s = (mach_msg_type_number_t) strlen(OutP->%s) + 1;\n", arg->argCount->argMsgField, arg->argMsgField);
2170 		fputs("#endif /* __LP64__ */\n", file);
2171 
2172 	}
2173 }
2174 
2175 static void
WriteCopyArgValue(FILE * file,argument_t * arg)2176 WriteCopyArgValue(FILE *file, argument_t *arg)
2177 {
2178 	fprintf(file, "\n");
2179 	WriteCopyType(file, arg->argType, "/* %d */ OutP->%s", "In%dP->%s", arg->argRequestPos, (arg->argSuffix != strNULL) ? arg->argSuffix : arg->argMsgField);
2180 }
2181 
2182 static void
WriteInitArgValue(FILE * file,argument_t * arg)2183 WriteInitArgValue(FILE *file, argument_t *arg)
2184 {
2185 	fprintf(file, "\n");
2186 	fprintf(file, "\tOutP->%s = %s;\n\n", arg->argMsgField, arg->argVarName);
2187 }
2188 
2189 /*
2190  * Calculate the size of a variable-length message field.
2191  */
2192 static void
WriteArgSize(FILE * file,register argument_t * arg)2193 WriteArgSize(FILE *file, register argument_t *arg)
2194 {
2195 	register ipc_type_t *ptype = arg->argType;
2196 	register int bsize = ptype->itElement->itTypeSize;
2197 	register argument_t *count = arg->argCount;
2198 
2199 	/* If the base type size of the data field isn`t a multiple of 4,
2200 	   we have to round up. */
2201 	if (bsize % itWordAlign != 0)
2202 		fprintf(file, "_WALIGN_");
2203 
2204 	/* Here, we generate ((value + %d) & ~%d). We have to put two (( at the
2205 	 * the beginning.
2206 	 */
2207 	fprintf(file, "((");
2208 	if (bsize > 1)
2209 		fprintf(file, "%d * ", bsize);
2210 	if (ptype->itString || !akCheck(count->argKind, akbVarNeeded))
2211 		/* get count from descriptor in message */
2212 		fprintf(file, "OutP->%s", count->argMsgField);
2213 	else
2214 		/* get count from argument */
2215 		fprintf(file, "%s", count->argVarName);
2216 
2217 	/*
2218 	 * If the base type size is not a multiple of sizeof(natural_t),
2219 	 * we have to round up.
2220 	 */
2221 	if (bsize % sizeof(natural_t) != 0)
2222 		fprintf(file, " + %ld) & ~%ld)", sizeof(natural_t)-1, sizeof(natural_t)-1);
2223 	else
2224 		fprintf(file, "))");
2225 }
2226 
2227 /*
2228  * Adjust message size and advance reply pointer.
2229  * Called after packing a variable-length argument that
2230  * has more arguments following.
2231  */
2232 static void
WriteAdjustMsgSize(FILE * file,register argument_t * arg)2233 WriteAdjustMsgSize(FILE *file, register argument_t *arg)
2234 {
2235 	register routine_t *rt = arg->argRoutine;
2236 	register ipc_type_t *ptype = arg->argType;
2237 
2238 	/* There are more Out arguments.  We need to adjust msgh_size
2239 	   and advance OutP, so we save the size of the current field
2240 	   in msgh_size_delta. */
2241 
2242 	fprintf(file, "\tmsgh_size_delta = ");
2243 	WriteArgSize(file, arg);
2244 	fprintf(file, ";\n");
2245 
2246 	if (rt->rtNumReplyVar == 1) {
2247 		/* We can still address the message header directly.  Fill
2248 		   in the size field. */
2249 
2250 		fprintf(file, "\tOutP->Head.msgh_size = ");
2251 		rtMinReplySize(file, rt, "Reply");
2252 		fprintf(file, " + msgh_size_delta;\n");
2253     } else if (arg->argReplyPos == 0) {
2254 		/* First variable-length argument.  The previous msgh_size value
2255 		   is the minimum reply size. */
2256 
2257 		fprintf(file, "\tmsgh_size = ");
2258 		rtMinReplySize(file, rt, "Reply");
2259 		fprintf(file, " + msgh_size_delta;\n");
2260     } else
2261 		fprintf(file, "\tmsgh_size += msgh_size_delta;\n");
2262 
2263     fprintf(file,
2264 			"\tOutP = (Reply *) ((pointer_t) OutP + msgh_size_delta - %d);\n",
2265 			ptype->itTypeSize + ptype->itPadSize);
2266 }
2267 
2268 /*
2269  * Calculate the size of the message.  Called after the
2270  * last argument has been packed.
2271  */
2272 static void
WriteFinishMsgSize(FILE * file,register argument_t * arg)2273 WriteFinishMsgSize(FILE *file, register argument_t *arg)
2274 {
2275 	/* No more Out arguments.  If this is the only variable Out
2276 	   argument, we can assign to msgh_size directly. */
2277 
2278 	if (arg->argReplyPos == 0) {
2279 		fprintf(file, "\tOutP->Head.msgh_size = ");
2280 		rtMinReplySize(file, arg->argRoutine, "Reply");
2281 		fprintf(file, " + (");
2282 		WriteArgSize(file, arg);
2283 		fprintf(file, ");\n");
2284 	}
2285 	else {
2286 		fprintf(file, "\tmsgh_size += ");
2287 		WriteArgSize(file, arg);
2288 		fprintf(file, ";\n");
2289 	}
2290 }
2291 
2292 /*
2293  * Handle reply arguments - fill in message types and copy arguments
2294  * that need to be copied.
2295  */
2296 static void
WriteReplyArgs(FILE * file,register routine_t * rt)2297 WriteReplyArgs(FILE *file, register routine_t *rt)
2298 {
2299 	register argument_t *arg;
2300 	register argument_t *lastVarArg;
2301 
2302 	/*
2303 	 * 1. The Kernel Processed Data
2304 	 */
2305 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)
2306 		if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnKPD))
2307 			(*arg->argKPD_Pack)(file, arg);
2308 	/*
2309 	 * 2. The Data Stream
2310 	 */
2311 	lastVarArg = argNULL;
2312 	for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext)  {
2313 		/*
2314 		 * Adjust message size and advance message pointer if
2315 		 * the last request argument was variable-length and the
2316 		 * request position will change.
2317 		 */
2318 		if (lastVarArg != argNULL &&
2319 			lastVarArg->argReplyPos < arg->argReplyPos) {
2320 			WriteAdjustMsgSize(file, lastVarArg);
2321 			lastVarArg = argNULL;
2322 		}
2323 
2324 		if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVarNeeded))
2325 			WritePackArgValueNormal(file, arg);
2326 		else if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable))
2327 			WritePackArgValueVariable(file, arg);
2328 
2329 		if (akCheck(arg->argKind, akbReplyCopy))
2330 			WriteCopyArgValue(file, arg);
2331 		if (akCheck(arg->argKind, akbReplyInit))
2332 			WriteInitArgValue(file, arg);
2333 		/*
2334 		 * Remember whether this was variable-length.
2335 		 */
2336 		if (akCheckAll(arg->argKind, akbReturnSnd|akbReturnBody|akbVariable))
2337 			lastVarArg = arg;
2338 	}
2339 	/*
2340 	 * Finish the message size.
2341 	 */
2342 	if (lastVarArg != argNULL)
2343 		WriteFinishMsgSize(file, lastVarArg);
2344 }
2345 
2346 static void
WriteFieldDecl(FILE * file,argument_t * arg)2347 WriteFieldDecl(FILE *file, argument_t *arg)
2348 {
2349 	if (akCheck(arg->argKind, akbSendKPD) ||
2350 		akCheck(arg->argKind, akbReturnKPD))
2351 		WriteFieldDeclPrim(file, arg, FetchKPDType);
2352 	else
2353 		WriteFieldDeclPrim(file, arg, FetchServerType);
2354 }
2355 
2356 static void
InitKPD_Disciplines(argument_t * args)2357 InitKPD_Disciplines(argument_t *args)
2358 {
2359 	argument_t *arg;
2360 	extern void KPD_noop();
2361 	extern void KPD_error();
2362 	extern void WriteTemplateKPD_port();
2363 	extern void WriteTemplateKPD_ool();
2364 	extern void WriteTemplateKPD_oolport();
2365 
2366 	/*
2367 	 * WriteInitKPD_port, WriteKPD_port,  WriteExtractKPD_port,
2368 	 * WriteInitKPD_ool, WriteKPD_ool,  WriteExtractKPD_ool,
2369 	 * WriteInitKPD_oolport, WriteKPD_oolport,  WriteExtractKPD_oolport
2370 	 * are local to this module (which is the reason why this initialization
2371 	 * takes place here rather than in utils.c).
2372 	 * Common routines for user and server will be established SOON, and
2373 	 * all of them (including the initialization) will be transfert to
2374 	 * utils.c
2375 	 * All the KPD disciplines are defaulted to be KPD_error().
2376 	 * Note that akbSendKPD and akbReturnKPd are not exclusive,
2377 	 * because of inout type of parameters.
2378 	 */
2379 	for (arg = args; arg != argNULL; arg = arg->argNext)
2380 		if (akCheck(arg->argKind, akbSendKPD|akbReturnKPD))
2381 			switch (arg->argKPD_Type) {
2382 
2383 			case MACH_MSG_PORT_DESCRIPTOR:
2384 				if akCheck(arg->argKind, akbSendKPD) {
2385 						arg->argKPD_Extract =
2386 							(IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_port : WriteExtractArgValue;
2387 						arg->argKPD_TypeCheck = WriteTCheckKPD_port;
2388 					}
2389 				if akCheck(arg->argKind, akbReturnKPD) {
2390 						arg->argKPD_Template = WriteTemplateKPD_port;
2391 						arg->argKPD_Init = WriteInitKPD_port;
2392 						arg->argKPD_Pack = WriteKPD_port;
2393 					}
2394 				break;
2395 
2396 			case MACH_MSG_OOL_DESCRIPTOR:
2397 				if akCheck(arg->argKind, akbSendKPD) {
2398 						arg->argKPD_Extract =
2399 							(IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_ool : WriteExtractArgValue;
2400 						arg->argKPD_TypeCheck = WriteTCheckKPD_ool;
2401 					}
2402 				if akCheck(arg->argKind, akbReturnKPD) {
2403 						arg->argKPD_Template = WriteTemplateKPD_ool;
2404 						arg->argKPD_Init = WriteInitKPD_ool;
2405 						arg->argKPD_Pack = WriteKPD_ool;
2406 					}
2407 				break;
2408 
2409 			case MACH_MSG_OOL_PORTS_DESCRIPTOR:
2410 				if akCheck(arg->argKind, akbSendKPD) {
2411 						arg->argKPD_Extract =
2412 							(IS_MULTIPLE_KPD(arg->argType)) ? WriteExtractKPD_oolport : WriteExtractArgValue;
2413 						arg->argKPD_TypeCheck = WriteTCheckKPD_oolport;
2414 					}
2415 				if akCheck(arg->argKind, akbReturnKPD) {
2416 						arg->argKPD_Template = WriteTemplateKPD_oolport;
2417 						arg->argKPD_Init = WriteInitKPD_oolport;
2418 						arg->argKPD_Pack = WriteKPD_oolport;
2419 					}
2420 				break;
2421 
2422 			default:
2423 				printf("MiG internal error: type of kernel processed data unknown\n");
2424 				exit(1);
2425 			}   /* end of switch */
2426 }
2427 
WriteStringTerminatorCheck(FILE * file,routine_t * rt)2428 static void WriteStringTerminatorCheck(FILE *file, routine_t *rt)
2429 {
2430 	// generate code to verify that the length of a C string is not greater than the size of the
2431 	// buffer in which it is stored.
2432 	argument_t  *argPtr;
2433 	int msg_limit_calculated = FALSE;
2434 	int found_string_argument = FALSE;
2435 	int variable_length_args_present = (rt->rtMaxRequestPos > 0);
2436 
2437 	// scan through arguments to see if there are any strings
2438 	for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2439 		if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) {
2440 			found_string_argument = TRUE;
2441 			break;
2442 		}
2443 	}
2444 
2445 	if (found_string_argument) {
2446 		// create a new scope, for local variables
2447 		fputs("#if __MigTypeCheck\n" "\t" "{" "\n", file);
2448 
2449 		for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2450 			if ((argPtr->argKind & akbRequest) && argPtr->argType->itString) {
2451 				//fprintf(stderr, "### found itString: variable name = %s, max length = %d\n", argPtr->argName, argPtr->argType->itNumber);
2452 
2453 				if (!msg_limit_calculated) {
2454 					msg_limit_calculated = TRUE; // only need to do this once
2455 					fputs("\t\t" "char * msg_limit = ((char *) In0P) + In0P->Head.msgh_size;\n", file);
2456 					if (IsKernelServer) {
2457 						fputs("#if __MigKernelSpecificCode\n", file);
2458 						fputs("\t\t" "size_t strnlen_limit;" "\n", file);
2459 						fputs("#else\n", file);
2460 					}
2461 					fputs("\t\t" "size_t memchr_limit;" "\n", file);
2462 					if (IsKernelServer) {
2463 						fputs("#endif /* __MigKernelSpecificCode */" "\n", file);
2464 					}
2465 					fputc('\n', file);
2466 				}
2467 
2468 				// I would really prefer to use strnlen() here, to ensure that the byte scanning logic does not extend beyond
2469 				// the end of the buffer, but it's not necessarily guaranteed to be available. Instead, I'll use memchr(),
2470 				// and let it look for the terminating null byte.
2471 				// (later...)
2472 				// It turns out that the kernel does not have memchr() available, but strnlen() IS available, so we'll just
2473 				// have to emit some conditional code to use the appropriate runtime environment scanning function.
2474 				//
2475 				if (IsKernelServer) {
2476 					fputs("#if __MigKernelSpecificCode\n", file);
2477 					fputs("\t\t" "strnlen_limit = min((msg_limit - ", file);
2478 					// If there are variable-length arguments within the message, the proper (adjusted)
2479 					// pointers must be used to access those strings
2480 					fprintf(file, "In%dP->%s),  %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
2481 					fputs("\t\t" "if (", file);
2482 					fprintf(file, "( strnlen(In%dP->%s, strnlen_limit) >= %d + 1 )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
2483 					fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file);
2484 					fputs("#else\n", file);
2485 				}
2486 				// If there are variable-length arguments within the message, the proper (adjusted)
2487 				// pointers must be used to access those strings
2488 				fprintf(file, "\t\t" "memchr_limit = min((msg_limit - In%dP->%s),  %d);" "\n", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName, argPtr->argType->itNumber);
2489 				fputs("\t\t" "if (", file);
2490 				fprintf(file, "( memchr(In%dP->%s, '\\0', memchr_limit) == NULL )", (variable_length_args_present ? argPtr->argRequestPos : 0), argPtr->argName);
2491 				fputs(")" "\n" "\t\t\t" "return MIG_BAD_ARGUMENTS; // string length exceeds buffer length!" "\n", file);
2492 				if (IsKernelServer) {
2493 					fputs("#endif /* __MigKernelSpecificCode */" "\n", file);
2494 				}
2495 			}
2496 		}
2497 		fputs("\t" "}" "\n" "#endif" "\t" "/* __MigTypeCheck */" "\n\n", file); // terminate new scope
2498 	}
2499 
2500 	return;
2501 }
2502 
2503 static void
WriteOOLSizeCheck(FILE * file,routine_t * rt)2504 WriteOOLSizeCheck(FILE *file, routine_t *rt)
2505 {
2506 	/* Emit code to validate the actual size of ool data vs. the reported size */
2507 
2508 	argument_t  *argPtr;
2509 	boolean_t   openedTypeCheckConditional = FALSE;
2510 
2511 	// scan through arguments to see if there are any ool data blocks
2512 	for (argPtr = rt->rtArgs; argPtr != NULL; argPtr = argPtr->argNext) {
2513 		if (akCheck(argPtr->argKind, akbSendKPD) && (argPtr->argKPD_Type == MACH_MSG_OOL_DESCRIPTOR)) {
2514 			register ipc_type_t *it = argPtr->argType;
2515 			const char *tab;
2516 			char string[MAX_STR_LEN];
2517 			boolean_t test;
2518 			argument_t  *argCountPtr;
2519 
2520 			if ( !openedTypeCheckConditional ) {
2521 				openedTypeCheckConditional = TRUE;
2522 				fputs("#if __MigTypeCheck\n", file);
2523 			}
2524 
2525 			if (IS_MULTIPLE_KPD(it)) {
2526 				WriteKPD_Iterator(file, TRUE, FALSE, argPtr, TRUE);
2527 				tab = "\t\t\t";
2528 				sprintf(string, "ptr->");
2529 				test = !it->itVarArray && !it->itElement->itVarArray;
2530 				it = it->itElement; // point to element descriptor, so size calculation is correct
2531 				argCountPtr = argPtr->argSubCount;
2532 			}
2533 			else {
2534 				tab = "";
2535 				sprintf(string, "In%dP->%s.", argPtr->argRequestPos, argPtr->argMsgField);
2536 				test = !it->itVarArray;
2537 				argCountPtr = argPtr->argCount;
2538 			}
2539 
2540 			if (!test) {
2541 				int multiplier = (argCountPtr->argMultiplier > 1 || it->itSize > 8) ? argCountPtr->argMultiplier * it->itSize / 8 : 1;
2542 				fprintf(file, "\t%s" "if (%ssize ", tab, string);
2543 				if (multiplier > 1)
2544 					fprintf(file, "/ %d ", multiplier);
2545 				fprintf(file,"!= In%dP->%s%s)\n", argCountPtr->argRequestPos, argCountPtr->argVarName, IS_MULTIPLE_KPD(it) ? "[i]" : "");
2546 
2547 				fprintf(file, "\t\t%s" "return MIG_TYPE_ERROR;\n", tab);
2548 			}
2549 
2550 			if (IS_MULTIPLE_KPD(it))
2551 				fprintf(file, "\t    }\n\t}\n");
2552 
2553 		}
2554 	}
2555 
2556 	if ( openedTypeCheckConditional )
2557 		fputs("#endif" "\t" "/* __MigTypeCheck */" "\n\n", file);
2558 }
2559 
2560 
2561 static void
WriteCheckRequest(FILE * file,routine_t * rt)2562 WriteCheckRequest(FILE *file, routine_t *rt)
2563 {
2564 	u_int i;
2565 
2566 	/* initialize the disciplines for the handling of KPDs */
2567 	InitKPD_Disciplines(rt->rtArgs);
2568 
2569 	fprintf(file, "\n");
2570 	fprintf(file, "#if ( __MigTypeCheck ");
2571 	if (CheckNDR)
2572 		fprintf(file, "|| __NDR_convert__ ");
2573 	fprintf(file, ")\n");
2574 	fprintf(file, "#if __MIG_check__Request__%s_subsystem__\n", SubsystemName);
2575 	fprintf(file, "#if !defined(__MIG_check__Request__%s_t__defined)\n", rt->rtName);
2576 	fprintf(file, "#define __MIG_check__Request__%s_t__defined\n", rt->rtName);
2577 	if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) {
2578 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgDecl, akbSendNdr, "", "");
2579 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgDecl, akbSendNdr, "", "");
2580 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgDecl, akbSendNdr, "", "");
2581 	}
2582 	fprintf(file, "\n");
2583 	fprintf(file, "mig_internal kern_return_t __MIG_check__Request__%s_t(__attribute__((__unused__)) __Request__%s_t *In0P", rt->rtName, rt->rtName);
2584 	for (i = 1; i <= rt->rtMaxRequestPos; i++)
2585 		fprintf(file, ", __attribute__((__unused__)) __Request__%s_t **In%dPP", rt->rtName, i);
2586 	fprintf(file, ")\n{\n");
2587 
2588 	fprintf(file, "\n\ttypedef __Request__%s_t __Request;\n", rt->rtName);
2589 	for (i = 1; i <= rt->rtMaxRequestPos; i++)
2590 		fprintf(file, "\t__Request *In%dP;\n", i);
2591 	if (rt->rtNumRequestVar > 0) {
2592 		fprintf(file, "#if\t__MigTypeCheck\n");
2593 		fprintf(file, "\tunsigned int msgh_size;\n");
2594 		fprintf(file, "#endif\t/* __MigTypeCheck */\n");
2595 	}
2596 	if (rt->rtMaxRequestPos > 0)
2597 		fprintf(file, "\tunsigned int msgh_size_delta;\n");
2598 	if (rt->rtNumRequestVar > 0 || rt->rtMaxRequestPos > 0)
2599 		fprintf(file, "\n");
2600 
2601 	WriteCheckHead(file, rt);
2602 
2603 	WriteList(file, rt->rtArgs, WriteTypeCheck, akbSendKPD, "\n", "\n");
2604 
2605 	{
2606 		argument_t *arg, *lastVarArg;
2607 
2608 		lastVarArg = argNULL;
2609 		for (arg = rt->rtArgs; arg != argNULL; arg = arg->argNext) {
2610 			if (lastVarArg != argNULL &&
2611 				lastVarArg->argRequestPos < arg->argRequestPos) {
2612 				WriteAdjustRequestMsgPtr(file, lastVarArg);
2613 				lastVarArg = argNULL;
2614 			}
2615 			if (akCheckAll(arg->argKind, akbSendRcv|akbSendBody)) {
2616 				if (akCheck(arg->argKind, akbVariable)) {
2617 					WriteCheckMsgSize(file, arg);
2618 					lastVarArg = arg;
2619 				}
2620 			}
2621 		}
2622 	}
2623 
2624 	if (CheckNDR && akCheck(rt->rtNdrCode->argKind, akbRequest)) {
2625 		fprintf(file, "#if\t");
2626 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgCond, akbSendNdr, " || \\\n\t", "\n");
2627 		fprintf(file, "\tif (In0P->NDR.int_rep != NDR_record.int_rep) {\n");
2628 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertIntRepArgUse, akbSendNdr, "", "");
2629 		fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__int_rep...) */\n\n");
2630 
2631 		WriteOOLSizeCheck(file, rt);
2632 
2633 		fprintf(file, "#if\t");
2634 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgCond, akbSendNdr, " || \\\n\t", "\n");
2635 		fprintf(file, "\tif (In0P->NDR.char_rep != NDR_record.char_rep) {\n");
2636 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertCharRepArgUse, akbSendNdr, "", "");
2637 		fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__char_rep...) */\n\n");
2638 
2639 		fprintf(file, "#if\t");
2640 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgCond, akbSendNdr, " || \\\n\t", "\n");
2641 		fprintf(file, "\tif (In0P->NDR.float_rep != NDR_record.float_rep) {\n");
2642 		WriteList(file, rt->rtArgs, WriteRequestNDRConvertFloatRepArgUse, akbSendNdr, "", "");
2643 		fprintf(file, "\t}\n#endif\t/* defined(__NDR_convert__float_rep...) */\n\n");
2644 	} else {
2645 		WriteOOLSizeCheck(file, rt);
2646 	}
2647 
2648 	WriteStringTerminatorCheck(file, rt);
2649 
2650 	fprintf(file, "\treturn MACH_MSG_SUCCESS;\n");
2651 	fprintf(file, "}\n");
2652 	fprintf(file, "#endif /* !defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName);
2653 	fprintf(file, "#endif /* __MIG_check__Request__%s_subsystem__ */\n", SubsystemName);
2654 	fprintf(file, "#endif /* ( __MigTypeCheck ");
2655 	if (CheckNDR)
2656 		fprintf(file, "|| __NDR_convert__ ");
2657 	fprintf(file, ") */\n");
2658 	fprintf(file, "\n");
2659 }
2660 
2661 static void
WriteCheckRequestCall(FILE * file,routine_t * rt)2662 WriteCheckRequestCall(FILE *file, routine_t *rt)
2663 {
2664 	u_int i;
2665 
2666 	fprintf(file, "\n");
2667 	fprintf(file, "#if\tdefined(__MIG_check__Request__%s_t__defined)\n", rt->rtName);
2668 	fprintf(file, "\tcheck_result = __MIG_check__Request__%s_t((__Request *)In0P", rt->rtName);
2669 	for (i = 1; i <= rt->rtMaxRequestPos; i++)
2670 		fprintf(file, ", (__Request **)&In%dP", i);
2671 	fprintf(file, ");\n");
2672 	fprintf(file, "\tif (check_result != MACH_MSG_SUCCESS)\n");
2673 	fprintf(file, "\t\t{ MIG_RETURN_ERROR(OutP, check_result); }\n");
2674 	fprintf(file, "#endif\t/* defined(__MIG_check__Request__%s_t__defined) */\n", rt->rtName);
2675 	fprintf(file, "\n");
2676 }
2677 
2678 void
WriteCheckRequests(FILE * file,statement_t * stats)2679 WriteCheckRequests(FILE *file, statement_t *stats)
2680 {
2681 	statement_t *stat;
2682 
2683 	for (stat = stats; stat != stNULL; stat = stat->stNext)
2684 		if (stat->stKind == skRoutine)
2685 			WriteCheckRequest(file, stat->stRoutine);
2686 }
2687 
2688 static void
WriteRoutine(FILE * file,register routine_t * rt)2689 WriteRoutine(FILE *file, register routine_t *rt)
2690 {
2691 	/*  Declare the server work function: */
2692 	if (ServerHeaderFileName == strNULL)
2693 		WriteServerRoutine(file, rt);
2694 
2695 	fprintf(file, "\n");
2696 
2697 	fprintf(file, "/* %s %s */\n", rtRoutineKindToStr(rt->rtKind), rt->rtName);
2698 	fprintf(file, "mig_internal novalue _X%s\n", rt->rtName);
2699 	if (BeAnsiC) {
2700 		fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
2701     } else {
2702 		fprintf(file, "#if\t%s\n", NewCDecl);
2703 		fprintf(file, "\t(mach_msg_header_t *InHeadP, mach_msg_header_t *OutHeadP)\n");
2704 		fprintf(file, "#else\n");
2705 		fprintf(file, "\t(InHeadP, OutHeadP)\n");
2706 		fprintf(file, "\tmach_msg_header_t *InHeadP, *OutHeadP;\n");
2707 		fprintf(file, "#endif\t/* %s */\n", NewCDecl);
2708 	}
2709 
2710 	fprintf(file, "{\n");
2711 	WriteStructDecl(file, rt->rtArgs, WriteFieldDecl, akbRequest, "Request", rt->rtSimpleRequest, TRUE, rt->rtServerImpl, FALSE);
2712 	fprintf(file, "\ttypedef __Request__%s_t __Request;\n", rt->rtName);
2713 	fprintf(file, "\ttypedef __Reply__%s_t Reply;\n\n", rt->rtName);
2714 
2715 	/*
2716 	 * Define a Minimal Reply structure to be used in case of errors
2717 	 */
2718 	fprintf(file, "\t/*\n");
2719 	fprintf(file, "\t * typedef struct {\n");
2720 	fprintf(file, "\t * \tmach_msg_header_t Head;\n");
2721 	fprintf(file, "\t * \tNDR_record_t NDR;\n");
2722 	fprintf(file, "\t * \tkern_return_t RetCode;\n");
2723 	fprintf(file, "\t * } mig_reply_error_t;\n");
2724 	fprintf(file, "\t */\n");
2725 	fprintf(file, "\n");
2726 
2727 	WriteVarDecls(file, rt);
2728 
2729 	if (IsKernelServer) {
2730 		fprintf(file, "#if\t__MigKernelSpecificCode\n");
2731 		WriteList(file, rt->rtArgs, WriteTemplateDeclOut, akbReturnKPD, "\n", "\n");
2732 		fprintf(file, "#else\n");
2733 	}
2734 	WriteList(file, rt->rtArgs, WriteTemplateDeclIn, akbReturnKPD, "\n", "\n");
2735 	if (IsKernelServer) {
2736 		fprintf(file, "#endif /* __MigKernelSpecificCode */\n");
2737 	}
2738 	WriteRetCode(file, rt->rtRetCode);
2739 	WriteList(file, rt->rtArgs, WriteLocalVarDecl, akbVarNeeded | akbServerArg, ";\n", ";\n\n");
2740 	WriteApplMacro(file, "Rcv", "Declare", rt);
2741 	WriteApplMacro(file, "Rcv", "Before", rt);
2742 	if (rt->rtRetCArg != argNULL && !rt->rtSimpleRequest) {
2743 		WriteRetCArgCheckError(file, rt);
2744 		if (rt->rtServerImpl)
2745 			WriteCheckTrailerHead(file, rt, FALSE);
2746 		WriteServerCall(file, rt, WriteConditionalCallArg);
2747 		WriteRetCArgFinishError(file, rt);
2748 	} else
2749 		fprintf(file, "/* RetCArg=%p rtSimpleRequest=%u */\n", rt->rtRetCArg, rt->rtSimpleRequest);
2750 
2751 	WriteCheckRequestCall(file, rt);
2752 
2753 	WriteCheckRequestTrailerArgs(file, rt);
2754 
2755 
2756 	/*
2757 	 * Initialize the KPD records in the Reply structure with the
2758 	 * templates. We do this beforehand because the call to the procedure
2759 	 * will overwrite some of the values (after the call it would be impossible
2760 	 * to initialize the KPD records from the static Templates, because we
2761 	 * would lose data).
2762 	 */
2763 	WriteList(file, rt->rtArgs, WriteInitKPDValue, akbReturnKPD, "\n", "\n");
2764 
2765 	WriteList(file, rt->rtArgs, WriteExtractArg, akbNone, "", "");
2766 
2767 	if (UseEventLogger)
2768 		WriteLogMsg(file, rt, LOG_SERVER, LOG_REQUEST);
2769 
2770 
2771 	WriteServerCall(file, rt, WriteServerCallArg);
2772 
2773 
2774 	WriteReverseList(file, rt->rtArgs, WriteDestroyArg, akbDestroy, "", "");
2775 
2776 	/*
2777 	 * For one-way routines, it doesn`t make sense to check the return
2778 	 * code, because we return immediately afterwards.  However,
2779 	 * kernel servers may want to deallocate port arguments - and the
2780 	 * deallocation must not be done if the return code is not KERN_SUCCESS.
2781 	 */
2782 	if (rt->rtOneWay || rt->rtNoReplyArgs) {
2783 		if (IsKernelServer) {
2784 			fprintf(file,"#if\t__MigKernelSpecificCode\n");
2785 			if (rtCheckMaskFunction(rt->rtArgs, akbSendKPD, CheckDestroyPortArg)) {
2786 				WriteCheckReturnValue(file, rt);
2787 			}
2788 			WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", "");
2789 			fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
2790 		}
2791 		/* although we have an empty reply, we still have to make sure that
2792 		   some fields such as NDR get properly initialized */
2793 		if (!rt->rtOneWay)
2794 			WriteList(file, rt->rtArgs, WriteInitArgValue, akbReplyInit, "\n", "\n");
2795     } else {
2796 		WriteCheckReturnValue(file, rt);
2797 
2798 		if (IsKernelServer) {
2799 			fprintf(file,"#if\t__MigKernelSpecificCode\n");
2800 			WriteReverseList(file, rt->rtArgs, WriteDestroyPortArg, akbSendKPD, "", "");
2801 			fprintf(file,"#endif /* __MigKernelSpecificCode */\n");
2802 		}
2803 		WriteReplyArgs(file, rt);
2804 		WriteReplyInit(file, rt);
2805 		if (!rt->rtSimpleReply)
2806 			fprintf(file, "\tOutP->msgh_body.msgh_descriptor_count = %d;\n", rt->rtReplyKPDs);
2807 	}
2808 	if (UseEventLogger)
2809 		WriteLogMsg(file, rt, LOG_SERVER, LOG_REPLY);
2810 
2811 	WriteApplMacro(file, "Rcv", "After", rt);
2812 	fprintf(file, "}\n");
2813 }
2814 
2815 void
WriteServer(FILE * file,statement_t * stats)2816 WriteServer(FILE *file, statement_t *stats)
2817 {
2818 	register statement_t *stat;
2819 
2820 	WriteProlog(file, stats);
2821 	if (BeAnsiC)
2822 		WriteForwardDeclarations(file, stats);
2823 	for (stat = stats; stat != stNULL; stat = stat->stNext) {
2824 		switch (stat->stKind) {
2825 		case skRoutine:
2826 			WriteCheckRequest(file, stat->stRoutine);
2827 			WriteRoutine(file, stat->stRoutine);
2828 			break;
2829 		case skIImport:
2830 		case skImport:
2831 		case skSImport:
2832 		case skDImport:
2833 		case skUImport:
2834 			break;
2835 
2836 		default:
2837 			fatal("WriteServer(): bad statement_kind_t (%d)",
2838 				  (int) stat->stKind);
2839 		}
2840 	}
2841 	WriteDispatcher(file, stats);
2842 }
2843