Improve signals and memory protection

- Document sigaction()
- Simplify New Technology fork() code
- Testing and many bug fixes for mprotect()
- Distribute Intel Xed ILD in the amalgamation
- Turn Xed enums into defines to avoid DWARF bloat
- Improve polyfilling of SA_SIGINFO on BSDs and fix bugs
- setpgid(getpid(), getpid()) on Windows will ignore CTRL-C
- Work around issues relating to NT mappings being executable
- Permit automatic executable stack override via `ape_stack_pf`
This commit is contained in:
Justine Tunney 2022-04-12 22:11:00 -07:00
parent c95c9d9508
commit f684e348d4
76 changed files with 1844 additions and 1121 deletions

View file

@ -294,6 +294,7 @@ COSMOPOLITAN_OBJECTS = \
THIRD_PARTY_COMPILER_RT \ THIRD_PARTY_COMPILER_RT \
LIBC_THREAD \ LIBC_THREAD \
LIBC_TINYMATH \ LIBC_TINYMATH \
THIRD_PARTY_XED \
LIBC_STR \ LIBC_STR \
LIBC_SYSV \ LIBC_SYSV \
LIBC_INTRIN \ LIBC_INTRIN \
@ -317,6 +318,7 @@ COSMOPOLITAN_HEADERS = \
LIBC_RUNTIME \ LIBC_RUNTIME \
LIBC_SOCK \ LIBC_SOCK \
LIBC_STDIO \ LIBC_STDIO \
THIRD_PARTY_XED \
LIBC_STR \ LIBC_STR \
LIBC_SYSV \ LIBC_SYSV \
LIBC_THREAD \ LIBC_THREAD \

View file

@ -660,6 +660,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
#if SupportsSystemv() || SupportsMetal() #if SupportsSystemv() || SupportsMetal()
.section .elf.phdrs,"a",@progbits .section .elf.phdrs,"a",@progbits
.long PT_LOAD .long PT_LOAD
.long PF_R|PF_X .long PF_R|PF_X
.stub ape_rom_offset,quad .stub ape_rom_offset,quad
@ -668,6 +669,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_rom_filesz,quad .stub ape_rom_filesz,quad
.stub ape_rom_memsz,quad .stub ape_rom_memsz,quad
.stub ape_rom_align,quad .stub ape_rom_align,quad
.long PT_LOAD .long PT_LOAD
.long PF_R|PF_W .long PF_R|PF_W
.stub ape_ram_offset,quad .stub ape_ram_offset,quad
@ -676,14 +678,32 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
.stub ape_ram_filesz,quad .stub ape_ram_filesz,quad
.stub ape_ram_memsz,quad .stub ape_ram_memsz,quad
.stub ape_ram_align,quad .stub ape_ram_align,quad
// APE Stack Configuration
//
// We actually respect this when allocating a deterministically
// addressed stack on Windows and other operating systems. However
// there's a few caveats:
//
// - If ape_stack_pf has PF_X then OpenBSD probably won't work
// - We don't bother creating a deterministic stack in MODE=tiny
//
// With that said, here's some examples of configuration:
//
// STATIC_SYMBOL("ape_stack_pf", "7"); // RWX
// STATIC_STACK_ADDR(0x6fffffff0000);
// STATIC_STACK_SIZE(65536);
//
// @see ape.lds for defaults
.long PT_GNU_STACK .long PT_GNU_STACK
.long PF_R|PF_W .stub ape_stack_pf,long # override w/ PF_X for execstack
.stub ape_stack_offset,quad .stub ape_stack_offset,quad # ignored
.stub ape_stack_vaddr,quad .stub ape_stack_vaddr,quad # is mmap()'d with MAP_FIXED
.stub ape_stack_paddr,quad .stub ape_stack_paddr,quad # ignored
.stub ape_stack_filesz,quad .stub ape_stack_filesz,quad # ignored
.stub ape_stack_memsz,quad .stub ape_stack_memsz,quad # is mmap(size) argument
.stub ape_stack_align,quad .stub ape_stack_align,quad # must be 16+
#if SupportsOpenbsd() || SupportsNetbsd() #if SupportsOpenbsd() || SupportsNetbsd()
.long PT_NOTE .long PT_NOTE
.long PF_R .long PF_R

View file

@ -177,6 +177,8 @@
#include "ape/macros.internal.h" #include "ape/macros.internal.h"
#include "ape/relocations.h" #include "ape/relocations.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/elf/pf2prot.internal.h"
#include "libc/nt/pedef.internal.h" #include "libc/nt/pedef.internal.h"
#include "libc/zip.h" #include "libc/zip.h"
@ -505,6 +507,8 @@ HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
HIDDEN(ape_ram_align = PAGESIZE); HIDDEN(ape_ram_align = PAGESIZE);
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr)); HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
HIDDEN(ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W);
HIDDEN(ape_stack_prot = _PF2PROT(ape_stack_pf));
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz); HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE); HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE);
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz); HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);

View file

@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n"); fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n");
CHECK_NE(-1, sigaction(SIGINT, &saint, NULL)); CHECK_NE(-1, sigaction(SIGINT, &saint, NULL));
for (;;) { for (;;) {
rc = read(0, buf, BUFSIZ); rc = read(0, buf, 512);
if (rc != -1) { if (rc != -1) {
got = rc; got = rc;
} else { } else {

View file

@ -55,8 +55,8 @@ int fgethex(FILE *f) {
} }
int main(int argc, char *argv[argc]) { int main(int argc, char *argv[argc]) {
int err;
unsigned c, i, j, l; unsigned c, i, j, l;
enum XedError err;
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
unsigned char buf[XED_MAX_INSTRUCTION_BYTES]; unsigned char buf[XED_MAX_INSTRUCTION_BYTES];
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));

View file

@ -17,6 +17,7 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/errno.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/errors.h" #include "libc/nt/errors.h"
#include "libc/nt/files.h" #include "libc/nt/files.h"
@ -27,7 +28,7 @@
textwindows int sys_chdir_nt(const char *path) { textwindows int sys_chdir_nt(const char *path) {
uint32_t n; uint32_t n;
int e, ms, len; int e, ms, err, len;
char16_t path16[PATH_MAX], var[4]; char16_t path16[PATH_MAX], var[4];
if ((len = __mkntpath(path, path16)) == -1) return -1; if ((len = __mkntpath(path, path16)) == -1) return -1;
if (len && path16[len - 1] != u'\\') { if (len && path16[len - 1] != u'\\') {
@ -39,7 +40,7 @@ textwindows int sys_chdir_nt(const char *path) {
* chdir() seems flaky on windows 7 * chdir() seems flaky on windows 7
* in a similar way to rmdir() sigh * in a similar way to rmdir() sigh
*/ */
for (ms = 1;; ms *= 2) { for (err = errno, ms = 1;; ms *= 2) {
if (SetCurrentDirectory(path16)) { if (SetCurrentDirectory(path16)) {
/* /*
* Now we need to set a magic environment variable. * Now we need to set a magic environment variable.
@ -68,12 +69,12 @@ textwindows int sys_chdir_nt(const char *path) {
if (ms <= 512 && if (ms <= 512 &&
(e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) { (e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) {
Sleep(ms); Sleep(ms);
errno = err;
continue; continue;
} else { } else {
break; break;
} }
} }
} }
errno = e;
return -1; return -1;
} }

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/assert.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/filemapflags.h" #include "libc/nt/enum/filemapflags.h"
#include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/pageflags.h"
@ -23,39 +24,70 @@
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size, textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
int prot, int flags, int prot, int flags, int fd,
int64_t handle, int64_t off) { int64_t off) {
size_t i; size_t i;
bool iscow;
int64_t handle;
uint32_t oldprot;
struct DirectMap dm; struct DirectMap dm;
struct ProtectNt fl; struct ProtectNt fl;
const struct NtSecurityAttributes *sec; const struct NtSecurityAttributes *sec;
if (fd != -1) {
handle = g_fds.p[fd].handle;
} else {
handle = kNtInvalidHandleValue;
}
if (flags & MAP_PRIVATE) { if (flags & MAP_PRIVATE) {
sec = 0; // MAP_PRIVATE isn't inherited across fork() sec = 0; // MAP_PRIVATE isn't inherited across fork()
} else { } else {
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork() sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
} }
if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE) && handle != -1) { // nt will whine under many circumstances if we change the execute bit
// windows has cow pages but they can't propagate across fork() // later using mprotect(). the workaround is to always request execute
if (prot & PROT_EXEC) { // and then virtualprotect() it away until we actually need it. please
// note that open-nt.c always requests an kNtGenericExecute accessmask
iscow = false;
if (handle != -1) {
if (flags & MAP_PRIVATE) {
// windows has cow pages but they can't propagate across fork()
// that means we only get copy-on-write for the root process :(
fl = (struct ProtectNt){kNtPageExecuteWritecopy, fl = (struct ProtectNt){kNtPageExecuteWritecopy,
kNtFileMapCopy | kNtFileMapExecute}; kNtFileMapCopy | kNtFileMapExecute};
iscow = true;
} else { } else {
fl = (struct ProtectNt){kNtPageWritecopy, kNtFileMapCopy}; assert(flags & MAP_SHARED);
if ((g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY) {
fl = (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};
} else {
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
}
} }
} else { } else {
fl = __nt2prot(prot); assert(flags & MAP_ANONYMOUS);
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
kNtFileMapWrite | kNtFileMapExecute};
} }
if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1, if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
(size + off) >> 32, (size + off), 0))) { (size + off) >> 32, (size + off), 0))) {
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off, if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
size, addr))) { size, addr))) {
return dm; if (VirtualProtect(addr, size, __prot2nt(prot, iscow), &oldprot)) {
return dm;
} else {
return dm;
UnmapViewOfFile(dm.addr);
}
} }
CloseHandle(dm.maphandle); CloseHandle(dm.maphandle);
} }

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
@ -35,7 +36,6 @@
noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags, noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
int fd, int64_t off) { int fd, int64_t off) {
/* asan runtime depends on this function */ /* asan runtime depends on this function */
char mode[8];
struct DirectMap d; struct DirectMap d;
if (!IsWindows() && !IsMetal()) { if (!IsWindows() && !IsMetal()) {
d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off); d.addr = __sys_mmap(addr, size, prot, flags, fd, off, off);
@ -43,11 +43,10 @@ noasan struct DirectMap sys_mmap(void *addr, size_t size, int prot, int flags,
} else if (IsMetal()) { } else if (IsMetal()) {
d = sys_mmap_metal(addr, size, prot, flags, fd, off); d = sys_mmap_metal(addr, size, prot, flags, fd, off);
} else { } else {
d = sys_mmap_nt(addr, size, prot, flags, d = sys_mmap_nt(addr, size, prot, flags, fd, off);
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue, off);
} }
STRACE("sys_mmap(%.12p%s, %'zu, %s, %d, %'ld) → {%.12p, %p}% m", addr, STRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
DescribeFrame((intptr_t)addr >> 16), size, DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
DescribeMapping(prot, flags, mode), fd, off, d.addr, d.maphandle); DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
return d; return d;
} }

View file

@ -7,6 +7,7 @@
#include "libc/calls/struct/metastat.internal.h" #include "libc/calls/struct/metastat.internal.h"
#include "libc/calls/struct/rusage.h" #include "libc/calls/struct/rusage.h"
#include "libc/calls/struct/sigaction-xnu.internal.h" #include "libc/calls/struct/sigaction-xnu.internal.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/sigval.h" #include "libc/calls/struct/sigval.h"
#include "libc/calls/struct/stat.h" #include "libc/calls/struct/stat.h"
@ -234,7 +235,7 @@ int sys_utimensat_xnu(int, const char *, const struct timespec *, int) hidden;
int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden; int sys_nanosleep_xnu(const struct timespec *, struct timespec *) hidden;
void __stat2cosmo(struct stat *restrict, const union metastat *) hidden; void __stat2cosmo(struct stat *restrict, const union metastat *) hidden;
void __restore_rt_netbsd(void) hidden; void __restore_rt_netbsd(void) hidden;
void __sigenter_xnu(void *, i32, i32, struct __darwin_siginfo *, void __sigenter_xnu(void *, i32, i32, struct siginfo_xnu *,
struct __darwin_ucontext *) hidden; struct __darwin_ucontext *) hidden;
int gethostname_linux(char *, size_t) hidden; int gethostname_linux(char *, size_t) hidden;
int gethostname_bsd(char *, size_t) hidden; int gethostname_bsd(char *, size_t) hidden;

View file

@ -25,6 +25,7 @@
/** /**
* Changes process group for process. * Changes process group for process.
* @vforksafe
*/ */
int setpgid(int pid, int pgid) { int setpgid(int pid, int pgid) {
int rc, me; int rc, me;

View file

@ -100,7 +100,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
cthread_spinlock(&__sig_lock); cthread_spinlock(&__sig_lock);
rva = __sighandrvas[sig]; rva = __sighandrvas[sig];
flags = __sighandflags[sig]; flags = __sighandflags[sig];
if (~flags & SA_NODEFER) { if ((~flags & SA_NODEFER) || (flags & SA_RESETHAND)) {
// by default we try to avoid reentering a signal handler. for // by default we try to avoid reentering a signal handler. for
// example, if a sigsegv handler segfaults, then we'd want the // example, if a sigsegv handler segfaults, then we'd want the
// second signal to just kill the process. doing this means we // second signal to just kill the process. doing this means we
@ -125,16 +125,15 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
// handover control to user // handover control to user
((sigaction_f)(_base + rva))(sig, infop, ctx); ((sigaction_f)(_base + rva))(sig, infop, ctx);
// leave the signal if ((~flags & SA_NODEFER) && (~flags & SA_RESETHAND)) {
cthread_spinlock(&__sig_lock); // it's now safe to reenter the signal so we need to restore it.
if (~flags & SA_NODEFER) { // since sigaction() is @asyncsignalsafe we only restore it if the
// user didn't change it during the signal handler. we also don't
// need to do anything if this was a oneshot signal or nodefer.
cthread_spinlock(&__sig_lock);
_cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva); _cmpxchg(__sighandrvas + sig, (int32_t)(intptr_t)SIG_DFL, rva);
cthread_spunlock(&__sig_lock);
} }
if (flags & SA_RESETHAND) {
STRACE("resetting oneshot signal handler");
__sighandrvas[sig] = (int32_t)(intptr_t)SIG_DFL;
}
cthread_spunlock(&__sig_lock);
if (!restartable) { if (!restartable) {
return true; // always send EINTR for wait4(), poll(), etc. return true; // always send EINTR for wait4(), poll(), etc.

View file

@ -236,15 +236,64 @@ static int __sigaction(int sig, const struct sigaction *act,
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO}; * .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL)); * CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
* *
* Here's an example of the most professional way to handle signals. * The following flags are supported across platforms:
* 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 * - `SA_SIGINFO`: Causes the `siginfo_t` and `ucontext_t` parameters to
* hand-in-glove with the EINTR errno returned by i/o. * be passed. 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.
*
* - `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
* can't call `wait()` anymore; similar to SIGCHLD + SIG_IGN but may
* 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.
* *
* static volatile bool gotctrlc; * static volatile bool gotctrlc;
*
* void OnCtrlC(int sig) { * void OnCtrlC(int sig) {
* gotctrlc = true; * gotctrlc = true;
* } * }
*
* int main() { * int main() {
* size_t got; * size_t got;
* ssize_t rc; * ssize_t rc;
@ -286,7 +335,96 @@ static int __sigaction(int sig, const struct sigaction *act,
* *
* Please note that you can't do the above if you use SA_RESTART. Since * 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 * the purpose of SA_RESTART is to restart i/o operations whose docs say
* that they're @restartable and read() is one such function. * 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;
* }
*
* void OnCrash(int sig, struct siginfo *si, struct ucontext *ctx) {
* 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.
* *
* @return 0 on success or -1 w/ errno * @return 0 on success or -1 w/ errno
* @see xsigaction() for a much better api * @see xsigaction() for a much better api

View file

@ -19,83 +19,101 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/siginfo-freebsd.internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/ucontext-freebsd.internal.h" #include "libc/calls/struct/ucontext-freebsd.internal.h"
#include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/repstosb.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
void __sigenter_freebsd(int sig, struct siginfo_freebsd *si, void __sigenter_freebsd(int sig, struct siginfo_freebsd *freebsdinfo,
struct ucontext_freebsd *ctx) { struct ucontext_freebsd *ctx) {
int rva; int rva, flags;
ucontext_t uc; struct Goodies {
ucontext_t uc;
siginfo_t si;
} g;
rva = __sighandrvas[sig & (NSIG - 1)]; rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) { if (rva >= kSigactionMinRva) {
bzero(&uc, sizeof(uc)); flags = __sighandflags[sig & (NSIG - 1)];
if (ctx) { if (~flags & SA_SIGINFO) {
uc.uc_mcontext.fpregs = &uc.__fpustate; ((sigaction_f)(_base + rva))(sig, 0, 0);
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp; } else {
uc.uc_stack.ss_size = ctx->uc_stack.ss_size; repstosb(&g, 0, sizeof(g));
uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags; g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
uc.uc_flags = ctx->uc_flags; g.uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
memcpy(&uc.uc_sigmask, &ctx->uc_sigmask, g.uc.uc_stack.ss_size = ctx->uc_stack.ss_size;
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); g.uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags;
uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8; g.uc.uc_flags = ctx->uc_flags;
uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9; memcpy(&g.uc.uc_sigmask, &ctx->uc_sigmask,
uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10; MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
uc.uc_mcontext.r11 = ctx->uc_mcontext.mc_r11; g.uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8;
uc.uc_mcontext.r12 = ctx->uc_mcontext.mc_r12; g.uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9;
uc.uc_mcontext.r13 = ctx->uc_mcontext.mc_r13; g.uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10;
uc.uc_mcontext.r14 = ctx->uc_mcontext.mc_r14; g.uc.uc_mcontext.r11 = ctx->uc_mcontext.mc_r11;
uc.uc_mcontext.r15 = ctx->uc_mcontext.mc_r15; g.uc.uc_mcontext.r12 = ctx->uc_mcontext.mc_r12;
uc.uc_mcontext.rdi = ctx->uc_mcontext.mc_rdi; g.uc.uc_mcontext.r13 = ctx->uc_mcontext.mc_r13;
uc.uc_mcontext.rsi = ctx->uc_mcontext.mc_rsi; g.uc.uc_mcontext.r14 = ctx->uc_mcontext.mc_r14;
uc.uc_mcontext.rbp = ctx->uc_mcontext.mc_rbp; g.uc.uc_mcontext.r15 = ctx->uc_mcontext.mc_r15;
uc.uc_mcontext.rbx = ctx->uc_mcontext.mc_rbx; g.uc.uc_mcontext.rdi = ctx->uc_mcontext.mc_rdi;
uc.uc_mcontext.rdx = ctx->uc_mcontext.mc_rdx; g.uc.uc_mcontext.rsi = ctx->uc_mcontext.mc_rsi;
uc.uc_mcontext.rax = ctx->uc_mcontext.mc_rax; g.uc.uc_mcontext.rbp = ctx->uc_mcontext.mc_rbp;
uc.uc_mcontext.rcx = ctx->uc_mcontext.mc_rcx; g.uc.uc_mcontext.rbx = ctx->uc_mcontext.mc_rbx;
uc.uc_mcontext.rsp = ctx->uc_mcontext.mc_rsp; g.uc.uc_mcontext.rdx = ctx->uc_mcontext.mc_rdx;
uc.uc_mcontext.rip = ctx->uc_mcontext.mc_rip; g.uc.uc_mcontext.rax = ctx->uc_mcontext.mc_rax;
uc.uc_mcontext.eflags = ctx->uc_mcontext.mc_flags; g.uc.uc_mcontext.rcx = ctx->uc_mcontext.mc_rcx;
uc.uc_mcontext.fs = ctx->uc_mcontext.mc_fs; g.uc.uc_mcontext.rsp = ctx->uc_mcontext.mc_rsp;
uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs; g.uc.uc_mcontext.rip = ctx->uc_mcontext.mc_rip;
uc.uc_mcontext.err = ctx->uc_mcontext.mc_err; g.uc.uc_mcontext.eflags = ctx->uc_mcontext.mc_flags;
uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno; g.uc.uc_mcontext.fs = ctx->uc_mcontext.mc_fs;
memcpy(&uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512); g.uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs;
} g.uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
((sigaction_f)(_base + rva))(sig, (void *)si, &uc); g.uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
if (ctx) { memcpy(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
ctx->uc_stack.ss_sp = uc.uc_stack.ss_sp; g.si.si_signo = freebsdinfo->si_signo;
ctx->uc_stack.ss_size = uc.uc_stack.ss_size; g.si.si_errno = freebsdinfo->si_errno;
ctx->uc_stack.ss_flags = uc.uc_stack.ss_flags; g.si.si_code = freebsdinfo->si_code;
ctx->uc_flags = uc.uc_flags; if (freebsdinfo->si_pid) {
memcpy(&ctx->uc_sigmask, &uc.uc_sigmask, g.si.si_pid = freebsdinfo->si_pid;
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask))); g.si.si_uid = freebsdinfo->si_uid;
ctx->uc_mcontext.mc_rdi = uc.uc_mcontext.rdi; } else {
ctx->uc_mcontext.mc_rsi = uc.uc_mcontext.rsi; g.si.si_addr = (void *)freebsdinfo->si_addr;
ctx->uc_mcontext.mc_rdx = uc.uc_mcontext.rdx; }
ctx->uc_mcontext.mc_rcx = uc.uc_mcontext.rcx; g.si.si_value = freebsdinfo->si_value;
ctx->uc_mcontext.mc_r8 = uc.uc_mcontext.r8; ((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
ctx->uc_mcontext.mc_r9 = uc.uc_mcontext.r9; ctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp;
ctx->uc_mcontext.mc_rax = uc.uc_mcontext.rax; ctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
ctx->uc_mcontext.mc_rbx = uc.uc_mcontext.rbx; ctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
ctx->uc_mcontext.mc_rbp = uc.uc_mcontext.rbp; ctx->uc_flags = g.uc.uc_flags;
ctx->uc_mcontext.mc_r10 = uc.uc_mcontext.r10; memcpy(&ctx->uc_sigmask, &g.uc.uc_sigmask,
ctx->uc_mcontext.mc_r11 = uc.uc_mcontext.r11; MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
ctx->uc_mcontext.mc_r12 = uc.uc_mcontext.r12; ctx->uc_mcontext.mc_rdi = g.uc.uc_mcontext.rdi;
ctx->uc_mcontext.mc_r13 = uc.uc_mcontext.r13; ctx->uc_mcontext.mc_rsi = g.uc.uc_mcontext.rsi;
ctx->uc_mcontext.mc_r14 = uc.uc_mcontext.r14; ctx->uc_mcontext.mc_rdx = g.uc.uc_mcontext.rdx;
ctx->uc_mcontext.mc_r15 = uc.uc_mcontext.r15; ctx->uc_mcontext.mc_rcx = g.uc.uc_mcontext.rcx;
ctx->uc_mcontext.mc_trapno = uc.uc_mcontext.trapno; ctx->uc_mcontext.mc_r8 = g.uc.uc_mcontext.r8;
ctx->uc_mcontext.mc_fs = uc.uc_mcontext.fs; ctx->uc_mcontext.mc_r9 = g.uc.uc_mcontext.r9;
ctx->uc_mcontext.mc_gs = uc.uc_mcontext.gs; ctx->uc_mcontext.mc_rax = g.uc.uc_mcontext.rax;
ctx->uc_mcontext.mc_flags = uc.uc_mcontext.eflags; ctx->uc_mcontext.mc_rbx = g.uc.uc_mcontext.rbx;
ctx->uc_mcontext.mc_err = uc.uc_mcontext.err; ctx->uc_mcontext.mc_rbp = g.uc.uc_mcontext.rbp;
ctx->uc_mcontext.mc_rip = uc.uc_mcontext.rip; ctx->uc_mcontext.mc_r10 = g.uc.uc_mcontext.r10;
ctx->uc_mcontext.mc_rsp = uc.uc_mcontext.rsp; ctx->uc_mcontext.mc_r11 = g.uc.uc_mcontext.r11;
memcpy(&ctx->uc_mcontext.mc_fpstate, &uc.__fpustate, 512); ctx->uc_mcontext.mc_r12 = g.uc.uc_mcontext.r12;
ctx->uc_mcontext.mc_r13 = g.uc.uc_mcontext.r13;
ctx->uc_mcontext.mc_r14 = g.uc.uc_mcontext.r14;
ctx->uc_mcontext.mc_r15 = g.uc.uc_mcontext.r15;
ctx->uc_mcontext.mc_trapno = g.uc.uc_mcontext.trapno;
ctx->uc_mcontext.mc_fs = g.uc.uc_mcontext.fs;
ctx->uc_mcontext.mc_gs = g.uc.uc_mcontext.gs;
ctx->uc_mcontext.mc_flags = g.uc.uc_mcontext.eflags;
ctx->uc_mcontext.mc_err = g.uc.uc_mcontext.err;
ctx->uc_mcontext.mc_rip = g.uc.uc_mcontext.rip;
ctx->uc_mcontext.mc_rsp = g.uc.uc_mcontext.rsp;
memcpy(&ctx->uc_mcontext.mc_fpstate, &g.uc.__fpustate, 512);
} }
} }
/* /*

View file

@ -19,11 +19,13 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/siginfo-netbsd.internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
#define RDI 0 #define RDI 0
#define RSI 1 #define RSI 1
@ -57,50 +59,6 @@ union sigval_netbsd {
void *sival_ptr; void *sival_ptr;
}; };
struct siginfo_netbsd {
int32_t _signo;
int32_t _code;
int32_t _errno;
int32_t _pad;
union {
struct {
int32_t _pid;
uint32_t _uid;
union sigval_netbsd _value;
} _rt;
struct {
int32_t _pid;
uint32_t _uid;
int32_t _status;
int64_t _utime;
int64_t _stime;
} _child;
struct {
void *_addr;
int32_t _trap;
int32_t _trap2;
int32_t _trap3;
} _fault;
struct {
int64_t _band;
int32_t _fd;
} _poll;
struct {
int32_t _sysnum;
int32_t _retval[2];
int32_t _error;
uint64_t _args[8];
} _syscall;
struct {
int32_t _pe_report_event;
union {
int32_t _pe_other_pid;
int32_t _pe_lwp;
} _option;
} _ptrace_state;
} _reason;
};
struct sigset_netbsd { struct sigset_netbsd {
uint32_t __bits[4]; uint32_t __bits[4];
}; };
@ -127,19 +85,23 @@ struct ucontext_netbsd {
void __sigenter_netbsd(int sig, struct siginfo_netbsd *si, void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
struct ucontext_netbsd *ctx) { struct ucontext_netbsd *ctx) {
int rva; int rva, flags;
ucontext_t uc; ucontext_t uc;
struct siginfo si2; struct siginfo si2;
rva = __sighandrvas[sig & (NSIG - 1)]; rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) { if (rva >= kSigactionMinRva) {
bzero(&uc, sizeof(uc)); flags = __sighandflags[sig & (NSIG - 1)];
bzero(&si2, sizeof(si2)); if (~flags & SA_SIGINFO) {
if (si) { ((sigaction_f)(_base + rva))(sig, 0, 0);
si2.si_signo = si->_signo; } else {
si2.si_code = si->_code; bzero(&uc, sizeof(uc));
si2.si_errno = si->_errno; bzero(&si2, sizeof(si2));
} si2.si_signo = si->si_signo;
if (ctx) { si2.si_code = si->si_code;
si2.si_errno = si->si_errno;
si2.si_pid = si->si_pid;
si2.si_uid = si->si_uid;
si2.si_value = si->si_value;
uc.uc_mcontext.fpregs = &uc.__fpustate; uc.uc_mcontext.fpregs = &uc.__fpustate;
uc.uc_flags = ctx->uc_flags; uc.uc_flags = ctx->uc_flags;
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp; uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
@ -169,9 +131,7 @@ void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
uc.uc_mcontext.rip = ctx->uc_mcontext.__gregs[RIP]; uc.uc_mcontext.rip = ctx->uc_mcontext.__gregs[RIP];
uc.uc_mcontext.rsp = ctx->uc_mcontext.__gregs[RSP]; uc.uc_mcontext.rsp = ctx->uc_mcontext.__gregs[RSP];
*uc.uc_mcontext.fpregs = ctx->uc_mcontext.__fpregs; *uc.uc_mcontext.fpregs = ctx->uc_mcontext.__fpregs;
} ((sigaction_f)(_base + rva))(sig, &si2, &uc);
((sigaction_f)(_base + rva))(sig, &si2, &uc);
if (ctx) {
ctx->uc_mcontext.__gregs[RDI] = uc.uc_mcontext.rdi; ctx->uc_mcontext.__gregs[RDI] = uc.uc_mcontext.rdi;
ctx->uc_mcontext.__gregs[RSI] = uc.uc_mcontext.rsi; ctx->uc_mcontext.__gregs[RSI] = uc.uc_mcontext.rsi;
ctx->uc_mcontext.__gregs[RDX] = uc.uc_mcontext.rdx; ctx->uc_mcontext.__gregs[RDX] = uc.uc_mcontext.rdx;

View file

@ -19,145 +19,91 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/sigaction-freebsd.internal.h" #include "libc/calls/struct/sigaction-freebsd.internal.h"
#include "libc/calls/struct/siginfo-openbsd.internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/struct/ucontext-openbsd.internal.h"
#include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/intrin/repstosb.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sa.h"
union sigval_openbsd { void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
int32_t sival_int;
void *sival_ptr;
};
struct siginfo_openbsd {
int32_t si_signo;
int32_t si_code;
int32_t si_errno;
union {
int _pad[29];
struct {
int32_t _pid;
union {
struct {
uint32_t _uid;
union sigval_openbsd _value;
} _kill;
struct {
int64_t _utime;
int64_t _stime;
int32_t _status;
} _cld;
} _pdata;
} _proc;
struct {
void *_addr;
int32_t _trapno;
} _fault;
} _data;
};
struct ucontext_openbsd {
int64_t sc_rdi;
int64_t sc_rsi;
int64_t sc_rdx;
int64_t sc_rcx;
int64_t sc_r8;
int64_t sc_r9;
int64_t sc_r10;
int64_t sc_r11;
int64_t sc_r12;
int64_t sc_r13;
int64_t sc_r14;
int64_t sc_r15;
int64_t sc_rbp;
int64_t sc_rbx;
int64_t sc_rax;
int64_t sc_gs;
int64_t sc_fs;
int64_t sc_es;
int64_t sc_ds;
int64_t sc_trapno;
int64_t sc_err;
int64_t sc_rip;
int64_t sc_cs;
int64_t sc_rflags;
int64_t sc_rsp;
int64_t sc_ss;
struct FpuState *sc_fpstate;
int32_t __sc_unused;
int32_t sc_mask;
int64_t sc_cookie;
};
void __sigenter_openbsd(int sig, struct siginfo_openbsd *si,
struct ucontext_openbsd *ctx) { struct ucontext_openbsd *ctx) {
int rva; int rva, flags;
ucontext_t uc; struct Goodies {
struct siginfo si2; ucontext_t uc;
struct siginfo si;
} g;
rva = __sighandrvas[sig & (NSIG - 1)]; rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) { if (rva >= kSigactionMinRva) {
bzero(&uc, sizeof(uc)); flags = __sighandflags[sig & (NSIG - 1)];
bzero(&si2, sizeof(si2)); if (~flags & SA_SIGINFO) {
if (si) { ((sigaction_f)(_base + rva))(sig, 0, 0);
si2.si_signo = si->si_signo; } else {
si2.si_code = si->si_code; repstosb(&g, 0, sizeof(g));
si2.si_errno = si->si_errno; g.si.si_signo = openbsdinfo->si_signo;
} g.si.si_code = openbsdinfo->si_code;
if (ctx) { g.si.si_errno = openbsdinfo->si_errno;
uc.uc_mcontext.fpregs = &uc.__fpustate; if (openbsdinfo->si_pid) {
memcpy(&uc.uc_sigmask, &ctx->sc_mask, g.si.si_pid = openbsdinfo->si_pid;
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->sc_mask))); g.si.si_uid = openbsdinfo->si_uid;
uc.uc_mcontext.rdi = ctx->sc_rdi; } else {
uc.uc_mcontext.rsi = ctx->sc_rsi; g.si.si_addr = (void *)openbsdinfo->si_addr;
uc.uc_mcontext.rdx = ctx->sc_rdx;
uc.uc_mcontext.rcx = ctx->sc_rcx;
uc.uc_mcontext.r8 = ctx->sc_r8;
uc.uc_mcontext.r9 = ctx->sc_r9;
uc.uc_mcontext.rax = ctx->sc_rax;
uc.uc_mcontext.rbx = ctx->sc_rbx;
uc.uc_mcontext.rbp = ctx->sc_rbp;
uc.uc_mcontext.r10 = ctx->sc_r10;
uc.uc_mcontext.r11 = ctx->sc_r11;
uc.uc_mcontext.r12 = ctx->sc_r12;
uc.uc_mcontext.r13 = ctx->sc_r13;
uc.uc_mcontext.r14 = ctx->sc_r14;
uc.uc_mcontext.r15 = ctx->sc_r15;
uc.uc_mcontext.trapno = ctx->sc_trapno;
uc.uc_mcontext.fs = ctx->sc_fs;
uc.uc_mcontext.gs = ctx->sc_gs;
uc.uc_mcontext.err = ctx->sc_err;
uc.uc_mcontext.rip = ctx->sc_rip;
uc.uc_mcontext.rsp = ctx->sc_rsp;
if (ctx->sc_fpstate) {
*uc.uc_mcontext.fpregs = *ctx->sc_fpstate;
} }
} g.si.si_value = openbsdinfo->si_value;
((sigaction_f)(_base + rva))(sig, &si2, &uc); g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
if (ctx) { memcpy(&g.uc.uc_sigmask, &ctx->sc_mask,
ctx->sc_rdi = uc.uc_mcontext.rdi; MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));
ctx->sc_rsi = uc.uc_mcontext.rsi; g.uc.uc_mcontext.rdi = ctx->sc_rdi;
ctx->sc_rdx = uc.uc_mcontext.rdx; g.uc.uc_mcontext.rsi = ctx->sc_rsi;
ctx->sc_rcx = uc.uc_mcontext.rcx; g.uc.uc_mcontext.rdx = ctx->sc_rdx;
ctx->sc_r8 = uc.uc_mcontext.r8; g.uc.uc_mcontext.rcx = ctx->sc_rcx;
ctx->sc_r9 = uc.uc_mcontext.r9; g.uc.uc_mcontext.r8 = ctx->sc_r8;
ctx->sc_rax = uc.uc_mcontext.rax; g.uc.uc_mcontext.r9 = ctx->sc_r9;
ctx->sc_rbx = uc.uc_mcontext.rbx; g.uc.uc_mcontext.rax = ctx->sc_rax;
ctx->sc_rbp = uc.uc_mcontext.rbp; g.uc.uc_mcontext.rbx = ctx->sc_rbx;
ctx->sc_r10 = uc.uc_mcontext.r10; g.uc.uc_mcontext.rbp = ctx->sc_rbp;
ctx->sc_r11 = uc.uc_mcontext.r11; g.uc.uc_mcontext.r10 = ctx->sc_r10;
ctx->sc_r12 = uc.uc_mcontext.r12; g.uc.uc_mcontext.r11 = ctx->sc_r11;
ctx->sc_r13 = uc.uc_mcontext.r13; g.uc.uc_mcontext.r12 = ctx->sc_r12;
ctx->sc_r14 = uc.uc_mcontext.r14; g.uc.uc_mcontext.r13 = ctx->sc_r13;
ctx->sc_r15 = uc.uc_mcontext.r15; g.uc.uc_mcontext.r14 = ctx->sc_r14;
ctx->sc_trapno = uc.uc_mcontext.trapno; g.uc.uc_mcontext.r15 = ctx->sc_r15;
ctx->sc_fs = uc.uc_mcontext.fs; g.uc.uc_mcontext.trapno = ctx->sc_trapno;
ctx->sc_gs = uc.uc_mcontext.gs; g.uc.uc_mcontext.fs = ctx->sc_fs;
ctx->sc_err = uc.uc_mcontext.err; g.uc.uc_mcontext.gs = ctx->sc_gs;
ctx->sc_rip = uc.uc_mcontext.rip; g.uc.uc_mcontext.err = ctx->sc_err;
ctx->sc_rsp = uc.uc_mcontext.rsp; g.uc.uc_mcontext.rip = ctx->sc_rip;
g.uc.uc_mcontext.rsp = ctx->sc_rsp;
if (ctx->sc_fpstate) { if (ctx->sc_fpstate) {
*ctx->sc_fpstate = *uc.uc_mcontext.fpregs; *g.uc.uc_mcontext.fpregs = *ctx->sc_fpstate;
}
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
ctx->sc_rdi = g.uc.uc_mcontext.rdi;
ctx->sc_rsi = g.uc.uc_mcontext.rsi;
ctx->sc_rdx = g.uc.uc_mcontext.rdx;
ctx->sc_rcx = g.uc.uc_mcontext.rcx;
ctx->sc_r8 = g.uc.uc_mcontext.r8;
ctx->sc_r9 = g.uc.uc_mcontext.r9;
ctx->sc_rax = g.uc.uc_mcontext.rax;
ctx->sc_rbx = g.uc.uc_mcontext.rbx;
ctx->sc_rbp = g.uc.uc_mcontext.rbp;
ctx->sc_r10 = g.uc.uc_mcontext.r10;
ctx->sc_r11 = g.uc.uc_mcontext.r11;
ctx->sc_r12 = g.uc.uc_mcontext.r12;
ctx->sc_r13 = g.uc.uc_mcontext.r13;
ctx->sc_r14 = g.uc.uc_mcontext.r14;
ctx->sc_r15 = g.uc.uc_mcontext.r15;
ctx->sc_trapno = g.uc.uc_mcontext.trapno;
ctx->sc_fs = g.uc.uc_mcontext.fs;
ctx->sc_gs = g.uc.uc_mcontext.gs;
ctx->sc_err = g.uc.uc_mcontext.err;
ctx->sc_rip = g.uc.uc_mcontext.rip;
ctx->sc_rsp = g.uc.uc_mcontext.rsp;
if (ctx->sc_fpstate) {
*ctx->sc_fpstate = *g.uc.uc_mcontext.fpregs;
} }
} }
} }

View file

@ -19,9 +19,11 @@
#include "libc/calls/calls.h" #include "libc/calls/calls.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/struct/metasigaltstack.h" #include "libc/calls/struct/metasigaltstack.h"
#include "libc/calls/struct/siginfo-xnu.internal.h"
#include "libc/calls/struct/siginfo.h" #include "libc/calls/struct/siginfo.h"
#include "libc/calls/typedef/sigaction_f.h" #include "libc/calls/typedef/sigaction_f.h"
#include "libc/calls/ucontext.h" #include "libc/calls/ucontext.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/repstosb.h" #include "libc/intrin/repstosb.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/sa.h" #include "libc/sysv/consts/sa.h"
@ -30,24 +32,6 @@
* @fileoverview XNU kernel callback normalization. * @fileoverview XNU kernel callback normalization.
*/ */
union __darwin_sigval {
int32_t sival_int;
void *sival_ptr;
};
struct __darwin_siginfo {
int32_t si_signo;
int32_t si_errno;
int32_t si_code;
int32_t si_pid;
uint32_t si_uid;
int32_t si_status;
void *si_addr;
union __darwin_sigval si_value;
int64_t si_band;
uint64_t __pad[7];
};
struct __darwin_mmst_reg { struct __darwin_mmst_reg {
char __mmst_reg[10]; char __mmst_reg[10];
char __mmst_rsrv[6]; char __mmst_rsrv[6];
@ -467,71 +451,76 @@ noasan static void linuxssefpustate2xnu(
} }
noasan void __sigenter_xnu(void *fn, int infostyle, int sig, noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
struct __darwin_siginfo *xnuinfo, struct siginfo_xnu *xnuinfo,
struct __darwin_ucontext *xnuctx) { struct __darwin_ucontext *xnuctx) {
int rva;
intptr_t ax; intptr_t ax;
int rva, flags;
struct Goodies { struct Goodies {
ucontext_t uc; ucontext_t uc;
siginfo_t si; siginfo_t si;
} g; } g;
rva = __sighandrvas[sig & (NSIG - 1)]; rva = __sighandrvas[sig & (NSIG - 1)];
if (rva >= kSigactionMinRva) { if (rva >= kSigactionMinRva) {
repstosb(&g, 0, sizeof(g)); flags = __sighandflags[sig & (NSIG - 1)];
if (xnuctx) { if (~flags & SA_SIGINFO) {
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0; ((sigaction_f)(_base + rva))(sig, 0, 0);
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask; } else {
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp; repstosb(&g, 0, sizeof(g));
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags; if (xnuctx) {
g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size; g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate; g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
if (xnuctx->uc_mcontext) { g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
if (xnuctx->uc_mcsize >= g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
sizeof(struct __darwin_x86_exception_state64)) { g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size;
xnuexceptionstate2linux(&g.uc.uc_mcontext, g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
&xnuctx->uc_mcontext->__es); if (xnuctx->uc_mcontext) {
} if (xnuctx->uc_mcsize >=
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_x86_exception_state64)) {
(sizeof(struct __darwin_x86_exception_state64) + xnuexceptionstate2linux(&g.uc.uc_mcontext,
sizeof(struct __darwin_x86_thread_state64))) { &xnuctx->uc_mcontext->__es);
xnuthreadstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__ss); }
} if (xnuctx->uc_mcsize >=
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) { (sizeof(struct __darwin_x86_exception_state64) +
xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs); sizeof(struct __darwin_x86_thread_state64))) {
xnuthreadstate2linux(&g.uc.uc_mcontext, &xnuctx->uc_mcontext->__ss);
}
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
xnussefpustate2linux(&g.uc.__fpustate, &xnuctx->uc_mcontext->__fs);
}
} }
} }
} if (xnuinfo) {
if (xnuinfo) { g.si.si_signo = xnuinfo->si_signo;
g.si.si_signo = xnuinfo->si_signo; g.si.si_errno = xnuinfo->si_errno;
g.si.si_errno = xnuinfo->si_errno; g.si.si_code = xnuinfo->si_code;
g.si.si_code = xnuinfo->si_code; if (xnuinfo->si_pid) {
if (xnuinfo->si_pid) { g.si.si_pid = xnuinfo->si_pid;
g.si.si_pid = xnuinfo->si_pid; g.si.si_uid = xnuinfo->si_uid;
g.si.si_uid = xnuinfo->si_uid; } else {
g.si.si_status = xnuinfo->si_status; g.si.si_addr = (void *)xnuinfo->si_addr;
} else { }
g.si.si_addr = (void *)xnuinfo->si_addr; g.si.si_value = xnuinfo->si_value;
} }
} ((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc); if (xnuctx) {
if (xnuctx) { xnuctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp;
xnuctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp; xnuctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
xnuctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags; xnuctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
xnuctx->uc_stack.ss_size = g.uc.uc_stack.ss_size; if (xnuctx->uc_mcontext) {
if (xnuctx->uc_mcontext) { if (xnuctx->uc_mcsize >=
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_x86_exception_state64)) {
sizeof(struct __darwin_x86_exception_state64)) { linuxexceptionstate2xnu(&xnuctx->uc_mcontext->__es,
linuxexceptionstate2xnu(&xnuctx->uc_mcontext->__es, &g.uc.uc_mcontext);
&g.uc.uc_mcontext); }
} if (xnuctx->uc_mcsize >=
if (xnuctx->uc_mcsize >= (sizeof(struct __darwin_x86_exception_state64) +
(sizeof(struct __darwin_x86_exception_state64) + sizeof(struct __darwin_x86_thread_state64))) {
sizeof(struct __darwin_x86_thread_state64))) { linuxthreadstate2xnu(&xnuctx->uc_mcontext->__ss, &g.uc,
linuxthreadstate2xnu(&xnuctx->uc_mcontext->__ss, &g.uc, &g.uc.uc_mcontext);
&g.uc.uc_mcontext); }
} if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) { linuxssefpustate2xnu(&xnuctx->uc_mcontext->__fs, &g.uc.__fpustate);
linuxssefpustate2xnu(&xnuctx->uc_mcontext->__fs, &g.uc.__fpustate); }
} }
} }
} }

View file

@ -28,7 +28,7 @@
* *
* @return old signal handler on success or SIG_ERR w/ errno * @return old signal handler on success or SIG_ERR w/ errno
* @note this function has BSD semantics, i.e. SA_RESTART * @note this function has BSD semantics, i.e. SA_RESTART
* @see sigaction() which has more features * @see sigaction() which has more features and docs
*/ */
sighandler_t(signal)(int sig, sighandler_t func) { sighandler_t(signal)(int sig, sighandler_t func) {
struct sigaction old, sa = {.sa_handler = func, .sa_flags = SA_RESTART}; struct sigaction old, sa = {.sa_handler = func, .sa_flags = SA_RESTART};

View file

@ -0,0 +1,39 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_FREEBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_FREEBSD_H_
#include "libc/calls/struct/sigval.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct siginfo_freebsd {
int32_t si_signo;
int32_t si_errno;
int32_t si_code;
int32_t si_pid;
int32_t si_uid;
int32_t si_status;
void *si_addr;
union sigval si_value;
union {
struct {
int32_t si_trapno;
};
struct {
int32_t si_timerid;
int32_t si_overrun;
};
struct {
int32_t si_mqd;
};
struct {
long si_band;
};
struct {
int64_t __pad1;
int32_t __pad2[7];
};
};
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_FREEBSD_H_ */

View file

@ -0,0 +1,53 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_NETBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_NETBSD_H_
#include "libc/calls/struct/sigval.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct siginfo_netbsd {
int32_t si_signo;
int32_t si_code;
int32_t si_errno;
int32_t __pad;
union {
struct { /* RT */
int32_t si_pid;
int32_t si_uid;
union sigval si_value;
};
struct { /* chld */
int32_t _pid;
int32_t _uid;
int32_t si_status;
int64_t si_utime;
int64_t si_stime;
};
struct { /* fault */
void *si_addr;
int32_t si_trap;
int32_t si_trap2;
int32_t si_trap3;
};
struct { /* poll */
int64_t si_band;
int32_t si_fd;
};
struct { /* syscall */
int32_t si_sysnum;
int32_t si_retval[2];
int32_t si_error;
uint64_t si_args[8];
};
struct { /* ptrace */
int32_t si_pe_report_event;
union {
int32_t si_pe_other_pid;
int32_t si_pe_lwp;
};
};
};
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_NETBSD_H_ */

View file

@ -0,0 +1,36 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_OPENBSD_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_OPENBSD_H_
#include "libc/calls/struct/sigval.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct siginfo_openbsd {
int32_t si_signo;
int32_t si_code;
int32_t si_errno;
union {
int32_t _pad[(128 / 4) - 3];
struct {
int32_t si_pid;
union {
struct {
int32_t si_uid;
union sigval si_value;
};
struct {
int64_t si_utime;
int64_t si_stime;
int32_t si_status;
};
};
};
struct {
void *si_addr;
int32_t si_trapno;
};
};
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_OPENBSD_H_ */

View file

@ -0,0 +1,22 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_XNU_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_XNU_H_
#include "libc/calls/struct/sigval.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct siginfo_xnu {
int32_t si_signo;
int32_t si_errno;
int32_t si_code;
int32_t si_pid;
int32_t si_uid;
int32_t si_status;
void *si_addr;
union sigval si_value;
int64_t si_band;
uint64_t __pad[7];
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGINFO_XNU_H_ */

View file

@ -15,7 +15,7 @@ struct siginfo {
uint32_t si_uid; uint32_t si_uid;
}; };
struct { struct {
int32_t si_timerid; int32_t si_timerid; /* SIGALRM */
int32_t si_overrun; int32_t si_overrun;
}; };
}; };
@ -23,7 +23,8 @@ struct siginfo {
union sigval si_value; /* provided by third arg of sigqueue(2) */ union sigval si_value; /* provided by third arg of sigqueue(2) */
struct { struct {
int32_t si_status; int32_t si_status;
int64_t si_utime, si_stime; int64_t si_utime;
int64_t si_stime;
}; };
}; };
}; };
@ -39,7 +40,7 @@ struct siginfo {
}; };
}; };
struct { struct {
int64_t si_band; int64_t si_band; /* SIGPOLL */
int32_t si_fd; int32_t si_fd;
}; };
struct { struct {

View file

@ -4,43 +4,6 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
union sigval_freebsd {
int32_t sival_int;
void *sival_ptr;
int32_t sigval_int;
void *sigval_ptr;
};
struct siginfo_freebsd {
int32_t si_signo;
int32_t si_errno;
int32_t si_code;
int32_t si_pid;
uint32_t si_uid;
int32_t si_status;
void *si_addr;
union sigval_freebsd si_value;
union {
struct {
int32_t _trapno;
} _fault;
struct {
int32_t _timerid;
int32_t _overrun;
} _timer;
struct {
int32_t _mqd;
} _mesgq;
struct {
int64_t _band;
} _poll;
struct {
int64_t __spare1__;
int32_t __spare2__[7];
} __spare__;
} _reason;
};
struct stack_freebsd { struct stack_freebsd {
void *ss_sp; void *ss_sp;
uint64_t ss_size; uint64_t ss_size;

View file

@ -0,0 +1,42 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_OPENBSD_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_OPENBSD_INTERNAL_H_
#include "libc/calls/ucontext.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct ucontext_openbsd {
int64_t sc_rdi;
int64_t sc_rsi;
int64_t sc_rdx;
int64_t sc_rcx;
int64_t sc_r8;
int64_t sc_r9;
int64_t sc_r10;
int64_t sc_r11;
int64_t sc_r12;
int64_t sc_r13;
int64_t sc_r14;
int64_t sc_r15;
int64_t sc_rbp;
int64_t sc_rbx;
int64_t sc_rax;
int64_t sc_gs;
int64_t sc_fs;
int64_t sc_es;
int64_t sc_ds;
int64_t sc_trapno;
int64_t sc_err;
int64_t sc_rip;
int64_t sc_cs;
int64_t sc_rflags;
int64_t sc_rsp;
int64_t sc_ss;
struct FpuState *sc_fpstate;
int32_t __sc_unused;
int32_t sc_mask;
int64_t sc_cookie;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_UCONTEXT_OPENBSD_INTERNAL_H_ */

View file

@ -96,7 +96,9 @@ static textwindows bool IsDirectorySymlink(const char16_t *path) {
static textwindows int sys_rmdir_nt(const char16_t *path) { static textwindows int sys_rmdir_nt(const char16_t *path) {
int e, ms; int e, ms;
for (ms = 1;; ms *= 2) { for (ms = 1;; ms *= 2) {
if (RemoveDirectory(path)) return 0; if (RemoveDirectory(path)) {
return 0;
}
/* /*
* Files can linger, for absolutely no reason. * Files can linger, for absolutely no reason.
* Possibly some Windows Defender bug on Win7. * Possibly some Windows Defender bug on Win7.
@ -104,14 +106,13 @@ static textwindows int sys_rmdir_nt(const char16_t *path) {
* Alternative is use Microsoft internal APIs. * Alternative is use Microsoft internal APIs.
* Never could have imagined it'd be this bad. * Never could have imagined it'd be this bad.
*/ */
if ((e = GetLastError()) == kNtErrorDirNotEmpty && ms <= 512) { if (GetLastError() == kNtErrorDirNotEmpty && ms <= 2048) {
Sleep(ms); Sleep(ms);
continue; continue;
} else { } else {
break; break;
} }
} }
errno = e;
return -1; return -1;
} }
@ -121,7 +122,7 @@ static textwindows int sys_unlink_nt(const char16_t *path) {
} else if (DeleteFile(path)) { } else if (DeleteFile(path)) {
return 0; return 0;
} else { } else {
return __winerr(); return -1;
} }
} }

View file

@ -0,0 +1,7 @@
#ifndef COSMOPOLITAN_LIBC_ELF_PF2PROT_INTERNAL_H_
#define COSMOPOLITAN_LIBC_ELF_PF2PROT_INTERNAL_H_
#include "libc/elf/def.h"
#define _PF2PROT(x) ((PF_R & (x)) >> 2 | (PF_W & (x)) | (PF_X & (x)) << 2)
#endif /* COSMOPOLITAN_LIBC_ELF_PF2PROT_INTERNAL_H_ */

View file

@ -57,7 +57,7 @@ STATIC_YOINK("_init_asan");
#define ASAN_MORGUE_ITEMS 512 #define ASAN_MORGUE_ITEMS 512
#define ASAN_MORGUE_THRESHOLD 65536 // morgue memory O(ITEMS*THRESHOLD) #define ASAN_MORGUE_THRESHOLD 65536 // morgue memory O(ITEMS*THRESHOLD)
#define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin #define ASAN_TRACE_ITEMS 16 // backtrace limit on malloc origin
/** /**
* @fileoverview Cosmopolitan Address Sanitizer Runtime. * @fileoverview Cosmopolitan Address Sanitizer Runtime.
@ -177,7 +177,8 @@ static uint64_t __asan_roundup2pow(uint64_t x) {
static char *__asan_utf8cpy(char *p, unsigned c) { static char *__asan_utf8cpy(char *p, unsigned c) {
uint64_t z; uint64_t z;
z = tpenc(c); z = tpenc(c);
do *p++ = z; do
*p++ = z;
while ((z >>= 8)); while ((z >>= 8));
return p; return p;
} }
@ -921,7 +922,8 @@ static void __asan_trace(struct AsanTrace *bt, const struct StackFrame *bp) {
if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) { if (!__asan_checka(SHADOW(bp), sizeof(*bp) >> 3).kind) {
addr = bp->addr; addr = bp->addr;
if (addr == weakaddr("__gc") && weakaddr("__gc")) { if (addr == weakaddr("__gc") && weakaddr("__gc")) {
do --gi; do
--gi;
while ((addr = garbage->p[gi].ret) == weakaddr("__gc")); while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
} }
bt->p[i] = addr; bt->p[i] = addr;
@ -1307,7 +1309,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
if (sm.addr == MAP_FAILED || if (sm.addr == MAP_FAILED ||
weaken(TrackMemoryInterval)( weaken(TrackMemoryInterval)(
m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE, m, a, a + i - 1, sm.maphandle, PROT_READ | PROT_WRITE,
MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED, 0, size) == -1) { MAP_PRIVATE | *weaken(MAP_ANONYMOUS) | MAP_FIXED, false, false, 0,
size) == -1) {
kprintf("error: could not map asan shadow memory%n"); kprintf("error: could not map asan shadow memory%n");
__asan_die()(); __asan_die()();
__asan_unreachable(); __asan_unreachable();

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,49 +16,22 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/bits/asmflag.h"
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/nt/files.h"
#include "libc/errno.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h" #include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h" extern typeof(DeleteFile) *const __imp_DeleteFileW __msabi;
#include "libc/sysv/consts/nr.h"
/** /**
* Modifies restrictions on virtual memory address range. * Deletes existing file.
* * @note this wrapper takes care of ABI, STRACE(), and __winerr()
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
* @return 0 on success, or -1 w/ errno
* @see mmap()
*/ */
noasan noubsan privileged int mprotect(void *addr, size_t len, int prot) { textwindows bool32 DeleteFile(const char16_t *lpPathName) {
bool cf; bool32 ok;
int64_t rc; ok = __imp_DeleteFileW(lpPathName);
uint32_t oldprot; if (!ok) __winerr();
char protbuf[4]; STRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok);
if (!IsWindows()) { return ok;
asm volatile(CFLAG_ASM("clc\n\tsyscall")
: CFLAG_CONSTRAINT(cf), "=a"(rc)
: "1"(__NR_mprotect), "D"(addr), "S"(len), "d"(prot)
: "rcx", "r11", "memory", "cc");
if (cf) {
errno = rc;
rc = -1;
} else if (rc > -4096ul) {
errno = -rc;
rc = -1;
}
} else {
if (VirtualProtect(addr, len, __prot2nt(prot, 0), &oldprot)) {
rc = 0;
} else {
rc = __winerr();
}
}
STRACE("mprotect(%p, %'zu, %s[%#x]) → %d% m", addr, len,
DescribeProt(prot, protbuf), prot, rc);
return rc;
} }

View file

@ -25,7 +25,7 @@ const char *DescribeFlags(char *p, size_t n, struct DescribeFlags *d, size_t m,
char b[21]; char b[21];
size_t i, j, k; size_t i, j, k;
for (t = i = j = 0; j < m; ++j) { for (t = i = j = 0; j < m; ++j) {
if ((x & d[j].flag) == d[j].flag) { if (d[j].flag && d[j].flag != -1 && (x & d[j].flag) == d[j].flag) {
x &= ~d[j].flag; x &= ~d[j].flag;
if (t) { if (t) {
if (i + 1 < n) p[i++] = '|'; if (i + 1 < n) p[i++] = '|';

View file

@ -10,6 +10,11 @@ struct thatispacked DescribeFlags {
const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t, const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t,
const char *, unsigned); const char *, unsigned);
const char *DescribeMapFlags(int);
const char *DescribeProtFlags(int);
const char *DescribeRemapFlags(int);
const char *DescribeNtPageFlags(uint32_t); const char *DescribeNtPageFlags(uint32_t);
const char *DescribeNtFileMapFlags(uint32_t); const char *DescribeNtFileMapFlags(uint32_t);
const char *DescribeNtFileFlagsAndAttributes(uint32_t); const char *DescribeNtFileFlagsAndAttributes(uint32_t);

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,51 +16,29 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/calls.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/calls/struct/sigaction.h" #include "libc/macros.internal.h"
#include "libc/runtime/runtime.h" #include "libc/nt/enum/consolemodeflags.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sa.h"
#include "libc/testlib/testlib.h"
jmp_buf jb; const char *DescribeMapFlags(int x) {
bool gotsegv; static char mapflags[256];
struct sigaction old[2]; const struct DescribeFlags kMapFlags[] = {
{MAP_ANONYMOUS, "ANONYMOUS"}, //
void OnSigSegv(int sig) { {MAP_PRIVATE, "PRIVATE"}, //
gotsegv = true; {MAP_SHARED, "SHARED"}, //
longjmp(jb, 1); {MAP_FIXED, "FIXED"}, //
} {MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
{MAP_GROWSDOWN, "GROWSDOWN"}, //
void SetUp(void) { {MAP_CONCEAL, "CONCEAL"}, //
sigaction(SIGBUS, NULL, &old[0]); {MAP_HUGETLB, "HUGETLB"}, //
sigaction(SIGSEGV, NULL, &old[1]); {MAP_LOCKED, "LOCKED"}, //
} {MAP_NORESERVE, "NORESERVE"}, //
{MAP_NONBLOCK, "NONBLOCK"}, //
void TearDown(void) { {MAP_POPULATE, "POPULATE"}, //
sigaction(SIGBUS, &old[0], NULL); {MAP_STACK, "STACK"}, // order matters
sigaction(SIGSEGV, &old[1], NULL); };
} return DescribeFlags(mapflags, sizeof(mapflags), kMapFlags,
ARRAYLEN(kMapFlags), "MAP_", x);
TEST(mprotect, test) {
char *p = gc(memalign(PAGESIZE, PAGESIZE));
p[0] = 0;
ASSERT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
p[0] = 1;
EXPECT_EQ(1, p[0]);
}
TEST(mprotect, testSegfault) {
char *p;
struct sigaction ss = {.sa_handler = OnSigSegv, .sa_flags = SA_NODEFER};
p = gc(memalign(PAGESIZE, PAGESIZE));
EXPECT_NE(-1, sigaction(SIGBUS, &ss, NULL));
EXPECT_NE(-1, sigaction(SIGSEGV, &ss, NULL));
if (!setjmp(jb)) p[0] = 1;
EXPECT_FALSE(gotsegv);
EXPECT_NE(-1, mprotect(p, sizeof(p), PROT_READ));
if (!setjmp(jb)) p[0] = 2;
EXPECT_TRUE(gotsegv);
EXPECT_EQ(1, p[0]);
EXPECT_NE(-1, mprotect(p, sizeof(p), PROT_READ | PROT_WRITE));
} }

View file

@ -1,7 +1,7 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ /*-*- 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 vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the any purpose with or without fee is hereby granted, provided that the
@ -16,27 +16,18 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/nt/enum/filemapflags.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/nt/enum/pageflags.h" #include "libc/macros.internal.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
privileged struct ProtectNt __nt2prot(int prot) { static const struct DescribeFlags kProtFlags[] = {
if (prot & PROT_WRITE) { {PROT_READ, "READ"}, //
if (prot & PROT_EXEC) { {PROT_WRITE, "WRITE"}, //
return (struct ProtectNt){kNtPageExecuteReadwrite, {PROT_EXEC, "EXEC"}, //
kNtFileMapWrite | kNtFileMapExecute}; };
} else {
return (struct ProtectNt){kNtPageReadwrite, kNtFileMapWrite}; const char *DescribeProtFlags(int x) {
} static char protflags[64];
} else if (prot & PROT_READ) { return DescribeFlags(protflags, sizeof(protflags), kProtFlags,
if (prot & PROT_EXEC) { ARRAYLEN(kProtFlags), "PROT_", x);
return (struct ProtectNt){kNtPageExecuteRead,
kNtFileMapRead | kNtFileMapExecute};
} else {
return (struct ProtectNt){kNtPageReadonly, kNtFileMapRead};
}
} else {
return (struct ProtectNt){kNtPageNoaccess};
}
} }

View file

@ -0,0 +1,32 @@
/*-*- 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/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/sysv/consts/mremap.h"
static const struct DescribeFlags kRemapFlags[] = {
{MREMAP_MAYMOVE, "MAYMOVE"}, //
{MREMAP_FIXED, "FIXED"}, //
};
const char *DescribeRemapFlags(int x) {
static char remapflags[64];
return DescribeFlags(remapflags, sizeof(remapflags), kRemapFlags,
ARRAYLEN(kRemapFlags), "MREMAP_", x);
}

View file

@ -65,12 +65,14 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
$(NO_MAGIC) $(NO_MAGIC)
o/$(MODE)/libc/intrin/createfile.greg.o \ o/$(MODE)/libc/intrin/createfile.greg.o \
o/$(MODE)/libc/intrin/deletefile.greg.o \
o/$(MODE)/libc/intrin/createpipe.greg.o \ o/$(MODE)/libc/intrin/createpipe.greg.o \
o/$(MODE)/libc/intrin/closehandle.greg.o \ o/$(MODE)/libc/intrin/closehandle.greg.o \
o/$(MODE)/libc/intrin/openprocess.greg.o \ o/$(MODE)/libc/intrin/openprocess.greg.o \
o/$(MODE)/libc/intrin/createthread.greg.o \ o/$(MODE)/libc/intrin/createthread.greg.o \
o/$(MODE)/libc/intrin/createprocess.greg.o \ o/$(MODE)/libc/intrin/createprocess.greg.o \
o/$(MODE)/libc/intrin/describeflags.greg.o \ o/$(MODE)/libc/intrin/describeflags.greg.o \
o/$(MODE)/libc/intrin/removedirectory.greg.o \
o/$(MODE)/libc/intrin/createnamedpipe.greg.o \ o/$(MODE)/libc/intrin/createnamedpipe.greg.o \
o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \ o/$(MODE)/libc/intrin/unmapviewoffile.greg.o \
o/$(MODE)/libc/intrin/flushviewoffile.greg.o \ o/$(MODE)/libc/intrin/flushviewoffile.greg.o \
@ -78,7 +80,9 @@ o/$(MODE)/libc/intrin/deviceiocontrol.greg.o \
o/$(MODE)/libc/intrin/createdirectory.greg.o \ o/$(MODE)/libc/intrin/createdirectory.greg.o \
o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \ o/$(MODE)/libc/intrin/flushfilebuffers.greg.o \
o/$(MODE)/libc/intrin/terminateprocess.greg.o \ o/$(MODE)/libc/intrin/terminateprocess.greg.o \
o/$(MODE)/libc/intrin/describemapflags.greg.o \
o/$(MODE)/libc/intrin/getfileattributes.greg.o \ o/$(MODE)/libc/intrin/getfileattributes.greg.o \
o/$(MODE)/libc/intrin/setcurrentdirectory.greg.o \
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \ o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \ o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \
o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \ o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \

View file

@ -438,7 +438,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
i = 0; i = 0;
m = (1 << base) - 1; m = (1 << base) - 1;
if (hash && x) sign = hash; if (hash && x) sign = hash;
do z[i++ & 127] = abet[x & m]; do
z[i++ & 127] = abet[x & m];
while ((x >>= base) || (pdot && i < prec)); while ((x >>= base) || (pdot && i < prec));
goto EmitNumber; goto EmitNumber;
@ -487,8 +488,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
goto EmitChar; goto EmitChar;
case 'm': case 'm':
if (!(x = errno) && sign == ' ' && if (!(x = errno) && sign == ' ' /* && */
(!IsWindows() || !__imp_GetLastError())) { /* (!IsWindows() || !__imp_GetLastError()) */) {
break; break;
} else if (weaken(strerror_r) && } else if (weaken(strerror_r) &&
!weaken(strerror_r)(x, z, sizeof(z))) { !weaken(strerror_r)(x, z, sizeof(z))) {

View file

@ -18,20 +18,30 @@
*/ */
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/nt/enum/pageflags.h" #include "libc/nt/enum/pageflags.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
privileged uint32_t __prot2nt(int prot, int flags) { privileged uint32_t __prot2nt(int prot, bool iscow) {
switch (prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) { switch (prot & (PROT_READ | PROT_WRITE | PROT_EXEC)) {
case PROT_READ: case PROT_READ:
return kNtPageReadonly; return kNtPageReadonly;
case PROT_EXEC:
case PROT_EXEC | PROT_READ:
return kNtPageExecuteRead;
case PROT_WRITE: case PROT_WRITE:
case PROT_READ | PROT_WRITE: case PROT_READ | PROT_WRITE:
return kNtPageReadwrite; if (iscow) {
case PROT_READ | PROT_EXEC: return kNtPageWritecopy;
return kNtPageExecuteRead; } else {
return kNtPageReadwrite;
}
case PROT_WRITE | PROT_EXEC: case PROT_WRITE | PROT_EXEC:
case PROT_READ | PROT_WRITE | PROT_EXEC: case PROT_READ | PROT_WRITE | PROT_EXEC:
return kNtPageExecuteReadwrite; if (iscow) {
return kNtPageExecuteWritecopy;
} else {
return kNtPageExecuteReadwrite;
}
default: default:
return kNtPageNoaccess; return kNtPageNoaccess;
} }

View file

@ -0,0 +1,37 @@
/*-*- 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/strace.internal.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(RemoveDirectory) *const __imp_RemoveDirectoryW __msabi;
/**
* Deletes existing empty directory.
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows bool32 RemoveDirectory(const char16_t *lpPathName) {
bool32 ok;
ok = __imp_RemoveDirectoryW(lpPathName);
if (!ok) __winerr();
STRACE("RemoveDirectory(%#hs) → %hhhd% m", lpPathName, ok);
return ok;
}

View file

@ -0,0 +1,37 @@
/*-*- 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/strace.internal.h"
#include "libc/nt/files.h"
#include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h"
extern typeof(SetCurrentDirectory) *const __imp_SetCurrentDirectoryW __msabi;
/**
* Sets current directory.
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/
textwindows bool32 SetCurrentDirectory(const char16_t *lpPathName) {
bool32 ok;
ok = __imp_SetCurrentDirectoryW(lpPathName);
if (!ok) __winerr();
STRACE("SetCurrentDirectory(%#hs) → %hhhd% m", lpPathName, ok);
return ok;
}

View file

@ -19,6 +19,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/intrin/describeflags.internal.h" #include "libc/intrin/describeflags.internal.h"
#include "libc/log/libfatal.internal.h"
#include "libc/nt/memory.h" #include "libc/nt/memory.h"
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi; extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
@ -27,13 +28,19 @@ extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
* Protects memory on the New Technology. * Protects memory on the New Technology.
* @note this wrapper takes care of ABI, STRACE(), and __winerr() * @note this wrapper takes care of ABI, STRACE(), and __winerr()
*/ */
bool32 VirtualProtect(void *lpAddress, uint64_t dwSize, uint32_t flNewProtect, textwindows bool32 VirtualProtect(void *lpAddress, uint64_t dwSize,
uint32_t *lpflOldProtect) { uint32_t flNewProtect,
uint32_t *lpflOldProtect) {
bool32 bOk; bool32 bOk;
char oldbuf[64];
bOk = __imp_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect); bOk = __imp_VirtualProtect(lpAddress, dwSize, flNewProtect, lpflOldProtect);
if (!bOk) __winerr(); if (bOk) {
__stpcpy(oldbuf, DescribeNtPageFlags(*lpflOldProtect));
} else {
__winerr();
__stpcpy(oldbuf, "n/a");
}
STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize, STRACE("VirtualProtect(%p, %'zu, %s, [%s]) → %hhhd% m", lpAddress, dwSize,
DescribeNtPageFlags(flNewProtect), DescribeNtPageFlags(flNewProtect), oldbuf, bOk);
DescribeNtPageFlags(*lpflOldProtect), bOk);
return bOk; return bOk;
} }

View file

@ -82,6 +82,8 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 5, "MAPERR"); /* address not mapped to object */ strcpy(b + 5, "MAPERR"); /* address not mapped to object */
} else if (si_code == SEGV_ACCERR) { } else if (si_code == SEGV_ACCERR) {
strcpy(b + 5, "ACCERR"); /* invalid permissions for mapped object */ strcpy(b + 5, "ACCERR"); /* invalid permissions for mapped object */
} else if (si_code == SEGV_PKUERR) {
strcpy(b + 5, "PKUERR"); /* FreeBSD: x86: PKU violation */
} }
} else if (sig == SIGFPE) { } else if (sig == SIGFPE) {
strcpy(b, "FPE_???"); strcpy(b, "FPE_???");
@ -129,10 +131,12 @@ const char *GetSiCodeName(int sig, int si_code) {
strcpy(b + 4, "ADRERR"); /* non-existent physical address */ strcpy(b + 4, "ADRERR"); /* non-existent physical address */
} else if (si_code == BUS_OBJERR) { } else if (si_code == BUS_OBJERR) {
strcpy(b + 4, "OBJERR"); /* object specific hardware error */ strcpy(b + 4, "OBJERR"); /* object specific hardware error */
} else if (si_code == BUS_OOMERR) {
strcpy(b + 4, "OOMERR"); /* FreeBSD */
} else if (si_code == BUS_MCEERR_AR) { } else if (si_code == BUS_MCEERR_AR) {
strcpy(b + 4, "BUS_AR"); /* Linux 2.6.32+ */ strcpy(b + 4, "MCEERR_AR"); /* Linux 2.6.32+ */
} else if (si_code == BUS_MCEERR_AO) { } else if (si_code == BUS_MCEERR_AO) {
strcpy(b + 4, "BUS_AO"); /* Linux 2.6.32+ */ strcpy(b + 4, "MCEERR_AO"); /* Linux 2.6.32+ */
} }
} else if (sig == SIGIO) { } else if (sig == SIGIO) {
strcpy(b, "POLL_???"); strcpy(b, "POLL_???");

View file

@ -78,7 +78,7 @@ noasan void CheckForMemoryLeaks(void) {
exit(1); exit(1);
} }
__cxa_finalize(0); __cxa_finalize(0);
STRACE("checking for memory leaks"); STRACE("checking for memory leaks% m");
if (!IsAsan()) { if (!IsAsan()) {
/* TODO(jart): How can we make this work without ASAN? */ /* TODO(jart): How can we make this work without ASAN? */
return; return;

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_DeleteFileW,DeleteFileW,0 .imp kernel32,__imp_DeleteFileW,DeleteFileW,0
.text.windows .text.windows
DeleteFile: __DeleteFile:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
@ -11,5 +11,5 @@ DeleteFile:
call *__imp_DeleteFileW(%rip) call *__imp_DeleteFileW(%rip)
leave leave
ret ret
.endfn DeleteFile,globl .endfn __DeleteFile,globl
.previous .previous

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_RemoveDirectoryW,RemoveDirectoryW,0 .imp kernel32,__imp_RemoveDirectoryW,RemoveDirectoryW,0
.text.windows .text.windows
RemoveDirectory: __RemoveDirectory:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
@ -11,5 +11,5 @@ RemoveDirectory:
call *__imp_RemoveDirectoryW(%rip) call *__imp_RemoveDirectoryW(%rip)
leave leave
ret ret
.endfn RemoveDirectory,globl .endfn __RemoveDirectory,globl
.previous .previous

View file

@ -2,7 +2,7 @@
.imp kernel32,__imp_SetCurrentDirectoryW,SetCurrentDirectoryW,0 .imp kernel32,__imp_SetCurrentDirectoryW,SetCurrentDirectoryW,0
.text.windows .text.windows
SetCurrentDirectory: __SetCurrentDirectory:
push %rbp push %rbp
mov %rsp,%rbp mov %rsp,%rbp
.profilable .profilable
@ -11,5 +11,5 @@ SetCurrentDirectory:
call *__imp_SetCurrentDirectoryW(%rip) call *__imp_SetCurrentDirectoryW(%rip)
leave leave
ret ret
.endfn SetCurrentDirectory,globl .endfn __SetCurrentDirectory,globl
.previous .previous

View file

@ -228,7 +228,6 @@ imp 'DeleteAtom' DeleteAtom kernel32 270
imp 'DeleteBoundaryDescriptor' DeleteBoundaryDescriptor kernel32 0 imp 'DeleteBoundaryDescriptor' DeleteBoundaryDescriptor kernel32 0
imp 'DeleteCriticalSection' DeleteCriticalSection kernel32 0 1 imp 'DeleteCriticalSection' DeleteCriticalSection kernel32 0 1
imp 'DeleteFiber' DeleteFiber kernel32 0 imp 'DeleteFiber' DeleteFiber kernel32 0
imp 'DeleteFile' DeleteFileW kernel32 0 1
imp 'DeleteFileA' DeleteFileA kernel32 0 1 imp 'DeleteFileA' DeleteFileA kernel32 0 1
imp 'DeleteFileTransacted' DeleteFileTransactedW kernel32 276 imp 'DeleteFileTransacted' DeleteFileTransactedW kernel32 276
imp 'DeleteFileTransactedA' DeleteFileTransactedA kernel32 275 imp 'DeleteFileTransactedA' DeleteFileTransactedA kernel32 275
@ -1033,7 +1032,6 @@ imp 'ReleaseMutex' ReleaseMutex kernel32 0 1
imp 'ReleaseSRWLockExclusive' ReleaseSRWLockExclusive kernel32 0 1 imp 'ReleaseSRWLockExclusive' ReleaseSRWLockExclusive kernel32 0 1
imp 'ReleaseSRWLockShared' ReleaseSRWLockShared kernel32 0 1 imp 'ReleaseSRWLockShared' ReleaseSRWLockShared kernel32 0 1
imp 'ReleaseSemaphore' ReleaseSemaphore kernel32 0 3 imp 'ReleaseSemaphore' ReleaseSemaphore kernel32 0 3
imp 'RemoveDirectory' RemoveDirectoryW kernel32 0 1
imp 'RemoveDirectoryA' RemoveDirectoryA kernel32 0 1 imp 'RemoveDirectoryA' RemoveDirectoryA kernel32 0 1
imp 'RemoveDirectoryTransacted' RemoveDirectoryTransactedW kernel32 1206 imp 'RemoveDirectoryTransacted' RemoveDirectoryTransactedW kernel32 1206
imp 'RemoveDirectoryTransactedA' RemoveDirectoryTransactedA kernel32 1205 imp 'RemoveDirectoryTransactedA' RemoveDirectoryTransactedA kernel32 1205
@ -1099,7 +1097,6 @@ imp 'SetConsoleTitleA' SetConsoleTitleA kernel32 0 1
imp 'SetConsoleWindowInfo' SetConsoleWindowInfo kernel32 0 3 imp 'SetConsoleWindowInfo' SetConsoleWindowInfo kernel32 0 3
imp 'SetCriticalSectionSpinCount' SetCriticalSectionSpinCount kernel32 0 2 imp 'SetCriticalSectionSpinCount' SetCriticalSectionSpinCount kernel32 0 2
imp 'SetCurrentConsoleFontEx' SetCurrentConsoleFontEx kernel32 0 imp 'SetCurrentConsoleFontEx' SetCurrentConsoleFontEx kernel32 0
imp 'SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1
imp 'SetCurrentDirectoryA' SetCurrentDirectoryA kernel32 0 1 imp 'SetCurrentDirectoryA' SetCurrentDirectoryA kernel32 0 1
imp 'SetDefaultCommConfig' SetDefaultCommConfigW kernel32 1298 imp 'SetDefaultCommConfig' SetDefaultCommConfigW kernel32 1298
imp 'SetDefaultCommConfigA' SetDefaultCommConfigA kernel32 1297 imp 'SetDefaultCommConfigA' SetDefaultCommConfigA kernel32 1297
@ -1360,6 +1357,7 @@ imp '__CreateNamedPipe' CreateNamedPipeW kernel32 0 8
imp '__CreatePipe' CreatePipe kernel32 0 4 imp '__CreatePipe' CreatePipe kernel32 0 4
imp '__CreateProcess' CreateProcessW kernel32 0 10 imp '__CreateProcess' CreateProcessW kernel32 0 10
imp '__CreateThread' CreateThread kernel32 0 6 imp '__CreateThread' CreateThread kernel32 0 6
imp '__DeleteFile' DeleteFileW kernel32 0 1
imp '__DeviceIoControl' DeviceIoControl kernel32 0 8 imp '__DeviceIoControl' DeviceIoControl kernel32 0 8
imp '__FlushFileBuffers' FlushFileBuffers kernel32 0 1 imp '__FlushFileBuffers' FlushFileBuffers kernel32 0 1
imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2 imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2
@ -1368,6 +1366,8 @@ imp '__GetFileAttributes' GetFileAttributesW kernel32 0 1
imp '__MapViewOfFileEx' MapViewOfFileEx kernel32 0 6 imp '__MapViewOfFileEx' MapViewOfFileEx kernel32 0 6
imp '__MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7 imp '__MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7
imp '__OpenProcess' OpenProcess kernel32 0 3 imp '__OpenProcess' OpenProcess kernel32 0 3
imp '__RemoveDirectory' RemoveDirectoryW kernel32 0 1
imp '__SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1
imp '__TerminateProcess' TerminateProcess kernel32 0 2 imp '__TerminateProcess' TerminateProcess kernel32 0 2
imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1 imp '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1
imp '__VirtualProtect' VirtualProtect kernel32 0 4 imp '__VirtualProtect' VirtualProtect kernel32 0 4

View file

@ -14,11 +14,10 @@ struct DirectMap {
}; };
struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t); struct DirectMap sys_mmap(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_nt(void *, size_t, int, int, int64_t, int64_t); struct DirectMap sys_mmap_nt(void *, size_t, int, int, int, int64_t);
struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t); struct DirectMap sys_mmap_metal(void *, size_t, int, int, int, int64_t);
int sys_munmap_metal(void *, size_t); int sys_munmap_metal(void *, size_t);
uint32_t __prot2nt(int, int); uint32_t __prot2nt(int, bool);
struct ProtectNt __nt2prot(int);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -106,7 +106,6 @@ textwindows void WinMainForked(void) {
struct DirectMap dm; struct DirectMap dm;
uint64_t size, upsize; uint64_t size, upsize;
int64_t reader, writer; int64_t reader, writer;
uint32_t flags1, flags2;
struct MemoryInterval *maps; struct MemoryInterval *maps;
char16_t fvar[21 + 1 + 21 + 1]; char16_t fvar[21 + 1 + 21 + 1];
int64_t oncrash, savetsc, savebir; int64_t oncrash, savetsc, savebir;
@ -163,24 +162,21 @@ textwindows void WinMainForked(void) {
size = maps[i].size; size = maps[i].size;
if (maps[i].flags & MAP_PRIVATE) { if (maps[i].flags & MAP_PRIVATE) {
upsize = ROUNDUP(size, FRAMESIZE); upsize = ROUNDUP(size, FRAMESIZE);
if (maps[i].prot & PROT_EXEC) {
flags1 = kNtPageExecuteReadwrite;
flags2 = kNtFileMapWrite | kNtFileMapExecute;
} else {
flags1 = kNtPageReadwrite;
flags2 = kNtFileMapWrite;
}
// we don't need to close the map handle because sys_mmap_nt // we don't need to close the map handle because sys_mmap_nt
// doesn't mark it inheritable across fork() for MAP_PRIVATE // doesn't mark it inheritable across fork() for MAP_PRIVATE
if (!(maps[i].h = if (!(maps[i].h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite,
CreateFileMapping(-1, 0, flags1, upsize >> 32, upsize, 0)) || upsize >> 32, upsize, 0)) ||
!MapViewOfFileEx(maps[i].h, flags2, 0, 0, upsize, addr) || !MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
upsize, addr) ||
!ReadAll(reader, addr, size)) { !ReadAll(reader, addr, size)) {
ExitProcess(44); ExitProcess(44);
} }
} else { } else {
// we can however safely inherit MAP_SHARED with zero copy // we can however safely inherit MAP_SHARED with zero copy
if (!MapViewOfFileEx(maps[i].h, __nt2prot(maps[i].prot).flags2, if (!MapViewOfFileEx(maps[i].h,
maps[i].readonlyfile
? kNtFileMapRead | kNtFileMapExecute
: kNtFileMapWrite | kNtFileMapExecute,
maps[i].offset >> 32, maps[i].offset, size, addr)) { maps[i].offset >> 32, maps[i].offset, size, addr)) {
ExitProcess(45); ExitProcess(45);
} }
@ -203,11 +199,8 @@ textwindows void WinMainForked(void) {
_mmi.p = maps; _mmi.p = maps;
_mmi.n = specialz / sizeof(_mmi.p[0]); _mmi.n = specialz / sizeof(_mmi.p[0]);
for (i = 0; i < mapcount; ++i) { for (i = 0; i < mapcount; ++i) {
if ((maps[i].flags & MAP_PRIVATE) && (~maps[i].prot & PROT_WRITE)) { VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
VirtualProtect((void *)((uint64_t)maps[i].x << 16), __prot2nt(maps[i].prot, maps[i].iscow), &oldprot);
ROUNDUP(maps[i].size, FRAMESIZE),
__nt2prot(maps[i].prot).flags1, &oldprot);
}
} }
// we're all done reading! // we're all done reading!
@ -263,8 +256,7 @@ textwindows int sys_fork_nt(void) {
} }
#endif #endif
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar, if (ntspawn(GetProgramExecutableName(), args, environ, forkvar,
&kNtIsInheritable, NULL, true, &kNtIsInheritable, NULL, true, 0, NULL, &startinfo,
0 /* kNtCreateNewProcessGroup */, NULL, &startinfo,
&procinfo) != -1) { &procinfo) != -1) {
CloseHandle(reader); CloseHandle(reader);
CloseHandle(procinfo.hThread); CloseHandle(procinfo.hThread);

View file

@ -31,7 +31,7 @@ _jmpstack:
mov %rcx,%rsi mov %rcx,%rsi
mov %r8,%rdx mov %r8,%rdx
mov %r9,%rcx mov %r9,%rcx
xor %rbp,%rbp xor %ebp,%ebp
call *%rax call *%rax
ud2 .unreachable
.endfn _jmpstack,globl,hidden .endfn _jmpstack,globl,hidden

View file

@ -171,7 +171,8 @@ noasan int ReleaseMemoryIntervals(struct MemoryIntervals *mm, int x, int y,
} }
noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h, noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
int prot, int flags, long offset, long size) { int prot, int flags, bool readonlyfile,
bool iscow, long offset, long size) {
/* asan runtime depends on this function */ /* asan runtime depends on this function */
unsigned i; unsigned i;
assert(y >= x); assert(y >= x);
@ -197,6 +198,8 @@ noasan int TrackMemoryInterval(struct MemoryIntervals *mm, int x, int y, long h,
mm->p[i].flags = flags; mm->p[i].flags = flags;
mm->p[i].offset = offset; mm->p[i].offset = offset;
mm->p[i].size = size; mm->p[i].size = size;
mm->p[i].iscow = iscow;
mm->p[i].readonlyfile = readonlyfile;
} }
return 0; return 0;
} }

View file

@ -38,6 +38,8 @@ struct MemoryInterval {
int flags; int flags;
long offset; long offset;
long size; long size;
bool iscow;
bool readonlyfile;
}; };
struct MemoryIntervals { struct MemoryIntervals {
@ -50,12 +52,11 @@ extern hidden struct MemoryIntervals _mmi;
const char *DescribeFrame(int); const char *DescribeFrame(int);
void PrintSystemMappings(int) hidden; void PrintSystemMappings(int) hidden;
char *DescribeProt(int, char[hasatleast 4]);
char *DescribeMapping(int, int, char[hasatleast 8]) hidden; char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden; bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden; void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int, int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int,
long, long) hidden; bool, bool, long, long) hidden;
int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int, int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
void (*)(struct MemoryIntervals *, int, int)) hidden; void (*)(struct MemoryIntervals *, int, int)) hidden;
void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden; void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;

View file

@ -25,16 +25,19 @@
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/log/backtrace.internal.h" #include "libc/log/backtrace.internal.h"
#include "libc/log/libfatal.internal.h" #include "libc/log/libfatal.internal.h"
#include "libc/log/log.h" #include "libc/log/log.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/rand/rand.h" #include "libc/rand/rand.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/map.h" #include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h" #include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -45,9 +48,14 @@
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000) #define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
#define FRAME(x) ((int)((intptr_t)(x) >> 16)) #define FRAME(x) ((int)((intptr_t)(x) >> 16))
forceinline wontreturn void Die(void) { static wontreturn void OnUnrecoverableMmapError(const char *s) {
if (weaken(__die)) weaken(__die)(); if (IsTiny()) {
abort(); unreachable;
} else {
STRACE("%s %m", s);
__restorewintty();
_Exit(199);
}
} }
noasan static bool IsMapped(char *p, size_t n) { noasan static bool IsMapped(char *p, size_t n) {
@ -93,12 +101,9 @@ noasan static bool Automap(int n, int *res) {
if (*res + n <= FRAME(kAutomapStart + (kAutomapStart - 1))) { if (*res + n <= FRAME(kAutomapStart + (kAutomapStart - 1))) {
return true; return true;
} else { } else {
STRACE("mmap(%.12p, %p) ENOMEM (automap interval exhausted)", ADDR(*res),
ADDR(n + 1));
return false; return false;
} }
} else { } else {
STRACE("mmap(%.12p, %p) ENOMEM (automap failed)", ADDR(*res), ADDR(n + 1));
return false; return false;
} }
} }
@ -109,31 +114,23 @@ static noasan void *MapMemory(void *addr, size_t size, int prot, int flags,
dm = sys_mmap(addr, size, prot, f, fd, off); dm = sys_mmap(addr, size, prot, f, fd, off);
if (UNLIKELY(dm.addr == MAP_FAILED)) { if (UNLIKELY(dm.addr == MAP_FAILED)) {
if (IsWindows() && (flags & MAP_FIXED)) { if (IsWindows() && (flags & MAP_FIXED)) {
STRACE("mmap(%.12p, %'ld) → %m (%s)", addr, size, OnUnrecoverableMmapError(
"can't recover from MAP_FIXED errors on Windows"); "can't recover from MAP_FIXED errors on Windows");
assert(!"MapMemory() failed");
Die();
} }
return MAP_FAILED; return MAP_FAILED;
} }
if (UNLIKELY(dm.addr != addr)) { if (UNLIKELY(dm.addr != addr)) {
STRACE("KERNEL DIDN'T RESPECT MAP_FIXED"); OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
assert(!"MapMemory() failed");
Die();
} }
if (!IsWindows() && (flags & MAP_FIXED)) { if (!IsWindows() && (flags & MAP_FIXED)) {
if (UntrackMemoryIntervals(addr, size)) { if (UntrackMemoryIntervals(addr, size)) {
STRACE("FIXED UNTRACK FAILED %m"); OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
assert(!"MapMemory() failed");
Die();
} }
} }
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags, off, if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags,
size)) { false, false, off, size)) {
if (sys_munmap(addr, n) == -1) { if (sys_munmap(addr, n) == -1) {
STRACE("TRACK MUNMAP FAILED %m"); OnUnrecoverableMmapError("TRACK MUNMAP FAILED");
assert(!"MapMemory() failed");
Die();
} }
return MAP_FAILED; return MAP_FAILED;
} }
@ -155,21 +152,19 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
int f, int x, size_t n) { int f, int x, size_t n) {
int64_t oi, sz; int64_t oi, sz;
struct DirectMap dm; struct DirectMap dm;
bool iscow, readonlyfile;
size_t i, m = (n - 1) * FRAMESIZE; size_t i, m = (n - 1) * FRAMESIZE;
assert(m < size && m + FRAMESIZE >= size); assert(m < size && m + FRAMESIZE >= size);
oi = fd == -1 ? 0 : off + m; oi = fd == -1 ? 0 : off + m;
sz = size - m; sz = size - m;
dm = sys_mmap(addr + m, sz, prot, f, fd, oi); dm = sys_mmap(addr + m, sz, prot, f, fd, oi);
if (dm.addr == MAP_FAILED) { if (dm.addr == MAP_FAILED) return MAP_FAILED;
STRACE("MapMemories(%.12p+%lx/%lx) %m", addr, m, size); iscow = (flags & MAP_PRIVATE) && fd != -1;
return MAP_FAILED; readonlyfile = (flags & MAP_SHARED) && fd != -1 &&
} (g_fds.p[fd].flags & O_ACCMODE) == O_RDONLY;
if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot, if (TrackMemoryInterval(&_mmi, x + (n - 1), x + (n - 1), dm.maphandle, prot,
flags, oi, sz) == -1) { flags, readonlyfile, iscow, oi, sz) == -1) {
STRACE("MapMemories(%.12p+%lx/%lx) unrecoverable failure #1 %m", addr, m, OnUnrecoverableMmapError("MapMemories unrecoverable #1");
size);
assert(!"MapMemories() failed");
Die();
} }
for (i = 0; i < m; i += FRAMESIZE) { for (i = 0; i < m; i += FRAMESIZE) {
oi = fd == -1 ? 0 : off + i; oi = fd == -1 ? 0 : off + i;
@ -177,11 +172,9 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
dm = sys_mmap(addr + i, sz, prot, f, fd, oi); dm = sys_mmap(addr + i, sz, prot, f, fd, oi);
if (dm.addr == MAP_FAILED || if (dm.addr == MAP_FAILED ||
TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE, TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE,
dm.maphandle, prot, flags, oi, sz) == -1) { dm.maphandle, prot, flags, readonlyfile, iscow, oi,
STRACE("MapMemories(%p+%x/%x) unrecoverable failure #2 %m", addr, i, sz) == -1) {
size); OnUnrecoverableMmapError("MapMemories unrecoverable #2");
assert(!"MapMemories() failed");
Die();
} }
} }
if (weaken(__asan_map_shadow) && !OverlapsShadowSpace(addr, size)) { if (weaken(__asan_map_shadow) && !OverlapsShadowSpace(addr, size)) {
@ -221,94 +214,87 @@ static textwindows dontinline noasan void *MapMemories(char *addr, size_t size,
*/ */
noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd, noasan void *mmap(void *addr, size_t size, int prot, int flags, int fd,
int64_t off) { int64_t off) {
void *res;
char *p = addr;
struct DirectMap dm; struct DirectMap dm;
int a, b, i, f, m, n, x; int a, b, i, f, m, n, x;
char mode[8], *p = addr; if (!IsTiny() && UNLIKELY(!size)) {
if (UNLIKELY(!size)) { STRACE("size=0");
STRACE("mmap(%.12p, %'zu) EINVAL (size=0)", p, size); res = VIP(einval());
return VIP(einval()); } else if (!IsTiny() && UNLIKELY(!IsLegalSize(size))) {
} STRACE("size isn't 48-bit");
if (UNLIKELY(!IsLegalSize(size))) { res = VIP(einval());
STRACE("mmap(%.12p, %'zu) EINVAL (size isn't 48-bit)", p, size); } else if (!IsTiny() && UNLIKELY(!IsLegalPointer(p))) {
return VIP(einval()); STRACE("p isn't 48-bit");
} res = VIP(einval());
if (UNLIKELY(!IsLegalPointer(p))) { } else if (!IsTiny() && UNLIKELY(!ALIGNED(p))) {
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, size); STRACE("p isn't 64kb aligned");
return VIP(einval()); res = VIP(einval());
} } else if (!IsTiny() && UNLIKELY(fd < -1)) {
if (UNLIKELY(!ALIGNED(p))) {
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, size);
return VIP(einval());
}
if (UNLIKELY(fd < -1)) {
STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd); STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd);
return VIP(ebadf()); res = VIP(ebadf());
} } else if (!IsTiny() && UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) { STRACE("fd anonymous mismatch");
STRACE("mmap(%.12p, %'zu, %s, %d, %'ld) EINVAL (fd anonymous mismatch)", p, res = VIP(einval());
size, DescribeMapping(prot, flags, mode), fd, off); } else if (!IsTiny() &&
return VIP(einval()); UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
} STRACE("MAP_SHARED ^ MAP_PRIVATE");
if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) { res = VIP(einval());
STRACE("mmap(%.12p, %'zu) EINVAL (MAP_SHARED ^ MAP_PRIVATE)", p, size); } else if (!IsTiny() && UNLIKELY(off < 0)) {
return VIP(einval()); STRACE("neg off");
} res = VIP(einval());
if (UNLIKELY(off < 0)) { } else if (!IsTiny() && UNLIKELY(INT64_MAX - size < off)) {
STRACE("mmap(%.12p, %'zu, off=%'ld) EINVAL (neg off)", p, size, off); STRACE("too large");
return VIP(einval()); res = VIP(einval());
} } else if (!IsTiny() && UNLIKELY(!ALIGNED(off))) {
if (UNLIKELY(INT64_MAX - size < off)) { STRACE("p isn't 64kb aligned");
STRACE("mmap(%.12p, %'zu, off=%'ld) EINVAL (too large)", p, size, off); res = VIP(einval());
return VIP(einval()); } else if (!IsTiny() && (flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
} #ifdef SYSDEBUG
if (UNLIKELY(!ALIGNED(off))) {
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, size);
return VIP(einval());
}
if ((flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
if (OverlapsImageSpace(p, size)) { if (OverlapsImageSpace(p, size)) {
STRACE("mmap(%.12p, %'zu) EFAULT (overlaps image)", p, size); STRACE("overlaps image");
} else { } else {
STRACE("mmap(%.12p, %'zu) EFAULT (overlaps existing)", p, size); STRACE("overlaps existing");
} }
return VIP(efault()); #endif
} res = VIP(efault());
if (__isfdkind(fd, kFdZip)) { } else if (!IsTiny() && __isfdkind(fd, kFdZip)) {
STRACE("mmap(%.12p, %'zu) EINVAL (fd is zipos handle)", p, size); STRACE("fd is zipos handle");
return VIP(einval()); res = VIP(einval());
} } else {
STRACE("mmap(%.12p, %'zu, %s, %d, %'ld)% m", p, size, if (fd == -1) {
DescribeMapping(prot, flags, mode), fd, off); size = ROUNDUP(size, FRAMESIZE);
if (fd == -1) { if (IsWindows()) {
size = ROUNDUP(size, FRAMESIZE); prot |= PROT_WRITE; /* kludge */
if (IsWindows()) {
prot |= PROT_WRITE; /* kludge */
}
}
n = FRAME(size) + !!(size & (FRAMESIZE - 1));
f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
if (flags & MAP_FIXED) {
x = FRAME(p);
if (IsWindows()) {
if (UntrackMemoryIntervals(p, size)) {
STRACE("FIXED UNTRACK FAILED %m");
assert(!"mmap() failed");
Die();
} }
} }
} else if (!NeedAutomap(p, size)) { n = FRAME(size) + !!(size & (FRAMESIZE - 1));
x = FRAME(p); f = (flags & ~MAP_FIXED_NOREPLACE) | MAP_FIXED;
} else if (!Automap(n, &x)) { if (flags & MAP_FIXED) {
return VIP(enomem()); x = FRAME(p);
} if (IsWindows()) {
p = (char *)ADDR(x); if (UntrackMemoryIntervals(p, size)) {
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */ OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off); }
if (dm.addr == MAP_FAILED) return MAP_FAILED; }
} } else if (!NeedAutomap(p, size)) {
if (!IsWindows()) { x = FRAME(p);
return MapMemory(p, size, prot, flags, fd, off, f, x, n); } else if (!Automap(n, &x)) {
} else { STRACE("AUTOMAP OUT OF MEMORY D:");
return MapMemories(p, size, prot, flags, fd, off, f, x, n); return VIP(enomem());
}
p = (char *)ADDR(x);
if (IsOpenbsd() && (f & MAP_GROWSDOWN)) { /* openbsd:dubstack */
dm = sys_mmap(p, size, prot, f & ~MAP_GROWSDOWN, fd, off);
if (dm.addr == MAP_FAILED) res = MAP_FAILED;
}
if (!IsWindows()) {
res = MapMemory(p, size, prot, flags, fd, off, f, x, n);
} else {
res = MapMemories(p, size, prot, flags, fd, off, f, x, n);
}
} }
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size,
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res);
return res;
} }

View file

@ -0,0 +1,107 @@
/*-*- 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
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/bits/asmflag.h"
#include "libc/bits/likely.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h"
#include "libc/nt/memory.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h"
#include "libc/runtime/memtrack.internal.h"
#include "libc/sysv/consts/nr.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/errfuns.h"
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
/**
* Modifies restrictions on virtual memory address range.
*
* @param addr needs to be 4kb aligned
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN,GROWSUP}
* @return 0 on success, or -1 w/ errno
* @see mmap()
*/
noasan noubsan privileged int mprotect(void *addr, size_t size, int prot) {
bool cf;
int64_t rc;
unsigned i;
uint32_t op;
char *a, *b, *x, *y, *p;
if (SupportsWindows() && (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC |
PROT_GROWSDOWN | PROT_GROWSUP))) {
rc = einval(); // unix checks prot before checking size
} else if (!size) {
return 0; // make new technology consistent with unix
} else if (UNLIKELY((intptr_t)addr & 4095)) {
rc = einval();
} else if (!IsWindows()) {
asm volatile(CFLAG_ASM("clc\n\tsyscall")
: CFLAG_CONSTRAINT(cf), "=a"(rc)
: "1"(__NR_mprotect), "D"(addr), "S"(size), "d"(prot)
: "rcx", "r11", "memory", "cc");
if (cf) {
errno = rc;
rc = -1;
} else if (rc > -4096ul) {
errno = -rc;
rc = -1;
}
} else {
rc = 0;
p = addr;
i = FindMemoryInterval(&_mmi, (intptr_t)p >> 16);
if (i == _mmi.i || (!i && p + size <= ADDR(_mmi.p[0].x))) {
// memory isn't in memtrack
// let's just trust the user then
// it's probably part of the executable
if (!VirtualProtect(addr, size, __prot2nt(prot, false), &op)) {
rc = -1;
}
} else {
// memory is in memtrack, so use memtrack, to do dimensioning
// we unfortunately must do something similar to this for cow
for (; i < _mmi.i; ++i) {
x = ADDR(_mmi.p[i].x);
y = x + _mmi.p[i].size;
if ((x <= p && p < y) || (x < p + size && p + size <= y) ||
(p < x && y < p + size)) {
a = MIN(MAX(p, x), y);
b = MAX(MIN(p + size, y), x);
if (!VirtualProtect(a, b - a, __prot2nt(prot, _mmi.p[i].iscow),
&op)) {
rc = -1;
break;
}
} else {
break;
}
}
}
}
STRACE("mprotect(%p, %'zu, %s) → %d% m", addr, size, DescribeProtFlags(prot),
rc);
return rc;
}

View file

@ -24,6 +24,7 @@
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/intrin/asan.internal.h" #include "libc/intrin/asan.internal.h"
#include "libc/intrin/describeflags.internal.h"
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
@ -67,48 +68,54 @@ static bool MustMoveMap(intptr_t y, size_t j) {
* @param q is new address * @param q is new address
*/ */
void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) { void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
enosys();
return MAP_FAILED;
void *q;
va_list va; va_list va;
void *res, *q;
if (f & MREMAP_FIXED) {
va_start(va, f);
q = va_arg(va, void *);
va_end(va);
} else {
q = 0;
}
enosys();
res = MAP_FAILED;
STRACE("mremap(%p, %'zu, %'zu, %s, %p) → %p% m", p, n, m,
DescribeRemapFlags(f), q, res);
return res;
#if 0
// TODO(jart): perhaps some day?
// probably not a big perf gain at this point :|
size_t i, j, k; size_t i, j, k;
struct DirectMap dm; struct DirectMap dm;
int a, b, prot, flags; int a, b, prot, flags;
assert(!__vforked); assert(!__vforked);
if (UNLIKELY(!m)) { if (UNLIKELY(!m)) {
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (m=0)", p, n, m, f); STRACE("m=0");
return VIP(einval()); return VIP(einval());
} } else if (UNLIKELY(!n)) {
if (UNLIKELY(!n)) { STRACE("n=0");
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n=0)", p, n, m, f);
return VIP(eopnotsupp()); return VIP(eopnotsupp());
} } else if (UNLIKELY(!ALIGNED(n))) {
if (UNLIKELY(!ALIGNED(n))) { STRACE("n align");
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n align)", p, n, m, f);
return VIP(eopnotsupp()); return VIP(eopnotsupp());
} } else if (UNLIKELY(!ALIGNED(m))) {
if (UNLIKELY(!ALIGNED(m))) { STRACE("n align");
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n align)", p, n, m, f);
return VIP(eopnotsupp()); return VIP(eopnotsupp());
} } else if (UNLIKELY(!ALIGNED(p))) {
if (UNLIKELY(!ALIGNED(p))) { STRACE("64kb align");
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (64kb align)", p, n, m, f);
return VIP(einval()); return VIP(einval());
} } else if (UNLIKELY(!IsLegalSize(n))) {
if (UNLIKELY(!IsLegalSize(n))) { STRACE("n too big");
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (n too big)", p, n, m, f);
return VIP(enomem()); return VIP(enomem());
} } else if (UNLIKELY(!IsLegalSize(m))) {
if (UNLIKELY(!IsLegalSize(m))) { STRACE("m too big");
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (m too big)", p, n, m, f);
return VIP(enomem()); return VIP(enomem());
} } else if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) {
if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) { STRACE("bad flag");
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (bad flag)", p, n, m, f);
return VIP(einval()); return VIP(einval());
} } else if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) {
if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) { STRACE("interval not tracked");
STRACE("munmap(%p, %'zu) EFAULT (interval not tracked)", p, n);
return VIP(efault()); return VIP(efault());
} }
STRACE("mremap(%p, %'zu, %'zu, %#b)", p, n, m, f); STRACE("mremap(%p, %'zu, %'zu, %#b)", p, n, m, f);
@ -119,9 +126,6 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
return VIP(eopnotsupp()); /* TODO */ return VIP(eopnotsupp()); /* TODO */
} }
if (f & MREMAP_FIXED) { if (f & MREMAP_FIXED) {
va_start(va, f);
q = va_arg(va, void *);
va_end(va);
if (!ALIGNED(q)) return VIP(einval()); if (!ALIGNED(q)) return VIP(einval());
return VIP(eopnotsupp()); /* TODO */ return VIP(eopnotsupp()); /* TODO */
} }
@ -145,7 +149,7 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
if (dm.addr == MAP_FAILED) return 0; if (dm.addr == MAP_FAILED) return 0;
if (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16, if (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16,
((uintptr_t)p + m - FRAMESIZE) >> 16, dm.maphandle, ((uintptr_t)p + m - FRAMESIZE) >> 16, dm.maphandle,
prot, flags, 0, m - n) != -1) { prot, flags, false, false, 0, m - n) != -1) {
if (weaken(__asan_map_shadow)) { if (weaken(__asan_map_shadow)) {
weaken(__asan_map_shadow)((uintptr_t)dm.addr, m - n); weaken(__asan_map_shadow)((uintptr_t)dm.addr, m - n);
} }
@ -178,7 +182,8 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
if (q == MAP_FAILED) return 0; if (q == MAP_FAILED) return 0;
if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16, if (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 && ((uintptr_t)p + n - FRAMESIZE) >> 16, 0) != -1 &&
TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, 0, m) != -1) { TrackMemoryInterval(&_mmi, a, b, -1, prot, flags, false, false, 0, m) !=
-1) {
if (weaken(__asan_poison)) { if (weaken(__asan_poison)) {
if (!OverlapsShadowSpace(p, n)) { if (!OverlapsShadowSpace(p, n)) {
weaken(__asan_poison)((intptr_t)p, n, kAsanUnmapped); weaken(__asan_poison)((intptr_t)p, n, kAsanUnmapped);
@ -198,4 +203,5 @@ void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
} else { } else {
return q; return q;
} }
#endif
} }

View file

@ -29,6 +29,29 @@
#define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16)) #define ADDR(x) ((char *)((int64_t)((uint64_t)(x) << 32) >> 16))
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
int i, rc = 0;
char *a, *b, *x, *y;
for (i = FindMemoryInterval(&_mmi, (intptr_t)addr >> 16); i < _mmi.i; ++i) {
x = ADDR(_mmi.p[i].x);
y = x + _mmi.p[i].size;
if ((x <= addr && addr < y) || (x < addr + size && addr + size <= y) ||
(addr < x && y < addr + size)) {
a = MIN(MAX(addr, x), y);
b = MAX(MIN(addr + size, y), x);
if (!FlushViewOfFile(a, b - a)) {
rc = -1;
break;
}
// TODO(jart): FlushFileBuffers too on g_fds handle if MS_SYNC?
} else {
break;
}
}
return rc;
}
#if 0
noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) { noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
char *a, *b; char *a, *b;
int rc, x, y, l, r, i; int rc, x, y, l, r, i;
@ -51,3 +74,4 @@ noasan textwindows int sys_msync_nt(char *addr, size_t size, int flags) {
} }
return rc; return rc;
} }
#endif

View file

@ -52,7 +52,9 @@
#if defined(__GNUC__) && defined(__ELF__) && !defined(__STRICT_ANSI__) #if defined(__GNUC__) && defined(__ELF__) && !defined(__STRICT_ANSI__)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
extern char ape_stack_prot[] __attribute__((__weak__));
extern char ape_stack_memsz[] __attribute__((__weak__)); extern char ape_stack_memsz[] __attribute__((__weak__));
extern char ape_stack_align[] __attribute__((__weak__));
#define GetStackSize() ((uintptr_t)ape_stack_memsz) #define GetStackSize() ((uintptr_t)ape_stack_memsz)

View file

@ -22,6 +22,7 @@
#include "libc/calls/internal.h" #include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h" #include "libc/dce.h"
#include "libc/elf/pf2prot.internal.h"
#include "libc/errno.h" #include "libc/errno.h"
#include "libc/fmt/fmt.h" #include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h" #include "libc/intrin/kprintf.h"
@ -42,6 +43,7 @@
#include "libc/nt/process.h" #include "libc/nt/process.h"
#include "libc/nt/runtime.h" #include "libc/nt/runtime.h"
#include "libc/nt/struct/teb.h" #include "libc/nt/struct/teb.h"
#include "libc/nt/thunk/msabi.h"
#include "libc/runtime/directmap.internal.h" #include "libc/runtime/directmap.internal.h"
#include "libc/runtime/internal.h" #include "libc/runtime/internal.h"
#include "libc/runtime/memtrack.internal.h" #include "libc/runtime/memtrack.internal.h"
@ -53,8 +55,10 @@
#if IsTiny() #if IsTiny()
extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW __msabi; extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW __msabi;
extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx __msabi; extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx __msabi;
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
#define CreateFileMapping __imp_CreateFileMappingW #define CreateFileMapping __imp_CreateFileMappingW
#define MapViewOfFileEx __imp_MapViewOfFileEx #define MapViewOfFileEx __imp_MapViewOfFileEx
#define VirtualProtect __imp_VirtualProtect
#endif #endif
#define AT_EXECFN 31L #define AT_EXECFN 31L
@ -114,12 +118,11 @@ forceinline void MakeLongDoubleLongAgain(void) {
static noasan textwindows wontreturn noinstrument void WinMainNew( static noasan textwindows wontreturn noinstrument void WinMainNew(
const char16_t *cmdline) { const char16_t *cmdline) {
bool32 rc; bool32 rc;
int64_t h; int64_t h, hand;
int version; uint32_t oldprot;
int i, count;
int64_t hand;
struct WinArgs *wa; struct WinArgs *wa;
const char16_t *env16; const char16_t *env16;
int i, prot, count, version;
intptr_t stackaddr, allocaddr; intptr_t stackaddr, allocaddr;
size_t allocsize, argsize, stacksize; size_t allocsize, argsize, stacksize;
version = NtGetPeb()->OSMajorVersion; version = NtGetPeb()->OSMajorVersion;
@ -152,9 +155,13 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite, CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
allocsize >> 32, allocsize, NULL)), allocsize >> 32, allocsize, NULL)),
kNtFileMapWrite | kNtFileMapExecute, 0, 0, allocsize, (void *)allocaddr); kNtFileMapWrite | kNtFileMapExecute, 0, 0, allocsize, (void *)allocaddr);
prot = (intptr_t)ape_stack_prot;
if (~prot & PROT_EXEC) {
VirtualProtect((void *)allocaddr, allocsize, kNtPageReadwrite, &oldprot);
}
_mmi.p[0].x = allocaddr >> 16; _mmi.p[0].x = allocaddr >> 16;
_mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1); _mmi.p[0].y = (allocaddr >> 16) + ((allocsize >> 16) - 1);
_mmi.p[0].prot = PROT_READ | PROT_WRITE | PROT_EXEC; _mmi.p[0].prot = prot;
_mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS; _mmi.p[0].flags = MAP_PRIVATE | MAP_ANONYMOUS;
_mmi.p[0].size = allocsize; _mmi.p[0].size = allocsize;
_mmi.i = 1; _mmi.i = 1;
@ -175,8 +182,8 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
wa->auxv[0][0] = pushpop(AT_EXECFN); wa->auxv[0][0] = pushpop(AT_EXECFN);
wa->auxv[0][1] = (intptr_t)wa->argv[0]; wa->auxv[0][1] = (intptr_t)wa->argv[0];
STRACE("WinMainNew() switching stacks"); STRACE("WinMainNew() switching stacks");
_jmpstack((char *)stackaddr + stacksize, cosmo, count, wa->argv, wa->envp, _jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo,
wa->auxv); count, wa->argv, wa->envp, wa->auxv);
} }
/** /**

View file

@ -234,7 +234,6 @@ syscon mmap MAP_HUGE_SHIFT 26 0 0 0 0 0
syscon mmap MAP_LOCKED 0x2000 0 0 0 0 0 syscon mmap MAP_LOCKED 0x2000 0 0 0 0 0
syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0 0 syscon mmap MAP_NONBLOCK 0x10000 0 0 0 0 0
syscon mmap MAP_POPULATE 0x8000 0 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping syscon mmap MAP_POPULATE 0x8000 0 0 0 0 0 # can avoid madvise(MADV_WILLNEED) on private file mapping
syscon mmap MAP_CONCEAL 0 0 0 0x8000 0 0 # omit from dumps
syscon mmap MAP_STACK 0x0100 0 0x0000400 0x4000 0x2000 0x100000 # use MAP_GROWSDOWN syscon mmap MAP_STACK 0x0100 0 0x0000400 0x4000 0x2000 0x100000 # use MAP_GROWSDOWN
syscon compat MAP_NOCORE 0 0 0x0020000 0x8000 0x8000 0 # use MAP_CONCEAL syscon compat MAP_NOCORE 0 0 0x0020000 0x8000 0x8000 0 # use MAP_CONCEAL
syscon compat MAP_ANON 0x20 0x1000 0x0001000 0x1000 0x1000 0x20 # bsd consensus; faked nt syscon compat MAP_ANON 0x20 0x1000 0x0001000 0x1000 0x1000 0x20 # bsd consensus; faked nt
@ -541,7 +540,7 @@ syscon sigact SA_NOCLDWAIT 2 32 32 32 32 2 # changes SIGCHLD so t
syscon sigact SA_SIGINFO 4 64 64 64 64 4 # asks kernel to provide ucontext_t argument, which has mutable cpu/fpu state of signalled process; and it is polyfilled by cosmopolitan; bsd consensus syscon sigact SA_SIGINFO 4 64 64 64 64 4 # asks kernel to provide ucontext_t argument, which has mutable cpu/fpu state of signalled process; and it is polyfilled by cosmopolitan; bsd consensus
syscon sigact SA_ONSTACK 0x08000000 1 1 1 1 0x08000000 # causes signal handler to be called on stack provided by sigaltstack(2); bsd consensus syscon sigact SA_ONSTACK 0x08000000 1 1 1 1 0x08000000 # causes signal handler to be called on stack provided by sigaltstack(2); bsd consensus
syscon sigact SA_RESTART 0x10000000 2 2 2 2 0x10000000 # prevents signal delivery from triggering EINTR on i/o calls (e.g. read/write/open/wait/accept) but doesn't impact non-i/o blocking calls (e.g. poll, sigsuspend, nanosleep) which will still EINTR; bsd consensus syscon sigact SA_RESTART 0x10000000 2 2 2 2 0x10000000 # prevents signal delivery from triggering EINTR on i/o calls (e.g. read/write/open/wait/accept) but doesn't impact non-i/o blocking calls (e.g. poll, sigsuspend, nanosleep) which will still EINTR; bsd consensus
syscon sigact SA_NODEFER 0x40000000 16 16 16 16 0x40000000 # blocks signal delivery during signal handling (i.e. lets you use longjmp() in the signal handler); bsd consensus syscon sigact SA_NODEFER 0x40000000 16 16 16 16 0x40000000 # lets signal handler be reentrant (e.g. so you can longjmp() out of signal handler); bsd consensus
syscon sigact SA_RESETHAND 0x80000000 4 4 4 4 0x80000000 # causes signal handler to be called at most once and then set to SIG_DFL automatically; bsd consensus syscon sigact SA_RESETHAND 0x80000000 4 4 4 4 0x80000000 # causes signal handler to be called at most once and then set to SIG_DFL automatically; bsd consensus
syscon compat SA_NOMASK 0x40000000 16 16 16 16 0x40000000 # same as SA_NODEFER syscon compat SA_NOMASK 0x40000000 16 16 16 16 0x40000000 # same as SA_NODEFER
syscon compat SA_ONESHOT 0x80000000 4 4 4 4 0x80000000 # same as SA_RESETHAND syscon compat SA_ONESHOT 0x80000000 4 4 4 4 0x80000000 # same as SA_RESETHAND
@ -571,6 +570,7 @@ syscon sicode TRAP_BRKPT 1 1 1 1 1 1 # SIGTRAP; process breakpoin
syscon sicode TRAP_TRACE 2 2 2 2 2 2 # SIGTRAP; process trace trap; unix consensus syscon sicode TRAP_TRACE 2 2 2 2 2 2 # SIGTRAP; process trace trap; unix consensus
syscon sicode SEGV_MAPERR 1 1 1 1 1 1 # SIGSEGV; address not mapped to object; unix consensus syscon sicode SEGV_MAPERR 1 1 1 1 1 1 # SIGSEGV; address not mapped to object; unix consensus
syscon sicode SEGV_ACCERR 2 2 2 2 2 2 # SIGSEGV; invalid permissions for mapped object; unix consensus syscon sicode SEGV_ACCERR 2 2 2 2 2 2 # SIGSEGV; invalid permissions for mapped object; unix consensus
syscon sicode SEGV_PKUERR -1 -1 100 -1 -1 -1 # SIGSEGV: x86: PKU violation
syscon sicode FPE_INTDIV 1 7 2 1 1 1 # SIGFPE; integer divide by zero syscon sicode FPE_INTDIV 1 7 2 1 1 1 # SIGFPE; integer divide by zero
syscon sicode FPE_INTOVF 2 8 1 2 2 2 # SIGFPE; integer overflow syscon sicode FPE_INTOVF 2 8 1 2 2 2 # SIGFPE; integer overflow
syscon sicode FPE_FLTDIV 3 1 3 3 3 3 # SIGFPE; floating point divide by zero syscon sicode FPE_FLTDIV 3 1 3 3 3 3 # SIGFPE; floating point divide by zero
@ -590,6 +590,7 @@ syscon sicode ILL_BADSTK 8 8 8 8 8 8 # SIGILL; internal stack err
syscon sicode BUS_ADRALN 1 1 1 1 1 1 # SIGBUS; invalid address alignment; unix consensus syscon sicode BUS_ADRALN 1 1 1 1 1 1 # SIGBUS; invalid address alignment; unix consensus
syscon sicode BUS_ADRERR 2 2 2 2 2 2 # SIGBUS; non-existent physical address; unix consensus syscon sicode BUS_ADRERR 2 2 2 2 2 2 # SIGBUS; non-existent physical address; unix consensus
syscon sicode BUS_OBJERR 3 3 3 3 3 3 # SIGBUS; object specific hardware error; unix consensus syscon sicode BUS_OBJERR 3 3 3 3 3 3 # SIGBUS; object specific hardware error; unix consensus
syscon sicode BUS_OOMERR -1 -1 100 -1 -1 -1 # SIGBUS; Non-standard: No memory.
syscon sicode BUS_MCEERR_AR 4 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # SIGBUS; Linux 2.6.32+ syscon sicode BUS_MCEERR_AR 4 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # SIGBUS; Linux 2.6.32+
syscon sicode BUS_MCEERR_AO 5 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # SIGBUS; Linux 2.6.32+ syscon sicode BUS_MCEERR_AO 5 0x80000000 0x80000000 0x80000000 0x80000000 0x80000000 # SIGBUS; Linux 2.6.32+
syscon sicode POLL_IN 1 1 1 1 1 1 # SIGIO; data input available; unix consensus syscon sicode POLL_IN 1 1 1 1 1 1 # SIGIO; data input available; unix consensus

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sicode,BUS_OOMERR,-1,-1,100,-1,-1,-1

View file

@ -1,2 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h" #include "libc/sysv/consts/syscon.internal.h"
.syscon mmap,MAP_CONCEAL,0,0,0,0x8000,0,0 .syscon mmap,MAP_CONCEAL,0,0,0x0020000,0x8000,0x8000,0

View file

@ -0,0 +1,2 @@
#include "libc/sysv/consts/syscon.internal.h"
.syscon sicode,SEGV_PKUERR,-1,-1,100,-1,-1,-1

View file

@ -23,6 +23,7 @@ extern const long TRAP_BRKPT;
extern const long TRAP_TRACE; extern const long TRAP_TRACE;
extern const long SEGV_MAPERR; extern const long SEGV_MAPERR;
extern const long SEGV_ACCERR; extern const long SEGV_ACCERR;
extern const long SEGV_PKUERR;
extern const long FPE_INTDIV; extern const long FPE_INTDIV;
extern const long FPE_INTOVF; extern const long FPE_INTOVF;
extern const long FPE_FLTDIV; extern const long FPE_FLTDIV;
@ -44,6 +45,7 @@ extern const long BUS_ADRERR;
extern const long BUS_OBJERR; extern const long BUS_OBJERR;
extern const long BUS_MCEERR_AR; extern const long BUS_MCEERR_AR;
extern const long BUS_MCEERR_AO; extern const long BUS_MCEERR_AO;
extern const long BUS_OOMERR;
extern const long POLL_IN; extern const long POLL_IN;
extern const long POLL_OUT; extern const long POLL_OUT;
extern const long POLL_MSG; extern const long POLL_MSG;
@ -87,6 +89,7 @@ COSMOPOLITAN_C_END_
#define SI_ASYNCNL SYMBOLIC(SI_ASYNCNL) #define SI_ASYNCNL SYMBOLIC(SI_ASYNCNL)
#define SI_KERNEL SYMBOLIC(SI_KERNEL) #define SI_KERNEL SYMBOLIC(SI_KERNEL)
#define SI_NOINFO SYMBOLIC(SI_NOINFO) #define SI_NOINFO SYMBOLIC(SI_NOINFO)
#define SEGV_PKUERR SYMBOLIC(SEGV_PKUERR)
#define FPE_INTDIV SYMBOLIC(FPE_INTDIV) #define FPE_INTDIV SYMBOLIC(FPE_INTDIV)
#define FPE_INTOVF SYMBOLIC(FPE_INTOVF) #define FPE_INTOVF SYMBOLIC(FPE_INTOVF)
#define FPE_FLTDIV SYMBOLIC(FPE_FLTDIV) #define FPE_FLTDIV SYMBOLIC(FPE_FLTDIV)
@ -99,6 +102,7 @@ COSMOPOLITAN_C_END_
#define ILL_ILLADR SYMBOLIC(ILL_ILLADR) #define ILL_ILLADR SYMBOLIC(ILL_ILLADR)
#define ILL_ILLTRP SYMBOLIC(ILL_ILLTRP) #define ILL_ILLTRP SYMBOLIC(ILL_ILLTRP)
#define ILL_PRVOPC SYMBOLIC(ILL_PRVOPC) #define ILL_PRVOPC SYMBOLIC(ILL_PRVOPC)
#define BUS_OOMERR SYMBOLIC(BUS_OOMERR)
#define BUS_MCEERR_AR SYMBOLIC(BUS_MCEERR_AR) #define BUS_MCEERR_AR SYMBOLIC(BUS_MCEERR_AR)
#define BUS_MCEERR_AO SYMBOLIC(BUS_MCEERR_AO) #define BUS_MCEERR_AO SYMBOLIC(BUS_MCEERR_AO)

View file

@ -360,7 +360,7 @@ _init_systemfive_stack:
mov __NR_mmap,%eax mov __NR_mmap,%eax
movabs $ape_stack_vaddr,%rdi movabs $ape_stack_vaddr,%rdi
mov $ape_stack_memsz,%esi mov $ape_stack_memsz,%esi
mov $PROT_READ|PROT_WRITE,%edx mov $ape_stack_prot,%edx
mov $MAP_PRIVATE|MAP_FIXED,%r10d mov $MAP_PRIVATE|MAP_FIXED,%r10d
or MAP_ANONYMOUS,%r10d or MAP_ANONYMOUS,%r10d
or $-1,%r8d or $-1,%r8d
@ -548,6 +548,7 @@ syscon_windows:/*
.previous .previous
#endif /* DEBUGSYS */ #endif /* DEBUGSYS */
.weak ape_stack_prot
.weak ape_stack_vaddr .weak ape_stack_vaddr
.weak ape_stack_memsz .weak ape_stack_memsz
.weak ape_stack_align .weak ape_stack_align

View file

@ -124,11 +124,15 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) {
// test fpu crash (unrecoverable) // test fpu crash (unrecoverable)
// test signal handler can modify cpu registers (now it's recoverable!) // test signal handler can modify cpu registers (now it's recoverable!)
void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) { void SkipOverFaultingInstruction(struct ucontext *ctx) {
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15); xed_instruction_length_decode(&xedd, (void *)ctx->uc_mcontext.rip, 15);
ctx->uc_mcontext.rip += xedd.length; ctx->uc_mcontext.rip += xedd.length;
}
void OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) {
SkipOverFaultingInstruction(ctx);
ctx->uc_mcontext.rax = 42; ctx->uc_mcontext.rax = 42;
ctx->uc_mcontext.rdx = 0; ctx->uc_mcontext.rdx = 0;
} }

View file

@ -65,7 +65,7 @@ static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x,
struct MemoryIntervals *mm; struct MemoryIntervals *mm;
mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t)); mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t));
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0)); CHECK_NE(-1, TrackMemoryInterval(mm, x, y, h, 0, 0, 0, 0, 0, 0));
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
CheckMemoryIntervalsEqual(mm, t + 1); CheckMemoryIntervalsEqual(mm, t + 1);
free(mm); free(mm);
@ -102,10 +102,10 @@ TEST(TrackMemoryInterval, TestFull) {
mm = calloc(1, sizeof(struct MemoryIntervals)); mm = calloc(1, sizeof(struct MemoryIntervals));
for (i = 0; i < mm->n; ++i) { for (i = 0; i < mm->n; ++i) {
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0)); CHECK_NE(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0, 0, 0));
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
} }
CHECK_EQ(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0)); CHECK_EQ(-1, TrackMemoryInterval(mm, i, i, i, 0, 0, 0, 0, 0, 0));
CHECK_EQ(ENOMEM, errno); CHECK_EQ(ENOMEM, errno);
CheckMemoryIntervalsAreOk(mm); CheckMemoryIntervalsAreOk(mm);
free(mm); free(mm);

View file

@ -0,0 +1,212 @@
/*-*- 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 2021 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/calls.h"
#include "libc/calls/struct/sigaction.h"
#include "libc/dce.h"
#include "libc/errno.h"
#include "libc/fmt/fmt.h"
#include "libc/intrin/kprintf.h"
#include "libc/log/log.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/stdio.h"
#include "libc/sysv/consts/map.h"
#include "libc/sysv/consts/o.h"
#include "libc/sysv/consts/prot.h"
#include "libc/sysv/consts/sa.h"
#include "libc/testlib/testlib.h"
#include "libc/x/x.h"
#include "third_party/xed/x86.h"
volatile bool gotsegv;
volatile bool gotbusted;
struct sigaction old[2];
char testlib_enable_tmp_setup_teardown;
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;
}
void OnSigSegv(int sig, struct siginfo *si, struct ucontext *ctx) {
gotsegv = true;
SkipOverFaultingInstruction(ctx);
}
void OnSigBus(int sig, struct siginfo *si, struct ucontext *ctx) {
gotbusted = true;
SkipOverFaultingInstruction(ctx);
#if 0
kprintf("SIGBUS%n");
kprintf("si->si_signo = %G%n", si->si_signo);
kprintf("si->si_errno = %s (%d)%n", strerror_short(si->si_errno),
si->si_errno);
kprintf("si->si_code = %s (%d)%n", GetSiCodeName(sig, si->si_code),
si->si_code);
kprintf("┌si->si_addr = %p%n", si->si_addr);
kprintf("┼─────────────────%n");
kprintf("│si->si_pid = %d (note: getpid() is %d)%n", si->si_pid, getpid());
kprintf("│si->si_uid = %d%n", si->si_uid);
kprintf("┼─────────────────%n");
kprintf("│si->si_timerid = %d%n", si->si_timerid);
kprintf("└si->si_overrun = %d%n", si->si_overrun);
kprintf("si->si_value.sival_int = %d%n", si->si_value.sival_int);
kprintf("si->si_value.sival_ptr = %p%n", si->si_value.sival_ptr);
system(xasprintf("cat /proc/%d/map", getpid()));
#endif
}
void SetUp(void) {
struct sigaction sabus = {.sa_sigaction = OnSigBus,
.sa_flags = SA_SIGINFO | SA_RESETHAND};
struct sigaction sasegv = {.sa_sigaction = OnSigSegv,
.sa_flags = SA_SIGINFO | SA_RESETHAND};
sigaction(SIGBUS, &sabus, old + 0);
sigaction(SIGSEGV, &sasegv, old + 1);
gotbusted = false;
gotsegv = false;
}
void TearDown(void) {
sigaction(SIGBUS, old + 0, 0);
sigaction(SIGSEGV, old + 1, 0);
}
TEST(mprotect, testOkMemory) {
char *p = gc(memalign(PAGESIZE, PAGESIZE));
p[0] = 0;
ASSERT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
p[0] = 1;
EXPECT_EQ(1, p[0]);
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
}
TEST(mprotect, testSegfault_writeToReadOnlyAnonymous) {
volatile char *p;
p = gc(memalign(PAGESIZE, PAGESIZE));
EXPECT_FALSE(gotsegv);
p[0] = 1;
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ));
missingno(p[0]);
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
p[0] = 2;
EXPECT_TRUE(gotsegv | gotbusted);
EXPECT_EQ(1, p[0]);
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
}
TEST(mprotect, testExecOnly_impliesReadFlag) {
volatile char *p;
p = gc(memalign(PAGESIZE, PAGESIZE));
p[0] = 1;
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_EXEC));
missingno(p[0]);
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
p[0] = 2;
EXPECT_TRUE(gotsegv | gotbusted);
EXPECT_EQ(1, p[0]);
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
}
TEST(mprotect, testProtNone_cantEvenRead) {
volatile char *p;
p = gc(memalign(PAGESIZE, PAGESIZE));
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_NONE));
missingno(p[0]);
EXPECT_TRUE(gotsegv | gotbusted);
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
}
static const char kRet31337[] = {
0xb8, 0x69, 0x7a, 0x00, 0x00, // mov $31337,%eax
0xc3, // ret
};
TEST(mprotect, testExecJit_actuallyWorks) {
int (*p)(void) = gc(memalign(PAGESIZE, PAGESIZE));
memcpy(p, kRet31337, sizeof(kRet31337));
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_EXEC));
EXPECT_EQ(31337, p());
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
}
TEST(mprotect, testRwxMap_vonNeumannRules) {
if (IsOpenbsd()) return; // boo
int (*p)(void) = gc(memalign(PAGESIZE, PAGESIZE));
memcpy(p, kRet31337, sizeof(kRet31337));
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE | PROT_EXEC));
EXPECT_EQ(31337, p());
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
EXPECT_NE(-1, mprotect(p, PAGESIZE, PROT_READ | PROT_WRITE));
}
TEST(mprotect, testExecuteFlatFileMapOpenedAsReadonly) {
int (*p)(void);
size_t n = sizeof(kRet31337);
ASSERT_SYS(0, 3, creat("return31337", 0755));
ASSERT_SYS(0, n, write(3, kRet31337, n));
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 3, open("return31337", O_RDONLY));
EXPECT_NE(MAP_FAILED,
(p = mmap(NULL, n, PROT_READ | PROT_EXEC, MAP_PRIVATE, 3, 0)));
EXPECT_EQ(31337, p());
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 0, munmap(p, n));
}
TEST(mprotect, testFileMap_canChangeToExecWhileOpenInRdwrMode) {
int (*p)(void);
size_t n = sizeof(kRet31337);
ASSERT_SYS(0, 3, open("return31337", O_CREAT | O_TRUNC | O_RDWR, 0755));
ASSERT_SYS(0, n, write(3, kRet31337, n));
EXPECT_NE(MAP_FAILED,
(p = mmap(NULL, n, PROT_READ | PROT_WRITE, MAP_PRIVATE, 3, 0)));
EXPECT_NE(-1, mprotect(p, n, PROT_READ | PROT_EXEC));
EXPECT_EQ(31337, p());
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
ASSERT_SYS(0, 0, close(3));
ASSERT_SYS(0, 0, munmap(p, n));
}
TEST(mprotect, testBadProt_failsEinval) {
volatile char *p = gc(memalign(PAGESIZE, PAGESIZE));
EXPECT_EQ(-1, mprotect(p, 0, -1));
EXPECT_EQ(EINVAL, errno);
}
TEST(mprotect, testZeroSize_doesNothing) {
volatile char *p = gc(memalign(PAGESIZE, PAGESIZE));
EXPECT_NE(-1, mprotect(p, 0, PROT_READ));
p[0] = 1;
EXPECT_FALSE(gotsegv);
EXPECT_FALSE(gotbusted);
}

View file

@ -35,8 +35,8 @@ testonly dontdiscard uint8_t *unbingx86op(const char16_t *codez) {
* Long mode instruction length decoder. * Long mode instruction length decoder.
*/ */
testonly int ild(const char16_t *codez) { testonly int ild(const char16_t *codez) {
int error;
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
enum XedError error;
error = xed_instruction_length_decode( error = xed_instruction_length_decode(
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64), xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64),
gc(unbingx86op(codez)), strlen16(codez) + 16); gc(unbingx86op(codez)), strlen16(codez) + 16);
@ -47,8 +47,8 @@ testonly int ild(const char16_t *codez) {
* Real mode instruction length decoder. * Real mode instruction length decoder.
*/ */
testonly int ildreal(const char16_t *codez) { testonly int ildreal(const char16_t *codez) {
int error;
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
enum XedError error;
error = xed_instruction_length_decode( error = xed_instruction_length_decode(
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_REAL), xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_REAL),
gc(unbingx86op(codez)), strlen16(codez) + 16); gc(unbingx86op(codez)), strlen16(codez) + 16);
@ -59,8 +59,8 @@ testonly int ildreal(const char16_t *codez) {
* Legacy mode instruction length decoder. * Legacy mode instruction length decoder.
*/ */
testonly int ildlegacy(const char16_t *codez) { testonly int ildlegacy(const char16_t *codez) {
int error;
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
enum XedError error;
error = xed_instruction_length_decode( error = xed_instruction_length_decode(
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32), xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32),
gc(unbingx86op(codez)), strlen16(codez) + 16); gc(unbingx86op(codez)), strlen16(codez) + 16);

View file

@ -380,9 +380,14 @@ int dlmalloc_sys_trim(struct MallocState *m, size_t pad) {
size_t newsize = sp->size - extra; size_t newsize = sp->size - extra;
(void)newsize; /* placate people compiling -Wunused-variable */ (void)newsize; /* placate people compiling -Wunused-variable */
/* Prefer mremap, fall back to munmap */ /* Prefer mremap, fall back to munmap */
if ((mremap(sp->base, sp->size, newsize, 0, 0) != MAP_FAILED) || int err = errno;
(munmap(sp->base + newsize, extra) == 0)) { if (mremap(sp->base, sp->size, newsize, 0, 0) != MAP_FAILED) {
released = extra; released = extra;
} else {
errno = err;
if (!munmap(sp->base + newsize, extra)) {
released = extra;
}
} }
} }
} }

View file

@ -1,3 +1,4 @@
#include "libc/errno.h"
#include "third_party/dlmalloc/dlmalloc.internal.h" #include "third_party/dlmalloc/dlmalloc.internal.h"
/* Realloc using mmap */ /* Realloc using mmap */
@ -12,7 +13,9 @@ mchunkptr dlmalloc_mmap_resize(mstate m, mchunkptr oldp, size_t nb, int flags) {
size_t offset = oldp->prev_foot; size_t offset = oldp->prev_foot;
size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD; size_t oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK); size_t newmmsize = mmap_align(nb + SIX_SIZE_T_SIZES + CHUNK_ALIGN_MASK);
int err = errno;
char *cp = mremap((char *)oldp - offset, oldmmsize, newmmsize, flags, 0); char *cp = mremap((char *)oldp - offset, oldmmsize, newmmsize, flags, 0);
errno = err;
if (cp != CMFAIL) { if (cp != CMFAIL) {
mchunkptr newp = (mchunkptr)(cp + offset); mchunkptr newp = (mchunkptr)(cp + offset);
size_t psize = newmmsize - offset - MMAP_FOOT_PAD; size_t psize = newmmsize - offset - MMAP_FOOT_PAD;

View file

@ -46,9 +46,9 @@ too short, and lower numbers represent other errors.");
static PyObject * static PyObject *
xed_ild(PyObject *self, PyObject *args) xed_ild(PyObject *self, PyObject *args)
{ {
int e;
Py_ssize_t n; Py_ssize_t n;
const char *p; const char *p;
enum XedError e;
struct XedDecodedInst xedd; struct XedDecodedInst xedd;
if (!PyArg_ParseTuple(args, "y#:ild", &p, &n)) return 0; if (!PyArg_ParseTuple(args, "y#:ild", &p, &n)) return 0;
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64); xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);

440
third_party/xed/x86.h vendored
View file

@ -38,277 +38,58 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
enum XedMachineMode { #define XED_MACHINE_MODE_REAL XED_MODE_REAL
XED_MACHINE_MODE_REAL = XED_MODE_REAL, #define XED_MACHINE_MODE_LEGACY_32 XED_MODE_LEGACY
XED_MACHINE_MODE_LEGACY_32 = XED_MODE_LEGACY, #define XED_MACHINE_MODE_LONG_64 XED_MODE_LONG
XED_MACHINE_MODE_LONG_64 = XED_MODE_LONG, #define XED_MACHINE_MODE_UNREAL (1 << 2 | XED_MODE_REAL)
XED_MACHINE_MODE_UNREAL = 1 << 2 | XED_MODE_REAL, #define XED_MACHINE_MODE_LEGACY_16 (2 << 2 | XED_MODE_REAL)
XED_MACHINE_MODE_LEGACY_16 = 2 << 2 | XED_MODE_REAL, #define XED_MACHINE_MODE_LONG_COMPAT_16 (3 << 2 | XED_MODE_REAL)
XED_MACHINE_MODE_LONG_COMPAT_16 = 3 << 2 | XED_MODE_REAL, #define XED_MACHINE_MODE_LONG_COMPAT_32 (4 << 2 | XED_MODE_LEGACY)
XED_MACHINE_MODE_LONG_COMPAT_32 = 4 << 2 | XED_MODE_LEGACY, #define XED_MACHINE_MODE_LAST (XED_MACHINE_MODE_LONG_COMPAT_32 + 1)
XED_MACHINE_MODE_LAST,
};
enum XedError { #define XED_ERROR_NONE 0
XED_ERROR_NONE, #define XED_ERROR_BUFFER_TOO_SHORT 1
XED_ERROR_BUFFER_TOO_SHORT, #define XED_ERROR_GENERAL_ERROR 2
XED_ERROR_GENERAL_ERROR, #define XED_ERROR_INVALID_FOR_CHIP 3
XED_ERROR_INVALID_FOR_CHIP, #define XED_ERROR_BAD_REGISTER 4
XED_ERROR_BAD_REGISTER, #define XED_ERROR_BAD_LOCK_PREFIX 5
XED_ERROR_BAD_LOCK_PREFIX, #define XED_ERROR_BAD_REP_PREFIX 6
XED_ERROR_BAD_REP_PREFIX, #define XED_ERROR_BAD_LEGACY_PREFIX 7
XED_ERROR_BAD_LEGACY_PREFIX, #define XED_ERROR_BAD_REX_PREFIX 8
XED_ERROR_BAD_REX_PREFIX, #define XED_ERROR_BAD_EVEX_UBIT 9
XED_ERROR_BAD_EVEX_UBIT, #define XED_ERROR_BAD_MAP 10
XED_ERROR_BAD_MAP, #define XED_ERROR_BAD_EVEX_V_PRIME 11
XED_ERROR_BAD_EVEX_V_PRIME, #define XED_ERROR_BAD_EVEX_Z_NO_MASKING 12
XED_ERROR_BAD_EVEX_Z_NO_MASKING, #define XED_ERROR_NO_OUTPUT_POINTER 13
XED_ERROR_NO_OUTPUT_POINTER, #define XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED 14
XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED, #define XED_ERROR_BAD_MEMOP_INDEX 15
XED_ERROR_BAD_MEMOP_INDEX, #define XED_ERROR_CALLBACK_PROBLEM 16
XED_ERROR_CALLBACK_PROBLEM, #define XED_ERROR_GATHER_REGS 17
XED_ERROR_GATHER_REGS, #define XED_ERROR_INSTR_TOO_LONG 18
XED_ERROR_INSTR_TOO_LONG, #define XED_ERROR_INVALID_MODE 19
XED_ERROR_INVALID_MODE, #define XED_ERROR_BAD_EVEX_LL 20
XED_ERROR_BAD_EVEX_LL, #define XED_ERROR_UNIMPLEMENTED 21
XED_ERROR_UNIMPLEMENTED, #define XED_ERROR_LAST 22
XED_ERROR_LAST
};
enum XedAddressWidth { #define XED_ADDRESS_WIDTH_INVALID 0
XED_ADDRESS_WIDTH_INVALID = 0, #define XED_ADDRESS_WIDTH_16b 2
XED_ADDRESS_WIDTH_16b = 2, #define XED_ADDRESS_WIDTH_32b 4
XED_ADDRESS_WIDTH_32b = 4, #define XED_ADDRESS_WIDTH_64b 8
XED_ADDRESS_WIDTH_64b = 8, #define XED_ADDRESS_WIDTH_LAST 9
XED_ADDRESS_WIDTH_LAST
};
enum XedChip { #define XED_ILD_MAP0 0 /* 8086+ ... */
XED_CHIP_INVALID = 1, #define XED_ILD_MAP1 1 /* 286+ 0x0F,... */
XED_CHIP_I86 = 2, #define XED_ILD_MAP2 2 /* Core2+ 0x0F,0x38,... */
XED_CHIP_I86FP = 3, #define XED_ILD_MAP3 3 /* Core2+ 0x0F,0x3A,... */
XED_CHIP_I186 = 4, #define XED_ILD_MAP4 4
XED_CHIP_I186FP = 5, #define XED_ILD_MAP5 5
XED_CHIP_I286REAL = 6, #define XED_ILD_MAP6 6
XED_CHIP_I286 = 7, #define XED_ILD_MAPAMD 7
XED_CHIP_I2186FP = 8, #define XED_ILD_MAP_XOP8 8
XED_CHIP_I386REAL = 9, #define XED_ILD_MAP_XOP9 9
XED_CHIP_I386 = 10, #define XED_ILD_MAP_XOPA 10
XED_CHIP_I386FP = 11, #define XED_ILD_MAP_LAST 11
XED_CHIP_I486REAL = 12, #define XED_ILD_MAP_INVALID 12
XED_CHIP_I486 = 13,
XED_CHIP_PENTIUMREAL = 14,
XED_CHIP_PENTIUM = 15,
XED_CHIP_QUARK = 16,
XED_CHIP_PENTIUMMMXREAL = 17,
XED_CHIP_PENTIUMMMX = 18,
XED_CHIP_ALLREAL = 19,
XED_CHIP_PENTIUMPRO = 20,
XED_CHIP_PENTIUM2 = 21,
XED_CHIP_PENTIUM3 = 22,
XED_CHIP_PENTIUM4 = 23,
XED_CHIP_P4PRESCOTT = 24,
XED_CHIP_P4PRESCOTT_NOLAHF = 25,
XED_CHIP_P4PRESCOTT_VTX = 26,
XED_CHIP_CORE2 = 27,
XED_CHIP_PENRYN = 28,
XED_CHIP_PENRYN_E = 29,
XED_CHIP_NEHALEM = 30,
XED_CHIP_WESTMERE = 31,
XED_CHIP_BONNELL = 32,
XED_CHIP_SALTWELL = 33,
XED_CHIP_SILVERMONT = 34,
XED_CHIP_AMD = 35,
XED_CHIP_GOLDMONT = 36,
XED_CHIP_GOLDMONT_PLUS = 37,
XED_CHIP_TREMONT = 38,
XED_CHIP_SANDYBRIDGE = 39,
XED_CHIP_IVYBRIDGE = 40,
XED_CHIP_HASWELL = 41,
XED_CHIP_BROADWELL = 42,
XED_CHIP_SKYLAKE = 43,
XED_CHIP_SKYLAKE_SERVER = 44,
XED_CHIP_CASCADE_LAKE = 45,
XED_CHIP_KNL = 46,
XED_CHIP_KNM = 47,
XED_CHIP_CANNONLAKE = 48,
XED_CHIP_ICELAKE = 49,
XED_CHIP_ICELAKE_SERVER = 50,
XED_CHIP_FUTURE = 51,
XED_CHIP_ALL = 52,
XED_CHIP_LAST
};
enum XedIsaSet {
XED_ISA_SET_INVALID,
XED_ISA_SET_3DNOW,
XED_ISA_SET_ADOX_ADCX,
XED_ISA_SET_AES,
XED_ISA_SET_AMD,
XED_ISA_SET_AVX,
XED_ISA_SET_AVX2,
XED_ISA_SET_AVX2GATHER,
XED_ISA_SET_AVX512BW_128,
XED_ISA_SET_AVX512BW_128N,
XED_ISA_SET_AVX512BW_256,
XED_ISA_SET_AVX512BW_512,
XED_ISA_SET_AVX512BW_KOP,
XED_ISA_SET_AVX512CD_128,
XED_ISA_SET_AVX512CD_256,
XED_ISA_SET_AVX512CD_512,
XED_ISA_SET_AVX512DQ_128,
XED_ISA_SET_AVX512DQ_128N,
XED_ISA_SET_AVX512DQ_256,
XED_ISA_SET_AVX512DQ_512,
XED_ISA_SET_AVX512DQ_KOP,
XED_ISA_SET_AVX512DQ_SCALAR,
XED_ISA_SET_AVX512ER_512,
XED_ISA_SET_AVX512ER_SCALAR,
XED_ISA_SET_AVX512F_128,
XED_ISA_SET_AVX512F_128N,
XED_ISA_SET_AVX512F_256,
XED_ISA_SET_AVX512F_512,
XED_ISA_SET_AVX512F_KOP,
XED_ISA_SET_AVX512F_SCALAR,
XED_ISA_SET_AVX512PF_512,
XED_ISA_SET_AVX512_4FMAPS_512,
XED_ISA_SET_AVX512_4FMAPS_SCALAR,
XED_ISA_SET_AVX512_4VNNIW_512,
XED_ISA_SET_AVX512_BITALG_128,
XED_ISA_SET_AVX512_BITALG_256,
XED_ISA_SET_AVX512_BITALG_512,
XED_ISA_SET_AVX512_GFNI_128,
XED_ISA_SET_AVX512_GFNI_256,
XED_ISA_SET_AVX512_GFNI_512,
XED_ISA_SET_AVX512_IFMA_128,
XED_ISA_SET_AVX512_IFMA_256,
XED_ISA_SET_AVX512_IFMA_512,
XED_ISA_SET_AVX512_VAES_128,
XED_ISA_SET_AVX512_VAES_256,
XED_ISA_SET_AVX512_VAES_512,
XED_ISA_SET_AVX512_VBMI2_128,
XED_ISA_SET_AVX512_VBMI2_256,
XED_ISA_SET_AVX512_VBMI2_512,
XED_ISA_SET_AVX512_VBMI_128,
XED_ISA_SET_AVX512_VBMI_256,
XED_ISA_SET_AVX512_VBMI_512,
XED_ISA_SET_AVX512_VNNI_128,
XED_ISA_SET_AVX512_VNNI_256,
XED_ISA_SET_AVX512_VNNI_512,
XED_ISA_SET_AVX512_VPCLMULQDQ_128,
XED_ISA_SET_AVX512_VPCLMULQDQ_256,
XED_ISA_SET_AVX512_VPCLMULQDQ_512,
XED_ISA_SET_AVX512_VPOPCNTDQ_128,
XED_ISA_SET_AVX512_VPOPCNTDQ_256,
XED_ISA_SET_AVX512_VPOPCNTDQ_512,
XED_ISA_SET_AVXAES,
XED_ISA_SET_AVX_GFNI,
XED_ISA_SET_BMI1,
XED_ISA_SET_BMI2,
XED_ISA_SET_CET,
XED_ISA_SET_CLDEMOTE,
XED_ISA_SET_CLFLUSHOPT,
XED_ISA_SET_CLFSH,
XED_ISA_SET_CLWB,
XED_ISA_SET_CLZERO,
XED_ISA_SET_CMOV,
XED_ISA_SET_CMPXCHG16B,
XED_ISA_SET_F16C,
XED_ISA_SET_FAT_NOP,
XED_ISA_SET_FCMOV,
XED_ISA_SET_FMA,
XED_ISA_SET_FMA4,
XED_ISA_SET_FXSAVE,
XED_ISA_SET_FXSAVE64,
XED_ISA_SET_GFNI,
XED_ISA_SET_I186,
XED_ISA_SET_I286PROTECTED,
XED_ISA_SET_I286REAL,
XED_ISA_SET_I386,
XED_ISA_SET_I486,
XED_ISA_SET_I486REAL,
XED_ISA_SET_I86,
XED_ISA_SET_INVPCID,
XED_ISA_SET_LAHF,
XED_ISA_SET_LONGMODE,
XED_ISA_SET_LZCNT,
XED_ISA_SET_MONITOR,
XED_ISA_SET_MONITORX,
XED_ISA_SET_MOVBE,
XED_ISA_SET_MOVDIR,
XED_ISA_SET_MPX,
XED_ISA_SET_PAUSE,
XED_ISA_SET_PCLMULQDQ,
XED_ISA_SET_PCONFIG,
XED_ISA_SET_PENTIUMMMX,
XED_ISA_SET_PENTIUMREAL,
XED_ISA_SET_PKU,
XED_ISA_SET_POPCNT,
XED_ISA_SET_PPRO,
XED_ISA_SET_PREFETCHW,
XED_ISA_SET_PREFETCHWT1,
XED_ISA_SET_PREFETCH_NOP,
XED_ISA_SET_PT,
XED_ISA_SET_RDPID,
XED_ISA_SET_RDPMC,
XED_ISA_SET_RDRAND,
XED_ISA_SET_RDSEED,
XED_ISA_SET_RDTSCP,
XED_ISA_SET_RDWRFSGS,
XED_ISA_SET_RTM,
XED_ISA_SET_SGX,
XED_ISA_SET_SGX_ENCLV,
XED_ISA_SET_SHA,
XED_ISA_SET_SMAP,
XED_ISA_SET_SMX,
XED_ISA_SET_SSE,
XED_ISA_SET_SSE2,
XED_ISA_SET_SSE2MMX,
XED_ISA_SET_SSE3,
XED_ISA_SET_SSE3X87,
XED_ISA_SET_SSE4,
XED_ISA_SET_SSE42,
XED_ISA_SET_SSE4A,
XED_ISA_SET_SSEMXCSR,
XED_ISA_SET_SSE_PREFETCH,
XED_ISA_SET_SSSE3,
XED_ISA_SET_SSSE3MMX,
XED_ISA_SET_SVM,
XED_ISA_SET_TBM,
XED_ISA_SET_VAES,
XED_ISA_SET_VMFUNC,
XED_ISA_SET_VPCLMULQDQ,
XED_ISA_SET_VTX,
XED_ISA_SET_WAITPKG,
XED_ISA_SET_WBNOINVD,
XED_ISA_SET_X87,
XED_ISA_SET_XOP,
XED_ISA_SET_XSAVE,
XED_ISA_SET_XSAVEC,
XED_ISA_SET_XSAVEOPT,
XED_ISA_SET_XSAVES,
XED_ISA_SET_LAST
};
enum XedIldMap {
XED_ILD_MAP0, // 8086+ ...
XED_ILD_MAP1, // 286+ 0x0F,...
XED_ILD_MAP2, // Core2+ 0x0F,0x38,...
XED_ILD_MAP3, // Core2+ 0x0F,0x3A,...
XED_ILD_MAP4,
XED_ILD_MAP5,
XED_ILD_MAP6,
XED_ILD_MAPAMD,
XED_ILD_MAP_XOP8,
XED_ILD_MAP_XOP9,
XED_ILD_MAP_XOPA,
XED_ILD_MAP_LAST,
XED_ILD_MAP_INVALID
};
struct XedChipFeatures {
uint64_t f[3];
};
struct XedOperands { /* struct XedOperands { /*
rep rep
@ -341,7 +122,7 @@ struct XedOperands { /*
uint8_t opcode; uint8_t opcode;
uint8_t srm : 3; uint8_t srm : 3;
}; };
uint8_t map : 4; // enum XedIldMap uint8_t map : 4;
}; };
uint16_t dispatch; uint16_t dispatch;
}; };
@ -353,16 +134,16 @@ struct XedOperands { /*
uint8_t scale : 2; uint8_t scale : 2;
}; };
}; };
bool osz : 1; // operand size override prefix bool osz : 1; /* operand size override prefix */
bool rexw : 1; // rex.w or rex.wb or etc. 64-bit override bool rexw : 1; /* rex.w or rex.wb or etc. 64-bit override */
bool rexb : 1; // rex.b or rex.wb or etc. see modrm table bool rexb : 1; /* rex.b or rex.wb or etc. see modrm table */
bool rexr : 1; // rex.r or rex.wr or etc. see modrm table bool rexr : 1; /* rex.r or rex.wr or etc. see modrm table */
bool rex : 1; // any rex prefix including rex bool rex : 1; /* any rex prefix including rex */
bool rexx : 1; // rex.x or rex.wx or etc. see sib table bool rexx : 1; /* rex.x or rex.wx or etc. see sib table */
bool rexrr : 1; // evex bool rexrr : 1; /* evex */
bool asz : 1; // address size override bool asz : 1; /* address size override */
int64_t disp; // displacement(%xxx) mostly sign-extended int64_t disp; /* displacement(%xxx) mostly sign-extended */
uint64_t uimm0; // $immediate mostly sign-extended uint64_t uimm0; /* $immediate mostly sign-extended */
bool out_of_bytes : 1; bool out_of_bytes : 1;
bool is_intel_specific : 1; bool is_intel_specific : 1;
bool ild_f2 : 1; bool ild_f2 : 1;
@ -372,7 +153,7 @@ struct XedOperands { /*
bool amd3dnow : 1; bool amd3dnow : 1;
bool lock : 1; bool lock : 1;
union { union {
uint8_t modrm; // selects address register uint8_t modrm; /* selects address register */
struct { struct {
uint8_t rm : 3; uint8_t rm : 3;
uint8_t reg : 3; uint8_t reg : 3;
@ -380,33 +161,33 @@ struct XedOperands { /*
}; };
}; };
uint8_t max_bytes; uint8_t max_bytes;
uint8_t rep : 2; // 0, 2 (0xf2 repnz), 3 (0xf3 rep/repe) uint8_t rep : 2; /* 0, 2 (0xf2 repnz), 3 (0xf3 rep/repe) */
uint8_t has_modrm : 2; uint8_t has_modrm : 2;
bool imm_signed : 1; // internal bool imm_signed : 1; /* internal */
bool disp_unsigned : 1; // internal bool disp_unsigned : 1; /* internal */
uint8_t seg_ovd : 3; // XED_SEG_xx uint8_t seg_ovd : 3; /* XED_SEG_xx */
uint8_t error : 5; // enum XedError uint8_t error : 5; /* enum XedError */
uint8_t mode : 2; // real,legacy,long uint8_t mode : 2; /* real,legacy,long */
uint8_t hint : 3; // static branch prediction uint8_t hint : 3; /* static branch prediction */
uint8_t uimm1; // enter $x,$y uint8_t uimm1; /* enter $x,$y */
uint8_t disp_width; // in bits uint8_t disp_width; /* in bits */
uint8_t imm_width; // in bits uint8_t imm_width; /* in bits */
uint8_t mode_first_prefix; // see xed_set_chip_modes() uint8_t mode_first_prefix; /* see xed_set_chip_modes() */
uint8_t nrexes; uint8_t nrexes;
uint8_t nprefixes; uint8_t nprefixes;
uint8_t nseg_prefixes; uint8_t nseg_prefixes;
uint8_t ubit; // vex uint8_t ubit; /* vex */
uint8_t vexvalid; // vex uint8_t vexvalid; /* vex */
uint8_t vexdest3; // vex uint8_t vexdest3; /* vex */
uint8_t vexdest4; // vex uint8_t vexdest4; /* vex */
uint8_t vexdest210; // vex uint8_t vexdest210; /* vex */
uint8_t vex_prefix; // vex uint8_t vex_prefix; /* vex */
uint8_t zeroing; // evex uint8_t zeroing; /* evex */
uint8_t bcrc; // evex uint8_t bcrc; /* evex */
uint8_t llrc; // evex uint8_t llrc; /* evex */
uint8_t vl; // evex uint8_t vl; /* evex */
uint8_t mask; // evex uint8_t mask; /* evex */
uint8_t imm1_bytes; // evex uint8_t imm1_bytes; /* evex */
uint8_t pos_disp; uint8_t pos_disp;
uint8_t pos_imm; uint8_t pos_imm;
uint8_t pos_imm1; uint8_t pos_imm1;
@ -421,8 +202,7 @@ struct XedDecodedInst {
struct XedOperands op; struct XedOperands op;
}; };
forceinline void xed_operands_set_mode(struct XedOperands *p, forceinline void xed_operands_set_mode(struct XedOperands *p, int mmode) {
enum XedMachineMode mmode) {
p->realmode = false; p->realmode = false;
switch (mmode) { switch (mmode) {
default: default:
@ -448,57 +228,13 @@ forceinline void xed_operands_set_mode(struct XedOperands *p,
} }
} }
forceinline void xed_set_chip_modes(struct XedDecodedInst *d,
enum XedChip chip) {
switch (chip) {
case XED_CHIP_INVALID:
break;
case XED_CHIP_I86:
case XED_CHIP_I86FP:
case XED_CHIP_I186:
case XED_CHIP_I186FP:
case XED_CHIP_I286REAL:
case XED_CHIP_I286:
case XED_CHIP_I2186FP:
case XED_CHIP_I386REAL:
case XED_CHIP_I386:
case XED_CHIP_I386FP:
case XED_CHIP_I486REAL:
case XED_CHIP_I486:
case XED_CHIP_QUARK:
case XED_CHIP_PENTIUM:
case XED_CHIP_PENTIUMREAL:
case XED_CHIP_PENTIUMMMX:
case XED_CHIP_PENTIUMMMXREAL:
d->op.mode_first_prefix = 1;
break;
default:
break;
}
switch (chip) {
case XED_CHIP_INVALID:
case XED_CHIP_ALL:
case XED_CHIP_AMD:
break;
default:
d->op.is_intel_specific = 1;
break;
}
}
extern const char kXedErrorNames[]; extern const char kXedErrorNames[];
extern const uint64_t kXedChipFeatures[XED_CHIP_LAST][3];
extern const uint8_t kXedEamode[2][3]; extern const uint8_t kXedEamode[2][3];
struct XedDecodedInst *xed_decoded_inst_zero_set_mode(struct XedDecodedInst *, struct XedDecodedInst *xed_decoded_inst_zero_set_mode(struct XedDecodedInst *,
enum XedMachineMode); int);
int xed_instruction_length_decode(struct XedDecodedInst *, const void *,
enum XedError xed_instruction_length_decode(struct XedDecodedInst *, size_t);
const void *, size_t);
bool xed_isa_set_is_valid_for_chip(enum XedIsaSet, enum XedChip);
bool xed_test_chip_features(struct XedChipFeatures *, enum XedIsaSet);
void xed_get_chip_features(struct XedChipFeatures *, enum XedChip);
COSMOPOLITAN_C_END_ COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ #endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -16,7 +16,7 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
#include "third_party/xed/x86.h" #include "third_party/xed/x86isa.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Xed (Apache 2.0)\\n\ Xed (Apache 2.0)\\n\

View file

@ -1115,7 +1115,7 @@ privileged static void xed_decode_instruction_length(
* Clears instruction decoder state. * Clears instruction decoder state.
*/ */
privileged struct XedDecodedInst *xed_decoded_inst_zero_set_mode( privileged struct XedDecodedInst *xed_decoded_inst_zero_set_mode(
struct XedDecodedInst *p, enum XedMachineMode mmode) { struct XedDecodedInst *p, int mmode) {
__builtin_memset(p, 0, sizeof(*p)); __builtin_memset(p, 0, sizeof(*p));
xed_operands_set_mode(&p->op, mmode); xed_operands_set_mode(&p->op, mmode);
return p; return p;
@ -1131,8 +1131,8 @@ privileged struct XedDecodedInst *xed_decoded_inst_zero_set_mode(
* @note binary footprint increases ~4kb if this is used * @note binary footprint increases ~4kb if this is used
* @see biggest code in gdb/clang/tensorflow binaries * @see biggest code in gdb/clang/tensorflow binaries
*/ */
privileged enum XedError xed_instruction_length_decode( privileged int xed_instruction_length_decode(struct XedDecodedInst *xedd,
struct XedDecodedInst *xedd, const void *itext, size_t bytes) { const void *itext, size_t bytes) {
__builtin_memcpy(xedd->bytes, itext, MIN(15, bytes)); __builtin_memcpy(xedd->bytes, itext, MIN(15, bytes));
xedd->op.max_bytes = MIN(15, bytes); xedd->op.max_bytes = MIN(15, bytes);
xed_decode_instruction_length(xedd); xed_decode_instruction_length(xedd);

View file

@ -17,6 +17,7 @@
limitations under the License. limitations under the License.
*/ */
#include "third_party/xed/x86.h" #include "third_party/xed/x86.h"
#include "third_party/xed/x86isa.h"
asm(".ident\t\"\\n\\n\ asm(".ident\t\"\\n\\n\
Xed (Apache 2.0)\\n\ Xed (Apache 2.0)\\n\
@ -25,21 +26,21 @@ Copyright 2019 Justine Alexandra Roberts Tunney\\n\
Modifications: Trimmed down to 3kb [2019-03-22 jart]\""); Modifications: Trimmed down to 3kb [2019-03-22 jart]\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
bool xed_isa_set_is_valid_for_chip(enum XedIsaSet isa_set, enum XedChip chip) { bool xed_isa_set_is_valid_for_chip(int isa_set, int chip) {
unsigned n, r; unsigned n, r;
n = isa_set / 64; n = isa_set / 64;
r = isa_set - (64 * n); r = isa_set - (64 * n);
return !!(kXedChipFeatures[chip][n] & (1ul << r)); return !!(kXedChipFeatures[chip][n] & (1ul << r));
} }
bool xed_test_chip_features(struct XedChipFeatures *p, enum XedIsaSet isa_set) { bool xed_test_chip_features(struct XedChipFeatures *p, int isa_set) {
unsigned n, r; unsigned n, r;
n = isa_set / 64; n = isa_set / 64;
r = isa_set - (64 * n); r = isa_set - (64 * n);
return !!(p->f[n] & (1ul << r)); return !!(p->f[n] & (1ul << r));
} }
void xed_get_chip_features(struct XedChipFeatures *p, enum XedChip chip) { void xed_get_chip_features(struct XedChipFeatures *p, int chip) {
if (p) { if (p) {
if (chip < XED_CHIP_LAST) { if (chip < XED_CHIP_LAST) {
p->f[0] = kXedChipFeatures[chip][0]; p->f[0] = kXedChipFeatures[chip][0];

259
third_party/xed/x86isa.h vendored Normal file
View file

@ -0,0 +1,259 @@
#ifndef COSMOPOLITAN_THIRD_PARTY_XED_X86ISA_H_
#define COSMOPOLITAN_THIRD_PARTY_XED_X86ISA_H_
#include "third_party/xed/x86.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
#define XED_CHIP_INVALID 1
#define XED_CHIP_I86 2
#define XED_CHIP_I86FP 3
#define XED_CHIP_I186 4
#define XED_CHIP_I186FP 5
#define XED_CHIP_I286REAL 6
#define XED_CHIP_I286 7
#define XED_CHIP_I2186FP 8
#define XED_CHIP_I386REAL 9
#define XED_CHIP_I386 10
#define XED_CHIP_I386FP 11
#define XED_CHIP_I486REAL 12
#define XED_CHIP_I486 13
#define XED_CHIP_PENTIUMREAL 14
#define XED_CHIP_PENTIUM 15
#define XED_CHIP_QUARK 16
#define XED_CHIP_PENTIUMMMXREAL 17
#define XED_CHIP_PENTIUMMMX 18
#define XED_CHIP_ALLREAL 19
#define XED_CHIP_PENTIUMPRO 20
#define XED_CHIP_PENTIUM2 21
#define XED_CHIP_PENTIUM3 22
#define XED_CHIP_PENTIUM4 23
#define XED_CHIP_P4PRESCOTT 24
#define XED_CHIP_P4PRESCOTT_NOLAHF 25
#define XED_CHIP_P4PRESCOTT_VTX 26
#define XED_CHIP_CORE2 27
#define XED_CHIP_PENRYN 28
#define XED_CHIP_PENRYN_E 29
#define XED_CHIP_NEHALEM 30
#define XED_CHIP_WESTMERE 31
#define XED_CHIP_BONNELL 32
#define XED_CHIP_SALTWELL 33
#define XED_CHIP_SILVERMONT 34
#define XED_CHIP_AMD 35
#define XED_CHIP_GOLDMONT 36
#define XED_CHIP_GOLDMONT_PLUS 37
#define XED_CHIP_TREMONT 38
#define XED_CHIP_SANDYBRIDGE 39
#define XED_CHIP_IVYBRIDGE 40
#define XED_CHIP_HASWELL 41
#define XED_CHIP_BROADWELL 42
#define XED_CHIP_SKYLAKE 43
#define XED_CHIP_SKYLAKE_SERVER 44
#define XED_CHIP_CASCADE_LAKE 45
#define XED_CHIP_KNL 46
#define XED_CHIP_KNM 47
#define XED_CHIP_CANNONLAKE 48
#define XED_CHIP_ICELAKE 49
#define XED_CHIP_ICELAKE_SERVER 50
#define XED_CHIP_FUTURE 51
#define XED_CHIP_ALL 52
#define XED_CHIP_LAST 53
#define XED_ISA_SET_INVALID 0
#define XED_ISA_SET_3DNOW 1
#define XED_ISA_SET_ADOX_ADCX 2
#define XED_ISA_SET_AES 3
#define XED_ISA_SET_AMD 4
#define XED_ISA_SET_AVX 5
#define XED_ISA_SET_AVX2 6
#define XED_ISA_SET_AVX2GATHER 7
#define XED_ISA_SET_AVX512BW_128 8
#define XED_ISA_SET_AVX512BW_128N 9
#define XED_ISA_SET_AVX512BW_256 10
#define XED_ISA_SET_AVX512BW_512 11
#define XED_ISA_SET_AVX512BW_KOP 12
#define XED_ISA_SET_AVX512CD_128 13
#define XED_ISA_SET_AVX512CD_256 14
#define XED_ISA_SET_AVX512CD_512 15
#define XED_ISA_SET_AVX512DQ_128 16
#define XED_ISA_SET_AVX512DQ_128N 17
#define XED_ISA_SET_AVX512DQ_256 18
#define XED_ISA_SET_AVX512DQ_512 19
#define XED_ISA_SET_AVX512DQ_KOP 20
#define XED_ISA_SET_AVX512DQ_SCALAR 21
#define XED_ISA_SET_AVX512ER_512 22
#define XED_ISA_SET_AVX512ER_SCALAR 23
#define XED_ISA_SET_AVX512F_128 24
#define XED_ISA_SET_AVX512F_128N 25
#define XED_ISA_SET_AVX512F_256 26
#define XED_ISA_SET_AVX512F_512 27
#define XED_ISA_SET_AVX512F_KOP 28
#define XED_ISA_SET_AVX512F_SCALAR 29
#define XED_ISA_SET_AVX512PF_512 30
#define XED_ISA_SET_AVX512_4FMAPS_512 31
#define XED_ISA_SET_AVX512_4FMAPS_SCALAR 32
#define XED_ISA_SET_AVX512_4VNNIW_512 33
#define XED_ISA_SET_AVX512_BITALG_128 34
#define XED_ISA_SET_AVX512_BITALG_256 35
#define XED_ISA_SET_AVX512_BITALG_512 36
#define XED_ISA_SET_AVX512_GFNI_128 37
#define XED_ISA_SET_AVX512_GFNI_256 38
#define XED_ISA_SET_AVX512_GFNI_512 39
#define XED_ISA_SET_AVX512_IFMA_128 40
#define XED_ISA_SET_AVX512_IFMA_256 41
#define XED_ISA_SET_AVX512_IFMA_512 42
#define XED_ISA_SET_AVX512_VAES_128 43
#define XED_ISA_SET_AVX512_VAES_256 44
#define XED_ISA_SET_AVX512_VAES_512 45
#define XED_ISA_SET_AVX512_VBMI2_128 46
#define XED_ISA_SET_AVX512_VBMI2_256 47
#define XED_ISA_SET_AVX512_VBMI2_512 48
#define XED_ISA_SET_AVX512_VBMI_128 49
#define XED_ISA_SET_AVX512_VBMI_256 50
#define XED_ISA_SET_AVX512_VBMI_512 51
#define XED_ISA_SET_AVX512_VNNI_128 52
#define XED_ISA_SET_AVX512_VNNI_256 53
#define XED_ISA_SET_AVX512_VNNI_512 54
#define XED_ISA_SET_AVX512_VPCLMULQDQ_128 55
#define XED_ISA_SET_AVX512_VPCLMULQDQ_256 56
#define XED_ISA_SET_AVX512_VPCLMULQDQ_512 57
#define XED_ISA_SET_AVX512_VPOPCNTDQ_128 58
#define XED_ISA_SET_AVX512_VPOPCNTDQ_256 59
#define XED_ISA_SET_AVX512_VPOPCNTDQ_512 60
#define XED_ISA_SET_AVXAES 61
#define XED_ISA_SET_AVX_GFNI 62
#define XED_ISA_SET_BMI1 63
#define XED_ISA_SET_BMI2 64
#define XED_ISA_SET_CET 65
#define XED_ISA_SET_CLDEMOTE 66
#define XED_ISA_SET_CLFLUSHOPT 67
#define XED_ISA_SET_CLFSH 68
#define XED_ISA_SET_CLWB 69
#define XED_ISA_SET_CLZERO 70
#define XED_ISA_SET_CMOV 71
#define XED_ISA_SET_CMPXCHG16B 72
#define XED_ISA_SET_F16C 73
#define XED_ISA_SET_FAT_NOP 74
#define XED_ISA_SET_FCMOV 75
#define XED_ISA_SET_FMA 76
#define XED_ISA_SET_FMA4 77
#define XED_ISA_SET_FXSAVE 78
#define XED_ISA_SET_FXSAVE64 79
#define XED_ISA_SET_GFNI 80
#define XED_ISA_SET_I186 81
#define XED_ISA_SET_I286PROTECTED 82
#define XED_ISA_SET_I286REAL 83
#define XED_ISA_SET_I386 84
#define XED_ISA_SET_I486 85
#define XED_ISA_SET_I486REAL 86
#define XED_ISA_SET_I86 87
#define XED_ISA_SET_INVPCID 88
#define XED_ISA_SET_LAHF 89
#define XED_ISA_SET_LONGMODE 90
#define XED_ISA_SET_LZCNT 91
#define XED_ISA_SET_MONITOR 92
#define XED_ISA_SET_MONITORX 93
#define XED_ISA_SET_MOVBE 94
#define XED_ISA_SET_MOVDIR 95
#define XED_ISA_SET_MPX 96
#define XED_ISA_SET_PAUSE 97
#define XED_ISA_SET_PCLMULQDQ 98
#define XED_ISA_SET_PCONFIG 99
#define XED_ISA_SET_PENTIUMMMX 100
#define XED_ISA_SET_PENTIUMREAL 101
#define XED_ISA_SET_PKU 102
#define XED_ISA_SET_POPCNT 103
#define XED_ISA_SET_PPRO 104
#define XED_ISA_SET_PREFETCHW 105
#define XED_ISA_SET_PREFETCHWT1 106
#define XED_ISA_SET_PREFETCH_NOP 107
#define XED_ISA_SET_PT 108
#define XED_ISA_SET_RDPID 109
#define XED_ISA_SET_RDPMC 110
#define XED_ISA_SET_RDRAND 111
#define XED_ISA_SET_RDSEED 112
#define XED_ISA_SET_RDTSCP 113
#define XED_ISA_SET_RDWRFSGS 114
#define XED_ISA_SET_RTM 115
#define XED_ISA_SET_SGX 116
#define XED_ISA_SET_SGX_ENCLV 117
#define XED_ISA_SET_SHA 118
#define XED_ISA_SET_SMAP 119
#define XED_ISA_SET_SMX 120
#define XED_ISA_SET_SSE 121
#define XED_ISA_SET_SSE2 122
#define XED_ISA_SET_SSE2MMX 123
#define XED_ISA_SET_SSE3 124
#define XED_ISA_SET_SSE3X87 125
#define XED_ISA_SET_SSE4 126
#define XED_ISA_SET_SSE42 127
#define XED_ISA_SET_SSE4A 128
#define XED_ISA_SET_SSEMXCSR 129
#define XED_ISA_SET_SSE_PREFETCH 130
#define XED_ISA_SET_SSSE3 131
#define XED_ISA_SET_SSSE3MMX 132
#define XED_ISA_SET_SVM 133
#define XED_ISA_SET_TBM 134
#define XED_ISA_SET_VAES 135
#define XED_ISA_SET_VMFUNC 136
#define XED_ISA_SET_VPCLMULQDQ 137
#define XED_ISA_SET_VTX 138
#define XED_ISA_SET_WAITPKG 139
#define XED_ISA_SET_WBNOINVD 140
#define XED_ISA_SET_X87 141
#define XED_ISA_SET_XOP 142
#define XED_ISA_SET_XSAVE 143
#define XED_ISA_SET_XSAVEC 144
#define XED_ISA_SET_XSAVEOPT 145
#define XED_ISA_SET_XSAVES 146
#define XED_ISA_SET_LAST 147
struct XedChipFeatures {
uint64_t f[3];
};
forceinline void xed_set_chip_modes(struct XedDecodedInst *d, int chip) {
switch (chip) {
case XED_CHIP_INVALID:
break;
case XED_CHIP_I86:
case XED_CHIP_I86FP:
case XED_CHIP_I186:
case XED_CHIP_I186FP:
case XED_CHIP_I286REAL:
case XED_CHIP_I286:
case XED_CHIP_I2186FP:
case XED_CHIP_I386REAL:
case XED_CHIP_I386:
case XED_CHIP_I386FP:
case XED_CHIP_I486REAL:
case XED_CHIP_I486:
case XED_CHIP_QUARK:
case XED_CHIP_PENTIUM:
case XED_CHIP_PENTIUMREAL:
case XED_CHIP_PENTIUMMMX:
case XED_CHIP_PENTIUMMMXREAL:
d->op.mode_first_prefix = 1;
break;
default:
break;
}
switch (chip) {
case XED_CHIP_INVALID:
case XED_CHIP_ALL:
case XED_CHIP_AMD:
break;
default:
d->op.is_intel_specific = 1;
break;
}
}
extern const uint64_t kXedChipFeatures[XED_CHIP_LAST][3];
bool xed_test_chip_features(struct XedChipFeatures *, int);
void xed_get_chip_features(struct XedChipFeatures *, int);
bool xed_isa_set_is_valid_for_chip(int, int);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_THIRD_PARTY_XED_X86ISA_H_ */

View file

@ -38,7 +38,7 @@ const struct IdName kXedModeNames[] = {
{XED_MACHINE_MODE_UNREAL, "unreal"}, {XED_MACHINE_MODE_UNREAL, "unreal"},
}; };
enum XedMachineMode g_mode; int g_mode;
struct XedDecodedInst g_xedd; struct XedDecodedInst g_xedd;
wontreturn void ShowUsage(int rc, FILE *f) { wontreturn void ShowUsage(int rc, FILE *f) {

View file

@ -367,7 +367,6 @@ static bool hasonworkerstart;
static bool hasonhttprequest; static bool hasonhttprequest;
static bool hascontenttype; static bool hascontenttype;
static bool ishandlingrequest; static bool ishandlingrequest;
static bool keyboardinterrupt;
static bool listeningonport443; static bool listeningonport443;
static bool hasonprocesscreate; static bool hasonprocesscreate;
static bool hasonprocessdestroy; static bool hasonprocessdestroy;
@ -384,6 +383,7 @@ static int changeuid;
static int changegid; static int changegid;
static int isyielding; static int isyielding;
static int statuscode; static int statuscode;
static int shutdownsig;
static int sslpskindex; static int sslpskindex;
static int oldloglevel; static int oldloglevel;
static int maxpayloadsize; static int maxpayloadsize;
@ -477,24 +477,24 @@ static void OnUsr2(void) {
meltdown = true; meltdown = true;
} }
static void OnTerm(void) { static void OnTerm(int sig) {
if (!terminated) { if (!terminated) {
shutdownsig = sig;
terminated = true; terminated = true;
} else { } else {
killed = true; killed = true;
} }
} }
static void OnInt(void) { static void OnInt(int sig) {
keyboardinterrupt = true; OnTerm(sig);
OnTerm();
} }
static void OnHup(void) { static void OnHup(int sig) {
if (daemonize) { if (daemonize) {
OnUsr1(); OnUsr1();
} else { } else {
OnTerm(); OnTerm(sig);
} }
} }
@ -1182,6 +1182,18 @@ static void HandleWorkerExit(int pid, int ws, struct rusage *ru) {
SyncSharedMemory(); SyncSharedMemory();
} }
static void KillGroupImpl(int sig) {
LOGIFNEG1(kill(0, sig));
}
static void KillGroup(void) {
if (IsWindows()) {
KillGroupImpl(SIGINT);
} else {
KillGroupImpl(SIGTERM);
}
}
static void WaitAll(void) { static void WaitAll(void) {
int ws, pid; int ws, pid;
struct rusage ru; struct rusage ru;
@ -1198,7 +1210,7 @@ static void WaitAll(void) {
killed = false; killed = false;
terminated = false; terminated = false;
WARNF("(srvr) redbean shall terminate harder"); WARNF("(srvr) redbean shall terminate harder");
LOGIFNEG1(kill(0, SIGTERM)); KillGroup();
} }
errno = 0; errno = 0;
continue; continue;
@ -6680,15 +6692,11 @@ static void Listen(void) {
static void HandleShutdown(void) { static void HandleShutdown(void) {
CloseServerFds(); CloseServerFds();
if (keyboardinterrupt) { INFOF("(srvr) received %s", strsignal(shutdownsig));
INFOF("(srvr) received keyboard interrupt"); if (shutdownsig == SIGTERM) {
} else { if (!killed) terminated = false;
INFOF("(srvr) received term signal"); INFOF("(srvr) killing process group");
if (!killed) { KillGroup();
terminated = false;
}
DEBUGF("(srvr) sending TERM to process group");
LOGIFNEG1(kill(0, SIGTERM));
} }
WaitAll(); WaitAll();
} }
@ -6918,7 +6926,9 @@ void RedBean(int argc, char *argv[]) {
// to children. the downside to doing this seems to be that // to children. the downside to doing this seems to be that
// ctrl-c isn't propagating as expected when running redbean // ctrl-c isn't propagating as expected when running redbean
// underneath strace.com :| // underneath strace.com :|
setpgid(getpid(), getpid()); if (!IsWindows()) {
setpgid(getpid(), getpid());
}
if (logpath) { if (logpath) {
close(2); close(2);
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640); open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);