]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/xcodescripts/create-syscalls.pl
xnu-2422.90.20.tar.gz
[apple/xnu.git] / libsyscall / xcodescripts / create-syscalls.pl
1 #!/usr/bin/perl
2 #
3 # Copyright (c) 2006-2012 Apple Inc. All rights reserved.
4 #
5 # @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 #
7 # This file contains Original Code and/or Modifications of Original Code
8 # as defined in and that are subject to the Apple Public Source License
9 # Version 2.0 (the 'License'). You may not use this file except in
10 # compliance with the License. Please obtain a copy of the License at
11 # http://www.opensource.apple.com/apsl/ and read it before using this
12 # file.
13 #
14 # The Original Code and all software distributed under the License are
15 # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 # Please see the License for the specific language governing rights and
20 # limitations under the License.
21 #
22 # @APPLE_OSREFERENCE_LICENSE_HEADER_END@
23 #
24 ##########################################################################
25 #
26 # % create-syscalls.pl syscalls.master custom-directory platforms-directory platform-name out-directory
27 #
28 # This script fills the the out-directory with a Makefile.inc and *.s
29 # files to create the double-underbar syscall stubs. It reads the
30 # syscall.master file to get the symbol names and number of arguments,
31 # and whether Libsystem should automatically create the (non-double-underbar)
32 # stubs if Libc doesn't provide a wrapper. Which system calls will get
33 # the automatic treatment is writen to the libsyscall.list file, also
34 # written to the out-directory.
35 #
36 # The custom-directory contains:
37 # 1. SYS.h - used by the automatically created *.s and custom files
38 # 2. custom.s - contains architecture specific additional system calls and
39 # auxilliary routines (like cerror)
40 # 3. special case double-underbar stub files - which are copied into
41 # the out-directory
42 #
43 ##########################################################################
44
45 use strict;
46 use File::Basename ();
47 use File::Copy ();
48 use File::Spec;
49 use IO::File;
50
51 my $MyName = File::Basename::basename($0);
52
53 my @CustomSrc = qw(custom.s);
54
55 my @Architectures = split /\s/, $ENV{"ARCHS"};
56 my @Copy = (qw(SYS.h), @CustomSrc);
57 my $CustomDir;
58 my $PlatformsDir;
59 my $PlatformName;
60 my $OutDir;
61 # size in bytes of known types (only used for i386)
62 my %TypeBytes = (
63 'au_asid_t' => 4,
64 'associd_t' => 4,
65 'caddr_t' => 4,
66 'connid_t' => 4,
67 'gid_t' => 4,
68 'id_t' => 4,
69 'idtype_t' => 4,
70 'int' => 4,
71 'int32_t' => 4,
72 'int64_t' => 8,
73 'key_t' => 4,
74 'long' => 4,
75 'mach_port_name_t' => 4,
76 'mode_t' => 4,
77 'off_t' => 8,
78 'pid_t' => 4,
79 'semun_t' => 4,
80 'sigset_t' => 4,
81 'size_t' => 4,
82 'socklen_t' => 4,
83 'ssize_t' => 4,
84 'u_int' => 4,
85 'u_long' => 4,
86 'uid_t' => 4,
87 'uint32_t' => 4,
88 'uint64_t' => 8,
89 'user_addr_t' => 4,
90 'user_long_t' => 4,
91 'user_size_t' => 4,
92 'user_ssize_t' => 4,
93 'user_ulong_t' => 4,
94 'uuid_t' => 4,
95 );
96
97 # Moving towards storing all data in this hash, then we always know
98 # if data is aliased or not, or promoted or not.
99 my %Symbols = (
100 "quota" => {
101 c_sym => "quota",
102 syscall => "quota",
103 asm_sym => "_quota",
104 is_private => undef,
105 is_custom => undef,
106 nargs => 4,
107 bytes => 0,
108 aliases => {},
109 },
110 "setquota" => {
111 c_sym => "setquota",
112 syscall => "setquota",
113 asm_sym => "_setquota",
114 is_private => undef,
115 is_custom => undef,
116 nargs => 2,
117 bytes => 0,
118 aliases => {},
119 },
120 "syscall" => {
121 c_sym => "syscall",
122 syscall => "syscall",
123 asm_sym => "_syscall",
124 is_private => undef,
125 is_custom => undef,
126 nargs => 0,
127 bytes => 0,
128 aliases => {},
129 },
130 );
131
132 # An explicit list of cancelable syscalls. For creating stubs that call the
133 # cancellable version of cerror.
134 my @Cancelable = qw/
135 accept access aio_suspend
136 close connect connectx
137 disconnectx
138 fcntl fdatasync fpathconf fstat fsync
139 getlogin
140 ioctl
141 link lseek lstat
142 msgrcv msgsnd msync
143 open
144 pathconf peeloff poll posix_spawn pread pwrite
145 read readv recvfrom recvmsg rename
146 __semwait_signal __sigwait
147 select sem_wait semop sendmsg sendto sigsuspend stat symlink sync
148 unlink
149 wait4 waitid write writev
150 /;
151
152 sub usage {
153 die "Usage: $MyName syscalls.master custom-directory platforms-directory platform-name out-directory\n";
154 }
155
156 ##########################################################################
157 # Read the syscall.master file and collect the system call names and number
158 # of arguments. It looks for the NO_SYSCALL_STUB quailifier following the
159 # prototype to determine if no automatic stub should be created by Libsystem.
160 # System call name that are already prefixed with double-underbar are set as
161 # if the NO_SYSCALL_STUB qualifier were specified (whether it is or not).
162 #
163 # For the #if lines in syscall.master, all macros are assumed to be defined,
164 # except COMPAT_GETFSSTAT (assumed undefined).
165 ##########################################################################
166 sub readMaster {
167 my $file = shift;
168 local $_;
169 my $f = IO::File->new($file, 'r');
170 die "$MyName: $file: $!\n" unless defined($f);
171 my $line = 0;
172 my $skip = 0;
173 while(<$f>) {
174 $line++;
175 if(/^#\s*endif/) {
176 $skip = 0;
177 next;
178 }
179 if(/^#\s*else/) {
180 $skip = -$skip;
181 next;
182 }
183 chomp;
184 if(/^#\s*if\s+(\S+)$/) {
185 $skip = ($1 eq 'COMPAT_GETFSSTAT') ? -1 : 1;
186 next;
187 }
188 next if $skip < 0;
189 next unless /^\d/;
190 s/^[^{]*{\s*//;
191 s/\s*}.*$//; # }
192 die "$MyName: no function prototype on line $line\n" unless length($_) > 0 && /;$/;
193 my $no_syscall_stub = /\)\s*NO_SYSCALL_STUB\s*;/;
194 my($name, $args) = /\s(\S+)\s*\(([^)]*)\)/;
195 next if $name =~ /e?nosys/;
196 $args =~ s/^\s+//;
197 $args =~ s/\s+$//;
198 my $argbytes = 0;
199 my $nargs = 0;
200 if($args ne '' && $args ne 'void') {
201 my @a = split(',', $args);
202 $nargs = scalar(@a);
203 # Calculate the size of all the arguments (only used for i386)
204 for my $type (@a) {
205 $type =~ s/\s*\w+$//; # remove the argument name
206 if($type =~ /\*$/) {
207 $argbytes += 4; # a pointer type
208 } else {
209 $type =~ s/^.*\s//; # remove any type qualifier, like unsigned
210 my $b = $TypeBytes{$type};
211 die "$MyName: $name: unknown type '$type'\n" unless defined($b);
212 $argbytes += $b;
213 }
214 }
215 }
216 $Symbols{$name} = {
217 c_sym => $name,
218 syscall => $name,
219 asm_sym => $no_syscall_stub ? "___$name" : "_$name",
220 is_private => $no_syscall_stub,
221 is_custom => undef,
222 nargs => $nargs,
223 bytes => $argbytes,
224 aliases => {},
225 except => [],
226 };
227 }
228 }
229
230 sub checkForCustomStubs {
231 my ($dir) = @_;
232
233 my ($c_sym_name, $sym);
234 while (($c_sym_name, $sym) = each %Symbols) {
235 my $source = "__".$$sym{c_sym}.".s";
236 my $custom = File::Spec->join($dir, $source);
237 next unless -f $custom;
238
239 $$sym{is_custom} = $source;
240 if (!$$sym{is_private}) {
241 foreach my $subarch (@Architectures) {
242 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
243 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
244 push(@{$$sym{aliases}{$arch}}, $$sym{asm_sym});
245 }
246 $$sym{asm_sym} = "__".$$sym{asm_sym};
247 $$sym{is_private} = 1;
248 }
249 }
250 }
251
252 sub readAliases {
253 my ($platformDir, $platformName) = @_;
254 my $genericMap = File::Spec->join($platformDir, "syscall.map");
255
256 my %sym_to_c;
257 foreach my $k (keys %Symbols) {
258 $sym_to_c{$Symbols{$k}{asm_sym}} = $k;
259 }
260
261 my @a = ();
262 for my $arch (@Architectures) {
263 (my $new_arch = $arch) =~ s/arm(v.*)/arm/g;
264 push(@a, $new_arch) unless grep { $_ eq $new_arch } @a;
265 }
266
267 foreach my $arch (@a) {
268 my $syscallFile = File::Spec->join($platformDir, $platformName, $arch, "syscall.map");
269
270 my @files = ();
271 push(@files, IO::File->new($syscallFile, 'r'));
272 die "$MyName: $syscallFile: $!\n" unless defined($files[$#files]);
273 push(@files, IO::File->new($genericMap, 'r'));
274 die "$MyName: $genericMap: $!\n" unless defined($files[$#files]);
275
276 foreach my $f (@files) {
277 while (<$f>) {
278 next if /^#/;
279 chomp;
280
281 my ($alias, $target_symbol) = split;
282 if (defined($target_symbol)) {
283 foreach my $sym (values %Symbols) {
284 # I've eliminated most of the ugly from this script except
285 # the need to try stripping underbars here.
286 if ($$sym{is_private}) {
287 next unless $$sym{asm_sym} eq $target_symbol;
288 } else {
289 (my $target = $target_symbol) =~ s/^__//;
290 next unless ($$sym{asm_sym} eq $target || $$sym{asm_sym} eq $target_symbol);
291 }
292 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
293
294 die "$MyName: $arch $$sym{asm_sym} -> $alias: Duplicate alias.\n" if grep { $_ eq $alias } @{$$sym{aliases}{$arch}};
295 push(@{$$sym{aliases}{$arch}}, $alias);
296
297 # last thing to do, if we aliased over a first class symbol, we need
298 # to mark it
299 my $c = $sym_to_c{$alias};
300 if ($Symbols{$c}) {
301 push(@{$Symbols{$c}{except}}, $arch);
302 }
303 }
304 }
305 }
306 }
307 }
308 }
309
310 ##########################################################################
311 # Make a __xxx.s file: if it exists in the $CustomDir, just copy it, otherwise
312 # create one. We define the macro __SYSCALL_32BIT_ARG_BYTES so that SYS.h could
313 # use that to define __SYSCALL dependent on the arguments' total size.
314 ##########################################################################
315 sub writeStubForSymbol {
316 my ($f, $symbol) = @_;
317
318 my @conditions;
319 for my $subarch (@Architectures) {
320 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
321 push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}};
322 }
323
324 my %is_cancel;
325 for (@Cancelable) { $is_cancel{$_} = 1 };
326
327 print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n";
328 print $f "#include \"SYS.h\"\n\n";
329 if (scalar(@conditions)) {
330 printf $f "#ifndef SYS_%s\n", $$symbol{syscall};
331 printf $f "#error \"SYS_%s not defined. The header files libsyscall is building against do not match syscalls.master.\"\n", $$symbol{syscall};
332 printf $f "#endif\n\n";
333 my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel");
334 printf $f "#if " . join(" || ", @conditions) . "\n";
335 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
336 if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) {
337 printf $f "#else\n";
338 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
339 }
340 printf $f "#endif\n\n";
341 } else {
342 # actually this isnt an inconsistency. kernel can expose what it wants but if all our arches
343 # override it we need to honour that.
344 }
345 }
346
347 sub writeAliasesForSymbol {
348 my ($f, $symbol) = @_;
349
350 foreach my $subarch (@Architectures) {
351 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
352
353 next unless scalar($$symbol{aliases}{$arch});
354
355 printf $f "#if defined(__${arch}__)\n";
356 foreach my $alias_sym (@{$$symbol{aliases}{$arch}}) {
357 my $sym = (grep { $_ eq $arch } @{$$symbol{except}}) ? "__".$$symbol{asm_sym} : $$symbol{asm_sym};
358
359 printf $f "\t.globl\t$alias_sym\n";
360 printf $f "\t.set\t$alias_sym, $sym\n";
361 }
362 printf $f "#endif\n\n";
363 }
364 }
365
366 usage() unless scalar(@ARGV) == 5;
367 $CustomDir = $ARGV[1];
368 die "$MyName: $CustomDir: No such directory\n" unless -d $CustomDir;
369 $PlatformsDir = $ARGV[2];
370 die "$MyName: $PlatformsDir: No such directory\n" unless -d $PlatformsDir;
371 $PlatformName = $ARGV[3];
372 die "$MyName: $PlatformsDir/$PlatformName: No such directory\n" unless -d "$PlatformsDir/$PlatformName";
373 $OutDir = $ARGV[4];
374 die "$MyName: $OutDir: No such directory\n" unless -d $OutDir;
375
376 readMaster($ARGV[0]);
377 checkForCustomStubs($CustomDir);
378 readAliases($PlatformsDir, $PlatformName);
379
380 ##########################################################################
381 # copy the files specified in @Copy from the $CustomDir to $OutDir
382 ##########################################################################
383 for(@Copy) {
384 my $custom = File::Spec->join($CustomDir, $_);
385 my $path = File::Spec->join($OutDir, $_);
386 print "Copy $custom -> $path\n";
387 File::Copy::copy($custom, $path) || die "$MyName: copy($custom, $path): $!\n";
388 }
389
390 ##########################################################################
391 # make all the *.s files
392 ##########################################################################
393 my @src;
394 my($k, $sym);
395 while (($k, $sym) = each %Symbols)
396 {
397 my $srcname = $$sym{asm_sym} . ".s";
398 my $outpath = File::Spec->join($OutDir, $srcname);
399
400 if ($$sym{is_custom}) {
401 my $custom = File::Spec->join($CustomDir, $$sym{is_custom});
402 File::Copy::copy($custom, $outpath);
403 print "Copied $outpath\n";
404
405 print "Writing aliases for $srcname\n";
406 my $f = IO::File->new($outpath, 'a');
407 die "$MyName: $outpath: $!\n" unless defined($f);
408 writeAliasesForSymbol($f, $sym);
409 undef $f;
410 } else {
411 my $f = IO::File->new($outpath, 'w');
412 die "$MyName: $outpath: $!\n" unless defined($f);
413
414 printf "Creating $outpath\n";
415 writeStubForSymbol($f, $sym);
416 writeAliasesForSymbol($f, $sym);
417 undef $f;
418 }
419 push(@src, $srcname);
420 }
421
422 ##########################################################################
423 # create the Makefile.inc file from the list for files in @src and @CustomSrc
424 ##########################################################################
425 my $path = File::Spec->join($OutDir, 'stubs.list');
426 my $f = IO::File->new($path, 'w');
427 my @sources = sort(@src, @CustomSrc);
428 for my $s (@sources) {
429 printf $f File::Spec->join($OutDir, $s) . "\n";
430 }
431 undef $f;
432 undef $path;
433