xref: /openbsd/sys/kern/makesyscalls.sh (revision 404b540a)
1#! /bin/sh -
2#	$OpenBSD: makesyscalls.sh,v 1.11 2007/11/27 18:04:01 art Exp $
3#	$NetBSD: makesyscalls.sh,v 1.26 1998/01/09 06:17:51 thorpej Exp $
4#
5# Copyright (c) 1994,1996 Christopher G. Demetriou
6# All rights reserved.
7#
8# Redistribution and use in source and binary forms, with or without
9# modification, are permitted provided that the following conditions
10# are met:
11# 1. Redistributions of source code must retain the above copyright
12#    notice, this list of conditions and the following disclaimer.
13# 2. Redistributions in binary form must reproduce the above copyright
14#    notice, this list of conditions and the following disclaimer in the
15#    documentation and/or other materials provided with the distribution.
16# 3. All advertising materials mentioning features or use of this software
17#    must display the following acknowledgement:
18#      This product includes software developed for the NetBSD Project
19#      by Christopher G. Demetriou.
20# 4. The name of the author may not be used to endorse or promote products
21#    derived from this software without specific prior written permission
22#
23# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
34#	@(#)makesyscalls.sh	8.1 (Berkeley) 6/10/93
35
36set -e
37
38case $# in
39    2)	;;
40    *)	echo "Usage: $0 config-file input-file" 1>&2
41	exit 1
42	;;
43esac
44
45# source the config file.
46case $1 in
47    /*)	. $1
48	;;
49    *)	. ./$1
50	;;
51esac
52
53# the config file sets the following variables:
54#	sysnames	the syscall names file
55#	sysnumhdr	the syscall numbers file
56#	syssw		the syscall switch file
57#	sysarghdr	the syscall argument struct definitions
58#	compatopts	those syscall types that are for 'compat' syscalls
59#	switchname	the name for the 'struct sysent' we define
60#	namesname	the name for the 'char *[]' we define
61#	constprefix	the prefix for the system call constants
62#
63# NOTE THAT THIS makesyscalls.sh DOES NOT SUPPORT 'LIBCOMPAT'.
64
65# tmp files:
66sysdcl="sysent.dcl"
67sysprotos="sys.protos"
68syscompat_pref="sysent."
69sysent="sysent.switch"
70
71trap "rm $sysdcl $sysprotos $sysent" 0
72
73# Awk program (must support nawk extensions)
74# Use "awk" at Berkeley, "nawk" or "gawk" elsewhere.
75awk=${AWK:-awk}
76
77# Does this awk have a "toupper" function? (i.e. is it GNU awk)
78isgawk=`$awk 'BEGIN { print toupper("true"); exit; }' 2>/dev/null`
79
80# If this awk does not define "toupper" then define our own.
81if [ "$isgawk" = TRUE ] ; then
82	# GNU awk provides it.
83	toupper=
84else
85	# Provide our own toupper()
86	toupper='
87function toupper(str) {
88	_toupper_cmd = "echo "str" |tr a-z A-Z"
89	_toupper_cmd | getline _toupper_str;
90	close(_toupper_cmd);
91	return _toupper_str;
92}'
93fi
94
95# before handing it off to awk, make a few adjustments:
96#	(1) insert spaces around {, }, (, ), *, and commas.
97#	(2) get rid of any and all dollar signs (so that rcs id use safe)
98#
99# The awk script will deal with blank lines and lines that
100# start with the comment character (';').
101
102sed -e '
103s/\$//g
104:join
105	/\\$/{a\
106
107	N
108	s/\\\n//
109	b join
110	}
1112,${
112	/^#/!s/\([{}()*,]\)/ \1 /g
113}
114' < $2 | $awk "
115$toupper
116BEGIN {
117	# to allow nested #if/#else/#endif sets
118	savedepth = 0
119
120	sysnames = \"$sysnames\"
121	sysprotos = \"$sysprotos\"
122	sysnumhdr = \"$sysnumhdr\"
123	sysarghdr = \"$sysarghdr\"
124	switchname = \"$switchname\"
125	namesname = \"$namesname\"
126	constprefix = \"$constprefix\"
127
128	sysdcl = \"$sysdcl\"
129	syscompat_pref = \"$syscompat_pref\"
130	sysent = \"$sysent\"
131	infile = \"$2\"
132
133	compatopts = \"$compatopts\"
134	"'
135
136	printf "/*\t\$OpenBSD\$\t*/\n\n" > sysdcl
137	printf "/*\n * System call switch table.\n *\n" > sysdcl
138	printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysdcl
139
140	ncompat = split(compatopts,compat)
141	for (i = 1; i <= ncompat; i++) {
142		compat_upper[i] = toupper(compat[i])
143
144		printf "\n#ifdef %s\n", compat_upper[i] > sysent
145		printf "#define %s(func) __CONCAT(%s_,func)\n", compat[i], \
146		    compat[i] > sysent
147		printf "#else\n" > sysent
148		printf "#define %s(func) sys_nosys\n", compat[i] > sysent
149		printf "#endif\n" > sysent
150	}
151
152	printf "\n#define\ts(type)\tsizeof(type)\n\n" > sysent
153	printf "struct sysent %s[] = {\n",switchname > sysent
154
155	printf "/*\t\$OpenBSD\$\t*/\n\n" > sysnames
156	printf "/*\n * System call names.\n *\n" > sysnames
157	printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysnames
158
159	printf "\n/*\n * System call prototypes.\n */\n\n" > sysprotos
160
161	printf "/*\t\$OpenBSD\$\t*/\n\n" > sysnumhdr
162	printf "/*\n * System call numbers.\n *\n" > sysnumhdr
163	printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysnumhdr
164
165	printf "/*\t\$OpenBSD\$\t*/\n\n" > sysarghdr
166	printf "/*\n * System call argument lists.\n *\n" > sysarghdr
167	printf " * DO NOT EDIT-- this file is automatically generated.\n" > sysarghdr
168}
169NR == 1 {
170	printf " * created from%s\n */\n\n", $0 > sysdcl
171
172	printf " * created from%s\n */\n\n", $0 > sysnames
173	printf "char *%s[] = {\n",namesname > sysnames
174
175	printf " * created from%s\n */\n\n", $0 > sysnumhdr
176
177	printf " * created from%s\n */\n\n", $0 > sysarghdr
178	printf "#ifdef\tsyscallarg\n" > sysarghdr
179	printf "#undef\tsyscallarg\n" > sysarghdr
180	printf "#endif\n\n" > sysarghdr
181	printf "#define\tsyscallarg(x)\t\t\t\t\t\t\t\\\n" > sysarghdr
182	printf "\tunion {\t\t\t\t\t\t\t\t\\\n" > sysarghdr
183	printf "\t\tregister_t pad;\t\t\t\t\t\t\\\n" > sysarghdr
184	printf "\t\tstruct { x datum; } le;\t\t\t\t\t\\\n" > sysarghdr
185	printf "\t\tstruct {\t\t\t\t\t\t\\\n" > sysarghdr
186	printf "\t\t\tint8_t pad[ (sizeof (register_t) < sizeof (x))\t\\\n" \
187		> sysarghdr
188	printf "\t\t\t\t? 0\t\t\t\t\t\\\n" > sysarghdr
189	printf "\t\t\t\t: sizeof (register_t) - sizeof (x)];\t\\\n" \
190		> sysarghdr
191	printf "\t\t\tx datum;\t\t\t\t\t\\\n" > sysarghdr
192	printf "\t\t} be;\t\t\t\t\t\t\t\\\n" > sysarghdr
193	printf "\t}\n" > sysarghdr
194	next
195}
196NF == 0 || $1 ~ /^;/ {
197	next
198}
199$1 ~ /^#[ 	]*include/ {
200	print > sysdcl
201	next
202}
203$1 ~ /^#[ 	]*if/ {
204	print > sysent
205	print > sysprotos
206	print > sysnames
207	savesyscall[++savedepth] = syscall
208	next
209}
210$1 ~ /^#[ 	]*else/ {
211	print > sysent
212	print > sysprotos
213	print > sysnames
214	if (savedepth <= 0) {
215		printf "%s: line %d: unbalenced #else\n", \
216		    infile, NR
217		exit 1
218	}
219	syscall = savesyscall[savedepth]
220	next
221}
222$1 ~ /^#/ {
223	if ($1 ~ /^#[       ]*endif/) {
224		if (savedepth <= 0) {
225			printf "%s: line %d: unbalenced #endif\n", \
226			    infile, NR
227			exit 1
228		}
229		savedepth--;
230	}
231	print > sysent
232	print > sysprotos
233	print > sysnames
234	next
235}
236syscall != $1 {
237	printf "%s: line %d: syscall number out of sync at %d\n", \
238	   infile, NR, syscall
239	printf "line is:\n"
240	print
241	exit 1
242}
243function parserr(was, wanted) {
244	printf "%s: line %d: unexpected %s (expected %s)\n", \
245	    infile, NR, was, wanted
246	exit 1
247}
248function parseline() {
249	f=3			# toss number and type
250	sycall_flags="0"
251	if ($NF != "}") {
252		funcalias=$NF
253		end=NF-1
254	} else {
255		funcalias=""
256		end=NF
257	}
258	if ($f == "MPSAFE") {		# allow MP-safe syscalls
259		sycall_flags = sprintf("SY_MPSAFE | %s", sycall_flags)
260		f++
261	}
262	if ($f == "NOLOCK") {		# syscall does not need locks
263		sycall_flags = sprintf("SY_NOLOCK | %s", sycall_flags)
264		f++
265	}
266	if ($f ~ /^[a-z0-9_]*$/) {      # allow syscall alias
267		funcalias=$f
268		f++
269	}
270	if ($f != "{")
271		parserr($f, "{")
272	f++
273	if ($end != "}")
274		parserr($end, "}")
275	end--
276	if ($end != ";")
277		parserr($end, ";")
278	end--
279	if ($end != ")")
280		parserr($end, ")")
281	end--
282
283	returntype = oldf = "";
284	do {
285		if (returntype != "" && oldf != "*")
286			returntype = returntype" ";
287		returntype = returntype$f;
288		oldf = $f;
289		f++
290	} while (f < (end - 1) && $(f+1) != "(");
291	if (f == (end - 1)) {
292		parserr($f, "function argument definition (maybe \"(\"?)");
293	}
294
295	funcname=$f
296	if (funcalias == "") {
297		funcalias=funcname
298		sub(/^([^_]+_)*sys_/, "", funcalias)
299	}
300	f++
301
302	if ($f != "(")
303		parserr($f, ")")
304	f++
305
306	argc=0;
307	if (f == end) {
308		if ($f != "void")
309			parserr($f, "argument definition")
310		isvarargs = 0;
311		varargc = 0;
312		return
313	}
314
315	# some system calls (open() and fcntl()) can accept a variable
316	# number of arguments.  If syscalls accept a variable number of
317	# arguments, they must still have arguments specified for
318	# the remaining argument "positions," because of the way the
319	# kernel system call argument handling works.
320	#
321	# Indirect system calls, e.g. syscall(), are exceptions to this
322	# rule, since they are handled entirely by machine-dependent code
323	# and do not need argument structures built.
324
325	isvarargs = 0;
326	while (f <= end) {
327		if ($f == "...") {
328			f++;
329			isvarargs = 1;
330			varargc = argc;
331			continue;
332		}
333		argc++
334		argtype[argc]=""
335		oldf=""
336		while (f < end && $(f+1) != ",") {
337			if (argtype[argc] != "" && oldf != "*")
338				argtype[argc] = argtype[argc]" ";
339			argtype[argc] = argtype[argc]$f;
340			oldf = $f;
341			f++
342		}
343		if (argtype[argc] == "")
344			parserr($f, "argument definition")
345		argname[argc]=$f;
346		f += 2;			# skip name, and any comma
347	}
348	# must see another argument after varargs notice.
349	if (isvarargs) {
350		if (argc == varargc && $2 != "INDIR")
351			parserr($f, "argument definition")
352	} else
353		varargc = argc;
354}
355function putent(nodefs, compatwrap) {
356	# output syscall declaration for switch table.  INDIR functions
357	# get none, since they always have sys_nosys() for their table
358	# entries.
359	if (nodefs != "INDIR") {
360		prototype = "(struct proc *, void *, register_t *)"
361		if (compatwrap == "")
362			printf("int\t%s%s;\n", funcname,
363			    prototype) > sysprotos
364		else
365			printf("int\t%s_%s%s;\n", compatwrap, funcname,
366			    prototype) > sysprotos
367	}
368
369	# output syscall switch entry
370	if (nodefs == "INDIR") {
371		printf("\t{ 0, 0, %s,\n\t    sys_nosys },\t\t\t/* %d = %s (indir) */\n", \
372		    sycall_flags, syscall, funcalias) > sysent
373	} else {
374#		printf("\t{ { %d", argc) > sysent
375#		for (i = 1; i <= argc; i++) {
376#			if (i == 5) 		# wrap the line
377#				printf(",\n\t    ") > sysent
378#			else
379#				printf(", ") > sysent
380#			printf("s(%s)", argtypenospc[i]) > sysent
381#		}
382		printf("\t{ %d, ", argc) > sysent
383		if (argc == 0)
384			printf("0") > sysent
385		else if (compatwrap == "")
386			printf("s(struct %s_args)", funcname) > sysent
387		else
388			printf("s(struct %s_%s_args)", compatwrap,
389			    funcname) > sysent
390		if (compatwrap == "")
391			wfn = sprintf("%s", funcname);
392		else
393			wfn = sprintf("%s(%s)", compatwrap, funcname);
394		printf(", %s,\n\t    %s },", sycall_flags, wfn) > sysent
395		for (i = 0; i < (33 - length(wfn)) / 8; i++)
396			printf("\t") > sysent
397		if (compatwrap == "")
398			printf("/* %d = %s */\n", syscall, funcalias) > sysent
399		else
400			printf("/* %d = %s %s */\n", syscall, compatwrap,
401			    funcalias) > sysent
402	}
403
404	# output syscall name for names table
405	if (compatwrap == "")
406		printf("\t\"%s\",\t\t\t/* %d = %s */\n", funcalias, syscall,
407		    funcalias) > sysnames
408	else
409		printf("\t\"%s_%s\",\t/* %d = %s %s */\n", compatwrap,
410		    funcalias, syscall, compatwrap, funcalias) > sysnames
411
412	# output syscall number of header, if appropriate
413	if (nodefs == "" || nodefs == "NOARGS" || nodefs == "INDIR") {
414		# output a prototype, to be used to generate lint stubs in
415		# libc.
416		printf("/* syscall: \"%s\" ret: \"%s\" args:", funcalias,
417		    returntype) > sysnumhdr
418		for (i = 1; i <= varargc; i++)
419			printf(" \"%s\"", argtype[i]) > sysnumhdr
420		if (isvarargs)
421			printf(" \"...\"") > sysnumhdr
422		printf(" */\n") > sysnumhdr
423
424		printf("#define\t%s%s\t%d\n\n", constprefix, funcalias,
425		    syscall) > sysnumhdr
426	} else if (nodefs != "NODEF")
427		printf("\t\t\t\t/* %d is %s %s */\n\n", syscall,
428		    compatwrap, funcalias) > sysnumhdr
429
430	# output syscall argument structure, if it has arguments
431	if (argc != 0 && nodefs != "NOARGS" && nodefs != "INDIR") {
432		if (compatwrap == "")
433			printf("\nstruct %s_args {\n", funcname) > sysarghdr
434		else
435			printf("\nstruct %s_%s_args {\n", compatwrap,
436			    funcname) > sysarghdr
437		for (i = 1; i <= argc; i++)
438			printf("\tsyscallarg(%s) %s;\n", argtype[i],
439			    argname[i]) > sysarghdr
440		printf("};\n") > sysarghdr
441	}
442}
443$2 == "STD" {
444	parseline()
445	putent("", "");
446	syscall++
447	next
448}
449$2 == "NODEF" || $2 == "NOARGS" || $2 == "INDIR" {
450	parseline()
451	putent($2, "")
452	syscall++
453	next
454}
455$2 == "OBSOL" || $2 == "UNIMPL" {
456	if ($2 == "OBSOL")
457		comment="obsolete"
458	else
459		comment="unimplemented"
460	for (i = 3; i <= NF; i++)
461		comment=comment " " $i
462
463	printf("\t{ 0, 0, 0,\n\t    sys_nosys },\t\t\t/* %d = %s */\n", \
464	    syscall, comment) > sysent
465	printf("\t\"#%d (%s)\",\t\t/* %d = %s */\n", \
466	    syscall, comment, syscall, comment) > sysnames
467	if ($2 != "UNIMPL")
468		printf("\t\t\t\t/* %d is %s */\n", syscall, comment) > sysnumhdr
469	syscall++
470	next
471}
472{
473	for (i = 1; i <= ncompat; i++) {
474		if ($2 == compat_upper[i]) {
475			parseline();
476			putent("COMMENT", compat[i])
477			syscall++
478			next
479		}
480	}
481	printf "%s: line %d: unrecognized keyword %s\n", infile, NR, $2
482	exit 1
483}
484END {
485	printf("};\n\n") > sysent
486	printf("};\n") > sysnames
487	printf("#define\t%sMAXSYSCALL\t%d\n", constprefix, syscall) > sysnumhdr
488} '
489
490cat $sysprotos >> $sysarghdr
491cat $sysdcl $sysent > $syssw
492
493#chmod 444 $sysnames $sysnumhdr $syssw
494