Overhaul process spawning

This commit is contained in:
Justine Tunney 2023-09-10 08:12:43 -07:00
parent 99dc1281f5
commit 26e254fb4d
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
96 changed files with 1848 additions and 1541 deletions

View file

@ -16,20 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/atomic.h"
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/dce.h"
#include "libc/intrin/atomic.h"
#include "libc/errno.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/backtrace.internal.h"
#include "libc/log/internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/log/log.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/runtime.h"
#include "libc/thread/thread.h"
#include "libc/str/str.h"
#if SupportsMetal()
__static_yoink("_idt");
@ -37,29 +35,18 @@ __static_yoink("_idt");
/**
* Aborts process after printing a backtrace.
*
* If a debugger is present then this will trigger a breakpoint.
*/
relegated wontreturn void __die(void) {
/* asan runtime depends on this function */
int me, owner;
static atomic_int once;
owner = 0;
me = __tls_enabled ? __get_tls()->tib_tid : sys_gettid();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
if (__vforked ||
atomic_compare_exchange_strong_explicit(
&once, &owner, me, memory_order_relaxed, memory_order_relaxed)) {
__restore_tty();
if (IsDebuggerPresent(false)) {
DebugBreak();
}
ShowBacktrace(2, __builtin_frame_address(0));
_Exit(77);
} else if (owner == me) {
kprintf("die failed while dying\n");
_Exit(79);
} else {
_Exit1(79);
}
relegated dontasan wontreturn void __die(void) {
// print vital error nubers reliably
// the surface are of code this calls is small and audited
kprintf("\r\n\e[1;31m__die %s pid %d tid %d bt %s\e[0m\n",
program_invocation_short_name, getpid(), sys_gettid(),
DescribeBacktrace(__builtin_frame_address(0)));
// print much friendlier backtrace less reliably
// we're in a broken runtime state and so much can go wrong
__restore_tty();
ShowBacktrace(2, __builtin_frame_address(0));
_Exit(77);
}

View file

@ -9,6 +9,12 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
__funline unsigned long __strlen(const char *s) {
unsigned long n = 0;
while (*s++) ++n;
return n;
}
__funline int __strcmp(const char *l, const char *r) {
size_t i = 0;
while (l[i] == r[i] && r[i]) ++i;
@ -24,6 +30,15 @@ __funline char *__stpcpy(char *d, const char *s) {
}
}
__funline long __write_linux(int fd, const void *p, long n) {
long ax = 1;
asm volatile("syscall"
: "+a"(ax)
: "D"(fd), "S"(p), "d"(n)
: "rcx", "r11", "memory");
return ax;
}
__funline void *__repstosb(void *di, char al, size_t cx) {
#if defined(__x86__) && defined(__GNUC__) && !defined(__STRICT_ANSI__)
asm("rep stosb"

View file

@ -21,6 +21,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/state.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/utsname.h"
#include "libc/calls/syscall-sysv.internal.h"
#include "libc/calls/ucontext.h"
@ -29,6 +30,7 @@
#include "libc/fmt/itoa.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/atomic.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/intrin/kmalloc.h"
#include "libc/intrin/kprintf.h"
@ -259,113 +261,42 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
kprintf("\n");
}
static wontreturn relegated dontinstrument void __minicrash(int sig,
struct siginfo *si,
ucontext_t *ctx,
const char *kind) {
kprintf("\n"
"\n"
"CRASHED %s WITH %G\n"
"%s\n"
"RIP %x\n"
"RSP %x\n"
"RBP %x\n"
"PID %d\n"
"TID %d\n"
"\n",
kind, sig, __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0, __pid,
__tls_enabled ? __get_tls()->tib_tid : sys_gettid());
_Exit(119);
static relegated wontreturn void RaiseCrash(int sig) {
sigset_t ss;
sigfillset(&ss);
sigdelset(&ss, sig);
sigprocmask(SIG_SETMASK, &ss, 0);
signal(sig, SIG_DFL);
kill(getpid(), sig);
_Exit(128 + sig);
}
/**
* Crashes in a developer-friendly human-centric way.
*
* We first try to launch GDB if it's an interactive development
* session. Otherwise we show a really good crash report, sort of like
* Python, that includes filenames and line numbers. Many editors, e.g.
* Emacs, will even recognize its syntax for quick hopping to the
* failing line. That's only possible if the the .com.dbg file is in the
* same folder. If the concomitant debug binary can't be found, we
* simply print addresses which may be cross-referenced using objdump.
*
* This function never returns, except for traps w/ human supervision.
*
* @threadsafe
* @vforksafe
*/
relegated void __oncrash_amd64(int sig, struct siginfo *si, void *arg) {
int bZero;
#ifdef ATTACH_GDB_ON_CRASH
intptr_t rip;
#endif
int me, owner;
int gdbpid, err;
ucontext_t *ctx = arg;
static atomic_int once;
static atomic_int once2;
STRACE("__oncrash rip %x", ctx->uc_mcontext.rip);
// print vital error nubers reliably
// the surface are of code this calls is small and audited
kprintf(
"\r\n\e[1;31m__oncrash %G %s pid %d tid %d rip %x bt %s\e[0m\n", sig,
program_invocation_short_name, getpid(), sys_gettid(),
ctx ? ctx->uc_mcontext.rip : 0,
DescribeBacktrace(ctx ? (struct StackFrame *)ctx->uc_mcontext.rbp
: (struct StackFrame *)__builtin_frame_address(0)));
// print friendlier detailed crash report less reliably
// we're in a broken runtime state and so much can go wrong
ftrace_enabled(-1);
strace_enabled(-1);
owner = 0;
me = __tls_enabled ? __get_tls()->tib_tid : sys_gettid();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, 0);
if (atomic_compare_exchange_strong_explicit(
&once, &owner, me, memory_order_relaxed, memory_order_relaxed)) {
if (!__vforked) {
#ifdef ATTACH_GDB_ON_CRASH
rip = ctx ? ctx->uc_mcontext.rip : 0;
#endif
err = errno;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
} else if (__nocolor || g_isrunningundermake) {
gdbpid = -1;
#if ATTACH_GDB_ON_CRASH
} else if (!IsTiny() && IsLinux() && FindDebugBinary() && !__isworker) {
// RestoreDefaultCrashSignalHandlers();
gdbpid = AttachDebugger(
((sig == SIGTRAP || sig == SIGQUIT) &&
(rip >= (intptr_t)&__executable_start && rip < (intptr_t)&_etext))
? rip
: 0);
#endif
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty();
ShowCrashReport(err, sig, si, ctx);
_Exit(128 + sig);
}
atomic_store_explicit(&once, 0, memory_order_relaxed);
} else {
atomic_store_explicit(&once, 0, memory_order_relaxed);
__minicrash(sig, si, ctx, "WHILE VFORKED");
}
} else if (sig == SIGTRAP) {
// chances are IsDebuggerPresent() confused strace w/ gdb
goto ItsATrap;
} else if (owner == me) {
// we crashed while generating a crash report
bZero = false;
if (atomic_compare_exchange_strong_explicit(
&once2, &bZero, true, memory_order_relaxed, memory_order_relaxed)) {
__minicrash(sig, si, ctx, "WHILE CRASHING");
} else {
// somehow __minicrash() crashed not possible
for (;;) {
abort();
}
}
} else {
// multiple threads have crashed
// kill current thread assuming process dies soon
// TODO(jart): It'd be nice to report on all threads.
_Exit1(8);
err = errno;
if ((gdbpid = IsDebuggerPresent(true))) {
DebugBreak();
}
if (!(gdbpid > 0 && (sig == SIGTRAP || sig == SIGQUIT))) {
__restore_tty();
ShowCrashReport(err, sig, si, ctx);
RaiseCrash(sig);
}
ItsATrap:
strace_enabled(+1);
ftrace_enabled(+1);
}
#endif /* __x86_64__ */

View file

@ -21,6 +21,7 @@
#include "libc/calls/calls.h"
#include "libc/calls/struct/aarch64.internal.h"
#include "libc/calls/struct/rusage.internal.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/sigset.internal.h"
@ -63,18 +64,28 @@ struct Buffer {
int i;
};
static bool IsCode(uintptr_t p) {
static relegated bool IsCode(uintptr_t p) {
return __executable_start <= (uint8_t *)p && (uint8_t *)p < _etext;
}
static void Append(struct Buffer *b, const char *fmt, ...) {
static relegated void Append(struct Buffer *b, const char *fmt, ...) {
va_list va;
va_start(va, fmt);
b->i += kvsnprintf(b->p + b->i, b->n - b->i, fmt, va);
va_end(va);
}
static const char *ColorRegister(int r) {
static relegated wontreturn void RaiseCrash(int sig) {
sigset_t ss;
sigfillset(&ss);
sigdelset(&ss, sig);
sigprocmask(SIG_SETMASK, &ss, 0);
signal(sig, SIG_DFL);
kill(getpid(), sig);
_Exit(128 + sig);
}
static relegated const char *ColorRegister(int r) {
if (__nocolor) return "";
switch (r) {
case 0: // arg / res
@ -115,8 +126,8 @@ static const char *ColorRegister(int r) {
}
}
static bool AppendFileLine(struct Buffer *b, const char *addr2line,
const char *debugbin, long addr) {
static relegated bool AppendFileLine(struct Buffer *b, const char *addr2line,
const char *debugbin, long addr) {
ssize_t rc;
char *p, *q, buf[128];
int j, k, ws, pid, pfd[2];
@ -167,8 +178,8 @@ static bool AppendFileLine(struct Buffer *b, const char *addr2line,
}
}
static char *GetSymbolName(struct SymbolTable *st, int symbol, char **mem,
size_t *memsz) {
static relegated char *GetSymbolName(struct SymbolTable *st, int symbol,
char **mem, size_t *memsz) {
char *s, *t;
if ((s = __get_symbol_name(st, symbol)) && //
s[0] == '_' && s[1] == 'Z' && //
@ -348,7 +359,7 @@ relegated void __oncrash_arm64(int sig, struct siginfo *si, void *arg) {
}
sys_write(2, b->p, MIN(b->i, b->n));
__print_maps();
_Exit(128 + sig);
RaiseCrash(sig);
}
#endif /* __aarch64__ */

View file

@ -97,7 +97,7 @@ static void RemoveCrashHandler(void *arg) {
strace_enabled(+1);
}
static void InstallCrashHandler(int sig, sigaction_f thunk, int extraflags) {
static void InstallCrashHandler(int sig, sigaction_f thunk) {
int e;
struct sigaction sa;
struct CrashHandler *ch;
@ -114,7 +114,7 @@ static void InstallCrashHandler(int sig, sigaction_f thunk, int extraflags) {
sigdelset(&sa.sa_mask, SIGABRT);
sigdelset(&sa.sa_mask, SIGBUS);
sigdelset(&sa.sa_mask, SIGURG);
sa.sa_flags = SA_SIGINFO | SA_NODEFER | extraflags;
sa.sa_flags = SA_SIGINFO | SA_ONSTACK;
if (!sigaction(sig, &sa, &ch->old)) {
__cxa_atexit(RemoveCrashHandler, ch, 0);
}
@ -138,24 +138,21 @@ static void InstallCrashHandler(int sig, sigaction_f thunk, int extraflags) {
* useful, for example, if a program is caught in an infinite loop.
*/
void ShowCrashReports(void) {
int ef = 0;
struct sigaltstack ss;
_wantcrashreports = true;
if (!IsWindows()) {
ef = SA_ONSTACK;
struct sigaltstack ss;
ss.ss_flags = 0;
ss.ss_size = GetStackSize();
// FreeBSD sigaltstack() will EFAULT if we use MAP_STACK here
// OpenBSD sigaltstack() auto-applies MAP_STACK to the memory
npassert((ss.ss_sp = _mapanon(GetStackSize())));
npassert(!sigaltstack(&ss, 0));
ss.ss_size = SIGSTKSZ;
ss.ss_sp = malloc(SIGSTKSZ);
sigaltstack(&ss, 0);
__cxa_atexit(free, ss.ss_sp, 0);
}
InstallCrashHandler(SIGQUIT, __got_sigquit, ef); // ctrl+\ aka ctrl+break
InstallCrashHandler(SIGFPE, __got_sigfpe, ef); // 1 / 0
InstallCrashHandler(SIGILL, __got_sigill, ef); // illegal instruction
InstallCrashHandler(SIGSEGV, __got_sigsegv, ef); // bad memory access
InstallCrashHandler(SIGTRAP, __got_sigtrap, ef); // bad system call
InstallCrashHandler(SIGBUS, __got_sigbus, ef); // misalign, mmap i/o failed
InstallCrashHandler(SIGURG, __got_sigurg, ef); // placeholder
InstallCrashHandler(SIGQUIT, __got_sigquit); // ctrl+\ aka ctrl+break
InstallCrashHandler(SIGFPE, __got_sigfpe); // 1 / 0
InstallCrashHandler(SIGILL, __got_sigill); // illegal instruction
InstallCrashHandler(SIGSEGV, __got_sigsegv); // bad memory access
InstallCrashHandler(SIGTRAP, __got_sigtrap); // bad system call
InstallCrashHandler(SIGBUS, __got_sigbus); // misalign, mmap i/o failed
InstallCrashHandler(SIGURG, __got_sigurg); // placeholder
_wantcrashreports = true;
GetSymbolTable();
}