mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
Trim down MODE= linkage slightly
This commit is contained in:
parent
046c7ebd4a
commit
c95c9d9508
13 changed files with 315 additions and 283 deletions
|
@ -46,6 +46,6 @@ int kill(int pid, int sig) {
|
|||
} else {
|
||||
rc = sys_kill_nt(pid, sig);
|
||||
}
|
||||
STRACE("kill(%d, %s) → %d% m", pid, strsignal(sig), rc);
|
||||
STRACE("kill(%d, %G) → %d% m", pid, sig, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ static textwindows inline bool HasWorkingConsole(void) {
|
|||
*/
|
||||
int raise(int sig) {
|
||||
int rc, event;
|
||||
STRACE("raise(%s) → [...]", strsignal(sig));
|
||||
STRACE("raise(%G) → [...]", sig);
|
||||
if (sig == SIGTRAP) {
|
||||
DebugBreak();
|
||||
rc = 0;
|
||||
|
@ -75,6 +75,6 @@ int raise(int sig) {
|
|||
rc = __sig_raise(sig, SI_USER);
|
||||
}
|
||||
}
|
||||
STRACE("[...] raise(%s) → %d% m", strsignal(sig), rc);
|
||||
STRACE("[...] raise(%G) → %d% m", sig, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
248
libc/calls/sig.c
248
libc/calls/sig.c
|
@ -16,266 +16,20 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/lockcmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology.
|
||||
* @fileoverview UNIX signals for the New Technology, Part 1.
|
||||
* @threadsafe
|
||||
*/
|
||||
|
||||
struct Signal {
|
||||
struct Signal *next;
|
||||
bool used;
|
||||
int sig;
|
||||
int si_code;
|
||||
};
|
||||
|
||||
struct Signals {
|
||||
sigset_t mask;
|
||||
struct Signal *queue;
|
||||
struct Signal mem[__SIG_QUEUE_LENGTH];
|
||||
};
|
||||
|
||||
struct Signals __sig; // TODO(jart): Need TLS
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
* @assume lock is held
|
||||
*/
|
||||
static textwindows struct Signal *__sig_alloc(void) {
|
||||
int i;
|
||||
struct Signal *res = 0;
|
||||
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
||||
if (!__sig.mem[i].used) {
|
||||
__sig.mem[i].used = true;
|
||||
res = __sig.mem + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns signal memory to static pool.
|
||||
*/
|
||||
static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
*/
|
||||
static textwindows struct Signal *__sig_remove(void) {
|
||||
struct Signal *prev, *res;
|
||||
if (__sig.queue) {
|
||||
cthread_spinlock(&__sig_lock);
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
prev->next = res->next;
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%s is masked", strsignal(res->sig));
|
||||
}
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers signal to callback.
|
||||
* @note called from main thread
|
||||
* @return true if EINTR should be returned by caller
|
||||
*/
|
||||
static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
ucontext_t *ctx) {
|
||||
unsigned rva, flags;
|
||||
siginfo_t info, *infop;
|
||||
STRACE("delivering %s", strsignal(sig));
|
||||
|
||||
// enter the signal
|
||||
cthread_spinlock(&__sig_lock);
|
||||
rva = __sighandrvas[sig];
|
||||
flags = __sighandflags[sig];
|
||||
if (~flags & SA_NODEFER) {
|
||||
// by default we try to avoid reentering a signal handler. for
|
||||
// example, if a sigsegv handler segfaults, then we'd want the
|
||||
// second signal to just kill the process. doing this means we
|
||||
// track state. that's bad if you want to longjmp() out of the
|
||||
// signal handler. in that case you must use SA_NODEFER.
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
|
||||
// setup the somewhat expensive information args
|
||||
// only if they're requested by the user in sigaction()
|
||||
if (flags & SA_SIGINFO) {
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = si_code;
|
||||
infop = &info;
|
||||
} else {
|
||||
infop = 0;
|
||||
ctx = 0;
|
||||
}
|
||||
|
||||
// handover control to user
|
||||
((sigaction_f)(_base + rva))(sig, infop, ctx);
|
||||
|
||||
// leave the signal
|
||||
cthread_spinlock(&__sig_lock);
|
||||
if (~flags & SA_NODEFER) {
|
||||
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||
}
|
||||
if (flags & SA_RESETHAND) {
|
||||
STRACE("resetting oneshot signal handler");
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
|
||||
if (!restartable) {
|
||||
return true; // always send EINTR for wait4(), poll(), etc.
|
||||
} else if (flags & SA_RESTART) {
|
||||
STRACE("restarting syscall on %s", strsignal(sig));
|
||||
return false; // resume syscall for read(), write(), etc.
|
||||
} else {
|
||||
return true; // default course is to raise EINTR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
return sig != SIGCHLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles signal.
|
||||
*
|
||||
* @param restartable can be used to suppress true return if SA_RESTART
|
||||
* @return true if signal was delivered
|
||||
*/
|
||||
textwindows bool __sig_handle(bool restartable, int sig, int si_code,
|
||||
ucontext_t *ctx) {
|
||||
bool delivered;
|
||||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig)) {
|
||||
STRACE("terminating on %s", strsignal(sig));
|
||||
__restorewintty();
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
// fallthrough
|
||||
case (intptr_t)SIG_IGN:
|
||||
STRACE("ignoring %s", strsignal(sig));
|
||||
delivered = false;
|
||||
break;
|
||||
default:
|
||||
delivered = __sig_deliver(restartable, sig, si_code, ctx);
|
||||
break;
|
||||
}
|
||||
return delivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles signal immediately if not blocked.
|
||||
*
|
||||
* @param restartable is for functions like read() but not poll()
|
||||
* @return true if EINTR should be returned by caller
|
||||
* @return 1 if delivered, 0 if enqueued, otherwise -1 w/ errno
|
||||
* @note called from main thread
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_raise(int sig, int si_code) {
|
||||
int rc;
|
||||
int candeliver;
|
||||
cthread_spinlock(&__sig_lock);
|
||||
candeliver = !sigismember(&__sig.mask, sig);
|
||||
cthread_spunlock(&__sig_lock);
|
||||
switch (candeliver) {
|
||||
case 1:
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
case 0:
|
||||
STRACE("%s is masked", strsignal(sig));
|
||||
return __sig_add(sig, si_code);
|
||||
default:
|
||||
return -1; // sigismember() validates `sig`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
* @return 0 if enqueued, otherwise -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
int rc;
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
STRACE("enqueuing %s", strsignal(sig));
|
||||
cthread_spinlock(&__sig_lock);
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
mem->next = __sig.queue;
|
||||
__sig.queue = mem;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = enomem();
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
*
|
||||
* @param restartable is for functions like read() but not poll()
|
||||
* @return true if EINTR should be returned by caller
|
||||
* @note called from main thread
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows bool __sig_check(bool restartable) {
|
||||
unsigned rva;
|
||||
bool delivered;
|
||||
struct Signal *sig;
|
||||
delivered = false;
|
||||
while ((sig = __sig_remove())) {
|
||||
delivered |= __sig_handle(restartable, sig->sig, sig->si_code, 0);
|
||||
__sig_free(sig);
|
||||
}
|
||||
return delivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes signal mask for main thread.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
|
|
|
@ -10,6 +10,21 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
struct Signal {
|
||||
struct Signal *next;
|
||||
bool used;
|
||||
int sig;
|
||||
int si_code;
|
||||
};
|
||||
|
||||
struct Signals {
|
||||
sigset_t mask;
|
||||
struct Signal *queue;
|
||||
struct Signal mem[__SIG_QUEUE_LENGTH];
|
||||
};
|
||||
|
||||
extern struct Signals __sig; // TODO(jart): Need TLS
|
||||
|
||||
bool __sig_check(bool) hidden;
|
||||
bool __sig_handle(bool, int, int, ucontext_t *) hidden;
|
||||
int __sig_add(int, int) hidden;
|
||||
|
|
256
libc/calls/sig2.c
Normal file
256
libc/calls/sig2.c
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 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/calls/internal.h"
|
||||
#include "libc/calls/sig.internal.h"
|
||||
#include "libc/calls/sigbits.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/cmpxchg.h"
|
||||
#include "libc/intrin/spinlock.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* @fileoverview UNIX signals for the New Technology, Part 2.
|
||||
* @threadsafe
|
||||
*/
|
||||
|
||||
/**
|
||||
* Allocates piece of memory for storing pending signal.
|
||||
* @assume lock is held
|
||||
*/
|
||||
static textwindows struct Signal *__sig_alloc(void) {
|
||||
int i;
|
||||
struct Signal *res = 0;
|
||||
for (i = 0; i < ARRAYLEN(__sig.mem); ++i) {
|
||||
if (!__sig.mem[i].used) {
|
||||
__sig.mem[i].used = true;
|
||||
res = __sig.mem + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns signal memory to static pool.
|
||||
*/
|
||||
static textwindows void __sig_free(struct Signal *mem) {
|
||||
mem->used = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dequeues signal that isn't masked.
|
||||
* @return signal or null if empty or none unmasked
|
||||
*/
|
||||
static textwindows struct Signal *__sig_remove(void) {
|
||||
struct Signal *prev, *res;
|
||||
if (__sig.queue) {
|
||||
cthread_spinlock(&__sig_lock);
|
||||
for (prev = 0, res = __sig.queue; res; prev = res, res = res->next) {
|
||||
if (!sigismember(&__sig.mask, res->sig)) {
|
||||
if (res == __sig.queue) {
|
||||
__sig.queue = res->next;
|
||||
} else if (prev) {
|
||||
prev->next = res->next;
|
||||
}
|
||||
res->next = 0;
|
||||
break;
|
||||
} else {
|
||||
STRACE("%G is masked", res->sig);
|
||||
}
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
} else {
|
||||
res = 0;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delivers signal to callback.
|
||||
* @note called from main thread
|
||||
* @return true if EINTR should be returned by caller
|
||||
*/
|
||||
static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
|
||||
ucontext_t *ctx) {
|
||||
unsigned rva, flags;
|
||||
siginfo_t info, *infop;
|
||||
STRACE("delivering %G", sig);
|
||||
|
||||
// enter the signal
|
||||
cthread_spinlock(&__sig_lock);
|
||||
rva = __sighandrvas[sig];
|
||||
flags = __sighandflags[sig];
|
||||
if (~flags & SA_NODEFER) {
|
||||
// by default we try to avoid reentering a signal handler. for
|
||||
// example, if a sigsegv handler segfaults, then we'd want the
|
||||
// second signal to just kill the process. doing this means we
|
||||
// track state. that's bad if you want to longjmp() out of the
|
||||
// signal handler. in that case you must use SA_NODEFER.
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
|
||||
// setup the somewhat expensive information args
|
||||
// only if they're requested by the user in sigaction()
|
||||
if (flags & SA_SIGINFO) {
|
||||
bzero(&info, sizeof(info));
|
||||
info.si_signo = sig;
|
||||
info.si_code = si_code;
|
||||
infop = &info;
|
||||
} else {
|
||||
infop = 0;
|
||||
ctx = 0;
|
||||
}
|
||||
|
||||
// handover control to user
|
||||
((sigaction_f)(_base + rva))(sig, infop, ctx);
|
||||
|
||||
// leave the signal
|
||||
cthread_spinlock(&__sig_lock);
|
||||
if (~flags & SA_NODEFER) {
|
||||
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
|
||||
}
|
||||
if (flags & SA_RESETHAND) {
|
||||
STRACE("resetting oneshot signal handler");
|
||||
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
|
||||
if (!restartable) {
|
||||
return true; // always send EINTR for wait4(), poll(), etc.
|
||||
} else if (flags & SA_RESTART) {
|
||||
STRACE("restarting syscall on %G", sig);
|
||||
return false; // resume syscall for read(), write(), etc.
|
||||
} else {
|
||||
return true; // default course is to raise EINTR
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if signal default action is to end process.
|
||||
*/
|
||||
static textwindows bool __sig_isfatal(int sig) {
|
||||
return sig != SIGCHLD;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles signal.
|
||||
*
|
||||
* @param restartable can be used to suppress true return if SA_RESTART
|
||||
* @return true if signal was delivered
|
||||
*/
|
||||
textwindows bool __sig_handle(bool restartable, int sig, int si_code,
|
||||
ucontext_t *ctx) {
|
||||
bool delivered;
|
||||
switch (__sighandrvas[sig]) {
|
||||
case (intptr_t)SIG_DFL:
|
||||
if (__sig_isfatal(sig)) {
|
||||
STRACE("terminating on %G", sig);
|
||||
__restorewintty();
|
||||
_Exit(128 + sig);
|
||||
}
|
||||
// fallthrough
|
||||
case (intptr_t)SIG_IGN:
|
||||
STRACE("ignoring %G", sig);
|
||||
delivered = false;
|
||||
break;
|
||||
default:
|
||||
delivered = __sig_deliver(restartable, sig, si_code, ctx);
|
||||
break;
|
||||
}
|
||||
return delivered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles signal immediately if not blocked.
|
||||
*
|
||||
* @param restartable is for functions like read() but not poll()
|
||||
* @return true if EINTR should be returned by caller
|
||||
* @return 1 if delivered, 0 if enqueued, otherwise -1 w/ errno
|
||||
* @note called from main thread
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_raise(int sig, int si_code) {
|
||||
int rc;
|
||||
int candeliver;
|
||||
cthread_spinlock(&__sig_lock);
|
||||
candeliver = !sigismember(&__sig.mask, sig);
|
||||
cthread_spunlock(&__sig_lock);
|
||||
switch (candeliver) {
|
||||
case 1:
|
||||
__sig_handle(false, sig, si_code, 0);
|
||||
return 0;
|
||||
case 0:
|
||||
STRACE("%G is masked", sig);
|
||||
return __sig_add(sig, si_code);
|
||||
default:
|
||||
return -1; // sigismember() validates `sig`
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
* @return 0 if enqueued, otherwise -1 w/ errno
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows int __sig_add(int sig, int si_code) {
|
||||
int rc;
|
||||
struct Signal *mem;
|
||||
if (1 <= sig && sig <= NSIG) {
|
||||
STRACE("enqueuing %G", sig);
|
||||
cthread_spinlock(&__sig_lock);
|
||||
if ((mem = __sig_alloc())) {
|
||||
mem->sig = sig;
|
||||
mem->si_code = si_code;
|
||||
mem->next = __sig.queue;
|
||||
__sig.queue = mem;
|
||||
rc = 0;
|
||||
} else {
|
||||
rc = enomem();
|
||||
}
|
||||
cthread_spunlock(&__sig_lock);
|
||||
} else {
|
||||
rc = einval();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues generic signal for delivery on New Technology.
|
||||
*
|
||||
* @param restartable is for functions like read() but not poll()
|
||||
* @return true if EINTR should be returned by caller
|
||||
* @note called from main thread
|
||||
* @threadsafe
|
||||
*/
|
||||
textwindows bool __sig_check(bool restartable) {
|
||||
unsigned rva;
|
||||
bool delivered;
|
||||
struct Signal *sig;
|
||||
delivered = false;
|
||||
while ((sig = __sig_remove())) {
|
||||
delivered |= __sig_handle(restartable, sig->sig, sig->si_code, 0);
|
||||
__sig_free(sig);
|
||||
}
|
||||
return delivered;
|
||||
}
|
|
@ -301,7 +301,7 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
} else {
|
||||
rc = __sigaction(sig, act, oldact);
|
||||
}
|
||||
STRACE("sigaction(%s, %s, [%s]) → %d% m", strsignal(sig),
|
||||
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig,
|
||||
__strace_sigaction(buf[0], sizeof(buf[0]), 0, act),
|
||||
__strace_sigaction(buf[1], sizeof(buf[1]), rc, oldact), rc);
|
||||
return rc;
|
||||
|
|
|
@ -498,6 +498,21 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
|
|||
goto FormatDecimal;
|
||||
}
|
||||
|
||||
case 'G':
|
||||
x = va_arg(va, int);
|
||||
if (weaken(strsignal)) {
|
||||
s = weaken(strsignal)(x);
|
||||
goto FormatString;
|
||||
} else {
|
||||
if (p + 3 <= e) {
|
||||
p[0] = 'S';
|
||||
p[1] = 'I';
|
||||
p[2] = 'G';
|
||||
}
|
||||
p += 3;
|
||||
goto FormatDecimal;
|
||||
}
|
||||
|
||||
case 'n':
|
||||
// nonstandard %n specifier
|
||||
// used to print newlines that work in raw terminal modes
|
||||
|
@ -823,6 +838,7 @@ privileged void kvprintf(const char *fmt, va_list v) {
|
|||
* - `u` unsigned
|
||||
* - `r` carriage
|
||||
* - `m` strerror
|
||||
* - `G` strsignal
|
||||
* - `X` uppercase
|
||||
* - `T` timestamp
|
||||
* - `x` hexadecimal
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
*/
|
||||
|
||||
STATIC_YOINK("strerror_r"); /* for kprintf %m */
|
||||
STATIC_YOINK("strsignal"); /* for kprintf %G */
|
||||
|
||||
static const char kGregOrder[17] forcealign(1) = {
|
||||
13, 11, 8, 14, 12, 9, 10, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7,
|
||||
|
@ -54,29 +55,8 @@ static const char kGregNames[17][4] forcealign(1) = {
|
|||
static const char kCpuFlags[12] forcealign(1) = "CVPRAKZSTIDO";
|
||||
static const char kFpuExceptions[6] forcealign(1) = "IDZOUP";
|
||||
|
||||
/* <SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
int kCrashSigs[7];
|
||||
struct sigaction g_oldcrashacts[7];
|
||||
static const char kCrashSigNames[7][5] forcealign(1) = {
|
||||
"QUIT", //
|
||||
"FPE", //
|
||||
"ILL", //
|
||||
"SEGV", //
|
||||
"TRAP", //
|
||||
"ABRT", //
|
||||
"BUS", //
|
||||
};
|
||||
/* </SYNC-LIST>: showcrashreports.c, oncrashthunks.S, oncrash.c */
|
||||
|
||||
static relegated noinstrument const char *TinyStrSignal(int sig) {
|
||||
size_t i;
|
||||
for (i = 0; i < ARRAYLEN(kCrashSigs); ++i) {
|
||||
if (kCrashSigs[i] && sig == kCrashSigs[i]) {
|
||||
return kCrashSigNames[i];
|
||||
}
|
||||
}
|
||||
return "???";
|
||||
}
|
||||
|
||||
relegated static void ShowFunctionCalls(ucontext_t *ctx) {
|
||||
struct StackFrame *bp;
|
||||
|
@ -222,12 +202,11 @@ relegated void ShowCrashReport(int err, int sig, struct siginfo *si,
|
|||
uname(&names);
|
||||
p = buf;
|
||||
errno = err;
|
||||
kprintf("%n%serror%s: Uncaught SIG%s (%s) on %s pid %d%n"
|
||||
kprintf("%n%serror%s: Uncaught %G (%s) on %s pid %d%n"
|
||||
" %s%n"
|
||||
" %m%n"
|
||||
" %s %s %s %s%n",
|
||||
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "",
|
||||
TinyStrSignal(sig),
|
||||
!__nocolor ? "\e[30;101m" : "", !__nocolor ? "\e[0m" : "", sig,
|
||||
(ctx && (ctx->uc_mcontext.rsp >= GetStaticStackAddr(0) &&
|
||||
ctx->uc_mcontext.rsp <= GetStaticStackAddr(0) + PAGESIZE))
|
||||
? "Stack Overflow"
|
||||
|
@ -269,13 +248,13 @@ static wontreturn relegated noinstrument void __minicrash(int sig,
|
|||
const char *kind) {
|
||||
kprintf("%n"
|
||||
"%n"
|
||||
"CRASHED %s WITH SIG%s%n"
|
||||
"CRASHED %s WITH %G%n"
|
||||
"%s%n"
|
||||
"RIP %x%n"
|
||||
"RSP %x%n"
|
||||
"RBP %x%n"
|
||||
"%n",
|
||||
kind, TinyStrSignal(sig), __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
|
||||
kind, sig, __argv[0], ctx ? ctx->uc_mcontext.rip : 0,
|
||||
ctx ? ctx->uc_mcontext.rsp : 0, ctx ? ctx->uc_mcontext.rbp : 0);
|
||||
__restorewintty();
|
||||
_Exit(119);
|
||||
|
|
|
@ -1,2 +1,15 @@
|
|||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_SetDefaultDllDirectories,SetDefaultDllDirectories,0
|
||||
|
||||
.text.windows
|
||||
SetDefaultDllDirectories:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
mov %rdi,%rcx
|
||||
sub $32,%rsp
|
||||
call *__imp_SetDefaultDllDirectories(%rip)
|
||||
leave
|
||||
ret
|
||||
.endfn SetDefaultDllDirectories,globl
|
||||
.previous
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
.include "o/libc/nt/codegen.inc"
|
||||
.imp kernel32,__imp_SetLastError,SetLastError,1336
|
||||
.imp kernel32,__imp_SetLastError,SetLastError,0
|
||||
|
||||
.text.windows
|
||||
SetLastError:
|
||||
|
|
|
@ -1103,7 +1103,7 @@ imp 'SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1
|
|||
imp 'SetCurrentDirectoryA' SetCurrentDirectoryA kernel32 0 1
|
||||
imp 'SetDefaultCommConfig' SetDefaultCommConfigW kernel32 1298
|
||||
imp 'SetDefaultCommConfigA' SetDefaultCommConfigA kernel32 1297
|
||||
imp 'SetDefaultDllDirectories' SetDefaultDllDirectories kernel32 0 1, Windows 8+, KB2533623 on Windows 7
|
||||
imp 'SetDefaultDllDirectories' SetDefaultDllDirectories kernel32 0 1 # Windows 8+, KB2533623 on Windows 7
|
||||
imp 'SetDllDirectory' SetDllDirectoryW kernel32 1301
|
||||
imp 'SetDllDirectoryA' SetDllDirectoryA kernel32 1300
|
||||
imp 'SetDynamicTimeZoneInformation' SetDynamicTimeZoneInformation kernel32 0
|
||||
|
@ -1137,7 +1137,7 @@ imp 'SetHandleCount' SetHandleCount kernel32 0 1
|
|||
imp 'SetHandleInformation' SetHandleInformation kernel32 0 3
|
||||
imp 'SetInformationJobObject' SetInformationJobObject kernel32 1333
|
||||
imp 'SetIoRateControlInformationJobObject' SetIoRateControlInformationJobObject kernel32 1334
|
||||
imp 'SetLastError' SetLastError kernel32 1336 1
|
||||
imp 'SetLastError' SetLastError kernel32 0 1
|
||||
imp 'SetLocalPrimaryComputerName' SetLocalPrimaryComputerNameW kernel32 1338
|
||||
imp 'SetLocalPrimaryComputerNameA' SetLocalPrimaryComputerNameA kernel32 1337
|
||||
imp 'SetLocalTime' SetLocalTime kernel32 0
|
||||
|
|
|
@ -109,7 +109,6 @@ noasan int munmap(void *v, size_t n) {
|
|||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
STRACE("munmap(%.12p, %'zu) → %d %s", p, n, rc,
|
||||
rc == -1 ? strerror(errno) : "");
|
||||
STRACE("munmap(%.12p, %'zu) → %d% m", p, n, rc);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ textstartup void __printargs(void) {
|
|||
PRINT("BLOCKED SIGNALS {%#lx, %#lx}", ss.__bits[0], ss.__bits[1]);
|
||||
for (i = 0; i < 32; ++i) {
|
||||
if (ss.__bits[0] & (1u << i)) {
|
||||
PRINT(" ☼ %s (%d)", strsignal(i + 1), i + 1);
|
||||
PRINT(" ☼ %G (%d)", i + 1, i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue