]> git.saurik.com Git - apple/xnu.git/blob - libsyscall/xcodescripts/create-syscalls.pl
xnu-6153.141.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 #
154 # The `sys_` prefix is stripped from syscall names, and is only kept for
155 # the kernel symbol in order to avoid namespace clashes and identify
156 # syscalls more easily.
157 #
158 # For the #if lines in syscall.master, all macros are assumed to be defined,
159 # except COMPAT_GETFSSTAT (assumed undefined).
160 ##########################################################################
161 sub readMaster {
162 my $file = shift;
163 local $_;
164 my $f = IO::File->new($file, 'r');
165 die "$MyName: $file: $!\n" unless defined($f);
166 my $line = 0;
167 my $skip = 0;
168 while(<$f>) {
169 $line++;
170 if(/^#\s*endif/) {
171 $skip = 0;
172 next;
173 }
174 if(/^#\s*else/) {
175 $skip = -$skip;
176 next;
177 }
178 chomp;
179 if(/^#\s*if\s+(\S+)$/) {
180 $skip = ($1 eq 'COMPAT_GETFSSTAT') ? -1 : 1;
181 next;
182 }
183 next if $skip < 0;
184 next unless /^\d/;
185 s/^[^{]*{\s*//;
186 s/\s*}.*$//; # }
187 die "$MyName: no function prototype on line $line\n" unless length($_) > 0 && /;$/;
188 my $no_syscall_stub = /\)\s*NO_SYSCALL_STUB\s*;/;
189 my($name, $args) = /\s(\S+)\s*\(([^)]*)\)/;
190 next if $name =~ /e?nosys/;
191 $name =~ s/^sys_//;
192 $args =~ s/^\s+//;
193 $args =~ s/\s+$//;
194 my $argbytes = 0;
195 my $nargs = 0;
196 my %mismatch_args;
197 if($args ne '' && $args ne 'void') {
198 my @a = split(',', $args);
199 $nargs = scalar(@a);
200 my $index = 0;
201 for my $type (@a) {
202 $type =~ s/\s*\w+$//; # remove the argument name
203
204 # Calculate the size of all the arguments (only used for i386)
205 if($type =~ /\*$/) {
206 $argbytes += 4; # a pointer type
207 } else {
208 $type =~ s/^.*\s//; # remove any type qualifier, like unsigned
209 my $b = $TypeBytes{$type};
210 die "$MyName: $name: unknown type '$type'\n" unless defined($b);
211 $argbytes += $b;
212 }
213 # Determine which arguments might need to be zero/sign-extended
214 if(exists $UserKernelMismatchTypes{$type}) {
215 $mismatch_args{$index} = $UserKernelMismatchTypes{$type};
216 }
217
218 $index++;
219 }
220 }
221 $Symbols{$name} = {
222 c_sym => $name,
223 syscall => $name,
224 asm_sym => $no_syscall_stub ? "___$name" : "_$name",
225 is_private => $no_syscall_stub,
226 is_custom => undef,
227 nargs => $nargs,
228 bytes => $argbytes,
229 aliases => {},
230 mismatch_args => \%mismatch_args, # Arguments that might need to be zero/sign-extended
231 except => [],
232 };
233 }
234 }
235
236 sub checkForCustomStubs {
237 my ($dir) = @_;
238
239 my ($c_sym_name, $sym);
240 while (($c_sym_name, $sym) = each %Symbols) {
241 my $source = "__".$$sym{c_sym}.".s";
242 my $custom = File::Spec->join($dir, $source);
243 next unless -f $custom;
244
245 $$sym{is_custom} = $source;
246 if (!$$sym{is_private}) {
247 foreach my $subarch (@Architectures) {
248 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
249 $arch =~ s/x86_64(.*)/x86_64/;
250 $arch =~ s/arm64(.*)/arm64/;
251 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
252 push(@{$$sym{aliases}{$arch}}, $$sym{asm_sym});
253 }
254 $$sym{asm_sym} = "__".$$sym{asm_sym};
255 $$sym{is_private} = 1;
256 }
257 }
258 }
259
260 sub readAliases {
261 my ($platformDir, $platformName) = @_;
262 my $genericMap = File::Spec->join($platformDir, "syscall.map");
263
264 my %sym_to_c;
265 foreach my $k (keys %Symbols) {
266 $sym_to_c{$Symbols{$k}{asm_sym}} = $k;
267 }
268
269 my @a = ();
270 for my $arch (@Architectures) {
271 (my $new_arch = $arch) =~ s/arm(v.*)/arm/g;
272 $new_arch =~ s/x86_64(.*)/x86_64/g;
273 $new_arch =~ s/arm64(.*)/arm64/g;
274 push(@a, $new_arch) unless grep { $_ eq $new_arch } @a;
275 }
276
277 foreach my $arch (@a) {
278 my $syscallFile = File::Spec->join($platformDir, $platformName, $arch, "syscall.map");
279
280 my @files = ();
281 push(@files, IO::File->new($syscallFile, 'r'));
282 die "$MyName: $syscallFile: $!\n" unless defined($files[$#files]);
283 push(@files, IO::File->new($genericMap, 'r'));
284 die "$MyName: $genericMap: $!\n" unless defined($files[$#files]);
285
286 foreach my $f (@files) {
287 while (<$f>) {
288 next if /^#/;
289 chomp;
290
291 my ($alias, $target_symbol) = split;
292 if (defined($target_symbol)) {
293 foreach my $sym (values %Symbols) {
294 # I've eliminated most of the ugly from this script except
295 # the need to try stripping underbars here.
296 if ($$sym{is_private}) {
297 next unless $$sym{asm_sym} eq $target_symbol;
298 } else {
299 (my $target = $target_symbol) =~ s/^__//;
300 next unless ($$sym{asm_sym} eq $target || $$sym{asm_sym} eq $target_symbol);
301 }
302 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
303
304 die "$MyName: $arch $$sym{asm_sym} -> $alias: Duplicate alias.\n" if grep { $_ eq $alias } @{$$sym{aliases}{$arch}};
305 push(@{$$sym{aliases}{$arch}}, $alias);
306
307 # last thing to do, if we aliased over a first class symbol, we need
308 # to mark it
309 my $c = $sym_to_c{$alias};
310 if ($Symbols{$c}) {
311 push(@{$Symbols{$c}{except}}, $arch);
312 }
313 }
314 }
315 }
316 }
317 }
318 }
319
320 ##########################################################################
321 # Make a __xxx.s file: if it exists in the $CustomDir, just copy it, otherwise
322 # create one. We define the macro __SYSCALL_32BIT_ARG_BYTES so that SYS.h could
323 # use that to define __SYSCALL dependent on the arguments' total size.
324 ##########################################################################
325 sub writeStubForSymbol {
326 my ($f, $symbol) = @_;
327
328 my @conditions;
329 my $has_arm64 = 0;
330 for my $subarch (@Architectures) {
331 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
332 $arch =~ s/x86_64(.*)/x86_64/;
333 $arch =~ s/arm64(.*)/arm64/;
334 push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}};
335
336 if($arch eq "arm64") {
337 $has_arm64 = 1 unless grep { $_ eq $arch } @{$$symbol{except}};
338 }
339 }
340
341 my %is_cancel;
342 for (@Cancelable) { $is_cancel{$_} = 1 };
343
344 print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n";
345 print $f "#include \"SYS.h\"\n\n";
346
347 if (scalar(@conditions)) {
348 printf $f "#ifndef SYS_%s\n", $$symbol{syscall};
349 printf $f "#error \"SYS_%s not defined. The header files libsyscall is building against do not match syscalls.master.\"\n", $$symbol{syscall};
350 printf $f "#endif\n\n";
351 }
352
353 my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel");
354
355 if($has_arm64) {
356 printf $f "#if defined(__arm64__)\n";
357 printf $f "MI_ENTRY_POINT(%s)\n", $$symbol{asm_sym};
358 if(keys %{$$symbol{mismatch_args}}) {
359 while(my($argnum, $extend) = each %{$$symbol{mismatch_args}}) {
360 printf $f "%s(%d)\n", $extend, $argnum;
361 }
362 }
363
364 printf $f "SYSCALL_NONAME(%s, %d, %s)\n", $$symbol{syscall}, $$symbol{nargs}, $nc;
365 printf $f "ret\n";
366 printf $f "#else\n";
367 }
368
369 if (scalar(@conditions)) {
370 printf $f "#if " . join(" || ", @conditions) . "\n";
371 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
372 if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) {
373 printf $f "#else\n";
374 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
375 }
376 printf $f "#endif\n\n";
377 } else {
378 # actually this isnt an inconsistency. kernel can expose what it wants but if all our arches
379 # override it we need to honour that.
380 }
381
382 if($has_arm64) {
383 printf $f "#endif\n\n";
384 }
385 }
386
387 sub writeAliasesForSymbol {
388 my ($f, $symbol) = @_;
389
390 foreach my $subarch (@Architectures) {
391 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
392 $arch =~ s/x86_64(.*)/x86_64/;
393 $arch =~ s/arm64(.*)/arm64/;
394
395 next unless scalar($$symbol{aliases}{$arch});
396
397 printf $f "#if defined(__${arch}__)\n";
398 foreach my $alias_sym (@{$$symbol{aliases}{$arch}}) {
399 my $sym = (grep { $_ eq $arch } @{$$symbol{except}}) ? "__".$$symbol{asm_sym} : $$symbol{asm_sym};
400
401 printf $f "\t.globl\t$alias_sym\n";
402 printf $f "\t.set\t$alias_sym, $sym\n";
403 }
404 printf $f "#endif\n\n";
405 }
406 }
407
408 usage() unless scalar(@ARGV) == 5;
409 $CustomDir = $ARGV[1];
410 die "$MyName: $CustomDir: No such directory\n" unless -d $CustomDir;
411 $PlatformsDir = $ARGV[2];
412 die "$MyName: $PlatformsDir: No such directory\n" unless -d $PlatformsDir;
413 $PlatformName = $ARGV[3];
414 die "$MyName: $PlatformsDir/$PlatformName: No such directory\n" unless -d "$PlatformsDir/$PlatformName";
415 $OutDir = $ARGV[4];
416 die "$MyName: $OutDir: No such directory\n" unless -d $OutDir;
417
418 readMaster($ARGV[0]);
419 checkForCustomStubs($CustomDir);
420 readAliases($PlatformsDir, $PlatformName);
421
422 ##########################################################################
423 # copy the files specified in @Copy from the $CustomDir to $OutDir
424 ##########################################################################
425 for(@Copy) {
426 my $custom = File::Spec->join($CustomDir, $_);
427 my $path = File::Spec->join($OutDir, $_);
428 print "Copy $custom -> $path\n";
429 File::Copy::copy($custom, $path) || die "$MyName: copy($custom, $path): $!\n";
430 }
431
432 ##########################################################################
433 # make all the *.s files
434 ##########################################################################
435 my @src;
436 my($k, $sym);
437 while (($k, $sym) = each %Symbols)
438 {
439 my $srcname = $$sym{asm_sym} . ".s";
440 my $outpath = File::Spec->join($OutDir, $srcname);
441
442 if ($$sym{is_custom}) {
443 my $custom = File::Spec->join($CustomDir, $$sym{is_custom});
444 File::Copy::copy($custom, $outpath);
445 print "Copied $outpath\n";
446
447 print "Writing aliases for $srcname\n";
448 my $f = IO::File->new($outpath, 'a');
449 die "$MyName: $outpath: $!\n" unless defined($f);
450 writeAliasesForSymbol($f, $sym);
451 undef $f;
452 } else {
453 my $f = IO::File->new($outpath, 'w');
454 die "$MyName: $outpath: $!\n" unless defined($f);
455
456 printf "Creating $outpath\n";
457 writeStubForSymbol($f, $sym);
458 writeAliasesForSymbol($f, $sym);
459 undef $f;
460 }
461 push(@src, $srcname);
462 }
463
464 ##########################################################################
465 # create the Makefile.inc file from the list for files in @src and @CustomSrc
466 ##########################################################################
467 my $path = File::Spec->join($OutDir, 'stubs.list');
468 my $f = IO::File->new($path, 'w');
469 my @sources = sort(@src, @CustomSrc);
470 for my $s (@sources) {
471 printf $f File::Spec->join($OutDir, $s) . "\n";
472 }
473 undef $f;
474 undef $path;
475