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