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