mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-07 03:38:31 +00:00
Overhaul process spawning
This commit is contained in:
parent
99dc1281f5
commit
26e254fb4d
96 changed files with 1848 additions and 1541 deletions
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue