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 439