mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-01-31 11:37:35 +00:00
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.
This commit is contained in:
parent
933411ba99
commit
dc0ea6640e
127 changed files with 1354 additions and 866 deletions
|
@ -7,19 +7,30 @@
|
||||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#endif
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/backtrace.internal.h"
|
#include "libc/log/backtrace.internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/symbols.internal.h"
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/stdio/stdio.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
ShowCrashReports();
|
// ShowCrashReports();
|
||||||
|
|
||||||
if (IsDebuggerPresent(false)) {
|
if (IsDebuggerPresent(false)) {
|
||||||
printf("debugger found!\r\n");
|
kprintf("debugger found!%n");
|
||||||
DebugBreak();
|
} else {
|
||||||
return 0;
|
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;
|
||||||
}
|
}
|
||||||
|
|
23
examples/linenoise.c
Normal file
23
examples/linenoise.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -7,115 +7,8 @@
|
||||||
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
│ • http://creativecommons.org/publicdomain/zero/1.0/ │
|
||||||
╚─────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────*/
|
||||||
#endif
|
#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/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 {
|
int main() {
|
||||||
const char *fmt;
|
__printargs("");
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,14 +29,6 @@ textwindows int sys_close_nt(struct Fd *fd) {
|
||||||
int e;
|
int e;
|
||||||
bool ok = true;
|
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 &&
|
if (fd->kind == kFdFile && ((fd->flags & O_ACCMODE) != O_RDONLY &&
|
||||||
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
GetFileType(fd->handle) == kNtFileTypeDisk)) {
|
||||||
// Like Linux, closing a file on Windows doesn't guarantee it's
|
// 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;
|
errno = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
// now we can close the handle
|
// if this file descriptor is wrapped in a named pipe worker thread
|
||||||
if (!CloseHandle(fd->handle)) ok = false;
|
// 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 (fd->kind == kFdConsole && fd->extra && fd->extra != -1) {
|
||||||
if (!CloseHandle(fd->extra)) ok = false;
|
if (!CloseHandle(fd->extra)) ok = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,14 +40,13 @@ textwindows struct DirectMap sys_mmap_nt(void *addr, size_t size, int prot,
|
||||||
struct DirectMap dm;
|
struct DirectMap dm;
|
||||||
struct ProtectNt fl;
|
struct ProtectNt fl;
|
||||||
const struct NtSecurityAttributes *sec;
|
const struct NtSecurityAttributes *sec;
|
||||||
|
struct NtProcessMemoryCountersEx memcount;
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#if _NT_RLIMIT_PWSS_MB
|
||||||
struct NtProcessMemoryCountersEx memcount = {
|
|
||||||
.cb = sizeof(struct NtProcessMemoryCountersEx),
|
|
||||||
};
|
|
||||||
if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
|
if (GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
|
||||||
if (memcount.PeakWorkingSetSize > 5ull * 1024 * 1024 * 1024) {
|
if (memcount.PeakWorkingSetSize > _NT_RLIMIT_PWSS_MB * 1048576ull) {
|
||||||
kprintf("error: exceeded 5gb memory limit%n");
|
kprintf("error: PeakWorkingSetSize %'ldmb exceeded %'ldmb limit%n",
|
||||||
|
memcount.PeakWorkingSetSize / 1048576, (long)_NT_RLIMIT_PWSS_MB);
|
||||||
_Exit(201);
|
_Exit(201);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,8 +45,8 @@ struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||||
} else {
|
} else {
|
||||||
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
|
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
|
||||||
}
|
}
|
||||||
STRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
|
KERNTRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
|
||||||
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
|
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
|
||||||
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
|
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,6 @@ int fcntl(int fd, int cmd, ...) {
|
||||||
} else {
|
} else {
|
||||||
rc = einval();
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@ int fstat(int fd, struct stat *st) {
|
||||||
} else if (!__isfdkind(fd, kFdFile)) {
|
} else if (!__isfdkind(fd, kFdFile)) {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
} else {
|
} 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);
|
STRACE("fstat(%d, [%s]) → %d% m", fd, __strace_stat(rc, st), rc);
|
||||||
return rc;
|
return rc;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
|
|
||||||
STATIC_YOINK("_init_g_fds");
|
STATIC_YOINK("_init_g_fds");
|
||||||
|
|
||||||
|
@ -48,4 +49,7 @@ textstartup void InitializeFileDescriptors(void) {
|
||||||
fds->__init_p[1].handle = GetStdHandle(pushpop(kNtStdOutputHandle));
|
fds->__init_p[1].handle = GetStdHandle(pushpop(kNtStdOutputHandle));
|
||||||
fds->__init_p[2].handle = GetStdHandle(pushpop(kNtStdErrorHandle));
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,5 @@ unsigned long getauxval(unsigned long at) {
|
||||||
return ap[1];
|
return ap[1];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (at == AT_EXECFN) {
|
|
||||||
return (intptr_t)__argv[0];
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
31
libc/calls/getegid.c
Normal file
31
libc/calls/getegid.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -27,6 +27,8 @@
|
||||||
*
|
*
|
||||||
* pheidippides.domain.example
|
* pheidippides.domain.example
|
||||||
* ^^^^^^^^^^^^
|
* ^^^^^^^^^^^^
|
||||||
|
*
|
||||||
|
* @return 0 on success or -1 w/ errno
|
||||||
*/
|
*/
|
||||||
int gethostname(char *name, size_t len) {
|
int gethostname(char *name, size_t len) {
|
||||||
if (len < 1) return einval();
|
if (len < 1) return einval();
|
||||||
|
|
|
@ -16,27 +16,21 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ 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) {
|
* Returns process group id of calling process.
|
||||||
/* asan runtime depends on this function */
|
*/
|
||||||
unsigned l, m, r, n, k;
|
uint32_t getpgrp(void) {
|
||||||
if (t) {
|
int rc;
|
||||||
l = 0;
|
if (!IsWindows()) {
|
||||||
r = n = t->count;
|
rc = sys_getpgrp();
|
||||||
k = a - t->addr_base;
|
} else {
|
||||||
while (l < r) {
|
rc = getpid();
|
||||||
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;
|
STRACE("%s() → %d% m", "getpgrp", rc);
|
||||||
|
return rc;
|
||||||
}
|
}
|
|
@ -30,30 +30,22 @@
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
textwindows int sys_getrusage_nt(int who, struct rusage *usage) {
|
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 NtProcessMemoryCountersEx memcount;
|
||||||
|
struct NtFileTime ftExit, ftUser, ftKernel, ftCreation;
|
||||||
if (!usage) return efault();
|
if (!usage) return efault();
|
||||||
if (who == 99) return enosys(); /* @see libc/sysv/consts.sh */
|
if (who == 99) return enosys(); // @see libc/sysv/consts.sh
|
||||||
bzero(usage, sizeof(*usage));
|
if (!usage) return 0;
|
||||||
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
if (!(who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
||||||
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
||||||
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
|
&ftCreation, &ftExit, &ftKernel, &ftUser) ||
|
||||||
/* xxx: shouldn't clobber memory on failure below */
|
!GetProcessMemoryInfo(GetCurrentProcess(), &memcount, sizeof(memcount))) {
|
||||||
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 {
|
|
||||||
return __winerr();
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -157,6 +157,7 @@ i32 sys_futimes(i32, const struct timeval *) hidden;
|
||||||
i32 sys_futimesat(i32, const char *, const struct timeval *) hidden;
|
i32 sys_futimesat(i32, const char *, const struct timeval *) hidden;
|
||||||
i32 sys_getitimer(i32, struct itimerval *) hidden;
|
i32 sys_getitimer(i32, struct itimerval *) hidden;
|
||||||
i32 sys_getpgid(i32) hidden;
|
i32 sys_getpgid(i32) hidden;
|
||||||
|
i32 sys_getpgrp(void) hidden;
|
||||||
i32 sys_getppid(void) hidden;
|
i32 sys_getppid(void) hidden;
|
||||||
i32 sys_getpriority(i32, u32) hidden;
|
i32 sys_getpriority(i32, u32) hidden;
|
||||||
i32 sys_getrlimit(i32, struct rlimit *) 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_splice(i32, i64 *, i32, i64 *, u64, u32) hidden;
|
||||||
i64 sys_vmsplice(i32, const struct iovec *, i64, u32) hidden;
|
i64 sys_vmsplice(i32, const struct iovec *, i64, u32) hidden;
|
||||||
i64 sys_write(i32, const void *, u64) hidden;
|
i64 sys_write(i32, const void *, u64) hidden;
|
||||||
|
u32 sys_getegid(void) hidden;
|
||||||
u32 sys_geteuid(void) hidden;
|
u32 sys_geteuid(void) hidden;
|
||||||
u32 sys_getgid(void) hidden;
|
u32 sys_getgid(void) hidden;
|
||||||
u32 sys_getsid(int) hidden;
|
u32 sys_getsid(int) hidden;
|
||||||
|
|
|
@ -35,7 +35,7 @@ int ioctl_default(int fd, uint64_t request, ...) {
|
||||||
return sys_ioctl(fd, request, arg);
|
return sys_ioctl(fd, request, arg);
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (g_fds.p[fd].kind == kFdSocket) {
|
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) {
|
if ((rc = weaken(__sys_ioctlsocket_nt)(handle, request, arg)) != -1) {
|
||||||
return rc;
|
return rc;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -31,8 +31,8 @@ textwindows int ioctl_tcgets_nt(int ignored, struct termios *tio) {
|
||||||
int64_t in, out;
|
int64_t in, out;
|
||||||
bool32 inok, outok;
|
bool32 inok, outok;
|
||||||
uint32_t inmode, outmode;
|
uint32_t inmode, outmode;
|
||||||
inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode);
|
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
|
||||||
outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode);
|
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
|
||||||
if (inok | outok) {
|
if (inok | outok) {
|
||||||
bzero(tio, sizeof(*tio));
|
bzero(tio, sizeof(*tio));
|
||||||
if (inok) {
|
if (inok) {
|
||||||
|
|
|
@ -31,8 +31,8 @@ textwindows int ioctl_tcsets_nt(int ignored, uint64_t request,
|
||||||
int64_t in, out;
|
int64_t in, out;
|
||||||
bool32 inok, outok;
|
bool32 inok, outok;
|
||||||
uint32_t inmode, outmode;
|
uint32_t inmode, outmode;
|
||||||
inok = GetConsoleMode((in = g_fds.p[0].handle), &inmode);
|
inok = GetConsoleMode((in = __getfdhandleactual(0)), &inmode);
|
||||||
outok = GetConsoleMode((out = g_fds.p[1].handle), &outmode);
|
outok = GetConsoleMode((out = __getfdhandleactual(1)), &outmode);
|
||||||
if (inok | outok) {
|
if (inok | outok) {
|
||||||
if (inok) {
|
if (inok) {
|
||||||
if (request == TCSETSF) {
|
if (request == TCSETSF) {
|
||||||
|
|
|
@ -42,10 +42,10 @@ textwindows int ioctl_tiocgwinsz_nt(struct Fd *fd, struct winsize *ws) {
|
||||||
GetStartupInfo(&startinfo);
|
GetStartupInfo(&startinfo);
|
||||||
for (i = 0; i < ARRAYLEN(fds); ++i) {
|
for (i = 0; i < ARRAYLEN(fds); ++i) {
|
||||||
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
|
if (fds[i]->kind == kFdFile || fds[i]->kind == kFdConsole) {
|
||||||
if (GetConsoleMode(fds[i]->handle, &mode)) {
|
if (GetConsoleMode(__getfdhandleactual(i), &mode)) {
|
||||||
bzero(&sbinfo, sizeof(sbinfo));
|
bzero(&sbinfo, sizeof(sbinfo));
|
||||||
sbinfo.cbSize = 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_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left + 1;
|
||||||
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
|
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top + 1;
|
||||||
ws->ws_xpixel = 0;
|
ws->ws_xpixel = 0;
|
||||||
|
|
|
@ -29,9 +29,10 @@ textwindows int ioctl_tiocswinsz_nt(int fd, const struct winsize *ws) {
|
||||||
struct NtCoord coord;
|
struct NtCoord coord;
|
||||||
if (!ws) return efault();
|
if (!ws) return efault();
|
||||||
if (!__isfdkind(fd, kFdFile)) return ebadf();
|
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.X = ws->ws_col;
|
||||||
coord.Y = ws->ws_row;
|
coord.Y = ws->ws_row;
|
||||||
if (!SetConsoleScreenBufferSize(g_fds.p[fd].handle, coord)) return __winerr();
|
if (!SetConsoleScreenBufferSize(__getfdhandleactual(fd), coord))
|
||||||
|
return __winerr();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,5 +24,5 @@
|
||||||
textwindows bool32 sys_isatty_nt(int fd) {
|
textwindows bool32 sys_isatty_nt(int fd) {
|
||||||
return __isfdkind(fd, kFdConsole) ||
|
return __isfdkind(fd, kFdConsole) ||
|
||||||
(__isfdkind(fd, kFdFile) &&
|
(__isfdkind(fd, kFdFile) &&
|
||||||
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
|
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,6 @@ bool32 ischardev(int fd) {
|
||||||
} else {
|
} else {
|
||||||
return __isfdkind(fd, kFdConsole) ||
|
return __isfdkind(fd, kFdConsole) ||
|
||||||
(__isfdkind(fd, kFdFile) &&
|
(__isfdkind(fd, kFdFile) &&
|
||||||
GetFileType(g_fds.p[fd].handle) == kNtFileTypeChar);
|
GetFileType(__getfdhandleactual(fd)) == kNtFileTypeChar);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,6 @@ privileged void *sys_mremap(void *p, size_t n, size_t m, int f, void *q) {
|
||||||
} else {
|
} else {
|
||||||
rax = enosys();
|
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;
|
return (void *)rax;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ int sys_munmap(void *p, size_t n) {
|
||||||
} else {
|
} else {
|
||||||
rc = sys_munmap_metal(p, n);
|
rc = sys_munmap_metal(p, n);
|
||||||
}
|
}
|
||||||
STRACE("sys_munmap(%p%s, %'zu) → %d", p, DescribeFrame((intptr_t)p >> 16), n,
|
KERNTRACE("sys_munmap(%p%s, %'zu) → %d", p, DescribeFrame((intptr_t)p >> 16),
|
||||||
rc);
|
n, rc);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,9 @@
|
||||||
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
|
textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
|
||||||
struct timespec *rem) {
|
struct timespec *rem) {
|
||||||
int rc;
|
int rc;
|
||||||
int64_t sec, nsec;
|
bool alertable;
|
||||||
uint64_t ms, slice;
|
uint32_t slice;
|
||||||
|
int64_t ms, sec, nsec;
|
||||||
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
|
if (__builtin_mul_overflow(req->tv_sec, 1000, &ms) ||
|
||||||
__builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) {
|
__builtin_add_overflow(ms, req->tv_nsec / 1000000, &ms)) {
|
||||||
ms = -1;
|
ms = -1;
|
||||||
|
@ -44,18 +45,20 @@ textwindows noinstrument int sys_nanosleep_nt(const struct timespec *req,
|
||||||
rc = eintr();
|
rc = eintr();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ms > __SIG_POLLING_INTERVAL_MS) {
|
slice = MIN(__SIG_POLLING_INTERVAL_MS, ms);
|
||||||
slice = __SIG_POLLING_INTERVAL_MS;
|
if (__time_critical) {
|
||||||
|
alertable = false;
|
||||||
} else {
|
} else {
|
||||||
slice = ms;
|
alertable = true;
|
||||||
|
POLLTRACE("sys_nanosleep_nt polling for %'ldms of %'ld");
|
||||||
}
|
}
|
||||||
if (SleepEx(slice, true) == kNtWaitIoCompletion) {
|
if (SleepEx(slice, alertable) == kNtWaitIoCompletion) {
|
||||||
STRACE("IOCP TRIGGERED EINTR");
|
POLLTRACE("IOCP EINTR");
|
||||||
rc = eintr();
|
continue;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
ms -= slice;
|
ms -= slice;
|
||||||
} while (ms);
|
} while (ms > 0);
|
||||||
|
ms = MAX(ms, 0);
|
||||||
if (rem) {
|
if (rem) {
|
||||||
sec = ms / 1000;
|
sec = ms / 1000;
|
||||||
nsec = ms % 1000 * 1000000000;
|
nsec = ms % 1000 * 1000000000;
|
||||||
|
|
|
@ -61,6 +61,10 @@ ssize_t preadv(int fd, struct iovec *iov, int iovlen, int64_t off) {
|
||||||
return enosys();
|
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
|
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -65,6 +65,10 @@ ssize_t pwritev(int fd, const struct iovec *iov, int iovlen, int64_t off) {
|
||||||
return enosys();
|
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
|
* NT, 2018-era XNU, and 2007-era Linux don't support this system call
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -65,10 +65,7 @@ int raise(int sig) {
|
||||||
// groups potentially. We just shouldn't use this because it
|
// groups potentially. We just shouldn't use this because it
|
||||||
// doesn't make any sense and it's so evil.
|
// doesn't make any sense and it's so evil.
|
||||||
if (GenerateConsoleCtrlEvent(event, 0)) {
|
if (GenerateConsoleCtrlEvent(event, 0)) {
|
||||||
// XXX: we shouldn't need to sleep here ctrl-c is evil on nt
|
SleepEx(100, true);
|
||||||
if (SleepEx(100, true) == kNtWaitIoCompletion) {
|
|
||||||
STRACE("IOCP TRIGGERED EINTR");
|
|
||||||
}
|
|
||||||
__sig_check(false);
|
__sig_check(false);
|
||||||
rc = 0;
|
rc = 0;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/enum/wait.h"
|
#include "libc/nt/enum/wait.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
#include "libc/nt/files.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) {
|
size_t size, ssize_t offset) {
|
||||||
uint32_t err, got, avail;
|
uint32_t err, got, avail;
|
||||||
struct NtOverlapped overlap;
|
struct NtOverlapped overlap;
|
||||||
if (fd->worker) {
|
if (GetFileType(fd->handle) == kNtFileTypePipe) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break;
|
if (!PeekNamedPipe(fd->handle, 0, 0, 0, &avail, 0)) break;
|
||||||
if (avail) break;
|
if (avail) break;
|
||||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion ||
|
POLLTRACE("sys_read_nt polling");
|
||||||
_check_interrupts(true, g_fds.p)) {
|
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();
|
return eintr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
POLLTRACE("sys_read_nt ready to read");
|
||||||
}
|
}
|
||||||
if (ReadFile(fd->handle, data, _clampio(size), &got,
|
if (ReadFile(fd->handle, data, _clampio(size), &got,
|
||||||
_offset2overlap(fd->handle, offset, &overlap))) {
|
_offset2overlap(fd->handle, offset, &overlap))) {
|
||||||
|
|
|
@ -61,7 +61,7 @@ textwindows ssize_t sys_readlinkat_nt(int dirfd, const char *path, char *buf,
|
||||||
rdb = (struct NtReparseDataBuffer *)buf;
|
rdb = (struct NtReparseDataBuffer *)buf;
|
||||||
freeme = 0;
|
freeme = 0;
|
||||||
} else {
|
} 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();
|
return enomem();
|
||||||
}
|
}
|
||||||
if ((h = CreateFile(path16, 0, 0, 0, kNtOpenExisting,
|
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)) {
|
if (freeme || (intptr_t)(buf + j) <= (intptr_t)(p + i)) {
|
||||||
rc = j;
|
rc = j;
|
||||||
} else {
|
} else {
|
||||||
STRACE("sys_readlinkat_nt() too many astral codepoints");
|
NTTRACE("sys_readlinkat_nt() too many astral codepoints");
|
||||||
rc = enametoolong();
|
rc = enametoolong();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
STRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
|
NTTRACE("sys_readlinkat_nt() should have kNtIoReparseTagSymlink");
|
||||||
rc = einval();
|
rc = einval();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -29,6 +29,13 @@
|
||||||
/**
|
/**
|
||||||
* Reads data to multiple buffers.
|
* 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
|
* @return number of bytes actually read, or -1 w/ errno
|
||||||
* @restartable
|
* @restartable
|
||||||
*/
|
*/
|
||||||
|
@ -41,7 +48,11 @@ ssize_t readv(int fd, const struct iovec *iov, int iovlen) {
|
||||||
rc = weaken(__zipos_read)(
|
rc = weaken(__zipos_read)(
|
||||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||||
} else if (!IsWindows() && !IsMetal()) {
|
} 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) {
|
} else if (fd >= g_fds.n) {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal()) {
|
||||||
|
|
|
@ -90,7 +90,7 @@ int __reservefd(int start) {
|
||||||
*/
|
*/
|
||||||
static void __freefds(void) {
|
static void __freefds(void) {
|
||||||
int i;
|
int i;
|
||||||
STRACE("__freefds()");
|
NTTRACE("__freefds()");
|
||||||
for (i = 3; i < g_fds.n; ++i) {
|
for (i = 3; i < g_fds.n; ++i) {
|
||||||
if (g_fds.p[i].kind) {
|
if (g_fds.p[i].kind) {
|
||||||
close(i);
|
close(i);
|
||||||
|
|
|
@ -42,6 +42,10 @@
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
|
#ifdef SYSDEBUG
|
||||||
|
STATIC_YOINK("strsignal"); // for kprintf()
|
||||||
|
#endif
|
||||||
|
|
||||||
#define SA_RESTORER 0x04000000
|
#define SA_RESTORER 0x04000000
|
||||||
|
|
||||||
#ifndef SWITCHEROO
|
#ifndef SWITCHEROO
|
||||||
|
|
|
@ -78,15 +78,14 @@ int sigsuspend(const sigset_t *ignore) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||||
STRACE("IOCP TRIGGERED EINTR");
|
POLLTRACE("IOCP EINTR");
|
||||||
rc = eintr();
|
continue;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#ifdef SYSDEBUG
|
#if defined(SYSDEBUG) && defined(_POLLTRACE)
|
||||||
ms += __SIG_POLLING_INTERVAL_MS;
|
ms += __SIG_POLLING_INTERVAL_MS;
|
||||||
if (ms >= __SIG_LOGGING_INTERVAL_MS) {
|
if (ms >= __SIG_LOGGING_INTERVAL_MS) {
|
||||||
totoms += ms, ms = 0;
|
totoms += ms, ms = 0;
|
||||||
STRACE("... sigsuspending for %'lums...", totoms);
|
POLLTRACE("... sigsuspending for %'lums...", totoms);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} while (1);
|
} while (1);
|
||||||
|
|
|
@ -4,6 +4,11 @@
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
#include "libc/calls/struct/stat.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 "
|
#define STRACE_PROLOGUE "%rSYS %5P %'18T "
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
@ -20,6 +25,24 @@ COSMOPOLITAN_C_START_
|
||||||
#define STRACE(FMT, ...) (void)0
|
#define STRACE(FMT, ...) (void)0
|
||||||
#endif
|
#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;
|
extern int __strace;
|
||||||
|
|
||||||
void __stracef(const char *, ...);
|
void __stracef(const char *, ...);
|
||||||
|
|
|
@ -86,7 +86,7 @@ int uname(struct utsname *lool) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
v = NtGetVersion();
|
v = NtGetVersion();
|
||||||
p = lool->version;
|
p = lool->release;
|
||||||
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
|
p = FormatUint32(p, NtGetMajorVersion()), *p++ = '.';
|
||||||
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';
|
p = FormatUint32(p, NtGetMinorVersion()), *p++ = '-';
|
||||||
p = FormatUint32(p, NtGetBuildNumber());
|
p = FormatUint32(p, NtGetBuildNumber());
|
||||||
|
|
|
@ -28,6 +28,13 @@
|
||||||
/**
|
/**
|
||||||
* Writes data from multiple buffers.
|
* 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
|
* 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
|
* 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
|
* 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)(
|
rc = weaken(__zipos_write)(
|
||||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle, iov, iovlen, -1);
|
||||||
} else if (!IsWindows() && !IsMetal()) {
|
} 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) {
|
} else if (fd >= g_fds.n) {
|
||||||
rc = ebadf();
|
rc = ebadf();
|
||||||
} else if (IsMetal()) {
|
} else if (IsMetal()) {
|
||||||
|
|
|
@ -72,15 +72,11 @@ _start:
|
||||||
mov %rdi,%rcx # auxv
|
mov %rdi,%rcx # auxv
|
||||||
|
|
||||||
#if SupportsXnu()
|
#if SupportsXnu()
|
||||||
// should probably be removed in favor of newer apis
|
// xnu doesn't have auxiliary values
|
||||||
testb IsXnu()
|
testb IsXnu()
|
||||||
jz 1f # polyfill xnu auxv
|
jz 1f # polyfill xnu auxv
|
||||||
push $0 # auxv[1][1]=0
|
push $0 # auxv[1][1]=0
|
||||||
push $0 # auxv[1][0]=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
|
mov %rsp,%rcx # auxv
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,6 @@ textwindows bool32 CloseHandle(int64_t hObject) {
|
||||||
__winerr();
|
__winerr();
|
||||||
if (weaken(__die)) weaken(__die)();
|
if (weaken(__die)) weaken(__die)();
|
||||||
}
|
}
|
||||||
STRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok);
|
NTTRACE("CloseHandle(%ld) → %hhhd% m", hObject, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,7 @@ CreateDirectory(const char16_t *lpPathName,
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_CreateDirectoryW(lpPathName, lpSecurityAttributes);
|
ok = __imp_CreateDirectoryW(lpPathName, lpSecurityAttributes);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
|
NTTRACE("CreateDirectory(%#hs, %s) → %hhhd% m", lpPathName,
|
||||||
DescribeNtSecurityAttributes(lpSecurityAttributes), ok);
|
DescribeNtSecurityAttributes(lpSecurityAttributes), ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,12 +40,12 @@ textwindows int64_t CreateFile(
|
||||||
opt_lpSecurityAttributes, dwCreationDisposition,
|
opt_lpSecurityAttributes, dwCreationDisposition,
|
||||||
dwFlagsAndAttributes, opt_hTemplateFile);
|
dwFlagsAndAttributes, opt_hTemplateFile);
|
||||||
if (hHandle == -1) __winerr();
|
if (hHandle == -1) __winerr();
|
||||||
STRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName,
|
NTTRACE("CreateFile(%#hs, %s, %s, %s, %s, %s, %ld) → %ld% m", lpFileName,
|
||||||
DescribeNtFileAccessFlags(dwDesiredAccess),
|
DescribeNtFileAccessFlags(dwDesiredAccess),
|
||||||
DescribeNtFileShareFlags(dwShareMode),
|
DescribeNtFileShareFlags(dwShareMode),
|
||||||
DescribeNtSecurityAttributes(opt_lpSecurityAttributes),
|
DescribeNtSecurityAttributes(opt_lpSecurityAttributes),
|
||||||
DescribeNtCreationDisposition(dwCreationDisposition),
|
DescribeNtCreationDisposition(dwCreationDisposition),
|
||||||
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes),
|
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes),
|
||||||
opt_hTemplateFile, hHandle);
|
opt_hTemplateFile, hHandle);
|
||||||
return hHandle;
|
return hHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,10 @@ textwindows int64_t CreateFileMapping(
|
||||||
flProtect, dwMaximumSizeHigh,
|
flProtect, dwMaximumSizeHigh,
|
||||||
dwMaximumSizeLow, opt_lpName);
|
dwMaximumSizeLow, opt_lpName);
|
||||||
if (!hHandle) __winerr();
|
if (!hHandle) __winerr();
|
||||||
STRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
|
NTTRACE("CreateFileMapping(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
|
||||||
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
|
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
|
||||||
DescribeNtPageFlags(flProtect),
|
DescribeNtPageFlags(flProtect),
|
||||||
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
|
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
|
||||||
hHandle);
|
hHandle);
|
||||||
return hHandle;
|
return hHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,10 +44,10 @@ textwindows int64_t CreateFileMappingNuma(
|
||||||
opt_hFile, opt_lpFileMappingAttributes, flProtect, dwMaximumSizeHigh,
|
opt_hFile, opt_lpFileMappingAttributes, flProtect, dwMaximumSizeHigh,
|
||||||
dwMaximumSizeLow, opt_lpName, nndDesiredNumaNode);
|
dwMaximumSizeLow, opt_lpName, nndDesiredNumaNode);
|
||||||
if (!hHandle) __winerr();
|
if (!hHandle) __winerr();
|
||||||
STRACE("CreateFileMappingNuma(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
|
NTTRACE("CreateFileMappingNuma(%ld, %s, %s, %'zu, %#hs) → %ld% m", opt_hFile,
|
||||||
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
|
DescribeNtSecurityAttributes(opt_lpFileMappingAttributes),
|
||||||
DescribeNtPageFlags(flProtect),
|
DescribeNtPageFlags(flProtect),
|
||||||
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
|
(uint64_t)dwMaximumSizeHigh << 32 | dwMaximumSizeLow, opt_lpName,
|
||||||
hHandle);
|
hHandle);
|
||||||
return hHandle;
|
return hHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,10 +41,10 @@ textwindows int64_t CreateNamedPipe(
|
||||||
nMaxInstances, nOutBufferSize, nInBufferSize,
|
nMaxInstances, nOutBufferSize, nInBufferSize,
|
||||||
nDefaultTimeOutMs, opt_lpSecurityAttributes);
|
nDefaultTimeOutMs, opt_lpSecurityAttributes);
|
||||||
if (hServer == -1) __winerr();
|
if (hServer == -1) __winerr();
|
||||||
STRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m",
|
NTTRACE("CreateNamedPipe(%#hs, %s, %s, %u, %'u, %'u, %'u, %s) → %ld% m",
|
||||||
lpName, DescribeNtPipeOpenFlags(dwOpenMode),
|
lpName, DescribeNtPipeOpenFlags(dwOpenMode),
|
||||||
DescribeNtPipeModeFlags(dwPipeMode), nMaxInstances, nOutBufferSize,
|
DescribeNtPipeModeFlags(dwPipeMode), nMaxInstances, nOutBufferSize,
|
||||||
nInBufferSize, nDefaultTimeOutMs,
|
nInBufferSize, nDefaultTimeOutMs,
|
||||||
DescribeNtSecurityAttributes(opt_lpSecurityAttributes), hServer);
|
DescribeNtSecurityAttributes(opt_lpSecurityAttributes), hServer);
|
||||||
return hServer;
|
return hServer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ textwindows bool32 CreatePipe(
|
||||||
ok = __imp_CreatePipe(out_hReadPipe, out_hWritePipe, opt_lpPipeAttributes,
|
ok = __imp_CreatePipe(out_hReadPipe, out_hWritePipe, opt_lpPipeAttributes,
|
||||||
nSize);
|
nSize);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("CreatePipe([%ld], [%ld], %s, %'zu) → %hhhd% m", *out_hReadPipe,
|
NTTRACE("CreatePipe([%ld], [%ld], %s, %'zu) → %hhhd% m", *out_hReadPipe,
|
||||||
*out_hWritePipe, DescribeNtSecurityAttributes(opt_lpPipeAttributes),
|
*out_hWritePipe, DescribeNtSecurityAttributes(opt_lpPipeAttributes),
|
||||||
nSize, ok);
|
nSize, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ CreateProcess(const char16_t *opt_lpApplicationName, char16_t *lpCommandLine,
|
||||||
opt_lpCurrentDirectory, lpStartupInfo,
|
opt_lpCurrentDirectory, lpStartupInfo,
|
||||||
opt_out_lpProcessInformation);
|
opt_out_lpProcessInformation);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE(
|
NTTRACE(
|
||||||
"CreateFile(%#hs, %#hs, %s, %s, %hhhd, %u, %p, %#hs, %p, %p) → %hhhd% m",
|
"CreateFile(%#hs, %#hs, %s, %s, %hhhd, %u, %p, %#hs, %p, %p) → %hhhd% m",
|
||||||
opt_lpApplicationName, lpCommandLine,
|
opt_lpApplicationName, lpCommandLine,
|
||||||
DescribeNtSecurityAttributes(opt_lpProcessAttributes),
|
DescribeNtSecurityAttributes(opt_lpProcessAttributes),
|
||||||
|
|
|
@ -39,8 +39,9 @@ textwindows int64_t CreateThread(
|
||||||
hHandle = __imp_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
|
hHandle = __imp_CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress,
|
||||||
lpParameter, dwCreationFlags, opt_lpThreadId);
|
lpParameter, dwCreationFlags, opt_lpThreadId);
|
||||||
if (hHandle == -1) __winerr();
|
if (hHandle == -1) __winerr();
|
||||||
STRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m",
|
NTTRACE("CreateThread(%s, %'zu, %p, %p, %s, %p) → %ld% m",
|
||||||
DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize,
|
DescribeNtSecurityAttributes(lpThreadAttributes), dwStackSize,
|
||||||
lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId, hHandle);
|
lpStartAddress, lpParameter, dwCreationFlags, opt_lpThreadId,
|
||||||
|
hHandle);
|
||||||
return hHandle;
|
return hHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,7 +36,6 @@
|
||||||
void __cxa_finalize(void *pred) {
|
void __cxa_finalize(void *pred) {
|
||||||
unsigned i, mask;
|
unsigned i, mask;
|
||||||
struct CxaAtexitBlock *b, *b2;
|
struct CxaAtexitBlock *b, *b2;
|
||||||
STRACE("__cxa_finalize()");
|
|
||||||
StartOver:
|
StartOver:
|
||||||
if ((b = __cxa_blocks.p)) {
|
if ((b = __cxa_blocks.p)) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
@ -47,6 +46,7 @@ StartOver:
|
||||||
if (!pred || pred == b->p[i].pred) {
|
if (!pred || pred == b->p[i].pred) {
|
||||||
b->mask &= ~(1u << i);
|
b->mask &= ~(1u << i);
|
||||||
if (b->p[i].fp) {
|
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);
|
((void (*)(void *))b->p[i].fp)(b->p[i].arg);
|
||||||
goto StartOver;
|
goto StartOver;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,6 @@ textwindows bool32 DeleteFile(const char16_t *lpPathName) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_DeleteFileW(lpPathName);
|
ok = __imp_DeleteFileW(lpPathName);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok);
|
NTTRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,8 +40,8 @@ textwindows bool32 DeviceIoControl(int64_t hDevice, uint32_t dwIoControlCode,
|
||||||
nInBufferSize, lpOutBuffer, nOutBufferSize,
|
nInBufferSize, lpOutBuffer, nOutBufferSize,
|
||||||
lpBytesReturned, lpOverlapped);
|
lpBytesReturned, lpOverlapped);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m",
|
NTTRACE("DeviceIoControl(%ld, %#x, %p, %'zu, %p, %'zu, %p, %p) → %hhhd% m",
|
||||||
hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
|
hDevice, dwIoControlCode, lpInBuffer, nInBufferSize, lpOutBuffer,
|
||||||
nOutBufferSize, lpBytesReturned, lpOverlapped, ok);
|
nOutBufferSize, lpBytesReturned, lpOverlapped, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,6 @@ textwindows bool32 FindClose(int64_t hFindFile) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_FindClose(hFindFile);
|
ok = __imp_FindClose(hFindFile);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("FindClose(%ld) → %hhhd% m", hFindFile, ok);
|
NTTRACE("FindClose(%ld) → %hhhd% m", hFindFile, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ textwindows int64_t FindFirstFile(const char16_t *lpFileName,
|
||||||
int64_t hFindFile;
|
int64_t hFindFile;
|
||||||
hFindFile = __imp_FindFirstFileW(lpFileName, out_lpFindFileData);
|
hFindFile = __imp_FindFirstFileW(lpFileName, out_lpFindFileData);
|
||||||
if (hFindFile != -1) {
|
if (hFindFile != -1) {
|
||||||
STRACE(
|
NTTRACE(
|
||||||
"FindFirstFile(%#hs, [{"
|
"FindFirstFile(%#hs, [{"
|
||||||
".cFileName=%#hs, "
|
".cFileName=%#hs, "
|
||||||
".dwFileAttributes=%s, "
|
".dwFileAttributes=%s, "
|
||||||
|
@ -46,7 +46,7 @@ textwindows int64_t FindFirstFile(const char16_t *lpFileName,
|
||||||
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), hFindFile);
|
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), hFindFile);
|
||||||
} else {
|
} else {
|
||||||
__winerr();
|
__winerr();
|
||||||
STRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile);
|
NTTRACE("FindFirstFile(%#hs, [n/a]) → %ld% m", lpFileName, hFindFile);
|
||||||
}
|
}
|
||||||
return hFindFile;
|
return hFindFile;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ textwindows bool32 FindNextFile(int64_t hFindFile,
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_FindNextFileW(hFindFile, out_lpFindFileData);
|
ok = __imp_FindNextFileW(hFindFile, out_lpFindFileData);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
STRACE(
|
NTTRACE(
|
||||||
"FindNextFile(%ld, [{"
|
"FindNextFile(%ld, [{"
|
||||||
".cFileName=%#hs, "
|
".cFileName=%#hs, "
|
||||||
".dwFileAttributes=%s, "
|
".dwFileAttributes=%s, "
|
||||||
|
@ -48,7 +48,7 @@ textwindows bool32 FindNextFile(int64_t hFindFile,
|
||||||
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), ok);
|
DescribeNtFiletypeFlags(out_lpFindFileData->dwFileType), ok);
|
||||||
} else {
|
} else {
|
||||||
if (GetLastError() != kNtErrorNoMoreFiles) __winerr();
|
if (GetLastError() != kNtErrorNoMoreFiles) __winerr();
|
||||||
STRACE("FindNextFile(%ld) → %hhhd% m", hFindFile, ok);
|
NTTRACE("FindNextFile(%ld) → %hhhd% m", hFindFile, ok);
|
||||||
}
|
}
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,6 @@ textwindows bool32 FlushFileBuffers(int64_t hFile) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_FlushFileBuffers(hFile);
|
ok = __imp_FlushFileBuffers(hFile);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok);
|
NTTRACE("FlushFileBuffers(%ld) → %hhhd% m", hFile, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ textwindows bool32 FlushViewOfFile(const void *lpBaseAddress,
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_FlushViewOfFile(lpBaseAddress, dwNumberOfBytesToFlush);
|
ok = __imp_FlushViewOfFile(lpBaseAddress, dwNumberOfBytesToFlush);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress,
|
NTTRACE("FlushViewOfFile(%p, %'zu) → %hhhd% m", lpBaseAddress,
|
||||||
dwNumberOfBytesToFlush, ok);
|
dwNumberOfBytesToFlush, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ textwindows bool32 GenerateConsoleCtrlEvent(uint32_t dwCtrlEvent,
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_GenerateConsoleCtrlEvent(dwCtrlEvent, dwProcessGroupId);
|
ok = __imp_GenerateConsoleCtrlEvent(dwCtrlEvent, dwProcessGroupId);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("GenerateConsoleCtrlEvent(%x, %d) → %hhhd% m", dwCtrlEvent,
|
NTTRACE("GenerateConsoleCtrlEvent(%x, %d) → %hhhd% m", dwCtrlEvent,
|
||||||
dwProcessGroupId, ok);
|
dwProcessGroupId, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/log/libfatal.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
|
||||||
forceinline int Identity(int c) {
|
forceinline int Identity(int c) {
|
||||||
|
@ -66,6 +67,11 @@ char *getenv(const char *s) {
|
||||||
} else {
|
} else {
|
||||||
r = GetEnv(s, ToUpper);
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ textwindows uint32_t GetFileAttributes(const char16_t *lpPathName) {
|
||||||
uint32_t flags;
|
uint32_t flags;
|
||||||
flags = __imp_GetFileAttributesW(lpPathName);
|
flags = __imp_GetFileAttributesW(lpPathName);
|
||||||
if (flags == -1u) __winerr();
|
if (flags == -1u) __winerr();
|
||||||
STRACE("GetFileAttributes(%#hs) → %s% m", lpPathName,
|
NTTRACE("GetFileAttributes(%#hs) → %s% m", lpPathName,
|
||||||
DescribeNtFileFlagsAndAttributes(flags));
|
DescribeNtFileFlagsAndAttributes(flags));
|
||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/runtime/memtrack.internal.h"
|
#include "libc/runtime/memtrack.internal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/str/str.h"
|
#include "libc/str/str.h"
|
||||||
#include "libc/str/tpenc.h"
|
#include "libc/str/tpenc.h"
|
||||||
#include "libc/str/utf16.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':
|
case 'G':
|
||||||
x = va_arg(va, int);
|
x = va_arg(va, int);
|
||||||
if (weaken(strsignal)) {
|
if (weaken(strsignal) && (s = weaken(strsignal)(x))) {
|
||||||
s = weaken(strsignal)(x);
|
|
||||||
goto FormatString;
|
goto FormatString;
|
||||||
} else {
|
} else {
|
||||||
if (p + 3 <= e) {
|
|
||||||
p[0] = 'S';
|
|
||||||
p[1] = 'I';
|
|
||||||
p[2] = 'G';
|
|
||||||
}
|
|
||||||
p += 3;
|
|
||||||
goto FormatDecimal;
|
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':
|
case 'n':
|
||||||
// nonstandard %n specifier
|
// nonstandard %n specifier
|
||||||
// used to print newlines that work in raw terminal modes
|
// 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 *))) {
|
if (!(s = va_arg(va, const void *))) {
|
||||||
s = sign != ' ' ? "NULL" : "";
|
s = sign != ' ' ? "NULL" : "";
|
||||||
FormatString:
|
FormatString:
|
||||||
type = 0;
|
|
||||||
hash = 0;
|
hash = 0;
|
||||||
|
type = 0;
|
||||||
} else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) {
|
} else if (!dang && (kisdangerous(s) || kischarmisaligned(s, type))) {
|
||||||
if (sign == ' ') {
|
if (sign == ' ') {
|
||||||
if (p < e) *p = ' ';
|
if (p < e) *p = ' ';
|
||||||
|
@ -847,6 +856,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
||||||
* - `o` octal
|
* - `o` octal
|
||||||
* - `b` binary
|
* - `b` binary
|
||||||
* - `s` string
|
* - `s` string
|
||||||
|
* - `t` symbol
|
||||||
* - `p` pointer
|
* - `p` pointer
|
||||||
* - `d` decimal
|
* - `d` decimal
|
||||||
* - `n` newline
|
* - `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
|
* - `% m` formats error with leading space if errno isn't zero
|
||||||
* - `%lm` means favor WSAGetLastError() over GetLastError() if linked
|
* - `%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
|
* @asyncsignalsafe
|
||||||
* @vforksafe
|
* @vforksafe
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -45,9 +45,9 @@ textwindows void *MapViewOfFileEx(int64_t hFileMappingObject,
|
||||||
hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow,
|
hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow,
|
||||||
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress);
|
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress);
|
||||||
if (!pStartingAddress) __winerr();
|
if (!pStartingAddress) __winerr();
|
||||||
STRACE("MapViewOfFileEx(%ld, %s, %'ld, %'zu, %p) → %p% m", hFileMappingObject,
|
NTTRACE("MapViewOfFileEx(%ld, %s, %'ld, %'zu, %p) → %p% m",
|
||||||
DescribeNtFileMapFlags(dwDesiredAccess),
|
hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess),
|
||||||
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
|
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
|
||||||
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
|
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
|
||||||
return pStartingAddress;
|
return pStartingAddress;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,9 +47,9 @@ textwindows void *MapViewOfFileExNuma(int64_t hFileMappingObject,
|
||||||
hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow,
|
hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow,
|
||||||
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, nndDesiredNumaNode);
|
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, nndDesiredNumaNode);
|
||||||
if (!pStartingAddress) __winerr();
|
if (!pStartingAddress) __winerr();
|
||||||
STRACE("MapViewOfFileExNuma(%ld, %s, %'ld, %'zu, %p) → %p% m",
|
NTTRACE("MapViewOfFileExNuma(%ld, %s, %'ld, %'zu, %p) → %p% m",
|
||||||
hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess),
|
hFileMappingObject, DescribeNtFileMapFlags(dwDesiredAccess),
|
||||||
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
|
(uint64_t)dwFileOffsetHigh << 32 | dwFileOffsetLow,
|
||||||
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
|
dwNumberOfBytesToMap, opt_lpDesiredBaseAddress, pStartingAddress);
|
||||||
return pStartingAddress;
|
return pStartingAddress;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ textwindows int64_t OpenProcess(uint32_t dwDesiredAccess, bool32 bInheritHandle,
|
||||||
int64_t hHandle;
|
int64_t hHandle;
|
||||||
hHandle = __imp_OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
hHandle = __imp_OpenProcess(dwDesiredAccess, bInheritHandle, dwProcessId);
|
||||||
if (!hHandle) __winerr();
|
if (!hHandle) __winerr();
|
||||||
STRACE("OpenProcess(%s, %hhhd, %u) → %ld% m",
|
NTTRACE("OpenProcess(%s, %hhhd, %u) → %ld% m",
|
||||||
DescribeNtProcessAccessFlags(dwDesiredAccess), bInheritHandle,
|
DescribeNtProcessAccessFlags(dwDesiredAccess), bInheritHandle,
|
||||||
dwProcessId, hHandle);
|
dwProcessId, hHandle);
|
||||||
return hHandle;
|
return hHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,6 @@ textwindows bool32 RemoveDirectory(const char16_t *lpPathName) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_RemoveDirectoryW(lpPathName);
|
ok = __imp_RemoveDirectoryW(lpPathName);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok);
|
NTTRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,9 +36,9 @@ int64_t ReOpenFile(int64_t hOriginalFile, uint32_t dwDesiredAccess,
|
||||||
hHandle = __imp_ReOpenFile(hOriginalFile, dwDesiredAccess, dwShareMode,
|
hHandle = __imp_ReOpenFile(hOriginalFile, dwDesiredAccess, dwShareMode,
|
||||||
dwFlagsAndAttributes);
|
dwFlagsAndAttributes);
|
||||||
if (hHandle == -1) __winerr();
|
if (hHandle == -1) __winerr();
|
||||||
STRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile,
|
NTTRACE("ReOpenFile(%ld, %s, %s, %s) → %ld% m", hOriginalFile,
|
||||||
DescribeNtFileAccessFlags(dwDesiredAccess),
|
DescribeNtFileAccessFlags(dwDesiredAccess),
|
||||||
DescribeNtFileShareFlags(dwShareMode),
|
DescribeNtFileShareFlags(dwShareMode),
|
||||||
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), hHandle);
|
DescribeNtFileFlagsAndAttributes(dwFlagsAndAttributes), hHandle);
|
||||||
return hHandle;
|
return hHandle;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ const char kConsoleHandles[3] = {
|
||||||
noasan void __restorewintty(void) {
|
noasan void __restorewintty(void) {
|
||||||
int i;
|
int i;
|
||||||
if (!IsWindows()) return;
|
if (!IsWindows()) return;
|
||||||
STRACE("__restorewintty()");
|
NTTRACE("__restorewintty()");
|
||||||
if (GetCurrentProcessId() == __winmainpid) {
|
if (GetCurrentProcessId() == __winmainpid) {
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
SetConsoleMode(GetStdHandle(kConsoleHandles[i]), __ntconsolemode[i]);
|
||||||
|
|
|
@ -32,6 +32,6 @@ textwindows bool32 SetCurrentDirectory(const char16_t *lpPathName) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_SetCurrentDirectoryW(lpPathName);
|
ok = __imp_SetCurrentDirectoryW(lpPathName);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok);
|
NTTRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,6 @@ textwindows bool32 TerminateProcess(int64_t hProcess, uint32_t uExitCode) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_TerminateProcess(hProcess, uExitCode);
|
ok = __imp_TerminateProcess(hProcess, uExitCode);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uExitCode, ok);
|
NTTRACE("TerminateProcess(%ld, %u) → %hhhd% m", hProcess, uExitCode, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,6 @@ textwindows bool32 UnmapViewOfFile(const void *lpBaseAddress) {
|
||||||
bool32 ok;
|
bool32 ok;
|
||||||
ok = __imp_UnmapViewOfFile(lpBaseAddress);
|
ok = __imp_UnmapViewOfFile(lpBaseAddress);
|
||||||
if (!ok) __winerr();
|
if (!ok) __winerr();
|
||||||
STRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok);
|
NTTRACE("UnmapViewOfFile(%p) → %hhhd% m", lpBaseAddress, ok);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,7 @@ textwindows bool32 VirtualProtect(void *lpAddress, uint64_t dwSize,
|
||||||
__winerr();
|
__winerr();
|
||||||
__stpcpy(oldbuf, "n/a");
|
__stpcpy(oldbuf, "n/a");
|
||||||
}
|
}
|
||||||
STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize,
|
NTTRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize,
|
||||||
DescribeNtPageFlags(flNewProtect), oldbuf, bOk);
|
DescribeNtPageFlags(flNewProtect), oldbuf, bOk);
|
||||||
return bOk;
|
return bOk;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/log/internal.h"
|
#include "libc/log/internal.h"
|
||||||
#include "libc/log/log.h"
|
#include "libc/log/log.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
|
#include "libc/runtime/symbols.internal.h"
|
||||||
#include "libc/sysv/consts/sa.h"
|
#include "libc/sysv/consts/sa.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/consts/ss.h"
|
#include "libc/sysv/consts/ss.h"
|
||||||
|
@ -79,4 +80,5 @@ void ShowCrashReports(void) {
|
||||||
sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]);
|
sigaction(kCrashSigs[i], &sa, &g_oldcrashacts[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
GetSymbolTable();
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,29 +149,6 @@
|
||||||
pop \dest
|
pop \dest
|
||||||
.endm
|
.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.
|
// Loads address of linktime mergeable string literal into register.
|
||||||
.macro loadstr text:req reg:req regsz bias=0
|
.macro loadstr text:req reg:req regsz bias=0
|
||||||
.section .rodata.str1.1,"aSM",@progbits,1
|
.section .rodata.str1.1,"aSM",@progbits,1
|
||||||
|
|
|
@ -125,7 +125,7 @@ static textstartup void getrandom_init(void) {
|
||||||
if (!(rc = sys_getrandom(0, 0, 0))) {
|
if (!(rc = sys_getrandom(0, 0, 0))) {
|
||||||
have_getrandom = true;
|
have_getrandom = true;
|
||||||
}
|
}
|
||||||
STRACE("sys_getrandom(0,0,0) → %d% m");
|
KERNTRACE("sys_getrandom(0,0,0) → %d% m");
|
||||||
errno = e;
|
errno = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,11 +90,14 @@ cosmo: push %rbp
|
||||||
#if IsModeDbg()
|
#if IsModeDbg()
|
||||||
#ifdef SYSDEBUG
|
#ifdef SYSDEBUG
|
||||||
.init.start 307,_init_printargs
|
.init.start 307,_init_printargs
|
||||||
|
cmpl $0,__strace(%rip)
|
||||||
|
jz 1f
|
||||||
push %rdi
|
push %rdi
|
||||||
push %rsi
|
push %rsi
|
||||||
|
loadstr STRACE_PROLOGUE,di
|
||||||
call __printargs
|
call __printargs
|
||||||
pop %rsi
|
pop %rsi
|
||||||
pop %rdi
|
pop %rdi
|
||||||
.init.end 307,_init_printargs
|
1: .init.end 307,_init_printargs
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -52,6 +52,7 @@
|
||||||
STATIC_YOINK("_check_sigchld");
|
STATIC_YOINK("_check_sigchld");
|
||||||
|
|
||||||
extern int __pid;
|
extern int __pid;
|
||||||
|
extern int64_t __wincrashearly;
|
||||||
extern unsigned long long __kbirth;
|
extern unsigned long long __kbirth;
|
||||||
extern unsigned char __data_start[]; /* αpε */
|
extern unsigned char __data_start[]; /* αpε */
|
||||||
extern unsigned char __data_end[]; /* αpε */
|
extern unsigned char __data_end[]; /* αpε */
|
||||||
|
@ -59,6 +60,11 @@ extern unsigned char __bss_start[]; /* αpε */
|
||||||
extern unsigned char __bss_end[]; /* αpε */
|
extern unsigned char __bss_end[]; /* αpε */
|
||||||
bool32 __onntconsoleevent_nt(uint32_t);
|
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) {
|
static textwindows char16_t *ParseInt(char16_t *p, int64_t *x) {
|
||||||
*x = 0;
|
*x = 0;
|
||||||
while (*p == ' ') p++;
|
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,
|
static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n,
|
||||||
bool32 (*fn)(), const char *sf) {
|
bool32 (*fn)(), const char *sf) {
|
||||||
ssize_t rc = ForkIo(h, buf, n, fn);
|
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;
|
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");
|
return ForkIo2(h, buf, n, WriteFile, "WriteFile");
|
||||||
}
|
}
|
||||||
|
|
||||||
static textwindows dontinline bool ReadAll(int64_t h, void *buf, size_t n) {
|
static textwindows dontinline void ReadOrDie(int64_t h, void *buf, size_t n) {
|
||||||
return ForkIo2(h, buf, n, ReadFile, "ReadFile");
|
if (!ForkIo2(h, buf, n, ReadFile, "ReadFile")) {
|
||||||
|
KillForkChild("ReadFile");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows void WinMainForked(void) {
|
textwindows void WinMainForked(void) {
|
||||||
|
@ -114,7 +122,7 @@ textwindows void WinMainForked(void) {
|
||||||
// this variable should have the pipe handle numba
|
// this variable should have the pipe handle numba
|
||||||
varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar));
|
varlen = GetEnvironmentVariable(u"_FORK", fvar, ARRAYLEN(fvar));
|
||||||
if (!varlen || varlen >= ARRAYLEN(fvar)) return;
|
if (!varlen || varlen >= ARRAYLEN(fvar)) return;
|
||||||
STRACE("WinMainForked()");
|
NTTRACE("WinMainForked()");
|
||||||
SetEnvironmentVariable(u"_FORK", NULL);
|
SetEnvironmentVariable(u"_FORK", NULL);
|
||||||
ParseInt(fvar, &reader);
|
ParseInt(fvar, &reader);
|
||||||
|
|
||||||
|
@ -123,21 +131,21 @@ textwindows void WinMainForked(void) {
|
||||||
// this is stored in a special secretive memory map!
|
// this is stored in a special secretive memory map!
|
||||||
// read ExtendMemoryIntervals for further details :|
|
// read ExtendMemoryIntervals for further details :|
|
||||||
maps = (void *)kMemtrackStart;
|
maps = (void *)kMemtrackStart;
|
||||||
ReadAll(reader, jb, sizeof(jb));
|
ReadOrDie(reader, jb, sizeof(jb));
|
||||||
ReadAll(reader, &mapcount, sizeof(_mmi.i));
|
ReadOrDie(reader, &mapcount, sizeof(_mmi.i));
|
||||||
ReadAll(reader, &mapcapacity, sizeof(_mmi.n));
|
ReadOrDie(reader, &mapcapacity, sizeof(_mmi.n));
|
||||||
specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran);
|
specialz = ROUNDUP(mapcapacity * sizeof(_mmi.p[0]), kMemtrackGran);
|
||||||
MapViewOfFileEx(
|
MapViewOfFileEx(
|
||||||
CreateFileMapping(-1, 0, kNtPageReadwrite, specialz >> 32, specialz, 0),
|
CreateFileMapping(-1, 0, kNtPageReadwrite, specialz >> 32, specialz, 0),
|
||||||
kNtFileMapWrite, 0, 0, specialz, maps);
|
kNtFileMapWrite, 0, 0, specialz, maps);
|
||||||
ReadAll(reader, maps, mapcount * sizeof(_mmi.p[0]));
|
ReadOrDie(reader, maps, mapcount * sizeof(_mmi.p[0]));
|
||||||
if (IsAsan()) {
|
if (IsAsan()) {
|
||||||
shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000);
|
shad = (char *)(((intptr_t)maps >> 3) + 0x7fff8000);
|
||||||
size = ROUNDUP(specialz >> 3, FRAMESIZE);
|
size = ROUNDUP(specialz >> 3, FRAMESIZE);
|
||||||
MapViewOfFileEx(
|
MapViewOfFileEx(
|
||||||
CreateFileMapping(-1, 0, kNtPageReadwrite, size >> 32, size, 0),
|
CreateFileMapping(-1, 0, kNtPageReadwrite, size >> 32, size, 0),
|
||||||
kNtFileMapWrite, 0, 0, size, maps);
|
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
|
// read the heap mappings from the parent process
|
||||||
|
@ -152,7 +160,7 @@ textwindows void WinMainForked(void) {
|
||||||
upsize >> 32, upsize, 0);
|
upsize >> 32, upsize, 0);
|
||||||
MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
|
MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
|
||||||
upsize, addr);
|
upsize, addr);
|
||||||
ReadAll(reader, addr, size);
|
ReadOrDie(reader, addr, size);
|
||||||
} else {
|
} else {
|
||||||
// we can however safely inherit MAP_SHARED with zero copy
|
// we can however safely inherit MAP_SHARED with zero copy
|
||||||
MapViewOfFileEx(maps[i].h,
|
MapViewOfFileEx(maps[i].h,
|
||||||
|
@ -167,8 +175,8 @@ textwindows void WinMainForked(void) {
|
||||||
savepid = __pid;
|
savepid = __pid;
|
||||||
savebir = __kbirth;
|
savebir = __kbirth;
|
||||||
savetsc = ts;
|
savetsc = ts;
|
||||||
ReadAll(reader, __data_start, __data_end - __data_start);
|
ReadOrDie(reader, __data_start, __data_end - __data_start);
|
||||||
ReadAll(reader, __bss_start, __bss_end - __bss_start);
|
ReadOrDie(reader, __bss_start, __bss_end - __bss_start);
|
||||||
__pid = savepid;
|
__pid = savepid;
|
||||||
__kbirth = savebir;
|
__kbirth = savebir;
|
||||||
ts = savetsc;
|
ts = savetsc;
|
||||||
|
@ -177,23 +185,28 @@ textwindows void WinMainForked(void) {
|
||||||
_mmi.p = maps;
|
_mmi.p = maps;
|
||||||
_mmi.n = specialz / sizeof(_mmi.p[0]);
|
_mmi.n = specialz / sizeof(_mmi.p[0]);
|
||||||
for (i = 0; i < mapcount; ++i) {
|
for (i = 0; i < mapcount; ++i) {
|
||||||
VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
|
if (!VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
|
||||||
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot);
|
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot)) {
|
||||||
|
KillForkChild("VirtualProtect");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// mitosis complete
|
// mitosis complete
|
||||||
CloseHandle(reader);
|
if (!CloseHandle(reader)) {
|
||||||
|
KillForkChild("CloseHandle");
|
||||||
|
}
|
||||||
|
|
||||||
// rewrap the stdin named pipe hack
|
// rewrap the stdin named pipe hack
|
||||||
// since the handles closed on fork
|
// since the handles closed on fork
|
||||||
if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)();
|
if (weaken(ForkNtStdinWorker)) weaken(ForkNtStdinWorker)();
|
||||||
struct Fds *fds = VEIL("r", &g_fds);
|
struct Fds *fds = VEIL("r", &g_fds);
|
||||||
fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle); // just in case
|
fds->__init_p[0].handle = GetStdHandle(kNtStdInputHandle);
|
||||||
fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle); // just in case
|
fds->__init_p[1].handle = GetStdHandle(kNtStdOutputHandle);
|
||||||
fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle); // just in case
|
fds->__init_p[2].handle = GetStdHandle(kNtStdErrorHandle);
|
||||||
|
|
||||||
// restore the crash reporting stuff
|
// restore the crash reporting stuff
|
||||||
if (weaken(__wincrash_nt)) {
|
if (weaken(__wincrash_nt)) {
|
||||||
|
RemoveVectoredExceptionHandler(__wincrashearly);
|
||||||
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt));
|
AddVectoredExceptionHandler(1, (void *)weaken(__wincrash_nt));
|
||||||
}
|
}
|
||||||
if (weaken(__onntconsoleevent_nt)) {
|
if (weaken(__onntconsoleevent_nt)) {
|
||||||
|
|
|
@ -48,9 +48,8 @@ void ftrace_hook(void);
|
||||||
|
|
||||||
bool ftrace_enabled;
|
bool ftrace_enabled;
|
||||||
static int g_skew;
|
static int g_skew;
|
||||||
static int g_lastsymbol;
|
static int64_t g_lastaddr;
|
||||||
static uint64_t laststamp;
|
static uint64_t g_laststamp;
|
||||||
static struct SymbolTable *g_symbols;
|
|
||||||
|
|
||||||
static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
|
static privileged noinstrument noasan noubsan int GetNestingLevelImpl(
|
||||||
struct StackFrame *frame) {
|
struct StackFrame *frame) {
|
||||||
|
@ -80,34 +79,31 @@ static privileged noinstrument noasan noubsan int GetNestingLevel(
|
||||||
*/
|
*/
|
||||||
privileged noinstrument noasan noubsan void ftracer(void) {
|
privileged noinstrument noasan noubsan void ftracer(void) {
|
||||||
/* asan runtime depends on this function */
|
/* asan runtime depends on this function */
|
||||||
int symbol;
|
|
||||||
uint64_t stamp;
|
uint64_t stamp;
|
||||||
static bool noreentry;
|
static bool noreentry;
|
||||||
struct StackFrame *frame;
|
struct StackFrame *frame;
|
||||||
if (!_cmpxchg(&noreentry, 0, 1)) return;
|
if (!_cmpxchg(&noreentry, 0, 1)) return;
|
||||||
if (ftrace_enabled && g_symbols) {
|
if (ftrace_enabled) {
|
||||||
stamp = rdtsc();
|
stamp = rdtsc();
|
||||||
frame = __builtin_frame_address(0);
|
frame = __builtin_frame_address(0);
|
||||||
frame = frame->next;
|
frame = frame->next;
|
||||||
if ((symbol = __get_symbol(g_symbols, frame->addr)) != -1 &&
|
if (frame->addr != g_lastaddr) {
|
||||||
symbol != g_lastsymbol) {
|
kprintf("+ %*s%t %d\r\n", GetNestingLevel(frame) * 2, "", frame->addr,
|
||||||
g_lastsymbol = symbol;
|
(long)(unsignedsubtract(stamp, g_laststamp) / 3.3));
|
||||||
kprintf("+ %*s%s %d\r\n", GetNestingLevel(frame) * 2, "",
|
g_laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
||||||
__get_symbol_name(g_symbols, symbol),
|
g_lastaddr = frame->addr;
|
||||||
(long)(unsignedsubtract(stamp, laststamp) / 3.3));
|
|
||||||
laststamp = X86_HAVE(RDTSCP) ? rdtscp(0) : rdtsc();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
noreentry = 0;
|
noreentry = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup void ftrace_install(void) {
|
textstartup void ftrace_install(void) {
|
||||||
if ((g_symbols = GetSymbolTable())) {
|
if (GetSymbolTable()) {
|
||||||
laststamp = kStartTsc;
|
g_lastaddr = -1;
|
||||||
g_lastsymbol = -1;
|
g_laststamp = kStartTsc;
|
||||||
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
g_skew = GetNestingLevelImpl(__builtin_frame_address(0));
|
||||||
ftrace_enabled = 1;
|
ftrace_enabled = 1;
|
||||||
__hook(ftrace_hook, g_symbols);
|
__hook(ftrace_hook, GetSymbolTable());
|
||||||
} else {
|
} else {
|
||||||
kprintf("error: --ftrace failed to open symbol table\r\n");
|
kprintf("error: --ftrace failed to open symbol table\r\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ char *GetInterpreterExecutableName(char *p, size_t n) {
|
||||||
e = errno;
|
e = errno;
|
||||||
if (n < 2) {
|
if (n < 2) {
|
||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
} else if (IsWindows()) {
|
} else if (IsWindows() || IsXnu()) {
|
||||||
if (strlen(GetProgramExecutableName()) < n) {
|
if (strlen(GetProgramExecutableName()) < n) {
|
||||||
strcpy(p, GetProgramExecutableName());
|
strcpy(p, GetProgramExecutableName());
|
||||||
return p;
|
return p;
|
||||||
|
|
|
@ -29,10 +29,12 @@
|
||||||
#include "libc/zip.h"
|
#include "libc/zip.h"
|
||||||
#include "libc/zipos/zipos.internal.h"
|
#include "libc/zipos/zipos.internal.h"
|
||||||
|
|
||||||
|
static struct SymbolTable *g_symtab;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Looks for `.symtab` in zip central directory.
|
* 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;
|
size_t i, n, c;
|
||||||
c = GetZipCdirOffset(zipos->cdir);
|
c = GetZipCdirOffset(zipos->cdir);
|
||||||
n = GetZipCdirRecords(zipos->cdir);
|
n = GetZipCdirRecords(zipos->cdir);
|
||||||
|
@ -51,7 +53,7 @@ noasan static ssize_t FindSymtabInZip(struct Zipos *zipos) {
|
||||||
* Reads symbol table from zip directory.
|
* Reads symbol table from zip directory.
|
||||||
* @note This code can't depend on dlmalloc()
|
* @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;
|
ssize_t cf, lf;
|
||||||
size_t size, size2;
|
size_t size, size2;
|
||||||
struct DeflateState ds;
|
struct DeflateState ds;
|
||||||
|
@ -88,7 +90,7 @@ noasan static struct SymbolTable *GetSymbolTableFromZip(struct Zipos *zipos) {
|
||||||
* Reads symbol table from .com.dbg file.
|
* Reads symbol table from .com.dbg file.
|
||||||
* @note This code can't depend on dlmalloc()
|
* @note This code can't depend on dlmalloc()
|
||||||
*/
|
*/
|
||||||
noasan static struct SymbolTable *GetSymbolTableFromElf(void) {
|
static struct SymbolTable *GetSymbolTableFromElf(void) {
|
||||||
return OpenSymbolTable(FindDebugBinary());
|
return OpenSymbolTable(FindDebugBinary());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -112,24 +114,56 @@ noasan static struct SymbolTable *GetSymbolTableFromElf(void) {
|
||||||
*
|
*
|
||||||
* @return symbol table, or NULL w/ errno on first call
|
* @return symbol table, or NULL w/ errno on first call
|
||||||
*/
|
*/
|
||||||
noasan struct SymbolTable *GetSymbolTable(void) {
|
struct SymbolTable *GetSymbolTable(void) {
|
||||||
int ft, st;
|
int ft, st;
|
||||||
struct Zipos *z;
|
struct Zipos *z;
|
||||||
static struct SymbolTable *t;
|
if (!g_symtab) {
|
||||||
if (!t) {
|
|
||||||
ft = g_ftrace, g_ftrace = 0;
|
ft = g_ftrace, g_ftrace = 0;
|
||||||
st = __strace, __strace = 0;
|
st = __strace, __strace = 0;
|
||||||
if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) {
|
if (weaken(__zipos_get) && (z = weaken(__zipos_get)())) {
|
||||||
if ((t = GetSymbolTableFromZip(z))) {
|
if ((g_symtab = GetSymbolTableFromZip(z))) {
|
||||||
t->names = (uint32_t *)((char *)t + t->names_offset);
|
g_symtab->names =
|
||||||
t->name_base = (char *)((char *)t + t->name_base_offset);
|
(uint32_t *)((char *)g_symtab + g_symtab->names_offset);
|
||||||
|
g_symtab->name_base =
|
||||||
|
(char *)((char *)g_symtab + g_symtab->name_base_offset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!t) {
|
if (!g_symtab) {
|
||||||
t = GetSymbolTableFromElf();
|
g_symtab = GetSymbolTableFromElf();
|
||||||
}
|
}
|
||||||
g_ftrace = ft;
|
g_ftrace = ft;
|
||||||
__strace = st;
|
__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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
q = sys_mremap((void *)p, n, m, MREMAP_MAYMOVE | MREMAP_FIXED,
|
||||||
(void *)ADDR(a));
|
(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);
|
MREMAP_MAYMOVE | MREMAP_FIXED, ADDR(a), q);
|
||||||
if (q == MAP_FAILED) return 0;
|
if (q == MAP_FAILED) return 0;
|
||||||
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
|
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
|
||||||
|
|
|
@ -100,6 +100,7 @@ long GetResourceLimit(int);
|
||||||
long GetMaxFd(void);
|
long GetMaxFd(void);
|
||||||
char *GetProgramExecutableName(void);
|
char *GetProgramExecutableName(void);
|
||||||
char *GetInterpreterExecutableName(char *, size_t);
|
char *GetInterpreterExecutableName(char *, size_t);
|
||||||
|
void __printargs(const char *);
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -75,11 +75,13 @@ o/$(MODE)/libc/runtime/hook.greg.o \
|
||||||
o/$(MODE)/libc/runtime/isheap.o \
|
o/$(MODE)/libc/runtime/isheap.o \
|
||||||
o/$(MODE)/libc/runtime/memtrack.o \
|
o/$(MODE)/libc/runtime/memtrack.o \
|
||||||
o/$(MODE)/libc/runtime/memtracknt.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/mman.greg.o \
|
||||||
o/$(MODE)/libc/runtime/print.greg.o \
|
o/$(MODE)/libc/runtime/print.greg.o \
|
||||||
o/$(MODE)/libc/runtime/stackchkfail.o \
|
o/$(MODE)/libc/runtime/stackchkfail.o \
|
||||||
o/$(MODE)/libc/runtime/stackchkfaillocal.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 += \
|
OVERRIDE_CFLAGS += \
|
||||||
-ffreestanding \
|
-ffreestanding \
|
||||||
$(NO_MAGIC)
|
$(NO_MAGIC)
|
||||||
|
@ -90,13 +92,6 @@ o/$(MODE)/libc/runtime/fork-nt.o: \
|
||||||
OVERRIDE_CPPFLAGS += \
|
OVERRIDE_CPPFLAGS += \
|
||||||
-DSTACK_FRAME_UNLIMITED
|
-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: \
|
o/$(MODE)/libc/runtime/qsort.o: \
|
||||||
OVERRIDE_CFLAGS += \
|
OVERRIDE_CFLAGS += \
|
||||||
-Og
|
-Og
|
||||||
|
|
|
@ -120,7 +120,7 @@ forceinline void MakeLongDoubleLongAgain(void) {
|
||||||
asm volatile("fldcw\t%0" : /* no outputs */ : "m"(x87cw));
|
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;
|
uint32_t wrote;
|
||||||
char buf[64], *p = buf;
|
char buf[64], *p = buf;
|
||||||
*p++ = 'c';
|
*p++ = 'c';
|
||||||
|
@ -158,15 +158,16 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
||||||
if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) {
|
if ((intptr_t)v_ntsubsystem == kNtImageSubsystemWindowsCui && version >= 10) {
|
||||||
__winmainpid = __pid;
|
__winmainpid = __pid;
|
||||||
rc = SetConsoleCP(kNtCpUtf8);
|
rc = SetConsoleCP(kNtCpUtf8);
|
||||||
STRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc);
|
NTTRACE("SetConsoleCP(kNtCpUtf8) → %hhhd", rc);
|
||||||
rc = SetConsoleOutputCP(kNtCpUtf8);
|
rc = SetConsoleOutputCP(kNtCpUtf8);
|
||||||
STRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc);
|
NTTRACE("SetConsoleOutputCP(kNtCpUtf8) → %hhhd", rc);
|
||||||
for (i = 0; i < 3; ++i) {
|
for (i = 0; i < 3; ++i) {
|
||||||
hand = GetStdHandle(kConsoleHandles[i]);
|
hand = GetStdHandle(kConsoleHandles[i]);
|
||||||
rc = GetConsoleMode(hand, __ntconsolemode + 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]);
|
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;
|
_mmi.p = _mmi.s;
|
||||||
|
@ -176,8 +177,8 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
||||||
stacksize = GetStackSize();
|
stacksize = GetStackSize();
|
||||||
allocsize = argsize + stacksize;
|
allocsize = argsize + stacksize;
|
||||||
allocaddr = stackaddr - argsize;
|
allocaddr = stackaddr - argsize;
|
||||||
STRACE("WinMainNew() mapping %'zu byte arg block + stack at %p", allocsize,
|
NTTRACE("WinMainNew() mapping %'zu byte arg block + stack at %p", allocsize,
|
||||||
allocaddr);
|
allocaddr);
|
||||||
MapViewOfFileEx(
|
MapViewOfFileEx(
|
||||||
(_mmi.p[0].h =
|
(_mmi.p[0].h =
|
||||||
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
|
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
|
||||||
|
@ -194,7 +195,7 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
||||||
_mmi.p[0].size = allocsize;
|
_mmi.p[0].size = allocsize;
|
||||||
_mmi.i = 1;
|
_mmi.i = 1;
|
||||||
wa = (struct WinArgs *)allocaddr;
|
wa = (struct WinArgs *)allocaddr;
|
||||||
STRACE("WinMainNew() loading arg block");
|
NTTRACE("WinMainNew() loading arg block");
|
||||||
count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), wa->argv,
|
count = GetDosArgv(cmdline, wa->argblock, ARRAYLEN(wa->argblock), wa->argv,
|
||||||
ARRAYLEN(wa->argv));
|
ARRAYLEN(wa->argv));
|
||||||
for (i = 0; wa->argv[0][i]; ++i) {
|
for (i = 0; wa->argv[0][i]; ++i) {
|
||||||
|
@ -203,13 +204,11 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
env16 = GetEnvironmentStrings();
|
env16 = GetEnvironmentStrings();
|
||||||
STRACE("WinMainNew() loading environment");
|
NTTRACE("WinMainNew() loading environment");
|
||||||
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
GetDosEnviron(env16, wa->envblock, ARRAYLEN(wa->envblock) - 8, wa->envp,
|
||||||
ARRAYLEN(wa->envp) - 1);
|
ARRAYLEN(wa->envp) - 1);
|
||||||
FreeEnvironmentStrings(env16);
|
FreeEnvironmentStrings(env16);
|
||||||
wa->auxv[0][0] = pushpop(AT_EXECFN);
|
NTTRACE("WinMainNew() switching stacks");
|
||||||
wa->auxv[0][1] = (intptr_t)wa->argv[0];
|
|
||||||
STRACE("WinMainNew() switching stacks");
|
|
||||||
_jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo,
|
_jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo,
|
||||||
count, wa->argv, wa->envp, wa->auxv);
|
count, wa->argv, wa->envp, wa->auxv);
|
||||||
}
|
}
|
||||||
|
@ -255,13 +254,13 @@ __msabi textwindows int64_t WinMain(int64_t hInstance, int64_t hPrevInstance,
|
||||||
ts = rdtsc();
|
ts = rdtsc();
|
||||||
__nomultics = true;
|
__nomultics = true;
|
||||||
__pid = GetCurrentProcessId();
|
__pid = GetCurrentProcessId();
|
||||||
__wincrashearly = AddVectoredExceptionHandler(1, (void *)WinCrashEarly);
|
__wincrashearly = AddVectoredExceptionHandler(1, (void *)OnEarlyWinCrash);
|
||||||
cmdline = GetCommandLine();
|
cmdline = GetCommandLine();
|
||||||
#ifdef SYSDEBUG
|
#ifdef SYSDEBUG
|
||||||
/* sloppy flag-only check for early initialization */
|
/* sloppy flag-only check for early initialization */
|
||||||
if (__strstr16(cmdline, u"--strace")) ++__strace;
|
if (__strstr16(cmdline, u"--strace")) ++__strace;
|
||||||
#endif
|
#endif
|
||||||
STRACE("WinMain()");
|
NTTRACE("WinMain()");
|
||||||
MakeLongDoubleLongAgain();
|
MakeLongDoubleLongAgain();
|
||||||
if (weaken(WinSockInit)) weaken(WinSockInit)();
|
if (weaken(WinSockInit)) weaken(WinSockInit)();
|
||||||
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
if (weaken(WinMainForked)) weaken(WinMainForked)();
|
||||||
|
|
|
@ -144,6 +144,7 @@ ssize_t sys_recvfrom_nt(struct Fd *, const struct iovec *, size_t, uint32_t,
|
||||||
void WinSockInit(void) hidden;
|
void WinSockInit(void) hidden;
|
||||||
int64_t __winsockerr(void) nocallback hidden;
|
int64_t __winsockerr(void) nocallback hidden;
|
||||||
int __fixupnewsockfd(int, int) 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;
|
int64_t __winsockblock(int64_t, unsigned, int64_t) hidden;
|
||||||
struct SockFd *_dupsockfd(struct SockFd *) hidden;
|
struct SockFd *_dupsockfd(struct SockFd *) hidden;
|
||||||
int64_t GetNtBaseSocket(int64_t) hidden;
|
int64_t GetNtBaseSocket(int64_t) hidden;
|
||||||
|
|
|
@ -39,7 +39,7 @@ hidden struct NtWsaData kNtWsaData;
|
||||||
|
|
||||||
static textwindows void WinSockCleanup(void) {
|
static textwindows void WinSockCleanup(void) {
|
||||||
int i, rc;
|
int i, rc;
|
||||||
STRACE("WinSockCleanup()");
|
NTTRACE("WinSockCleanup()");
|
||||||
for (i = g_fds.n; i--;) {
|
for (i = g_fds.n; i--;) {
|
||||||
if (g_fds.p[i].kind == kFdSocket) {
|
if (g_fds.p[i].kind == kFdSocket) {
|
||||||
close(i);
|
close(i);
|
||||||
|
@ -47,13 +47,13 @@ static textwindows void WinSockCleanup(void) {
|
||||||
}
|
}
|
||||||
// TODO(jart): Check WSACleanup() result code
|
// TODO(jart): Check WSACleanup() result code
|
||||||
rc = WSACleanup();
|
rc = WSACleanup();
|
||||||
STRACE("WSACleanup() → %d% lm", rc);
|
NTTRACE("WSACleanup() → %d% lm", rc);
|
||||||
}
|
}
|
||||||
|
|
||||||
textwindows noasan void WinSockInit(void) {
|
textwindows noasan void WinSockInit(void) {
|
||||||
int rc;
|
int rc;
|
||||||
atexit(WinSockCleanup);
|
atexit(WinSockCleanup);
|
||||||
STRACE("WSAStartup()");
|
NTTRACE("WSAStartup()");
|
||||||
if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 ||
|
if ((rc = WSAStartup(VERSION, &kNtWsaData)) != 0 ||
|
||||||
kNtWsaData.wVersion != VERSION) {
|
kNtWsaData.wVersion != VERSION) {
|
||||||
ExitProcess(123);
|
ExitProcess(123);
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#define ShouldUseMsabiAttribute() 1
|
|
||||||
#include "libc/assert.h"
|
#include "libc/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
|
@ -41,41 +40,34 @@
|
||||||
* @fileoverview Pollable Standard Input for the New Technology.
|
* @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) {
|
static textwindows uint32_t StdinWorkerThread(void *arg) {
|
||||||
char buf[512];
|
char buf[512];
|
||||||
bool32 ok = true;
|
bool32 ok = true;
|
||||||
uint32_t i, rc, got, err, wrote;
|
uint32_t i, rc, got, err, wrote;
|
||||||
struct NtStdinWorker w, *wp = arg;
|
struct NtStdinWorker w, *wp = arg;
|
||||||
STRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader,
|
NTTRACE("StdinWorkerThread(%ld → %ld → %ld) pid %d tid %d", wp->reader,
|
||||||
wp->writer, wp->consumer, getpid(), gettid());
|
wp->writer, wp->consumer, getpid(), gettid());
|
||||||
__sync_lock_release(&wp->sync);
|
__sync_lock_release(&wp->sync);
|
||||||
w = *wp;
|
w = *wp;
|
||||||
do {
|
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
|
/* When writing to a non-blocking, byte-mode pipe handle with
|
||||||
insufficient buffer space, WriteFile returns TRUE with
|
insufficient buffer space, WriteFile returns TRUE with
|
||||||
*lpNumberOfBytesWritten < nNumberOfBytesToWrite.
|
*lpNumberOfBytesWritten < nNumberOfBytesToWrite.
|
||||||
──Quoth MSDN WriteFile() */
|
──Quoth MSDN WriteFile() */
|
||||||
for (i = 0; ok && i < got; i += wrote) {
|
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);
|
} while (ok && got);
|
||||||
|
err = GetLastError();
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
err = __imp_GetLastError();
|
|
||||||
if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe ||
|
if (err == kNtErrorHandleEof || err == kNtErrorBrokenPipe ||
|
||||||
err == kNtErrorNoData) {
|
err == kNtErrorNoData) {
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
STRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %d", w.reader, w.writer,
|
NTTRACE("StdinWorkerThread(%ld → %ld → %ld) → %hhhd %u", w.reader, w.writer,
|
||||||
w.consumer, __imp_GetLastError());
|
w.consumer, err);
|
||||||
return !ok;
|
return !ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,7 +79,7 @@ static textwindows uint32_t StdinWorkerThread(void *arg) {
|
||||||
*/
|
*/
|
||||||
textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) {
|
textwindows struct NtStdinWorker *NewNtStdinWorker(int fd) {
|
||||||
struct NtStdinWorker *w;
|
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(!g_fds.p[fd].worker);
|
||||||
assert(__isfdopen(fd));
|
assert(__isfdopen(fd));
|
||||||
if (!(w = calloc(1, sizeof(struct NtStdinWorker)))) return 0;
|
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) {
|
textwindows bool UnrefNtStdinWorker(struct NtStdinWorker *w) {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if (__atomic_sub_fetch(&w->refs, 1, __ATOMIC_SEQ_CST)) return 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->writer)) ok = false;
|
||||||
if (!CloseHandle(w->reader)) ok = false;
|
if (!CloseHandle(w->reader)) ok = false;
|
||||||
if (!CloseHandle(w->worker)) ok = false;
|
if (!CloseHandle(w->worker)) ok = false;
|
||||||
|
|
|
@ -24,11 +24,14 @@
|
||||||
#include "libc/calls/sigbits.h"
|
#include "libc/calls/sigbits.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/sigaction.h"
|
#include "libc/calls/struct/sigaction.h"
|
||||||
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/intrin/spinlock.h"
|
#include "libc/intrin/spinlock.h"
|
||||||
#include "libc/macros.internal.h"
|
#include "libc/macros.internal.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
|
#include "libc/nt/enum/filetype.h"
|
||||||
#include "libc/nt/errors.h"
|
#include "libc/nt/errors.h"
|
||||||
|
#include "libc/nt/files.h"
|
||||||
#include "libc/nt/ipc.h"
|
#include "libc/nt/ipc.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/struct/pollfd.h"
|
#include "libc/nt/struct/pollfd.h"
|
||||||
|
@ -37,13 +40,11 @@
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/ntstdin.internal.h"
|
#include "libc/sock/ntstdin.internal.h"
|
||||||
#include "libc/sock/yoink.inc"
|
#include "libc/sock/yoink.inc"
|
||||||
|
#include "libc/sysv/consts/o.h"
|
||||||
#include "libc/sysv/consts/poll.h"
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/sig.h"
|
#include "libc/sysv/consts/sig.h"
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
#undef STRACE // too verbosen
|
|
||||||
#define STRACE(...) // but don't want to delete
|
|
||||||
|
|
||||||
_Alignas(64) static char poll_lock;
|
_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];
|
struct sys_pollfd_nt sockfds[64];
|
||||||
int pipeindices[ARRAYLEN(pipefds)];
|
int pipeindices[ARRAYLEN(pipefds)];
|
||||||
int sockindices[ARRAYLEN(sockfds)];
|
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
|
// check for interrupts early before doing work
|
||||||
if (_check_interrupts(false, g_fds.p)) return eintr();
|
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 need to read static variables
|
||||||
// we might need to spawn threads and open pipes
|
// we might need to spawn threads and open pipes
|
||||||
_spinlock(&poll_lock);
|
_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 (fds[i].fd < 0) continue;
|
||||||
if (__isfdopen(fds[i].fd)) {
|
if (__isfdopen(fds[i].fd)) {
|
||||||
if (__isfdkind(fds[i].fd, kFdSocket)) {
|
if (__isfdkind(fds[i].fd, kFdSocket)) {
|
||||||
if (sn < ARRAYLEN(sockfds)) {
|
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;
|
sockindices[sn] = i;
|
||||||
sockfds[sn].handle = g_fds.p[fds[i].fd].handle;
|
sockfds[sn].handle = g_fds.p[fds[i].fd].handle;
|
||||||
sockfds[sn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT);
|
sockfds[sn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT);
|
||||||
sn += 1;
|
sockfds[sn].revents = 0;
|
||||||
|
++sn;
|
||||||
} else {
|
} else {
|
||||||
// too many socket fds
|
// too many socket fds
|
||||||
failed = enomem();
|
failed = enomem();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (fds[i].events & POLLIN) {
|
} else if (pn < ARRAYLEN(pipefds)) {
|
||||||
if (!g_fds.p[fds[i].fd].worker) {
|
pipeindices[pn] = i;
|
||||||
if (!(g_fds.p[fds[i].fd].worker = NewNtStdinWorker(fds[i].fd))) {
|
pipefds[pn].handle = g_fds.p[fds[i].fd].handle;
|
||||||
// failed to launch stdin worker
|
pipefds[pn].events = 0;
|
||||||
failed = -1;
|
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;
|
break;
|
||||||
}
|
case O_WRONLY:
|
||||||
}
|
pipefds[pn].events = fds[i].events & POLLOUT;
|
||||||
if (pn < ARRAYLEN(pipefds)) {
|
break;
|
||||||
pipeindices[pn] = i;
|
case O_RDWR:
|
||||||
pipefds[pn].handle = g_fds.p[fds[i].fd].handle;
|
pipefds[pn].events = fds[i].events & (POLLIN | POLLOUT);
|
||||||
pipefds[pn].events = fds[i].events & (POLLPRI | POLLIN | POLLOUT);
|
break;
|
||||||
pn += 1;
|
default:
|
||||||
} else {
|
unreachable;
|
||||||
// too many non-socket fds
|
|
||||||
failed = enomem();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
++pn;
|
||||||
} else {
|
} else {
|
||||||
// non-sock w/o pollin
|
// too many non-socket fds
|
||||||
failed = enotsock();
|
failed = enomem();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// non-open file descriptor
|
++gotinvals;
|
||||||
failed = einval();
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
_spunlock(&__fds_lock);
|
||||||
_spunlock(&poll_lock);
|
_spunlock(&poll_lock);
|
||||||
if (failed) {
|
if (failed) {
|
||||||
// failed to create a polling solution
|
// 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 (;;) {
|
for (;;) {
|
||||||
// see if input is available on non-sockets
|
// see if input is available on non-sockets
|
||||||
for (gotpipes = i = 0; i < pn; ++i) {
|
for (gotpipes = i = 0; i < pn; ++i) {
|
||||||
ok = PeekNamedPipe(pipefds[i].handle, 0, 0, 0, &avail, 0);
|
if (pipefds[i].events & POLLOUT) {
|
||||||
STRACE("PeekNamedPipe(%ld, 0, 0, 0, [%'u], 0) → %hhhd% m",
|
// we have no way of polling if a non-socket is writeable yet
|
||||||
pipefds[i].handle, avail, ok);
|
// therefore we assume that if it can happen, it shall happen
|
||||||
if (ok) {
|
pipefds[i].revents = POLLOUT;
|
||||||
if (avail) {
|
}
|
||||||
pipefds[i].revents = POLLIN;
|
if (pipefds[i].events & POLLIN) {
|
||||||
gotpipes += 1;
|
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 {
|
} 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;
|
if (pipefds[i].revents) {
|
||||||
gotpipes += 1;
|
++gotpipes;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// if we haven't found any good results yet then here we
|
// if we haven't found any good results yet then here we
|
||||||
// compute a small time slice we don't mind sleeping for
|
// 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) {
|
if (sn) {
|
||||||
// we need to poll the socket handles separately because
|
// we need to poll the socket handles separately because
|
||||||
// microsoft certainly loves to challenge us with coding
|
// microsoft certainly loves to challenge us with coding
|
||||||
// please note that winsock will fail if we pass zero fd
|
// 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) {
|
if ((gotsocks = WSAPoll(sockfds, sn, waitfor)) == -1) {
|
||||||
return __winsockerr();
|
return __winsockerr();
|
||||||
}
|
}
|
||||||
*ms -= waitfor;
|
*ms -= waitfor;
|
||||||
} else {
|
} else {
|
||||||
gotsocks = 0;
|
gotsocks = 0;
|
||||||
if (!gotpipes && waitfor) {
|
if (!gotinvals && !gotpipes && waitfor) {
|
||||||
// if we've only got pipes and none of them are ready
|
// if we've only got pipes and none of them are ready
|
||||||
// then we'll just explicitly sleep for the time left
|
// then we'll just explicitly sleep for the time left
|
||||||
STRACE("SleepEx(%'d, false) out of %'lu", waitfor, *ms);
|
POLLTRACE("SleepEx(%'d, false) out of %'lu", waitfor, *ms);
|
||||||
if (SleepEx(waitfor, true) == kNtWaitIoCompletion) {
|
if (SleepEx(__SIG_POLLING_INTERVAL_MS, true) == kNtWaitIoCompletion) {
|
||||||
STRACE("IOCP TRIGGERED EINTR");
|
POLLTRACE("IOCP EINTR");
|
||||||
return eintr();
|
} else {
|
||||||
|
*ms -= waitfor;
|
||||||
}
|
}
|
||||||
*ms -= waitfor;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// we gave all the sockets and all the named pipes a shot
|
// 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 we found anything at all then it's time to end work
|
||||||
if (gotpipes || gotsocks || *ms <= 0) {
|
if (gotinvals || gotpipes || gotsocks || *ms <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// otherwise loop limitlessly for timeout to elapse while
|
// 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
|
// the system call is going to succeed
|
||||||
// assemble the result
|
// it's now ok to start setting the output memory
|
||||||
for (i = 0; i < pn; ++i) {
|
for (i = 0; i < nfds; ++i) {
|
||||||
fds[pipeindices[i]].revents =
|
if (fds[i].fd < 0 || __isfdopen(fds[i].fd)) {
|
||||||
pipefds[i].handle < 0 ? 0 : pipefds[i].revents;
|
fds[i].revents = 0;
|
||||||
}
|
} else {
|
||||||
for (i = 0; i < sn; ++i) {
|
fds[i].revents = POLLNVAL;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
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) {
|
// and finally return
|
||||||
atexit(__freefds_workers);
|
return gotinvals + gotpipes + gotsocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
const void *const __freefds_workers_ctor[] initarray = {
|
|
||||||
__freefds_workers_init,
|
|
||||||
};
|
|
||||||
|
|
|
@ -28,13 +28,35 @@
|
||||||
/**
|
/**
|
||||||
* Waits for something to happen on multiple file descriptors at once.
|
* 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[𝑖].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
|
* @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
|
* @return number of items fds whose revents field has been set to
|
||||||
* nonzero to describe its events, or -1 w/ errno
|
* nonzero to describe its events, or 0 if the timeout elapsed,
|
||||||
* @return fds[𝑖].revents flags can have:
|
* or -1 w/ errno
|
||||||
* (fds[𝑖].events & POLL{IN,OUT,PRI,HUP,ERR,NVAL})
|
* @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
|
* @asyncsignalsafe
|
||||||
* @threadsafe
|
* @threadsafe
|
||||||
* @norestart
|
* @norestart
|
||||||
|
|
|
@ -20,15 +20,22 @@
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/calls/struct/sigset.h"
|
#include "libc/calls/struct/sigset.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
#include "libc/dns/dns.h"
|
||||||
#include "libc/intrin/describeflags.internal.h"
|
#include "libc/intrin/describeflags.internal.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/macros.internal.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/enum/startf.h"
|
||||||
#include "libc/nt/runtime.h"
|
#include "libc/nt/runtime.h"
|
||||||
#include "libc/nt/startupinfo.h"
|
#include "libc/nt/startupinfo.h"
|
||||||
#include "libc/nt/struct/ldrdatatableentry.h"
|
#include "libc/nt/struct/ldrdatatableentry.h"
|
||||||
#include "libc/nt/struct/startupinfo.h"
|
#include "libc/nt/struct/startupinfo.h"
|
||||||
#include "libc/nt/struct/teb.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/runtime.h"
|
||||||
#include "libc/runtime/stack.h"
|
#include "libc/runtime/stack.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
|
@ -37,8 +44,16 @@
|
||||||
#include "libc/sysv/consts/f.h"
|
#include "libc/sysv/consts/f.h"
|
||||||
#include "libc/sysv/consts/poll.h"
|
#include "libc/sysv/consts/poll.h"
|
||||||
#include "libc/sysv/consts/sig.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 {
|
static const struct AuxiliaryValue {
|
||||||
const char *fmt;
|
const char *fmt;
|
||||||
|
@ -82,6 +97,15 @@ static const struct AuxiliaryValue {
|
||||||
{"%-14p", &AT_EHDRFLAGS, "AT_EHDRFLAGS"},
|
{"%-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) {
|
static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
|
||||||
int i;
|
int i;
|
||||||
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
|
for (i = 0; i < ARRAYLEN(kAuxiliaryValues); ++i) {
|
||||||
|
@ -92,46 +116,202 @@ static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
noasan textstartup void __printargs(void) {
|
/**
|
||||||
#ifdef SYSDEBUG
|
* Prints lots of information about this process, e.g.
|
||||||
int st;
|
*
|
||||||
|
* __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;
|
long key;
|
||||||
char **env;
|
char **env;
|
||||||
unsigned i;
|
|
||||||
sigset_t ss;
|
sigset_t ss;
|
||||||
|
unsigned i, n;
|
||||||
uintptr_t *auxp;
|
uintptr_t *auxp;
|
||||||
|
struct utsname uts;
|
||||||
char path[PATH_MAX];
|
char path[PATH_MAX];
|
||||||
|
int x, st, ft, flags;
|
||||||
struct pollfd pfds[128];
|
struct pollfd pfds[128];
|
||||||
struct AuxiliaryValue *auxinfo;
|
struct AuxiliaryValue *auxinfo;
|
||||||
if (__strace <= 0) return;
|
st = __strace, __strace = 0;
|
||||||
st = __strace;
|
ft = g_ftrace, g_ftrace = 0;
|
||||||
__strace = 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("");
|
||||||
PRINT("ARGUMENTS (%p)", __argv);
|
PRINT("ARGUMENTS (%p)", __argv);
|
||||||
for (i = 0; i < __argc; ++i) {
|
if (*__argv) {
|
||||||
PRINT(" ☼ %s", __argv[i]);
|
for (i = 0; i < __argc; ++i) {
|
||||||
|
PRINT(" ☼ %s", __argv[i]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(" none");
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINT("");
|
PRINT("");
|
||||||
PRINT("ENVIRONMENT (%p)", __envp);
|
PRINT("ENVIRONMENT (%p)", __envp);
|
||||||
for (env = __envp; *env; ++env) {
|
if (*__envp) {
|
||||||
PRINT(" ☼ %s", *env);
|
for (env = __envp; *env; ++env) {
|
||||||
|
PRINT(" ☼ %s", *env);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PRINT(" none");
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINT("");
|
PRINT("");
|
||||||
PRINT("AUXILIARY (%p)", __auxv);
|
PRINT("AUXILIARY (%p)", __auxv);
|
||||||
for (auxp = __auxv; *auxp; auxp += 2) {
|
if (*__auxv) {
|
||||||
if ((auxinfo = DescribeAuxv(auxp[0]))) {
|
if (*__auxv) {
|
||||||
ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]);
|
for (auxp = __auxv; *auxp; auxp += 2) {
|
||||||
PRINT(" ☼ %16s[%4ld] = %s", auxinfo->name, auxp[0], path);
|
if ((auxinfo = DescribeAuxv(auxp[0]))) {
|
||||||
} else {
|
ksnprintf(path, sizeof(path), auxinfo->fmt, auxp[1]);
|
||||||
PRINT(" ☼ %16s[%4ld] = %014p", "unknown", auxp[0], 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("");
|
||||||
PRINT("SPECIALS");
|
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", "kTmpPath", kTmpPath);
|
||||||
PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory);
|
PRINT(" ☼ %s = %#s", "kNtSystemDirectory", kNtSystemDirectory);
|
||||||
PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory);
|
PRINT(" ☼ %s = %#s", "kNtWindowsDirectory", kNtWindowsDirectory);
|
||||||
|
@ -143,31 +323,9 @@ noasan textstartup void __printargs(void) {
|
||||||
PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0));
|
PRINT(" ☼ %s = %p", "GetStaticStackAddr(0)", GetStaticStackAddr(0));
|
||||||
PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize());
|
PRINT(" ☼ %s = %p", "GetStackSize()", GetStackSize());
|
||||||
|
|
||||||
if (!IsWindows()) {
|
PRINT("");
|
||||||
PRINT("");
|
PRINT("MEMTRACK");
|
||||||
PRINT("OPEN FILE DESCRIPTORS");
|
PrintMemoryIntervals(2, &_mmi);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (IsWindows()) {
|
if (IsWindows()) {
|
||||||
struct NtStartupInfo startinfo;
|
struct NtStartupInfo startinfo;
|
||||||
|
@ -234,12 +392,12 @@ noasan textstartup void __printargs(void) {
|
||||||
do {
|
do {
|
||||||
const struct NtLdrDataTableEntry *dll =
|
const struct NtLdrDataTableEntry *dll =
|
||||||
(const struct NtLdrDataTableEntry *)ldr;
|
(const struct NtLdrDataTableEntry *)ldr;
|
||||||
PRINT(" ☼ %.*!hs\t\t%'zu bytes", dll->FullDllName.Length,
|
PRINT(" ☼ %.*!hs (%'zukb)", dll->FullDllName.Length,
|
||||||
dll->FullDllName.Data, dll->SizeOfImage);
|
dll->FullDllName.Data, dll->SizeOfImage / 1024);
|
||||||
} while ((ldr = ldr->Next) && ldr != head);
|
} while ((ldr = ldr->Next) && ldr != head);
|
||||||
}
|
}
|
||||||
|
|
||||||
PRINT("");
|
PRINT("");
|
||||||
__strace = st;
|
__strace = st;
|
||||||
#endif
|
g_ftrace = ft;
|
||||||
}
|
}
|
|
@ -16,19 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/bits/weaken.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/struct/iovec.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/nt/struct/overlapped.h"
|
#include "libc/nt/struct/overlapped.h"
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/yoink.inc"
|
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,51 +32,16 @@
|
||||||
textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
textwindows ssize_t sys_recv_nt(struct Fd *fd, const struct iovec *iov,
|
||||||
size_t iovlen, uint32_t flags) {
|
size_t iovlen, uint32_t flags) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t i, got = 0;
|
uint32_t got = 0;
|
||||||
struct NtIovec iovnt[16];
|
struct NtIovec iovnt[16];
|
||||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||||
|
|
||||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||||
|
|
||||||
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags,
|
if (!WSARecv(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got, &flags,
|
||||||
&overlapped, NULL)) {
|
&overlapped, NULL)) {
|
||||||
rc = got;
|
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);
|
WSACloseEvent(overlapped.hEvent);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/nt/enum/wait.h"
|
|
||||||
#include "libc/nt/errors.h"
|
|
||||||
#include "libc/nt/struct/overlapped.h"
|
#include "libc/nt/struct/overlapped.h"
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/sock/internal.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,
|
void *opt_out_srcaddr,
|
||||||
uint32_t *opt_inout_srcaddrsize) {
|
uint32_t *opt_inout_srcaddrsize) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t i, got = 0;
|
uint32_t got = 0;
|
||||||
struct NtIovec iovnt[16];
|
struct NtIovec iovnt[16];
|
||||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||||
|
|
||||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||||
|
|
||||||
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got,
|
if (!WSARecvFrom(fd->handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &got,
|
||||||
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
|
&flags, opt_out_srcaddr, opt_inout_srcaddrsize, &overlapped,
|
||||||
NULL)) {
|
NULL)) {
|
||||||
rc = got;
|
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);
|
WSACloseEvent(overlapped.hEvent);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,8 +22,11 @@
|
||||||
#include "libc/sock/select.h"
|
#include "libc/sock/select.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does what poll() does except with a complicated bitset API.
|
* Does what poll() does except with bitset API.
|
||||||
* @note windows nt is limited to first 64 socket descriptors
|
*
|
||||||
|
* 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,
|
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
||||||
struct timeval *timeout) {
|
struct timeval *timeout) {
|
||||||
|
|
|
@ -16,17 +16,11 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/calls/calls.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/nt/struct/overlapped.h"
|
||||||
#include "libc/nt/enum/wait.h"
|
|
||||||
#include "libc/nt/errors.h"
|
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/yoink.inc"
|
|
||||||
#include "libc/sysv/consts/fileno.h"
|
|
||||||
#include "libc/sysv/errfuns.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,
|
textwindows ssize_t sys_send_nt(int fd, const struct iovec *iov, size_t iovlen,
|
||||||
uint32_t flags) {
|
uint32_t flags) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t i, sent = 0;
|
uint32_t sent = 0;
|
||||||
struct NtIovec iovnt[16];
|
struct NtIovec iovnt[16];
|
||||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||||
|
|
||||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||||
|
|
||||||
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent,
|
if (!WSASend(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen), &sent,
|
||||||
flags, &overlapped, NULL)) {
|
flags, &overlapped, NULL)) {
|
||||||
rc = sent;
|
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);
|
WSACloseEvent(overlapped.hEvent);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,10 +16,8 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/calls/sig.internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/struct/iovec.h"
|
||||||
#include "libc/nt/enum/wait.h"
|
|
||||||
#include "libc/nt/errors.h"
|
|
||||||
#include "libc/nt/struct/overlapped.h"
|
#include "libc/nt/struct/overlapped.h"
|
||||||
#include "libc/nt/winsock.h"
|
#include "libc/nt/winsock.h"
|
||||||
#include "libc/sock/internal.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,
|
size_t iovlen, uint32_t flags,
|
||||||
void *opt_in_addr, uint32_t in_addrsize) {
|
void *opt_in_addr, uint32_t in_addrsize) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t i, sent = 0;
|
uint32_t sent = 0;
|
||||||
struct NtIovec iovnt[16];
|
struct NtIovec iovnt[16];
|
||||||
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
struct NtOverlapped overlapped = {.hEvent = WSACreateEvent()};
|
||||||
|
|
||||||
if (_check_interrupts(true, g_fds.p)) return eintr();
|
if (_check_interrupts(true, g_fds.p)) return eintr();
|
||||||
|
|
||||||
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen),
|
if (!WSASendTo(g_fds.p[fd].handle, iovnt, __iovec2nt(iovnt, iov, iovlen),
|
||||||
&sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
|
&sent, flags, opt_in_addr, in_addrsize, &overlapped, NULL)) {
|
||||||
rc = sent;
|
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);
|
WSACloseEvent(overlapped.hEvent);
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
44
libc/sock/stdinworker.c
Normal file
44
libc/sock/stdinworker.c
Normal file
|
@ -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,
|
||||||
|
};
|
52
libc/sock/wsablock.c
Normal file
52
libc/sock/wsablock.c
Normal file
|
@ -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;
|
||||||
|
}
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.internal.inc"
|
|
||||||
.scall getegid,0xfff02b02b202b06c,globl
|
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.internal.inc"
|
|
||||||
.scall getpgrp,0x051051051205106f,globl
|
|
2
libc/sysv/calls/sys_getegid.s
Normal file
2
libc/sysv/calls/sys_getegid.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "o/libc/sysv/macros.internal.inc"
|
||||||
|
.scall sys_getegid,0x02b02b02b202b06c,globl,hidden
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue