Here's a new patch, mostly for sthen@'s obvious fix, although I have added some of gkoehler@'s suggestions, although I have some questions and comments inline.
I am looking at some of the other suggestions, but they showed up while I was testing this set. One thing to note, on the advice of miod@, I adjusted the mapping of size_t from u_int to u_long, but that means we no longer recognize getlogin_r. When I asked, miod@ suggested that syscalls.master was confused. $ grep getlogin_r /usr/src/sys/kern/syscalls.master /usr/include/unistd.h /usr/src/sys/kern/syscalls.master:141 STD { int sys_getlogin_r(char *namebuf, u_int namelen); } /usr/include/unistd.h:int getlogin_r(char *, size_t) On Thu, Jul 13, 2023 at 07:38:22AM +0100, Stuart Henderson wrote: > On 2023/07/13 00:57, George Koehler wrote: > > On Sun, 9 Jul 2023 13:29:58 -0700 > > Andrew Hewus Fresh <and...@afresh1.com> wrote: > > > > > Here is a patch to replace perl(1)'s use of syscall(2) with a dispatcher > > > that will call the libc function instead. > > > > patch(1) didn't "chmod +x gen_syscall_emulator.pl", but I needed to > > do so to get around this this error, > > There shouldn't be 'x' bits in files committed to the tree, so the > Makefile should explicitly run this with perl. Oops, fixed! On Mon, Jul 17, 2023 at 11:54:18PM -0400, George Koehler wrote: > I prefer braces like this, > > case SYS_truncate: { > ... > break; > } Easy enough, I didn't see that called out in style(9). > In my opinion, all va_arg()s should look like > > off_t length = (off_t)va_arg(args, long); > > because perl passes every argument as long (from pp_syscall in > pp_sys.c). I worry that va_arg(args, off_t) would act strangely > on platforms with 32-bit long and 64-bit off_t. Only a few syscalls > have off_t arguments, and these few calls are almost useless in Perl, > so this might not affect real programs. > > How to pread($fd, $buf, 4, 16)? > > 1. syscall(169, $fd, $buf, 4, 0, 16) > 2. syscall(169, $fd, $buf, 4, 0, 0, 16) > 3. syscall(169, $fd, $buf, 4, 16, 0) > 4. syscall(169, $fd, $buf, 4, 0, 16, 0) > 5. syscall(169, $fd, $buf, 4, 16) > > If va_args(args, off_t) takes 2 longs, then pick line 1 if big-endian, > or line 3 if little-endian. If it skips a 3rd long for alignment, > then pick line 2 or 4. If it takes 1 long, then pick line 5. > > If we (off_t)va_args(args, long), then it always takes 1 long, so > every platform picks line 5, but the offset must fit in a long. Which is the way it works without the this middleman? On Wed, Jul 19, 2023 at 03:58:25PM -0400, George Koehler wrote: > On Sun, 9 Jul 2023 13:29:58 -0700 > Andrew Hewus Fresh <and...@afresh1.com> wrote: > > > +syscall_emulator.h Emulator to dispatch syscalls to libc > > This got installed as > /usr/libdata/perl5/powerpc64-openbsd/CORE/syscall_emulator.h I was wondering about why there was a list of headers in the Makefile, I went cross eyed while trying to track that down, I'm testing what I expect will remove that now. > ExtUtils::MakeMaker is using cc -DHAS_SYSCALL_EMULATOR to build my XS > module; the define causes <perl.h> to #include <syscall_emulator.h>. Oh right, I forgot that I hacked that in as I tried to figure out _where_ I should do that. I will tidy that up too. > Can we hide this feature from XS? I wish that only pp_sys.c and > syscall_emulator.c would #include <syscall_emulator.h>, that > syscall_emulator.h would not be installed, and that > -DHAS_SYSCALL_EMULATOR would not appear in non-core modules. I can just patch it in without the define. I may have to do a bit more when syscall is actually removed, since Configure probes for it, but I _think_ I found the right define to do that, but it always takes me too long staring at this before it makes sense and I've been kept too busy away from computers to do that these last couple weeks. Preliminary testing tells me it probably works. > Also, the new test has a heap overflow, because $sb is too small for > a struct stat, > > $ cd /usr/src/gnu/usr.bin/perl/obj > $ MALLOC_OPTIONS=S perl t/op/syscall_emulator.t > /usr/include/sys/syscall.h -> /usr/include/sys/syscall.ph > 1..13 > ok 1 - Opened test.txt for write/create > ok 2 - Wrote out to test.txt > ok 3 - closed test.txt > perl(15511) in malloc(): write after free 0xc36d1efcddc0 > Abort trap (core dumped) Hmm, I guess I need to get a powerpc64 machine. > I prevented the overflow by making $sb too big, > > --- t/op/syscall_emulator.t.before Thu Jul 13 00:39:10 2023 > +++ t/op/syscall_emulator.t Wed Jul 19 15:32:40 2023 > @@ -47,7 +47,7 @@ > my $out = "Hello World\n"; > my $in = "\0" x 32; > my ($in_p, $in_v); > -my $sb = "\0\0\0\0"; > +my $sb = "\0" x 4096; > my $st_mode; > > my $perms = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; I applied this too. Thanks! On Wed, Jul 19, 2023 at 05:26:22PM -0600, Theo de Raadt wrote: > -my $sb = "\0\0\0\0"; > +my $sb = "\0" x 4096; > > That's pretty terrible. Does this language not have types? Of course! It has all three types: scalars, arrays, and hashes. :-D Index: gnu/usr.bin/perl/MANIFEST =================================================================== RCS file: /home/afresh1/OpenBSD-perl/OP/cvs/src/gnu/usr.bin/perl/MANIFEST,v retrieving revision 1.67 diff -u -p -a -u -p -r1.67 MANIFEST --- gnu/usr.bin/perl/MANIFEST 8 Jul 2023 14:18:35 -0000 1.67 +++ gnu/usr.bin/perl/MANIFEST 20 Jul 2023 04:14:30 -0000 @@ -6151,6 +6151,8 @@ SECURITY.md Add Security Policy for Gi sv.c Scalar value code sv.h Scalar value header sv_inline.h Perl_newSV_type and required defs +syscall_emulator.c Emulator to dispatch syscalls to libc +syscall_emulator.h Emulator to dispatch syscalls to libc t/base/cond.t See if conditionals work t/base/if.t See if if works t/base/lex.t See if lexical items work @@ -6605,6 +6607,7 @@ t/op/svleak.pl Test file for svleak.t t/op/svleak.t See if stuff leaks SVs t/op/switch.t See if switches (given/when) work t/op/symbolcache.t See if undef/delete works on stashes with functions +t/op/syscall_emulator.t Tests that syscall works via the emulator t/op/sysio.t See if sysread and syswrite work t/op/taint.t See if tainting works t/op/threads.t Misc. tests for perl features with threads Index: gnu/usr.bin/perl/Makefile.SH =================================================================== RCS file: /home/afresh1/OpenBSD-perl/OP/cvs/src/gnu/usr.bin/perl/Makefile.SH,v retrieving revision 1.60 diff -u -p -a -u -p -r1.60 Makefile.SH --- gnu/usr.bin/perl/Makefile.SH 8 Jul 2023 14:18:35 -0000 1.60 +++ gnu/usr.bin/perl/Makefile.SH 20 Jul 2023 04:14:30 -0000 @@ -534,14 +534,14 @@ h2 = embed.h form.h gv.h handy.h hv.h hv h3 = pad.h patchlevel.h perl.h perlapi.h perly.h pp.h proto.h regcomp.h h4 = regexp.h scope.h sv.h unixish.h util.h iperlsys.h thread.h h5 = utf8.h warnings.h mydtrace.h op_reg_common.h l1_char_class_tab.h -h6 = charclass_invlists.h +h6 = charclass_invlists.h syscall_emulator.h h = $(h1) $(h2) $(h3) $(h4) $(h5) $(h6) c1 = av.c scope.c op.c doop.c doio.c dump.c gv.c hv.c mg.c reentr.c mro_core.c perl.c c2 = perly.c pp.c pp_hot.c pp_ctl.c pp_sys.c regcomp.c regexec.c utf8.c sv.c c3 = taint.c toke.c util.c deb.c run.c builtin.c universal.c pad.c globals.c keywords.c c4 = perlio.c numeric.c mathoms.c locale.c pp_pack.c pp_sort.c caretx.c dquote.c time64.c -c5 = $(mallocsrc) +c5 = $(mallocsrc) syscall_emulator.c !NO!SUBS! @@ -557,7 +557,7 @@ c = $(c1) $(c2) $(c3) $(c4) $(c5) minipe obj1 = $(mallocobj) gv$(OBJ_EXT) toke$(OBJ_EXT) perly$(OBJ_EXT) pad$(OBJ_EXT) regcomp$(OBJ_EXT) dump$(OBJ_EXT) util$(OBJ_EXT) mg$(OBJ_EXT) reentr$(OBJ_EXT) mro_core$(OBJ_EXT) keywords$(OBJ_EXT) builtin$(OBJ_EXT) obj2 = hv$(OBJ_EXT) av$(OBJ_EXT) run$(OBJ_EXT) pp_hot$(OBJ_EXT) sv$(OBJ_EXT) pp$(OBJ_EXT) scope$(OBJ_EXT) pp_ctl$(OBJ_EXT) pp_sys$(OBJ_EXT) -obj3 = doop$(OBJ_EXT) doio$(OBJ_EXT) regexec$(OBJ_EXT) utf8$(OBJ_EXT) taint$(OBJ_EXT) deb$(OBJ_EXT) globals$(OBJ_EXT) perlio$(OBJ_EXT) numeric$(OBJ_EXT) mathoms$(OBJ_EXT) locale$(OBJ_EXT) pp_pack$(OBJ_EXT) pp_sort$(OBJ_EXT) caretx$(OBJ_EXT) dquote$(OBJ_EXT) time64$(OBJ_EXT) +obj3 = doop$(OBJ_EXT) doio$(OBJ_EXT) regexec$(OBJ_EXT) utf8$(OBJ_EXT) taint$(OBJ_EXT) deb$(OBJ_EXT) globals$(OBJ_EXT) perlio$(OBJ_EXT) numeric$(OBJ_EXT) mathoms$(OBJ_EXT) locale$(OBJ_EXT) pp_pack$(OBJ_EXT) pp_sort$(OBJ_EXT) caretx$(OBJ_EXT) dquote$(OBJ_EXT) time64$(OBJ_EXT) syscall_emulator$(OBJ_EXT) # split the objects into 3 exclusive sets: those used by both miniperl and # perl, and those used by just one or the other. Doesn't include the Index: gnu/usr.bin/perl/Makefile.bsd-wrapper =================================================================== RCS file: /home/afresh1/OpenBSD-perl/OP/cvs/src/gnu/usr.bin/perl/Makefile.bsd-wrapper,v retrieving revision 1.113 diff -u -p -a -u -p -r1.113 Makefile.bsd-wrapper --- gnu/usr.bin/perl/Makefile.bsd-wrapper 15 Feb 2023 01:38:20 -0000 1.113 +++ gnu/usr.bin/perl/Makefile.bsd-wrapper 20 Jul 2023 04:14:30 -0000 @@ -39,11 +39,15 @@ cleandir: fi cd ${.CURDIR} && ${MAKE} -f Makefile.bsd-wrapper1 cleandir -all: config.sh +all: syscall_emulator.c config.sh cd ${.CURDIR} && exec ${MAKE} -f Makefile.bsd-wrapper1 perl.build cd ${.CURDIR} && exec ${MAKE} -f Makefile.bsd-wrapper1 mansrc.build install: cd ${.CURDIR} && exec ${MAKE} -f Makefile.bsd-wrapper1 install + + +syscall_emulator.c: gen_syscall_emulator.pl /usr/include/sys/syscall.h /usr/include/sys/syscallargs.h + /usr/bin/perl $(.CURDIR)/gen_syscall_emulator.pl > $@ .include <bsd.obj.mk> Index: gnu/usr.bin/perl/config.over =================================================================== RCS file: /home/afresh1/OpenBSD-perl/OP/cvs/src/gnu/usr.bin/perl/config.over,v retrieving revision 1.22 diff -u -p -a -u -p -r1.22 config.over --- gnu/usr.bin/perl/config.over 5 Feb 2017 00:33:38 -0000 1.22 +++ gnu/usr.bin/perl/config.over 20 Jul 2023 04:14:30 -0000 @@ -64,3 +64,10 @@ myuname='openbsd' # force to use ranlib ranlib='ranlib' + +# Enable the syscall emulator, +# enabling syscall even if we don't have it +ccflags="-DHAS_SYSCALL_EMULATOR $ccflags" +d_syscall=define +d_syscallproto=define + Index: gnu/usr.bin/perl/gen_syscall_emulator.pl =================================================================== RCS file: gnu/usr.bin/perl/gen_syscall_emulator.pl diff -N gnu/usr.bin/perl/gen_syscall_emulator.pl --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/usr.bin/perl/gen_syscall_emulator.pl 20 Jul 2023 04:14:32 -0000 @@ -0,0 +1,354 @@ +#!/usr/bin/perl +# $OpenBSD$ # +use v5.36; + +# Copyright (c) 2023 Andrew Hewus Fresh <afre...@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +my $includes = '/usr/include'; + +# See also /usr/src/sys/kern/syscalls.master +my %syscalls = parse_syscalls( + "$includes/sys/syscall.h", + "$includes/sys/syscallargs.h", +); +delete $syscalls{MAXSYSCALL}; # not an actual function + +# The ordered list of all the headers we need +my @headers = qw< + sys/syscall.h + stdarg.h + errno.h + + sys/socket.h + sys/event.h + sys/futex.h + sys/ioctl.h + sys/ktrace.h + sys/mman.h + sys/mount.h + sys/msg.h + sys/poll.h + sys/ptrace.h + sys/resource.h + sys/select.h + sys/sem.h + sys/shm.h + sys/stat.h + sys/sysctl.h + sys/time.h + sys/uio.h + sys/wait.h + + dirent.h + fcntl.h + sched.h + signal.h + stdlib.h + stdio.h + syslog.h + tib.h + time.h + unistd.h +>; + +foreach my $header (@headers) { + my $file = "$includes/$header"; + open my $fh, '<', $file or die "Unable to open $file: $!"; + my $content = do { local $/; readline $fh }; + close $fh; + + # Look for matching syscalls in this header + foreach my $name (sort keys %syscalls) { + my $s = $syscalls{$name}; + my $func_sig = find_func_sig($content, $name, $s); + + if (ref $func_sig) { + die "Multiple defs for $name <$header> <$s->{header}>" + if $s->{header}; + $s->{func} = $func_sig; + $s->{header} = $header; + } elsif ($func_sig) { + $s->{mismatched_sig} = "$func_sig <$header>"; + } + } +} + +say "/*\n * Generated from gen_syscall_emulator.pl\n */"; +say "#include <$_>" for @headers; +print <<"EOL"; + +long +syscall_emulator(int syscall, ...) +{ + long ret = 0; + va_list args; + va_start(args, syscall); + + switch(syscall) { +EOL + +foreach my $name ( + sort { $syscalls{$a}{id} <=> $syscalls{$b}{id} } keys %syscalls + ) { + my %s = %{ $syscalls{$name} }; + + # Some syscalls we can't emulate, so we comment those out. + $s{skip} //= "Indirect syscalls not supported" + if !$s{argtypes} && ($s{args}[-1] || '') eq '...'; + $s{skip} //= "Mismatched func: $s{mismatched_sig}" + if $s{mismatched_sig} and not $s{func}; + $s{skip} //= "No signature found in headers" + unless $s{header}; + + my $ret = $s{ret} eq 'void' ? '' : 'ret = '; + $ret .= '(long)' if $s{ret} eq 'void *'; + + my (@args, @defines); + my $argname = ''; + if ($s{argtypes}) { + if (@{ $s{argtypes} } > 1) { + @defines = map { + my $t = $_->{type}; + my $n = $_->{name}; + $n = "_$n" if $n eq $name; # link :-/ + push @args, $n; + "$t $n = va_arg(args, $t);" + } @{ $s{argtypes} }; + } else { + if (@{ $s{argtypes} }) { + $argname = " // " . join ', ', + map { $_->{name} } + @{ $s{argtypes} }; + } + @args = map { "va_arg(args, $_->{type})" } + @{ $s{argtypes} }; + } + } else { + @args = @{ $s{args} }; + + # If we didn't find args in syscallargs.h but have args + # we don't know how to write our function. + $s{skip} //= "Not found in sys/syscallargs.h" + if @args; + } + + #my $header = $s{header} ? " <$s{header}>" : ''; + + my $indent = "\t"; + say "$indent/* $s{skip}" if $s{skip}; + + $indent .= ' *' if $s{skip}; + say "${indent} $s{signature} <sys/syscall.h>" + if $s{skip} && $s{skip} =~ /Mismatch/; + + my $brace = @defines ? " {" : ""; + say "${indent}case $s{define}:$brace"; # // $s{id}"; + say "${indent}\t$_" for @defines; + #say "${indent}\t// $s{signature}$header"; + say "${indent}\t$ret$name(" . join(', ', @args) . ");$argname"; + say "${indent}\tbreak;"; + say "${indent}}" if $brace; + + say "\t */" if $s{skip}; +} + +print <<"EOL"; + default: + ret = -1; + errno = ENOSYS; + } + va_end(args); + + return ret; +} +EOL + + +sub parse_syscalls ($syscall, $args) +{ + my %s = parse_syscall_h($syscall); + + my %a = parse_syscallargs_h($args); + $s{$_}{argtypes} = $a{$_} for grep { $a{$_} } keys %s; + + return %s; +} + +sub parse_syscall_h ($file) +{ + my %s; + open my $fh, '<', $file or die "Unable to open $file: $!"; + while ($_ = $fh->getline) { + if (m{^/\* + \s+ syscall: \s+ "(?<name>[^"]+)" + \s+ ret: \s+ "(?<ret> [^"]+)" + \s+ args: \s+ (?<args>.*?) + \s* \*/ + | + ^\#define \s+ (?<define>SYS_(?<name>\S+)) \s+ (?<id>\d+) + }x) { + my $name = $+{name}; + $s{$name}{$_} = $+{$_} for keys %+; + $s{$name}{args} = [ $+{args} =~ /"(.*?)"/g ] + if exists $+{args}; + } + } + close $fh or die "Unable to close $file: $!"; + + foreach my $name (keys %s) { + my %d = %{ $s{$name} }; + next unless $d{ret}; # the MAXSYSCALL + + my $ret = $d{ret}; + my @args = @{ $d{args} || [] }; + @args = 'void' unless @args; + + if ($args[-1] ne '...') { + my @a; + for (@args) { + push @a, $_; + last if $_ eq '...'; + } + @args = @a; + } + + my $args = join ", ", @args; + $s{$name}{signature} = "$ret\t$name($args);" =~ s/\s+/ /gr; + #print " $s{$name}{signature}\n"; + } + + return %s; +} + +sub _parse_syscallarg ($fh) +{ + my @a; + while ($_ = $fh->getline) { + last if /^\s*\};\s*$/; + if (/syscallarg\( ( [^)]+ ) \) \s+ (\w+) \s* ;/x) { + push @a, { type => $1, name => $2 }; + } + } + return \@a; +} + +sub parse_syscallargs_h ($file) +{ + my %a; + open my $fh, '<', $file or die "Unable to open $file; $!"; + while ($_ = $fh->getline) { + if (/^struct sys_(\w+)_args \{/) { + my $name = $1; + $a{$name} = _parse_syscallarg($fh); + } + } + close $fh; + return %a; +} + +sub find_func_sig ($content, $name, $s) +{ + my $re = $s->{re} //= qr{^ + (?<ret> \S+ (?: [^\S\n]+ \S+)? ) [^\S\n]* \n? + \b \Q$name\E \( (?<args> [^)]* ) \) + [^;]*;}xms; + + $content =~ /$re/ || return; + my $ret = $+{ret}; + my $args = $+{args}; + + for ($ret, $args) { + s/^\s+//; + s/\s+$//; + s/\s+/ /g; + } + + # The actual functions may have this extra annotation + $args =~ s/\*\s*__restrict/*/g; + + my %func_sig = ( ret => $ret, args => [ split /\s*,\s*/, $args ] ); + + return "$ret $name($args);" =~ s/\s+/ /gr + unless sigs_match( $s, \%func_sig ); + + return \%func_sig; +} + +# Tests whether two types are equivalent. +# Sometimes there are two ways to represent the same thing +# and it seems the functions and the syscalls +# differ a fair amount. +{ +my %m; BEGIN { %m = ( + caddr_t => 'char *', + idtype_t => 'int', + nfds_t => 'u_int', + __off_t => 'off_t', + pid_t => 'int', + __size_t => 'u_long', + size_t => 'u_long', + 'unsigned int' => 'u_int', + 'unsigned long' => 'u_long', +) } +sub types_match ($l, $r) +{ + $l //= '__undef__'; + $r //= '__undef__'; + + s/^volatile // for $l, $r; + s/^const // for $l, $r; + s/\s*\[\d*\]$/ \*/ for $l, $r; + + my ($f, $s) = sort { length($a) <=> length($b) } $l, $r; + if (index($s,$f) == 0) { + $s =~ s/^\Q$f\E\s*//; + if ( $s && $s =~ /^\w+$/ ) { + #warn "prefix ['$f', '$s']\n"; + s/\s*\Q$s\E$// for $l, $r; + } + } + + # my ($p_l, $p_r) = ($l, $r); + $l = $m{$l} //= $l; + $r = $m{$r} //= $r; + + #warn " $p_l [$l] $p_r [$r] <'$f' '$s'>\n"; + # return and use the original "right" value + # as it's from the function header and closer to what we need. + return $l eq $r; +} +} + + +# Tests whether two function signatures match, +# expected to be left from syscall.h, right from the appopriate header. +sub sigs_match ($l, $r) +{ + return unless types_match( $l->{ret}, $l->{ret} ); + + my @l_args = @{ $l->{args} || [] }; + my @r_args = @{ $r->{args} || [] }; + + for (\@l_args, \@r_args) { + @{$_} = 'void' unless @{$_}; + } + + for my $i ( 0 .. $#l_args ) { + return unless types_match( $l_args[$i], $r_args[$i] ); + last if $l_args[$i] eq '...'; + } + + return 1; +} Index: gnu/usr.bin/perl/perl.h =================================================================== RCS file: /home/afresh1/OpenBSD-perl/OP/cvs/src/gnu/usr.bin/perl/perl.h,v retrieving revision 1.28 diff -u -p -a -u -p -r1.28 perl.h --- gnu/usr.bin/perl/perl.h 15 Feb 2023 01:36:13 -0000 1.28 +++ gnu/usr.bin/perl/perl.h 20 Jul 2023 04:14:33 -0000 @@ -1152,6 +1152,11 @@ extern char **myenviron; EXTERN_C int syscall(int, ...); #endif +#ifdef HAS_SYSCALL_EMULATOR +#include "syscall_emulator.h" +#define syscall syscall_emulator +#endif + #if defined(HAS_USLEEP) && !defined(HAS_USLEEP_PROTO) EXTERN_C int usleep(unsigned int); #endif Index: gnu/usr.bin/perl/syscall_emulator.c =================================================================== RCS file: gnu/usr.bin/perl/syscall_emulator.c diff -N gnu/usr.bin/perl/syscall_emulator.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/usr.bin/perl/syscall_emulator.c 20 Jul 2023 04:14:33 -0000 @@ -0,0 +1,1419 @@ +/* + * Generated from gen_syscall_emulator.pl + */ +#include <sys/syscall.h> +#include <stdarg.h> +#include <errno.h> +#include <sys/socket.h> +#include <sys/event.h> +#include <sys/futex.h> +#include <sys/ioctl.h> +#include <sys/ktrace.h> +#include <sys/mman.h> +#include <sys/mount.h> +#include <sys/msg.h> +#include <sys/poll.h> +#include <sys/ptrace.h> +#include <sys/resource.h> +#include <sys/select.h> +#include <sys/sem.h> +#include <sys/shm.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/wait.h> +#include <dirent.h> +#include <fcntl.h> +#include <sched.h> +#include <signal.h> +#include <stdlib.h> +#include <stdio.h> +#include <syslog.h> +#include <tib.h> +#include <time.h> +#include <unistd.h> + +long +syscall_emulator(int syscall, ...) +{ + long ret = 0; + va_list args; + va_start(args, syscall); + + switch(syscall) { + /* Indirect syscalls not supported + *case SYS_syscall: + * ret = syscall(int, ...); + * break; + */ + case SYS_exit: + exit(va_arg(args, int)); // rval + break; + case SYS_fork: + ret = fork(); + break; + case SYS_read: { + int fd = va_arg(args, int); + void * buf = va_arg(args, void *); + size_t nbyte = va_arg(args, size_t); + ret = read(fd, buf, nbyte); + break; + } + case SYS_write: { + int fd = va_arg(args, int); + const void * buf = va_arg(args, const void *); + size_t nbyte = va_arg(args, size_t); + ret = write(fd, buf, nbyte); + break; + } + case SYS_open: { + const char * path = va_arg(args, const char *); + int flags = va_arg(args, int); + mode_t mode = va_arg(args, mode_t); + ret = open(path, flags, mode); + break; + } + case SYS_close: + ret = close(va_arg(args, int)); // fd + break; + case SYS_getentropy: { + void * buf = va_arg(args, void *); + size_t nbyte = va_arg(args, size_t); + ret = getentropy(buf, nbyte); + break; + } + /* No signature found in headers + *case SYS___tfork: { + * const struct __tfork * param = va_arg(args, const struct __tfork *); + * size_t psize = va_arg(args, size_t); + * ret = __tfork(param, psize); + * break; + *} + */ + case SYS_link: { + const char * path = va_arg(args, const char *); + const char * _link = va_arg(args, const char *); + ret = link(path, _link); + break; + } + case SYS_unlink: + ret = unlink(va_arg(args, const char *)); // path + break; + case SYS_wait4: { + pid_t pid = va_arg(args, pid_t); + int * status = va_arg(args, int *); + int options = va_arg(args, int); + struct rusage * rusage = va_arg(args, struct rusage *); + ret = wait4(pid, status, options, rusage); + break; + } + case SYS_chdir: + ret = chdir(va_arg(args, const char *)); // path + break; + case SYS_fchdir: + ret = fchdir(va_arg(args, int)); // fd + break; + case SYS_mknod: { + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + dev_t dev = va_arg(args, dev_t); + ret = mknod(path, mode, dev); + break; + } + case SYS_chmod: { + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + ret = chmod(path, mode); + break; + } + case SYS_chown: { + const char * path = va_arg(args, const char *); + uid_t uid = va_arg(args, uid_t); + gid_t gid = va_arg(args, gid_t); + ret = chown(path, uid, gid); + break; + } + /* No signature found in headers + *case SYS_break: + * ret = break(char *); + * break; + */ + case SYS_getdtablecount: + ret = getdtablecount(); + break; + case SYS_getrusage: { + int who = va_arg(args, int); + struct rusage * rusage = va_arg(args, struct rusage *); + ret = getrusage(who, rusage); + break; + } + case SYS_getpid: + ret = getpid(); + break; + case SYS_mount: { + const char * type = va_arg(args, const char *); + const char * path = va_arg(args, const char *); + int flags = va_arg(args, int); + void * data = va_arg(args, void *); + ret = mount(type, path, flags, data); + break; + } + case SYS_unmount: { + const char * path = va_arg(args, const char *); + int flags = va_arg(args, int); + ret = unmount(path, flags); + break; + } + case SYS_setuid: + ret = setuid(va_arg(args, uid_t)); // uid + break; + case SYS_getuid: + ret = getuid(); + break; + case SYS_geteuid: + ret = geteuid(); + break; + case SYS_ptrace: { + int req = va_arg(args, int); + pid_t pid = va_arg(args, pid_t); + caddr_t addr = va_arg(args, caddr_t); + int data = va_arg(args, int); + ret = ptrace(req, pid, addr, data); + break; + } + case SYS_recvmsg: { + int s = va_arg(args, int); + struct msghdr * msg = va_arg(args, struct msghdr *); + int flags = va_arg(args, int); + ret = recvmsg(s, msg, flags); + break; + } + case SYS_sendmsg: { + int s = va_arg(args, int); + const struct msghdr * msg = va_arg(args, const struct msghdr *); + int flags = va_arg(args, int); + ret = sendmsg(s, msg, flags); + break; + } + case SYS_recvfrom: { + int s = va_arg(args, int); + void * buf = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int flags = va_arg(args, int); + struct sockaddr * from = va_arg(args, struct sockaddr *); + socklen_t * fromlenaddr = va_arg(args, socklen_t *); + ret = recvfrom(s, buf, len, flags, from, fromlenaddr); + break; + } + case SYS_accept: { + int s = va_arg(args, int); + struct sockaddr * name = va_arg(args, struct sockaddr *); + socklen_t * anamelen = va_arg(args, socklen_t *); + ret = accept(s, name, anamelen); + break; + } + case SYS_getpeername: { + int fdes = va_arg(args, int); + struct sockaddr * asa = va_arg(args, struct sockaddr *); + socklen_t * alen = va_arg(args, socklen_t *); + ret = getpeername(fdes, asa, alen); + break; + } + case SYS_getsockname: { + int fdes = va_arg(args, int); + struct sockaddr * asa = va_arg(args, struct sockaddr *); + socklen_t * alen = va_arg(args, socklen_t *); + ret = getsockname(fdes, asa, alen); + break; + } + case SYS_access: { + const char * path = va_arg(args, const char *); + int amode = va_arg(args, int); + ret = access(path, amode); + break; + } + case SYS_chflags: { + const char * path = va_arg(args, const char *); + u_int flags = va_arg(args, u_int); + ret = chflags(path, flags); + break; + } + case SYS_fchflags: { + int fd = va_arg(args, int); + u_int flags = va_arg(args, u_int); + ret = fchflags(fd, flags); + break; + } + case SYS_sync: + sync(); + break; + /* No signature found in headers + *case SYS_msyscall: { + * void * addr = va_arg(args, void *); + * size_t len = va_arg(args, size_t); + * ret = msyscall(addr, len); + * break; + *} + */ + case SYS_stat: { + const char * path = va_arg(args, const char *); + struct stat * ub = va_arg(args, struct stat *); + ret = stat(path, ub); + break; + } + case SYS_getppid: + ret = getppid(); + break; + case SYS_lstat: { + const char * path = va_arg(args, const char *); + struct stat * ub = va_arg(args, struct stat *); + ret = lstat(path, ub); + break; + } + case SYS_dup: + ret = dup(va_arg(args, int)); // fd + break; + case SYS_fstatat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + struct stat * buf = va_arg(args, struct stat *); + int flag = va_arg(args, int); + ret = fstatat(fd, path, buf, flag); + break; + } + case SYS_getegid: + ret = getegid(); + break; + case SYS_profil: { + caddr_t samples = va_arg(args, caddr_t); + size_t size = va_arg(args, size_t); + u_long offset = va_arg(args, u_long); + u_int scale = va_arg(args, u_int); + ret = profil(samples, size, offset, scale); + break; + } + case SYS_ktrace: { + const char * fname = va_arg(args, const char *); + int ops = va_arg(args, int); + int facs = va_arg(args, int); + pid_t pid = va_arg(args, pid_t); + ret = ktrace(fname, ops, facs, pid); + break; + } + case SYS_sigaction: { + int signum = va_arg(args, int); + const struct sigaction * nsa = va_arg(args, const struct sigaction *); + struct sigaction * osa = va_arg(args, struct sigaction *); + ret = sigaction(signum, nsa, osa); + break; + } + case SYS_getgid: + ret = getgid(); + break; + /* Mismatched func: int sigprocmask(int, const sigset_t *, sigset_t *); <signal.h> + * int sigprocmask(int, sigset_t); <sys/syscall.h> + *case SYS_sigprocmask: { + * int how = va_arg(args, int); + * sigset_t mask = va_arg(args, sigset_t); + * ret = sigprocmask(how, mask); + * break; + *} + */ + case SYS_mmap: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int prot = va_arg(args, int); + int flags = va_arg(args, int); + int fd = va_arg(args, int); + off_t pos = va_arg(args, off_t); + ret = (long)mmap(addr, len, prot, flags, fd, pos); + break; + } + case SYS_setlogin: + ret = setlogin(va_arg(args, const char *)); // namebuf + break; + case SYS_acct: + ret = acct(va_arg(args, const char *)); // path + break; + /* Mismatched func: int sigpending(sigset_t *); <signal.h> + * int sigpending(void); <sys/syscall.h> + *case SYS_sigpending: + * ret = sigpending(); + * break; + */ + case SYS_fstat: { + int fd = va_arg(args, int); + struct stat * sb = va_arg(args, struct stat *); + ret = fstat(fd, sb); + break; + } + case SYS_ioctl: { + int fd = va_arg(args, int); + u_long com = va_arg(args, u_long); + void * data = va_arg(args, void *); + ret = ioctl(fd, com, data); + break; + } + case SYS_reboot: + ret = reboot(va_arg(args, int)); // opt + break; + case SYS_revoke: + ret = revoke(va_arg(args, const char *)); // path + break; + case SYS_symlink: { + const char * path = va_arg(args, const char *); + const char * link = va_arg(args, const char *); + ret = symlink(path, link); + break; + } + case SYS_readlink: { + const char * path = va_arg(args, const char *); + char * buf = va_arg(args, char *); + size_t count = va_arg(args, size_t); + ret = readlink(path, buf, count); + break; + } + case SYS_execve: { + const char * path = va_arg(args, const char *); + char *const * argp = va_arg(args, char *const *); + char *const * envp = va_arg(args, char *const *); + ret = execve(path, argp, envp); + break; + } + case SYS_umask: + ret = umask(va_arg(args, mode_t)); // newmask + break; + case SYS_chroot: + ret = chroot(va_arg(args, const char *)); // path + break; + case SYS_getfsstat: { + struct statfs * buf = va_arg(args, struct statfs *); + size_t bufsize = va_arg(args, size_t); + int flags = va_arg(args, int); + ret = getfsstat(buf, bufsize, flags); + break; + } + case SYS_statfs: { + const char * path = va_arg(args, const char *); + struct statfs * buf = va_arg(args, struct statfs *); + ret = statfs(path, buf); + break; + } + case SYS_fstatfs: { + int fd = va_arg(args, int); + struct statfs * buf = va_arg(args, struct statfs *); + ret = fstatfs(fd, buf); + break; + } + case SYS_fhstatfs: { + const fhandle_t * fhp = va_arg(args, const fhandle_t *); + struct statfs * buf = va_arg(args, struct statfs *); + ret = fhstatfs(fhp, buf); + break; + } + case SYS_vfork: + ret = vfork(); + break; + case SYS_gettimeofday: { + struct timeval * tp = va_arg(args, struct timeval *); + struct timezone * tzp = va_arg(args, struct timezone *); + ret = gettimeofday(tp, tzp); + break; + } + case SYS_settimeofday: { + const struct timeval * tv = va_arg(args, const struct timeval *); + const struct timezone * tzp = va_arg(args, const struct timezone *); + ret = settimeofday(tv, tzp); + break; + } + case SYS_setitimer: { + int which = va_arg(args, int); + const struct itimerval * itv = va_arg(args, const struct itimerval *); + struct itimerval * oitv = va_arg(args, struct itimerval *); + ret = setitimer(which, itv, oitv); + break; + } + case SYS_getitimer: { + int which = va_arg(args, int); + struct itimerval * itv = va_arg(args, struct itimerval *); + ret = getitimer(which, itv); + break; + } + case SYS_select: { + int nd = va_arg(args, int); + fd_set * in = va_arg(args, fd_set *); + fd_set * ou = va_arg(args, fd_set *); + fd_set * ex = va_arg(args, fd_set *); + struct timeval * tv = va_arg(args, struct timeval *); + ret = select(nd, in, ou, ex, tv); + break; + } + case SYS_kevent: { + int fd = va_arg(args, int); + const struct kevent * changelist = va_arg(args, const struct kevent *); + int nchanges = va_arg(args, int); + struct kevent * eventlist = va_arg(args, struct kevent *); + int nevents = va_arg(args, int); + const struct timespec * timeout = va_arg(args, const struct timespec *); + ret = kevent(fd, changelist, nchanges, eventlist, nevents, timeout); + break; + } + case SYS_munmap: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + ret = munmap(addr, len); + break; + } + case SYS_mprotect: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int prot = va_arg(args, int); + ret = mprotect(addr, len, prot); + break; + } + case SYS_madvise: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int behav = va_arg(args, int); + ret = madvise(addr, len, behav); + break; + } + case SYS_utimes: { + const char * path = va_arg(args, const char *); + const struct timeval * tptr = va_arg(args, const struct timeval *); + ret = utimes(path, tptr); + break; + } + case SYS_futimes: { + int fd = va_arg(args, int); + const struct timeval * tptr = va_arg(args, const struct timeval *); + ret = futimes(fd, tptr); + break; + } + case SYS_mquery: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int prot = va_arg(args, int); + int flags = va_arg(args, int); + int fd = va_arg(args, int); + off_t pos = va_arg(args, off_t); + ret = (long)mquery(addr, len, prot, flags, fd, pos); + break; + } + case SYS_getgroups: { + int gidsetsize = va_arg(args, int); + gid_t * gidset = va_arg(args, gid_t *); + ret = getgroups(gidsetsize, gidset); + break; + } + case SYS_setgroups: { + int gidsetsize = va_arg(args, int); + const gid_t * gidset = va_arg(args, const gid_t *); + ret = setgroups(gidsetsize, gidset); + break; + } + case SYS_getpgrp: + ret = getpgrp(); + break; + case SYS_setpgid: { + pid_t pid = va_arg(args, pid_t); + pid_t pgid = va_arg(args, pid_t); + ret = setpgid(pid, pgid); + break; + } + case SYS_futex: { + uint32_t * f = va_arg(args, uint32_t *); + int op = va_arg(args, int); + int val = va_arg(args, int); + const struct timespec * timeout = va_arg(args, const struct timespec *); + uint32_t * g = va_arg(args, uint32_t *); + ret = futex(f, op, val, timeout, g); + break; + } + case SYS_utimensat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + const struct timespec * times = va_arg(args, const struct timespec *); + int flag = va_arg(args, int); + ret = utimensat(fd, path, times, flag); + break; + } + case SYS_futimens: { + int fd = va_arg(args, int); + const struct timespec * times = va_arg(args, const struct timespec *); + ret = futimens(fd, times); + break; + } + /* No signature found in headers + *case SYS_kbind: { + * const struct __kbind * param = va_arg(args, const struct __kbind *); + * size_t psize = va_arg(args, size_t); + * int64_t proc_cookie = va_arg(args, int64_t); + * ret = kbind(param, psize, proc_cookie); + * break; + *} + */ + case SYS_clock_gettime: { + clockid_t clock_id = va_arg(args, clockid_t); + struct timespec * tp = va_arg(args, struct timespec *); + ret = clock_gettime(clock_id, tp); + break; + } + case SYS_clock_settime: { + clockid_t clock_id = va_arg(args, clockid_t); + const struct timespec * tp = va_arg(args, const struct timespec *); + ret = clock_settime(clock_id, tp); + break; + } + case SYS_clock_getres: { + clockid_t clock_id = va_arg(args, clockid_t); + struct timespec * tp = va_arg(args, struct timespec *); + ret = clock_getres(clock_id, tp); + break; + } + case SYS_dup2: { + int from = va_arg(args, int); + int to = va_arg(args, int); + ret = dup2(from, to); + break; + } + case SYS_nanosleep: { + const struct timespec * rqtp = va_arg(args, const struct timespec *); + struct timespec * rmtp = va_arg(args, struct timespec *); + ret = nanosleep(rqtp, rmtp); + break; + } + case SYS_fcntl: { + int fd = va_arg(args, int); + int cmd = va_arg(args, int); + void * arg = va_arg(args, void *); + ret = fcntl(fd, cmd, arg); + break; + } + case SYS_accept4: { + int s = va_arg(args, int); + struct sockaddr * name = va_arg(args, struct sockaddr *); + socklen_t * anamelen = va_arg(args, socklen_t *); + int flags = va_arg(args, int); + ret = accept4(s, name, anamelen, flags); + break; + } + /* No signature found in headers + *case SYS___thrsleep: { + * const volatile void * ident = va_arg(args, const volatile void *); + * clockid_t clock_id = va_arg(args, clockid_t); + * const struct timespec * tp = va_arg(args, const struct timespec *); + * void * lock = va_arg(args, void *); + * const int * abort = va_arg(args, const int *); + * ret = __thrsleep(ident, clock_id, tp, lock, abort); + * break; + *} + */ + case SYS_fsync: + ret = fsync(va_arg(args, int)); // fd + break; + case SYS_setpriority: { + int which = va_arg(args, int); + id_t who = va_arg(args, id_t); + int prio = va_arg(args, int); + ret = setpriority(which, who, prio); + break; + } + case SYS_socket: { + int domain = va_arg(args, int); + int type = va_arg(args, int); + int protocol = va_arg(args, int); + ret = socket(domain, type, protocol); + break; + } + case SYS_connect: { + int s = va_arg(args, int); + const struct sockaddr * name = va_arg(args, const struct sockaddr *); + socklen_t namelen = va_arg(args, socklen_t); + ret = connect(s, name, namelen); + break; + } + case SYS_getdents: { + int fd = va_arg(args, int); + void * buf = va_arg(args, void *); + size_t buflen = va_arg(args, size_t); + ret = getdents(fd, buf, buflen); + break; + } + case SYS_getpriority: { + int which = va_arg(args, int); + id_t who = va_arg(args, id_t); + ret = getpriority(which, who); + break; + } + case SYS_pipe2: { + int * fdp = va_arg(args, int *); + int flags = va_arg(args, int); + ret = pipe2(fdp, flags); + break; + } + case SYS_dup3: { + int from = va_arg(args, int); + int to = va_arg(args, int); + int flags = va_arg(args, int); + ret = dup3(from, to, flags); + break; + } + /* No signature found in headers + *case SYS_sigreturn: + * ret = sigreturn(va_arg(args, struct sigcontext *)); // sigcntxp + * break; + */ + case SYS_bind: { + int s = va_arg(args, int); + const struct sockaddr * name = va_arg(args, const struct sockaddr *); + socklen_t namelen = va_arg(args, socklen_t); + ret = bind(s, name, namelen); + break; + } + case SYS_setsockopt: { + int s = va_arg(args, int); + int level = va_arg(args, int); + int name = va_arg(args, int); + const void * val = va_arg(args, const void *); + socklen_t valsize = va_arg(args, socklen_t); + ret = setsockopt(s, level, name, val, valsize); + break; + } + case SYS_listen: { + int s = va_arg(args, int); + int backlog = va_arg(args, int); + ret = listen(s, backlog); + break; + } + case SYS_chflagsat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + u_int flags = va_arg(args, u_int); + int atflags = va_arg(args, int); + ret = chflagsat(fd, path, flags, atflags); + break; + } + case SYS_pledge: { + const char * promises = va_arg(args, const char *); + const char * execpromises = va_arg(args, const char *); + ret = pledge(promises, execpromises); + break; + } + case SYS_ppoll: { + struct pollfd * fds = va_arg(args, struct pollfd *); + u_int nfds = va_arg(args, u_int); + const struct timespec * ts = va_arg(args, const struct timespec *); + const sigset_t * mask = va_arg(args, const sigset_t *); + ret = ppoll(fds, nfds, ts, mask); + break; + } + case SYS_pselect: { + int nd = va_arg(args, int); + fd_set * in = va_arg(args, fd_set *); + fd_set * ou = va_arg(args, fd_set *); + fd_set * ex = va_arg(args, fd_set *); + const struct timespec * ts = va_arg(args, const struct timespec *); + const sigset_t * mask = va_arg(args, const sigset_t *); + ret = pselect(nd, in, ou, ex, ts, mask); + break; + } + /* Mismatched func: int sigsuspend(const sigset_t *); <signal.h> + * int sigsuspend(int); <sys/syscall.h> + *case SYS_sigsuspend: + * ret = sigsuspend(va_arg(args, int)); // mask + * break; + */ + case SYS_sendsyslog: { + const char * buf = va_arg(args, const char *); + size_t nbyte = va_arg(args, size_t); + int flags = va_arg(args, int); + ret = sendsyslog(buf, nbyte, flags); + break; + } + case SYS_unveil: { + const char * path = va_arg(args, const char *); + const char * permissions = va_arg(args, const char *); + ret = unveil(path, permissions); + break; + } + /* No signature found in headers + *case SYS___realpath: { + * const char * pathname = va_arg(args, const char *); + * char * resolved = va_arg(args, char *); + * ret = __realpath(pathname, resolved); + * break; + *} + */ + case SYS_recvmmsg: { + int s = va_arg(args, int); + struct mmsghdr * mmsg = va_arg(args, struct mmsghdr *); + unsigned int vlen = va_arg(args, unsigned int); + int flags = va_arg(args, int); + struct timespec * timeout = va_arg(args, struct timespec *); + ret = recvmmsg(s, mmsg, vlen, flags, timeout); + break; + } + case SYS_sendmmsg: { + int s = va_arg(args, int); + struct mmsghdr * mmsg = va_arg(args, struct mmsghdr *); + unsigned int vlen = va_arg(args, unsigned int); + int flags = va_arg(args, int); + ret = sendmmsg(s, mmsg, vlen, flags); + break; + } + case SYS_getsockopt: { + int s = va_arg(args, int); + int level = va_arg(args, int); + int name = va_arg(args, int); + void * val = va_arg(args, void *); + socklen_t * avalsize = va_arg(args, socklen_t *); + ret = getsockopt(s, level, name, val, avalsize); + break; + } + case SYS_thrkill: { + pid_t tid = va_arg(args, pid_t); + int signum = va_arg(args, int); + void * tcb = va_arg(args, void *); + ret = thrkill(tid, signum, tcb); + break; + } + case SYS_readv: { + int fd = va_arg(args, int); + const struct iovec * iovp = va_arg(args, const struct iovec *); + int iovcnt = va_arg(args, int); + ret = readv(fd, iovp, iovcnt); + break; + } + case SYS_writev: { + int fd = va_arg(args, int); + const struct iovec * iovp = va_arg(args, const struct iovec *); + int iovcnt = va_arg(args, int); + ret = writev(fd, iovp, iovcnt); + break; + } + case SYS_kill: { + int pid = va_arg(args, int); + int signum = va_arg(args, int); + ret = kill(pid, signum); + break; + } + case SYS_fchown: { + int fd = va_arg(args, int); + uid_t uid = va_arg(args, uid_t); + gid_t gid = va_arg(args, gid_t); + ret = fchown(fd, uid, gid); + break; + } + case SYS_fchmod: { + int fd = va_arg(args, int); + mode_t mode = va_arg(args, mode_t); + ret = fchmod(fd, mode); + break; + } + case SYS_setreuid: { + uid_t ruid = va_arg(args, uid_t); + uid_t euid = va_arg(args, uid_t); + ret = setreuid(ruid, euid); + break; + } + case SYS_setregid: { + gid_t rgid = va_arg(args, gid_t); + gid_t egid = va_arg(args, gid_t); + ret = setregid(rgid, egid); + break; + } + case SYS_rename: { + const char * from = va_arg(args, const char *); + const char * to = va_arg(args, const char *); + ret = rename(from, to); + break; + } + case SYS_flock: { + int fd = va_arg(args, int); + int how = va_arg(args, int); + ret = flock(fd, how); + break; + } + case SYS_mkfifo: { + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + ret = mkfifo(path, mode); + break; + } + case SYS_sendto: { + int s = va_arg(args, int); + const void * buf = va_arg(args, const void *); + size_t len = va_arg(args, size_t); + int flags = va_arg(args, int); + const struct sockaddr * to = va_arg(args, const struct sockaddr *); + socklen_t tolen = va_arg(args, socklen_t); + ret = sendto(s, buf, len, flags, to, tolen); + break; + } + case SYS_shutdown: { + int s = va_arg(args, int); + int how = va_arg(args, int); + ret = shutdown(s, how); + break; + } + case SYS_socketpair: { + int domain = va_arg(args, int); + int type = va_arg(args, int); + int protocol = va_arg(args, int); + int * rsv = va_arg(args, int *); + ret = socketpair(domain, type, protocol, rsv); + break; + } + case SYS_mkdir: { + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + ret = mkdir(path, mode); + break; + } + case SYS_rmdir: + ret = rmdir(va_arg(args, const char *)); // path + break; + case SYS_adjtime: { + const struct timeval * delta = va_arg(args, const struct timeval *); + struct timeval * olddelta = va_arg(args, struct timeval *); + ret = adjtime(delta, olddelta); + break; + } + /* Mismatched func: int getlogin_r(char *, size_t); <unistd.h> + * int getlogin_r(char *, u_int); <sys/syscall.h> + *case SYS_getlogin_r: { + * char * namebuf = va_arg(args, char *); + * u_int namelen = va_arg(args, u_int); + * ret = getlogin_r(namebuf, namelen); + * break; + *} + */ + case SYS_getthrname: { + pid_t tid = va_arg(args, pid_t); + char * name = va_arg(args, char *); + size_t len = va_arg(args, size_t); + ret = getthrname(tid, name, len); + break; + } + case SYS_setthrname: { + pid_t tid = va_arg(args, pid_t); + const char * name = va_arg(args, const char *); + ret = setthrname(tid, name); + break; + } + /* No signature found in headers + *case SYS_pinsyscall: { + * int syscall = va_arg(args, int); + * void * addr = va_arg(args, void *); + * size_t len = va_arg(args, size_t); + * ret = pinsyscall(syscall, addr, len); + * break; + *} + */ + case SYS_setsid: + ret = setsid(); + break; + case SYS_quotactl: { + const char * path = va_arg(args, const char *); + int cmd = va_arg(args, int); + int uid = va_arg(args, int); + char * arg = va_arg(args, char *); + ret = quotactl(path, cmd, uid, arg); + break; + } + /* No signature found in headers + *case SYS_ypconnect: + * ret = ypconnect(va_arg(args, int)); // type + * break; + */ + case SYS_nfssvc: { + int flag = va_arg(args, int); + void * argp = va_arg(args, void *); + ret = nfssvc(flag, argp); + break; + } + case SYS_mimmutable: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + ret = mimmutable(addr, len); + break; + } + case SYS_waitid: { + int idtype = va_arg(args, int); + id_t id = va_arg(args, id_t); + siginfo_t * info = va_arg(args, siginfo_t *); + int options = va_arg(args, int); + ret = waitid(idtype, id, info, options); + break; + } + case SYS_getfh: { + const char * fname = va_arg(args, const char *); + fhandle_t * fhp = va_arg(args, fhandle_t *); + ret = getfh(fname, fhp); + break; + } + /* No signature found in headers + *case SYS___tmpfd: + * ret = __tmpfd(va_arg(args, int)); // flags + * break; + */ + /* No signature found in headers + *case SYS_sysarch: { + * int op = va_arg(args, int); + * void * parms = va_arg(args, void *); + * ret = sysarch(op, parms); + * break; + *} + */ + case SYS_lseek: { + int fd = va_arg(args, int); + off_t offset = va_arg(args, off_t); + int whence = va_arg(args, int); + ret = lseek(fd, offset, whence); + break; + } + case SYS_truncate: { + const char * path = va_arg(args, const char *); + off_t length = va_arg(args, off_t); + ret = truncate(path, length); + break; + } + case SYS_ftruncate: { + int fd = va_arg(args, int); + off_t length = va_arg(args, off_t); + ret = ftruncate(fd, length); + break; + } + case SYS_pread: { + int fd = va_arg(args, int); + void * buf = va_arg(args, void *); + size_t nbyte = va_arg(args, size_t); + off_t offset = va_arg(args, off_t); + ret = pread(fd, buf, nbyte, offset); + break; + } + case SYS_pwrite: { + int fd = va_arg(args, int); + const void * buf = va_arg(args, const void *); + size_t nbyte = va_arg(args, size_t); + off_t offset = va_arg(args, off_t); + ret = pwrite(fd, buf, nbyte, offset); + break; + } + case SYS_preadv: { + int fd = va_arg(args, int); + const struct iovec * iovp = va_arg(args, const struct iovec *); + int iovcnt = va_arg(args, int); + off_t offset = va_arg(args, off_t); + ret = preadv(fd, iovp, iovcnt, offset); + break; + } + case SYS_pwritev: { + int fd = va_arg(args, int); + const struct iovec * iovp = va_arg(args, const struct iovec *); + int iovcnt = va_arg(args, int); + off_t offset = va_arg(args, off_t); + ret = pwritev(fd, iovp, iovcnt, offset); + break; + } + case SYS_setgid: + ret = setgid(va_arg(args, gid_t)); // gid + break; + case SYS_setegid: + ret = setegid(va_arg(args, gid_t)); // egid + break; + case SYS_seteuid: + ret = seteuid(va_arg(args, uid_t)); // euid + break; + case SYS_pathconf: { + const char * path = va_arg(args, const char *); + int name = va_arg(args, int); + ret = pathconf(path, name); + break; + } + case SYS_fpathconf: { + int fd = va_arg(args, int); + int name = va_arg(args, int); + ret = fpathconf(fd, name); + break; + } + case SYS_swapctl: { + int cmd = va_arg(args, int); + const void * arg = va_arg(args, const void *); + int misc = va_arg(args, int); + ret = swapctl(cmd, arg, misc); + break; + } + case SYS_getrlimit: { + int which = va_arg(args, int); + struct rlimit * rlp = va_arg(args, struct rlimit *); + ret = getrlimit(which, rlp); + break; + } + case SYS_setrlimit: { + int which = va_arg(args, int); + const struct rlimit * rlp = va_arg(args, const struct rlimit *); + ret = setrlimit(which, rlp); + break; + } + case SYS_sysctl: { + const int * name = va_arg(args, const int *); + u_int namelen = va_arg(args, u_int); + void * old = va_arg(args, void *); + size_t * oldlenp = va_arg(args, size_t *); + void * new = va_arg(args, void *); + size_t newlen = va_arg(args, size_t); + ret = sysctl(name, namelen, old, oldlenp, new, newlen); + break; + } + case SYS_mlock: { + const void * addr = va_arg(args, const void *); + size_t len = va_arg(args, size_t); + ret = mlock(addr, len); + break; + } + case SYS_munlock: { + const void * addr = va_arg(args, const void *); + size_t len = va_arg(args, size_t); + ret = munlock(addr, len); + break; + } + case SYS_getpgid: + ret = getpgid(va_arg(args, pid_t)); // pid + break; + case SYS_utrace: { + const char * label = va_arg(args, const char *); + const void * addr = va_arg(args, const void *); + size_t len = va_arg(args, size_t); + ret = utrace(label, addr, len); + break; + } + case SYS_semget: { + key_t key = va_arg(args, key_t); + int nsems = va_arg(args, int); + int semflg = va_arg(args, int); + ret = semget(key, nsems, semflg); + break; + } + case SYS_msgget: { + key_t key = va_arg(args, key_t); + int msgflg = va_arg(args, int); + ret = msgget(key, msgflg); + break; + } + case SYS_msgsnd: { + int msqid = va_arg(args, int); + const void * msgp = va_arg(args, const void *); + size_t msgsz = va_arg(args, size_t); + int msgflg = va_arg(args, int); + ret = msgsnd(msqid, msgp, msgsz, msgflg); + break; + } + case SYS_msgrcv: { + int msqid = va_arg(args, int); + void * msgp = va_arg(args, void *); + size_t msgsz = va_arg(args, size_t); + long msgtyp = va_arg(args, long); + int msgflg = va_arg(args, int); + ret = msgrcv(msqid, msgp, msgsz, msgtyp, msgflg); + break; + } + case SYS_shmat: { + int shmid = va_arg(args, int); + const void * shmaddr = va_arg(args, const void *); + int shmflg = va_arg(args, int); + ret = (long)shmat(shmid, shmaddr, shmflg); + break; + } + case SYS_shmdt: + ret = shmdt(va_arg(args, const void *)); // shmaddr + break; + case SYS_minherit: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int inherit = va_arg(args, int); + ret = minherit(addr, len, inherit); + break; + } + case SYS_poll: { + struct pollfd * fds = va_arg(args, struct pollfd *); + u_int nfds = va_arg(args, u_int); + int timeout = va_arg(args, int); + ret = poll(fds, nfds, timeout); + break; + } + case SYS_issetugid: + ret = issetugid(); + break; + case SYS_lchown: { + const char * path = va_arg(args, const char *); + uid_t uid = va_arg(args, uid_t); + gid_t gid = va_arg(args, gid_t); + ret = lchown(path, uid, gid); + break; + } + case SYS_getsid: + ret = getsid(va_arg(args, pid_t)); // pid + break; + case SYS_msync: { + void * addr = va_arg(args, void *); + size_t len = va_arg(args, size_t); + int flags = va_arg(args, int); + ret = msync(addr, len, flags); + break; + } + case SYS_pipe: + ret = pipe(va_arg(args, int *)); // fdp + break; + case SYS_fhopen: { + const fhandle_t * fhp = va_arg(args, const fhandle_t *); + int flags = va_arg(args, int); + ret = fhopen(fhp, flags); + break; + } + case SYS_kqueue: + ret = kqueue(); + break; + case SYS_mlockall: + ret = mlockall(va_arg(args, int)); // flags + break; + case SYS_munlockall: + ret = munlockall(); + break; + case SYS_getresuid: { + uid_t * ruid = va_arg(args, uid_t *); + uid_t * euid = va_arg(args, uid_t *); + uid_t * suid = va_arg(args, uid_t *); + ret = getresuid(ruid, euid, suid); + break; + } + case SYS_setresuid: { + uid_t ruid = va_arg(args, uid_t); + uid_t euid = va_arg(args, uid_t); + uid_t suid = va_arg(args, uid_t); + ret = setresuid(ruid, euid, suid); + break; + } + case SYS_getresgid: { + gid_t * rgid = va_arg(args, gid_t *); + gid_t * egid = va_arg(args, gid_t *); + gid_t * sgid = va_arg(args, gid_t *); + ret = getresgid(rgid, egid, sgid); + break; + } + case SYS_setresgid: { + gid_t rgid = va_arg(args, gid_t); + gid_t egid = va_arg(args, gid_t); + gid_t sgid = va_arg(args, gid_t); + ret = setresgid(rgid, egid, sgid); + break; + } + case SYS_closefrom: + ret = closefrom(va_arg(args, int)); // fd + break; + case SYS_sigaltstack: { + const struct sigaltstack * nss = va_arg(args, const struct sigaltstack *); + struct sigaltstack * oss = va_arg(args, struct sigaltstack *); + ret = sigaltstack(nss, oss); + break; + } + case SYS_shmget: { + key_t key = va_arg(args, key_t); + size_t size = va_arg(args, size_t); + int shmflg = va_arg(args, int); + ret = shmget(key, size, shmflg); + break; + } + case SYS_semop: { + int semid = va_arg(args, int); + struct sembuf * sops = va_arg(args, struct sembuf *); + size_t nsops = va_arg(args, size_t); + ret = semop(semid, sops, nsops); + break; + } + case SYS_fhstat: { + const fhandle_t * fhp = va_arg(args, const fhandle_t *); + struct stat * sb = va_arg(args, struct stat *); + ret = fhstat(fhp, sb); + break; + } + case SYS___semctl: { + int semid = va_arg(args, int); + int semnum = va_arg(args, int); + int cmd = va_arg(args, int); + union semun * arg = va_arg(args, union semun *); + ret = __semctl(semid, semnum, cmd, arg); + break; + } + case SYS_shmctl: { + int shmid = va_arg(args, int); + int cmd = va_arg(args, int); + struct shmid_ds * buf = va_arg(args, struct shmid_ds *); + ret = shmctl(shmid, cmd, buf); + break; + } + case SYS_msgctl: { + int msqid = va_arg(args, int); + int cmd = va_arg(args, int); + struct msqid_ds * buf = va_arg(args, struct msqid_ds *); + ret = msgctl(msqid, cmd, buf); + break; + } + case SYS_sched_yield: + ret = sched_yield(); + break; + case SYS_getthrid: + ret = getthrid(); + break; + /* No signature found in headers + *case SYS___thrwakeup: { + * const volatile void * ident = va_arg(args, const volatile void *); + * int n = va_arg(args, int); + * ret = __thrwakeup(ident, n); + * break; + *} + */ + /* No signature found in headers + *case SYS___threxit: + * __threxit(va_arg(args, pid_t *)); // notdead + * break; + */ + /* No signature found in headers + *case SYS___thrsigdivert: { + * sigset_t sigmask = va_arg(args, sigset_t); + * siginfo_t * info = va_arg(args, siginfo_t *); + * const struct timespec * timeout = va_arg(args, const struct timespec *); + * ret = __thrsigdivert(sigmask, info, timeout); + * break; + *} + */ + /* No signature found in headers + *case SYS___getcwd: { + * char * buf = va_arg(args, char *); + * size_t len = va_arg(args, size_t); + * ret = __getcwd(buf, len); + * break; + *} + */ + case SYS_adjfreq: { + const int64_t * freq = va_arg(args, const int64_t *); + int64_t * oldfreq = va_arg(args, int64_t *); + ret = adjfreq(freq, oldfreq); + break; + } + case SYS_setrtable: + ret = setrtable(va_arg(args, int)); // rtableid + break; + case SYS_getrtable: + ret = getrtable(); + break; + case SYS_faccessat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + int amode = va_arg(args, int); + int flag = va_arg(args, int); + ret = faccessat(fd, path, amode, flag); + break; + } + case SYS_fchmodat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + int flag = va_arg(args, int); + ret = fchmodat(fd, path, mode, flag); + break; + } + case SYS_fchownat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + uid_t uid = va_arg(args, uid_t); + gid_t gid = va_arg(args, gid_t); + int flag = va_arg(args, int); + ret = fchownat(fd, path, uid, gid, flag); + break; + } + case SYS_linkat: { + int fd1 = va_arg(args, int); + const char * path1 = va_arg(args, const char *); + int fd2 = va_arg(args, int); + const char * path2 = va_arg(args, const char *); + int flag = va_arg(args, int); + ret = linkat(fd1, path1, fd2, path2, flag); + break; + } + case SYS_mkdirat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + ret = mkdirat(fd, path, mode); + break; + } + case SYS_mkfifoat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + ret = mkfifoat(fd, path, mode); + break; + } + case SYS_mknodat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + mode_t mode = va_arg(args, mode_t); + dev_t dev = va_arg(args, dev_t); + ret = mknodat(fd, path, mode, dev); + break; + } + case SYS_openat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + int flags = va_arg(args, int); + mode_t mode = va_arg(args, mode_t); + ret = openat(fd, path, flags, mode); + break; + } + case SYS_readlinkat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + char * buf = va_arg(args, char *); + size_t count = va_arg(args, size_t); + ret = readlinkat(fd, path, buf, count); + break; + } + case SYS_renameat: { + int fromfd = va_arg(args, int); + const char * from = va_arg(args, const char *); + int tofd = va_arg(args, int); + const char * to = va_arg(args, const char *); + ret = renameat(fromfd, from, tofd, to); + break; + } + case SYS_symlinkat: { + const char * path = va_arg(args, const char *); + int fd = va_arg(args, int); + const char * link = va_arg(args, const char *); + ret = symlinkat(path, fd, link); + break; + } + case SYS_unlinkat: { + int fd = va_arg(args, int); + const char * path = va_arg(args, const char *); + int flag = va_arg(args, int); + ret = unlinkat(fd, path, flag); + break; + } + case SYS___set_tcb: + __set_tcb(va_arg(args, void *)); // tcb + break; + case SYS___get_tcb: + ret = (long)__get_tcb(); + break; + default: + ret = -1; + errno = ENOSYS; + } + va_end(args); + + return ret; +} Index: gnu/usr.bin/perl/syscall_emulator.h =================================================================== RCS file: gnu/usr.bin/perl/syscall_emulator.h diff -N gnu/usr.bin/perl/syscall_emulator.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/usr.bin/perl/syscall_emulator.h 20 Jul 2023 04:14:33 -0000 @@ -0,0 +1 @@ +long syscall_emulator(int, ...); Index: gnu/usr.bin/perl/t/op/syscall_emulator.t =================================================================== RCS file: gnu/usr.bin/perl/t/op/syscall_emulator.t diff -N gnu/usr.bin/perl/t/op/syscall_emulator.t --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/usr.bin/perl/t/op/syscall_emulator.t 20 Jul 2023 04:14:33 -0000 @@ -0,0 +1,126 @@ +#!/usr/bin/perl +# $OpenBSD$ # + +# Copyright (c) 2023 Andrew Hewus Fresh <afre...@openbsd.org> +# +# Permission to use, copy, modify, and distribute this software for any +# purpose with or without fee is hereby granted, provided that the above +# copyright notice and this permission notice appear in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +BEGIN { + chdir 't' if -d 't'; + require "./test.pl"; + set_up_inc( qw(. ../lib lib ../dist/base/lib) ); +} + +use v5.36; + +use File::Temp; +use POSIX qw< S_IRUSR S_IWUSR S_IRGRP S_IROTH O_CREAT O_WRONLY O_RDONLY >; + +use constant { + PROT_READ => 0x01, + MAP_PRIVATE => 0x0002, + MAP_FAILED => -1, +}; + +my $dir = File::Temp->newdir("syscall_emulator-XXXXXXXXX"); +{ + local $ENV{PERL5LIB} = join ':', @INC; + system($^X, "../utils/h2ph", '-d', $dir, + "/usr/include/sys/syscall.h"); + local @INC = ("$dir/usr/include", "$dir"); + require 'sys/syscall.ph'; +} + +my $filename = "test.txt"; +my $file = "$dir/$filename"; +my $fd; +my $out = "Hello World\n"; +my $in = "\0" x 32; +my ($in_p, $in_v); +my $sb = "\0" x 4096; +my $st_mode; + +my $perms = S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH; + +plan tests => 13; + +ok(! + (($fd = syscall(SYS_open(), $file, O_CREAT|O_WRONLY, $perms)) < 0), + "Opened $filename for write/create" +); +ok(! + (syscall(SYS_write(), $fd, $out, length $out) <= 0), + "Wrote out to $filename" +); +ok(! + (syscall(SYS_close(), $fd) != 0), + "closed $filename" +); + + +ok(! + (syscall(SYS_stat(), $file, $sb) != 0), + "stat $filename" +); + +# fortunately st_mode is the first unsigned long in stat struct +$st_mode = unpack "L", $sb; + +ok( ($st_mode & 0777) == ($perms & 0777), + sprintf "new file %s has correct permissions (%o)", + $filename, $st_mode & 0777 +); + +ok(! + (($fd = syscall(SYS_open(), $file, O_RDONLY)) < 0), + "Opened $filename for read" +); +ok(! + (syscall(SYS_read(), $fd, $in, length $in) <= 0), + "read from $filename" +); + +$in = unpack 'Z*', $in; + +ok( length($in) == length($out) && ($in eq $out), + "Read written content from $filename" +); + +ok(! + (syscall(SYS_lseek(), $fd, 0, SEEK_SET) < 0), + "lseek on fd" +); + + +ok(! + (($in_p = syscall(SYS_mmap(), undef, length($out), PROT_READ, MAP_PRIVATE, + $fd, 0)) == MAP_FAILED), + "mmap fd" +); + +# From ingy's Pointer module +$in_v = unpack "p*", pack "L!", $in_p; + +ok( length($in_v) == length($out) && ($in_v eq $out), + "Read written content from $filename" +); + +ok(! + (syscall(SYS_munmap(), $in_p, length($out)) != 0), + "munmap fd" +); + +ok(! + (syscall(SYS_close(), $fd) != 0), + "closed $filename" +);