mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-13 06:29:11 +00:00
Make fixes and improvements
- Introduce __assert_disable global - Improve strsignal() thread safety - Make system call tracing thread safe - Fix SO_RCVTIMEO / SO_SNDTIMEO on Windows - Refactor DescribeFoo() functions into one place - Fix fork() on Windows when TLS and MAP_STACK exist - Round upwards in setsockopt(SO_RCVTIMEO) on Windows - Disable futexes on OpenBSD which seem extremely broken - Implement a better kludge for monotonic time on Windows
This commit is contained in:
parent
5d837c4e7c
commit
fbc053e018
186 changed files with 1836 additions and 1325 deletions
45
libc/runtime/clone-openbsd.S
Normal file
45
libc/runtime/clone-openbsd.S
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
|
||||
│vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
|
||||
|
||||
#define SYS___tfork 8
|
||||
|
||||
// Creates thread on OpenBSD.
|
||||
//
|
||||
// @param rdi is params
|
||||
// @param rsi is size of params
|
||||
// @param rdx is start function
|
||||
// @param rcx is start parameter
|
||||
// @return thread id or negative errno
|
||||
__tfork_thread:
|
||||
mov %rdx,%r8
|
||||
mov %rcx,%r9
|
||||
mov $SYS___tfork,%eax
|
||||
syscall
|
||||
jc 2f
|
||||
test %eax,%eax
|
||||
jz 1f
|
||||
ret
|
||||
1: xor %ebp,%ebp
|
||||
mov %r9,%rdi
|
||||
jmp *%r8
|
||||
.unreachable
|
||||
2: neg %eax
|
||||
ret
|
||||
.endfn __tfork_thread,globl
|
|
@ -20,12 +20,15 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/ucontext-netbsd.internal.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nexgen32e/gettls.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
|
@ -39,6 +42,7 @@
|
|||
#include "libc/sysv/consts/nrlinux.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/thread/freebsd.internal.h"
|
||||
#include "libc/thread/openbsd.internal.h"
|
||||
#include "libc/thread/xnu.internal.h"
|
||||
|
||||
STATIC_YOINK("gettid"); // for kprintf()
|
||||
|
@ -261,35 +265,8 @@ static int CloneFreebsd(int (*func)(void *), char *stk, size_t stksz, int flags,
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// OPEN BESIYATA DISHMAYA
|
||||
|
||||
struct __tfork {
|
||||
void *tf_tcb;
|
||||
int32_t *tf_tid;
|
||||
void *tf_stack;
|
||||
};
|
||||
|
||||
int __tfork(struct __tfork *params, size_t psize, struct CloneArgs *wt);
|
||||
asm("__tfork:\n\t"
|
||||
"push\t$8\n\t"
|
||||
"pop\t%rax\n\t"
|
||||
"mov\t%rdx,%r8\n\t"
|
||||
"syscall\n\t"
|
||||
"jc\t1f\n\t"
|
||||
"test\t%eax,%eax\n\t"
|
||||
"jz\t2f\n\t"
|
||||
"ret\n1:\t"
|
||||
"neg\t%eax\n\t"
|
||||
"ret\n2:\t"
|
||||
"xor\t%ebp,%ebp\n\t"
|
||||
"mov\t%r8,%rsp\n\t"
|
||||
"mov\t%r8,%rdi\n\t"
|
||||
"and\t$-16,%rsp\n\t"
|
||||
"push\t%rax\n\t"
|
||||
"jmp\tOpenbsdThreadMain\n\t"
|
||||
".size\t__tfork,.-__tfork\n\t");
|
||||
__attribute__((__used__, __no_reorder__))
|
||||
|
||||
static wontreturn void
|
||||
OpenbsdThreadMain(struct CloneArgs *wt) {
|
||||
static wontreturn void OpenbsdThreadMain(void *p) {
|
||||
struct CloneArgs *wt = p;
|
||||
wt->func(wt->arg);
|
||||
// we no longer use the stack after this point. however openbsd
|
||||
// validates the rsp register too so a race condition can still
|
||||
|
@ -298,14 +275,11 @@ OpenbsdThreadMain(struct CloneArgs *wt) {
|
|||
// although ideally there should be a better solution.
|
||||
//
|
||||
// void __threxit(%rdi = int32_t *notdead);
|
||||
asm volatile("mov\t%2,%%rsp\n\t"
|
||||
asm volatile("mov\t%2,%%rsp\n\t" // set stack
|
||||
"movl\t$0,(%%rdi)\n\t" // *wt->ztid = 0
|
||||
"syscall\n\t" // futex()
|
||||
"mov\t$302,%%eax\n\t" // __threxit()
|
||||
"syscall"
|
||||
"syscall" // __threxit()
|
||||
: "=m"(*wt->ztid)
|
||||
: "a"(83), "m"(wt->pstack), "D"(wt->ztid), "S"(FUTEX_WAKE),
|
||||
"d"(INT_MAX)
|
||||
: "a"(302), "m"(wt->pstack), "D"(wt->ztid)
|
||||
: "rcx", "r11", "memory");
|
||||
unreachable;
|
||||
}
|
||||
|
@ -313,20 +287,24 @@ OpenbsdThreadMain(struct CloneArgs *wt) {
|
|||
static int CloneOpenbsd(int (*func)(void *), char *stk, size_t stksz, int flags,
|
||||
void *arg, void *tls, size_t tlssz, int *ctid) {
|
||||
int tid;
|
||||
intptr_t sp;
|
||||
struct __tfork *tf;
|
||||
struct CloneArgs *wt;
|
||||
struct __tfork params;
|
||||
wt = (struct CloneArgs *)(((intptr_t)(stk + stksz) -
|
||||
sizeof(struct CloneArgs)) &
|
||||
-alignof(struct CloneArgs));
|
||||
wt->ctid = flags & CLONE_CHILD_SETTID ? ctid : &wt->tid;
|
||||
sp = (intptr_t)stk + stksz;
|
||||
sp -= sizeof(struct __tfork);
|
||||
sp &= -alignof(struct __tfork);
|
||||
tf = (struct __tfork *)sp;
|
||||
sp -= sizeof(struct CloneArgs);
|
||||
sp &= -MAX(16, alignof(struct CloneArgs));
|
||||
wt = (struct CloneArgs *)sp;
|
||||
wt->ztid = flags & CLONE_CHILD_CLEARTID ? ctid : &wt->tid;
|
||||
wt->pstack = __builtin_frame_address(0);
|
||||
wt->func = func;
|
||||
wt->arg = arg;
|
||||
params.tf_stack = wt;
|
||||
params.tf_tcb = flags & CLONE_SETTLS ? tls : 0;
|
||||
params.tf_tid = flags & CLONE_CHILD_SETTID ? ctid : 0;
|
||||
if ((tid = __tfork(¶ms, sizeof(params), wt)) < 0) {
|
||||
wt->func = func;
|
||||
tf->tf_stack = (char *)wt - 8;
|
||||
tf->tf_tcb = flags & CLONE_SETTLS ? tls : 0;
|
||||
tf->tf_tid = flags & CLONE_CHILD_SETTID ? ctid : 0;
|
||||
if ((tid = __tfork_thread(tf, sizeof(*tf), OpenbsdThreadMain, wt)) < 0) {
|
||||
errno = -tid;
|
||||
tid = -1;
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ static inline textwindows ssize_t ForkIo(int64_t h, char *p, size_t n,
|
|||
uint32_t x;
|
||||
for (i = 0; i < n; i += x) {
|
||||
if (!f(h, p + i, n - i, &x, NULL)) {
|
||||
return -1;
|
||||
return __winerr();
|
||||
}
|
||||
}
|
||||
return i;
|
||||
|
@ -91,7 +91,7 @@ static inline textwindows ssize_t ForkIo(int64_t h, char *p, size_t n,
|
|||
static dontinline textwindows bool ForkIo2(int64_t h, void *buf, size_t n,
|
||||
bool32 (*fn)(), const char *sf) {
|
||||
ssize_t rc = ForkIo(h, buf, n, fn);
|
||||
NTTRACE("%s(%ld, %'zu) → %'zd% m", sf, h, n, rc);
|
||||
NTTRACE("%s(%ld, %p, %'zu) → %'zd% m", sf, h, buf, n, rc);
|
||||
return rc != -1;
|
||||
}
|
||||
|
||||
|
@ -202,6 +202,9 @@ textwindows void WinMainForked(void) {
|
|||
ReadOrDie(reader, __bss_start, __bss_end - __bss_start);
|
||||
__pid = savepid;
|
||||
kStartTsc = savetsc;
|
||||
__threaded = false;
|
||||
__tls_index = 0;
|
||||
__tls_enabled = false;
|
||||
|
||||
// apply fixups and reapply memory protections
|
||||
_mmi.p = maps;
|
||||
|
@ -255,6 +258,7 @@ textwindows void WinMainForked(void) {
|
|||
textwindows int sys_fork_nt(void) {
|
||||
bool ok;
|
||||
jmp_buf jb;
|
||||
uint32_t oldprot;
|
||||
char **args, **args2;
|
||||
char16_t pipename[64];
|
||||
int64_t reader, writer;
|
||||
|
|
|
@ -90,7 +90,7 @@ privileged void ftracer(void) {
|
|||
frame = frame->next;
|
||||
if (frame->addr != g_ftrace.lastaddr) {
|
||||
stackuse = (intptr_t)GetStackAddr(0) + GetStackSize() - (intptr_t)frame;
|
||||
kprintf("%rFUN %5P %'13T %'*ld %*s%t\n", g_ftrace.stackdigs, stackuse,
|
||||
kprintf("%rFUN %6P %'13T %'*ld %*s%t\n", g_ftrace.stackdigs, stackuse,
|
||||
GetNestingLevel(frame) * 2, "", frame->addr);
|
||||
g_ftrace.lastaddr = frame->addr;
|
||||
}
|
||||
|
|
|
@ -62,8 +62,6 @@ void __mmi_lock(void) hidden;
|
|||
void __mmi_unlock(void) hidden;
|
||||
bool IsMemtracked(int, int) hidden;
|
||||
void PrintSystemMappings(int) hidden;
|
||||
const char *DescribeFrame(int) hidden;
|
||||
char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
|
||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
|
||||
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
|
||||
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int,
|
||||
|
|
|
@ -237,12 +237,6 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
|
|||
|
||||
static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off) {
|
||||
#if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE)
|
||||
if (IsWindows()) {
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off);
|
||||
}
|
||||
#endif
|
||||
char *p = addr;
|
||||
struct DirectMap dm;
|
||||
int a, b, i, f, m, n, x;
|
||||
|
@ -405,7 +399,10 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
|||
|
||||
if (p != MAP_FAILED) {
|
||||
if (needguard) {
|
||||
mprotect(p, PAGESIZE, PROT_NONE);
|
||||
if (!IsWindows()) {
|
||||
// make windows fork() code simpler
|
||||
mprotect(p, PAGESIZE, PROT_NONE);
|
||||
}
|
||||
if (IsAsan()) {
|
||||
__repstosb((void *)(((intptr_t)p >> 3) + 0x7fff8000),
|
||||
kAsanStackOverflow, PAGESIZE / 8);
|
||||
|
@ -474,10 +471,15 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
|||
* to be 64kb aligned too
|
||||
* @return virtual base address of new mapping, or MAP_FAILED w/ errno
|
||||
*/
|
||||
noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
|
||||
int64_t off) {
|
||||
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
||||
void *res;
|
||||
size_t toto;
|
||||
#if defined(SYSDEBUG) && (_KERNTRACE || _NTTRACE)
|
||||
if (IsWindows()) {
|
||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → ...", addr, size,
|
||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off);
|
||||
}
|
||||
#endif
|
||||
__mmi_lock();
|
||||
res = Mmap(addr, size, prot, flags, fd, off);
|
||||
#if SYSDEBUG
|
||||
|
|
|
@ -161,7 +161,7 @@ static noasan int Munmap(char *p, size_t n) {
|
|||
* @raises EINVAL if `p+(n-1)` isn't 48-bit
|
||||
* @raises EINVAL if `p` isn't 65536-byte aligned
|
||||
*/
|
||||
noasan int munmap(void *p, size_t n) {
|
||||
int munmap(void *p, size_t n) {
|
||||
int rc;
|
||||
size_t toto;
|
||||
__mmi_lock();
|
||||
|
|
|
@ -126,6 +126,17 @@ static const struct AuxiliaryValue *DescribeAuxv(unsigned long x) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static noasan void PrintDependencies(const char *prologue) {
|
||||
struct NtLinkedList *head = &NtGetPeb()->Ldr->InLoadOrderModuleList;
|
||||
struct NtLinkedList *ldr = head->Next;
|
||||
do {
|
||||
const struct NtLdrDataTableEntry *dll =
|
||||
(const struct NtLdrDataTableEntry *)ldr;
|
||||
PRINT(" ☼ %.*!hs (%'zukb)", dll->FullDllName.Length, dll->FullDllName.Data,
|
||||
dll->SizeOfImage / 1024);
|
||||
} while ((ldr = ldr->Next) && ldr != head);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints lots of information about this process, e.g.
|
||||
*
|
||||
|
@ -283,10 +294,11 @@ textstartup void __printargs(const char *prologue) {
|
|||
PRINT("RESOURCE LIMITS");
|
||||
for (i = 0; i < RLIM_NLIMITS; ++i) {
|
||||
if (!getrlimit(i, &rlim)) {
|
||||
char buf[12];
|
||||
if (rlim.rlim_cur == RLIM_INFINITY) rlim.rlim_cur = -1;
|
||||
if (rlim.rlim_max == RLIM_INFINITY) rlim.rlim_max = -1;
|
||||
PRINT(" ☼ %-20s %,16ld %,16ld", DescribeRlimitName(i), rlim.rlim_cur,
|
||||
rlim.rlim_max);
|
||||
PRINT(" ☼ %-20s %,16ld %,16ld", (DescribeRlimitName)(buf, i),
|
||||
rlim.rlim_cur, rlim.rlim_max);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -551,14 +563,7 @@ textstartup void __printargs(const char *prologue) {
|
|||
|
||||
PRINT("");
|
||||
PRINT("DEPENDENCIES");
|
||||
struct NtLinkedList *head = &NtGetPeb()->Ldr->InLoadOrderModuleList;
|
||||
struct NtLinkedList *ldr = head->Next;
|
||||
do {
|
||||
const struct NtLdrDataTableEntry *dll =
|
||||
(const struct NtLdrDataTableEntry *)ldr;
|
||||
PRINT(" ☼ %.*!hs (%'zukb)", dll->FullDllName.Length,
|
||||
dll->FullDllName.Data, dll->SizeOfImage / 1024);
|
||||
} while ((ldr = ldr->Next) && ldr != head);
|
||||
PrintDependencies(prologue);
|
||||
}
|
||||
|
||||
PRINT("");
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/fmt/itoa.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
@ -33,7 +34,7 @@ static bool IsNoteworthyHole(unsigned i, const struct MemoryIntervals *mm) {
|
|||
}
|
||||
|
||||
void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
|
||||
char *p, mode[8];
|
||||
char *p, mappingbuf[8], framebuf[32];
|
||||
long i, w, frames, maptally = 0, gaptally = 0;
|
||||
for (w = i = 0; i < mm->i; ++i) {
|
||||
w = MAX(w, LengthInt64Thousands(mm->p[i].y + 1 - mm->p[i].x));
|
||||
|
@ -42,8 +43,8 @@ void PrintMemoryIntervals(int fd, const struct MemoryIntervals *mm) {
|
|||
frames = mm->p[i].y + 1 - mm->p[i].x;
|
||||
maptally += frames;
|
||||
kprintf("%08x-%08x %s %'*ldx%s", mm->p[i].x, mm->p[i].y,
|
||||
DescribeMapping(mm->p[i].prot, mm->p[i].flags, mode), w, frames,
|
||||
DescribeFrame(mm->p[i].x));
|
||||
(DescribeMapping)(mappingbuf, mm->p[i].prot, mm->p[i].flags), w,
|
||||
frames, (DescribeFrame)(framebuf, mm->p[i].x));
|
||||
if (mm->p[i].iscow) kprintf(" cow");
|
||||
if (mm->p[i].readonlyfile) kprintf(" readonlyfile");
|
||||
if (mm->p[i].size !=
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/syscall-sysv.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nexgen32e/threaded.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
|
@ -28,7 +29,7 @@ extern int __threadcalls_start[];
|
|||
|
||||
void __enable_tls(void) {
|
||||
__initialize_tls(tibdefault);
|
||||
*(int *)((char *)tibdefault + 0x38) = gettid();
|
||||
*(int *)((char *)tibdefault + 0x38) = sys_gettid();
|
||||
*(int *)((char *)tibdefault + 0x3c) = __errno;
|
||||
__install_tls(tibdefault);
|
||||
}
|
||||
|
|
|
@ -163,6 +163,8 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
int64_t h, hand;
|
||||
uint32_t oldprot;
|
||||
struct WinArgs *wa;
|
||||
char inflagsbuf[256];
|
||||
char outflagsbuf[128];
|
||||
const char16_t *env16;
|
||||
int i, prot, count, version;
|
||||
intptr_t stackaddr, allocaddr;
|
||||
|
@ -179,13 +181,13 @@ __msabi static textwindows wontreturn void WinMainNew(const char16_t *cmdline) {
|
|||
hand = GetStdHandle(kConsoleHandles[i]);
|
||||
rc = GetConsoleMode(hand, __ntconsolemode + i);
|
||||
NTTRACE("GetConsoleMode(%p, [%s]) → %hhhd", hand,
|
||||
i ? DescribeNtConsoleModeOutputFlags(__ntconsolemode[i])
|
||||
: DescribeNtConsoleModeInputFlags(__ntconsolemode[i]),
|
||||
i ? (DescribeNtConsoleOutFlags)(outflagsbuf, __ntconsolemode[i])
|
||||
: (DescribeNtConsoleInFlags)(inflagsbuf, __ntconsolemode[i]),
|
||||
rc);
|
||||
rc = SetConsoleMode(hand, kConsoleModes[i]);
|
||||
NTTRACE("SetConsoleMode(%p, %s) → %hhhd", hand,
|
||||
i ? DescribeNtConsoleModeOutputFlags(kConsoleModes[i])
|
||||
: DescribeNtConsoleModeInputFlags(kConsoleModes[i]),
|
||||
i ? (DescribeNtConsoleOutFlags)(outflagsbuf, kConsoleModes[i])
|
||||
: (DescribeNtConsoleInFlags)(inflagsbuf, kConsoleModes[i]),
|
||||
rc);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue