]> git.saurik.com Git - apple/xnu.git/blame_incremental - libsyscall/xcodescripts/create-syscalls.pl
xnu-4570.1.46.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# Moving towards storing all data in this hash, then we always know
98# if data is aliased or not, or promoted or not.
99my %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.
114my @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
133sub 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##########################################################################
147sub 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
211sub 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 $arch =~ s/arm64(.*)/arm64/;
226 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
227 push(@{$$sym{aliases}{$arch}}, $$sym{asm_sym});
228 }
229 $$sym{asm_sym} = "__".$$sym{asm_sym};
230 $$sym{is_private} = 1;
231 }
232 }
233}
234
235sub readAliases {
236 my ($platformDir, $platformName) = @_;
237 my $genericMap = File::Spec->join($platformDir, "syscall.map");
238
239 my %sym_to_c;
240 foreach my $k (keys %Symbols) {
241 $sym_to_c{$Symbols{$k}{asm_sym}} = $k;
242 }
243
244 my @a = ();
245 for my $arch (@Architectures) {
246 (my $new_arch = $arch) =~ s/arm(v.*)/arm/g;
247 $new_arch =~ s/x86_64(.*)/x86_64/g;
248 $new_arch =~ s/arm64(.*)/arm64/g;
249 push(@a, $new_arch) unless grep { $_ eq $new_arch } @a;
250 }
251
252 foreach my $arch (@a) {
253 my $syscallFile = File::Spec->join($platformDir, $platformName, $arch, "syscall.map");
254
255 my @files = ();
256 push(@files, IO::File->new($syscallFile, 'r'));
257 die "$MyName: $syscallFile: $!\n" unless defined($files[$#files]);
258 push(@files, IO::File->new($genericMap, 'r'));
259 die "$MyName: $genericMap: $!\n" unless defined($files[$#files]);
260
261 foreach my $f (@files) {
262 while (<$f>) {
263 next if /^#/;
264 chomp;
265
266 my ($alias, $target_symbol) = split;
267 if (defined($target_symbol)) {
268 foreach my $sym (values %Symbols) {
269 # I've eliminated most of the ugly from this script except
270 # the need to try stripping underbars here.
271 if ($$sym{is_private}) {
272 next unless $$sym{asm_sym} eq $target_symbol;
273 } else {
274 (my $target = $target_symbol) =~ s/^__//;
275 next unless ($$sym{asm_sym} eq $target || $$sym{asm_sym} eq $target_symbol);
276 }
277 $$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
278
279 die "$MyName: $arch $$sym{asm_sym} -> $alias: Duplicate alias.\n" if grep { $_ eq $alias } @{$$sym{aliases}{$arch}};
280 push(@{$$sym{aliases}{$arch}}, $alias);
281
282 # last thing to do, if we aliased over a first class symbol, we need
283 # to mark it
284 my $c = $sym_to_c{$alias};
285 if ($Symbols{$c}) {
286 push(@{$Symbols{$c}{except}}, $arch);
287 }
288 }
289 }
290 }
291 }
292 }
293}
294
295##########################################################################
296# Make a __xxx.s file: if it exists in the $CustomDir, just copy it, otherwise
297# create one. We define the macro __SYSCALL_32BIT_ARG_BYTES so that SYS.h could
298# use that to define __SYSCALL dependent on the arguments' total size.
299##########################################################################
300sub writeStubForSymbol {
301 my ($f, $symbol) = @_;
302
303 my @conditions;
304 for my $subarch (@Architectures) {
305 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
306 $arch =~ s/x86_64(.*)/x86_64/;
307 $arch =~ s/arm64(.*)/arm64/;
308 push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}};
309 }
310
311 my %is_cancel;
312 for (@Cancelable) { $is_cancel{$_} = 1 };
313
314 print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n";
315 print $f "#include \"SYS.h\"\n\n";
316 if (scalar(@conditions)) {
317 printf $f "#ifndef SYS_%s\n", $$symbol{syscall};
318 printf $f "#error \"SYS_%s not defined. The header files libsyscall is building against do not match syscalls.master.\"\n", $$symbol{syscall};
319 printf $f "#endif\n\n";
320 my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel");
321 printf $f "#if " . join(" || ", @conditions) . "\n";
322 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
323 if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) {
324 printf $f "#else\n";
325 printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
326 }
327 printf $f "#endif\n\n";
328 } else {
329 # actually this isnt an inconsistency. kernel can expose what it wants but if all our arches
330 # override it we need to honour that.
331 }
332}
333
334sub writeAliasesForSymbol {
335 my ($f, $symbol) = @_;
336
337 foreach my $subarch (@Architectures) {
338 (my $arch = $subarch) =~ s/arm(v.*)/arm/;
339 $arch =~ s/x86_64(.*)/x86_64/;
340 $arch =~ s/arm64(.*)/arm64/;
341
342 next unless scalar($$symbol{aliases}{$arch});
343
344 printf $f "#if defined(__${arch}__)\n";
345 foreach my $alias_sym (@{$$symbol{aliases}{$arch}}) {
346 my $sym = (grep { $_ eq $arch } @{$$symbol{except}}) ? "__".$$symbol{asm_sym} : $$symbol{asm_sym};
347
348 printf $f "\t.globl\t$alias_sym\n";
349 printf $f "\t.set\t$alias_sym, $sym\n";
350 }
351 printf $f "#endif\n\n";
352 }
353}
354
355usage() unless scalar(@ARGV) == 5;
356$CustomDir = $ARGV[1];
357die "$MyName: $CustomDir: No such directory\n" unless -d $CustomDir;
358$PlatformsDir = $ARGV[2];
359die "$MyName: $PlatformsDir: No such directory\n" unless -d $PlatformsDir;
360$PlatformName = $ARGV[3];
361die "$MyName: $PlatformsDir/$PlatformName: No such directory\n" unless -d "$PlatformsDir/$PlatformName";
362$OutDir = $ARGV[4];
363die "$MyName: $OutDir: No such directory\n" unless -d $OutDir;
364
365readMaster($ARGV[0]);
366checkForCustomStubs($CustomDir);
367readAliases($PlatformsDir, $PlatformName);
368
369##########################################################################
370# copy the files specified in @Copy from the $CustomDir to $OutDir
371##########################################################################
372for(@Copy) {
373 my $custom = File::Spec->join($CustomDir, $_);
374 my $path = File::Spec->join($OutDir, $_);
375 print "Copy $custom -> $path\n";
376 File::Copy::copy($custom, $path) || die "$MyName: copy($custom, $path): $!\n";
377}
378
379##########################################################################
380# make all the *.s files
381##########################################################################
382my @src;
383my($k, $sym);
384while (($k, $sym) = each %Symbols)
385{
386 my $srcname = $$sym{asm_sym} . ".s";
387 my $outpath = File::Spec->join($OutDir, $srcname);
388
389 if ($$sym{is_custom}) {
390 my $custom = File::Spec->join($CustomDir, $$sym{is_custom});
391 File::Copy::copy($custom, $outpath);
392 print "Copied $outpath\n";
393
394 print "Writing aliases for $srcname\n";
395 my $f = IO::File->new($outpath, 'a');
396 die "$MyName: $outpath: $!\n" unless defined($f);
397 writeAliasesForSymbol($f, $sym);
398 undef $f;
399 } else {
400 my $f = IO::File->new($outpath, 'w');
401 die "$MyName: $outpath: $!\n" unless defined($f);
402
403 printf "Creating $outpath\n";
404 writeStubForSymbol($f, $sym);
405 writeAliasesForSymbol($f, $sym);
406 undef $f;
407 }
408 push(@src, $srcname);
409}
410
411##########################################################################
412# create the Makefile.inc file from the list for files in @src and @CustomSrc
413##########################################################################
414my $path = File::Spec->join($OutDir, 'stubs.list');
415my $f = IO::File->new($path, 'w');
416my @sources = sort(@src, @CustomSrc);
417for my $s (@sources) {
418 printf $f File::Spec->join($OutDir, $s) . "\n";
419}
420undef $f;
421undef $path;
422