cosmopolitan/tool/build/lib/syscall.c

1419 lines
43 KiB
C
Raw Normal View History

/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
2020-12-28 01:18:44 +00:00
Permission to use, copy, modify, and/or 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.
2020-12-28 01:18:44 +00:00
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.
*/
#include "libc/calls/calls.h"
#include "libc/calls/internal.h"
#include "libc/calls/ioctl.h"
#include "libc/calls/sig.internal.h"
#include "libc/calls/struct/dirent.h"
#include "libc/calls/struct/iovec.h"
#include "libc/calls/struct/rlimit.h"
#include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction-linux.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/stat.h"
#include "libc/calls/struct/sysinfo.h"
#include "libc/calls/struct/termios.h"
#include "libc/calls/struct/timespec.h"
#include "libc/calls/struct/timeval.h"
#include "libc/calls/struct/tms.h"
#include "libc/calls/struct/utsname.h"
#include "libc/calls/struct/winsize.h"
#include "libc/calls/weirdtypes.h"
#include "libc/errno.h"
2020-10-27 10:39:46 +00:00
#include "libc/fmt/fmt.h"
#include "libc/log/check.h"
#include "libc/log/log.h"
#include "libc/macros.internal.h"
#include "libc/mem/mem.h"
#include "libc/nexgen32e/vendor.internal.h"
#include "libc/runtime/gc.internal.h"
#include "libc/runtime/pc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/sock/select.h"
#include "libc/sock/sock.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/at.h"
#include "libc/sysv/consts/clock.h"
#include "libc/sysv/consts/f.h"
#include "libc/sysv/consts/fd.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/lock.h"
#include "libc/sysv/consts/madv.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/msync.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/ok.h"
#include "libc/sysv/consts/poll.h"
#include "libc/sysv/consts/pr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/rusage.h"
#include "libc/sysv/consts/sa.h"
#include "libc/sysv/consts/sicode.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/so.h"
#include "libc/sysv/consts/sock.h"
#include "libc/sysv/consts/sol.h"
#include "libc/sysv/consts/ss.h"
#include "libc/sysv/consts/tcp.h"
#include "libc/sysv/consts/termios.h"
#include "libc/sysv/consts/w.h"
#include "libc/sysv/errfuns.h"
#include "libc/time/struct/timezone.h"
#include "libc/time/struct/utimbuf.h"
#include "libc/time/time.h"
#include "libc/x/x.h"
#include "third_party/mbedtls/endian.h"
#include "tool/build/lib/bits.h"
#include "tool/build/lib/case.h"
#include "tool/build/lib/endian.h"
#include "tool/build/lib/iovs.h"
#include "tool/build/lib/machine.h"
#include "tool/build/lib/memory.h"
#include "tool/build/lib/pml4t.h"
#include "tool/build/lib/signal.h"
#include "tool/build/lib/syscall.h"
#include "tool/build/lib/throw.h"
#include "tool/build/lib/xlat.h"
#include "tool/build/lib/xlaterrno.h"
#define TIOCGWINSZ_LINUX 0x5413
#define TCGETS_LINUX 0x5401
#define TCSETS_LINUX 0x5402
#define TCSETSW_LINUX 0x5403
#define TCSETSF_LINUX 0x5404
#define ARCH_SET_GS_LINUX 0x1001
#define ARCH_SET_FS_LINUX 0x1002
#define ARCH_GET_FS_LINUX 0x1003
#define ARCH_GET_GS_LINUX 0x1004
#define SOCK_CLOEXEC_LINUX 0x080000
#define O_CLOEXEC_LINUX 0x080000
#define SA_RESTORER 0x04000000
#define POLLIN_LINUX 0x01
#define POLLPRI_LINUX 0x02
#define POLLOUT_LINUX 0x04
#define POLLERR_LINUX 0x08
#define POLLHUP_LINUX 0x10
#define POLLNVAL_LINUX 0x20
Make major improvements to redbean and libraries The most exciting improvement is dynamic pages will soon be able to use the executable itself as an object store. it required a heroic technique for overcoming ETXTBSY restrictions which lets us open the executable in read/write mode, which means (1) wa can restore the APE header, and (2) we can potentially containerize redbean extension code so that modules you download for your redbean online will only impact your redbean. Here's a list of breaking changes to redbean: - Remove /tool/net/ prefix from magic ZIP paths - GetHeader() now returns NIL if header is absent Here's a list of fixes and enhancements to redbean: - Support 64-bit ZIP archives - Record User-Agent header in logs - Add twelve error handlers to accept() - Display octal st_mode on listing page - Show ZIP file comments on listing page - Restore APE MZ header on redbean startup - Track request count on redbean index page - Report server uptime on redbean index page - Don't bind server socket using SO_REUSEPORT - Fix #151 where Lua LoadAsset() could free twice - Report rusage accounting when workers exit w/ -vv - Use ZIP iattr field as text/plain vs. binary hint - Add ParseUrl() API for parsing things like a.href - Add ParseParams() API for parsing HTTP POST bodies - Add IsAcceptablePath() API for checking dots, etc. - Add IsValidHttpToken() API for validating sane ASCII - Add IsAcceptableHostPort() for validating HOST[:PORT] - Send 400 response to HTTP/1.1 requests without a Host - Send 403 response if ZIP or file isn't other readable - Add virtual hosting that tries prepending Host to path - Route requests based on Host in Request-URI if present - Host routing will attempt to remove or add the www. prefix - Sign-extend UNIX timestamps and don't adjust FileTime zone Here's some of the improvements made to Cosmopolitan Libc: - Fix ape.S indentation - Improve consts.sh magnums - Write pretty good URL parser - Improve rusage accounting apis - Bring mremap() closer to working - Added ZIP APIs which will change - Check for overflow in reallocarray() - Remove overly fancy linkage in strerror() - Fix GDB attach on crash w/ OpenBSD msyscall() - Make sigqueue() portable to most UNIX distros - Make integer serialization macros more elegant - Bring back 34x tprecode8to16() performance boost - Make malloc() more resilient to absurdly large sizes
2021-04-18 18:34:59 +00:00
#define TIOCGWINSZ_LINUX 0x5413
#define TCGETS_LINUX 0x5401
#define TCSETS_LINUX 0x5402
#define TCSETSW_LINUX 0x5403
#define TCSETSF_LINUX 0x5404
#define ISIG_LINUX 0b0000000000000001
#define ICANON_LINUX 0b0000000000000010
#define ECHO_LINUX 0b0000000000001000
#define OPOST_LINUX 0b0000000000000001
#define POINTER(x) ((void *)(intptr_t)(x))
#define UNPOINTER(x) ((int64_t)(intptr_t)(x))
#define SYSCALL(x, y) CASE(x, asm("# " #y); ax = y)
#define XLAT(x, y) CASE(x, return y)
#define PNN(x) ResolveAddress(m, x)
#define P(x) ((x) ? PNN(x) : 0)
#define ASSIGN(D, S) memcpy(&D, &S, MIN(sizeof(S), sizeof(D)))
const struct MachineFdCb kMachineFdCbHost = {
.close = close,
.readv = readv,
.poll = poll,
.writev = writev,
Undiamond Python headers This change gets the Python codebase into a state where it conforms to the conventions of this codebase. It's now possible to include headers from Python, without worrying about ordering. Python has traditionally solved that problem by "diamonding" everything in Python.h, but that's problematic since it means any change to any Python header invalidates all the build artifacts. Lastly it makes tooling not work. Since it is hard to explain to Emacs when I press C-c C-h to add an import line it shouldn't add the header that actually defines the symbol, and instead do follow the nonstandard Python convention. Progress has been made on letting Python load source code from the zip executable structure via the standard C library APIs. System calss now recognizes zip!FILENAME alternative URIs as equivalent to zip:FILENAME since Python uses colon as its delimiter. Some progress has been made on embedding the notice license terms into the Python object code. This is easier said than done since Python has an extremely complicated ownership story. - Some termios APIs have been added - Implement rewinddir() dirstream API - GetCpuCount() API added to Cosmopolitan Libc - More bugs in Cosmopolitan Libc have been fixed - zipobj.com now has flags for mangling the path - Fixed bug a priori with sendfile() on certain BSDs - Polyfill F_DUPFD and F_DUPFD_CLOEXEC across platforms - FIOCLEX / FIONCLEX now polyfilled for fast O_CLOEXEC changes - APE now supports a hybrid solution to no-self-modify for builds - Many BSD-only magnums added, e.g. O_SEARCH, O_SHLOCK, SF_NODISKIO
2021-08-12 07:42:14 +00:00
.ioctl = (void *)ioctl,
};
static int GetFd(struct Machine *m, int fd) {
if (!(0 <= fd && fd < m->fds.i)) return ebadf();
if (!m->fds.p[fd].cb) return ebadf();
return m->fds.p[fd].fd;
}
static int GetAfd(struct Machine *m, int fd) {
if (fd == -100) return AT_FDCWD;
return GetFd(m, fd);
}
2020-10-27 10:39:46 +00:00
static const char *GetSimulated(void) {
if (IsGenuineCosmo()) {
return " SIMULATED";
} else {
return "";
}
}
static int AppendIovsReal(struct Machine *m, struct Iovs *ib, int64_t addr,
size_t size) {
void *real;
size_t have;
unsigned got;
while (size) {
if (!(real = FindReal(m, addr))) return efault();
have = 0x1000 - (addr & 0xfff);
got = MIN(size, have);
if (AppendIovs(ib, real, got) == -1) return -1;
addr += got;
size -= got;
}
return 0;
}
static int AppendIovsGuest(struct Machine *m, struct Iovs *iv, int64_t iovaddr,
long iovlen) {
int rc;
2020-12-09 12:00:48 +00:00
size_t i, iovsize;
struct iovec *guestiovs;
if (!__builtin_mul_overflow(iovlen, sizeof(struct iovec), &iovsize) &&
(0 <= iovsize && iovsize <= 0x7ffff000)) {
if ((guestiovs = malloc(iovsize))) {
VirtualSendRead(m, guestiovs, iovaddr, iovsize);
for (rc = i = 0; i < iovlen; ++i) {
if (AppendIovsReal(m, iv, (intptr_t)guestiovs[i].iov_base,
guestiovs[i].iov_len) == -1) {
rc = -1;
break;
}
}
free(guestiovs);
} else {
rc = enomem();
}
} else {
rc = eoverflow();
}
return rc;
}
static int OpPrctl(struct Machine *m, int op, int64_t a, int64_t b, int64_t c,
int64_t d) {
return einval();
}
static int OpArchPrctl(struct Machine *m, int code, int64_t addr) {
switch (code) {
case ARCH_SET_GS:
Write64(m->gs, addr);
return 0;
case ARCH_SET_FS:
Write64(m->fs, addr);
return 0;
case ARCH_GET_GS:
VirtualRecvWrite(m, addr, m->gs, 8);
return 0;
case ARCH_GET_FS:
VirtualRecvWrite(m, addr, m->fs, 8);
return 0;
default:
return einval();
}
}
static int OpMprotect(struct Machine *m, int64_t addr, uint64_t len, int prot) {
return 0;
}
static int OpMadvise(struct Machine *m, int64_t addr, size_t length,
int advice) {
return enosys();
}
static int64_t OpBrk(struct Machine *m, int64_t addr) {
addr = ROUNDUP(addr, PAGESIZE);
if (addr > m->brk) {
if (ReserveVirtual(m, m->brk, addr - m->brk,
PAGE_V | PAGE_RW | PAGE_U | PAGE_RSRV) != -1) {
m->brk = addr;
}
} else if (addr < m->brk) {
if (FreeVirtual(m, addr, m->brk - addr) != -1) {
m->brk = addr;
}
}
return m->brk;
}
2020-10-27 10:39:46 +00:00
static int OpMunmap(struct Machine *m, int64_t virt, uint64_t size) {
VERBOSEF("MUNMAP%s %012lx %,ld", GetSimulated(), virt, size);
2020-10-27 10:39:46 +00:00
return FreeVirtual(m, virt, size);
}
static int64_t OpMmap(struct Machine *m, int64_t virt, size_t size, int prot,
int flags, int fd, int64_t offset) {
int e;
void *tmp;
ssize_t rc;
2020-10-27 10:39:46 +00:00
uint64_t key;
VERBOSEF("MMAP%s %012lx %,ld %#x %#x %d %#lx", GetSimulated(), virt, size,
prot, flags, fd, offset);
2020-10-27 10:39:46 +00:00
if (prot & PROT_READ) {
key = PAGE_RSRV | PAGE_U | PAGE_V;
if (prot & PROT_WRITE) key |= PAGE_RW;
if (!(prot & PROT_EXEC)) key |= PAGE_XD;
if (flags & 256 /* MAP_GROWSDOWN */) key |= PAGE_GROD;
2020-10-27 10:39:46 +00:00
flags = XlatMapFlags(flags);
if (fd != -1 && (fd = GetFd(m, fd)) == -1) return -1;
2020-10-27 10:39:46 +00:00
if (!(flags & MAP_FIXED)) {
if (!virt) {
if ((virt = FindVirtual(m, m->brk, size)) == -1) return -1;
m->brk = virt + size;
} else {
if ((virt = FindVirtual(m, virt, size)) == -1) return -1;
}
}
if (ReserveVirtual(m, virt, size, key) != -1) {
if (fd != -1 && !(flags & MAP_ANONYMOUS)) {
/* TODO: lazy file mappings */
CHECK_NOTNULL((tmp = malloc(size)));
for (e = errno;;) {
rc = pread(fd, tmp, size, offset);
if (rc != -1) break;
CHECK_EQ(EINTR, errno);
errno = e;
}
CHECK_EQ(size, rc);
2020-10-27 10:39:46 +00:00
VirtualRecvWrite(m, virt, tmp, size);
free(tmp);
}
} else {
2020-10-27 10:39:46 +00:00
FreeVirtual(m, virt, size);
return -1;
}
2020-10-27 10:39:46 +00:00
return virt;
} else {
return FreeVirtual(m, virt, size);
}
}
static int OpMsync(struct Machine *m, int64_t virt, size_t size, int flags) {
return enosys();
#if 0
size_t i;
void *page;
virt = ROUNDDOWN(virt, 4096);
flags = XlatMsyncFlags(flags);
for (i = 0; i < size; i += 4096) {
if (!(page = FindReal(m, virt + i))) return efault();
if (msync(page, 4096, flags) == -1) return -1;
}
return 0;
#endif
}
static int OpClose(struct Machine *m, int fd) {
int rc;
struct FdClosed *closed;
if (!(0 <= fd && fd < m->fds.i)) return ebadf();
if (!m->fds.p[fd].cb) return ebadf();
rc = m->fds.p[fd].cb->close(m->fds.p[fd].fd);
MachineFdRemove(&m->fds, fd);
return rc;
}
2020-10-27 10:39:46 +00:00
static int OpOpenat(struct Machine *m, int dirfd, int64_t pathaddr, int flags,
int mode) {
int fd, i;
2020-10-27 10:39:46 +00:00
const char *path;
flags = XlatOpenFlags(flags);
if ((dirfd = GetAfd(m, dirfd)) == -1) return -1;
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
2020-10-27 10:39:46 +00:00
path = LoadStr(m, pathaddr);
if ((fd = openat(dirfd, path, flags, mode)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = fd;
2020-10-27 10:39:46 +00:00
VERBOSEF("openat(%#x, %`'s, %#x, %#x) → %d [%d]", dirfd, path, flags, mode,
i, fd);
fd = i;
} else {
MachineFdRemove(&m->fds, i);
2020-10-27 10:39:46 +00:00
VERBOSEF("openat(%#x, %`'s, %#x, %#x) failed", dirfd, path, flags, mode);
}
return fd;
}
static int OpPipe(struct Machine *m, int64_t pipefds_addr) {
int i, j, pipefds[2];
if ((i = MachineFdAdd(&m->fds)) != -1) {
if ((j = MachineFdAdd(&m->fds)) != -1) {
if (pipe(pipefds) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = pipefds[0];
m->fds.p[j].cb = &kMachineFdCbHost;
m->fds.p[j].fd = pipefds[1];
pipefds[0] = i;
pipefds[1] = j;
VirtualRecvWrite(m, pipefds_addr, pipefds, sizeof(pipefds));
return 0;
}
MachineFdRemove(&m->fds, j);
}
MachineFdRemove(&m->fds, i);
}
return -1;
}
static int OpDup(struct Machine *m, int fd) {
int i;
if ((fd = GetFd(m, fd)) != -1) {
if ((i = MachineFdAdd(&m->fds)) != -1) {
if ((fd = dup(fd)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = fd;
return i;
}
MachineFdRemove(&m->fds, i);
}
}
return -1;
}
static int OpDup2(struct Machine *m, int fd, int newfd) {
int i, rc;
if ((fd = GetFd(m, fd)) == -1) return -1;
if ((0 <= newfd && newfd < m->fds.i)) {
if ((rc = dup2(fd, m->fds.p[newfd].fd)) != -1) {
m->fds.p[newfd].cb = &kMachineFdCbHost;
m->fds.p[newfd].fd = rc;
rc = newfd;
}
} else if ((i = MachineFdAdd(&m->fds)) != -1) {
if ((rc = dup(fd)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = rc;
rc = i;
}
} else {
rc = -1;
}
return rc;
}
static int OpDup3(struct Machine *m, int fd, int newfd, int flags) {
int i, rc;
if (!(flags & ~O_CLOEXEC_LINUX)) {
if ((fd = GetFd(m, fd)) == -1) return -1;
if ((0 <= newfd && newfd < m->fds.i)) {
if ((rc = dup2(fd, m->fds.p[newfd].fd)) != -1) {
if (flags & O_CLOEXEC_LINUX) {
fcntl(rc, F_SETFD, FD_CLOEXEC);
}
m->fds.p[newfd].cb = &kMachineFdCbHost;
m->fds.p[newfd].fd = rc;
rc = newfd;
}
} else if ((i = MachineFdAdd(&m->fds)) != -1) {
if ((rc = dup(fd)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = rc;
rc = i;
}
} else {
rc = -1;
}
return rc;
} else {
return einval();
}
}
static int OpSocket(struct Machine *m, int family, int type, int protocol) {
int i, fd;
if ((family = XlatSocketFamily(family)) == -1) return -1;
if ((type = XlatSocketType(type)) == -1) return -1;
if ((protocol = XlatSocketProtocol(protocol)) == -1) return -1;
if ((i = MachineFdAdd(&m->fds)) == -1) return -1;
if ((fd = socket(family, type, protocol)) != -1) {
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = fd;
fd = i;
} else {
MachineFdRemove(&m->fds, i);
}
return fd;
}
static int OpAccept4(struct Machine *m, int fd, int64_t aa, int64_t asa,
int flags) {
int i, rc;
uint32_t addrsize;
uint8_t gaddrsize[4];
struct sockaddr_in addr;
struct sockaddr_in_bits gaddr;
if (!(flags & ~SOCK_CLOEXEC_LINUX)) {
if ((fd = GetFd(m, fd)) == -1) return -1;
if (aa) {
VirtualSendRead(m, gaddrsize, asa, sizeof(gaddrsize));
if (Read32(gaddrsize) < sizeof(gaddr)) return einval();
}
if ((i = rc = MachineFdAdd(&m->fds)) != -1) {
addrsize = sizeof(addr);
if ((rc = accept(fd, (struct sockaddr *)&addr, &addrsize)) != -1) {
if (flags & SOCK_CLOEXEC_LINUX) {
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
if (aa) {
Write32(gaddrsize, sizeof(gaddr));
XlatSockaddrToLinux(&gaddr, &addr);
VirtualRecv(m, asa, gaddrsize, sizeof(gaddrsize));
VirtualRecvWrite(m, aa, &gaddr, sizeof(gaddr));
}
m->fds.p[i].cb = &kMachineFdCbHost;
m->fds.p[i].fd = rc;
rc = i;
} else {
MachineFdRemove(&m->fds, i);
}
}
return rc;
} else {
return einval();
}
}
static int OpConnectBind(struct Machine *m, int fd, int64_t aa, uint32_t as,
int impl(int, const void *, uint32_t)) {
struct sockaddr_in addr;
struct sockaddr_in_bits gaddr;
if (as != sizeof(gaddr)) return einval();
if ((fd = GetFd(m, fd)) == -1) return -1;
VirtualSendRead(m, &gaddr, aa, sizeof(gaddr));
XlatSockaddrToHost(&addr, &gaddr);
return impl(fd, (const struct sockaddr *)&addr, sizeof(addr));
}
static int OpBind(struct Machine *m, int fd, int64_t aa, uint32_t as) {
return OpConnectBind(m, fd, aa, as, bind);
}
static int OpConnect(struct Machine *m, int fd, int64_t aa, uint32_t as) {
return OpConnectBind(m, fd, aa, as, connect);
}
static int OpSetsockopt(struct Machine *m, int fd, int level, int optname,
int64_t optvaladdr, uint32_t optvalsize) {
int rc;
void *optval;
if ((level = XlatSocketLevel(level)) == -1) return -1;
if ((optname = XlatSocketOptname(level, optname)) == -1) return -1;
if ((fd = GetFd(m, fd)) == -1) return -1;
if (!(optval = malloc(optvalsize))) return -1;
VirtualSendRead(m, optval, optvaladdr, optvalsize);
rc = setsockopt(fd, level, optname, optval, optvalsize);
free(optval);
return rc;
}
static int OpGetsockopt(struct Machine *m, int fd, int level, int optname,
int64_t optvaladdr, int64_t optsizeaddr) {
int rc;
void *optval;
uint32_t optsize;
if ((level = XlatSocketLevel(level)) == -1) return -1;
if ((optname = XlatSocketOptname(level, optname)) == -1) return -1;
if ((fd = GetFd(m, fd)) == -1) return -1;
if (!optvaladdr) {
rc = getsockopt(fd, level, optname, 0, 0);
} else {
VirtualSendRead(m, &optsize, optsizeaddr, sizeof(optsize));
if (!(optval = malloc(optsize))) return -1;
if ((rc = getsockopt(fd, level, optname, optval, &optsize)) != -1) {
VirtualRecvWrite(m, optvaladdr, optval, optsize);
VirtualRecvWrite(m, optsizeaddr, &optsize, sizeof(optsize));
}
free(optval);
}
return rc;
}
static int OpSocketName(struct Machine *m, int fd, int64_t aa, int64_t asa,
int SocketName(int, void *, socklen_t *)) {
int rc;
uint32_t addrsize;
uint8_t gaddrsize[4];
struct sockaddr_in addr;
struct sockaddr_in_bits gaddr;
if ((fd = GetFd(m, fd)) == -1) return -1;
VirtualSendRead(m, gaddrsize, asa, sizeof(gaddrsize));
if (Read32(gaddrsize) < sizeof(gaddr)) return einval();
addrsize = sizeof(addr);
if ((rc = SocketName(fd, (struct sockaddr *)&addr, &addrsize)) != -1) {
Write32(gaddrsize, sizeof(gaddr));
XlatSockaddrToLinux(&gaddr, &addr);
VirtualRecv(m, asa, gaddrsize, sizeof(gaddrsize));
VirtualRecvWrite(m, aa, &gaddr, sizeof(gaddr));
}
return rc;
}
static int OpGetsockname(struct Machine *m, int fd, int64_t aa, int64_t asa) {
return OpSocketName(m, fd, aa, asa, getsockname);
}
static int OpGetpeername(struct Machine *m, int fd, int64_t aa, int64_t asa) {
return OpSocketName(m, fd, aa, asa, getpeername);
}
static ssize_t OpRead(struct Machine *m, int fd, int64_t addr, size_t size) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = m->fds.p[fd].cb->readv(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
SetWriteAddr(m, addr, rc);
}
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static int OpGetdents(struct Machine *m, int dirfd, int64_t addr,
uint32_t size) {
int rc;
DIR *dir;
struct dirent *ent;
if (size < sizeof(struct dirent)) return einval();
if (0 <= dirfd && dirfd < m->fds.i) {
if ((dir = fdopendir(m->fds.p[dirfd].fd))) {
rc = 0;
while (rc + sizeof(struct dirent) <= size) {
if (!(ent = readdir(dir))) break;
VirtualRecvWrite(m, addr + rc, ent, ent->d_reclen);
rc += ent->d_reclen;
}
free(dir);
} else {
rc = -1;
}
} else {
rc = ebadf();
}
return rc;
}
static ssize_t OpPread(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((rc = GetFd(m, fd)) != -1) {
fd = rc;
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = preadv(fd, iv.p, iv.i, offset)) != -1) {
SetWriteAddr(m, addr, rc);
}
}
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpWrite(struct Machine *m, int fd, int64_t addr, size_t size) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i)) != -1) {
SetReadAddr(m, addr, rc);
2020-10-27 10:39:46 +00:00
} else {
VERBOSEF("write(%d [%d], %012lx, %zu) failed: %s", fd, m->fds.p[fd].fd,
2020-10-27 10:39:46 +00:00
addr, size, strerror(errno));
}
}
} else {
VERBOSEF("write(%d, %012lx, %zu) bad fd", fd, addr, size);
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpPwrite(struct Machine *m, int fd, int64_t addr, size_t size,
int64_t offset) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((rc = GetFd(m, fd)) != -1) {
fd = rc;
if ((rc = AppendIovsReal(m, &iv, addr, size)) != -1) {
if ((rc = pwritev(fd, iv.p, iv.i, offset)) != -1) {
SetReadAddr(m, addr, rc);
}
}
}
FreeIovs(&iv);
return rc;
}
static int IoctlTiocgwinsz(struct Machine *m, int fd, int64_t addr,
int fn(int, int, ...)) {
int rc;
struct winsize ws;
struct winsize_bits gws;
if ((rc = fn(fd, TIOCGWINSZ, &ws)) != -1) {
XlatWinsizeToLinux(&gws, &ws);
VirtualRecvWrite(m, addr, &gws, sizeof(gws));
}
return rc;
}
static int IoctlTcgets(struct Machine *m, int fd, int64_t addr,
int fn(int, int, ...)) {
int rc;
struct termios tio;
struct termios_bits gtio;
if ((rc = fn(fd, TCGETS, &tio)) != -1) {
XlatTermiosToLinux(&gtio, &tio);
VirtualRecvWrite(m, addr, &gtio, sizeof(gtio));
}
return rc;
}
static int IoctlTcsets(struct Machine *m, int fd, int64_t request, int64_t addr,
int (*fn)(int, int, ...)) {
struct termios tio;
struct termios_bits gtio;
VirtualSendRead(m, &gtio, addr, sizeof(gtio));
XlatLinuxToTermios(&tio, &gtio);
return fn(fd, request, &tio);
}
static int OpIoctl(struct Machine *m, int fd, uint64_t request, int64_t addr) {
int (*fn)(int, int, ...);
if (!(0 <= fd && fd < m->fds.i) || !m->fds.p[fd].cb) return ebadf();
fn = m->fds.p[fd].cb->ioctl;
fd = m->fds.p[fd].fd;
switch (request) {
case TIOCGWINSZ_LINUX:
return IoctlTiocgwinsz(m, fd, addr, fn);
case TCGETS_LINUX:
return IoctlTcgets(m, fd, addr, fn);
case TCSETS_LINUX:
return IoctlTcsets(m, fd, TCSETS, addr, fn);
case TCSETSW_LINUX:
return IoctlTcsets(m, fd, TCSETSW, addr, fn);
case TCSETSF_LINUX:
return IoctlTcsets(m, fd, TCSETSF, addr, fn);
default:
return einval();
}
}
static ssize_t OpReadv(struct Machine *m, int fd, int64_t iovaddr, int iovlen) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen)) != -1) {
rc = m->fds.p[fd].cb->readv(m->fds.p[fd].fd, iv.p, iv.i);
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static ssize_t OpWritev(struct Machine *m, int fd, int64_t iovaddr,
int iovlen) {
ssize_t rc;
struct Iovs iv;
InitIovs(&iv);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
if ((rc = AppendIovsGuest(m, &iv, iovaddr, iovlen)) != -1) {
rc = m->fds.p[fd].cb->writev(m->fds.p[fd].fd, iv.p, iv.i);
}
} else {
rc = ebadf();
}
FreeIovs(&iv);
return rc;
}
static int64_t OpLseek(struct Machine *m, int fd, int64_t offset, int whence) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return lseek(fd, offset, whence);
}
static ssize_t OpFtruncate(struct Machine *m, int fd, int64_t size) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return ftruncate(fd, size);
}
static int OpFaccessat(struct Machine *m, int dirfd, int64_t path, int mode,
int flags) {
flags = XlatAtf(flags);
mode = XlatAccess(mode);
if ((dirfd = GetAfd(m, dirfd)) == -1) return -1;
return faccessat(dirfd, LoadStr(m, path), mode, flags);
}
static int OpFstatat(struct Machine *m, int dirfd, int64_t path, int64_t staddr,
int flags) {
int rc;
struct stat st;
struct stat_bits gst;
flags = XlatAtf(flags);
if ((dirfd = GetAfd(m, dirfd)) == -1) return -1;
if ((rc = fstatat(dirfd, LoadStr(m, path), &st, flags)) != -1) {
XlatStatToLinux(&gst, &st);
VirtualRecvWrite(m, staddr, &gst, sizeof(gst));
}
return rc;
}
static int OpFstat(struct Machine *m, int fd, int64_t staddr) {
int rc;
struct stat st;
struct stat_bits gst;
if ((fd = GetFd(m, fd)) == -1) return -1;
if ((rc = fstat(fd, &st)) != -1) {
XlatStatToLinux(&gst, &st);
VirtualRecvWrite(m, staddr, &gst, sizeof(gst));
}
return rc;
}
static int OpListen(struct Machine *m, int fd, int backlog) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return listen(fd, backlog);
}
static int OpShutdown(struct Machine *m, int fd, int how) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return shutdown(fd, how);
}
static int OpFsync(struct Machine *m, int fd) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return fsync(fd);
}
static int OpFdatasync(struct Machine *m, int fd) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return fdatasync(fd);
}
static int OpFchmod(struct Machine *m, int fd, uint32_t mode) {
if ((fd = GetFd(m, fd)) == -1) return -1;
return fchmod(fd, mode);
}
static int OpFcntl(struct Machine *m, int fd, int cmd, int arg) {
if ((cmd = XlatFcntlCmd(cmd)) == -1) return -1;
if ((arg = XlatFcntlArg(arg)) == -1) return -1;
if ((fd = GetFd(m, fd)) == -1) return -1;
return fcntl(fd, cmd, arg);
}
static int OpFadvise(struct Machine *m, int fd, uint64_t offset, uint64_t len,
int advice) {
if ((fd = GetFd(m, fd)) == -1) return -1;
if ((advice = XlatAdvice(advice)) == -1) return -1;
return fadvise(fd, offset, len, advice);
}
static int OpFlock(struct Machine *m, int fd, int lock) {
if ((fd = GetFd(m, fd)) == -1) return -1;
if ((lock = XlatLock(lock)) == -1) return -1;
return flock(fd, lock);
}
static int OpChdir(struct Machine *m, int64_t path) {
return chdir(LoadStr(m, path));
}
static int OpMkdir(struct Machine *m, int64_t path, int mode) {
return mkdir(LoadStr(m, path), mode);
}
static int OpMkdirat(struct Machine *m, int dirfd, int64_t path, int mode) {
return mkdirat(GetAfd(m, dirfd), LoadStr(m, path), mode);
}
static int OpMknod(struct Machine *m, int64_t path, uint32_t mode,
uint64_t dev) {
return mknod(LoadStr(m, path), mode, dev);
}
static int OpRmdir(struct Machine *m, int64_t path) {
return rmdir(LoadStr(m, path));
}
static int OpUnlink(struct Machine *m, int64_t path) {
return unlink(LoadStr(m, path));
}
static int OpUnlinkat(struct Machine *m, int dirfd, int64_t path, int flags) {
return unlinkat(GetAfd(m, dirfd), LoadStr(m, path), XlatAtf(flags));
}
static int OpRename(struct Machine *m, int64_t src, int64_t dst) {
return rename(LoadStr(m, src), LoadStr(m, dst));
}
static int OpRenameat(struct Machine *m, int srcdirfd, int64_t src,
int dstdirfd, int64_t dst) {
return renameat(GetAfd(m, srcdirfd), LoadStr(m, src), GetAfd(m, dstdirfd),
LoadStr(m, dst));
}
static int OpTruncate(struct Machine *m, int64_t path, uint64_t length) {
return truncate(LoadStr(m, path), length);
}
static int OpLink(struct Machine *m, int64_t existingpath, int64_t newpath) {
return link(LoadStr(m, existingpath), LoadStr(m, newpath));
}
static int OpSymlink(struct Machine *m, int64_t target, int64_t linkpath) {
return symlink(LoadStr(m, target), LoadStr(m, linkpath));
}
static int OpChmod(struct Machine *m, int64_t path, uint32_t mode) {
return chmod(LoadStr(m, path), mode);
}
static int OpFork(struct Machine *m) {
int pid;
pid = fork();
if (!pid) m->isfork = true;
return pid;
}
static int OpExecve(struct Machine *m, int64_t programaddr, int64_t argvaddr,
int64_t envpaddr) {
return enosys();
}
wontreturn static void OpExit(struct Machine *m, int rc) {
if (m->isfork) {
_Exit(rc);
} else {
HaltMachine(m, rc | 0x100);
}
}
_Noreturn static void OpExitGroup(struct Machine *m, int rc) {
OpExit(m, rc);
}
static int OpWait4(struct Machine *m, int pid, int64_t opt_out_wstatus_addr,
int options, int64_t opt_out_rusage_addr) {
int rc;
int32_t wstatus;
struct rusage hrusage;
struct rusage_bits grusage;
if ((options = XlatWait(options)) == -1) return -1;
if ((rc = wait4(pid, &wstatus, options, &hrusage)) != -1) {
if (opt_out_wstatus_addr) {
VirtualRecvWrite(m, opt_out_wstatus_addr, &wstatus, sizeof(wstatus));
}
if (opt_out_rusage_addr) {
XlatRusageToLinux(&grusage, &hrusage);
VirtualRecvWrite(m, opt_out_rusage_addr, &grusage, sizeof(grusage));
}
}
return rc;
}
static int OpGetrusage(struct Machine *m, int resource, int64_t rusageaddr) {
int rc;
struct rusage hrusage;
struct rusage_bits grusage;
if ((resource = XlatRusage(resource)) == -1) return -1;
if ((rc = getrusage(resource, &hrusage)) != -1) {
XlatRusageToLinux(&grusage, &hrusage);
VirtualRecvWrite(m, rusageaddr, &grusage, sizeof(grusage));
}
return rc;
}
static int OpGetrlimit(struct Machine *m, int resource, int64_t rlimitaddr) {
return enosys();
}
static ssize_t OpReadlinkat(struct Machine *m, int dirfd, int64_t pathaddr,
int64_t bufaddr, size_t size) {
char *buf;
ssize_t rc;
const char *path;
if ((dirfd = GetAfd(m, dirfd)) == -1) return -1;
path = LoadStr(m, pathaddr);
if (!(buf = malloc(size))) return enomem();
if ((rc = readlinkat(dirfd, path, buf, size)) != -1) {
VirtualRecvWrite(m, bufaddr, buf, rc);
}
free(buf);
return rc;
}
static int64_t OpGetcwd(struct Machine *m, int64_t bufaddr, size_t size) {
size_t n;
char *buf;
int64_t res;
size = MIN(size, PATH_MAX);
if (!(buf = malloc(size))) return enomem();
if ((getcwd)(buf, size)) {
n = strlen(buf);
VirtualRecvWrite(m, bufaddr, buf, n);
res = bufaddr;
} else {
res = -1;
}
free(buf);
return res;
}
static int OpSigaction(struct Machine *m, int sig, int64_t act, int64_t old,
uint64_t sigsetsize) {
if ((sig = XlatSignal(sig) - 1) != -1 &&
(0 <= sig && sig < ARRAYLEN(m->sighand)) && sigsetsize == 8) {
if (old) VirtualRecvWrite(m, old, &m->sighand[sig], sizeof(m->sighand[0]));
if (act) VirtualSendRead(m, &m->sighand[sig], act, sizeof(m->sighand[0]));
return 0;
} else {
return einval();
}
}
static int OpSigprocmask(struct Machine *m, int how, int64_t setaddr,
int64_t oldsetaddr, uint64_t sigsetsize) {
uint8_t set[8];
if ((how = XlatSig(how)) != -1 && sigsetsize == sizeof(set)) {
if (oldsetaddr) {
VirtualRecvWrite(m, oldsetaddr, m->sigmask, sizeof(set));
}
if (setaddr) {
VirtualSendRead(m, set, setaddr, sizeof(set));
if (how == SIG_BLOCK) {
Write64(m->sigmask, Read64(m->sigmask) | Read64(set));
} else if (how == SIG_UNBLOCK) {
Write64(m->sigmask, Read64(m->sigmask) & ~Read64(set));
} else {
Write64(m->sigmask, Read64(set));
}
}
return 0;
} else {
return einval();
}
}
static int OpGetitimer(struct Machine *m, int which, int64_t curvaladdr) {
int rc;
struct itimerval it;
struct itimerval_bits git;
if ((rc = getitimer(which, &it)) != -1) {
XlatItimervalToLinux(&git, &it);
VirtualRecvWrite(m, curvaladdr, &git, sizeof(git));
}
return rc;
}
static int OpSetitimer(struct Machine *m, int which, int64_t neuaddr,
int64_t oldaddr) {
int rc;
struct itimerval neu, old;
struct itimerval_bits git;
VirtualSendRead(m, &git, neuaddr, sizeof(git));
XlatLinuxToItimerval(&neu, &git);
if ((rc = setitimer(which, &neu, &old)) != -1) {
if (oldaddr) {
XlatItimervalToLinux(&git, &old);
VirtualRecvWrite(m, oldaddr, &git, sizeof(git));
}
}
return rc;
}
static int OpNanosleep(struct Machine *m, int64_t req, int64_t rem) {
int rc;
struct timespec hreq, hrem;
struct timespec_bits gtimespec;
if (req) {
VirtualSendRead(m, &gtimespec, req, sizeof(gtimespec));
hreq.tv_sec = Read64(gtimespec.tv_sec);
hreq.tv_nsec = Read64(gtimespec.tv_nsec);
}
if ((rc = nanosleep(req ? &hreq : 0, rem ? &hrem : 0)) != -1) {
if (rem) {
Write64(gtimespec.tv_sec, hrem.tv_sec);
Write64(gtimespec.tv_nsec, hrem.tv_nsec);
VirtualRecvWrite(m, rem, &gtimespec, sizeof(gtimespec));
}
}
return rc;
}
static int OpSigsuspend(struct Machine *m, int64_t maskaddr) {
sigset_t mask;
uint8_t gmask[8];
VirtualSendRead(m, &gmask, maskaddr, 8);
XlatLinuxToSigset(&mask, gmask);
return sigsuspend(&mask);
}
static int OpClockGettime(struct Machine *m, int clockid, int64_t ts) {
int rc;
struct timespec htimespec;
struct timespec_bits gtimespec;
if ((rc = clock_gettime(XlatClock(clockid), ts ? &htimespec : 0)) != -1) {
if (ts) {
Write64(gtimespec.tv_sec, htimespec.tv_sec);
Write64(gtimespec.tv_nsec, htimespec.tv_nsec);
VirtualRecvWrite(m, ts, &gtimespec, sizeof(gtimespec));
}
}
return rc;
}
static int OpGettimeofday(struct Machine *m, int64_t tv, int64_t tz) {
int rc;
struct timeval htimeval;
struct timezone htimezone;
struct timeval_bits gtimeval;
struct timezone_bits gtimezone;
if ((rc = gettimeofday(&htimeval, tz ? &htimezone : 0)) != -1) {
Write64(gtimeval.tv_sec, htimeval.tv_sec);
Write64(gtimeval.tv_usec, htimeval.tv_usec);
VirtualRecvWrite(m, tv, &gtimeval, sizeof(gtimeval));
if (tz) {
Write32(gtimezone.tz_minuteswest, htimezone.tz_minuteswest);
Write32(gtimezone.tz_dsttime, htimezone.tz_dsttime);
VirtualRecvWrite(m, tz, &gtimezone, sizeof(gtimezone));
}
}
return rc;
}
static int OpUtimes(struct Machine *m, int64_t pathaddr, int64_t tvsaddr) {
const char *path;
struct timeval tvs[2];
struct timeval_bits gtvs[2];
path = LoadStr(m, pathaddr);
if (tvsaddr) {
VirtualSendRead(m, gtvs, tvsaddr, sizeof(gtvs));
tvs[0].tv_sec = Read64(gtvs[0].tv_sec);
tvs[0].tv_usec = Read64(gtvs[0].tv_usec);
tvs[1].tv_sec = Read64(gtvs[1].tv_sec);
tvs[1].tv_usec = Read64(gtvs[1].tv_usec);
return utimes(path, tvs);
} else {
return utimes(path, 0);
}
}
static int OpPoll(struct Machine *m, int64_t fdsaddr, uint64_t nfds,
int32_t timeout_ms) {
uint64_t gfdssize;
struct pollfd hfds[1];
int i, fd, rc, ev, count;
struct timespec ts1, ts2;
struct pollfd_bits *gfds;
int64_t wait, elapsed, timeout;
timeout = timeout_ms * 1000L;
if (!__builtin_mul_overflow(nfds, sizeof(struct pollfd_bits), &gfdssize) &&
gfdssize <= 0x7ffff000) {
if ((gfds = malloc(gfdssize))) {
rc = 0;
VirtualSendRead(m, gfds, fdsaddr, gfdssize);
ts1 = _timespec_mono();
for (;;) {
for (i = 0; i < nfds; ++i) {
fd = Read32(gfds[i].fd);
if ((0 <= fd && fd < m->fds.i) && m->fds.p[fd].cb) {
hfds[0].fd = m->fds.p[fd].fd;
ev = Read16(gfds[i].events);
hfds[0].events = (((ev & POLLIN_LINUX) ? POLLIN : 0) |
((ev & POLLOUT_LINUX) ? POLLOUT : 0) |
((ev & POLLPRI_LINUX) ? POLLPRI : 0));
switch (m->fds.p[fd].cb->poll(hfds, 1, 0)) {
case 0:
Write16(gfds[i].revents, 0);
break;
case 1:
++rc;
ev = 0;
if (hfds[0].revents & POLLIN) ev |= POLLIN_LINUX;
if (hfds[0].revents & POLLPRI) ev |= POLLPRI_LINUX;
if (hfds[0].revents & POLLOUT) ev |= POLLOUT_LINUX;
if (hfds[0].revents & POLLERR) ev |= POLLERR_LINUX;
if (hfds[0].revents & POLLHUP) ev |= POLLHUP_LINUX;
if (hfds[0].revents & POLLNVAL) ev |= POLLERR_LINUX;
if (!ev) ev |= POLLERR_LINUX;
Write16(gfds[i].revents, ev);
break;
case -1:
++rc;
Write16(gfds[i].revents, POLLERR_LINUX);
break;
default:
break;
}
} else {
Write16(gfds[i].revents, POLLNVAL_LINUX);
}
}
if (rc || !timeout) break;
wait = __SIG_POLLING_INTERVAL_MS * 1000;
if (timeout < 0) {
if (usleep(wait)) {
errno = EINTR;
rc = -1;
goto Finished;
}
} else {
ts2 = _timespec_mono();
elapsed = _timespec_tomicros(_timespec_sub(ts2, ts1));
if (elapsed >= timeout) {
break;
}
if (timeout - elapsed < wait) {
wait = timeout - elapsed;
}
if (usleep(wait)) {
errno = EINTR;
rc = -1;
goto Finished;
}
}
}
VirtualRecvWrite(m, fdsaddr, gfds, nfds * sizeof(*gfds));
} else {
errno = ENOMEM;
rc = -1;
}
Finished:
free(gfds);
return rc;
} else {
return einval();
}
}
static int OpGetPid(struct Machine *m) {
return getpid();
}
static int OpGetPpid(struct Machine *m) {
return getppid();
}
static void OpKill(struct Machine *m, int pid, int sig) {
if (!pid || pid == getpid()) {
DeliverSignal(m, sig, SI_USER);
} else {
Write64(m->ax, -3); // ESRCH
}
}
static int OpGetUid(struct Machine *m) {
return getuid();
}
static int OpGetGid(struct Machine *m) {
return getgid();
}
static int OpGetTid(struct Machine *m) {
return gettid();
}
static int OpSchedYield(struct Machine *m) {
return sched_yield();
}
static int OpAlarm(struct Machine *m, unsigned seconds) {
return alarm(seconds);
}
static int OpPause(struct Machine *m) {
return pause();
}
static int DoOpen(struct Machine *m, int64_t path, int flags, int mode) {
return OpOpenat(m, -100, path, flags, mode);
}
static int DoCreat(struct Machine *m, int64_t file, int mode) {
return DoOpen(m, file, 0x241, mode);
}
static int DoAccess(struct Machine *m, int64_t path, int mode) {
return OpFaccessat(m, -100, path, mode, 0);
}
static int DoStat(struct Machine *m, int64_t path, int64_t st) {
return OpFstatat(m, -100, path, st, 0);
}
static int DoLstat(struct Machine *m, int64_t path, int64_t st) {
return OpFstatat(m, -100, path, st, 0x0400);
}
static int OpAccept(struct Machine *m, int fd, int64_t sa, int64_t sas) {
return OpAccept4(m, fd, sa, sas, 0);
}
void OpSyscall(struct Machine *m, uint32_t rde) {
uint64_t i, ax, di, si, dx, r0, r8, r9;
if (m->redraw) {
m->redraw();
}
ax = Read64(m->ax);
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
if (m->ismetal) {
WARNF("metal syscall 0x%03x", ax);
}
di = Read64(m->di);
si = Read64(m->si);
dx = Read64(m->dx);
r0 = Read64(m->r10);
r8 = Read64(m->r8);
r9 = Read64(m->r9);
switch (ax & 0x1ff) {
SYSCALL(0x000, OpRead(m, di, si, dx));
SYSCALL(0x001, OpWrite(m, di, si, dx));
SYSCALL(0x002, DoOpen(m, di, si, dx));
SYSCALL(0x003, OpClose(m, di));
SYSCALL(0x004, DoStat(m, di, si));
SYSCALL(0x005, OpFstat(m, di, si));
SYSCALL(0x006, DoLstat(m, di, si));
SYSCALL(0x007, OpPoll(m, di, si, dx));
SYSCALL(0x008, OpLseek(m, di, si, dx));
SYSCALL(0x009, OpMmap(m, di, si, dx, r0, r8, r9));
SYSCALL(0x01A, OpMsync(m, di, si, dx));
SYSCALL(0x00A, OpMprotect(m, di, si, dx));
SYSCALL(0x00B, OpMunmap(m, di, si));
SYSCALL(0x00C, OpBrk(m, di));
SYSCALL(0x00D, OpSigaction(m, di, si, dx, r0));
SYSCALL(0x00E, OpSigprocmask(m, di, si, dx, r0));
SYSCALL(0x010, OpIoctl(m, di, si, dx));
SYSCALL(0x011, OpPread(m, di, si, dx, r0));
SYSCALL(0x012, OpPwrite(m, di, si, dx, r0));
SYSCALL(0x013, OpReadv(m, di, si, dx));
SYSCALL(0x014, OpWritev(m, di, si, dx));
SYSCALL(0x015, DoAccess(m, di, si));
SYSCALL(0x016, OpPipe(m, di));
SYSCALL(0x017, select(di, P(si), P(dx), P(r0), P(r8)));
SYSCALL(0x018, OpSchedYield(m));
SYSCALL(0x01C, OpMadvise(m, di, si, dx));
SYSCALL(0x020, OpDup(m, di));
SYSCALL(0x021, OpDup2(m, di, si));
SYSCALL(0x124, OpDup3(m, di, si, dx));
SYSCALL(0x022, OpPause(m));
SYSCALL(0x023, OpNanosleep(m, di, si));
SYSCALL(0x024, OpGetitimer(m, di, si));
SYSCALL(0x025, OpAlarm(m, di));
SYSCALL(0x026, OpSetitimer(m, di, si, dx));
SYSCALL(0x027, OpGetPid(m));
SYSCALL(0x028, sendfile(di, si, P(dx), r0));
SYSCALL(0x029, OpSocket(m, di, si, dx));
SYSCALL(0x02A, OpConnect(m, di, si, dx));
SYSCALL(0x02B, OpAccept(m, di, di, dx));
SYSCALL(0x02C, sendto(di, PNN(si), dx, r0, P(r8), r9));
SYSCALL(0x02D, recvfrom(di, P(si), dx, r0, P(r8), P(r9)));
SYSCALL(0x030, OpShutdown(m, di, si));
SYSCALL(0x031, OpBind(m, di, si, dx));
SYSCALL(0x032, OpListen(m, di, si));
SYSCALL(0x033, OpGetsockname(m, di, si, dx));
SYSCALL(0x034, OpGetpeername(m, di, si, dx));
SYSCALL(0x036, OpSetsockopt(m, di, si, dx, r0, r8));
SYSCALL(0x037, OpGetsockopt(m, di, si, dx, r0, r8));
SYSCALL(0x039, OpFork(m));
SYSCALL(0x03B, OpExecve(m, di, si, dx));
SYSCALL(0x03D, OpWait4(m, di, si, dx, r0));
SYSCALL(0x03F, uname(P(di)));
SYSCALL(0x048, OpFcntl(m, di, si, dx));
SYSCALL(0x049, OpFlock(m, di, si));
SYSCALL(0x04A, OpFsync(m, di));
SYSCALL(0x04B, OpFdatasync(m, di));
SYSCALL(0x04C, OpTruncate(m, di, si));
SYSCALL(0x04D, OpFtruncate(m, di, si));
SYSCALL(0x04F, OpGetcwd(m, di, si));
SYSCALL(0x050, OpChdir(m, di));
SYSCALL(0x052, OpRename(m, di, si));
SYSCALL(0x053, OpMkdir(m, di, si));
SYSCALL(0x054, OpRmdir(m, di));
SYSCALL(0x055, DoCreat(m, di, si));
SYSCALL(0x056, OpLink(m, di, si));
SYSCALL(0x057, OpUnlink(m, di));
SYSCALL(0x058, OpSymlink(m, di, si));
SYSCALL(0x05A, OpChmod(m, di, si));
SYSCALL(0x05B, OpFchmod(m, di, si));
SYSCALL(0x060, OpGettimeofday(m, di, si));
SYSCALL(0x061, OpGetrlimit(m, di, si));
SYSCALL(0x062, OpGetrusage(m, di, si));
SYSCALL(0x063, sysinfo(PNN(di)));
SYSCALL(0x064, times(PNN(di)));
SYSCALL(0x066, OpGetUid(m));
SYSCALL(0x068, OpGetGid(m));
SYSCALL(0x06E, OpGetPpid(m));
SYSCALL(0x075, setresuid(di, si, dx));
SYSCALL(0x077, setresgid(di, si, dx));
SYSCALL(0x082, OpSigsuspend(m, di));
SYSCALL(0x085, OpMknod(m, di, si, dx));
SYSCALL(0x08C, getpriority(di, si));
SYSCALL(0x08D, setpriority(di, si, dx));
SYSCALL(0x0A0, setrlimit(di, P(si)));
SYSCALL(0x084, utime(PNN(di), PNN(si)));
SYSCALL(0x0EB, OpUtimes(m, di, si));
SYSCALL(0x09D, OpPrctl(m, di, si, dx, r0, r8));
SYSCALL(0x09E, OpArchPrctl(m, di, si));
SYSCALL(0x0BA, OpGetTid(m));
SYSCALL(0x0CB, sched_setaffinity(di, si, P(dx)));
SYSCALL(0x0D9, OpGetdents(m, di, si, dx));
SYSCALL(0x0DD, OpFadvise(m, di, si, dx, r0));
SYSCALL(0x0E4, OpClockGettime(m, di, si));
SYSCALL(0x101, OpOpenat(m, di, si, dx, r0));
SYSCALL(0x102, OpMkdirat(m, di, si, dx));
SYSCALL(0x104, fchownat(GetAfd(m, di), P(si), dx, r0, XlatAtf(r8)));
SYSCALL(0x105, futimesat(GetAfd(m, di), P(si), P(dx)));
SYSCALL(0x106, OpFstatat(m, di, si, dx, r0));
SYSCALL(0x107, OpUnlinkat(m, di, si, dx));
SYSCALL(0x108, OpRenameat(m, di, si, dx, r0));
SYSCALL(0x10B, OpReadlinkat(m, di, si, dx, r0));
SYSCALL(0x10D, OpFaccessat(m, di, si, dx, r0));
SYSCALL(0x113, splice(di, P(si), dx, P(r0), r8, XlatAtf(r9)));
SYSCALL(0x115, sync_file_range(di, si, dx, XlatAtf(r0)));
SYSCALL(0x118, utimensat(GetAfd(m, di), P(si), P(dx), XlatAtf(r0)));
SYSCALL(0x120, OpAccept4(m, di, si, dx, r0));
SYSCALL(0x177, vmsplice(di, P(si), dx, r0));
case 0x3C:
OpExit(m, di);
case 0xE7:
OpExitGroup(m, di);
case 0x00F:
OpRestore(m);
return;
case 0x03E:
OpKill(m, di, si);
return;
default:
Make numerous improvements - Python static hello world now 1.8mb - Python static fully loaded now 10mb - Python HTTPS client now uses MbedTLS - Python REPL now completes import stmts - Increase stack size for Python for now - Begin synthesizing posixpath and ntpath - Restore Python \N{UNICODE NAME} support - Restore Python NFKD symbol normalization - Add optimized code path for Intel SHA-NI - Get more Python unit tests passing faster - Get Python help() pagination working on NT - Python hashlib now supports MbedTLS PBKDF2 - Make memcpy/memmove/memcmp/bcmp/etc. faster - Add Mersenne Twister and Vigna to LIBC_RAND - Provide privileged __printf() for error code - Fix zipos opendir() so that it reports ENOTDIR - Add basic chmod() implementation for Windows NT - Add Cosmo's best functions to Python cosmo module - Pin function trace indent depth to that of caller - Show memory diagram on invalid access in MODE=dbg - Differentiate stack overflow on crash in MODE=dbg - Add stb_truetype and tools for analyzing font files - Upgrade to UNICODE 13 and reduce its binary footprint - COMPILE.COM now logs resource usage of build commands - Start implementing basic poll() support on bare metal - Set getauxval(AT_EXECFN) to GetModuleFileName() on NT - Add descriptions to strerror() in non-TINY build modes - Add COUNTBRANCH() macro to help with micro-optimizations - Make error / backtrace / asan / memory code more unbreakable - Add fast perfect C implementation of μ-Law and a-Law audio codecs - Make strtol() functions consistent with other libc implementations - Improve Linenoise implementation (see also github.com/jart/bestline) - COMPILE.COM now suppresses stdout/stderr of successful build commands
2021-09-28 05:58:51 +00:00
WARNF("missing syscall 0x%03x", ax);
ax = enosys();
break;
}
Write64(m->ax, ax != -1 ? ax : -(XlatErrno(errno) & 0xfff));
for (i = 0; i < m->freelist.i; ++i) free(m->freelist.p[i]);
m->freelist.i = 0;
}