2020-06-15 14:18:57 +00:00
|
|
|
/*-*- 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 2020 Justine Alexandra Roberts Tunney │
|
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
│ 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. │
|
2020-06-15 14:18:57 +00:00
|
|
|
│ │
|
2020-12-28 01:18:44 +00:00
|
|
|
│ 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. │
|
2020-06-15 14:18:57 +00:00
|
|
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
2023-04-27 03:45:01 +00:00
|
|
|
#include "libc/calls/struct/sigaction.h"
|
2023-05-19 02:05:08 +00:00
|
|
|
#include "ape/sections.internal.h"
|
2021-02-08 17:19:00 +00:00
|
|
|
#include "libc/assert.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
#include "libc/calls/blocksigs.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/calls/calls.h"
|
|
|
|
#include "libc/calls/internal.h"
|
2022-05-27 20:25:46 +00:00
|
|
|
#include "libc/calls/sig.internal.h"
|
2022-05-23 22:06:11 +00:00
|
|
|
#include "libc/calls/state.internal.h"
|
2023-07-10 11:29:46 +00:00
|
|
|
#include "libc/calls/struct/sigaction.h"
|
2022-08-13 20:11:56 +00:00
|
|
|
#include "libc/calls/struct/sigaction.internal.h"
|
|
|
|
#include "libc/calls/struct/siginfo.internal.h"
|
2022-10-17 18:02:04 +00:00
|
|
|
#include "libc/calls/struct/sigset.h"
|
2022-05-23 22:06:11 +00:00
|
|
|
#include "libc/calls/syscall-sysv.internal.h"
|
|
|
|
#include "libc/calls/syscall_support-sysv.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/calls/ucontext.h"
|
|
|
|
#include "libc/dce.h"
|
Improve ZIP filesystem and change its prefix
The ZIP filesystem has a breaking change. You now need to use /zip/ to
open() / opendir() / etc. assets within the ZIP structure of your APE
binary, instead of the previous convention of using zip: or zip! URIs.
This is needed because Python likes to use absolute paths, and having
ZIP paths encoded like URIs simply broke too many things.
Many more system calls have been updated to be able to operate on ZIP
files and file descriptors. In particular fcntl() and ioctl() since
Python would do things like ask if a ZIP file is a terminal and get
confused when the old implementation mistakenly said yes, because the
fastest way to guarantee native file descriptors is to dup(2). This
change also improves the async signal safety of zipos and ensures it
doesn't maintain any open file descriptors beyond that which the user
has opened.
This change makes a lot of progress towards adding magic numbers that
are specific to platforms other than Linux. The philosophy here is that,
if you use an operating system like FreeBSD, then you should be able to
take advantage of FreeBSD exclusive features, even if we don't polyfill
them on other platforms. For example, you can now open() a file with the
O_VERIFY flag. If your program runs on other platforms, then Cosmo will
automatically set O_VERIFY to zero. This lets you safely use it without
the need for #ifdef or ifstatements which detract from readability.
One of the blindspots of the ASAN memory hardening we use to offer Rust
like assurances has always been that memory passed to the kernel via
system calls (e.g. writev) can't be checked automatically since the
kernel wasn't built with MODE=asan. This change makes more progress
ensuring that each system call will verify the soundness of memory
before it's passed to the kernel. The code for doing these checks is
fast, particularly for buffers, where it can verify 64 bytes a cycle.
- Correct O_LOOP definition on NT
- Introduce program_executable_name
- Add ASAN guards to more system calls
- Improve termios compatibility with BSDs
- Fix bug in Windows auxiliary value encoding
- Add BSD and XNU specific errnos and open flags
- Add check to ensure build doesn't talk to internet
2021-08-22 08:04:18 +00:00
|
|
|
#include "libc/intrin/asan.internal.h"
|
2022-08-13 20:11:56 +00:00
|
|
|
#include "libc/intrin/bits.h"
|
2022-05-12 13:43:59 +00:00
|
|
|
#include "libc/intrin/describeflags.internal.h"
|
2022-09-13 06:10:38 +00:00
|
|
|
#include "libc/intrin/strace.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/limits.h"
|
2022-04-28 16:42:36 +00:00
|
|
|
#include "libc/log/backtrace.internal.h"
|
|
|
|
#include "libc/log/log.h"
|
2021-03-01 07:42:35 +00:00
|
|
|
#include "libc/macros.internal.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/mem/mem.h"
|
|
|
|
#include "libc/runtime/runtime.h"
|
|
|
|
#include "libc/str/str.h"
|
2022-11-07 10:22:09 +00:00
|
|
|
#include "libc/sysv/consts/limits.h"
|
2020-06-15 14:18:57 +00:00
|
|
|
#include "libc/sysv/consts/sa.h"
|
|
|
|
#include "libc/sysv/consts/sig.h"
|
|
|
|
#include "libc/sysv/errfuns.h"
|
|
|
|
|
2022-04-16 17:40:23 +00:00
|
|
|
#ifdef SYSDEBUG
|
2023-07-26 20:54:49 +00:00
|
|
|
__static_yoink("strsignal"); // for kprintf()
|
2022-04-16 17:40:23 +00:00
|
|
|
#endif
|
|
|
|
|
2023-07-10 11:29:46 +00:00
|
|
|
#if SupportsWindows()
|
2023-07-26 20:54:49 +00:00
|
|
|
__static_yoink("_init_onntconsoleevent");
|
|
|
|
__static_yoink("_check_sigwinch");
|
|
|
|
__static_yoink("_init_wincrash");
|
2023-07-10 11:29:46 +00:00
|
|
|
#endif
|
|
|
|
|
2021-04-18 18:34:59 +00:00
|
|
|
#define SA_RESTORER 0x04000000
|
|
|
|
|
2021-02-05 17:44:54 +00:00
|
|
|
static void sigaction_cosmo2native(union metasigaction *sa) {
|
2022-11-07 10:22:09 +00:00
|
|
|
void *handler;
|
|
|
|
uint64_t flags;
|
|
|
|
void *restorer;
|
|
|
|
uint32_t mask[4];
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!sa) return;
|
2022-11-07 10:22:09 +00:00
|
|
|
flags = sa->cosmo.sa_flags;
|
|
|
|
handler = sa->cosmo.sa_handler;
|
|
|
|
restorer = sa->cosmo.sa_restorer;
|
|
|
|
mask[0] = sa->cosmo.sa_mask.__bits[0];
|
|
|
|
mask[1] = sa->cosmo.sa_mask.__bits[0] >> 32;
|
|
|
|
mask[2] = sa->cosmo.sa_mask.__bits[1];
|
|
|
|
mask[3] = sa->cosmo.sa_mask.__bits[1] >> 32;
|
|
|
|
if (IsLinux()) {
|
|
|
|
sa->linux.sa_flags = flags;
|
|
|
|
sa->linux.sa_handler = handler;
|
|
|
|
sa->linux.sa_restorer = restorer;
|
|
|
|
sa->linux.sa_mask[0] = mask[0];
|
|
|
|
sa->linux.sa_mask[1] = mask[1];
|
|
|
|
} else if (IsXnu()) {
|
|
|
|
sa->xnu_in.sa_flags = flags;
|
|
|
|
sa->xnu_in.sa_handler = handler;
|
|
|
|
sa->xnu_in.sa_restorer = restorer;
|
|
|
|
sa->xnu_in.sa_mask[0] = mask[0];
|
|
|
|
} else if (IsFreebsd()) {
|
|
|
|
sa->freebsd.sa_flags = flags;
|
|
|
|
sa->freebsd.sa_handler = handler;
|
|
|
|
sa->freebsd.sa_mask[0] = mask[0];
|
|
|
|
sa->freebsd.sa_mask[1] = mask[1];
|
|
|
|
sa->freebsd.sa_mask[2] = mask[2];
|
|
|
|
sa->freebsd.sa_mask[3] = mask[3];
|
|
|
|
} else if (IsOpenbsd()) {
|
|
|
|
sa->openbsd.sa_flags = flags;
|
|
|
|
sa->openbsd.sa_handler = handler;
|
|
|
|
sa->openbsd.sa_mask[0] = mask[0];
|
|
|
|
} else if (IsNetbsd()) {
|
|
|
|
sa->netbsd.sa_flags = flags;
|
|
|
|
sa->netbsd.sa_handler = handler;
|
|
|
|
sa->netbsd.sa_mask[0] = mask[0];
|
|
|
|
sa->netbsd.sa_mask[1] = mask[1];
|
|
|
|
sa->netbsd.sa_mask[2] = mask[2];
|
|
|
|
sa->netbsd.sa_mask[3] = mask[3];
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-05 17:44:54 +00:00
|
|
|
static void sigaction_native2cosmo(union metasigaction *sa) {
|
2022-11-07 10:22:09 +00:00
|
|
|
void *handler;
|
|
|
|
uint64_t flags;
|
|
|
|
void *restorer = 0;
|
|
|
|
uint32_t mask[4] = {0};
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!sa) return;
|
2022-11-07 10:22:09 +00:00
|
|
|
if (IsLinux()) {
|
|
|
|
flags = sa->linux.sa_flags;
|
|
|
|
handler = sa->linux.sa_handler;
|
|
|
|
restorer = sa->linux.sa_restorer;
|
|
|
|
mask[0] = sa->linux.sa_mask[0];
|
|
|
|
mask[1] = sa->linux.sa_mask[1];
|
|
|
|
} else if (IsXnu()) {
|
|
|
|
flags = sa->xnu_out.sa_flags;
|
|
|
|
handler = sa->xnu_out.sa_handler;
|
|
|
|
mask[0] = sa->xnu_out.sa_mask[0];
|
|
|
|
} else if (IsFreebsd()) {
|
|
|
|
flags = sa->freebsd.sa_flags;
|
|
|
|
handler = sa->freebsd.sa_handler;
|
|
|
|
mask[0] = sa->freebsd.sa_mask[0];
|
|
|
|
mask[1] = sa->freebsd.sa_mask[1];
|
|
|
|
mask[2] = sa->freebsd.sa_mask[2];
|
|
|
|
mask[3] = sa->freebsd.sa_mask[3];
|
|
|
|
} else if (IsOpenbsd()) {
|
|
|
|
flags = sa->openbsd.sa_flags;
|
|
|
|
handler = sa->openbsd.sa_handler;
|
|
|
|
mask[0] = sa->openbsd.sa_mask[0];
|
|
|
|
} else if (IsNetbsd()) {
|
|
|
|
flags = sa->netbsd.sa_flags;
|
|
|
|
handler = sa->netbsd.sa_handler;
|
|
|
|
mask[0] = sa->netbsd.sa_mask[0];
|
|
|
|
mask[1] = sa->netbsd.sa_mask[1];
|
|
|
|
mask[2] = sa->netbsd.sa_mask[2];
|
|
|
|
mask[3] = sa->netbsd.sa_mask[3];
|
|
|
|
} else {
|
|
|
|
return;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
2022-11-07 10:22:09 +00:00
|
|
|
sa->cosmo.sa_flags = flags;
|
|
|
|
sa->cosmo.sa_handler = handler;
|
|
|
|
sa->cosmo.sa_restorer = restorer;
|
|
|
|
sa->cosmo.sa_mask.__bits[0] = mask[0] | (uint64_t)mask[1] << 32;
|
|
|
|
sa->cosmo.sa_mask.__bits[1] = mask[2] | (uint64_t)mask[3] << 32;
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
static int __sigaction(int sig, const struct sigaction *act,
|
|
|
|
struct sigaction *oldact) {
|
2022-11-07 10:22:09 +00:00
|
|
|
_Static_assert(
|
|
|
|
(sizeof(struct sigaction) >= sizeof(struct sigaction_linux) &&
|
|
|
|
sizeof(struct sigaction) >= sizeof(struct sigaction_xnu_in) &&
|
|
|
|
sizeof(struct sigaction) >= sizeof(struct sigaction_xnu_out) &&
|
|
|
|
sizeof(struct sigaction) >= sizeof(struct sigaction_freebsd) &&
|
|
|
|
sizeof(struct sigaction) >= sizeof(struct sigaction_openbsd) &&
|
|
|
|
sizeof(struct sigaction) >= sizeof(struct sigaction_netbsd)),
|
|
|
|
"sigaction cosmo abi needs tuning");
|
2021-02-05 17:44:54 +00:00
|
|
|
int64_t arg4, arg5;
|
2020-06-15 14:18:57 +00:00
|
|
|
int rc, rva, oldrva;
|
2022-11-02 13:49:42 +00:00
|
|
|
sigaction_f sigenter;
|
2020-06-15 14:18:57 +00:00
|
|
|
struct sigaction *ap, copy;
|
2021-02-24 04:23:19 +00:00
|
|
|
if (IsMetal()) return enosys(); /* TODO: Signals on Metal */
|
2022-11-07 10:22:09 +00:00
|
|
|
if (!(1 <= sig && sig <= _NSIG)) return einval();
|
2021-02-03 14:22:51 +00:00
|
|
|
if (sig == SIGKILL || sig == SIGSTOP) return einval();
|
Improve ZIP filesystem and change its prefix
The ZIP filesystem has a breaking change. You now need to use /zip/ to
open() / opendir() / etc. assets within the ZIP structure of your APE
binary, instead of the previous convention of using zip: or zip! URIs.
This is needed because Python likes to use absolute paths, and having
ZIP paths encoded like URIs simply broke too many things.
Many more system calls have been updated to be able to operate on ZIP
files and file descriptors. In particular fcntl() and ioctl() since
Python would do things like ask if a ZIP file is a terminal and get
confused when the old implementation mistakenly said yes, because the
fastest way to guarantee native file descriptors is to dup(2). This
change also improves the async signal safety of zipos and ensures it
doesn't maintain any open file descriptors beyond that which the user
has opened.
This change makes a lot of progress towards adding magic numbers that
are specific to platforms other than Linux. The philosophy here is that,
if you use an operating system like FreeBSD, then you should be able to
take advantage of FreeBSD exclusive features, even if we don't polyfill
them on other platforms. For example, you can now open() a file with the
O_VERIFY flag. If your program runs on other platforms, then Cosmo will
automatically set O_VERIFY to zero. This lets you safely use it without
the need for #ifdef or ifstatements which detract from readability.
One of the blindspots of the ASAN memory hardening we use to offer Rust
like assurances has always been that memory passed to the kernel via
system calls (e.g. writev) can't be checked automatically since the
kernel wasn't built with MODE=asan. This change makes more progress
ensuring that each system call will verify the soundness of memory
before it's passed to the kernel. The code for doing these checks is
fast, particularly for buffers, where it can verify 64 bytes a cycle.
- Correct O_LOOP definition on NT
- Introduce program_executable_name
- Add ASAN guards to more system calls
- Improve termios compatibility with BSDs
- Fix bug in Windows auxiliary value encoding
- Add BSD and XNU specific errnos and open flags
- Add check to ensure build doesn't talk to internet
2021-08-22 08:04:18 +00:00
|
|
|
if (IsAsan() && ((act && !__asan_is_valid(act, sizeof(*act))) ||
|
|
|
|
(oldact && !__asan_is_valid(oldact, sizeof(*oldact))))) {
|
|
|
|
return efault();
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!act) {
|
|
|
|
rva = (int32_t)(intptr_t)SIG_DFL;
|
|
|
|
} else if ((intptr_t)act->sa_handler < kSigactionMinRva) {
|
|
|
|
rva = (int)(intptr_t)act->sa_handler;
|
2023-05-19 02:05:08 +00:00
|
|
|
} else if ((intptr_t)act->sa_handler >=
|
|
|
|
(intptr_t)&__executable_start + kSigactionMinRva &&
|
|
|
|
(intptr_t)act->sa_handler <
|
|
|
|
(intptr_t)&__executable_start + INT_MAX) {
|
|
|
|
rva = (int)((uintptr_t)act->sa_handler - (uintptr_t)&__executable_start);
|
2020-06-15 14:18:57 +00:00
|
|
|
} else {
|
|
|
|
return efault();
|
|
|
|
}
|
2021-02-03 14:22:51 +00:00
|
|
|
if (__vforked && rva != (intptr_t)SIG_DFL && rva != (intptr_t)SIG_IGN) {
|
|
|
|
return einval();
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
if (!IsWindows()) {
|
2021-02-05 17:44:54 +00:00
|
|
|
if (act) {
|
|
|
|
memcpy(©, act, sizeof(copy));
|
|
|
|
ap = ©
|
2022-11-07 10:22:09 +00:00
|
|
|
|
|
|
|
if (IsLinux()) {
|
|
|
|
if (!(ap->sa_flags & SA_RESTORER)) {
|
|
|
|
ap->sa_flags |= SA_RESTORER;
|
|
|
|
ap->sa_restorer = &__restore_rt;
|
|
|
|
}
|
|
|
|
if (IsWsl1()) {
|
|
|
|
sigenter = __sigenter_wsl;
|
|
|
|
} else {
|
|
|
|
sigenter = ap->sa_sigaction;
|
|
|
|
}
|
|
|
|
} else if (IsXnu()) {
|
2021-02-26 02:30:17 +00:00
|
|
|
ap->sa_restorer = (void *)&__sigenter_xnu;
|
2022-11-02 13:49:42 +00:00
|
|
|
sigenter = __sigenter_xnu;
|
2022-08-19 20:00:50 +00:00
|
|
|
// mitigate Rosetta signal handling strangeness
|
|
|
|
// https://github.com/jart/cosmopolitan/issues/455
|
|
|
|
ap->sa_flags |= SA_SIGINFO;
|
2021-02-05 17:44:54 +00:00
|
|
|
} else if (IsNetbsd()) {
|
2022-11-02 13:49:42 +00:00
|
|
|
sigenter = __sigenter_netbsd;
|
2021-02-26 02:30:17 +00:00
|
|
|
} else if (IsFreebsd()) {
|
2022-11-02 13:49:42 +00:00
|
|
|
sigenter = __sigenter_freebsd;
|
2021-02-26 02:30:17 +00:00
|
|
|
} else if (IsOpenbsd()) {
|
2022-11-02 13:49:42 +00:00
|
|
|
sigenter = __sigenter_openbsd;
|
2021-02-26 02:30:17 +00:00
|
|
|
} else {
|
|
|
|
return enosys();
|
2021-02-05 17:44:54 +00:00
|
|
|
}
|
2022-11-02 13:49:42 +00:00
|
|
|
if (rva < kSigactionMinRva) {
|
|
|
|
ap->sa_sigaction = (void *)(intptr_t)rva;
|
|
|
|
} else {
|
|
|
|
ap->sa_sigaction = sigenter;
|
|
|
|
}
|
2021-02-05 17:44:54 +00:00
|
|
|
sigaction_cosmo2native((union metasigaction *)ap);
|
|
|
|
} else {
|
|
|
|
ap = NULL;
|
|
|
|
}
|
|
|
|
if (IsXnu()) {
|
|
|
|
arg4 = (int64_t)(intptr_t)oldact; /* from go code */
|
|
|
|
arg5 = 0;
|
|
|
|
} else if (IsNetbsd()) {
|
2022-07-19 05:26:11 +00:00
|
|
|
/* int __sigaction_sigtramp(int signum,
|
|
|
|
const struct sigaction *nsa,
|
|
|
|
struct sigaction *osa,
|
|
|
|
const void *tramp,
|
|
|
|
int vers); */
|
2021-02-05 17:44:54 +00:00
|
|
|
if (ap) {
|
|
|
|
arg4 = (int64_t)(intptr_t)&__restore_rt_netbsd;
|
|
|
|
arg5 = 2; /* netbsd/lib/libc/arch/x86_64/sys/__sigtramp2.S */
|
2021-01-17 01:52:15 +00:00
|
|
|
} else {
|
2021-02-05 17:44:54 +00:00
|
|
|
arg4 = 0;
|
|
|
|
arg5 = 0; /* netbsd/lib/libc/arch/x86_64/sys/__sigtramp2.S */
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
} else {
|
2021-02-05 17:44:54 +00:00
|
|
|
arg4 = 8; /* or linux whines */
|
|
|
|
arg5 = 0;
|
|
|
|
}
|
|
|
|
if ((rc = sys_sigaction(sig, ap, oldact, arg4, arg5)) != -1) {
|
|
|
|
sigaction_native2cosmo((union metasigaction *)oldact);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (oldact) {
|
2021-09-28 05:58:51 +00:00
|
|
|
bzero(oldact, sizeof(*oldact));
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
rc = 0;
|
|
|
|
}
|
2021-02-03 14:22:51 +00:00
|
|
|
if (rc != -1 && !__vforked) {
|
2020-06-15 14:18:57 +00:00
|
|
|
if (oldact) {
|
2021-01-28 23:49:15 +00:00
|
|
|
oldrva = __sighandrvas[sig];
|
2023-04-27 03:45:01 +00:00
|
|
|
oldact->sa_sigaction =
|
2023-05-19 02:05:08 +00:00
|
|
|
(sigaction_f)(oldrva < kSigactionMinRva
|
|
|
|
? oldrva
|
|
|
|
: (intptr_t)&__executable_start + oldrva);
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
if (act) {
|
2021-01-28 23:49:15 +00:00
|
|
|
__sighandrvas[sig] = rva;
|
2022-03-25 14:11:44 +00:00
|
|
|
__sighandflags[sig] = act->sa_flags;
|
2023-05-09 08:56:56 +00:00
|
|
|
if (IsWindows()) {
|
|
|
|
__sig_check_ignore(sig, rva);
|
|
|
|
}
|
2020-06-15 14:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return rc;
|
|
|
|
}
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
|
|
|
|
/**
|
2022-08-07 23:18:33 +00:00
|
|
|
* Installs handler for kernel interrupt to thread, e.g.:
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
*
|
2022-09-02 12:08:35 +00:00
|
|
|
* void GotCtrlC(int sig, siginfo_t *si, void *ctx);
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
* struct sigaction sa = {.sa_sigaction = GotCtrlC,
|
|
|
|
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
|
|
|
|
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
|
|
|
|
*
|
2022-04-13 05:11:00 +00:00
|
|
|
* The following flags are supported across platforms:
|
|
|
|
*
|
|
|
|
* - `SA_SIGINFO`: Causes the `siginfo_t` and `ucontext_t` parameters to
|
2022-09-02 12:08:35 +00:00
|
|
|
* be passed. `void *ctx` actually refers to `struct ucontext *`.
|
|
|
|
* This not only gives you more information about the signal, but also
|
|
|
|
* allows your signal handler to change the CPU registers. That's
|
|
|
|
* useful for recovering from crashes. If you don't use this attribute,
|
|
|
|
* then signal delivery will go a little faster.
|
2022-04-13 05:11:00 +00:00
|
|
|
*
|
|
|
|
* - `SA_RESTART`: Enables BSD signal handling semantics. Normally i/o
|
|
|
|
* entrypoints check for pending signals to deliver. If one gets
|
|
|
|
* delivered during an i/o call, the normal behavior is to cancel the
|
|
|
|
* i/o operation and return -1 with EINTR in errno. If you use the
|
|
|
|
* `SA_RESTART` flag then that behavior changes, so that any function
|
|
|
|
* that's been annotated with @restartable will not return `EINTR` and
|
|
|
|
* will instead resume the i/o operation. This makes coding easier but
|
|
|
|
* it can be an anti-pattern if not used carefully, since poor usage
|
|
|
|
* can easily result in latency issues. It also requires one to do
|
|
|
|
* more work in signal handlers, so special care needs to be given to
|
|
|
|
* which C library functions are @asyncsignalsafe.
|
|
|
|
*
|
|
|
|
* - `SA_RESETHAND`: Causes signal handler to be single-shot. This means
|
|
|
|
* that, upon entry of delivery to a signal handler, it's reset to the
|
|
|
|
* `SIG_DFL` handler automatically. You may use the alias `SA_ONESHOT`
|
|
|
|
* for this flag, which means the same thing.
|
|
|
|
*
|
|
|
|
* - `SA_NODEFER`: Disables the reentrancy safety check on your signal
|
|
|
|
* handler. Normally that's a good thing, since for instance if your
|
|
|
|
* `SIGSEGV` signal handler happens to segfault, you're going to want
|
|
|
|
* your process to just crash rather than looping endlessly. But in
|
|
|
|
* some cases it's desirable to use `SA_NODEFER` instead, such as at
|
|
|
|
* times when you wish to `longjmp()` out of your signal handler and
|
|
|
|
* back into your program. This is only safe to do across platforms
|
|
|
|
* for non-crashing signals such as `SIGCHLD` and `SIGINT`. Crash
|
|
|
|
* handlers should use Xed instead to recover execution, because on
|
|
|
|
* Windows a `SIGSEGV` or `SIGTRAP` crash handler might happen on a
|
|
|
|
* separate stack and/or a separate thread. You may use the alias
|
|
|
|
* `SA_NOMASK` for this flag, which means the same thing.
|
|
|
|
*
|
|
|
|
* - `SA_NOCLDWAIT`: Changes `SIGCHLD` so the zombie is gone and you
|
2022-04-20 16:56:53 +00:00
|
|
|
* can't call `wait()` anymore; similar but may
|
2022-04-13 05:11:00 +00:00
|
|
|
* still deliver the SIGCHLD.
|
|
|
|
*
|
|
|
|
* - `SA_NOCLDSTOP`: Lets you set `SIGCHLD` handler that's only notified
|
|
|
|
* on exit/termination and not notified on `SIGSTOP`, `SIGTSTP`,
|
|
|
|
* `SIGTTIN`, `SIGTTOU`, or `SIGCONT`.
|
|
|
|
*
|
|
|
|
* Here's an example of the most professional way to handle signals in
|
|
|
|
* an i/o event loop. It's generally a best practice to have signal
|
|
|
|
* handlers do the fewest number of things possible. The trick is to
|
|
|
|
* have your signals work hand-in-glove with the EINTR errno. This
|
|
|
|
* obfuscates the need for having to worry about @asyncsignalsafe.
|
2022-04-12 12:20:17 +00:00
|
|
|
*
|
2022-04-17 19:25:10 +00:00
|
|
|
* static volatile bool gotctrlc;
|
2022-04-13 05:11:00 +00:00
|
|
|
*
|
2022-04-17 19:25:10 +00:00
|
|
|
* void OnCtrlC(int sig) {
|
|
|
|
* gotctrlc = true;
|
|
|
|
* }
|
2022-04-13 05:11:00 +00:00
|
|
|
*
|
2022-04-17 19:25:10 +00:00
|
|
|
* int main() {
|
|
|
|
* size_t got;
|
|
|
|
* ssize_t rc;
|
|
|
|
* char buf[1];
|
|
|
|
* struct sigaction oldint;
|
|
|
|
* struct sigaction saint = {.sa_handler = GotCtrlC};
|
|
|
|
* if (sigaction(SIGINT, &saint, &oldint) == -1) {
|
|
|
|
* perror("sigaction");
|
|
|
|
* exit(1);
|
|
|
|
* }
|
|
|
|
* for (;;) {
|
|
|
|
* rc = read(0, buf, sizeof(buf));
|
|
|
|
* if (rc == -1) {
|
|
|
|
* if (errno == EINTR) {
|
|
|
|
* if (gotctrlc) {
|
|
|
|
* break;
|
|
|
|
* }
|
|
|
|
* } else {
|
|
|
|
* perror("read");
|
|
|
|
* exit(2);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* if (!(got = rc)) {
|
|
|
|
* break;
|
|
|
|
* }
|
|
|
|
* for (;;) {
|
|
|
|
* rc = write(1, buf, got);
|
|
|
|
* if (rc != -1) {
|
|
|
|
* assert(rc == 1);
|
|
|
|
* break;
|
|
|
|
* } else if (errno != EINTR) {
|
|
|
|
* perror("write");
|
|
|
|
* exit(3);
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* sigaction(SIGINT, &oldint, 0);
|
|
|
|
* }
|
2022-04-12 12:20:17 +00:00
|
|
|
*
|
|
|
|
* Please note that you can't do the above if you use SA_RESTART. Since
|
|
|
|
* the purpose of SA_RESTART is to restart i/o operations whose docs say
|
2022-04-13 05:11:00 +00:00
|
|
|
* that they're @restartable and read() is one such function. Here's
|
|
|
|
* some even better news: if you don't install any signal handlers at
|
|
|
|
* all, then your i/o calls will never be interrupted!
|
|
|
|
*
|
|
|
|
* Here's an example of the most professional way to recover from
|
|
|
|
* `SIGSEGV`, `SIGFPE`, and `SIGILL`.
|
|
|
|
*
|
|
|
|
* void ContinueOnCrash(void);
|
|
|
|
*
|
|
|
|
* void SkipOverFaultingInstruction(struct ucontext *ctx) {
|
|
|
|
* struct XedDecodedInst xedd;
|
|
|
|
* xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
|
|
|
* xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
|
|
|
|
* ctx->uc_mcontext.rip += xedd.length;
|
|
|
|
* }
|
|
|
|
*
|
2022-09-02 12:08:35 +00:00
|
|
|
* void OnCrash(int sig, struct siginfo *si, void *vctx) {
|
|
|
|
* struct ucontext *ctx = vctx;
|
2022-04-13 05:11:00 +00:00
|
|
|
* SkipOverFaultingInstruction(ctx);
|
|
|
|
* ContinueOnCrash(); // reinstall here in case *rip faults
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* void ContinueOnCrash(void) {
|
|
|
|
* struct sigaction sa = {.sa_handler = OnSigSegv,
|
|
|
|
* .sa_flags = SA_SIGINFO | SA_RESETHAND};
|
|
|
|
* sigaction(SIGSEGV, &sa, 0);
|
|
|
|
* sigaction(SIGFPE, &sa, 0);
|
|
|
|
* sigaction(SIGILL, &sa, 0);
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* int main() {
|
|
|
|
* ContinueOnCrash();
|
|
|
|
* // ...
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* You may also edit any other CPU registers during the handler. For
|
|
|
|
* example, you can use the above technique so that division by zero
|
|
|
|
* becomes defined to a specific value of your choosing!
|
|
|
|
*
|
|
|
|
* Please note that Xed isn't needed to recover from `SIGTRAP` which can
|
|
|
|
* be raised at any time by embedding `DebugBreak()` or `asm("int3")` in
|
|
|
|
* your program code. Your signal handler will automatically skip over
|
|
|
|
* the interrupt instruction, assuming your signal handler returns.
|
|
|
|
*
|
|
|
|
* The important signals supported across all platforms are:
|
|
|
|
*
|
|
|
|
* - `SIGINT`: When you press Ctrl-C this signal gets broadcasted to
|
|
|
|
* your process session group. This is the normal way to terminate
|
|
|
|
* console applications.
|
|
|
|
*
|
|
|
|
* - `SIGQUIT`: When you press CTRL-\ this signal gets broadcasted to
|
|
|
|
* your process session group. This is the irregular way to kill an
|
|
|
|
* application in cases where maybe your `SIGINT` handler is broken
|
|
|
|
* although, Cosmopolitan Libc ShowCrashReports() should program it
|
|
|
|
* such as to attach a debugger to the process if possible, or else
|
|
|
|
* show a crash report. Also note that in New Technology you should
|
|
|
|
* press CTRL+BREAK rather than CTRL+\ to get this signal.
|
|
|
|
*
|
|
|
|
* - `SIGHUP`: This gets sent to your non-daemon processes when you
|
|
|
|
* close your terminal session.
|
|
|
|
*
|
|
|
|
* - `SIGTERM` is what the `kill` command sends by default. It's the
|
|
|
|
* choice signal for terminating daemons.
|
|
|
|
*
|
|
|
|
* - `SIGUSR1` and `SIGUSR2` can be anything you want. Their default
|
|
|
|
* action is to kill the process. By convention `SIGUSR1` is usually
|
|
|
|
* used by daemons to reload the config file.
|
|
|
|
*
|
|
|
|
* - `SIGCHLD` is sent when a process terminates and it takes a certain
|
|
|
|
* degree of UNIX mastery to address sanely.
|
|
|
|
*
|
|
|
|
* - `SIGALRM` is invoked by `setitimer()` and `alarm()`. It can be
|
|
|
|
* useful for interrupting i/o operations like `connect()`.
|
|
|
|
*
|
|
|
|
* - `SIGTRAP`: This happens when an INT3 instruction is encountered.
|
|
|
|
*
|
|
|
|
* - `SIGILL` happens on illegal instructions, e.g. `UD2`.
|
|
|
|
*
|
|
|
|
* - `SIGABRT` happens when you call `abort()`.
|
|
|
|
*
|
|
|
|
* - `SIGFPE` happens when you divide ints by zero, among other things.
|
|
|
|
*
|
|
|
|
* - `SIGSEGV` and `SIGBUS` indicate memory access errors and they have
|
|
|
|
* inconsistent semantics across platforms like FreeBSD.
|
|
|
|
*
|
|
|
|
* - `SIGWINCH` is sent when your terminal window is resized.
|
|
|
|
*
|
|
|
|
* - `SIGXCPU` and `SIGXFSZ` may be raised if you run out of resources,
|
|
|
|
* which can happen if your process, or the parent process that
|
|
|
|
* spawned your process, happened to call `setrlimit()`. Doing this is
|
|
|
|
* a wonderful idea.
|
2022-04-12 12:20:17 +00:00
|
|
|
*
|
2023-07-04 00:35:11 +00:00
|
|
|
* Using signals might make your C runtime slower. Upon successfully
|
|
|
|
* installing its first signal handling function, sigaction() will set
|
|
|
|
* the global variable `__interruptible` to true, to let everything else
|
|
|
|
* know that signals are in play. That way code which would otherwise be
|
|
|
|
* frequently calling sigprocmask() out of an abundance of caution, will
|
|
|
|
* no longer need to pay its outrageous cost.
|
|
|
|
*
|
2022-03-25 14:11:44 +00:00
|
|
|
* @return 0 on success or -1 w/ errno
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
* @see xsigaction() for a much better api
|
|
|
|
* @asyncsignalsafe
|
|
|
|
* @vforksafe
|
|
|
|
*/
|
2022-04-20 16:56:53 +00:00
|
|
|
int sigaction(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
int rc;
|
2022-04-12 12:20:17 +00:00
|
|
|
if (sig == SIGKILL || sig == SIGSTOP) {
|
|
|
|
rc = einval();
|
|
|
|
} else {
|
|
|
|
rc = __sigaction(sig, act, oldact);
|
2023-07-04 00:35:11 +00:00
|
|
|
if (!rc && act && (uintptr_t)act->sa_handler >= kSigactionMinRva) {
|
|
|
|
static bool once;
|
|
|
|
if (!once) {
|
|
|
|
__interruptible = true;
|
|
|
|
once = true;
|
|
|
|
}
|
|
|
|
}
|
2022-04-12 12:20:17 +00:00
|
|
|
}
|
2022-06-26 01:17:31 +00:00
|
|
|
STRACE("sigaction(%G, %s, [%s]) → %d% m", sig, DescribeSigaction(0, act),
|
|
|
|
DescribeSigaction(rc, oldact), rc);
|
Introduce --strace flag for system call tracing
This is similar to the --ftrace (c function call trace) flag, except
it's less noisy since it only logs system calls to stderr. Having this
flag is valuable because (1) system call tracing tells us a lot about
the behavior of complex programs and (2) it's usually very hard to get
system call tracing on various operating systems, e.g. strace, ktrace,
dtruss, truss, nttrace, etc. Especially on Apple platforms where even
with the special boot trick, debuggers still aren't guaranteed to work.
make -j8 o//examples
o//examples/hello.com --strace
This is enabled by default in MODE=, MODE=opt, and MODE=dbg. In MODE=dbg
extra information will be printed.
make -j8 MODE=dbg o/dbg/examples
o/dbg/examples/hello.com --strace |& less
This change also changes:
- Rename IsText() → _istext()
- Rename IsUtf8() → _isutf8()
- Fix madvise() on Windows NT
- Fix empty string case of inet_ntop()
- vfork() wrapper now saves and restores errno
- Update xsigaction() to yoink syscall support
2022-03-19 01:07:28 +00:00
|
|
|
return rc;
|
|
|
|
}
|