From dc0ea6640e13e6f615e2c1f853c76d1de367b4b9 Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Sat, 16 Apr 2022 10:40:23 -0700 Subject: [PATCH] Fix bugs with recent change This change makes further effort towards improving our poll() implementation on the New Technology. The stdin worker didn't work out so well for Python so it's not being used for now. System call tracing with the --strace flag should now be less noisy now on Windows unless you modify the strace.internal.h defines to turn on some optional ones that are most useful for debugging the system call wrappers. --- examples/breakpoint.c | 25 +- examples/linenoise.c | 23 ++ examples/printargs.c | 111 +------- libc/calls/close-nt.c | 19 +- libc/calls/directmap-nt.c | 11 +- libc/calls/directmap.c | 6 +- libc/calls/fcntl.c | 2 +- libc/calls/fstat.c | 2 +- libc/calls/g_fds.c | 4 + libc/calls/getauxval.c | 3 - libc/calls/getegid.c | 31 +++ libc/calls/gethostname.c | 2 + libc/{runtime/getsymbol.c => calls/getpgrp.c} | 36 ++- libc/calls/getrusage-nt.c | 32 +-- libc/calls/internal.h | 2 + libc/calls/ioctl_default.c | 2 +- libc/calls/ioctl_tcgets-nt.c | 4 +- libc/calls/ioctl_tcsets-nt.c | 4 +- libc/calls/ioctl_tiocgwinsz-nt.c | 4 +- libc/calls/ioctl_tiocswinsz-nt.c | 5 +- libc/calls/isatty-nt.c | 2 +- libc/calls/ischardev.c | 2 +- libc/calls/mremap-sysv.greg.c | 2 +- libc/calls/munmap-sysv.c | 4 +- libc/calls/nanosleep-nt.c | 23 +- libc/calls/preadv.c | 4 + libc/calls/pwritev.c | 4 + libc/calls/raise.c | 5 +- libc/calls/read-nt.c | 12 +- libc/calls/readlinkat-nt.c | 6 +- libc/calls/readv.c | 13 +- libc/calls/reservefd.c | 2 +- libc/calls/sigaction.c | 4 + libc/calls/sigsuspend.c | 9 +- libc/calls/strace.internal.h | 23 ++ libc/calls/uname.c | 2 +- libc/calls/writev.c | 13 +- libc/crt/crt.S | 6 +- libc/intrin/closehandle.greg.c | 2 +- libc/intrin/createdirectory.greg.c | 4 +- libc/intrin/createfile.greg.c | 14 +- libc/intrin/createfilemapping.greg.c | 10 +- libc/intrin/createfilemappingnuma.greg.c | 10 +- libc/intrin/createnamedpipe.greg.c | 10 +- libc/intrin/createpipe.greg.c | 6 +- libc/intrin/createprocess.greg.c | 2 +- libc/intrin/createthread.greg.c | 7 +- libc/intrin/cxafinalize.c | 2 +- libc/intrin/deletefile.greg.c | 2 +- libc/intrin/deviceiocontrol.greg.c | 6 +- libc/intrin/findclose.greg.c | 2 +- libc/intrin/findfirstfile.greg.c | 4 +- libc/intrin/findnextfile.greg.c | 4 +- libc/intrin/flushfilebuffers.greg.c | 2 +- libc/intrin/flushviewoffile.greg.c | 4 +- libc/intrin/generateconsolectrlevent.greg.c | 4 +- libc/intrin/getenv.c | 8 +- libc/intrin/getfileattributes.greg.c | 4 +- libc/intrin/kprintf.greg.c | 32 ++- libc/intrin/mapviewoffileex.greg.c | 8 +- libc/intrin/mapviewoffileexnuma.greg.c | 8 +- libc/intrin/openprocess.greg.c | 6 +- libc/intrin/removedirectory.greg.c | 2 +- libc/intrin/reopenfile.greg.c | 8 +- libc/intrin/restorewintty.greg.c | 2 +- libc/intrin/setcurrentdirectory.greg.c | 2 +- libc/intrin/terminateprocess.greg.c | 2 +- libc/intrin/unmapviewoffile.greg.c | 2 +- libc/intrin/virtualprotect.greg.c | 4 +- libc/log/showcrashreports.c | 2 + libc/macros-cpp.internal.inc | 23 -- .../lib => libc/nexgen32e}/x86gradenames.c | 0 .../lib => libc/nexgen32e}/x86marchnames.c | 0 libc/rand/getrandom.c | 2 +- libc/runtime/cosmo.S | 5 +- libc/runtime/fork-nt.c | 49 ++-- libc/runtime/ftracer.c | 28 +- libc/runtime/getinterpreterexecutablename.c | 2 +- libc/runtime/getsymboltable.c | 58 +++- libc/runtime/{memtrack.c => memtrack.greg.c} | 0 libc/runtime/mremap.c | 2 +- libc/runtime/runtime.h | 1 + libc/runtime/runtime.mk | 11 +- libc/runtime/winmain.greg.c | 27 +- libc/sock/internal.h | 1 + libc/sock/kntwsadata.c | 6 +- libc/sock/ntstdin.greg.c | 26 +- libc/sock/poll-nt.c | 152 ++++++----- libc/sock/poll.c | 30 ++- .../printargs.c => sock/printargs.greg.c} | 250 ++++++++++++++---- libc/sock/recv-nt.c | 51 +--- libc/sock/recvfrom-nt.c | 47 +--- libc/sock/select.c | 7 +- libc/sock/send-nt.c | 52 +--- libc/sock/sendto-nt.c | 48 +--- libc/sock/stdinworker.c | 44 +++ libc/sock/wsablock.c | 52 ++++ libc/sysv/calls/getegid.s | 2 - libc/sysv/calls/getpgrp.s | 2 - libc/sysv/calls/sys_getegid.s | 2 + libc/sysv/calls/sys_geteuid.s | 2 +- libc/sysv/calls/sys_getpgrp.s | 2 + libc/sysv/consts.sh | 5 +- libc/sysv/consts/PTRACE_EVENT_SECCOMP.S | 2 + libc/sysv/consts/PTRACE_EVENT_STOP.S | 2 + libc/sysv/consts/PTRACE_O_TRACESECCOMP.S | 2 + libc/sysv/consts/ptrace.h | 6 + libc/sysv/syscalls.sh | 6 +- libc/sysv/systemfive.S | 19 +- test/libc/calls/printargs_test.c | 35 +++ test/libc/calls/read_test.c | 47 ++++ test/libc/calls/write_test.c | 1 + test/libc/intrin/kprintf_test.c | 14 + test/libc/stdio/spawn_test.c | 2 +- test/libc/x/test.mk | 1 + third_party/linenoise/linenoise.c | 1 - third_party/make/getopt.c | 8 - third_party/make/getopt1.c | 8 - third_party/sqlite3/shell.c | 8 - tool/build/runitd.c | 27 +- tool/build/strace.c | 86 +++--- tool/emacs/cosmo-c-keywords.el | 1 - tool/net/help.txt | 196 +++++++++++--- tool/net/lunix.c | 9 + tool/net/net.mk | 74 ++++++ tool/net/redbean.c | 15 +- tool/net/tiny/help.txt | 12 + 127 files changed, 1354 insertions(+), 866 deletions(-) create mode 100644 examples/linenoise.c create mode 100644 libc/calls/getegid.c rename libc/{runtime/getsymbol.c => calls/getpgrp.c} (76%) rename {tool/decode/lib => libc/nexgen32e}/x86gradenames.c (100%) rename {tool/decode/lib => libc/nexgen32e}/x86marchnames.c (100%) rename libc/runtime/{memtrack.c => memtrack.greg.c} (100%) rename libc/{runtime/printargs.c => sock/printargs.greg.c} (58%) create mode 100644 libc/sock/stdinworker.c create mode 100644 libc/sock/wsablock.c delete mode 100644 libc/sysv/calls/getegid.s delete mode 100644 libc/sysv/calls/getpgrp.s create mode 100644 libc/sysv/calls/sys_getegid.s create mode 100644 libc/sysv/calls/sys_getpgrp.s create mode 100644 libc/sysv/consts/PTRACE_EVENT_SECCOMP.S create mode 100644 libc/sysv/consts/PTRACE_EVENT_STOP.S create mode 100644 libc/sysv/consts/PTRACE_O_TRACESECCOMP.S create mode 100644 test/libc/calls/printargs_test.c create mode 100644 test/libc/calls/read_test.c create mode 100644 tool/net/tiny/help.txt diff --git a/examples/breakpoint.c b/examples/breakpoint.c index 6298bf933..c9a7a58e5 100644 --- a/examples/breakpoint.c +++ b/examples/breakpoint.c @@ -7,19 +7,30 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif +#include "libc/intrin/kprintf.h" #include "libc/log/backtrace.internal.h" #include "libc/log/log.h" #include "libc/runtime/runtime.h" #include "libc/runtime/symbols.internal.h" -#include "libc/stdio/stdio.h" int main(int argc, char *argv[]) { - ShowCrashReports(); + // ShowCrashReports(); + if (IsDebuggerPresent(false)) { - printf("debugger found!\r\n"); - DebugBreak(); - return 0; + kprintf("debugger found!%n"); + } else { + kprintf("try running: gdb %s%n", argv[0]); + kprintf("try running: o//tool/build/strace.com %s%n", argv[0]); } - printf("try running: gdb %s\r\n", argv[0]); - return 1; + + asm volatile("mov\t%4,%%r10\n\t" + "mov\t%5,%%r8\n\t" + "mov\t%6,%%r9\n\t" + "int3" + : /* no outputs */ + : "a"(0), "D"(1), "S"(2), "d"(3), "g"(4), "g"(5), "g"(6) + : "r8", "r9", "r10"); + + printf("recovered from SIGTRAP without handler\r\n"); + return 0; } diff --git a/examples/linenoise.c b/examples/linenoise.c new file mode 100644 index 000000000..b54e6f899 --- /dev/null +++ b/examples/linenoise.c @@ -0,0 +1,23 @@ +#if 0 +/*─────────────────────────────────────────────────────────────────╗ +│ To the extent possible under law, Justine Tunney has waived │ +│ all copyright and related or neighboring rights to this file, │ +│ as it is written in the following disclaimers: │ +│ • http://unlicense.org/ │ +│ • http://creativecommons.org/publicdomain/zero/1.0/ │ +╚─────────────────────────────────────────────────────────────────*/ +#endif +#include "libc/mem/mem.h" +#include "libc/stdio/stdio.h" +#include "third_party/linenoise/linenoise.h" + +int main(int argc, char *argv[]) { + char *line; + while ((line = linenoiseWithHistory("IN> ", "foo"))) { + fputs("OUT> ", stdout); + fputs(line, stdout); + fputs("\n", stdout); + free(line); + } + return 0; +} diff --git a/examples/printargs.c b/examples/printargs.c index d09af9b14..60ce148ed 100644 --- a/examples/printargs.c +++ b/examples/printargs.c @@ -7,115 +7,8 @@ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif -#include "libc/calls/calls.h" -#include "libc/intrin/kprintf.h" -#include "libc/log/log.h" -#include "libc/macros.internal.h" -#include "libc/mem/mem.h" -#include "libc/nt/process.h" -#include "libc/runtime/gc.h" #include "libc/runtime/runtime.h" -#include "libc/runtime/stack.h" -#include "libc/stdio/stdio.h" -#include "libc/str/str.h" -#include "libc/sysv/consts/auxv.h" -const struct AuxiliaryValue { - const char *fmt; - long *id; - const char *name; - const char *description; -} kAuxiliaryValues[] = { - {"%-14p", &AT_EXECFD, "AT_EXECFD", "file descriptor of program"}, - {"%-14p", &AT_PHDR, "AT_PHDR", "address of elf program headers"}, - {"%-14p", &AT_PHENT, "AT_PHENT", "size of program header entry"}, - {"%-14p", &AT_PHNUM, "AT_PHNUM", "number of program headers"}, - {"%-14p", &AT_PAGESZ, "AT_PAGESZ", "system page size"}, - {"%-14p", &AT_BASE, "AT_BASE", "base address of the program interpreter"}, - {"%-14p", &AT_ENTRY, "AT_ENTRY", "entry address of executable"}, - {"%-14p", &AT_NOTELF, "AT_NOTELF", "set if not an elf"}, - {"%-14d", &AT_UID, "AT_UID", "real user id of thread"}, - {"%-14d", &AT_EUID, "AT_EUID", "effective user id of thread"}, - {"%-14d", &AT_GID, "AT_GID", "real group id of thread"}, - {"%-14d", &AT_EGID, "AT_EGID", "effective group id of thread"}, - {"%-14d", &AT_CLKTCK, "AT_CLKTCK", "frequency of times() counts"}, - {"%-14d", &AT_OSRELDATE, "AT_OSRELDATE", - "freebsd release number, e.g. 1200086"}, - {"%-14p", &AT_PLATFORM, "AT_PLATFORM", - "string identifying hardware platform"}, - {"%-14p", &AT_DCACHEBSIZE, "AT_DCACHEBSIZE", "data cache block size"}, - {"%-14p", &AT_ICACHEBSIZE, "AT_ICACHEBSIZE", - "instruction cache block size"}, - {"%-14p", &AT_UCACHEBSIZE, "AT_UCACHEBSIZE", "unified cache block size"}, - {"%-14p", &AT_SECURE, "AT_SECURE", - "for set{u,g}id binz & security blankets"}, - {"%-14s", &AT_BASE_PLATFORM, "AT_BASE_PLATFORM", - "string identifying real platform"}, - {"%-14p", &AT_RANDOM, "AT_RANDOM", "address of sixteen random bytes"}, - {"%-14s (%p)", &AT_EXECFN, "AT_EXECFN", "pathname used to execute program"}, - {"%-14p", &AT_SYSINFO_EHDR, "AT_SYSINFO_EHDR", - "linux virtual dso page address"}, - {"%-14p", &AT_FLAGS, "AT_FLAGS", "unused?"}, - {"%-14p", &AT_HWCAP, "AT_HWCAP", "cpu stuff"}, - {"%-14p", &AT_HWCAP2, "AT_HWCAP2", "more cpu stuff"}, - {"%-14p", &AT_STACKBASE, "AT_STACKBASE", "NetBSD stack base"}, - {"%-14p", &AT_CANARY, "AT_CANARY", "FreeBSD AT_CANARY"}, - {"%-14p", &AT_CANARYLEN, "AT_CANARYLEN", "FreeBSD AT_CANARYLEN"}, - {"%-14ld", &AT_NCPUS, "AT_NCPUS", "FreeBSD AT_NCPUS"}, - {"%-14p", &AT_PAGESIZES, "AT_PAGESIZES", "FreeBSD AT_PAGESIZES"}, - {"%-14d", &AT_PAGESIZESLEN, "AT_PAGESIZESLEN", "FreeBSD AT_PAGESIZESLEN"}, - {"%-14p", &AT_TIMEKEEP, "AT_TIMEKEEP", "FreeBSD AT_TIMEKEEP"}, - {"%-14p", &AT_STACKPROT, "AT_STACKPROT", "FreeBSD AT_STACKPROT"}, - {"%-14p", &AT_EHDRFLAGS, "AT_EHDRFLAGS", "FreeBSD AT_EHDRFLAGS"}, -}; - -const struct AuxiliaryValue *DescribeAuxv(unsigned long x) { - int i; - for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) { - if (*kAuxiliaryValues[i].id && x == *kAuxiliaryValues[i].id) { - return kAuxiliaryValues + i; - } - } - return NULL; -} - -int main(int argc, char *argv[], char **envp) { - long key; - char **env; - unsigned i; - unsigned long *auxp; - struct AuxiliaryValue *auxinfo; - uint32_t varlen; - char16_t var[PATH_MAX]; - kprintf("%nArguments:%n"); - for (i = 0; i < __argc; ++i) { - kprintf(" ☼ %s%n", argv[i]); - } - kprintf("%nEnvironment:%n"); - for (env = envp; *env; ++env) { - kprintf(" ☼ %s%n", *env); - } - kprintf("%nAuxiliary Values:%n"); - for (auxp = __auxv; *auxp; auxp += 2) { - if ((auxinfo = DescribeAuxv(auxp[0]))) { - kprintf(" ☼ %16s[%4ld] = ", auxinfo->name, auxp[0]); - kprintf(auxinfo->fmt, auxp[1], auxp[1]); - kprintf(" # %s%n", auxinfo->description); - } else { - kprintf(" ☼ %16s[%4ld] = %014p%n", "unknown", auxp[0], auxp[1]); - } - } - kprintf("%nSpecial Parameters:%n"); - kprintf(" ☼ kTmpPath = %#s%n", kTmpPath); - kprintf(" ☼ kNtSystemDirectory = %#s%n", kNtSystemDirectory); - kprintf(" ☼ kNtWindowsDirectory = %#s%n", kNtWindowsDirectory); - kprintf(" ☼ program_executable_name = %#s (%p)%n", GetProgramExecutableName(), - GetProgramExecutableName()); - kprintf(" ☼ GetInterpreterExecutableName() → %#s%n", - GetInterpreterExecutableName(_gc(malloc(1024)), 1024)); - kprintf(" ☼ RSP → %p%n", __builtin_frame_address(0)); - kprintf(" ☼ GetStackAddr() → %p%n", GetStackAddr(0)); - kprintf(" ☼ GetStaticStackAddr() → %p%n", GetStaticStackAddr(0)); - kprintf(" ☼ GetStackSize() → %p%n", GetStackSize()); - return 0; +int main() { + __printargs(""); } diff --git a/libc/calls/close-nt.c b/libc/calls/close-nt.c index 8f6964bf0..a6270628a 100644 --- a/libc/calls/close-nt.c +++ b/libc/calls/close-nt.c @@ -29,14 +29,6 @@ textwindows int sys_close_nt(struct Fd *fd) { int e; bool ok = true; - // if this file descriptor is wrapped in a named pipe worker thread - // then we need to close our copy of the worker thread handle. it's - // also required that whatever install a worker use malloc, so free - if (fd->worker) { - if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false; - fd->worker = 0; - } - if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY && GetFileType(fd->handle) == kNtFileTypeDisk)) { // Like Linux, closing a file on Windows doesn't guarantee it's @@ -47,8 +39,15 @@ textwindows int sys_close_nt(struct Fd *fd) { errno = e; } - // now we can close the handle - if (!CloseHandle(fd->handle)) ok = false; + // if this file descriptor is wrapped in a named pipe worker thread + // then we need to close our copy of the worker thread handle. it's + // also required that whatever install a worker use malloc, so free + if (fd->worker) { + if (!weaken(UnrefNtStdinWorker)(fd->worker)) ok = false; + fd->worker = 0; + } else { + if (!CloseHandle(fd->handle)) ok = false; + } if (fd->kind == kFdConsole && fd->extra && fd->extra != -1) { if (!CloseHandle(fd->extra)) ok = false; } diff --git a/libc/calls/directmap-nt.c b/libc/calls/directmap-nt.c index 7215ccc3e..3fa1139ea 100644 --- a/libc/calls/directmap-nt.c +++ b/libc/calls/directmap-nt.c @@ -40,14 +40,13 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot, struct DirectMap dm; struct ProtectNt fl; const struct NtSecurityAttributes *sec; + struct NtProcessMemoryCountersEx memcount; -#ifndef NDEBUG - struct NtProcessMemoryCountersEx memcount = { - .cb = sizeof(struct NtProcessMemoryCountersEx), - }; +#if _NT_RLIMIT_PWSS_MB if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) { - if (memcount.PeakWorkingSetSize > 5ull * 1024 * 1024 * 1024) { - kprintf("error: exceeded 5gb memory limit%n"); + if (memcount.PeakWorkingSetSize > _NT_RLIMIT_PWSS_MB * 1048576ull) { + kprintf("error: PeakWorkingSetSize %'ldmb exceeded %'ldmb limit%n", + memcount.PeakWorkingSetSize / 1048576, (long)_NT_RLIMIT_PWSS_MB); _Exit(201); } } diff --git a/libc/calls/directmap.c b/libc/calls/directmap.c index 0ad050478..a8ecd85d3 100644 --- a/libc/calls/directmap.c +++ b/libc/calls/directmap.c @@ -45,8 +45,8 @@ struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd, } else { d = sys_mmap_nt(addr, size, prot, flags, fd, off); } - STRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr, - DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot), - DescribeMapFlags(flags), fd, off, d.addr, d.maphandle); + KERNTRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr, + DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot), + DescribeMapFlags(flags), fd, off, d.addr, d.maphandle); return d; } diff --git a/libc/calls/fcntl.c b/libc/calls/fcntl.c index c18c3eaaa..44d469619 100644 --- a/libc/calls/fcntl.c +++ b/libc/calls/fcntl.c @@ -68,6 +68,6 @@ int fcntl(int fd, int cmd, ...) { } else { rc = einval(); } - STRACE("fcntl(%d, %d, %p) → %d% m", fd, cmd, arg); + STRACE("fcntl(%d, %d, %p) → %#x% m", fd, cmd, arg, rc); return rc; } diff --git a/libc/calls/fstat.c b/libc/calls/fstat.c index 3ae6364b9..1b2a7b952 100644 --- a/libc/calls/fstat.c +++ b/libc/calls/fstat.c @@ -41,7 +41,7 @@ int fstat(int fd, struct stat *st) { } else if (!__isfdkind(fd, kFdFile)) { rc = ebadf(); } else { - rc = sys_fstat_nt(g_fds.p[fd].handle, st); + rc = sys_fstat_nt(__getfdhandleactual(fd), st); } STRACE("fstat(%d, [%s]) → %d% m", fd, __strace_stat(rc, st), rc); return rc; diff --git a/libc/calls/g_fds.c b/libc/calls/g_fds.c index 148031d4a..d071e00b0 100644 --- a/libc/calls/g_fds.c +++ b/libc/calls/g_fds.c @@ -20,6 +20,7 @@ #include "libc/calls/internal.h" #include "libc/calls/strace.internal.h" #include "libc/nt/runtime.h" +#include "libc/sysv/consts/o.h" STATIC_YOINK("_init_g_fds"); @@ -48,4 +49,7 @@ textstartup void InitializeFileDescriptors(void) { fds->__init_p[1].handle = GetStdHandle(pushpop(kNtStdOutputHandle)); fds->__init_p[2].handle = GetStdHandle(pushpop(kNtStdErrorHandle)); } + fds->__init_p[0].flags = O_RDONLY; + fds->__init_p[1].flags = O_WRONLY | O_APPEND; + fds->__init_p[2].flags = O_WRONLY | O_APPEND; } diff --git a/libc/calls/getauxval.c b/libc/calls/getauxval.c index 3eb531a33..7b43ffa50 100644 --- a/libc/calls/getauxval.c +++ b/libc/calls/getauxval.c @@ -39,8 +39,5 @@ unsigned long getauxval(unsigned long at) { return ap[1]; } } - if (at == AT_EXECFN) { - return (intptr_t)__argv[0]; - } return 0; } diff --git a/libc/calls/getegid.c b/libc/calls/getegid.c new file mode 100644 index 000000000..a6c4709bb --- /dev/null +++ b/libc/calls/getegid.c @@ -0,0 +1,31 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ 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. │ +│ │ +│ 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/strace.internal.h" + +/** + * Returns effective group ID of calling process. + */ +uint32_t getegid(void) { + int rc; + rc = sys_getegid(); + STRACE("%s() → %d% m", "getegid", rc); + return rc; +} diff --git a/libc/calls/gethostname.c b/libc/calls/gethostname.c index 46f23eae3..eaafb2b43 100644 --- a/libc/calls/gethostname.c +++ b/libc/calls/gethostname.c @@ -27,6 +27,8 @@ * * pheidippides.domain.example * ^^^^^^^^^^^^ + * + * @return 0 on success or -1 w/ errno */ int gethostname(char *name, size_t len) { if (len < 1) return einval(); diff --git a/libc/runtime/getsymbol.c b/libc/calls/getpgrp.c similarity index 76% rename from libc/runtime/getsymbol.c rename to libc/calls/getpgrp.c index a480051d0..e6edd52f4 100644 --- a/libc/runtime/getsymbol.c +++ b/libc/calls/getpgrp.c @@ -16,27 +16,21 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/runtime/symbols.internal.h" +#include "libc/calls/calls.h" +#include "libc/calls/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/dce.h" -privileged noinstrument noasan noubsan int __get_symbol(struct SymbolTable *t, - intptr_t a) { - /* asan runtime depends on this function */ - unsigned l, m, r, n, k; - if (t) { - l = 0; - r = n = t->count; - k = a - t->addr_base; - while (l < r) { - m = (l + r) >> 1; - if (t->symbols[m].y < k) { - l = m + 1; - } else { - r = m; - } - } - if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) { - return l; - } +/** + * Returns process group id of calling process. + */ +uint32_t getpgrp(void) { + int rc; + if (!IsWindows()) { + rc = sys_getpgrp(); + } else { + rc = getpid(); } - return -1; + STRACE("%s() → %d% m", "getpgrp", rc); + return rc; } diff --git a/libc/calls/getrusage-nt.c b/libc/calls/getrusage-nt.c index c96b449b4..341736356 100644 --- a/libc/calls/getrusage-nt.c +++ b/libc/calls/getrusage-nt.c @@ -30,30 +30,22 @@ #include "libc/sysv/errfuns.h" textwindows int sys_getrusage_nt(int who, struct rusage *usage) { - struct NtFileTime CreationFileTime; - struct NtFileTime ExitFileTime; - struct NtFileTime KernelFileTime; - struct NtFileTime UserFileTime; struct NtProcessMemoryCountersEx memcount; + struct NtFileTime ftExit, ftUser, ftKernel, ftCreation; if (!usage) return efault(); - if (who == 99) return enosys(); /* @see libc/sysv/consts.sh */ - bzero(usage, sizeof(*usage)); - if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)( + if (who == 99) return enosys(); // @see libc/sysv/consts.sh + if (!usage) return 0; + if (!(who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)( (who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(), - &CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) { - /* xxx: shouldn't clobber memory on failure below */ - usage->ru_utime = WindowsDurationToTimeVal(ReadFileTime(UserFileTime)); - usage->ru_stime = WindowsDurationToTimeVal(ReadFileTime(KernelFileTime)); - } else { - return __winerr(); - } - bzero(&memcount, sizeof(memcount)); - memcount.cb = sizeof(struct NtProcessMemoryCountersEx); - if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) { - usage->ru_maxrss = memcount.PeakWorkingSetSize / 1024; - usage->ru_majflt = memcount.PageFaultCount; - } else { + &ftCreation, &ftExit, &ftKernel, &ftUser) || + !GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) { return __winerr(); } + *usage = (struct rusage){ + .ru_utime = WindowsDurationToTimeVal(ReadFileTime(ftUser)), + .ru_stime = WindowsDurationToTimeVal(ReadFileTime(ftKernel)), + .ru_maxrss = memcount.PeakWorkingSetSize / 1024, + .ru_majflt = memcount.PageFaultCount, + }; return 0; } diff --git a/libc/calls/internal.h b/libc/calls/internal.h index 4a0f9e03e..68ab4682b 100644 --- a/libc/calls/internal.h +++ b/libc/calls/internal.h @@ -157,6 +157,7 @@ i32 sys_futimes(i32, const struct timeval *) hidden; i32 sys_futimesat(i32, const char *, const struct timeval *) hidden; i32 sys_getitimer(i32, struct itimerval *) hidden; i32 sys_getpgid(i32) hidden; +i32 sys_getpgrp(void) hidden; i32 sys_getppid(void) hidden; i32 sys_getpriority(i32, u32) hidden; i32 sys_getrlimit(i32, struct rlimit *) hidden; @@ -223,6 +224,7 @@ i64 sys_sendfile(i32, i32, i64 *, u64) hidden; i64 sys_splice(i32, i64 *, i32, i64 *, u64, u32) hidden; i64 sys_vmsplice(i32, const struct iovec *, i64, u32) hidden; i64 sys_write(i32, const void *, u64) hidden; +u32 sys_getegid(void) hidden; u32 sys_geteuid(void) hidden; u32 sys_getgid(void) hidden; u32 sys_getsid(int) hidden; diff --git a/libc/calls/ioctl_default.c b/libc/calls/ioctl_default.c index 8b58cb107..11886fb1a 100644 --- a/libc/calls/ioctl_default.c +++ b/libc/calls/ioctl_default.c @@ -35,7 +35,7 @@ int ioctl_default(int fd, uint64_t request, ...) { return sys_ioctl(fd, request, arg); } else if (__isfdopen(fd)) { if (g_fds.p[fd].kind == kFdSocket) { - handle = g_fds.p[fd].handle; + handle = __getfdhandleactual(fd); if ((rc = weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) { return rc; } else { diff --git a/libc/calls/ioctl_tcgets-nt.c b/libc/calls/ioctl_tcgets-nt.c index 4dc69e732..f5e3cae72 100644 --- a/libc/calls/ioctl_tcgets-nt.c +++ b/libc/calls/ioctl_tcgets-nt.c @@ -31,8 +31,8 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) { int64_t in, out; bool32 inok, outok; uint32_t inmode, outmode; - inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode); - outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode); + inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode); + outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode); if (inok | outok) { bzero(tio, sizeof(*tio)); if (inok) { diff --git a/libc/calls/ioctl_tcsets-nt.c b/libc/calls/ioctl_tcsets-nt.c index ba52c2a80..a457a1d4e 100644 --- a/libc/calls/ioctl_tcsets-nt.c +++ b/libc/calls/ioctl_tcsets-nt.c @@ -31,8 +31,8 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request, int64_t in, out; bool32 inok, outok; uint32_t inmode, outmode; - inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode); - outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode); + inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode); + outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode); if (inok | outok) { if (inok) { if (request == TCSETSF) { diff --git a/libc/calls/ioctl_tiocgwinsz-nt.c b/libc/calls/ioctl_tiocgwinsz-nt.c index 25980bc22..5080a3df5 100644 --- a/libc/calls/ioctl_tiocgwinsz-nt.c +++ b/libc/calls/ioctl_tiocgwinsz-nt.c @@ -42,10 +42,10 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) { GetStartupInfo(&startinfo); for (i = 0; i < ARRAYLEN(fds); ++i) { if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) { - if (GetConsoleMode(fds[i]->handle, &mode)) { + if (GetConsoleMode(__getfdhandleactual(i), &mode)) { bzero(&sbinfo, sizeof(sbinfo)); sbinfo.cbSize = sizeof(sbinfo); - if (GetConsoleScreenBufferInfoEx(fds[i]->handle, &sbinfo)) { + if (GetConsoleScreenBufferInfoEx(__getfdhandleactual(i), &sbinfo)) { ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1; ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1; ws->ws_xpixel = 0; diff --git a/libc/calls/ioctl_tiocswinsz-nt.c b/libc/calls/ioctl_tiocswinsz-nt.c index bf87f4181..1b80cd24f 100644 --- a/libc/calls/ioctl_tiocswinsz-nt.c +++ b/libc/calls/ioctl_tiocswinsz-nt.c @@ -29,9 +29,10 @@ textwindows int ioctl_tiocswinsz_nt(int fd, const struct winsize *ws) { struct NtCoord coord; if (!ws) return efault(); if (!__isfdkind(fd, kFdFile)) return ebadf(); - if (!GetConsoleMode(g_fds.p[fd].handle, &mode)) return enotty(); + if (!GetConsoleMode(__getfdhandleactual(fd), &mode)) return enotty(); coord.X = ws->ws_col; coord.Y = ws->ws_row; - if (!SetConsoleScreenBufferSize(g_fds.p[fd].handle, coord)) return __winerr(); + if (!SetConsoleScreenBufferSize(__getfdhandleactual(fd), coord)) + return __winerr(); return 0; } diff --git a/libc/calls/isatty-nt.c b/libc/calls/isatty-nt.c index 014cd1990..f59eb9ba4 100644 --- a/libc/calls/isatty-nt.c +++ b/libc/calls/isatty-nt.c @@ -24,5 +24,5 @@ textwindows bool32 sys_isatty_nt(int fd) { return __isfdkind(fd, kFdConsole) || (__isfdkind(fd, kFdFile) && - GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar); + GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar); } diff --git a/libc/calls/ischardev.c b/libc/calls/ischardev.c index 2777d0ad4..82fbe7d51 100644 --- a/libc/calls/ischardev.c +++ b/libc/calls/ischardev.c @@ -66,6 +66,6 @@ bool32 ischardev(int fd) { } else { return __isfdkind(fd, kFdConsole) || (__isfdkind(fd, kFdFile) && - GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar); + GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar); } } diff --git a/libc/calls/mremap-sysv.greg.c b/libc/calls/mremap-sysv.greg.c index e0ea8371d..c44cff2d1 100644 --- a/libc/calls/mremap-sysv.greg.c +++ b/libc/calls/mremap-sysv.greg.c @@ -60,6 +60,6 @@ privileged void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) { } else { rax = enosys(); } - STRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p% m", p, n, m, f, q, rax); + KERNTRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p% m", p, n, m, f, q, rax); return (void *)rax; } diff --git a/libc/calls/munmap-sysv.c b/libc/calls/munmap-sysv.c index 2d93337da..cbb9a186d 100644 --- a/libc/calls/munmap-sysv.c +++ b/libc/calls/munmap-sysv.c @@ -28,7 +28,7 @@ int sys_munmap(void *p, size_t n) { } else { rc = sys_munmap_metal(p, n); } - STRACE("sys_munmap(%p%s, %'zu) → %d", p, DescribeFrame((intptr_t)p >> 16), n, - rc); + KERNTRACE("sys_munmap(%p%s, %'zu) → %d", p, DescribeFrame((intptr_t)p >> 16), + n, rc); return rc; } diff --git a/libc/calls/nanosleep-nt.c b/libc/calls/nanosleep-nt.c index 9d6e56a63..c7b7d7125 100644 --- a/libc/calls/nanosleep-nt.c +++ b/libc/calls/nanosleep-nt.c @@ -29,8 +29,9 @@ textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req, struct timespec *rem) { int rc; - int64_t sec, nsec; - uint64_t ms, slice; + bool alertable; + uint32_t slice; + int64_t ms, sec, nsec; if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) || __builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) { ms = -1; @@ -44,18 +45,20 @@ textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req, rc = eintr(); break; } - if (ms > __SIG_POLLING_INTERVAL_MS) { - slice = __SIG_POLLING_INTERVAL_MS; + slice = MIN(__SIG_POLLING_INTERVAL_MS, ms); + if (__time_critical) { + alertable = false; } else { - slice = ms; + alertable = true; + POLLTRACE("sys_nanosleep_nt polling for %'ldms of %'ld"); } - if (SleepEx(slice, true) == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - rc = eintr(); - break; + if (SleepEx(slice, alertable) == kNtWaitIoCompletion) { + POLLTRACE("IOCP EINTR"); + continue; } ms -= slice; - } while (ms); + } while (ms > 0); + ms = MAX(ms, 0); if (rem) { sec = ms / 1000; nsec = ms % 1000 * 1000000000; diff --git a/libc/calls/preadv.c b/libc/calls/preadv.c index 4bd339aca..f503be71c 100644 --- a/libc/calls/preadv.c +++ b/libc/calls/preadv.c @@ -61,6 +61,10 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) { return enosys(); } + if (iovlen == 1) { + return sys_pread(fd, iov[0].iov_base, iov[0].iov_len, off, off); + } + /* * NT, 2018-era XNU, and 2007-era Linux don't support this system call */ diff --git a/libc/calls/pwritev.c b/libc/calls/pwritev.c index 6bbf9d8fb..db15e7746 100644 --- a/libc/calls/pwritev.c +++ b/libc/calls/pwritev.c @@ -65,6 +65,10 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) { return enosys(); } + if (iovlen == 1) { + return sys_pwrite(fd, iov[0].iov_base, iov[0].iov_len, off, off); + } + /* * NT, 2018-era XNU, and 2007-era Linux don't support this system call */ diff --git a/libc/calls/raise.c b/libc/calls/raise.c index e73c58884..6b47956d6 100644 --- a/libc/calls/raise.c +++ b/libc/calls/raise.c @@ -65,10 +65,7 @@ int raise(int sig) { // groups potentially. We just shouldn't use this because it // doesn't make any sense and it's so evil. if (GenerateConsoleCtrlEvent(event, 0)) { - // XXX: we shouldn't need to sleep here ctrl-c is evil on nt - if (SleepEx(100, true) == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - } + SleepEx(100, true); __sig_check(false); rc = 0; } else { diff --git a/libc/calls/read-nt.c b/libc/calls/read-nt.c index ff8cb597a..ed64fa32f 100644 --- a/libc/calls/read-nt.c +++ b/libc/calls/read-nt.c @@ -26,6 +26,7 @@ #include "libc/errno.h" #include "libc/intrin/kprintf.h" #include "libc/limits.h" +#include "libc/nt/enum/filetype.h" #include "libc/nt/enum/wait.h" #include "libc/nt/errors.h" #include "libc/nt/files.h" @@ -40,15 +41,20 @@ static textwindows ssize_t sys_read_nt_impl(struct Fd *fd, void *data, size_t size, ssize_t offset) { uint32_t err, got, avail; struct NtOverlapped overlap; - if (fd->worker) { + if (GetFileType(fd->handle) == kNtFileTypePipe) { for (;;) { if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break; if (avail) break; - if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion || - _check_interrupts(true, g_fds.p)) { + POLLTRACE("sys_read_nt polling"); + if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) { + POLLTRACE("IOCP EINTR"); + } + if (_check_interrupts(true, g_fds.p)) { + POLLTRACE("sys_read_nt interrupted"); return eintr(); } } + POLLTRACE("sys_read_nt ready to read"); } if (ReadFile(fd->handle, data, _clampio(size), &got, _offset2overlap(fd->handle, offset, &overlap))) { diff --git a/libc/calls/readlinkat-nt.c b/libc/calls/readlinkat-nt.c index ea8b53b54..af1cdc3a1 100644 --- a/libc/calls/readlinkat-nt.c +++ b/libc/calls/readlinkat-nt.c @@ -61,7 +61,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, rdb = (struct NtReparseDataBuffer *)buf; freeme = 0; } else { - STRACE("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked"); + NTTRACE("sys_readlinkat_nt() needs bigger buffer malloc() to be yoinked"); return enomem(); } if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting, @@ -102,11 +102,11 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf, if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) { rc = j; } else { - STRACE("sys_readlinkat_nt() too many astral codepoints"); + NTTRACE("sys_readlinkat_nt() too many astral codepoints"); rc = enametoolong(); } } else { - STRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink"); + NTTRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink"); rc = einval(); } } else { diff --git a/libc/calls/readv.c b/libc/calls/readv.c index 7da2d6aad..de6d3df0f 100644 --- a/libc/calls/readv.c +++ b/libc/calls/readv.c @@ -29,6 +29,13 @@ /** * Reads data to multiple buffers. * + * This is the same thing as read() except it has multiple buffers. + * This yields a performance boost in situations where it'd be expensive + * to stitch data together using memcpy() or issuing multiple syscalls. + * This wrapper is implemented so that readv() calls where iovlen<2 may + * be passed to the kernel as read() instead. This yields a 100 cycle + * performance boost in the case of a single small iovec. + * * @return number of bytes actually read, or -1 w/ errno * @restartable */ @@ -41,7 +48,11 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) { rc = weaken(__zipos_read)( (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1); } else if (!IsWindows() && !IsMetal()) { - rc = sys_readv(fd, iov, iovlen); + if (iovlen == 1) { + rc = sys_read(fd, iov[0].iov_base, iov[0].iov_len); + } else { + rc = sys_readv(fd, iov, iovlen); + } } else if (fd >= g_fds.n) { rc = ebadf(); } else if (IsMetal()) { diff --git a/libc/calls/reservefd.c b/libc/calls/reservefd.c index e4461710b..1937d2e08 100644 --- a/libc/calls/reservefd.c +++ b/libc/calls/reservefd.c @@ -90,7 +90,7 @@ int __reservefd(int start) { */ static void __freefds(void) { int i; - STRACE("__freefds()"); + NTTRACE("__freefds()"); for (i = 3; i < g_fds.n; ++i) { if (g_fds.p[i].kind) { close(i); diff --git a/libc/calls/sigaction.c b/libc/calls/sigaction.c index 11199fb0b..4cd2f5738 100644 --- a/libc/calls/sigaction.c +++ b/libc/calls/sigaction.c @@ -42,6 +42,10 @@ #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" +#ifdef SYSDEBUG +STATIC_YOINK("strsignal"); // for kprintf() +#endif + #define SA_RESTORER 0x04000000 #ifndef SWITCHEROO diff --git a/libc/calls/sigsuspend.c b/libc/calls/sigsuspend.c index 7dc0c58bc..098327c28 100644 --- a/libc/calls/sigsuspend.c +++ b/libc/calls/sigsuspend.c @@ -78,15 +78,14 @@ int sigsuspend(const sigset_t *ignore) { break; } if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - rc = eintr(); - break; + POLLTRACE("IOCP EINTR"); + continue; } -#ifdef SYSDEBUG +#if defined(SYSDEBUG) && defined(_POLLTRACE) ms += __SIG_POLLING_INTERVAL_MS; if (ms >= __SIG_LOGGING_INTERVAL_MS) { totoms += ms, ms = 0; - STRACE("... sigsuspending for %'lums...", totoms); + POLLTRACE("... sigsuspending for %'lums...", totoms); } #endif } while (1); diff --git a/libc/calls/strace.internal.h b/libc/calls/strace.internal.h index af87cc139..e68041907 100644 --- a/libc/calls/strace.internal.h +++ b/libc/calls/strace.internal.h @@ -4,6 +4,11 @@ #include "libc/calls/struct/sigaction.h" #include "libc/calls/struct/stat.h" +#define _NT_RLIMIT_PWSS_MB 1000 /* nocommit */ +#define _KERNTRACE 0 /* not configurable w/ flag yet */ +#define _POLLTRACE 0 /* not configurable w/ flag yet */ +#define _NTTRACE 0 /* not configurable w/ flag yet */ + #define STRACE_PROLOGUE "%rSYS %5P %'18T " #if !(__ASSEMBLER__ + __LINKER__ + 0) @@ -20,6 +25,24 @@ COSMOPOLITAN_C_START_ #define STRACE(FMT, ...) (void)0 #endif +#if defined(SYSDEBUG) && _POLLTRACE +#define POLLTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__) +#else +#define POLLTRACE(FMT, ...) (void)0 +#endif + +#if defined(SYSDEBUG) && _KERNTRACE +#define KERNTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__) +#else +#define KERNTRACE(FMT, ...) (void)0 +#endif + +#if defined(SYSDEBUG) && _NTTRACE +#define NTTRACE(FMT, ...) STRACE(FMT, ##__VA_ARGS__) +#else +#define NTTRACE(FMT, ...) (void)0 +#endif + extern int __strace; void __stracef(const char *, ...); diff --git a/libc/calls/uname.c b/libc/calls/uname.c index 413d705bd..b96686840 100644 --- a/libc/calls/uname.c +++ b/libc/calls/uname.c @@ -86,7 +86,7 @@ int uname(struct utsname *lool) { } } else { v = NtGetVersion(); - p = lool->version; + p = lool->release; p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.'; p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-'; p = FormatUint32(p, NtGetBuildNumber()); diff --git a/libc/calls/writev.c b/libc/calls/writev.c index bcd4b9aed..ed6d465a1 100644 --- a/libc/calls/writev.c +++ b/libc/calls/writev.c @@ -28,6 +28,13 @@ /** * Writes data from multiple buffers. * + * This is the same thing as write() except it has multiple buffers. + * This yields a performance boost in situations where it'd be expensive + * to stitch data together using memcpy() or issuing multiple syscalls. + * This wrapper is implemented so that writev() calls where iovlen<2 may + * be passed to the kernel as write() instead. This yields a 100 cycle + * performance boost in the case of a single small iovec. + * * Please note that it's not an error for a short write to happen. This * can happen in the kernel if EINTR happens after some of the write has * been committed. It can also happen if we need to polyfill this system @@ -45,7 +52,11 @@ ssize_t writev(int fd, const struct iovec *iov, int iovlen) { rc = weaken(__zipos_write)( (struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1); } else if (!IsWindows() && !IsMetal()) { - rc = sys_writev(fd, iov, iovlen); + if (iovlen == 1) { + rc = sys_write(fd, iov[0].iov_base, iov[0].iov_len); + } else { + rc = sys_writev(fd, iov, iovlen); + } } else if (fd >= g_fds.n) { rc = ebadf(); } else if (IsMetal()) { diff --git a/libc/crt/crt.S b/libc/crt/crt.S index 400396d70..83a86ab20 100644 --- a/libc/crt/crt.S +++ b/libc/crt/crt.S @@ -72,15 +72,11 @@ _start: mov %rdi,%rcx # auxv #if SupportsXnu() -// should probably be removed in favor of newer apis +// xnu doesn't have auxiliary values testb IsXnu() jz 1f # polyfill xnu auxv push $0 # auxv[1][1]=0 push $0 # auxv[1][0]=0 - mov (%rcx),%rax # executable_path=BIN - lea 16(%rax),%rax # BIN - push %rax # auxv[0][0]=BIN - push $31 # auxv[0][0]=AT_EXECFN mov %rsp,%rcx # auxv #endif diff --git a/libc/intrin/closehandle.greg.c b/libc/intrin/closehandle.greg.c index fdf99152d..17f31261a 100644 --- a/libc/intrin/closehandle.greg.c +++ b/libc/intrin/closehandle.greg.c @@ -36,6 +36,6 @@ textwindows bool32 CloseHandle(int64_t hObject) { __winerr(); if (weaken(__die)) weaken(__die)(); } - STRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok); + NTTRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok); return ok; } diff --git a/libc/intrin/createdirectory.greg.c b/libc/intrin/createdirectory.greg.c index 16252b79e..f0a8efd10 100644 --- a/libc/intrin/createdirectory.greg.c +++ b/libc/intrin/createdirectory.greg.c @@ -36,7 +36,7 @@ CreateDirectory(const char16_t *lpPathName, bool32 ok; ok = __imp_CreateDirectoryW(lpPathName, lpSecurityAttributes); if (!ok) __winerr(); - STRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName, - DescribeNtSecurityAttributes(lpSecurityAttributes), ok); + NTTRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName, + DescribeNtSecurityAttributes(lpSecurityAttributes), ok); return ok; } diff --git a/libc/intrin/createfile.greg.c b/libc/intrin/createfile.greg.c index 23755b1cc..6290f7381 100644 --- a/libc/intrin/createfile.greg.c +++ b/libc/intrin/createfile.greg.c @@ -40,12 +40,12 @@ textwindows int64_t CreateFile( opt_lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, opt_hTemplateFile); if (hHandle == -1) __winerr(); - STRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName, - DescribeNtFileAccessFlags(dwDesiredAccess), - DescribeNtFileShareFlags(dwShareMode), - DescribeNtSecurityAttributes(opt_lpSecurityAttributes), - DescribeNtCreationDisposition(dwCreationDisposition), - DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), - opt_hTemplateFile, hHandle); + NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName, + DescribeNtFileAccessFlags(dwDesiredAccess), + DescribeNtFileShareFlags(dwShareMode), + DescribeNtSecurityAttributes(opt_lpSecurityAttributes), + DescribeNtCreationDisposition(dwCreationDisposition), + DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), + opt_hTemplateFile, hHandle); return hHandle; } diff --git a/libc/intrin/createfilemapping.greg.c b/libc/intrin/createfilemapping.greg.c index 9022f8f77..a8a5ea4aa 100644 --- a/libc/intrin/createfilemapping.greg.c +++ b/libc/intrin/createfilemapping.greg.c @@ -43,10 +43,10 @@ textwindows int64_t CreateFileMapping( flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, opt_lpName); if (!hHandle) __winerr(); - STRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile, - DescribeNtSecurityAttributes(opt_lpFileMappingAttributes), - DescribeNtPageFlags(flProtect), - (uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName, - hHandle); + NTTRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile, + DescribeNtSecurityAttributes(opt_lpFileMappingAttributes), + DescribeNtPageFlags(flProtect), + (uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName, + hHandle); return hHandle; } diff --git a/libc/intrin/createfilemappingnuma.greg.c b/libc/intrin/createfilemappingnuma.greg.c index bdc005761..7da20c4fc 100644 --- a/libc/intrin/createfilemappingnuma.greg.c +++ b/libc/intrin/createfilemappingnuma.greg.c @@ -44,10 +44,10 @@ textwindows int64_t CreateFileMappingNuma( opt_hFile, opt_lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, opt_lpName, nndDesiredNumaNode); if (!hHandle) __winerr(); - STRACE("CreateFileMappingNuma(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile, - DescribeNtSecurityAttributes(opt_lpFileMappingAttributes), - DescribeNtPageFlags(flProtect), - (uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName, - hHandle); + NTTRACE("CreateFileMappingNuma(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile, + DescribeNtSecurityAttributes(opt_lpFileMappingAttributes), + DescribeNtPageFlags(flProtect), + (uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName, + hHandle); return hHandle; } diff --git a/libc/intrin/createnamedpipe.greg.c b/libc/intrin/createnamedpipe.greg.c index 457ba3986..7e70683e1 100644 --- a/libc/intrin/createnamedpipe.greg.c +++ b/libc/intrin/createnamedpipe.greg.c @@ -41,10 +41,10 @@ textwindows int64_t CreateNamedPipe( nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOutMs, opt_lpSecurityAttributes); if (hServer == -1) __winerr(); - STRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m", - lpName, DescribeNtPipeOpenFlags(dwOpenMode), - DescribeNtPipeModeFlags(dwPipeMode), nMaxInstances, nOutBufferSize, - nInBufferSize, nDefaultTimeOutMs, - DescribeNtSecurityAttributes(opt_lpSecurityAttributes), hServer); + NTTRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m", + lpName, DescribeNtPipeOpenFlags(dwOpenMode), + DescribeNtPipeModeFlags(dwPipeMode), nMaxInstances, nOutBufferSize, + nInBufferSize, nDefaultTimeOutMs, + DescribeNtSecurityAttributes(opt_lpSecurityAttributes), hServer); return hServer; } diff --git a/libc/intrin/createpipe.greg.c b/libc/intrin/createpipe.greg.c index 8eede07cc..4e295530a 100644 --- a/libc/intrin/createpipe.greg.c +++ b/libc/intrin/createpipe.greg.c @@ -36,8 +36,8 @@ textwindows bool32 CreatePipe( ok = __imp_CreatePipe(out_hReadPipe, out_hWritePipe, opt_lpPipeAttributes, nSize); if (!ok) __winerr(); - STRACE("CreatePipe([%ld], [%ld], %s, %'zu) → %hhhd% m", *out_hReadPipe, - *out_hWritePipe, DescribeNtSecurityAttributes(opt_lpPipeAttributes), - nSize, ok); + NTTRACE("CreatePipe([%ld], [%ld], %s, %'zu) → %hhhd% m", *out_hReadPipe, + *out_hWritePipe, DescribeNtSecurityAttributes(opt_lpPipeAttributes), + nSize, ok); return ok; } diff --git a/libc/intrin/createprocess.greg.c b/libc/intrin/createprocess.greg.c index 36cf40d9b..40b15876f 100644 --- a/libc/intrin/createprocess.greg.c +++ b/libc/intrin/createprocess.greg.c @@ -44,7 +44,7 @@ CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine, opt_lpCurrentDirectory, lpStartupInfo, opt_out_lpProcessInformation); if (!ok) __winerr(); - STRACE( + NTTRACE( "CreateFile(%#hs, %#hs, %s, %s, %hhhd, %u, %p, %#hs, %p, %p) → %hhhd% m", opt_lpApplicationName, lpCommandLine, DescribeNtSecurityAttributes(opt_lpProcessAttributes), diff --git a/libc/intrin/createthread.greg.c b/libc/intrin/createthread.greg.c index 2dab0bd54..77992f157 100644 --- a/libc/intrin/createthread.greg.c +++ b/libc/intrin/createthread.greg.c @@ -39,8 +39,9 @@ textwindows int64_t CreateThread( hHandle = __imp_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId); if (hHandle == -1) __winerr(); - STRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m", - DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize, - lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId, hHandle); + NTTRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m", + DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize, + lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId, + hHandle); return hHandle; } diff --git a/libc/intrin/cxafinalize.c b/libc/intrin/cxafinalize.c index 34250cd3d..ca9796b05 100644 --- a/libc/intrin/cxafinalize.c +++ b/libc/intrin/cxafinalize.c @@ -36,7 +36,6 @@ void __cxa_finalize(void *pred) { unsigned i, mask; struct CxaAtexitBlock *b, *b2; - STRACE("__cxa_finalize()"); StartOver: if ((b = __cxa_blocks.p)) { for (;;) { @@ -47,6 +46,7 @@ StartOver: if (!pred || pred == b->p[i].pred) { b->mask &= ~(1u << i); if (b->p[i].fp) { + STRACE("__cxa_finalize(%t, %p)", b->p[i].fp, b->p[i].arg); ((void (*)(void *))b->p[i].fp)(b->p[i].arg); goto StartOver; } diff --git a/libc/intrin/deletefile.greg.c b/libc/intrin/deletefile.greg.c index 17ac4a829..0038afd6a 100644 --- a/libc/intrin/deletefile.greg.c +++ b/libc/intrin/deletefile.greg.c @@ -32,6 +32,6 @@ textwindows bool32 DeleteFile(const char16_t *lpPathName) { bool32 ok; ok = __imp_DeleteFileW(lpPathName); if (!ok) __winerr(); - STRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok); + NTTRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok); return ok; } diff --git a/libc/intrin/deviceiocontrol.greg.c b/libc/intrin/deviceiocontrol.greg.c index c9924e17f..903137913 100644 --- a/libc/intrin/deviceiocontrol.greg.c +++ b/libc/intrin/deviceiocontrol.greg.c @@ -40,8 +40,8 @@ textwindows bool32 DeviceIoControl(int64_t hDevice, uint32_t dwIoControlCode, nInBufferSize, lpOutBuffer, nOutBufferSize, lpBytesReturned, lpOverlapped); if (!ok) __winerr(); - STRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m", - hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, - nOutBufferSize, lpBytesReturned, lpOverlapped, ok); + NTTRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m", + hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer, + nOutBufferSize, lpBytesReturned, lpOverlapped, ok); return ok; } diff --git a/libc/intrin/findclose.greg.c b/libc/intrin/findclose.greg.c index b30f697b8..17fe27fe7 100644 --- a/libc/intrin/findclose.greg.c +++ b/libc/intrin/findclose.greg.c @@ -31,6 +31,6 @@ textwindows bool32 FindClose(int64_t hFindFile) { bool32 ok; ok = __imp_FindClose(hFindFile); if (!ok) __winerr(); - STRACE("FindClose(%ld) → %hhhd% m", hFindFile, ok); + NTTRACE("FindClose(%ld) → %hhhd% m", hFindFile, ok); return ok; } diff --git a/libc/intrin/findfirstfile.greg.c b/libc/intrin/findfirstfile.greg.c index 48a8e773a..76936932d 100644 --- a/libc/intrin/findfirstfile.greg.c +++ b/libc/intrin/findfirstfile.greg.c @@ -35,7 +35,7 @@ textwindows int64_t FindFirstFile(const char16_t *lpFileName, int64_t hFindFile; hFindFile = __imp_FindFirstFileW(lpFileName, out_lpFindFileData); if (hFindFile != -1) { - STRACE( + NTTRACE( "FindFirstFile(%#hs, [{" ".cFileName=%#hs, " ".dwFileAttributes=%s, " @@ -46,7 +46,7 @@ textwindows int64_t FindFirstFile(const char16_t *lpFileName, DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), hFindFile); } else { __winerr(); - STRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile); + NTTRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile); } return hFindFile; } diff --git a/libc/intrin/findnextfile.greg.c b/libc/intrin/findnextfile.greg.c index 9532ba07b..750ea2138 100644 --- a/libc/intrin/findnextfile.greg.c +++ b/libc/intrin/findnextfile.greg.c @@ -37,7 +37,7 @@ textwindows bool32 FindNextFile(int64_t hFindFile, bool32 ok; ok = __imp_FindNextFileW(hFindFile, out_lpFindFileData); if (ok) { - STRACE( + NTTRACE( "FindNextFile(%ld, [{" ".cFileName=%#hs, " ".dwFileAttributes=%s, " @@ -48,7 +48,7 @@ textwindows bool32 FindNextFile(int64_t hFindFile, DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), ok); } else { if (GetLastError() != kNtErrorNoMoreFiles) __winerr(); - STRACE("FindNextFile(%ld) → %hhhd% m", hFindFile, ok); + NTTRACE("FindNextFile(%ld) → %hhhd% m", hFindFile, ok); } return ok; } diff --git a/libc/intrin/flushfilebuffers.greg.c b/libc/intrin/flushfilebuffers.greg.c index 28e7ecfa3..e6b4c90e4 100644 --- a/libc/intrin/flushfilebuffers.greg.c +++ b/libc/intrin/flushfilebuffers.greg.c @@ -38,6 +38,6 @@ textwindows bool32 FlushFileBuffers(int64_t hFile) { bool32 ok; ok = __imp_FlushFileBuffers(hFile); if (!ok) __winerr(); - STRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok); + NTTRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok); return ok; } diff --git a/libc/intrin/flushviewoffile.greg.c b/libc/intrin/flushviewoffile.greg.c index c90111e94..e8ad6082c 100644 --- a/libc/intrin/flushviewoffile.greg.c +++ b/libc/intrin/flushviewoffile.greg.c @@ -37,7 +37,7 @@ textwindows bool32 FlushViewOfFile(const void *lpBaseAddress, bool32 ok; ok = __imp_FlushViewOfFile(lpBaseAddress, dwNumberOfBytesToFlush); if (!ok) __winerr(); - STRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress, - dwNumberOfBytesToFlush, ok); + NTTRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress, + dwNumberOfBytesToFlush, ok); return ok; } diff --git a/libc/intrin/generateconsolectrlevent.greg.c b/libc/intrin/generateconsolectrlevent.greg.c index de4b21306..4617973d2 100644 --- a/libc/intrin/generateconsolectrlevent.greg.c +++ b/libc/intrin/generateconsolectrlevent.greg.c @@ -35,7 +35,7 @@ textwindows bool32 GenerateConsoleCtrlEvent(uint32_t dwCtrlEvent, bool32 ok; ok = __imp_GenerateConsoleCtrlEvent(dwCtrlEvent, dwProcessGroupId); if (!ok) __winerr(); - STRACE("GenerateConsoleCtrlEvent(%x, %d) → %hhhd% m", dwCtrlEvent, - dwProcessGroupId, ok); + NTTRACE("GenerateConsoleCtrlEvent(%x, %d) → %hhhd% m", dwCtrlEvent, + dwProcessGroupId, ok); return ok; } diff --git a/libc/intrin/getenv.c b/libc/intrin/getenv.c index d92dd5f1f..107cfb4db 100644 --- a/libc/intrin/getenv.c +++ b/libc/intrin/getenv.c @@ -21,6 +21,7 @@ #include "libc/dce.h" #include "libc/errno.h" #include "libc/intrin/kprintf.h" +#include "libc/log/libfatal.internal.h" #include "libc/runtime/runtime.h" forceinline int Identity(int c) { @@ -66,6 +67,11 @@ char *getenv(const char *s) { } else { r = GetEnv(s, ToUpper); } - STRACE("getenv(%#s) → %#s", s, r); +#if SYSDEBUG + if (!(s[0] == 'T' && s[1] == 'Z' && !s[2])) { + // TODO(jart): memoize TZ or something + STRACE("getenv(%#s) → %#s", s, r); + } +#endif return r; } diff --git a/libc/intrin/getfileattributes.greg.c b/libc/intrin/getfileattributes.greg.c index 8bf406a31..b7dcefb7b 100644 --- a/libc/intrin/getfileattributes.greg.c +++ b/libc/intrin/getfileattributes.greg.c @@ -35,7 +35,7 @@ textwindows uint32_t GetFileAttributes(const char16_t *lpPathName) { uint32_t flags; flags = __imp_GetFileAttributesW(lpPathName); if (flags == -1u) __winerr(); - STRACE("GetFileAttributes(%#hs) → %s% m", lpPathName, - DescribeNtFileFlagsAndAttributes(flags)); + NTTRACE("GetFileAttributes(%#hs) → %s% m", lpPathName, + DescribeNtFileFlagsAndAttributes(flags)); return flags; } diff --git a/libc/intrin/kprintf.greg.c b/libc/intrin/kprintf.greg.c index 634dcd7e8..08364779e 100644 --- a/libc/intrin/kprintf.greg.c +++ b/libc/intrin/kprintf.greg.c @@ -40,6 +40,7 @@ #include "libc/nt/winsock.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" #include "libc/str/str.h" #include "libc/str/tpenc.h" #include "libc/str/utf16.h" @@ -515,19 +516,27 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, case 'G': x = va_arg(va, int); - if (weaken(strsignal)) { - s = weaken(strsignal)(x); + if (weaken(strsignal) && (s = weaken(strsignal)(x))) { goto FormatString; } else { - if (p + 3 <= e) { - p[0] = 'S'; - p[1] = 'I'; - p[2] = 'G'; - } - p += 3; goto FormatDecimal; } + case 't': { + int idx; + x = va_arg(va, intptr_t); + if (weaken(__get_symbol) && + (idx = weaken(__get_symbol)(0, x)) != -1) { + if (p + 1 <= e) *p++ = '&'; + s = weaken(GetSymbolTable)()->name_base + + weaken(GetSymbolTable)()->names[idx]; + goto FormatString; + } + base = 4; + hash = '&'; + goto FormatNumber; + } + case 'n': // nonstandard %n specifier // used to print newlines that work in raw terminal modes @@ -558,8 +567,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va, if (!(s = va_arg(va, const void *))) { s = sign != ' ' ? "NULL" : ""; FormatString: - type = 0; hash = 0; + type = 0; } else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) { if (sign == ' ') { if (p < e) *p = ' '; @@ -847,6 +856,7 @@ privileged void kvprintf(const char *fmt, va_list v) { * - `o` octal * - `b` binary * - `s` string + * - `t` symbol * - `p` pointer * - `d` decimal * - `n` newline @@ -885,6 +895,10 @@ privileged void kvprintf(const char *fmt, va_list v) { * - `% m` formats error with leading space if errno isn't zero * - `%lm` means favor WSAGetLastError() over GetLastError() if linked * + * You need to link and load the symbol table before `%t` will work. You + * can do that by calling `GetSymbolTable()`. If that hasn't happened it + * will print `&hexnumber` instead. + * * @asyncsignalsafe * @vforksafe */ diff --git a/libc/intrin/mapviewoffileex.greg.c b/libc/intrin/mapviewoffileex.greg.c index b4acc0f87..778e56497 100644 --- a/libc/intrin/mapviewoffileex.greg.c +++ b/libc/intrin/mapviewoffileex.greg.c @@ -45,9 +45,9 @@ textwindows void *MapViewOfFileEx(int64_t hFileMappingObject, hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, opt_lpDesiredBaseAddress); if (!pStartingAddress) __winerr(); - STRACE("MapViewOfFileEx(%ld, %s, %'ld, %'zu, %p) → %p% m", hFileMappingObject, - DescribeNtFileMapFlags(dwDesiredAccess), - (uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow, - dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress); + NTTRACE("MapViewOfFileEx(%ld, %s, %'ld, %'zu, %p) → %p% m", + hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess), + (uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow, + dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress); return pStartingAddress; } diff --git a/libc/intrin/mapviewoffileexnuma.greg.c b/libc/intrin/mapviewoffileexnuma.greg.c index 2ee0b2813..dbbe9e3e5 100644 --- a/libc/intrin/mapviewoffileexnuma.greg.c +++ b/libc/intrin/mapviewoffileexnuma.greg.c @@ -47,9 +47,9 @@ textwindows void *MapViewOfFileExNuma(int64_t hFileMappingObject, hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, nndDesiredNumaNode); if (!pStartingAddress) __winerr(); - STRACE("MapViewOfFileExNuma(%ld, %s, %'ld, %'zu, %p) → %p% m", - hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess), - (uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow, - dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress); + NTTRACE("MapViewOfFileExNuma(%ld, %s, %'ld, %'zu, %p) → %p% m", + hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess), + (uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow, + dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress); return pStartingAddress; } diff --git a/libc/intrin/openprocess.greg.c b/libc/intrin/openprocess.greg.c index b38b03b5a..897d4f7c9 100644 --- a/libc/intrin/openprocess.greg.c +++ b/libc/intrin/openprocess.greg.c @@ -39,8 +39,8 @@ textwindows int64_t OpenProcess(uint32_t dwDesiredAccess, bool32 bInheritHandle, int64_t hHandle; hHandle = __imp_OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId); if (!hHandle) __winerr(); - STRACE("OpenProcess(%s, %hhhd, %u) → %ld% m", - DescribeNtProcessAccessFlags(dwDesiredAccess), bInheritHandle, - dwProcessId, hHandle); + NTTRACE("OpenProcess(%s, %hhhd, %u) → %ld% m", + DescribeNtProcessAccessFlags(dwDesiredAccess), bInheritHandle, + dwProcessId, hHandle); return hHandle; } diff --git a/libc/intrin/removedirectory.greg.c b/libc/intrin/removedirectory.greg.c index fdd9a6211..3fcf0aac5 100644 --- a/libc/intrin/removedirectory.greg.c +++ b/libc/intrin/removedirectory.greg.c @@ -32,6 +32,6 @@ textwindows bool32 RemoveDirectory(const char16_t *lpPathName) { bool32 ok; ok = __imp_RemoveDirectoryW(lpPathName); if (!ok) __winerr(); - STRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok); + NTTRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok); return ok; } diff --git a/libc/intrin/reopenfile.greg.c b/libc/intrin/reopenfile.greg.c index 1462affc9..b20292ae6 100644 --- a/libc/intrin/reopenfile.greg.c +++ b/libc/intrin/reopenfile.greg.c @@ -36,9 +36,9 @@ int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess, hHandle = __imp_ReOpenFile(hOriginalFile, dwDesiredAccess, dwShareMode, dwFlagsAndAttributes); if (hHandle == -1) __winerr(); - STRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile, - DescribeNtFileAccessFlags(dwDesiredAccess), - DescribeNtFileShareFlags(dwShareMode), - DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), hHandle); + NTTRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile, + DescribeNtFileAccessFlags(dwDesiredAccess), + DescribeNtFileShareFlags(dwShareMode), + DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), hHandle); return hHandle; } diff --git a/libc/intrin/restorewintty.greg.c b/libc/intrin/restorewintty.greg.c index 9c9b68ad8..808d81986 100644 --- a/libc/intrin/restorewintty.greg.c +++ b/libc/intrin/restorewintty.greg.c @@ -37,7 +37,7 @@ const char kConsoleHandles[3] = { noasan void __restorewintty(void) { int i; if (!IsWindows()) return; - STRACE("__restorewintty()"); + NTTRACE("__restorewintty()"); if (GetCurrentProcessId() == __winmainpid) { for (i = 0; i < 3; ++i) { SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]); diff --git a/libc/intrin/setcurrentdirectory.greg.c b/libc/intrin/setcurrentdirectory.greg.c index 92d6107d1..28f0f9516 100644 --- a/libc/intrin/setcurrentdirectory.greg.c +++ b/libc/intrin/setcurrentdirectory.greg.c @@ -32,6 +32,6 @@ textwindows bool32 SetCurrentDirectory(const char16_t *lpPathName) { bool32 ok; ok = __imp_SetCurrentDirectoryW(lpPathName); if (!ok) __winerr(); - STRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok); + NTTRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok); return ok; } diff --git a/libc/intrin/terminateprocess.greg.c b/libc/intrin/terminateprocess.greg.c index e19c0464a..5f308f7cf 100644 --- a/libc/intrin/terminateprocess.greg.c +++ b/libc/intrin/terminateprocess.greg.c @@ -32,6 +32,6 @@ textwindows bool32 TerminateProcess(int64_t hProcess, uint32_t uExitCode) { bool32 ok; ok = __imp_TerminateProcess(hProcess, uExitCode); if (!ok) __winerr(); - STRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uExitCode, ok); + NTTRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uExitCode, ok); return ok; } diff --git a/libc/intrin/unmapviewoffile.greg.c b/libc/intrin/unmapviewoffile.greg.c index 33da0e10a..aa7684fa0 100644 --- a/libc/intrin/unmapviewoffile.greg.c +++ b/libc/intrin/unmapviewoffile.greg.c @@ -30,6 +30,6 @@ textwindows bool32 UnmapViewOfFile(const void *lpBaseAddress) { bool32 ok; ok = __imp_UnmapViewOfFile(lpBaseAddress); if (!ok) __winerr(); - STRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok); + NTTRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok); return ok; } diff --git a/libc/intrin/virtualprotect.greg.c b/libc/intrin/virtualprotect.greg.c index 3f3529e74..07fb6f747 100644 --- a/libc/intrin/virtualprotect.greg.c +++ b/libc/intrin/virtualprotect.greg.c @@ -40,7 +40,7 @@ textwindows bool32 VirtualProtect(void *lpAddress, uint64_t dwSize, __winerr(); __stpcpy(oldbuf, "n/a"); } - STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize, - DescribeNtPageFlags(flNewProtect), oldbuf, bOk); + NTTRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize, + DescribeNtPageFlags(flNewProtect), oldbuf, bOk); return bOk; } diff --git a/libc/log/showcrashreports.c b/libc/log/showcrashreports.c index 7297becf5..66edf6490 100644 --- a/libc/log/showcrashreports.c +++ b/libc/log/showcrashreports.c @@ -22,6 +22,7 @@ #include "libc/log/internal.h" #include "libc/log/log.h" #include "libc/macros.internal.h" +#include "libc/runtime/symbols.internal.h" #include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/consts/ss.h" @@ -79,4 +80,5 @@ void ShowCrashReports(void) { sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]); } } + GetSymbolTable(); } diff --git a/libc/macros-cpp.internal.inc b/libc/macros-cpp.internal.inc index 173ef7877..21f91ecbe 100644 --- a/libc/macros-cpp.internal.inc +++ b/libc/macros-cpp.internal.inc @@ -149,29 +149,6 @@ pop \dest .endm -// Loads address of linktime mergeable string literal into register. -.macro getstr text:req reg64:req reg32 regsz64 regsz32 bias=0 - .section .rodata.str1.1,"aSM",@progbits,1 - .type .Lstr\@,@object -.Lstr\@: .asciz "\text" -.Lstr\@.size = .-.Lstr\@ - 1 - .size .Lstr\@,.-.Lstr\@ - .previous - plea .Lstr\@,\reg64,\reg32 - .ifnb \regsz64 -#ifdef __OPTIMIZE_SIZE__ - .if .Lstr\@.size + \bias < 128 - pushpop .Lstr\@.size,\regsz64 - .else - mov $.Lstr\@.size,\regsz32 - .endif -#else - mov $.Lstr\@.size,\regsz32 -#endif - .endif -.endm - -// TODO(jart): delete // Loads address of linktime mergeable string literal into register. .macro loadstr text:req reg:req regsz bias=0 .section .rodata.str1.1,"aSM",@progbits,1 diff --git a/tool/decode/lib/x86gradenames.c b/libc/nexgen32e/x86gradenames.c similarity index 100% rename from tool/decode/lib/x86gradenames.c rename to libc/nexgen32e/x86gradenames.c diff --git a/tool/decode/lib/x86marchnames.c b/libc/nexgen32e/x86marchnames.c similarity index 100% rename from tool/decode/lib/x86marchnames.c rename to libc/nexgen32e/x86marchnames.c diff --git a/libc/rand/getrandom.c b/libc/rand/getrandom.c index bbcf2093d..866dd671e 100644 --- a/libc/rand/getrandom.c +++ b/libc/rand/getrandom.c @@ -125,7 +125,7 @@ static textstartup void getrandom_init(void) { if (!(rc = sys_getrandom(0, 0, 0))) { have_getrandom = true; } - STRACE("sys_getrandom(0,0,0) → %d% m"); + KERNTRACE("sys_getrandom(0,0,0) → %d% m"); errno = e; } diff --git a/libc/runtime/cosmo.S b/libc/runtime/cosmo.S index 869d72823..df505099e 100644 --- a/libc/runtime/cosmo.S +++ b/libc/runtime/cosmo.S @@ -90,11 +90,14 @@ cosmo: push %rbp #if IsModeDbg() #ifdef SYSDEBUG .init.start 307,_init_printargs + cmpl $0,__strace(%rip) + jz 1f push %rdi push %rsi + loadstr STRACE_PROLOGUE,di call __printargs pop %rsi pop %rdi - .init.end 307,_init_printargs +1: .init.end 307,_init_printargs #endif #endif diff --git a/libc/runtime/fork-nt.c b/libc/runtime/fork-nt.c index 6cca9b5ca..79b15176c 100644 --- a/libc/runtime/fork-nt.c +++ b/libc/runtime/fork-nt.c @@ -52,6 +52,7 @@ STATIC_YOINK("_check_sigchld"); extern int __pid; +extern int64_t __wincrashearly; extern unsigned long long __kbirth; extern unsigned char __data_start[]; /* αpε */ extern unsigned char __data_end[]; /* αpε */ @@ -59,6 +60,11 @@ extern unsigned char __bss_start[]; /* αpε */ extern unsigned char __bss_end[]; /* αpε */ bool32 __onntconsoleevent_nt(uint32_t); +static textwindows wontreturn void KillForkChild(const char *func) { + STRACE("fork() %s() failed %d", func, GetLastError()); + ExitProcess(177); +} + static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) { *x = 0; while (*p == ' ') p++; @@ -84,7 +90,7 @@ static inline textwindows ssize_t ForkIo(int64_t h, char *p, size_t n, static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n, bool32 (*fn)(), const char *sf) { ssize_t rc = ForkIo(h, buf, n, fn); - // STRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc); + NTTRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc); return rc != -1; } @@ -92,8 +98,10 @@ static dontinline textwindows bool WriteAll(int64_t h, void *buf, size_t n) { return ForkIo2(h, buf, n, WriteFile, "WriteFile"); } -static textwindows dontinline bool ReadAll(int64_t h, void *buf, size_t n) { - return ForkIo2(h, buf, n, ReadFile, "ReadFile"); +static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) { + if (!ForkIo2(h, buf, n, ReadFile, "ReadFile")) { + KillForkChild("ReadFile"); + } } textwindows void WinMainForked(void) { @@ -114,7 +122,7 @@ textwindows void WinMainForked(void) { // this variable should have the pipe handle numba varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar)); if (!varlen || varlen >= ARRAYLEN(fvar)) return; - STRACE("WinMainForked()"); + NTTRACE("WinMainForked()"); SetEnvironmentVariable(u"_FORK", NULL); ParseInt(fvar, &reader); @@ -123,21 +131,21 @@ textwindows void WinMainForked(void) { // this is stored in a special secretive memory map! // read ExtendMemoryIntervals for further details :| maps = (void *)kMemtrackStart; - ReadAll(reader, jb, sizeof(jb)); - ReadAll(reader, &mapcount, sizeof(_mmi.i)); - ReadAll(reader, &mapcapacity, sizeof(_mmi.n)); + ReadOrDie(reader, jb, sizeof(jb)); + ReadOrDie(reader, &mapcount, sizeof(_mmi.i)); + ReadOrDie(reader, &mapcapacity, sizeof(_mmi.n)); specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran); MapViewOfFileEx( CreateFileMapping(-1, 0, kNtPageReadwrite, specialz >> 32, specialz, 0), kNtFileMapWrite, 0, 0, specialz, maps); - ReadAll(reader, maps, mapcount * sizeof(_mmi.p[0])); + ReadOrDie(reader, maps, mapcount * sizeof(_mmi.p[0])); if (IsAsan()) { shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000); size = ROUNDUP(specialz >> 3, FRAMESIZE); MapViewOfFileEx( CreateFileMapping(-1, 0, kNtPageReadwrite, size >> 32, size, 0), kNtFileMapWrite, 0, 0, size, maps); - ReadAll(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3); + ReadOrDie(reader, shad, (mapcount * sizeof(_mmi.p[0])) >> 3); } // read the heap mappings from the parent process @@ -152,7 +160,7 @@ textwindows void WinMainForked(void) { upsize >> 32, upsize, 0); MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0, upsize, addr); - ReadAll(reader, addr, size); + ReadOrDie(reader, addr, size); } else { // we can however safely inherit MAP_SHARED with zero copy MapViewOfFileEx(maps[i].h, @@ -167,8 +175,8 @@ textwindows void WinMainForked(void) { savepid = __pid; savebir = __kbirth; savetsc = ts; - ReadAll(reader, __data_start, __data_end - __data_start); - ReadAll(reader, __bss_start, __bss_end - __bss_start); + ReadOrDie(reader, __data_start, __data_end - __data_start); + ReadOrDie(reader, __bss_start, __bss_end - __bss_start); __pid = savepid; __kbirth = savebir; ts = savetsc; @@ -177,23 +185,28 @@ textwindows void WinMainForked(void) { _mmi.p = maps; _mmi.n = specialz / sizeof(_mmi.p[0]); for (i = 0; i < mapcount; ++i) { - VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size, - __prot2nt(maps[i].prot, maps[i].iscow), &oldprot); + if (!VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size, + __prot2nt(maps[i].prot, maps[i].iscow), &oldprot)) { + KillForkChild("VirtualProtect"); + } } // mitosis complete - CloseHandle(reader); + if (!CloseHandle(reader)) { + KillForkChild("CloseHandle"); + } // rewrap the stdin named pipe hack // since the handles closed on fork if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)(); struct Fds *fds = VEIL("r", &g_fds); - fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); // just in case - fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); // just in case - fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle); // just in case + fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); + fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); + fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle); // restore the crash reporting stuff if (weaken(__wincrash_nt)) { + RemoveVectoredExceptionHandler(__wincrashearly); AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt)); } if (weaken(__onntconsoleevent_nt)) { diff --git a/libc/runtime/ftracer.c b/libc/runtime/ftracer.c index 4011d5781..9060b36ba 100644 --- a/libc/runtime/ftracer.c +++ b/libc/runtime/ftracer.c @@ -48,9 +48,8 @@ void ftrace_hook(void); bool ftrace_enabled; static int g_skew; -static int g_lastsymbol; -static uint64_t laststamp; -static struct SymbolTable *g_symbols; +static int64_t g_lastaddr; +static uint64_t g_laststamp; static privileged noinstrument noasan noubsan int GetNestingLevelImpl( struct StackFrame *frame) { @@ -80,34 +79,31 @@ static privileged noinstrument noasan noubsan int GetNestingLevel( */ privileged noinstrument noasan noubsan void ftracer(void) { /* asan runtime depends on this function */ - int symbol; uint64_t stamp; static bool noreentry; struct StackFrame *frame; if (!_cmpxchg(&noreentry, 0, 1)) return; - if (ftrace_enabled && g_symbols) { + if (ftrace_enabled) { stamp = rdtsc(); frame = __builtin_frame_address(0); frame = frame->next; - if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 && - symbol != g_lastsymbol) { - g_lastsymbol = symbol; - kprintf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "", - __get_symbol_name(g_symbols, symbol), - (long)(unsignedsubtract(stamp, laststamp) / 3.3)); - laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc(); + if (frame->addr != g_lastaddr) { + kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr, + (long)(unsignedsubtract(stamp, g_laststamp) / 3.3)); + g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc(); + g_lastaddr = frame->addr; } } noreentry = 0; } textstartup void ftrace_install(void) { - if ((g_symbols = GetSymbolTable())) { - laststamp = kStartTsc; - g_lastsymbol = -1; + if (GetSymbolTable()) { + g_lastaddr = -1; + g_laststamp = kStartTsc; g_skew = GetNestingLevelImpl(__builtin_frame_address(0)); ftrace_enabled = 1; - __hook(ftrace_hook, g_symbols); + __hook(ftrace_hook, GetSymbolTable()); } else { kprintf("error: --ftrace failed to open symbol table\r\n"); } diff --git a/libc/runtime/getinterpreterexecutablename.c b/libc/runtime/getinterpreterexecutablename.c index 695c3f46c..fd4331b8a 100644 --- a/libc/runtime/getinterpreterexecutablename.c +++ b/libc/runtime/getinterpreterexecutablename.c @@ -50,7 +50,7 @@ char *GetInterpreterExecutableName(char *p, size_t n) { e = errno; if (n < 2) { errno = ENAMETOOLONG; - } else if (IsWindows()) { + } else if (IsWindows() || IsXnu()) { if (strlen(GetProgramExecutableName()) < n) { strcpy(p, GetProgramExecutableName()); return p; diff --git a/libc/runtime/getsymboltable.c b/libc/runtime/getsymboltable.c index 43ff79632..354d42e01 100644 --- a/libc/runtime/getsymboltable.c +++ b/libc/runtime/getsymboltable.c @@ -29,10 +29,12 @@ #include "libc/zip.h" #include "libc/zipos/zipos.internal.h" +static struct SymbolTable *g_symtab; + /** * Looks for `.symtab` in zip central directory. */ -noasan static ssize_t FindSymtabInZip(struct Zipos *zipos) { +static ssize_t FindSymtabInZip(struct Zipos *zipos) { size_t i, n, c; c = GetZipCdirOffset(zipos->cdir); n = GetZipCdirRecords(zipos->cdir); @@ -51,7 +53,7 @@ noasan static ssize_t FindSymtabInZip(struct Zipos *zipos) { * Reads symbol table from zip directory. * @note This code can't depend on dlmalloc() */ -noasan static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) { +static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) { ssize_t cf, lf; size_t size, size2; struct DeflateState ds; @@ -88,7 +90,7 @@ noasan static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) { * Reads symbol table from .com.dbg file. * @note This code can't depend on dlmalloc() */ -noasan static struct SymbolTable *GetSymbolTableFromElf(void) { +static struct SymbolTable *GetSymbolTableFromElf(void) { return OpenSymbolTable(FindDebugBinary()); } @@ -112,24 +114,56 @@ noasan static struct SymbolTable *GetSymbolTableFromElf(void) { * * @return symbol table, or NULL w/ errno on first call */ -noasan struct SymbolTable *GetSymbolTable(void) { +struct SymbolTable *GetSymbolTable(void) { int ft, st; struct Zipos *z; - static struct SymbolTable *t; - if (!t) { + if (!g_symtab) { ft = g_ftrace, g_ftrace = 0; st = __strace, __strace = 0; if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) { - if ((t = GetSymbolTableFromZip(z))) { - t->names = (uint32_t *)((char *)t + t->names_offset); - t->name_base = (char *)((char *)t + t->name_base_offset); + if ((g_symtab = GetSymbolTableFromZip(z))) { + g_symtab->names = + (uint32_t *)((char *)g_symtab + g_symtab->names_offset); + g_symtab->name_base = + (char *)((char *)g_symtab + g_symtab->name_base_offset); } } - if (!t) { - t = GetSymbolTableFromElf(); + if (!g_symtab) { + g_symtab = GetSymbolTableFromElf(); } g_ftrace = ft; __strace = st; } - return t; + return g_symtab; +} + +/** + * Returns low index into symbol table for address. + * + * @param t if null will be auto-populated only if already open + * @return index or -1 if nothing found + */ +privileged int __get_symbol(struct SymbolTable *t, intptr_t a) { + /* asan runtime depends on this function */ + unsigned l, m, r, n, k; + if (!t && g_symtab) { + t = g_symtab; + } + if (t) { + l = 0; + r = n = t->count; + k = a - t->addr_base; + while (l < r) { + m = (l + r) >> 1; + if (t->symbols[m].y < k) { + l = m + 1; + } else { + r = m; + } + } + if (l < n && t->symbols[l].x <= k && k <= t->symbols[l].y) { + return l; + } + } + return -1; } diff --git a/libc/runtime/memtrack.c b/libc/runtime/memtrack.greg.c similarity index 100% rename from libc/runtime/memtrack.c rename to libc/runtime/memtrack.greg.c diff --git a/libc/runtime/mremap.c b/libc/runtime/mremap.c index e09c323c3..0233e962d 100644 --- a/libc/runtime/mremap.c +++ b/libc/runtime/mremap.c @@ -180,7 +180,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { } q = sys_mremap((void *)p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED, (void *)ADDR(a)); - STRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p", p, n, m, + KERNTRACE("sys_mremap(%p, %'zu, %'zu, %#b, %p) → %p", p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED, ADDR(a), q); if (q == MAP_FAILED) return 0; if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16, diff --git a/libc/runtime/runtime.h b/libc/runtime/runtime.h index 7d8a8418c..02ba9f5fd 100644 --- a/libc/runtime/runtime.h +++ b/libc/runtime/runtime.h @@ -100,6 +100,7 @@ long GetResourceLimit(int); long GetMaxFd(void); char *GetProgramExecutableName(void); char *GetInterpreterExecutableName(char *, size_t); +void __printargs(const char *); COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ diff --git a/libc/runtime/runtime.mk b/libc/runtime/runtime.mk index 429f76ddb..5a929505b 100644 --- a/libc/runtime/runtime.mk +++ b/libc/runtime/runtime.mk @@ -75,11 +75,13 @@ o/$(MODE)/libc/runtime/hook.greg.o \ o/$(MODE)/libc/runtime/isheap.o \ o/$(MODE)/libc/runtime/memtrack.o \ o/$(MODE)/libc/runtime/memtracknt.o \ +o/$(MODE)/libc/runtime/printargs.greg.o \ o/$(MODE)/libc/runtime/mman.greg.o \ o/$(MODE)/libc/runtime/print.greg.o \ o/$(MODE)/libc/runtime/stackchkfail.o \ o/$(MODE)/libc/runtime/stackchkfaillocal.o \ -o/$(MODE)/libc/runtime/winmain.greg.o: \ +o/$(MODE)/libc/runtime/winmain.greg.o \ +o/$(MODE)/libc/runtime/getsymboltable.greg.o: \ OVERRIDE_CFLAGS += \ -ffreestanding \ $(NO_MAGIC) @@ -90,13 +92,6 @@ o/$(MODE)/libc/runtime/fork-nt.o: \ OVERRIDE_CPPFLAGS += \ -DSTACK_FRAME_UNLIMITED -o/$(MODE)/libc/runtime/printf.o \ -o/$(MODE)/libc/runtime/memtrack.o \ -o/$(MODE)/libc/runtime/mman.greg.o: \ - OVERRIDE_CFLAGS += \ - -ffreestanding \ - -mgeneral-regs-only - o/$(MODE)/libc/runtime/qsort.o: \ OVERRIDE_CFLAGS += \ -Og diff --git a/libc/runtime/winmain.greg.c b/libc/runtime/winmain.greg.c index 5c3078c57..f28852cc3 100644 --- a/libc/runtime/winmain.greg.c +++ b/libc/runtime/winmain.greg.c @@ -120,7 +120,7 @@ forceinline void MakeLongDoubleLongAgain(void) { asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw)); } -__msabi static textwindows int WinCrashEarly(struct NtExceptionPointers *ep) { +__msabi static textwindows int OnEarlyWinCrash(struct NtExceptionPointers *ep) { uint32_t wrote; char buf[64], *p = buf; *p++ = 'c'; @@ -158,15 +158,16 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) { __winmainpid = __pid; rc = SetConsoleCP(kNtCpUtf8); - STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc); + NTTRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc); rc = SetConsoleOutputCP(kNtCpUtf8); - STRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc); + NTTRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc); for (i = 0; i < 3; ++i) { hand = GetStdHandle(kConsoleHandles[i]); rc = GetConsoleMode(hand, __ntconsolemode + i); - STRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i], rc); + NTTRACE("GetConsoleMode(%p, [%#x]) → %hhhd", hand, __ntconsolemode[i], + rc); rc = SetConsoleMode(hand, kConsoleModes[i]); - STRACE("SetConsoleMode(%p, %#x) → %hhhd", hand, kConsoleModes[i], rc); + NTTRACE("SetConsoleMode(%p, %#x) → %hhhd", hand, kConsoleModes[i], rc); } } _mmi.p = _mmi.s; @@ -176,8 +177,8 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { stacksize = GetStackSize(); allocsize = argsize + stacksize; allocaddr = stackaddr - argsize; - STRACE("WinMainNew() mapping %'zu byte arg block + stack at %p", allocsize, - allocaddr); + NTTRACE("WinMainNew() mapping %'zu byte arg block + stack at %p", allocsize, + allocaddr); MapViewOfFileEx( (_mmi.p[0].h = CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite, @@ -194,7 +195,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { _mmi.p[0].size = allocsize; _mmi.i = 1; wa = (struct WinArgs *)allocaddr; - STRACE("WinMainNew() loading arg block"); + NTTRACE("WinMainNew() loading arg block"); count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), wa->argv, ARRAYLEN(wa->argv)); for (i = 0; wa->argv[0][i]; ++i) { @@ -203,13 +204,11 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) { } } env16 = GetEnvironmentStrings(); - STRACE("WinMainNew() loading environment"); + NTTRACE("WinMainNew() loading environment"); GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp, ARRAYLEN(wa->envp) - 1); FreeEnvironmentStrings(env16); - wa->auxv[0][0] = pushpop(AT_EXECFN); - wa->auxv[0][1] = (intptr_t)wa->argv[0]; - STRACE("WinMainNew() switching stacks"); + NTTRACE("WinMainNew() switching stacks"); _jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo, count, wa->argv, wa->envp, wa->auxv); } @@ -255,13 +254,13 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance, ts = rdtsc(); __nomultics = true; __pid = GetCurrentProcessId(); - __wincrashearly = AddVectoredExceptionHandler(1, (void *)WinCrashEarly); + __wincrashearly = AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash); cmdline = GetCommandLine(); #ifdef SYSDEBUG /* sloppy flag-only check for early initialization */ if (__strstr16(cmdline, u"--strace")) ++__strace; #endif - STRACE("WinMain()"); + NTTRACE("WinMain()"); MakeLongDoubleLongAgain(); if (weaken(WinSockInit)) weaken(WinSockInit)(); if (weaken(WinMainForked)) weaken(WinMainForked)(); diff --git a/libc/sock/internal.h b/libc/sock/internal.h index 3f54c86d4..5fe8fccc2 100644 --- a/libc/sock/internal.h +++ b/libc/sock/internal.h @@ -144,6 +144,7 @@ ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t, void WinSockInit(void) hidden; int64_t __winsockerr(void) nocallback hidden; int __fixupnewsockfd(int, int) hidden; +int __wsablock(int64_t, struct NtOverlapped *, uint32_t *, bool) hidden; int64_t __winsockblock(int64_t, unsigned, int64_t) hidden; struct SockFd *_dupsockfd(struct SockFd *) hidden; int64_t GetNtBaseSocket(int64_t) hidden; diff --git a/libc/sock/kntwsadata.c b/libc/sock/kntwsadata.c index 6396f4eab..133dffe3c 100644 --- a/libc/sock/kntwsadata.c +++ b/libc/sock/kntwsadata.c @@ -39,7 +39,7 @@ hidden struct NtWsaData kNtWsaData; static textwindows void WinSockCleanup(void) { int i, rc; - STRACE("WinSockCleanup()"); + NTTRACE("WinSockCleanup()"); for (i = g_fds.n; i--;) { if (g_fds.p[i].kind == kFdSocket) { close(i); @@ -47,13 +47,13 @@ static textwindows void WinSockCleanup(void) { } // TODO(jart): Check WSACleanup() result code rc = WSACleanup(); - STRACE("WSACleanup() → %d% lm", rc); + NTTRACE("WSACleanup() → %d% lm", rc); } textwindows noasan void WinSockInit(void) { int rc; atexit(WinSockCleanup); - STRACE("WSAStartup()"); + NTTRACE("WSAStartup()"); if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 || kNtWsaData.wVersion != VERSION) { ExitProcess(123); diff --git a/libc/sock/ntstdin.greg.c b/libc/sock/ntstdin.greg.c index 6253b69d3..9531f59e3 100644 --- a/libc/sock/ntstdin.greg.c +++ b/libc/sock/ntstdin.greg.c @@ -16,7 +16,6 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#define ShouldUseMsabiAttribute() 1 #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/calls/internal.h" @@ -41,41 +40,34 @@ * @fileoverview Pollable Standard Input for the New Technology. */ -__msabi extern typeof(CloseHandle) *const __imp_CloseHandle; - -static textwindows bool IsEof(bool ok, uint32_t got) { - return (ok && !got) || (!ok && (__imp_GetLastError() == kNtErrorHandleEof || - __imp_GetLastError() == kNtErrorBrokenPipe)); -} - static textwindows uint32_t StdinWorkerThread(void *arg) { char buf[512]; bool32 ok = true; uint32_t i, rc, got, err, wrote; struct NtStdinWorker w, *wp = arg; - STRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader, - wp->writer, wp->consumer, getpid(), gettid()); + NTTRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader, + wp->writer, wp->consumer, getpid(), gettid()); __sync_lock_release(&wp->sync); w = *wp; do { - ok = __imp_ReadFile(w.reader, buf, sizeof(buf), &got, 0); + ok = ReadFile(w.reader, buf, sizeof(buf), &got, 0); /* When writing to a non-blocking, byte-mode pipe handle with insufficient buffer space, WriteFile returns TRUE with *lpNumberOfBytesWritten < nNumberOfBytesToWrite. ──Quoth MSDN WriteFile() */ for (i = 0; ok && i < got; i += wrote) { - ok = __imp_WriteFile(w.writer, buf + i, got - i, &wrote, 0); + ok = WriteFile(w.writer, buf + i, got - i, &wrote, 0); } } while (ok && got); + err = GetLastError(); if (!ok) { - err = __imp_GetLastError(); if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe || err == kNtErrorNoData) { ok = true; } } - STRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %d", w.reader, w.writer, - w.consumer, __imp_GetLastError()); + NTTRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %u", w.reader, w.writer, + w.consumer, err); return !ok; } @@ -87,7 +79,7 @@ static textwindows uint32_t StdinWorkerThread(void *arg) { */ textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) { struct NtStdinWorker *w; - STRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid()); + NTTRACE("LaunchNtStdinWorker(%d) pid %d tid %d", fd, getpid(), gettid()); assert(!g_fds.p[fd].worker); assert(__isfdopen(fd)); if (!(w = calloc(1, sizeof(struct NtStdinWorker)))) return 0; @@ -136,7 +128,7 @@ textwindows struct NtStdinWorker *RefNtStdinWorker(struct NtStdinWorker *w) { textwindows bool UnrefNtStdinWorker(struct NtStdinWorker *w) { bool ok = true; if (__atomic_sub_fetch(&w->refs, 1, __ATOMIC_SEQ_CST)) return true; - // w->consumer is freed by close_nt() + if (!CloseHandle(w->consumer)) ok = false; if (!CloseHandle(w->writer)) ok = false; if (!CloseHandle(w->reader)) ok = false; if (!CloseHandle(w->worker)) ok = false; diff --git a/libc/sock/poll-nt.c b/libc/sock/poll-nt.c index c0718242c..828de7a7d 100644 --- a/libc/sock/poll-nt.c +++ b/libc/sock/poll-nt.c @@ -24,11 +24,14 @@ #include "libc/calls/sigbits.h" #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigaction.h" +#include "libc/errno.h" #include "libc/intrin/kprintf.h" #include "libc/intrin/spinlock.h" #include "libc/macros.internal.h" #include "libc/mem/mem.h" +#include "libc/nt/enum/filetype.h" #include "libc/nt/errors.h" +#include "libc/nt/files.h" #include "libc/nt/ipc.h" #include "libc/nt/runtime.h" #include "libc/nt/struct/pollfd.h" @@ -37,13 +40,11 @@ #include "libc/sock/internal.h" #include "libc/sock/ntstdin.internal.h" #include "libc/sock/yoink.inc" +#include "libc/sysv/consts/o.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/sig.h" #include "libc/sysv/errfuns.h" -#undef STRACE // too verbosen -#define STRACE(...) // but don't want to delete - _Alignas(64) static char poll_lock; /** @@ -60,7 +61,7 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) { struct sys_pollfd_nt sockfds[64]; int pipeindices[ARRAYLEN(pipefds)]; int sockindices[ARRAYLEN(sockfds)]; - int i, sn, pn, failed, gotpipes, gotsocks, waitfor; + int i, sn, pn, failed, gotinvals, gotpipes, gotsocks, waitfor; // check for interrupts early before doing work if (_check_interrupts(false, g_fds.p)) return eintr(); @@ -69,49 +70,53 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) { // we need to read static variables // we might need to spawn threads and open pipes _spinlock(&poll_lock); - for (failed = sn = pn = i = 0; i < nfds; ++i) { + _spinlock(&__fds_lock); + for (gotinvals = failed = sn = pn = i = 0; i < nfds; ++i) { if (fds[i].fd < 0) continue; if (__isfdopen(fds[i].fd)) { if (__isfdkind(fds[i].fd, kFdSocket)) { if (sn < ARRAYLEN(sockfds)) { + // the magnums for POLLIN/OUT/PRI on NT include the other ones too + // we need to clear ones like POLLNVAL or else WSAPoll shall whine sockindices[sn] = i; sockfds[sn].handle = g_fds.p[fds[i].fd].handle; sockfds[sn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT); - sn += 1; + sockfds[sn].revents = 0; + ++sn; } else { // too many socket fds failed = enomem(); break; } - } else if (fds[i].events & POLLIN) { - if (!g_fds.p[fds[i].fd].worker) { - if (!(g_fds.p[fds[i].fd].worker = NewNtStdinWorker(fds[i].fd))) { - // failed to launch stdin worker - failed = -1; + } else if (pn < ARRAYLEN(pipefds)) { + pipeindices[pn] = i; + pipefds[pn].handle = g_fds.p[fds[i].fd].handle; + pipefds[pn].events = 0; + pipefds[pn].revents = 0; + switch (g_fds.p[fds[i].fd].flags & O_ACCMODE) { + case O_RDONLY: + pipefds[pn].events = fds[i].events & POLLIN; break; - } - } - if (pn < ARRAYLEN(pipefds)) { - pipeindices[pn] = i; - pipefds[pn].handle = g_fds.p[fds[i].fd].handle; - pipefds[pn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT); - pn += 1; - } else { - // too many non-socket fds - failed = enomem(); - break; + case O_WRONLY: + pipefds[pn].events = fds[i].events & POLLOUT; + break; + case O_RDWR: + pipefds[pn].events = fds[i].events & (POLLIN | POLLOUT); + break; + default: + unreachable; } + ++pn; } else { - // non-sock w/o pollin - failed = enotsock(); + // too many non-socket fds + failed = enomem(); break; } } else { - // non-open file descriptor - failed = einval(); - break; + ++gotinvals; } } + _spunlock(&__fds_lock); _spunlock(&poll_lock); if (failed) { // failed to create a polling solution @@ -122,49 +127,61 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) { for (;;) { // see if input is available on non-sockets for (gotpipes = i = 0; i < pn; ++i) { - ok = PeekNamedPipe(pipefds[i].handle, 0, 0, 0, &avail, 0); - STRACE("PeekNamedPipe(%ld, 0, 0, 0, [%'u], 0) → %hhhd% m", - pipefds[i].handle, avail, ok); - if (ok) { - if (avail) { - pipefds[i].revents = POLLIN; - gotpipes += 1; + if (pipefds[i].events & POLLOUT) { + // we have no way of polling if a non-socket is writeable yet + // therefore we assume that if it can happen, it shall happen + pipefds[i].revents = POLLOUT; + } + if (pipefds[i].events & POLLIN) { + if (GetFileType(pipefds[i].handle) == kNtFileTypePipe) { + ok = PeekNamedPipe(pipefds[i].handle, 0, 0, 0, &avail, 0); + POLLTRACE("PeekNamedPipe(%ld, 0, 0, 0, [%'u], 0) → %hhhd% m", + pipefds[i].handle, avail, ok); + if (ok) { + if (avail) { + pipefds[i].revents = POLLIN; + } + } else { + pipefds[i].revents = POLLERR; + } } else { - pipefds[i].revents = 0; + // we have no way of polling if a non-socket is readable yet + // therefore we assume that if it can happen it shall happen + pipefds[i].revents = POLLIN; } - } else { - pipefds[i].revents = POLLERR; - gotpipes += 1; + } + if (pipefds[i].revents) { + ++gotpipes; } } // if we haven't found any good results yet then here we // compute a small time slice we don't mind sleeping for - waitfor = gotpipes ? 0 : MIN(__SIG_POLLING_INTERVAL_MS, *ms); + waitfor = gotinvals || gotpipes ? 0 : MIN(__SIG_POLLING_INTERVAL_MS, *ms); if (sn) { // we need to poll the socket handles separately because // microsoft certainly loves to challenge us with coding // please note that winsock will fail if we pass zero fd - STRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms); + POLLTRACE("WSAPoll(%p, %u, %'d) out of %'lu", sockfds, sn, waitfor, *ms); if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) { return __winsockerr(); } *ms -= waitfor; } else { gotsocks = 0; - if (!gotpipes && waitfor) { + if (!gotinvals && !gotpipes && waitfor) { // if we've only got pipes and none of them are ready // then we'll just explicitly sleep for the time left - STRACE("SleepEx(%'d, false) out of %'lu", waitfor, *ms); - if (SleepEx(waitfor, true) == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - return eintr(); + POLLTRACE("SleepEx(%'d, false) out of %'lu", waitfor, *ms); + if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) { + POLLTRACE("IOCP EINTR"); + } else { + *ms -= waitfor; } - *ms -= waitfor; } } // we gave all the sockets and all the named pipes a shot // if we found anything at all then it's time to end work - if (gotpipes || gotsocks || *ms <= 0) { + if (gotinvals || gotpipes || gotsocks || *ms <= 0) { break; } // otherwise loop limitlessly for timeout to elapse while @@ -174,33 +191,22 @@ textwindows int sys_poll_nt(struct pollfd *fds, uint64_t nfds, uint64_t *ms) { } } - // we got some - // assemble the result - for (i = 0; i < pn; ++i) { - fds[pipeindices[i]].revents = - pipefds[i].handle < 0 ? 0 : pipefds[i].revents; - } - for (i = 0; i < sn; ++i) { - fds[sockindices[i]].revents = - sockfds[i].handle < 0 ? 0 : sockfds[i].revents; - } - return gotpipes + gotsocks; -} - -static textexit void __freefds_workers(void) { - int i; - STRACE("__freefds_workers()"); - for (i = g_fds.n; i--;) { - if (g_fds.p[i].kind && g_fds.p[i].worker) { - close(i); + // the system call is going to succeed + // it's now ok to start setting the output memory + for (i = 0; i < nfds; ++i) { + if (fds[i].fd < 0 || __isfdopen(fds[i].fd)) { + fds[i].revents = 0; + } else { + fds[i].revents = POLLNVAL; } } -} + for (i = 0; i < pn; ++i) { + fds[pipeindices[i]].revents = pipefds[i].revents; + } + for (i = 0; i < sn; ++i) { + fds[sockindices[i]].revents = sockfds[i].revents; + } -static textstartup void __freefds_workers_init(void) { - atexit(__freefds_workers); + // and finally return + return gotinvals + gotpipes + gotsocks; } - -const void *const __freefds_workers_ctor[] initarray = { - __freefds_workers_init, -}; diff --git a/libc/sock/poll.c b/libc/sock/poll.c index d2eed6ecd..0c81a093f 100644 --- a/libc/sock/poll.c +++ b/libc/sock/poll.c @@ -28,13 +28,35 @@ /** * Waits for something to happen on multiple file descriptors at once. * + * Warning: XNU has an inconsistency with other platforms. If you have + * pollfds with fd≥0 and none of the meaningful events flags are added + * e.g. POLLIN then XNU won't check for POLLNVAL. This matters because + * one of the use-cases for poll() is quickly checking for open files. + * + * Note: Polling works best on Windows for sockets. We're able to poll + * input on named pipes. But for anything that isn't a socket, or pipe + * with POLLIN, (e.g. regular file) then POLLIN/POLLOUT are always set + * into revents if they're requested, provided they were opened with a + * mode that permits reading and/or writing. + * + * Note: Windows has a limit of 64 file descriptors and ENOMEM with -1 + * is returned if that limit is exceeded. In practice the limit is not + * this low. For example, pollfds with fd<0 don't count. So the caller + * could flip the sign bit with a short timeout, to poll a larger set. + * * @param fds[𝑖].fd should be a socket, input pipe, or conosle input - * @param fds[𝑖].events flags can have POLLIN, POLLOUT, and POLLPRI + * and if it's a negative number then the entry is ignored + * @param fds[𝑖].events flags can have POLLIN, POLLOUT, POLLPRI, + * POLLRDNORM, POLLWRNORM, POLLRDBAND, POLLWRBAND as well as + * POLLERR, POLLHUP, and POLLNVAL although the latter are + * always implied (assuming fd≥0) so they're ignored here * @param timeout_ms if 0 means don't wait and -1 means wait forever * @return number of items fds whose revents field has been set to - * nonzero to describe its events, or -1 w/ errno - * @return fds[𝑖].revents flags can have: - * (fds[𝑖].events & POLL{IN,OUT,PRI,HUP,ERR,NVAL}) + * nonzero to describe its events, or 0 if the timeout elapsed, + * or -1 w/ errno + * @return fds[𝑖].revents is always zero initializaed and then will + * be populated with POLL{IN,OUT,PRI,HUP,ERR,NVAL} if something + * was determined about the file descriptor * @asyncsignalsafe * @threadsafe * @norestart diff --git a/libc/runtime/printargs.c b/libc/sock/printargs.greg.c similarity index 58% rename from libc/runtime/printargs.c rename to libc/sock/printargs.greg.c index 5503211ee..47e8a736a 100644 --- a/libc/runtime/printargs.c +++ b/libc/sock/printargs.greg.c @@ -20,15 +20,22 @@ #include "libc/calls/strace.internal.h" #include "libc/calls/struct/sigset.h" #include "libc/dce.h" +#include "libc/dns/dns.h" #include "libc/intrin/describeflags.internal.h" #include "libc/intrin/kprintf.h" #include "libc/macros.internal.h" +#include "libc/nexgen32e/cpuid4.internal.h" +#include "libc/nexgen32e/kcpuids.h" +#include "libc/nexgen32e/x86feature.h" +#include "libc/nexgen32e/x86info.h" #include "libc/nt/enum/startf.h" #include "libc/nt/runtime.h" #include "libc/nt/startupinfo.h" #include "libc/nt/struct/ldrdatatableentry.h" #include "libc/nt/struct/startupinfo.h" #include "libc/nt/struct/teb.h" +#include "libc/runtime/internal.h" +#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" #include "libc/sock/internal.h" @@ -37,8 +44,16 @@ #include "libc/sysv/consts/f.h" #include "libc/sysv/consts/poll.h" #include "libc/sysv/consts/sig.h" +#include "tool/decode/lib/idname.h" +#include "tool/decode/lib/x86idnames.h" -#define PRINT(FMT, ...) kprintf(STRACE_PROLOGUE FMT "%n", ##__VA_ARGS__) +STATIC_YOINK("strsignal"); // for kprintf() + +#define PRINT(FMT, ...) \ + do { \ + kprintf(prologue); \ + kprintf(FMT "%n", ##__VA_ARGS__); \ + } while (0) static const struct AuxiliaryValue { const char *fmt; @@ -82,6 +97,15 @@ static const struct AuxiliaryValue { {"%-14p", &AT_EHDRFLAGS, "AT_EHDRFLAGS"}, }; +static const char *FindNameById(const struct IdName *names, unsigned long id) { + for (; names->name; names++) { + if (names->id == id) { + return names->name; + } + } + return NULL; +} + static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) { int i; for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) { @@ -92,46 +116,202 @@ static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) { return NULL; } -noasan textstartup void __printargs(void) { -#ifdef SYSDEBUG - int st; +/** + * Prints lots of information about this process, e.g. + * + * __printargs(""); + * + * This is called automatically in MODE=dbg if `--strace` is used. + * + * @param prologue needs to be a .rodata kprintf string + */ +textstartup void __printargs(const char *prologue) { long key; char **env; - unsigned i; sigset_t ss; + unsigned i, n; uintptr_t *auxp; + struct utsname uts; char path[PATH_MAX]; + int x, st, ft, flags; struct pollfd pfds[128]; struct AuxiliaryValue *auxinfo; - if (__strace <= 0) return; - st = __strace; - __strace = 0; + st = __strace, __strace = 0; + ft = g_ftrace, g_ftrace = 0; + + PRINT(""); + PRINT("SYSTEM"); + if (!uname(&uts)) { + kprintf(prologue); + kprintf(" %s", uts.nodename); + if (*uts.sysname) { + kprintf(" on %s", uts.sysname); + if (*uts.release) { + kprintf(" %s", uts.release); + } + } + kprintf("%n"); + } else { + PRINT(" uname() failed %m"); + } + + PRINT(""); + PRINT("MICROPROCESSOR"); + kprintf(prologue); + kprintf(" %.*s%.*s%.*s", 4, &KCPUIDS(0H, EBX), 4, &KCPUIDS(0H, EDX), 4, + &KCPUIDS(0H, ECX)); + if (getx86processormodel(kX86ProcessorModelKey)) { + kprintf(" %s", + FindNameById(kX86MarchNames, + getx86processormodel(kX86ProcessorModelKey)->march)); + } + if (getx86processormodel(kX86ProcessorModelKey)) { + kprintf(" (%s Grade)", + FindNameById(kX86GradeNames, + getx86processormodel(kX86ProcessorModelKey)->grade)); + } + kprintf("%n"); + if ((x = KCPUIDS(16H, EAX) & 0x7fff)) { + kprintf(prologue); + kprintf(" %dmhz %s", x, "freq"); + if ((x = KCPUIDS(16H, EBX) & 0x7fff)) { + kprintf(" / %dmhz %s", x, "turbo"); + } + if ((x = KCPUIDS(16H, ECX) & 0x7fff)) { + kprintf(" / %dmhz %s", x, "bus"); + } + kprintf("%n"); + } + if (X86_HAVE(HYPERVISOR)) { + unsigned eax, ebx, ecx, edx; + asm("push\t%%rbx\n\t" + "cpuid\n\t" + "mov\t%%ebx,%1\n\t" + "pop\t%%rbx" + : "=a"(eax), "=rm"(ebx), "=c"(ecx), "=d"(edx) + : "0"(0x40000000), "2"(0)); + PRINT(" Running inside %.4s%.4s%.4s (eax=%#x)", &ebx, &ecx, &edx, eax); + } + CPUID4_ITERATE(i, { + PRINT(" L%d%s%s %u-way %,u byte cache w/%s " + "%,u sets of %,u byte lines shared across %u threads%s", + CPUID4_CACHE_LEVEL, + CPUID4_CACHE_TYPE == 1 ? " data" + : CPUID4_CACHE_TYPE == 2 ? " code" + : "", + CPUID4_IS_FULLY_ASSOCIATIVE ? " fully-associative" : "", + CPUID4_WAYS_OF_ASSOCIATIVITY, CPUID4_CACHE_SIZE_IN_BYTES, + CPUID4_PHYSICAL_LINE_PARTITIONS > 1 ? " physically partitioned" : "", + CPUID4_NUMBER_OF_SETS, CPUID4_SYSTEM_COHERENCY_LINE_SIZE, + CPUID4_MAX_THREADS_SHARING_CACHE, + CPUID4_COMPLEX_INDEXING ? " complexly-indexed" : ""); + }); + kprintf(prologue); + kprintf(" "); + if (X86_HAVE(SSE3)) kprintf(" SSE3"); + if (X86_HAVE(SSSE3)) kprintf(" SSSE3"); + if (X86_HAVE(SSE4_2)) kprintf(" SSE4_2"); + if (X86_HAVE(POPCNT)) kprintf(" POPCNT"); + if (X86_HAVE(AVX)) kprintf(" AVX"); + if (X86_HAVE(AVX2)) kprintf(" AVX2"); + if (X86_HAVE(FMA)) kprintf(" FMA"); + if (X86_HAVE(BMI)) kprintf(" BMI"); + if (X86_HAVE(BMI2)) kprintf(" BMI2"); + if (X86_HAVE(ADX)) kprintf(" ADX"); + if (X86_HAVE(F16C)) kprintf(" F16C"); + if (X86_HAVE(SHA)) kprintf(" SHA"); + if (X86_HAVE(AES)) kprintf(" AES"); + if (X86_HAVE(RDRND)) kprintf(" RDRND"); + if (X86_HAVE(RDSEED)) kprintf(" RDSEED"); + if (X86_HAVE(RDTSCP)) kprintf(" RDTSCP"); + if (X86_HAVE(RDPID)) kprintf(" RDPID"); + if (X86_HAVE(LA57)) kprintf(" LA57"); + if (X86_HAVE(FSGSBASE)) kprintf(" FSGSBASE"); + kprintf("%n"); + + PRINT(""); + PRINT("FILE DESCRIPTORS"); + for (i = 0; i < ARRAYLEN(pfds); ++i) { + pfds[i].fd = i; + pfds[i].events = POLLIN | POLLOUT; + } + if ((n = poll(pfds, ARRAYLEN(pfds), 20)) != -1) { + for (i = 0; i < ARRAYLEN(pfds); ++i) { + if (i && (pfds[i].revents & POLLNVAL)) continue; + PRINT(" ☼ %d (revents=%#hx F_GETFL=%#x)", i, pfds[i].revents, + fcntl(i, F_GETFL)); + } + } else { + PRINT(" poll() returned %d %m", n); + } + + if (!sigprocmask(SIG_BLOCK, 0, &ss)) { + PRINT(""); + PRINT("SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]); + if (ss.__bits[0] || ss.__bits[1]) { + for (i = 0; i < 32; ++i) { + if (ss.__bits[0] & (1u << i)) { + PRINT(" ☼ %G (%d) is masked", i + 1, i + 1); + } + } + } else { + PRINT(" no signals blocked"); + } + } else { + PRINT(""); + PRINT("SIGNALS"); + PRINT(" error: sigprocmask() failed %m"); + } PRINT(""); PRINT("ARGUMENTS (%p)", __argv); - for (i = 0; i < __argc; ++i) { - PRINT(" ☼ %s", __argv[i]); + if (*__argv) { + for (i = 0; i < __argc; ++i) { + PRINT(" ☼ %s", __argv[i]); + } + } else { + PRINT(" none"); } PRINT(""); PRINT("ENVIRONMENT (%p)", __envp); - for (env = __envp; *env; ++env) { - PRINT(" ☼ %s", *env); + if (*__envp) { + for (env = __envp; *env; ++env) { + PRINT(" ☼ %s", *env); + } + } else { + PRINT(" none"); } PRINT(""); PRINT("AUXILIARY (%p)", __auxv); - for (auxp = __auxv; *auxp; auxp += 2) { - if ((auxinfo = DescribeAuxv(auxp[0]))) { - ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]); - PRINT(" ☼ %16s[%4ld] = %s", auxinfo->name, auxp[0], path); - } else { - PRINT(" ☼ %16s[%4ld] = %014p", "unknown", auxp[0], auxp[1]); + if (*__auxv) { + if (*__auxv) { + for (auxp = __auxv; *auxp; auxp += 2) { + if ((auxinfo = DescribeAuxv(auxp[0]))) { + ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]); + PRINT(" ☼ %16s[%4ld] = %s", auxinfo->name, auxp[0], path); + } else { + PRINT(" ☼ %16s[%4ld] = %014p", "unknown", auxp[0], auxp[1]); + } + } } + } else { + PRINT(" none"); } PRINT(""); PRINT("SPECIALS"); + umask((i = umask(022))); + PRINT(" ☼ %s = %#o", "umask()", i); + PRINT(" ☼ %s = %d", "getpid()", getpid()); + PRINT(" ☼ %s = %d", "getppid()", getppid()); + PRINT(" ☼ %s = %d", "getpgrp()", getpgrp()); + PRINT(" ☼ %s = %d", "getsid()", getsid(0)); + PRINT(" ☼ %s = %d", "getuid()", getuid()); + PRINT(" ☼ %s = %d", "geteuid()", geteuid()); + PRINT(" ☼ %s = %d", "getgid()", getgid()); + PRINT(" ☼ %s = %d", "getegid()", getegid()); PRINT(" ☼ %s = %#s", "kTmpPath", kTmpPath); PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory); PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory); @@ -143,31 +323,9 @@ noasan textstartup void __printargs(void) { PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0)); PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize()); - if (!IsWindows()) { - PRINT(""); - PRINT("OPEN FILE DESCRIPTORS"); - for (i = 0; i < ARRAYLEN(pfds); ++i) { - pfds[i].fd = i; - pfds[i].events = 0; - } - if (sys_poll(pfds, ARRAYLEN(pfds), 0) != -1) { - for (i = 0; i < ARRAYLEN(pfds); ++i) { - if (~pfds[i].revents & POLLNVAL) { - PRINT(" ☼ %d (F_GETFL=%#x)", i, fcntl(i, F_GETFL)); - } - } - } - } - - if (!sigprocmask(SIG_BLOCK, 0, &ss) && (ss.__bits[0] || ss.__bits[1])) { - PRINT(""); - PRINT("BLOCKED SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]); - for (i = 0; i < 32; ++i) { - if (ss.__bits[0] & (1u << i)) { - PRINT(" ☼ %G (%d)", i + 1, i + 1); - } - } - } + PRINT(""); + PRINT("MEMTRACK"); + PrintMemoryIntervals(2, &_mmi); if (IsWindows()) { struct NtStartupInfo startinfo; @@ -234,12 +392,12 @@ noasan textstartup void __printargs(void) { do { const struct NtLdrDataTableEntry *dll = (const struct NtLdrDataTableEntry *)ldr; - PRINT(" ☼ %.*!hs\t\t%'zu bytes", dll->FullDllName.Length, - dll->FullDllName.Data, dll->SizeOfImage); + PRINT(" ☼ %.*!hs (%'zukb)", dll->FullDllName.Length, + dll->FullDllName.Data, dll->SizeOfImage / 1024); } while ((ldr = ldr->Next) && ldr != head); } PRINT(""); __strace = st; -#endif + g_ftrace = ft; } diff --git a/libc/sock/recv-nt.c b/libc/sock/recv-nt.c index 651075102..5c2e0bc99 100644 --- a/libc/sock/recv-nt.c +++ b/libc/sock/recv-nt.c @@ -16,19 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/bits/weaken.h" #include "libc/calls/internal.h" -#include "libc/calls/sig.internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/intrin/kprintf.h" -#include "libc/log/backtrace.internal.h" -#include "libc/nt/enum/wait.h" -#include "libc/nt/errors.h" +#include "libc/calls/struct/iovec.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" -#include "libc/sock/yoink.inc" #include "libc/sysv/errfuns.h" /** @@ -40,51 +32,16 @@ textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov, size_t iovlen, uint32_t flags) { ssize_t rc; - uint32_t i, got = 0; + uint32_t got = 0; struct NtIovec iovnt[16]; struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()}; - if (_check_interrupts(true, g_fds.p)) return eintr(); - if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags, &overlapped, NULL)) { rc = got; - goto Finished; + } else { + rc = __wsablock(fd->handle, &overlapped, &flags, true); } - - if (WSAGetLastError() != kNtErrorIoPending) { - STRACE("WSARecv failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - for (;;) { - i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true, - __SIG_POLLING_INTERVAL_MS, true); - if (i == kNtWaitFailed) { - STRACE("WSAWaitForMultipleEvents failed %lm"); - rc = __winsockerr(); - goto Finished; - } else if (i == kNtWaitTimeout) { - if (_check_interrupts(true, g_fds.p)) { - rc = eintr(); - goto Finished; - } - } else if (i == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - } else { - break; - } - } - - if (!WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) { - STRACE("WSAGetOverlappedResult failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - rc = got; -Finished: WSACloseEvent(overlapped.hEvent); return rc; } diff --git a/libc/sock/recvfrom-nt.c b/libc/sock/recvfrom-nt.c index 5edc144a5..6ce60ca11 100644 --- a/libc/sock/recvfrom-nt.c +++ b/libc/sock/recvfrom-nt.c @@ -16,10 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/sig.internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/nt/enum/wait.h" -#include "libc/nt/errors.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" @@ -36,52 +34,17 @@ textwindows ssize_t sys_recvfrom_nt(struct Fd *fd, const struct iovec *iov, void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) { ssize_t rc; - uint32_t i, got = 0; + uint32_t got = 0; struct NtIovec iovnt[16]; struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()}; - if (_check_interrupts(true, g_fds.p)) return eintr(); - if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped, NULL)) { rc = got; - goto Finished; + } else { + rc = __wsablock(fd->handle, &overlapped, &flags, true); } - - if (WSAGetLastError() != kNtErrorIoPending) { - STRACE("WSARecvFrom failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - for (;;) { - i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true, - __SIG_POLLING_INTERVAL_MS, true); - if (i == kNtWaitFailed) { - STRACE("WSAWaitForMultipleEvents failed %lm"); - rc = __winsockerr(); - goto Finished; - } else if (i == kNtWaitTimeout) { - if (_check_interrupts(true, g_fds.p)) { - rc = eintr(); - goto Finished; - } - } else if (i == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - } else { - break; - } - } - - if (!WSAGetOverlappedResult(fd->handle, &overlapped, &got, false, &flags)) { - STRACE("WSAGetOverlappedResult failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - rc = got; -Finished: WSACloseEvent(overlapped.hEvent); return rc; } diff --git a/libc/sock/select.c b/libc/sock/select.c index 9e4f147d0..e322a2db7 100644 --- a/libc/sock/select.c +++ b/libc/sock/select.c @@ -22,8 +22,11 @@ #include "libc/sock/select.h" /** - * Does what poll() does except with a complicated bitset API. - * @note windows nt is limited to first 64 socket descriptors + * Does what poll() does except with bitset API. + * + * This system call is supported on all platforms. However, on Windows, + * this is polyfilled to translate into poll(). So it's recommended that + * poll() be used instead. */ int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) { diff --git a/libc/sock/send-nt.c b/libc/sock/send-nt.c index 52b7e81d2..69af0c438 100644 --- a/libc/sock/send-nt.c +++ b/libc/sock/send-nt.c @@ -16,17 +16,11 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/assert.h" -#include "libc/calls/calls.h" #include "libc/calls/internal.h" -#include "libc/calls/sig.internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/nt/enum/wait.h" -#include "libc/nt/errors.h" +#include "libc/calls/struct/iovec.h" +#include "libc/nt/struct/overlapped.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" -#include "libc/sock/yoink.inc" -#include "libc/sysv/consts/fileno.h" #include "libc/sysv/errfuns.h" /** @@ -38,52 +32,16 @@ textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen, uint32_t flags) { ssize_t rc; - uint32_t i, sent = 0; + uint32_t sent = 0; struct NtIovec iovnt[16]; struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()}; - if (_check_interrupts(true, g_fds.p)) return eintr(); - if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent, flags, &overlapped, NULL)) { rc = sent; - goto Finished; + } else { + rc = __wsablock(g_fds.p[fd].handle, &overlapped, &flags, true); } - - if (WSAGetLastError() != kNtErrorIoPending) { - STRACE("WSASend failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - for (;;) { - i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true, - __SIG_POLLING_INTERVAL_MS, true); - if (i == kNtWaitFailed) { - STRACE("WSAWaitForMultipleEvents failed %lm"); - rc = __winsockerr(); - goto Finished; - } else if (i == kNtWaitTimeout) { - if (_check_interrupts(true, g_fds.p)) { - rc = eintr(); - goto Finished; - } - } else if (i == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - } else { - break; - } - } - - if (!WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &sent, false, - &flags)) { - STRACE("WSAGetOverlappedResult failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - rc = sent; -Finished: WSACloseEvent(overlapped.hEvent); return rc; } diff --git a/libc/sock/sendto-nt.c b/libc/sock/sendto-nt.c index 5bdd3b19d..43c716979 100644 --- a/libc/sock/sendto-nt.c +++ b/libc/sock/sendto-nt.c @@ -16,10 +16,8 @@ │ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ │ PERFORMANCE OF THIS SOFTWARE. │ ╚─────────────────────────────────────────────────────────────────────────────*/ -#include "libc/calls/sig.internal.h" -#include "libc/calls/strace.internal.h" -#include "libc/nt/enum/wait.h" -#include "libc/nt/errors.h" +#include "libc/calls/internal.h" +#include "libc/calls/struct/iovec.h" #include "libc/nt/struct/overlapped.h" #include "libc/nt/winsock.h" #include "libc/sock/internal.h" @@ -35,52 +33,16 @@ textwindows ssize_t sys_sendto_nt(int fd, const struct iovec *iov, size_t iovlen, uint32_t flags, void *opt_in_addr, uint32_t in_addrsize) { ssize_t rc; - uint32_t i, sent = 0; + uint32_t sent = 0; struct NtIovec iovnt[16]; struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()}; - if (_check_interrupts(true, g_fds.p)) return eintr(); - if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) { rc = sent; - goto Finished; + } else { + rc = __wsablock(g_fds.p[fd].handle, &overlapped, &flags, true); } - - if (WSAGetLastError() != kNtErrorIoPending) { - STRACE("WSASendTo failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - for (;;) { - i = WSAWaitForMultipleEvents(1, &overlapped.hEvent, true, - __SIG_POLLING_INTERVAL_MS, true); - if (i == kNtWaitFailed) { - STRACE("WSAWaitForMultipleEvents failed %lm"); - rc = __winsockerr(); - goto Finished; - } else if (i == kNtWaitTimeout) { - if (_check_interrupts(true, g_fds.p)) { - rc = eintr(); - goto Finished; - } - } else if (i == kNtWaitIoCompletion) { - STRACE("IOCP TRIGGERED EINTR"); - } else { - break; - } - } - - if (!WSAGetOverlappedResult(g_fds.p[fd].handle, &overlapped, &sent, false, - &flags)) { - STRACE("WSAGetOverlappedResult failed %lm"); - rc = __winsockerr(); - goto Finished; - } - - rc = sent; -Finished: WSACloseEvent(overlapped.hEvent); return rc; } diff --git a/libc/sock/stdinworker.c b/libc/sock/stdinworker.c new file mode 100644 index 000000000..0dc32fe94 --- /dev/null +++ b/libc/sock/stdinworker.c @@ -0,0 +1,44 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ 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. │ +│ │ +│ 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/internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/runtime/runtime.h" +#include "libc/sock/ntstdin.internal.h" +#include "libc/sock/sock.h" + +/* STATIC_YOINK("StdinWorker"); */ + +static textexit void StdinWorkerFree(void) { + int i; + NTTRACE("StdinWorkerFree()"); + for (i = g_fds.n; i--;) { + if (g_fds.p[i].kind && g_fds.p[i].worker) { + close(i); + } + } +} + +static textstartup void StdinWorkerInit(void) { + g_fds.p[0].worker = NewNtStdinWorker(0); + atexit(StdinWorkerFree); +} + +const void *const StdinWorker[] initarray = { + StdinWorkerInit, +}; diff --git a/libc/sock/wsablock.c b/libc/sock/wsablock.c new file mode 100644 index 000000000..53252e083 --- /dev/null +++ b/libc/sock/wsablock.c @@ -0,0 +1,52 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ 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. │ +│ │ +│ 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/sig.internal.h" +#include "libc/calls/strace.internal.h" +#include "libc/nt/enum/wait.h" +#include "libc/nt/errors.h" +#include "libc/sock/internal.h" +#include "libc/sock/sock.h" +#include "libc/sysv/errfuns.h" + +textwindows int __wsablock(int64_t handle, struct NtOverlapped *overlapped, + uint32_t *flags, bool restartable) { + uint32_t i, got; + if (WSAGetLastError() != kNtErrorIoPending) { + NTTRACE("WSARecv failed %lm"); + return __winsockerr(); + } + for (;;) { + i = WSAWaitForMultipleEvents(1, &overlapped->hEvent, true, + __SIG_POLLING_INTERVAL_MS, true); + if (i == kNtWaitFailed) { + NTTRACE("WSAWaitForMultipleEvents failed %lm"); + return __winsockerr(); + } else if (i == kNtWaitTimeout || i == kNtWaitIoCompletion) { + if (_check_interrupts(restartable, g_fds.p)) return eintr(); + POLLTRACE("WSAWaitForMultipleEvents..."); + } else { + break; + } + } + if (!WSAGetOverlappedResult(handle, overlapped, &got, false, flags)) { + NTTRACE("WSAGetOverlappedResult failed %lm"); + return __winsockerr(); + } + return got; +} diff --git a/libc/sysv/calls/getegid.s b/libc/sysv/calls/getegid.s deleted file mode 100644 index c8a7ff412..000000000 --- a/libc/sysv/calls/getegid.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall getegid,0xfff02b02b202b06c,globl diff --git a/libc/sysv/calls/getpgrp.s b/libc/sysv/calls/getpgrp.s deleted file mode 100644 index 10a08f07a..000000000 --- a/libc/sysv/calls/getpgrp.s +++ /dev/null @@ -1,2 +0,0 @@ -.include "o/libc/sysv/macros.internal.inc" -.scall getpgrp,0x051051051205106f,globl diff --git a/libc/sysv/calls/sys_getegid.s b/libc/sysv/calls/sys_getegid.s new file mode 100644 index 000000000..8e5dba159 --- /dev/null +++ b/libc/sysv/calls/sys_getegid.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_getegid,0x02b02b02b202b06c,globl,hidden diff --git a/libc/sysv/calls/sys_geteuid.s b/libc/sysv/calls/sys_geteuid.s index ed2898bac..9426150e3 100644 --- a/libc/sysv/calls/sys_geteuid.s +++ b/libc/sysv/calls/sys_geteuid.s @@ -1,2 +1,2 @@ .include "o/libc/sysv/macros.internal.inc" -.scall sys_geteuid,0xfff019019201906b,globl,hidden +.scall sys_geteuid,0x019019019201906b,globl,hidden diff --git a/libc/sysv/calls/sys_getpgrp.s b/libc/sysv/calls/sys_getpgrp.s new file mode 100644 index 000000000..f89e2cc7b --- /dev/null +++ b/libc/sysv/calls/sys_getpgrp.s @@ -0,0 +1,2 @@ +.include "o/libc/sysv/macros.internal.inc" +.scall sys_getpgrp,0x051051051205106f,globl,hidden diff --git a/libc/sysv/consts.sh b/libc/sysv/consts.sh index dfe9822fd..2cdaa1fc3 100755 --- a/libc/sysv/consts.sh +++ b/libc/sysv/consts.sh @@ -901,6 +901,7 @@ syscon ptrace PTRACE_O_TRACECLONE 0x0008 -1 -1 -1 -1 -1 syscon ptrace PTRACE_O_TRACEEXEC 0x0010 -1 -1 -1 -1 -1 syscon ptrace PTRACE_O_TRACEVFORKDONE 0x0020 -1 -1 -1 -1 -1 syscon ptrace PTRACE_O_TRACEEXIT 0x0040 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_O_TRACESECCOMP 0x0080 -1 -1 -1 -1 -1 syscon ptrace PTRACE_O_MASK 0x007f -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_FORK 1 -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_VFORK 2 -1 -1 -1 -1 -1 @@ -908,6 +909,8 @@ syscon ptrace PTRACE_EVENT_CLONE 3 -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_EXEC 4 -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_VFORK_DONE 5 -1 -1 -1 -1 -1 syscon ptrace PTRACE_EVENT_EXIT 6 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_SECCOMP 7 -1 -1 -1 -1 -1 +syscon ptrace PTRACE_EVENT_STOP 128 -1 -1 -1 -1 -1 # clone() codes # @@ -1807,9 +1810,9 @@ syscon misc NL_NMAX 0x7fffffff 1 1 0 0 0 syscon misc NL_SETD 1 1 0 1 1 0 syscon rusage RUSAGE_SELF 0 0 0 0 0 0 # unix consensus & faked nt +syscon rusage RUSAGE_THREAD 1 99 1 1 1 1 # faked nt & unavailable on xnu syscon rusage RUSAGE_CHILDREN -1 -1 -1 -1 -1 99 # unix consensus & unavailable on nt syscon rusage RUSAGE_BOTH -2 99 99 99 99 99 # woop -syscon rusage RUSAGE_THREAD 1 99 1 1 1 1 # faked nt & unavailable on xnu syscon misc FSETLOCKING_QUERY 0 0 0 0 0 0 # consensus syscon misc FSETLOCKING_BYCALLER 2 0 0 0 0 0 diff --git a/libc/sysv/consts/PTRACE_EVENT_SECCOMP.S b/libc/sysv/consts/PTRACE_EVENT_SECCOMP.S new file mode 100644 index 000000000..81f486a31 --- /dev/null +++ b/libc/sysv/consts/PTRACE_EVENT_SECCOMP.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon ptrace,PTRACE_EVENT_SECCOMP,7,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/PTRACE_EVENT_STOP.S b/libc/sysv/consts/PTRACE_EVENT_STOP.S new file mode 100644 index 000000000..8aaf95499 --- /dev/null +++ b/libc/sysv/consts/PTRACE_EVENT_STOP.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon ptrace,PTRACE_EVENT_STOP,128,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/PTRACE_O_TRACESECCOMP.S b/libc/sysv/consts/PTRACE_O_TRACESECCOMP.S new file mode 100644 index 000000000..85d279b86 --- /dev/null +++ b/libc/sysv/consts/PTRACE_O_TRACESECCOMP.S @@ -0,0 +1,2 @@ +#include "libc/sysv/consts/syscon.internal.h" +.syscon ptrace,PTRACE_O_TRACESECCOMP,0x0080,-1,-1,-1,-1,-1 diff --git a/libc/sysv/consts/ptrace.h b/libc/sysv/consts/ptrace.h index 7f6fdd337..444bcb21b 100644 --- a/libc/sysv/consts/ptrace.h +++ b/libc/sysv/consts/ptrace.h @@ -43,6 +43,7 @@ extern const long PTRACE_O_TRACECLONE; extern const long PTRACE_O_TRACEEXEC; extern const long PTRACE_O_TRACEVFORKDONE; extern const long PTRACE_O_TRACEEXIT; +extern const long PTRACE_O_TRACESECCOMP; extern const long PTRACE_O_MASK; extern const long PTRACE_EVENT_FORK; extern const long PTRACE_EVENT_VFORK; @@ -50,6 +51,8 @@ extern const long PTRACE_EVENT_CLONE; extern const long PTRACE_EVENT_EXEC; extern const long PTRACE_EVENT_VFORK_DONE; extern const long PTRACE_EVENT_EXIT; +extern const long PTRACE_EVENT_STOP; +extern const long PTRACE_EVENT_SECCOMP; COSMOPOLITAN_C_END_ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ @@ -93,6 +96,7 @@ COSMOPOLITAN_C_END_ #define PTRACE_O_TRACEEXEC SYMBOLIC(PTRACE_O_TRACEEXEC) #define PTRACE_O_TRACEVFORKDONE SYMBOLIC(PTRACE_O_TRACEVFORKDONE) #define PTRACE_O_TRACEEXIT SYMBOLIC(PTRACE_O_TRACEEXIT) +#define PTRACE_O_TRACESECCOMP SYMBOLIC(PTRACE_O_TRACESECCOMP) #define PTRACE_O_MASK SYMBOLIC(PTRACE_O_MASK) #define PTRACE_EVENT_FORK SYMBOLIC(PTRACE_EVENT_FORK) #define PTRACE_EVENT_VFORK SYMBOLIC(PTRACE_EVENT_VFORK) @@ -100,5 +104,7 @@ COSMOPOLITAN_C_END_ #define PTRACE_EVENT_EXEC SYMBOLIC(PTRACE_EVENT_EXEC) #define PTRACE_EVENT_VFORK_DONE SYMBOLIC(PTRACE_EVENT_VFORK_DONE) #define PTRACE_EVENT_EXIT SYMBOLIC(PTRACE_EVENT_EXIT) +#define PTRACE_EVENT_STOP SYMBOLIC(PTRACE_EVENT_STOP) +#define PTRACE_EVENT_SECCOMP SYMBOLIC(PTRACE_EVENT_SECCOMP) #endif /* COSMOPOLITAN_LIBC_SYSV_CONSTS_PTRACE_H_ */ diff --git a/libc/sysv/syscalls.sh b/libc/sysv/syscalls.sh index c0a2b0f20..3af4e8599 100755 --- a/libc/sysv/syscalls.sh +++ b/libc/sysv/syscalls.sh @@ -145,13 +145,13 @@ scall syslog 0xfffffffffffff067 globl scall sys_getuid 0x0180180182018066 globl hidden scall sys_getgid 0x02f02f02f202f068 globl hidden scall sys_getppid 0xfff027027202706e globl hidden # see sys_getpid()→edx for netbsd -scall getpgrp 0x051051051205106f globl +scall sys_getpgrp 0x051051051205106f globl hidden scall sys_setsid 0x0930930932093070 globl hidden scall sys_getsid 0x11e0ff136213607c globl hidden scall sys_getpgid 0x0cf0cf0cf2097079 globl hidden scall sys_setpgid 0x052052052205206d globl hidden -scall sys_geteuid 0xfff019019201906b globl hidden -scall getegid 0xfff02b02b202b06c globl +scall sys_geteuid 0x019019019201906b globl hidden +scall sys_getegid 0x02b02b02b202b06c globl hidden scall getgroups 0x04f04f04f204f073 globl scall setgroups 0x0500500502050074 globl scall setreuid 0x07e07e07e207e071 globl diff --git a/libc/sysv/systemfive.S b/libc/sysv/systemfive.S index 226071843..9540717f0 100644 --- a/libc/sysv/systemfive.S +++ b/libc/sysv/systemfive.S @@ -198,27 +198,36 @@ systemfive_xnu: .init.start 300,_init_systemfive push %rbx push %rsi - mov (%rdi),%eax +// Detect the operating system. + mov (%rdi),%eax # __hostos +#if SupportsWindows() || SupportsXnu() || SupportsFreebsd() +// set by libc/ape.S for XNU +// set by libc/crt/crt.S for XNU/FreeBSD +// set by libc/nt/winmain.greg.c for New Technology + test %eax,%eax + jnz _init_systemfive_detected # os is already known +#endif #if SupportsOpenbsd() cmpq $0,(%r15) # OpenBSD has no auxv jnz 0f mov $OPENBSD,%al + jmp _init_systemfive_detected 0: #endif #if SupportsNetbsd() xor %ecx,%ecx -0: cmpq $2014,(%r15,%rcx,8) # NetBSD AT_EXECFN +0: cmpq $2014,(%r15,%rcx,8) # NetBSD's AT_EXECFN jne 1f mov $NETBSD,%al + jmp _init_systemfive_detected 1: cmpq $0,(%r15,%rcx,8) lea 2(%ecx),%ecx jnz 0b 2: #endif - test %eax,%eax - jnz 1f mov $LINUX,%al -1: stosq #→ __hostos +_init_systemfive_detected: + stosq #→ __hostos bsr %eax,%eax mov $_init_systemfive_jmptab,%ebx movzbl (%rbx,%rax),%eax diff --git a/test/libc/calls/printargs_test.c b/test/libc/calls/printargs_test.c new file mode 100644 index 000000000..25d0f6484 --- /dev/null +++ b/test/libc/calls/printargs_test.c @@ -0,0 +1,35 @@ +/*-*- 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 2022 Justine Alexandra Roberts Tunney │ +│ │ +│ 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. │ +│ │ +│ 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/runtime/internal.h" +#include "libc/sysv/consts/o.h" +#include "libc/testlib/testlib.h" +#include "libc/x/x.h" + +/** + * @fileoverview platform arguments tool + * + * This is intended to integrate with the Emacs keystroke `C-c C-s` + * which will remotely launch it on all the other operating systems and + * print the output. This way we can audit stuff. + */ + +TEST(printargs, test) { + __printargs("%r"); +} diff --git a/test/libc/calls/read_test.c b/test/libc/calls/read_test.c new file mode 100644 index 000000000..c2f156805 --- /dev/null +++ b/test/libc/calls/read_test.c @@ -0,0 +1,47 @@ +/*-*- 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 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ 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. │ +│ │ +│ 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/struct/iovec.h" +#include "libc/sock/internal.h" +#include "libc/sysv/consts/nr.h" +#include "libc/sysv/consts/o.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/testlib.h" + +static long Read(long fd, void *buf, unsigned long size) { + long ax, di, si, dx; + asm volatile("syscall" + : "=a"(ax), "=D"(di), "=S"(si), "=d"(dx) + : "0"(__NR_read), "1"(fd), "2"(buf), "3"(size) + : "rcx", "r8", "r9", "r10", "r11", "memory", "cc"); + return ax; +} + +BENCH(read, bench) { + char buf[16]; + ASSERT_SYS(0, 3, open("/dev/zero", O_RDONLY)); + EZBENCH2("read", donothing, read(3, buf, 5)); + EZBENCH2("readv", donothing, readv(3, &(struct iovec){buf, 5}, 1)); + EZBENCH2("sys_read", donothing, sys_read(3, buf, 5)); + EZBENCH2("sys_readv", donothing, sys_readv(3, &(struct iovec){buf, 5}, 1)); + EZBENCH2("Read", donothing, Read(3, buf, 5)); + EZBENCH2("Read", donothing, Read(3, buf, 5)); + ASSERT_SYS(0, 0, close(3)); +} diff --git a/test/libc/calls/write_test.c b/test/libc/calls/write_test.c index 476b349a8..39e068529 100644 --- a/test/libc/calls/write_test.c +++ b/test/libc/calls/write_test.c @@ -37,6 +37,7 @@ static long Write(long fd, const void *data, unsigned long size) { BENCH(write, bench) { ASSERT_SYS(0, 3, open("/dev/null", O_WRONLY)); EZBENCH2("write", donothing, write(3, "hello", 5)); + EZBENCH2("writev", donothing, writev(3, &(struct iovec){"hello", 5}, 1)); EZBENCH2("sys_write", donothing, sys_write(3, "hello", 5)); EZBENCH2("sys_writev", donothing, sys_writev(3, &(struct iovec){"hello", 5}, 1)); diff --git a/test/libc/intrin/kprintf_test.c b/test/libc/intrin/kprintf_test.c index 542e06775..6275426d1 100644 --- a/test/libc/intrin/kprintf_test.c +++ b/test/libc/intrin/kprintf_test.c @@ -28,6 +28,7 @@ #include "libc/rand/rand.h" #include "libc/runtime/memtrack.internal.h" #include "libc/runtime/runtime.h" +#include "libc/runtime/symbols.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/map.h" #include "libc/sysv/consts/prot.h" @@ -208,6 +209,19 @@ TEST(ksnprintf, test) { } } +TEST(ksnprintf, testSymbols) { + char b[2][32]; + bool hassymbols; + hassymbols = GetSymbolTable(); + ksnprintf(b[0], 32, "%t", strlen); + if (hassymbols) { + ASSERT_STREQ("&strlen", b[0]); + } else { + ksnprintf(b[1], 32, "&%x", strlen); + ASSERT_STREQ(b[1], b[0]); + } +} + TEST(ksnprintf, fuzzTheUnbreakable) { int e; size_t i; diff --git a/test/libc/stdio/spawn_test.c b/test/libc/stdio/spawn_test.c index c834a6a9c..75fd4ecb8 100644 --- a/test/libc/stdio/spawn_test.c +++ b/test/libc/stdio/spawn_test.c @@ -30,7 +30,7 @@ TEST(spawn, test) { int rc, ws, pid; - char *prog = (char *)getauxval(AT_EXECFN); + char *prog = GetProgramExecutableName(); char *args[] = {program_invocation_name, NULL}; char *envs[] = {"THE_DOGE=42", NULL}; if (atoi(nulltoempty(getenv("THE_DOGE"))) == 42) exit(42); diff --git a/test/libc/x/test.mk b/test/libc/x/test.mk index b5fa44aa6..025c759c0 100644 --- a/test/libc/x/test.mk +++ b/test/libc/x/test.mk @@ -32,6 +32,7 @@ TEST_LIBC_X_DIRECTDEPS = \ LIBC_STDIO \ LIBC_STR \ LIBC_RAND \ + LIBC_SOCK \ LIBC_STUBS \ LIBC_SYSV \ LIBC_TESTLIB \ diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index cdfb4789d..c49e7b532 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -465,7 +465,6 @@ static char *FormatUnsigned(char *p, unsigned x) { } static char HasPendingInput(int fd) { - if (IsWindows()) return 0; return poll((struct pollfd[]){{fd, POLLIN}}, 1, 0) == 1; } diff --git a/third_party/make/getopt.c b/third_party/make/getopt.c index 9a502e9a5..170c82f83 100644 --- a/third_party/make/getopt.c +++ b/third_party/make/getopt.c @@ -35,14 +35,6 @@ this program. If not, see . */ #endif #pragma GCC diagnostic ignored "-Wredundant-decls" -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -# ifndef const -# define const -# endif -#endif - /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling diff --git a/third_party/make/getopt1.c b/third_party/make/getopt1.c index 43a55faaf..d0e42fdfb 100644 --- a/third_party/make/getopt1.c +++ b/third_party/make/getopt1.c @@ -23,14 +23,6 @@ this program. If not, see . */ #include "third_party/make/config.h" #endif -#if !defined __STDC__ || !__STDC__ -/* This is a separate conditional since some stdc systems - reject `defined (const)'. */ -#ifndef const -#define const -#endif -#endif - /* Comment out all this code if we are using the GNU C Library, and are not actually compiling the library itself. This code is part of the GNU C Library, but also included in many other GNU distributions. Compiling diff --git a/third_party/sqlite3/shell.c b/third_party/sqlite3/shell.c index 7408d1149..f3323e8b9 100644 --- a/third_party/sqlite3/shell.c +++ b/third_party/sqlite3/shell.c @@ -159,14 +159,6 @@ typedef unsigned char u8; # define SHELL_USE_LOCAL_GETLINE 1 #endif -#if defined(_WIN32_WCE) -/* Windows CE (arm-wince-mingw32ce-gcc) does not provide isatty() - * thus we always assume that we have a console. That can be - * overridden with the -batch command line option. - */ -#define isatty(x) 1 -#endif - /* ctype macros that work with signed characters */ #define IsSpace(X) isspace((unsigned char)X) #define IsDigit(X) isdigit((unsigned char)X) diff --git a/tool/build/runitd.c b/tool/build/runitd.c index 741a5078f..bc2def800 100644 --- a/tool/build/runitd.c +++ b/tool/build/runitd.c @@ -99,7 +99,7 @@ volatile bool g_interrupted; struct sockaddr_in g_servaddr; unsigned char g_buf[PAGESIZE]; bool g_daemonize, g_sendready, g_alarmed; -int g_timeout, g_devnullfd, g_servfd, g_clifd, g_exefd; +int g_timeout, g_bogusfd, g_servfd, g_clifd, g_exefd; void OnInterrupt(int sig) { g_interrupted = true; @@ -193,10 +193,8 @@ void StartTcpServer(void) { * TODO: How can we make close(serversocket) on Windows go fast? * That way we can put back SOCK_CLOEXEC. */ - CHECK_NE(-1, (g_servfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))); - CHECK_NE(-1, dup2(g_servfd, 10)); - CHECK_NE(-1, close(g_servfd)); - g_servfd = 10; + CHECK_NE(-1, (g_servfd = + socket(AF_INET, SOCK_STREAM | SOCK_CLOEXEC, IPPROTO_TCP))); LOGIFNEG1(setsockopt(g_servfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes))); if (bind(g_servfd, &g_servaddr, sizeof(g_servaddr)) == -1) { @@ -216,7 +214,7 @@ void StartTcpServer(void) { printf("ready %hu\n", ntohs(g_servaddr.sin_port)); fflush(stdout); fclose(stdout); - dup2(g_devnullfd, stdout->fd); + dup2(g_bogusfd, stdout->fd); } } @@ -343,11 +341,11 @@ void HandleClient(void) { sigaction(SIGINT, &saveint, NULL); sigaction(SIGQUIT, &savequit, NULL); sigprocmask(SIG_SETMASK, &savemask, NULL); - dup2(g_devnullfd, 0); + /* dup2(g_bogusfd, 0); */ dup2(pipefds[1], 1); dup2(pipefds[1], 2); if (pipefds[0] > 2) close(pipefds[1]); - if (g_devnullfd > 2) close(g_devnullfd); + if (g_bogusfd > 2) close(g_bogusfd); int i = 0; char *args[4] = {0}; args[i++] = g_exepath; @@ -454,8 +452,8 @@ void Daemonize(void) { if (fork() > 0) _exit(0); setsid(); if (fork() > 0) _exit(0); - dup2(g_devnullfd, stdin->fd); - if (!g_sendready) dup2(g_devnullfd, stdout->fd); + dup2(g_bogusfd, stdin->fd); + if (!g_sendready) dup2(g_bogusfd, stdout->fd); freopen(kLogFile, "ae", stderr); if (fstat(fileno(stderr), &st) != -1 && st.st_size > kLogMaxBytes) { ftruncate(fileno(stderr), 0); @@ -467,8 +465,13 @@ int main(int argc, char *argv[]) { SetupPresharedKeySsl(MBEDTLS_SSL_IS_SERVER, GetRunitPsk()); /* __log_level = kLogDebug; */ GetOpts(argc, argv); - CHECK_EQ(3, (g_devnullfd = open("/dev/null", O_RDWR | O_CLOEXEC))); - defer(close_s, &g_devnullfd); + // poll()'ing /dev/null stdin file descriptor on xnu returns POLLNVAL?! + if (IsWindows()) { + CHECK_EQ(3, (g_bogusfd = open("/dev/null", O_RDONLY | O_CLOEXEC))); + } else { + CHECK_EQ(3, (g_bogusfd = open("/dev/zero", O_RDONLY | O_CLOEXEC))); + } + defer(close_s, &g_bogusfd); if (!isdirectory("o")) CHECK_NE(-1, mkdir("o", 0700)); if (g_daemonize) Daemonize(); return Serve(); diff --git a/tool/build/strace.c b/tool/build/strace.c index 4a40d8e3b..ba11e630a 100644 --- a/tool/build/strace.c +++ b/tool/build/strace.c @@ -22,6 +22,7 @@ #include "libc/calls/sigbits.h" #include "libc/calls/struct/iovec.h" #include "libc/calls/struct/sigaction.h" +#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/sigset.h" #include "libc/calls/struct/stat.h" #include "libc/calls/struct/user_regs_struct.h" @@ -1042,11 +1043,12 @@ wontreturn void PropagateTermination(int wstatus) { wontreturn void StraceMain(int argc, char *argv[]) { unsigned long msg; + struct siginfo si; struct Pid *s, *child; struct PidList pidlist; - sigset_t mask, truemask; - struct sigaction sigdfl; + sigset_t mask, origmask; int i, sig, evpid, root, wstatus, signal; + struct sigaction sigign, saveint, savequit; if (!IsLinux()) { kprintf("error: ptrace() is only supported on linux right now%n"); @@ -1064,20 +1066,22 @@ wontreturn void StraceMain(int argc, char *argv[]) { pidlist.n = 0; pidlist.p = 0; - sigdfl.sa_flags = 0; - sigdfl.sa_handler = SIG_DFL; - sigemptyset(&sigdfl.sa_mask); + sigign.sa_flags = 0; + sigign.sa_handler = SIG_IGN; + sigemptyset(&sigign.sa_mask); + + sigaction(SIGINT, &sigign, &saveint); + sigaction(SIGQUIT, &sigign, &savequit); sigemptyset(&mask); - sigaddset(&mask, SIGCHLD); - sigaddset(&mask, SIGINT); - sigaddset(&mask, SIGQUIT); - sigaddset(&mask, SIGTERM); - sigprocmask(SIG_BLOCK, &mask, &truemask); + /* sigaddset(&mask, SIGCHLD); */ + sigprocmask(SIG_BLOCK, &mask, &origmask); - CHECK_NE(-1, (root = vfork())); + CHECK_NE(-1, (root = fork())); if (!root) { - sigprocmask(SIG_SETMASK, &truemask, 0); + sigaction(SIGINT, &saveint, 0); + sigaction(SIGQUIT, &savequit, 0); + sigprocmask(SIG_SETMASK, &origmask, 0); ptrace(PTRACE_TRACEME); execvp(argv[1], argv + 1); _Exit(127); @@ -1091,7 +1095,7 @@ wontreturn void StraceMain(int argc, char *argv[]) { CHECK_NE(-1, ptrace(PTRACE_SETOPTIONS, sp->pid, 0, (PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE | PTRACE_O_TRACEEXEC | - PTRACE_O_TRACEEXIT))); + PTRACE_O_TRACEEXIT | PTRACE_O_TRACESYSGOOD))); // continue child process setting breakpoint at next system call CHECK_NE(-1, ptrace(PTRACE_SYSCALL, sp->pid, 0, 0)); @@ -1120,8 +1124,20 @@ wontreturn void StraceMain(int argc, char *argv[]) { // handle actual kill if (WIFSIGNALED(wstatus)) { - kprintf(PROLOGUE " exited with signal %s%n", sp->pid, - strsignal(WTERMSIG(wstatus))); + kprintf(PROLOGUE " exited with signal %G%n", sp->pid, WTERMSIG(wstatus)); + RemovePid(&pidlist, sp->pid); + sp = 0; + // we die when the last process being monitored dies + if (!pidlist.i) { + PropagateTermination(wstatus); + } else { + continue; + } + } + + // handle core dump + if (WCOREDUMP(wstatus)) { + kprintf(PROLOGUE " exited with core%n", sp->pid); RemovePid(&pidlist, sp->pid); sp = 0; // we die when the last process being monitored dies @@ -1136,19 +1152,29 @@ wontreturn void StraceMain(int argc, char *argv[]) { sig = 0; signal = (wstatus >> 8) & 0xffff; assert(WIFSTOPPED(wstatus)); - if (signal == SIGTRAP) { - CHECK_NE(-1, ptrace(PTRACE_GETREGS, sp->pid, 0, &sp->args)); - PrintSyscall(sp->insyscall); - sp->insyscall = !sp->insyscall; + if (signal == SIGTRAP | PTRACE_EVENT_STOP) { + CHECK_NE(-1, ptrace(PTRACE_GETSIGINFO, sp->pid, 0, &si)); + if (si.si_code == SIGTRAP || si.si_code == SIGTRAP | 0x80) { + CHECK_NE(-1, ptrace(PTRACE_GETREGS, sp->pid, 0, &sp->args)); + PrintSyscall(sp->insyscall); + sp->insyscall = !sp->insyscall; + ptrace(PTRACE_SYSCALL, sp->pid, 0, 0); + } else { + sig = signal & 127; + kappendf(&ob, PROLOGUE " got signal %G%n", sp->pid, sig); + Flush(); + ptrace(PTRACE_SYSCALL, sp->pid, 0, sig); + } } else if (signal == (SIGTRAP | (PTRACE_EVENT_EXIT << 8))) { CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, sp->pid, 0, &msg)); sig = WSTOPSIG(wstatus); + ptrace(PTRACE_SYSCALL, sp->pid, 0, 0); } else if (signal == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) { CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, sp->pid, 0, &msg)); - } else if (WIFSTOPPED(wstatus) && - (signal == (SIGTRAP | (PTRACE_EVENT_FORK << 8)) || - signal == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) || - signal == (SIGTRAP | (PTRACE_EVENT_CLONE << 8)))) { + ptrace(PTRACE_SYSCALL, sp->pid, 0, 0); + } else if (signal == (SIGTRAP | (PTRACE_EVENT_FORK << 8)) || + signal == (SIGTRAP | (PTRACE_EVENT_VFORK << 8)) || + signal == (SIGTRAP | (PTRACE_EVENT_CLONE << 8))) { CHECK_NE(-1, ptrace(PTRACE_GETEVENTMSG, evpid, 0, &msg)); child = AddPid(&pidlist, msg); child->pid = msg; @@ -1161,18 +1187,12 @@ wontreturn void StraceMain(int argc, char *argv[]) { } Flush(); ptrace(PTRACE_SYSCALL, child->pid, 0, 0); + ptrace(PTRACE_SYSCALL, sp->pid, 0, 0); } else { - sig = signal & 0x7f; - if (sig != SIGSTOP) { - kappendf(&ob, PROLOGUE " %s%n", sp->pid, strsignal(sig)); - Flush(); - } - sig = sig; + kappendf(&ob, PROLOGUE " gottish signal %G%n", sp->pid, sig); + Flush(); + ptrace(PTRACE_SYSCALL, sp->pid, 0, signal & 127); } - - // trace events always freeze the traced process - // this call will help it to start running again - ptrace(PTRACE_SYSCALL, sp->pid, 0, sig); } } diff --git a/tool/emacs/cosmo-c-keywords.el b/tool/emacs/cosmo-c-keywords.el index 80cada8b1..441b7c977 100644 --- a/tool/emacs/cosmo-c-keywords.el +++ b/tool/emacs/cosmo-c-keywords.el @@ -22,7 +22,6 @@ (cosmo '("__msabi" - "var" "function" "offsetof" "microarchitecture" diff --git a/tool/net/help.txt b/tool/net/help.txt index c3836293f..efd4fbdc8 100644 --- a/tool/net/help.txt +++ b/tool/net/help.txt @@ -1,6 +1,6 @@ SYNOPSIS - redbean.com [-hvduzmbagf] [-p PORT] [-- SCRIPTARGS...] + redbean.com [-hvduzmbagf] [-p PORT] [-D DIR] [-- SCRIPTARGS...] DESCRIPTION @@ -1233,7 +1233,7 @@ UNIX MODULE fork exit stat open close seek read write access fcntl chdir chown chmod getcwd kill raise wait pipe dup mkdir rmdir opendir rename link unlink symlink sync fsync fdatasync truncate umask getppid - getpgid setpgid getsid setsid getpid getuid getgid gettime + getpgrp getpgid setpgid getsid setsid getpid getuid getgid gettime nanosleep socket socketpair bind listen accept connect recvfrom sendto shutdown getpeername getsockname sigaction sigprocmask strerror @@ -1260,19 +1260,77 @@ UNIX MODULE There's also a /unix.lua file in redbean-demo.com that provides a glimpse of how these powerful APIs can be used. Here's a synopsis: + unix.open(path, flags[, mode]) → fd, errno + + Opens file. + + unix.read(fd[, bufsiz, offset]) → data, errno + + Reads from file descriptor. + + unix.write(fd, data[, offset]) → rc, errno + + Writes to file descriptor. + + unix.close(fd) → rc, errno + + Closes file descriptor. + unix.exit([exitcode]) → ⊥ + + Invokes `_Exit(exitcode)` on the process. This will immediately + halt the current process. Memory will be freed. File descriptors + will be closed. Any open connections it owns will be reset. + unix.fork() → childpid|0, errno + + Creates a new process mitosis style. This returns twice. The + parent process gets the nonzero pid. The child gets zero. + unix.commandv(prog) → path, errno + + Performs `$PATH` lookup of executable. We automatically suffix + `.com` and `.exe` automatically for all platforms when path + searching. By default, the current directory is not on the path. + If `prog` is an absolute path, then it's returned as-is. If + `prog` contains slashes then it's not path searched either and + will be returned if it exists. + unix.execve(prog, argv[, envp]) → errno - prog needs to be absolute, see commandv() - envp defaults to environ + + Exits current process, replacing it with a new instance of the + specified program. `prog` needs to be an absolute path, see + commandv(). `envp` defaults to to the current `environ`. Both + `prog` and `envp` are arrays of strings. + + unix.execve("/bin/ls", {"/bin/ls", "-hal"}) + unix.exit(127) + + The first element in `argv` should be `prog`. This function is + normally called after forking. + unix.access(path, mode) → rc, errno - mode can be: R_OK, W_OK, X_OK, F_OK + + Checks if effective user of current process has permission to + access file. `mode` can be `R_OK`, `W_OK`, `X_OK`, or `F_OK` to + check for read, write, execute, and existence respectively. + unix.mkdir(path, mode) → rc, errno - mode should be octal + + Makes directory. `mode` should be octal, e.g. `0755`. + unix.chdir(path) → rc, errno + + Changes current directory to `path`. + unix.unlink(path) → rc, errno + + Removes file at `path`. + unix.rmdir(path) → rc, errno + + Removes empty directory at `path`. + unix.rename(oldpath, newpath) → rc, errno unix.link(existingpath, newpath) → rc, errno unix.symlink(target, linkpath) → rc, errno @@ -1290,67 +1348,131 @@ UNIX MODULE unix.pipe([flags]) → reader, writer, errno flags can have O_CLOEXEC unix.getsid(pid) → sid, errno + unix.getpgrp() → pgid, errno unix.getpgid(pid) → pgid, errno - unix.umask(mask) → rc, errno unix.setpgid(pid, pgid) → pgid, errno unix.setsid() → sid, errno unix.getuid() → uid, errno unix.getgid() → gid, errno + unix.umask(mask) → rc, errno unix.gettime([clock]) → seconds, nanos, errno unix.nanosleep(seconds, nanos) → remseconds, remnanos, errno unix.sync(fd) unix.fsync(fd) → rc, errno unix.fdatasync(fd) → rc, errno - unix.open(path, flags[, mode]) → fd, errno - unix.close(fd) → rc, errno + unix.seek(fd, offset, whence) → newpos, errno where whence ∈ {SEEK_SET, SEEK_CUR, SEEK_END} whence defaults to SEEK_SET unix.truncate(path, length) → rc, errno unix.truncate(fd, length) → rc, errno - unix.read(fd[, bufsiz, offset]) → data, errno - unix.write(fd, data[, offset]) → rc, errno + unix.socket([family[, type[, protocol]]]) → fd, errno - SOCK_CLOEXEC may be or'd into type - family defaults to AF_INET - type defaults to SOCK_STREAM - protocol defaults to IPPROTO_TCP + + `SOCK_CLOEXEC` may be or'd into type + `family` defaults to `AF_INET` + `type` defaults to `SOCK_STREAM` + `protocol` defaults to `IPPROTO_TCP` + unix.socketpair([family[, type[, protocol]]]) → fd1, fd2, errno - SOCK_CLOEXEC may be or'd into type - family defaults to AF_INET - type defaults to SOCK_STREAM - protocol defaults to IPPROTO_TCP + + `SOCK_CLOEXEC` may be or'd into type + `family` defaults to `AF_INET` + `type` defaults to `SOCK_STREAM` + `protocol` defaults to `IPPROTO_TCP` + unix.bind(fd, ip, port) → rc, errno - SOCK_CLOEXEC may be or'd into type - family defaults to AF_INET - type defaults to SOCK_STREAM - protocol defaults to IPPROTO_TCP + unix.connect(fd, ip, port) → rc, errno - SOCK_CLOEXEC may be or'd into type - family defaults to AF_INET - type defaults to SOCK_STREAM - protocol defaults to IPPROTO_TCP + unix.listen(fd[, backlog]) → rc, errno + unix.getsockname(fd) → ip, port, errno + unix.getpeername(fd) → ip, port, errno + unix.accept(serverfd) → clientfd, ip, port, errno + + unix.recv(fd[, bufsiz[, flags]]) → data, errno + + `flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc. + unix.recvfrom(fd[, bufsiz[, flags]]) → data, ip, port, errno - flags can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc. + + `flags` can have MSG_{WAITALL,DONTROUTE,PEEK,OOB}, etc. + + unix.send(fd, data[, flags]) → sent, errno + + This is the same as `write` except it has a `flags` argument + that's intended for sockets. `flags` can have `MSG_OOB`, + `MSG_DONTROUTE`, or `MSG_NOSIGNAL`. + unix.sendto(fd, data, ip, port[, flags]) → sent, errno - flags MSG_OOB, MSG_DONTROUTE, MSG_NOSIGNAL, etc. + + This is useful for sending messages over UDP sockets to specific + addresses. The `flags` parameter can have `MSG_OOB`, + `MSG_DONTROUTE`, or `MSG_NOSIGNAL`. + unix.shutdown(fd, how) → rc, errno - how can be SHUT_RD, SHUT_WR, or SHUT_RDWR + + Partially closes socket. `how` can be `SHUT_RD`, `SHUT_WR`, or + `SHUT_RDWR`. + unix.sigprocmask(how[, mask]) → oldmask, errno - how can be SIG_BLOCK, SIG_UNBLOCK, SIG_SETMASK + + `how` can be `SIG_BLOCK`, `SIG_UNBLOCK`, `SIG_SETMASK` + unix.sigaction(sig[, handler[, flags[, mask]]]) → handler, flags, mask, errno - handler can be SIG_IGN, SIG_DFL, intptr_t, or a Lua function - sig can be SIGINT, SIGQUIT, SIGTERM, SIGUSR1, etc. + + `handler` can be `SIG_IGN`, `SIG_DFL`, `intptr_t`, or a Lua + function. `sig` can be `SIGINT`, `SIGQUIT`, `SIGTERM`, etc. + `flags` can have `SA_RESTART`, `SA_RESETHAND`, etc. Example: + + unix = require "unix" + unix.sigaction(unix.SIGUSR1, function(sig) + print(string.format("got %s", unix.strsignal(sig))) + end) + unix.sigprocmask(unix.SIG_SETMASK, -1) + unix.raise(unix.SIGUSR1) + unix.sigsuspend() + + It's a good idea to not do too much work in a signal handler. + unix.sigsuspend([mask]) → errno + + Waits for signal to be delivered. + unix.setitimer(which[, intsec, intmicros, valsec, valmicros]) - → intsec, intns, valsec, valns, errno - which should be ITIMER_REAL - unix.strerror(errno) → str - unix.strsignal(sig) → str + → intsec, intns, valsec, valns, errno + + Causes `SIGALRM` signals to be generated at some point(s) in the + future. The `which` parameter should be `ITIMER_REAL`. + + Here's an example of how to create a 400 ms interval timer: + + ticks = 0 + unix.sigaction(unix.SIGALRM, function(sig) + print(string.format("tick no. %d", ticks)) + ticks = ticks + 1 + end) + unix.setitimer(unix.ITIMER_REAL, 0, 400000, 0, 400000) + while true do + unix.sigsuspend() + end + + Here's how you'd do a single-shot timeout in 1 second: + + unix.sigaction(unix.SIGALRM, MyOnSigAlrm, unix.SA_RESETHAND) + unix.setitimer(unix.ITIMER_REAL, 0, 0, 1, 0) + + unix.strerror(errno:int) → str + + Turns `errno` code into a string describing the error. + + unix.strsignal(sig:int) → str + + Turns platform-specific `sig` code into its name, e.g. + `strsignal(9)` always returns `"SIGKILL"`. Here's your UnixStat* object. diff --git a/tool/net/lunix.c b/tool/net/lunix.c index ef9374412..ab35ccd75 100644 --- a/tool/net/lunix.c +++ b/tool/net/lunix.c @@ -425,6 +425,14 @@ static int LuaUnixGetsid(lua_State *L) { return ReturnRc(L, rc, olderr); } +// unix.getpgrp() → pgid, errno +static int LuaUnixGetpgrp(lua_State *L) { + int rc, olderr; + olderr = errno; + rc = getpgrp(); + return ReturnRc(L, rc, olderr); +} + // unix.getpgid(pid) → pgid, errno static int LuaUnixGetpgid(lua_State *L) { int rc, pid, olderr; @@ -1427,6 +1435,7 @@ static const luaL_Reg kLuaUnix[] = { {"truncate", LuaUnixTruncate}, // shrink or extend file medium {"umask", LuaUnixUmask}, // set file mode creation mask {"getppid", LuaUnixGetppid}, // get parent process id + {"getpgrp", LuaUnixGetpgrp}, // get process group id {"getpgid", LuaUnixGetpgid}, // get process group id of pid {"setpgid", LuaUnixSetpgid}, // set process group id for pid {"getsid", LuaUnixGetsid}, // get session id of pid diff --git a/tool/net/net.mk b/tool/net/net.mk index f4280f6c2..995893f40 100644 --- a/tool/net/net.mk +++ b/tool/net/net.mk @@ -98,6 +98,8 @@ o/$(MODE)/tool/net/redbean.com.dbg: \ $(APE) @$(APELINK) +ifneq ($(MODE),tiny) +ifneq ($(MODE),tinylinux) o/$(MODE)/tool/net/redbean.com: \ o/$(MODE)/tool/net/redbean.com.dbg \ o/$(MODE)/third_party/infozip/zip.com \ @@ -118,6 +120,44 @@ o/$(MODE)/tool/net/redbean.com: \ tool/net/.init.lua \ tool/net/favicon.ico \ tool/net/redbean.png +endif +endif + +o/tiny/tool/net/redbean.com: \ + o/tiny/tool/net/redbean.com.dbg \ + o/tiny/third_party/infozip/zip.com \ + tool/net/net.mk \ + tool/net/tiny/help.txt \ + tool/net/.init.lua \ + tool/net/favicon.ico \ + tool/net/redbean.png + @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ + @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tiny/tool/net/.redbean + @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tiny/tool/net/.redbean/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AZIP -T$@ o/tiny/third_party/infozip/zip.com -9qj $@ \ + o/tiny/tool/net/.redbean/.ape \ + tool/net/tiny/help.txt \ + tool/net/.init.lua \ + tool/net/favicon.ico \ + tool/net/redbean.png + +o/tinylinux/tool/net/redbean.com: \ + o/tinylinux/tool/net/redbean.com.dbg \ + o/tinylinux/third_party/infozip/zip.com \ + tool/net/net.mk \ + tool/net/tiny/help.txt \ + tool/net/.init.lua \ + tool/net/favicon.ico \ + tool/net/redbean.png + @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ + @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tinylinux/tool/net/.redbean + @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tinylinux/tool/net/.redbean/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AZIP -T$@ o/tinylinux/third_party/infozip/zip.com -9qj $@ \ + o/tinylinux/tool/net/.redbean/.ape \ + tool/net/tiny/help.txt \ + tool/net/.init.lua \ + tool/net/favicon.ico \ + tool/net/redbean.png # REDBEAN-DEMO.COM # @@ -293,6 +333,8 @@ o/$(MODE)/tool/net/redbean-unsecure.o: tool/net/redbean.c o/$(MODE)/tool/net/red # produce 200kb binary that's very similar to redbean as it existed on # Hacker News the day it went viral. +ifneq ($(MODE),tiny) +ifneq ($(MODE),tinylinux) o/$(MODE)/tool/net/redbean-original.com: \ o/$(MODE)/tool/net/redbean-original.com.dbg \ o/$(MODE)/third_party/infozip/zip.com \ @@ -311,6 +353,38 @@ o/$(MODE)/tool/net/redbean-original.com: \ tool/net/help.txt \ tool/net/favicon.ico \ tool/net/redbean.png +endif +endif + +o/tiny/tool/net/redbean-original.com: \ + o/tiny/tool/net/redbean-original.com.dbg \ + o/tiny/third_party/infozip/zip.com \ + tool/net/tiny/help.txt \ + tool/net/favicon.ico \ + tool/net/redbean.png + @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ + @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tiny/tool/net/.redbean-original + @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tiny/tool/net/.redbean-original/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AZIP -T$@ o/tiny/third_party/infozip/zip.com -9qj $@ \ + o/tiny/tool/net/.redbean-original/.ape \ + tool/net/tiny/help.txt \ + tool/net/favicon.ico \ + tool/net/redbean.png + +o/tinylinux/tool/net/redbean-original.com: \ + o/tinylinux/tool/net/redbean-original.com.dbg \ + o/tinylinux/third_party/infozip/zip.com \ + tool/net/tiny/help.txt \ + tool/net/favicon.ico \ + tool/net/redbean.png + @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ + @$(COMPILE) -AMKDIR -T$@ mkdir -p o/tinylinux/tool/net/.redbean-original + @$(COMPILE) -ADD -T$@ dd if=$@ of=o/tinylinux/tool/net/.redbean-original/.ape bs=64 count=11 conv=notrunc 2>/dev/null + @$(COMPILE) -AZIP -T$@ o/tinylinux/third_party/infozip/zip.com -9qj $@ \ + o/tinylinux/tool/net/.redbean-original/.ape \ + tool/net/tiny/help.txt \ + tool/net/favicon.ico \ + tool/net/redbean.png o/$(MODE)/tool/net/redbean-original.com.dbg: \ $(TOOL_NET_DEPS) \ diff --git a/tool/net/redbean.c b/tool/net/redbean.c index 04ade2143..188e2547a 100644 --- a/tool/net/redbean.c +++ b/tool/net/redbean.c @@ -58,6 +58,7 @@ #include "libc/runtime/gc.internal.h" #include "libc/runtime/runtime.h" #include "libc/runtime/stack.h" +#include "libc/runtime/symbols.internal.h" #include "libc/sock/goodsocket.internal.h" #include "libc/sock/sock.h" #include "libc/stdio/append.internal.h" @@ -504,13 +505,6 @@ static long ParseInt(const char *s) { return strtol(s, 0, 0); } -static void SyncSharedMemory(void) { - if (IsWindows() && !uniprocess) { - LOGIFNEG1( - msync(shared, ROUNDUP(sizeof(struct Shared), FRAMESIZE), MS_ASYNC)); - } -} - static void *FreeLater(void *p) { if (p) { if (++freelist.n > freelist.c) { @@ -944,14 +938,11 @@ static void ProgramDirectory(const char *path) { char *s; size_t n; struct stat st; - if (stat(path, &st) == -1 || !S_ISDIR(st.st_mode)) { DIEF("(cfg) error: not a directory: %`'s", path); } - s = strdup(path); n = strlen(s); - INFOF("(cfg) program directory: %s", s); AddString(&stagedirs, s, n); } @@ -1172,7 +1163,6 @@ static void ReportWorkerResources(int pid, struct rusage *ru) { } static void HandleWorkerExit(int pid, int ws, struct rusage *ru) { - SyncSharedMemory(); LockInc(&shared->c.connectionshandled); AddRusage(&shared->children, ru); ReportWorkerExit(pid, ws); @@ -1180,7 +1170,6 @@ static void HandleWorkerExit(int pid, int ws, struct rusage *ru) { if (hasonprocessdestroy) { LuaOnProcessDestroy(pid); } - SyncSharedMemory(); } static void KillGroupImpl(int sig) { @@ -6429,7 +6418,6 @@ static bool HandleMessage(void) { ishandlingrequest = true; r = HandleMessageActual(); ishandlingrequest = false; - SyncSharedMemory(); return r; } @@ -6936,7 +6924,6 @@ static wontreturn void ExitWorker(void) { MemDestroy(); CheckForMemoryLeaks(); } - SyncSharedMemory(); _Exit(0); } diff --git a/tool/net/tiny/help.txt b/tool/net/tiny/help.txt new file mode 100644 index 000000000..4adba268e --- /dev/null +++ b/tool/net/tiny/help.txt @@ -0,0 +1,12 @@ +SYNOPSIS + + redbean.com [-hvduzmbagf] [-p PORT] [-D DIR] + +DESCRIPTION + + redbean - single-file distributable web server + +DOCUMENTATION + + This binary was built in MODE=tiny or MODE=tinylinux + You can view documentation online at https://redbean.dev/