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