mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-02 17:28:30 +00:00
Make improvements
- Get threads working on NetBSD - Get threads working on OpenBSD - Fix Emacs config for Emacs v28 - Improve --strace logging of sigset_t - Improve --strace logging of struct stat - Improve memory safety of DescribeThing functions - Refactor auto stack allocation into LIBC_RUNTIME - Introduce shell.com example which works on Windows - Refactor __strace_thing into DescribeThing functions - Document the CHECK macros and improve them in NDEBUG mode - Rewrite MAP_STACK so it uses FreeBSD behavior across platforms - Deprecate and discourage the use of MAP_GROWSDOWN (it's weird)
This commit is contained in:
parent
dd9ab01d25
commit
e7611a8476
101 changed files with 967 additions and 464 deletions
|
@ -16,12 +16,12 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/notice.inc"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/dce.h"
|
||||
.text.startup
|
||||
|
||||
|
@ -76,6 +76,44 @@ cosmo: push %rbp
|
|||
ret
|
||||
.endfn cosmo,weak
|
||||
|
||||
#if !IsTiny()
|
||||
.init.start 304,_init_stack
|
||||
testb IsWindows()
|
||||
jnz 9f
|
||||
push %rdi
|
||||
push %rsi
|
||||
// allocate stack
|
||||
movabs $ape_stack_vaddr,%rdi
|
||||
mov $ape_stack_memsz,%esi
|
||||
mov $ape_stack_prot,%edx
|
||||
mov $MAP_STACK,%ecx
|
||||
or MAP_ANONYMOUS,%ecx
|
||||
or $-1,%r8
|
||||
xor %r9d,%r9d
|
||||
push %rsi
|
||||
call mmap
|
||||
pop %r8
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
cmp $-1,%rax
|
||||
je 9f
|
||||
// switch stacks
|
||||
leave
|
||||
pop %rcx
|
||||
lea (%rax,%r8),%rsp
|
||||
sub $ape_stack_align,%rsp # openbsd:stackbound
|
||||
mov %rbp,(%rsp)
|
||||
push %rcx
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
9: nop
|
||||
.init.end 304,_init_stack
|
||||
.weak ape_stack_prot
|
||||
.weak ape_stack_vaddr
|
||||
.weak ape_stack_memsz
|
||||
.weak ape_stack_align
|
||||
#endif
|
||||
|
||||
#ifdef __PG__
|
||||
.init.start 306,_init_ftrace
|
||||
push %rdi
|
||||
|
|
|
@ -122,6 +122,15 @@ static textwindows void ViewOrDie(int64_t h, uint32_t access, size_t pos,
|
|||
}
|
||||
}
|
||||
|
||||
static textwindows int OnForkCrash(struct NtExceptionPointers *ep) {
|
||||
kprintf("error: fork() child crashed!%n"
|
||||
"\tExceptionCode = %#x%n"
|
||||
"\tRip = %x%n",
|
||||
ep->ExceptionRecord->ExceptionCode,
|
||||
ep->ContextRecord ? ep->ContextRecord->Rip : -1);
|
||||
ExitProcess(73);
|
||||
}
|
||||
|
||||
textwindows void WinMainForked(void) {
|
||||
bool ok;
|
||||
jmp_buf jb;
|
||||
|
@ -129,9 +138,9 @@ textwindows void WinMainForked(void) {
|
|||
char *addr, *shad;
|
||||
struct DirectMap dm;
|
||||
uint64_t size, upsize;
|
||||
int64_t savetsc, savebir;
|
||||
struct MemoryInterval *maps;
|
||||
char16_t fvar[21 + 1 + 21 + 1];
|
||||
int64_t oncrash, savetsc, savebir;
|
||||
uint32_t i, varlen, oldprot, savepid;
|
||||
long mapcount, mapcapacity, specialz;
|
||||
extern uint64_t ts asm("kStartTsc");
|
||||
|
@ -142,6 +151,9 @@ textwindows void WinMainForked(void) {
|
|||
if (!varlen || varlen >= ARRAYLEN(fvar)) return;
|
||||
NTTRACE("WinMainForked()");
|
||||
SetEnvironmentVariable(u"_FORK", NULL);
|
||||
#ifdef SYSDEBUG
|
||||
oncrash = AddVectoredExceptionHandler(1, NT2SYSV(OnForkCrash));
|
||||
#endif
|
||||
ParseInt(fvar, &reader);
|
||||
|
||||
// read the cpu state from the parent process & plus
|
||||
|
@ -167,7 +179,7 @@ textwindows void WinMainForked(void) {
|
|||
for (i = 0; i < mapcount; ++i) {
|
||||
addr = (char *)((uint64_t)maps[i].x << 16);
|
||||
size = maps[i].size;
|
||||
if (maps[i].flags & MAP_PRIVATE) {
|
||||
if ((maps[i].flags & MAP_TYPE) != MAP_SHARED) {
|
||||
upsize = ROUNDUP(size, FRAMESIZE);
|
||||
// we don't need to close the map handle because sys_mmap_nt
|
||||
// doesn't mark it inheritable across fork() for MAP_PRIVATE
|
||||
|
@ -226,6 +238,9 @@ textwindows void WinMainForked(void) {
|
|||
}
|
||||
|
||||
// restore the crash reporting stuff
|
||||
#ifdef SYSDEBUG
|
||||
RemoveVectoredExceptionHandler(oncrash);
|
||||
#endif
|
||||
if (weaken(__wincrash_nt)) {
|
||||
if (!IsTiny()) {
|
||||
RemoveVectoredExceptionHandler(__wincrashearly);
|
||||
|
@ -292,7 +307,7 @@ textwindows int sys_fork_nt(void) {
|
|||
(_mmi.i * sizeof(_mmi.p[0])) >> 3);
|
||||
}
|
||||
for (i = 0; i < _mmi.i && ok; ++i) {
|
||||
if (_mmi.p[i].flags & MAP_PRIVATE) {
|
||||
if ((_mmi.p[i].flags & MAP_TYPE) != MAP_SHARED) {
|
||||
ok = WriteAll(writer, (void *)((uint64_t)_mmi.p[i].x << 16),
|
||||
_mmi.p[i].size);
|
||||
}
|
||||
|
|
|
@ -47,6 +47,12 @@
|
|||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define MAP_ANONYMOUS_linux 0x00000020
|
||||
#define MAP_ANONYMOUS_openbsd 0x00001000
|
||||
#define MAP_GROWSDOWN_linux 0x00000100
|
||||
#define MAP_STACK_freebsd 0x00000400
|
||||
#define MAP_STACK_openbsd 0x00004000
|
||||
|
||||
#define IP(X) (intptr_t)(X)
|
||||
#define VIP(X) (void *)IP(X)
|
||||
#define ALIGNED(p) (!(IP(p) & (FRAMESIZE - 1)))
|
||||
|
@ -122,20 +128,9 @@ noasan static size_t GetMemtrackSize(struct MemoryIntervals *mm) {
|
|||
return n;
|
||||
}
|
||||
|
||||
static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off, int f, int x, int n) {
|
||||
struct DirectMap dm;
|
||||
dm = sys_mmap(addr, size, prot, f, fd, off);
|
||||
if (UNLIKELY(dm.addr == MAP_FAILED)) {
|
||||
if (IsWindows() && (flags & MAP_FIXED)) {
|
||||
OnUnrecoverableMmapError(
|
||||
"can't recover from MAP_FIXED errors on Windows");
|
||||
}
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if (UNLIKELY(dm.addr != addr)) {
|
||||
OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
|
||||
}
|
||||
static noasan void *FinishMemory(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off, int f, int x, int n,
|
||||
struct DirectMap dm) {
|
||||
if (!IsWindows() && (flags & MAP_FIXED)) {
|
||||
if (UntrackMemoryIntervals(addr, size)) {
|
||||
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
|
||||
|
@ -154,6 +149,23 @@ static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
|
|||
return addr;
|
||||
}
|
||||
|
||||
static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
|
||||
int fd, int64_t off, int f, int x, int n) {
|
||||
struct DirectMap dm;
|
||||
dm = sys_mmap(addr, size, prot, f, fd, off);
|
||||
if (UNLIKELY(dm.addr == MAP_FAILED)) {
|
||||
if (IsWindows() && (flags & MAP_FIXED)) {
|
||||
OnUnrecoverableMmapError(
|
||||
"can't recover from MAP_FIXED errors on Windows");
|
||||
}
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if (UNLIKELY(dm.addr != addr)) {
|
||||
OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
|
||||
}
|
||||
return FinishMemory(addr, size, prot, flags, fd, off, f, x, n, dm);
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps memory from system, one frame at a time.
|
||||
*
|
||||
|
@ -175,8 +187,8 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
|
|||
sz = size - m;
|
||||
dm = sys_mmap(addr + m, sz, prot, f, fd, oi);
|
||||
if (dm.addr == MAP_FAILED) return MAP_FAILED;
|
||||
iscow = (flags & MAP_PRIVATE) && fd != -1;
|
||||
readonlyfile = (flags & MAP_SHARED) && fd != -1 &&
|
||||
iscow = (flags & MAP_TYPE) != MAP_SHARED && fd != -1;
|
||||
readonlyfile = (flags & MAP_TYPE) == MAP_SHARED && fd != -1 &&
|
||||
(g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY;
|
||||
if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot,
|
||||
flags, readonlyfile, iscow, oi, sz) == -1) {
|
||||
|
@ -208,6 +220,7 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
|||
}
|
||||
#endif
|
||||
char *p = addr;
|
||||
bool needguard;
|
||||
struct DirectMap dm;
|
||||
size_t virtualused, virtualneed;
|
||||
int a, b, i, f, m, n, x;
|
||||
|
@ -311,19 +324,68 @@ static noasan inline void *Mmap(void *addr, size_t size, int prot, int flags,
|
|||
return VIP(enomem());
|
||||
}
|
||||
|
||||
needguard = false;
|
||||
p = (char *)ADDR(x);
|
||||
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
|
||||
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
|
||||
if (dm.addr == MAP_FAILED) {
|
||||
return MAP_FAILED;
|
||||
if ((f & MAP_TYPE) == MAP_STACK) {
|
||||
if (~f & MAP_ANONYMOUS) {
|
||||
STRACE("MAP_STACK must be anonymous");
|
||||
return VIP(einval());
|
||||
}
|
||||
f &= ~MAP_TYPE;
|
||||
f |= MAP_PRIVATE;
|
||||
if (IsOpenbsd()) { // openbsd:dubstack
|
||||
// on openbsd this is less about scalability of threads, and more
|
||||
// about defining the legal intervals for the RSP register. sadly
|
||||
// openbsd doesn't let us create a new fixed stack mapping. but..
|
||||
// openbsd does allow us to overwrite existing fixed mappings, to
|
||||
// authorize its usage as a stack.
|
||||
if (sys_mmap(p, size, prot, f, fd, off).addr == MAP_FAILED) {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
f |= MAP_STACK_openbsd;
|
||||
} else if (IsLinux()) {
|
||||
// by default MAP_GROWSDOWN will auto-allocate 10mb of pages. it's
|
||||
// supposed to stop growing if an adjacent allocation exists, to
|
||||
// prevent your stacks from overlapping on each other. we're not
|
||||
// able to easily assume a mapping beneath this one exists. even
|
||||
// if we could, the linux kernel requires for muh security reasons
|
||||
// that stacks be at least 1mb away from each other, so it's not
|
||||
// possible to avoid this call if our goal is to have 60kb stacks
|
||||
// with 4kb guards like a sane multithreaded production system.
|
||||
// however this 1mb behavior oddly enough is smart enough to not
|
||||
// apply if the mapping is a manually-created guard page.
|
||||
if ((dm = sys_mmap(p + size - PAGESIZE, PAGESIZE, prot,
|
||||
f | MAP_GROWSDOWN_linux, fd, off))
|
||||
.addr == MAP_FAILED) {
|
||||
return MAP_FAILED;
|
||||
}
|
||||
sys_mmap(p, PAGESIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
|
||||
-1, 0);
|
||||
dm.addr = p;
|
||||
return FinishMemory(p, size, prot, flags, fd, off, f, x, n, dm);
|
||||
} else {
|
||||
if (IsFreebsd()) {
|
||||
f |= MAP_STACK_freebsd;
|
||||
}
|
||||
needguard = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!IsWindows()) {
|
||||
return MapMemory(p, size, prot, flags, fd, off, f, x, n);
|
||||
p = MapMemory(p, size, prot, flags, fd, off, f, x, n);
|
||||
} else {
|
||||
return MapMemories(p, size, prot, flags, fd, off, f, x, n);
|
||||
p = MapMemories(p, size, prot, flags, fd, off, f, x, n);
|
||||
}
|
||||
|
||||
if (p != MAP_FAILED) {
|
||||
if (needguard) {
|
||||
if (IsWindows()) _spunlock(&_mmi.lock);
|
||||
mprotect(p, PAGESIZE, PROT_NONE);
|
||||
if (IsWindows()) _spinlock(&_mmi.lock);
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue