#!/usr/bin/perl
#
-# Copyright (c) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (c) 2006-2014 Apple Inc. All rights reserved.
#
# @APPLE_OSREFERENCE_LICENSE_HEADER_START@
#
#
##########################################################################
#
-# % create-syscalls.pl syscalls.master custom-directory out-directory
+# % create-syscalls.pl syscalls.master custom-directory platforms-directory platform-name out-directory
#
# This script fills the the out-directory with a Makefile.inc and *.s
# files to create the double-underbar syscall stubs. It reads the
# size in bytes of known types (only used for i386)
my %TypeBytes = (
'au_asid_t' => 4,
+ 'sae_associd_t' => 4,
'caddr_t' => 4,
+ 'sae_connid_t' => 4,
'gid_t' => 4,
'id_t' => 4,
'idtype_t' => 4,
'user_size_t' => 4,
'user_ssize_t' => 4,
'user_ulong_t' => 4,
+ 'uuid_t' => 4,
+);
+
+# Types that potentially have different sizes in user-space compared to
+# kernel-space as well as whether the value should be sign/zero-extended when
+# passing the user/kernel boundary.
+my %UserKernelMismatchTypes = (
+ 'long' => 'SIGN_EXTEND',
+ 'size_t' => 'ZERO_EXTEND',
+ 'u_long' => 'ZERO_EXTEND',
+ 'user_size_t' => 'ZERO_EXTEND',
+ 'user_ssize_t' => 'SIGN_EXTEND'
);
# Moving towards storing all data in this hash, then we always know
# if data is aliased or not, or promoted or not.
my %Symbols = (
- "quota" => {
- c_sym => "quota",
- syscall => "quota",
- asm_sym => "_quota",
- is_private => undef,
- is_custom => undef,
- nargs => 4,
- bytes => 0,
- aliases => {},
- },
- "setquota" => {
- c_sym => "setquota",
- syscall => "setquota",
- asm_sym => "_setquota",
- is_private => undef,
- is_custom => undef,
- nargs => 2,
- bytes => 0,
- aliases => {},
- },
"syscall" => {
c_sym => "syscall",
syscall => "syscall",
nargs => 0,
bytes => 0,
aliases => {},
+ mismatch_args => {}, # Arguments that might need to be zero/sign-extended
},
);
+# An explicit list of cancelable syscalls. For creating stubs that call the
+# cancellable version of cerror.
+my @Cancelable = qw/
+ accept access aio_suspend
+ close connect connectx
+ disconnectx
+ faccessat fcntl fdatasync fpathconf fstat fstatat fsync
+ getlogin
+ ioctl
+ link linkat lseek lstat
+ msgrcv msgsnd msync
+ open openat
+ pathconf peeloff poll posix_spawn pread pselect pwrite
+ read readv recvfrom recvmsg rename renameat
+ rename_ext
+ __semwait_signal __sigwait
+ select sem_wait semop sendmsg sendto sigsuspend stat symlink symlinkat sync
+ unlink unlinkat
+ wait4 waitid write writev
+/;
+
sub usage {
- die "Usage: $MyName syscalls.master custom-directory platforms-directory out-directory\n";
+ die "Usage: $MyName syscalls.master custom-directory platforms-directory platform-name out-directory\n";
}
##########################################################################
# Read the syscall.master file and collect the system call names and number
# of arguments. It looks for the NO_SYSCALL_STUB quailifier following the
# prototype to determine if no automatic stub should be created by Libsystem.
-# System call name that are already prefixed with double-underbar are set as
-# if the NO_SYSCALL_STUB qualifier were specified (whether it is or not).
+#
+# The `sys_` prefix is stripped from syscall names, and is only kept for
+# the kernel symbol in order to avoid namespace clashes and identify
+# syscalls more easily.
#
# For the #if lines in syscall.master, all macros are assumed to be defined,
# except COMPAT_GETFSSTAT (assumed undefined).
my $no_syscall_stub = /\)\s*NO_SYSCALL_STUB\s*;/;
my($name, $args) = /\s(\S+)\s*\(([^)]*)\)/;
next if $name =~ /e?nosys/;
+ $name =~ s/^sys_//;
$args =~ s/^\s+//;
$args =~ s/\s+$//;
my $argbytes = 0;
my $nargs = 0;
+ my %mismatch_args;
if($args ne '' && $args ne 'void') {
my @a = split(',', $args);
$nargs = scalar(@a);
- # Calculate the size of all the arguments (only used for i386)
+ my $index = 0;
for my $type (@a) {
$type =~ s/\s*\w+$//; # remove the argument name
+
+ # Calculate the size of all the arguments (only used for i386)
if($type =~ /\*$/) {
$argbytes += 4; # a pointer type
} else {
die "$MyName: $name: unknown type '$type'\n" unless defined($b);
$argbytes += $b;
}
+ # Determine which arguments might need to be zero/sign-extended
+ if(exists $UserKernelMismatchTypes{$type}) {
+ $mismatch_args{$index} = $UserKernelMismatchTypes{$type};
+ }
+
+ $index++;
}
}
$Symbols{$name} = {
nargs => $nargs,
bytes => $argbytes,
aliases => {},
+ mismatch_args => \%mismatch_args, # Arguments that might need to be zero/sign-extended
except => [],
};
}
$$sym{is_custom} = $source;
if (!$$sym{is_private}) {
foreach my $subarch (@Architectures) {
- (my $arch = $subarch) =~ s/arm(.*)/arm/;
+ (my $arch = $subarch) =~ s/arm(v.*)/arm/;
+ $arch =~ s/x86_64(.*)/x86_64/;
+ $arch =~ s/arm64(.*)/arm64/;
$$sym{aliases}{$arch} = [] unless $$sym{aliases}{$arch};
push(@{$$sym{aliases}{$arch}}, $$sym{asm_sym});
}
my @a = ();
for my $arch (@Architectures) {
- (my $new_arch = $arch) =~ s/arm(.*)/arm/g;
+ (my $new_arch = $arch) =~ s/arm(v.*)/arm/g;
+ $new_arch =~ s/x86_64(.*)/x86_64/g;
+ $new_arch =~ s/arm64(.*)/arm64/g;
push(@a, $new_arch) unless grep { $_ eq $new_arch } @a;
}
my ($f, $symbol) = @_;
my @conditions;
+ my $has_arm64 = 0;
for my $subarch (@Architectures) {
- (my $arch = $subarch) =~ s/arm(.*)/arm/;
+ (my $arch = $subarch) =~ s/arm(v.*)/arm/;
+ $arch =~ s/x86_64(.*)/x86_64/;
+ $arch =~ s/arm64(.*)/arm64/;
push(@conditions, "defined(__${arch}__)") unless grep { $_ eq $arch } @{$$symbol{except}};
+
+ if($arch eq "arm64") {
+ $has_arm64 = 1 unless grep { $_ eq $arch } @{$$symbol{except}};
+ }
}
-
+
+ my %is_cancel;
+ for (@Cancelable) { $is_cancel{$_} = 1 };
+
print $f "#define __SYSCALL_32BIT_ARG_BYTES $$symbol{bytes}\n";
print $f "#include \"SYS.h\"\n\n";
+
+ if (scalar(@conditions)) {
+ printf $f "#ifndef SYS_%s\n", $$symbol{syscall};
+ printf $f "#error \"SYS_%s not defined. The header files libsyscall is building against do not match syscalls.master.\"\n", $$symbol{syscall};
+ printf $f "#endif\n\n";
+ }
+
+ my $nc = ($is_cancel{$$symbol{syscall}} ? "cerror" : "cerror_nocancel");
+
+ if($has_arm64) {
+ printf $f "#if defined(__arm64__)\n";
+ printf $f "MI_ENTRY_POINT(%s)\n", $$symbol{asm_sym};
+ if(keys %{$$symbol{mismatch_args}}) {
+ while(my($argnum, $extend) = each %{$$symbol{mismatch_args}}) {
+ printf $f "%s(%d)\n", $extend, $argnum;
+ }
+ }
+
+ printf $f "SYSCALL_NONAME(%s, %d, %s)\n", $$symbol{syscall}, $$symbol{nargs}, $nc;
+ printf $f "ret\n";
+ printf $f "#else\n";
+ }
+
if (scalar(@conditions)) {
printf $f "#if " . join(" || ", @conditions) . "\n";
- printf $f "__SYSCALL(%s, %s, %d)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs};
+ printf $f "__SYSCALL2(%s, %s, %d, %s)\n", $$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
if (!$$symbol{is_private} && (scalar(@conditions) < scalar(@Architectures))) {
printf $f "#else\n";
- printf $f "__SYSCALL(%s, %s, %d)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs};
+ printf $f "__SYSCALL2(%s, %s, %d, %s)\n", "__".$$symbol{asm_sym}, $$symbol{syscall}, $$symbol{nargs}, $nc;
}
printf $f "#endif\n\n";
} else {
# actually this isnt an inconsistency. kernel can expose what it wants but if all our arches
# override it we need to honour that.
}
+
+ if($has_arm64) {
+ printf $f "#endif\n\n";
+ }
}
sub writeAliasesForSymbol {
my ($f, $symbol) = @_;
foreach my $subarch (@Architectures) {
- (my $arch = $subarch) =~ s/arm(.*)/arm/;
+ (my $arch = $subarch) =~ s/arm(v.*)/arm/;
+ $arch =~ s/x86_64(.*)/x86_64/;
+ $arch =~ s/arm64(.*)/arm64/;
next unless scalar($$symbol{aliases}{$arch});