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