mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-27 14:58:30 +00:00
Improve crash signal reporting on Windows
This change fixes a bug where exiting a crash signal handler on Windows after adding the signal to uc_sigmask, but not correcting the CPU state would cause the signal handler to loop infinitely, causing process hang Another issue is that very tiny programs, that don't link posix signals would not have their SIGILL / SIGSEGV / etc. status reported to Cosmo's bash shell when terminating on crash. That's fixed by a tiny handler in WinMain() that knows how to map WIN32 crash codes to the POSIX flavors.
This commit is contained in:
parent
500a47bc2f
commit
cd672e251f
7 changed files with 169 additions and 88 deletions
102
libc/calls/sig.c
102
libc/calls/sig.c
|
@ -301,7 +301,7 @@ static textwindows wontreturn void __sig_tramp(struct SignalFrame *sf) {
|
|||
}
|
||||
|
||||
// sends signal to another specific thread which is ref'd
|
||||
static int __sig_killer(struct PosixThread *pt, int sig, int sic) {
|
||||
static textwindows int __sig_killer(struct PosixThread *pt, int sig, int sic) {
|
||||
unsigned rva = __sighandrvas[sig];
|
||||
unsigned flags = __sighandflags[sig];
|
||||
|
||||
|
@ -462,66 +462,7 @@ textwindows void __sig_generate(int sig, int sic) {
|
|||
ALLOW_SIGNALS;
|
||||
}
|
||||
|
||||
static int __sig_crash_sig(struct NtExceptionPointers *ep, int *code) {
|
||||
switch (ep->ExceptionRecord->ExceptionCode) {
|
||||
case kNtSignalBreakpoint:
|
||||
*code = TRAP_BRKPT;
|
||||
return SIGTRAP;
|
||||
case kNtSignalIllegalInstruction:
|
||||
*code = ILL_ILLOPC;
|
||||
return SIGILL;
|
||||
case kNtSignalPrivInstruction:
|
||||
*code = ILL_PRVOPC;
|
||||
return SIGILL;
|
||||
case kNtSignalInPageError:
|
||||
case kNtStatusStackOverflow:
|
||||
*code = SEGV_MAPERR;
|
||||
return SIGSEGV;
|
||||
case kNtSignalGuardPage:
|
||||
case kNtSignalAccessViolation:
|
||||
*code = SEGV_ACCERR;
|
||||
return SIGSEGV;
|
||||
case kNtSignalInvalidHandle:
|
||||
case kNtSignalInvalidParameter:
|
||||
case kNtSignalAssertionFailure:
|
||||
*code = SI_USER;
|
||||
return SIGABRT;
|
||||
case kNtStatusIntegerOverflow:
|
||||
*code = FPE_INTOVF;
|
||||
return SIGFPE;
|
||||
case kNtSignalFltDivideByZero:
|
||||
*code = FPE_FLTDIV;
|
||||
return SIGFPE;
|
||||
case kNtSignalFltOverflow:
|
||||
*code = FPE_FLTOVF;
|
||||
return SIGFPE;
|
||||
case kNtSignalFltUnderflow:
|
||||
*code = FPE_FLTUND;
|
||||
return SIGFPE;
|
||||
case kNtSignalFltInexactResult:
|
||||
*code = FPE_FLTRES;
|
||||
return SIGFPE;
|
||||
case kNtSignalFltDenormalOperand:
|
||||
case kNtSignalFltInvalidOperation:
|
||||
case kNtSignalFltStackCheck:
|
||||
case kNtSignalIntegerDivideByZero:
|
||||
case kNtSignalFloatMultipleFaults:
|
||||
case kNtSignalFloatMultipleTraps:
|
||||
*code = FPE_FLTINV;
|
||||
return SIGFPE;
|
||||
case kNtSignalDllNotFound:
|
||||
case kNtSignalOrdinalNotFound:
|
||||
case kNtSignalEntrypointNotFound:
|
||||
case kNtSignalDllInitFailed:
|
||||
*code = SI_KERNEL;
|
||||
return SIGSYS;
|
||||
default:
|
||||
*code = ep->ExceptionRecord->ExceptionCode;
|
||||
return SIGSEGV;
|
||||
}
|
||||
}
|
||||
|
||||
static char *__sig_stpcpy(char *d, const char *s) {
|
||||
static textwindows char *__sig_stpcpy(char *d, const char *s) {
|
||||
size_t i;
|
||||
for (i = 0;; ++i) {
|
||||
if (!(d[i] = s[i])) {
|
||||
|
@ -530,8 +471,24 @@ static char *__sig_stpcpy(char *d, const char *s) {
|
|||
}
|
||||
}
|
||||
|
||||
static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
|
||||
struct CosmoTib *tib) {
|
||||
static textwindows wontreturn void __sig_death(int sig, const char *thing) {
|
||||
#ifndef TINY
|
||||
intptr_t hStderr;
|
||||
char sigbuf[21], s[128], *p;
|
||||
hStderr = GetStdHandle(kNtStdErrorHandle);
|
||||
p = __sig_stpcpy(s, "Terminating on ");
|
||||
p = __sig_stpcpy(p, thing);
|
||||
p = __sig_stpcpy(p, strsignal_r(sig, sigbuf));
|
||||
p = __sig_stpcpy(p,
|
||||
". Pass --strace and/or ShowCrashReports() for details.\n");
|
||||
WriteFile(hStderr, s, p - s, 0, 0);
|
||||
#endif
|
||||
__sig_terminate(sig);
|
||||
}
|
||||
|
||||
static textwindows void __sig_unmaskable(struct NtExceptionPointers *ep,
|
||||
int code, int sig,
|
||||
struct CosmoTib *tib) {
|
||||
|
||||
// log vital crash information reliably for --strace before doing much
|
||||
// we don't print this without the flag since raw numbers scare people
|
||||
|
@ -549,17 +506,7 @@ static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
|
|||
// exception, then print a friendly helpful hint message to stderr
|
||||
unsigned rva = __sighandrvas[sig];
|
||||
if (rva == (intptr_t)SIG_DFL || rva == (intptr_t)SIG_IGN) {
|
||||
#ifndef TINY
|
||||
intptr_t hStderr;
|
||||
char sigbuf[21], s[128], *p;
|
||||
hStderr = GetStdHandle(kNtStdErrorHandle);
|
||||
p = __sig_stpcpy(s, "Terminating on uncaught ");
|
||||
p = __sig_stpcpy(p, strsignal_r(sig, sigbuf));
|
||||
p = __sig_stpcpy(
|
||||
p, ". Pass --strace and/or ShowCrashReports() for details.\n");
|
||||
WriteFile(hStderr, s, p - s, 0, 0);
|
||||
#endif
|
||||
__sig_terminate(sig);
|
||||
__sig_death(sig, "uncaught ");
|
||||
}
|
||||
|
||||
// if this signal handler is configured to auto-reset to the default
|
||||
|
@ -580,8 +527,9 @@ static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
|
|||
}
|
||||
|
||||
// call the user signal handler
|
||||
// with a temporarily replaced signal mask
|
||||
// and a modifiable view of the faulting code's cpu state
|
||||
// temporarily replace signal mask while calling crash handler
|
||||
// abort process if sig is already blocked to avoid crash loop
|
||||
// note ucontext_t is a hefty data structures on top of NtContext
|
||||
ucontext_t ctx = {0};
|
||||
siginfo_t si = {.si_signo = sig, .si_code = code, .si_addr = si_addr};
|
||||
|
@ -591,6 +539,10 @@ static void __sig_unmaskable(struct NtExceptionPointers *ep, int code, int sig,
|
|||
blocksigs |= 1ull << (sig - 1);
|
||||
ctx.uc_sigmask = atomic_fetch_or_explicit(&tib->tib_sigmask, blocksigs,
|
||||
memory_order_acquire);
|
||||
if (ctx.uc_sigmask & (1ull << (sig - 1))) {
|
||||
__sig_death(sig, "masked ");
|
||||
__sig_terminate(sig);
|
||||
}
|
||||
__sig_handler(rva)(sig, &si, &ctx);
|
||||
atomic_store_explicit(&tib->tib_sigmask, ctx.uc_sigmask,
|
||||
memory_order_release);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue