]>
Commit | Line | Data |
---|---|---|
6d2010ae A |
1 | #!/usr/bin/perl |
2 | # | |
fe8ab488 | 3 | # Copyright (c) 2006-2014 Apple Inc. All rights reserved. |
6d2010ae A |
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 | # | |
39236c6e | 26 | # % create-syscalls.pl syscalls.master custom-directory platforms-directory platform-name out-directory |
6d2010ae A |
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, | |
3e170ce0 | 64 | 'sae_associd_t' => 4, |
6d2010ae | 65 | 'caddr_t' => 4, |
3e170ce0 | 66 | 'sae_connid_t' => 4, |
6d2010ae A |
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, | |
39236c6e | 94 | 'uuid_t' => 4, |
6d2010ae A |
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. | |
99 | my %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 | ||
316670eb A |
132 | # An explicit list of cancelable syscalls. For creating stubs that call the |
133 | # cancellable version of cerror. | |
134 | my @Cancelable = qw/ | |
135 | accept access aio_suspend | |
39236c6e A |
136 | close connect connectx |
137 | disconnectx | |
fe8ab488 | 138 | faccessat fcntl fdatasync fpathconf fstat fstatat fsync |
316670eb A |
139 | getlogin |
140 | ioctl | |
fe8ab488 | 141 | link linkat lseek lstat |
316670eb | 142 | msgrcv msgsnd msync |
fe8ab488 | 143 | open openat |
39236c6e | 144 | pathconf peeloff poll posix_spawn pread pwrite |
fe8ab488 A |
145 | read readv recvfrom recvmsg rename renameat |
146 | rename_ext | |
316670eb | 147 | __semwait_signal __sigwait |
fe8ab488 A |
148 | select sem_wait semop sendmsg sendto sigsuspend stat symlink symlinkat sync |
149 | unlink unlinkat | |
316670eb A |
150 | wait4 waitid write writev |
151 | /; | |
152 | ||
6d2010ae | 153 | sub usage { |
39236c6e | 154 | die "Usage: $MyName syscalls.master custom-directory platforms-directory platform-name out-directory\n"; |
6d2010ae A |
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 | ########################################################################## | |
167 | sub 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 | ||
231 | sub 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) { | |
316670eb | 243 | (my $arch = $subarch) =~ s/arm(v.*)/arm/; |
fe8ab488 | 244 | $arch =~ s/x86_64(.*)/x86_64/; |
6d2010ae A |
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 | ||
254 | sub 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) { | |
316670eb | 265 | (my $new_arch = $arch) =~ s/arm(v.*)/arm/g; |
fe8ab488 | 266 | $new_arch =~ s/x86_64(.*)/x86_64/g; |
6d2010ae A |
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 | ########################################################################## | |
318 | sub writeStubForSymbol { | |
319 | my ($f, $symbol) = @_; | |
320 | ||
321 | my @conditions; | |
322 | for my $subarch (@Architectures) { | |
316670eb | 323 | (my $arch = $subarch) =~ s/arm(v.*)/arm/; |
fe8ab488 | 324 | $arch =~ s/x86_64(.*)/x86_64/; |
6d2010ae A |
325 | push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}}; |
326 | } | |
316670eb A |
327 | |
328 | my %is_cancel; | |
329 | for (@Cancelable) { $is_cancel{$_} = 1 }; | |
6d2010ae A |
330 | |
331 | print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n"; | |
332 | print $f "#include \"SYS.h\"\n\n"; | |
333 | if (scalar(@conditions)) { | |
39236c6e A |
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"; | |
316670eb | 337 | my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel"); |
6d2010ae | 338 | printf $f "#if " . join(" || ", @conditions) . "\n"; |
316670eb | 339 | printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc; |
6d2010ae A |
340 | if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) { |
341 | printf $f "#else\n"; | |
316670eb | 342 | printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc; |
6d2010ae A |
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 | ||
351 | sub writeAliasesForSymbol { | |
352 | my ($f, $symbol) = @_; | |
353 | ||
354 | foreach my $subarch (@Architectures) { | |
316670eb | 355 | (my $arch = $subarch) =~ s/arm(v.*)/arm/; |
fe8ab488 | 356 | $arch =~ s/x86_64(.*)/x86_64/; |
6d2010ae A |
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 | ||
371 | usage() unless scalar(@ARGV) == 5; | |
372 | $CustomDir = $ARGV[1]; | |
373 | die "$MyName: $CustomDir: No such directory\n" unless -d $CustomDir; | |
374 | $PlatformsDir = $ARGV[2]; | |
375 | die "$MyName: $PlatformsDir: No such directory\n" unless -d $PlatformsDir; | |
376 | $PlatformName = $ARGV[3]; | |
377 | die "$MyName: $PlatformsDir/$PlatformName: No such directory\n" unless -d "$PlatformsDir/$PlatformName"; | |
378 | $OutDir = $ARGV[4]; | |
379 | die "$MyName: $OutDir: No such directory\n" unless -d $OutDir; | |
380 | ||
381 | readMaster($ARGV[0]); | |
382 | checkForCustomStubs($CustomDir); | |
383 | readAliases($PlatformsDir, $PlatformName); | |
384 | ||
385 | ########################################################################## | |
386 | # copy the files specified in @Copy from the $CustomDir to $OutDir | |
387 | ########################################################################## | |
388 | for(@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 | ########################################################################## | |
398 | my @src; | |
399 | my($k, $sym); | |
400 | while (($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 | ########################################################################## | |
430 | my $path = File::Spec->join($OutDir, 'stubs.list'); | |
431 | my $f = IO::File->new($path, 'w'); | |
432 | my @sources = sort(@src, @CustomSrc); | |
433 | for my $s (@sources) { | |
434 | printf $f File::Spec->join($OutDir, $s) . "\n"; | |
435 | } | |
436 | undef $f; | |
437 | undef $path; | |
438 |