]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/xcodescripts/create-syscalls.pl
xnu-3789.70.16.tar.gz
[apple/xnu.git] / libsyscall / xcodescripts / create-syscalls.pl
1 #!/usr/bin/perl
2 #
3 # Copyright (c) 2006-2014 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 'sae_associd_t' => 4,
65 'caddr_t' => 4,
66 'sae_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 "syscall" => {
101 c_sym => "syscall",
102 syscall => "syscall",
103 asm_sym => "_syscall",
104 is_private => undef,
105 is_custom => undef,
106 nargs => 0,
107 bytes => 0,
108 aliases => {},
109 },
110 );
111
112 # An explicit list of cancelable syscalls. For creating stubs that call the
113 # cancellable version of cerror.
114 my @Cancelable = qw/
115 accept access aio_suspend
116 close connect connectx
117 disconnectx
118 faccessat fcntl fdatasync fpathconf fstat fstatat fsync
119 getlogin
120 ioctl
121 link linkat lseek lstat
122 msgrcv msgsnd msync
123 open openat
124 pathconf peeloff poll posix_spawn pread pselect pwrite
125 read readv recvfrom recvmsg rename renameat
126 rename_ext
127 __semwait_signal __sigwait
128 select sem_wait semop sendmsg sendto sigsuspend stat symlink symlinkat sync
129 unlink unlinkat
130 wait4 waitid write writev
131 /;
132
133 sub usage {
134 die "Usage: $MyName syscalls.master custom-directory platforms-directory platform-name out-directory\n";
135 }
136
137 ##########################################################################
138 # Read the syscall.master file and collect the system call names and number
139 # of arguments. It looks for the NO_SYSCALL_STUB quailifier following the
140 # prototype to determine if no automatic stub should be created by Libsystem.
141 # System call name that are already prefixed with double-underbar are set as
142 # if the NO_SYSCALL_STUB qualifier were specified (whether it is or not).
143 #
144 # For the #if lines in syscall.master, all macros are assumed to be defined,
145 # except COMPAT_GETFSSTAT (assumed undefined).
146 ##########################################################################
147 sub readMaster {
148 my $file = shift;
149 local $_;
150 my $f = IO::File->new($file, 'r');
151 die "$MyName: $file: $!\n" unless defined($f);
152 my $line = 0;
153 my $skip = 0;
154 while(<$f>) {
155 $line++;
156 if(/^#\s*endif/) {
157 $skip = 0;
158 next;
159 }
160 if(/^#\s*else/) {
161 $skip = -$skip;
162 next;
163 }
164 chomp;
165 if(/^#\s*if\s+(\S+)$/) {
166 $skip = ($1 eq 'COMPAT_GETFSSTAT') ? -1 : 1;
167 next;
168 }
169 next if $skip < 0;
170 next unless /^\d/;
171 s/^[^{]*{\s*//;
172 s/\s*}.*$//; # }
173 die "$MyName: no function prototype on line $line\n" unless length($_) > 0 && /;$/;
174 my $no_syscall_stub = /\)\s*NO_SYSCALL_STUB\s*;/;
175 my($name, $args) = /\s(\S+)\s*\(([^)]*)\)/;
176 next if $name =~ /e?nosys/;
177 $args =~ s/^\s+//;
178 $args =~ s/\s+$//;
179 my $argbytes = 0;
180 my $nargs = 0;
181 if($args ne '' && $args ne 'void') {
182 my @a = split(',', $args);
183 $nargs = scalar(@a);
184 # Calculate the size of all the arguments (only used for i386)
185 for my $type (@a) {
186 $type =~ s/\s*\w+$//; # remove the argument name
187 if($type =~ /\*$/) {
188 $argbytes += 4; # a pointer type
189 } else {
190 $type =~ s/^.*\s//; # remove any type qualifier, like unsigned
191 my $b = $TypeBytes{$type};
192 die "$MyName: $name: unknown type '$type'\n" unless defined($b);
193 $argbytes += $b;
194 }
195 }
196 }
197 $Symbols{$name} = {
198 c_sym => $name,
199 syscall => $name,
200 asm_sym => $no_syscall_stub ? "___$name" : "_$name",
201 is_private => $no_syscall_stub,
202 is_custom => undef,
203 nargs => $nargs,
204 bytes => $argbytes,
205 aliases => {},
206 except => [],
207 };
208 }
209 }
210
211 sub checkForCustomStubs {
212 my ($dir) = @_;
213
214 my ($c_sym_name, $sym);
215 while (($c_sym_name, $sym) = each %Symbols) {
216 my $source = "__".$$sym{c_sym}.".s";
217 my $custom = File::Spec->join($dir, $source);
218 next unless -f $custom;
219
220 $$sym{is_custom} = $source;
221 if (!$$sym{is_private}) {
222 foreach my $subarch (@Architectures) {
223 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
224 $arch =~ s/x86_64(.*)/x86_64/;
225 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
226 push(@{$$sym{aliases}{$arch}}, $$sym{asm_sym});
227 }
228 $$sym{asm_sym} = "__".$$sym{asm_sym};
229 $$sym{is_private} = 1;
230 }
231 }
232 }
233
234 sub readAliases {
235 my ($platformDir, $platformName) = @_;
236 my $genericMap = File::Spec->join($platformDir, "syscall.map");
237
238 my %sym_to_c;
239 foreach my $k (keys %Symbols) {
240 $sym_to_c{$Symbols{$k}{asm_sym}} = $k;
241 }
242
243 my @a = ();
244 for my $arch (@Architectures) {
245 (my $new_arch = $arch) =~ s/arm(v.*)/arm/g;
246 $new_arch =~ s/x86_64(.*)/x86_64/g;
247 push(@a, $new_arch) unless grep { $_ eq $new_arch } @a;
248 }
249
250 foreach my $arch (@a) {
251 my $syscallFile = File::Spec->join($platformDir, $platformName, $arch, "syscall.map");
252
253 my @files = ();
254 push(@files, IO::File->new($syscallFile, 'r'));
255 die "$MyName: $syscallFile: $!\n" unless defined($files[$#files]);
256 push(@files, IO::File->new($genericMap, 'r'));
257 die "$MyName: $genericMap: $!\n" unless defined($files[$#files]);
258
259 foreach my $f (@files) {
260 while (<$f>) {
261 next if /^#/;
262 chomp;
263
264 my ($alias, $target_symbol) = split;
265 if (defined($target_symbol)) {
266 foreach my $sym (values %Symbols) {
267 # I've eliminated most of the ugly from this script except
268 # the need to try stripping underbars here.
269 if ($$sym{is_private}) {
270 next unless $$sym{asm_sym} eq $target_symbol;
271 } else {
272 (my $target = $target_symbol) =~ s/^__//;
273 next unless ($$sym{asm_sym} eq $target || $$sym{asm_sym} eq $target_symbol);
274 }
275 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
276
277 die "$MyName: $arch $$sym{asm_sym} -> $alias: Duplicate alias.\n" if grep { $_ eq $alias } @{$$sym{aliases}{$arch}};
278 push(@{$$sym{aliases}{$arch}}, $alias);
279
280 # last thing to do, if we aliased over a first class symbol, we need
281 # to mark it
282 my $c = $sym_to_c{$alias};
283 if ($Symbols{$c}) {
284 push(@{$Symbols{$c}{except}}, $arch);
285 }
286 }
287 }
288 }
289 }
290 }
291 }
292
293 ##########################################################################
294 # Make a __xxx.s file: if it exists in the $CustomDir, just copy it, otherwise
295 # create one. We define the macro __SYSCALL_32BIT_ARG_BYTES so that SYS.h could
296 # use that to define __SYSCALL dependent on the arguments' total size.
297 ##########################################################################
298 sub writeStubForSymbol {
299 my ($f, $symbol) = @_;
300
301 my @conditions;
302 for my $subarch (@Architectures) {
303 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
304 $arch =~ s/x86_64(.*)/x86_64/;
305 push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}};
306 }
307
308 my %is_cancel;
309 for (@Cancelable) { $is_cancel{$_} = 1 };
310
311 print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n";
312 print $f "#include \"SYS.h\"\n\n";
313 if (scalar(@conditions)) {
314 printf $f "#ifndef SYS_%s\n", $$symbol{syscall};
315 printf $f "#error \"SYS_%s not defined. The header files libsyscall is building against do not match syscalls.master.\"\n", $$symbol{syscall};
316 printf $f "#endif\n\n";
317 my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel");
318 printf $f "#if " . join(" || ", @conditions) . "\n";
319 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
320 if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) {
321 printf $f "#else\n";
322 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
323 }
324 printf $f "#endif\n\n";
325 } else {
326 # actually this isnt an inconsistency. kernel can expose what it wants but if all our arches
327 # override it we need to honour that.
328 }
329 }
330
331 sub writeAliasesForSymbol {
332 my ($f, $symbol) = @_;
333
334 foreach my $subarch (@Architectures) {
335 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
336 $arch =~ s/x86_64(.*)/x86_64/;
337
338 next unless scalar($$symbol{aliases}{$arch});
339
340 printf $f "#if defined(__${arch}__)\n";
341 foreach my $alias_sym (@{$$symbol{aliases}{$arch}}) {
342 my $sym = (grep { $_ eq $arch } @{$$symbol{except}}) ? "__".$$symbol{asm_sym} : $$symbol{asm_sym};
343
344 printf $f "\t.globl\t$alias_sym\n";
345 printf $f "\t.set\t$alias_sym, $sym\n";
346 }
347 printf $f "#endif\n\n";
348 }
349 }
350
351 usage() unless scalar(@ARGV) == 5;
352 $CustomDir = $ARGV[1];
353 die "$MyName: $CustomDir: No such directory\n" unless -d $CustomDir;
354 $PlatformsDir = $ARGV[2];
355 die "$MyName: $PlatformsDir: No such directory\n" unless -d $PlatformsDir;
356 $PlatformName = $ARGV[3];
357 die "$MyName: $PlatformsDir/$PlatformName: No such directory\n" unless -d "$PlatformsDir/$PlatformName";
358 $OutDir = $ARGV[4];
359 die "$MyName: $OutDir: No such directory\n" unless -d $OutDir;
360
361 readMaster($ARGV[0]);
362 checkForCustomStubs($CustomDir);
363 readAliases($PlatformsDir, $PlatformName);
364
365 ##########################################################################
366 # copy the files specified in @Copy from the $CustomDir to $OutDir
367 ##########################################################################
368 for(@Copy) {
369 my $custom = File::Spec->join($CustomDir, $_);
370 my $path = File::Spec->join($OutDir, $_);
371 print "Copy $custom -> $path\n";
372 File::Copy::copy($custom, $path) || die "$MyName: copy($custom, $path): $!\n";
373 }
374
375 ##########################################################################
376 # make all the *.s files
377 ##########################################################################
378 my @src;
379 my($k, $sym);
380 while (($k, $sym) = each %Symbols)
381 {
382 my $srcname = $$sym{asm_sym} . ".s";
383 my $outpath = File::Spec->join($OutDir, $srcname);
384
385 if ($$sym{is_custom}) {
386 my $custom = File::Spec->join($CustomDir, $$sym{is_custom});
387 File::Copy::copy($custom, $outpath);
388 print "Copied $outpath\n";
389
390 print "Writing aliases for $srcname\n";
391 my $f = IO::File->new($outpath, 'a');
392 die "$MyName: $outpath: $!\n" unless defined($f);
393 writeAliasesForSymbol($f, $sym);
394 undef $f;
395 } else {
396 my $f = IO::File->new($outpath, 'w');
397 die "$MyName: $outpath: $!\n" unless defined($f);
398
399 printf "Creating $outpath\n";
400 writeStubForSymbol($f, $sym);
401 writeAliasesForSymbol($f, $sym);
402 undef $f;
403 }
404 push(@src, $srcname);
405 }
406
407 ##########################################################################
408 # create the Makefile.inc file from the list for files in @src and @CustomSrc
409 ##########################################################################
410 my $path = File::Spec->join($OutDir, 'stubs.list');
411 my $f = IO::File->new($path, 'w');
412 my @sources = sort(@src, @CustomSrc);
413 for my $s (@sources) {
414 printf $f File::Spec->join($OutDir, $s) . "\n";
415 }
416 undef $f;
417 undef $path;
418