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