mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-02-07 06:53:33 +00:00
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:
parent
c95c9d9508
commit
f684e348d4
76 changed files with 1844 additions and 1121 deletions
2
Makefile
2
Makefile
|
@ -294,6 +294,7 @@ COSMOPOLITAN_OBJECTS = \
|
|||
THIRD_PARTY_COMPILER_RT \
|
||||
LIBC_THREAD \
|
||||
LIBC_TINYMATH \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_INTRIN \
|
||||
|
@ -317,6 +318,7 @@ COSMOPOLITAN_HEADERS = \
|
|||
LIBC_RUNTIME \
|
||||
LIBC_SOCK \
|
||||
LIBC_STDIO \
|
||||
THIRD_PARTY_XED \
|
||||
LIBC_STR \
|
||||
LIBC_SYSV \
|
||||
LIBC_THREAD \
|
||||
|
|
34
ape/ape.S
34
ape/ape.S
|
@ -660,6 +660,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
|
||||
#if SupportsSystemv() || SupportsMetal()
|
||||
.section .elf.phdrs,"a",@progbits
|
||||
|
||||
.long PT_LOAD
|
||||
.long PF_R|PF_X
|
||||
.stub ape_rom_offset,quad
|
||||
|
@ -668,6 +669,7 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
.stub ape_rom_filesz,quad
|
||||
.stub ape_rom_memsz,quad
|
||||
.stub ape_rom_align,quad
|
||||
|
||||
.long PT_LOAD
|
||||
.long PF_R|PF_W
|
||||
.stub ape_ram_offset,quad
|
||||
|
@ -676,14 +678,32 @@ apesh: .ascii "'\n#'\"\n" # sixth edition shebang
|
|||
.stub ape_ram_filesz,quad
|
||||
.stub ape_ram_memsz,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 PF_R|PF_W
|
||||
.stub ape_stack_offset,quad
|
||||
.stub ape_stack_vaddr,quad
|
||||
.stub ape_stack_paddr,quad
|
||||
.stub ape_stack_filesz,quad
|
||||
.stub ape_stack_memsz,quad
|
||||
.stub ape_stack_align,quad
|
||||
.stub ape_stack_pf,long # override w/ PF_X for execstack
|
||||
.stub ape_stack_offset,quad # ignored
|
||||
.stub ape_stack_vaddr,quad # is mmap()'d with MAP_FIXED
|
||||
.stub ape_stack_paddr,quad # ignored
|
||||
.stub ape_stack_filesz,quad # ignored
|
||||
.stub ape_stack_memsz,quad # is mmap(size) argument
|
||||
.stub ape_stack_align,quad # must be 16+
|
||||
|
||||
#if SupportsOpenbsd() || SupportsNetbsd()
|
||||
.long PT_NOTE
|
||||
.long PF_R
|
||||
|
|
|
@ -177,6 +177,8 @@
|
|||
#include "ape/macros.internal.h"
|
||||
#include "ape/relocations.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/def.h"
|
||||
#include "libc/elf/pf2prot.internal.h"
|
||||
#include "libc/nt/pedef.internal.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_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_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000 - STACKSIZE);
|
||||
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
|
||||
|
|
|
@ -36,7 +36,7 @@ int main(int argc, char *argv[]) {
|
|||
fprintf(stderr, "This echos stdio until Ctrl+C is pressed.\n");
|
||||
CHECK_NE(-1, sigaction(SIGINT, &saint, NULL));
|
||||
for (;;) {
|
||||
rc = read(0, buf, BUFSIZ);
|
||||
rc = read(0, buf, 512);
|
||||
if (rc != -1) {
|
||||
got = rc;
|
||||
} else {
|
||||
|
|
|
@ -55,8 +55,8 @@ int fgethex(FILE *f) {
|
|||
}
|
||||
|
||||
int main(int argc, char *argv[argc]) {
|
||||
int err;
|
||||
unsigned c, i, j, l;
|
||||
enum XedError err;
|
||||
struct XedDecodedInst xedd;
|
||||
unsigned char buf[XED_MAX_INSTRUCTION_BYTES];
|
||||
memset(buf, 0, sizeof(buf));
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/errors.h"
|
||||
#include "libc/nt/files.h"
|
||||
|
@ -27,7 +28,7 @@
|
|||
|
||||
textwindows int sys_chdir_nt(const char *path) {
|
||||
uint32_t n;
|
||||
int e, ms, len;
|
||||
int e, ms, err, len;
|
||||
char16_t path16[PATH_MAX], var[4];
|
||||
if ((len = __mkntpath(path, path16)) == -1) return -1;
|
||||
if (len && path16[len - 1] != u'\\') {
|
||||
|
@ -39,7 +40,7 @@ textwindows int sys_chdir_nt(const char *path) {
|
|||
* chdir() seems flaky on windows 7
|
||||
* in a similar way to rmdir() sigh
|
||||
*/
|
||||
for (ms = 1;; ms *= 2) {
|
||||
for (err = errno, ms = 1;; ms *= 2) {
|
||||
if (SetCurrentDirectory(path16)) {
|
||||
/*
|
||||
* Now we need to set a magic environment variable.
|
||||
|
@ -68,12 +69,12 @@ textwindows int sys_chdir_nt(const char *path) {
|
|||
if (ms <= 512 &&
|
||||
(e == kNtErrorFileNotFound || e == kNtErrorAccessDenied)) {
|
||||
Sleep(ms);
|
||||
errno = err;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
|
@ -23,39 +24,70 @@
|
|||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
textwindows noasan struct DirectMap sys_mmap_nt(void *addr, size_t size,
|
||||
int prot, int flags,
|
||||
int64_t handle, int64_t off) {
|
||||
int prot, int flags, int fd,
|
||||
int64_t off) {
|
||||
size_t i;
|
||||
bool iscow;
|
||||
int64_t handle;
|
||||
uint32_t oldprot;
|
||||
struct DirectMap dm;
|
||||
struct ProtectNt fl;
|
||||
const struct NtSecurityAttributes *sec;
|
||||
|
||||
if (fd != -1) {
|
||||
handle = g_fds.p[fd].handle;
|
||||
} else {
|
||||
handle = kNtInvalidHandleValue;
|
||||
}
|
||||
|
||||
if (flags & MAP_PRIVATE) {
|
||||
sec = 0; // MAP_PRIVATE isn't inherited across fork()
|
||||
} else {
|
||||
sec = &kNtIsInheritable; // MAP_SHARED gives us zero-copy fork()
|
||||
}
|
||||
|
||||
if ((prot & PROT_WRITE) && (flags & MAP_PRIVATE) && handle != -1) {
|
||||
// windows has cow pages but they can't propagate across fork()
|
||||
if (prot & PROT_EXEC) {
|
||||
// nt will whine under many circumstances if we change the execute bit
|
||||
// later using mprotect(). the workaround is to always request execute
|
||||
// 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,
|
||||
kNtFileMapCopy | kNtFileMapExecute};
|
||||
iscow = true;
|
||||
} 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 {
|
||||
fl = __nt2prot(prot);
|
||||
assert(flags & MAP_ANONYMOUS);
|
||||
fl = (struct ProtectNt){kNtPageExecuteReadwrite,
|
||||
kNtFileMapWrite | kNtFileMapExecute};
|
||||
}
|
||||
|
||||
if ((dm.maphandle = CreateFileMapping(handle, sec, fl.flags1,
|
||||
(size + off) >> 32, (size + off), 0))) {
|
||||
if ((dm.addr = MapViewOfFileEx(dm.maphandle, fl.flags2, off >> 32, off,
|
||||
size, addr))) {
|
||||
return dm;
|
||||
if (VirtualProtect(addr, size, __prot2nt(prot, iscow), &oldprot)) {
|
||||
return dm;
|
||||
} else {
|
||||
return dm;
|
||||
UnmapViewOfFile(dm.addr);
|
||||
}
|
||||
}
|
||||
CloseHandle(dm.maphandle);
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/runtime/directmap.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,
|
||||
int fd, int64_t off) {
|
||||
/* asan runtime depends on this function */
|
||||
char mode[8];
|
||||
struct DirectMap d;
|
||||
if (!IsWindows() && !IsMetal()) {
|
||||
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()) {
|
||||
d = sys_mmap_metal(addr, size, prot, flags, fd, off);
|
||||
} else {
|
||||
d = sys_mmap_nt(addr, size, prot, flags,
|
||||
fd != -1 ? g_fds.p[fd].handle : kNtInvalidHandleValue, off);
|
||||
d = sys_mmap_nt(addr, size, prot, flags, fd, off);
|
||||
}
|
||||
STRACE("sys_mmap(%.12p%s, %'zu, %s, %d, %'ld) → {%.12p, %p}% m", addr,
|
||||
DescribeFrame((intptr_t)addr >> 16), size,
|
||||
DescribeMapping(prot, flags, mode), fd, off, d.addr, d.maphandle);
|
||||
STRACE("sys_mmap(%.12p%s, %'zu, %s, %s, %d, %'ld) → {%.12p, %p}% m", addr,
|
||||
DescribeFrame((intptr_t)addr >> 16), size, DescribeProtFlags(prot),
|
||||
DescribeMapFlags(flags), fd, off, d.addr, d.maphandle);
|
||||
return d;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "libc/calls/struct/metastat.internal.h"
|
||||
#include "libc/calls/struct/rusage.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/sigval.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;
|
||||
void __stat2cosmo(struct stat *restrict, const union metastat *) 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;
|
||||
int gethostname_linux(char *, size_t) hidden;
|
||||
int gethostname_bsd(char *, size_t) hidden;
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
/**
|
||||
* Changes process group for process.
|
||||
* @vforksafe
|
||||
*/
|
||||
int setpgid(int pid, int pgid) {
|
||||
int rc, me;
|
||||
|
|
|
@ -100,7 +100,7 @@ static textwindows bool __sig_deliver(bool restartable, int sig, int si_code,
|
|||
cthread_spinlock(&__sig_lock);
|
||||
rva = __sighandrvas[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
|
||||
// example, if a sigsegv handler segfaults, then we'd want the
|
||||
// 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
|
||||
((sigaction_f)(_base + rva))(sig, infop, ctx);
|
||||
|
||||
// leave the signal
|
||||
cthread_spinlock(&__sig_lock);
|
||||
if (~flags & SA_NODEFER) {
|
||||
if ((~flags & SA_NODEFER) && (~flags & SA_RESETHAND)) {
|
||||
// it's now safe to reenter the signal so we need to restore it.
|
||||
// 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);
|
||||
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) {
|
||||
return true; // always send EINTR for wait4(), poll(), etc.
|
||||
|
|
|
@ -236,15 +236,64 @@ static int __sigaction(int sig, const struct sigaction *act,
|
|||
* .sa_flags = SA_RESETHAND|SA_RESTART|SA_SIGINFO};
|
||||
* CHECK_NE(-1, sigaction(SIGINT, &sa, NULL));
|
||||
*
|
||||
* Here's an example of the most professional way to handle signals.
|
||||
* 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 returned by i/o.
|
||||
* The following flags are supported across platforms:
|
||||
*
|
||||
* - `SA_SIGINFO`: Causes the `siginfo_t` and `ucontext_t` parameters to
|
||||
* 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;
|
||||
*
|
||||
* void OnCtrlC(int sig) {
|
||||
* gotctrlc = true;
|
||||
* }
|
||||
*
|
||||
* int main() {
|
||||
* size_t got;
|
||||
* 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
|
||||
* 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
|
||||
* @see xsigaction() for a much better api
|
||||
|
|
|
@ -19,83 +19,101 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/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/ucontext-freebsd.internal.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/repstosb.h"
|
||||
#include "libc/macros.internal.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) {
|
||||
int rva;
|
||||
ucontext_t uc;
|
||||
int rva, flags;
|
||||
struct Goodies {
|
||||
ucontext_t uc;
|
||||
siginfo_t si;
|
||||
} g;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
bzero(&uc, sizeof(uc));
|
||||
if (ctx) {
|
||||
uc.uc_mcontext.fpregs = &uc.__fpustate;
|
||||
uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
|
||||
uc.uc_stack.ss_size = ctx->uc_stack.ss_size;
|
||||
uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags;
|
||||
uc.uc_flags = ctx->uc_flags;
|
||||
memcpy(&uc.uc_sigmask, &ctx->uc_sigmask,
|
||||
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
|
||||
uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8;
|
||||
uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9;
|
||||
uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10;
|
||||
uc.uc_mcontext.r11 = ctx->uc_mcontext.mc_r11;
|
||||
uc.uc_mcontext.r12 = ctx->uc_mcontext.mc_r12;
|
||||
uc.uc_mcontext.r13 = ctx->uc_mcontext.mc_r13;
|
||||
uc.uc_mcontext.r14 = ctx->uc_mcontext.mc_r14;
|
||||
uc.uc_mcontext.r15 = ctx->uc_mcontext.mc_r15;
|
||||
uc.uc_mcontext.rdi = ctx->uc_mcontext.mc_rdi;
|
||||
uc.uc_mcontext.rsi = ctx->uc_mcontext.mc_rsi;
|
||||
uc.uc_mcontext.rbp = ctx->uc_mcontext.mc_rbp;
|
||||
uc.uc_mcontext.rbx = ctx->uc_mcontext.mc_rbx;
|
||||
uc.uc_mcontext.rdx = ctx->uc_mcontext.mc_rdx;
|
||||
uc.uc_mcontext.rax = ctx->uc_mcontext.mc_rax;
|
||||
uc.uc_mcontext.rcx = ctx->uc_mcontext.mc_rcx;
|
||||
uc.uc_mcontext.rsp = ctx->uc_mcontext.mc_rsp;
|
||||
uc.uc_mcontext.rip = ctx->uc_mcontext.mc_rip;
|
||||
uc.uc_mcontext.eflags = ctx->uc_mcontext.mc_flags;
|
||||
uc.uc_mcontext.fs = ctx->uc_mcontext.mc_fs;
|
||||
uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs;
|
||||
uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
|
||||
uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
|
||||
memcpy(&uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
|
||||
}
|
||||
((sigaction_f)(_base + rva))(sig, (void *)si, &uc);
|
||||
if (ctx) {
|
||||
ctx->uc_stack.ss_sp = uc.uc_stack.ss_sp;
|
||||
ctx->uc_stack.ss_size = uc.uc_stack.ss_size;
|
||||
ctx->uc_stack.ss_flags = uc.uc_stack.ss_flags;
|
||||
ctx->uc_flags = uc.uc_flags;
|
||||
memcpy(&ctx->uc_sigmask, &uc.uc_sigmask,
|
||||
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
|
||||
ctx->uc_mcontext.mc_rdi = uc.uc_mcontext.rdi;
|
||||
ctx->uc_mcontext.mc_rsi = uc.uc_mcontext.rsi;
|
||||
ctx->uc_mcontext.mc_rdx = uc.uc_mcontext.rdx;
|
||||
ctx->uc_mcontext.mc_rcx = uc.uc_mcontext.rcx;
|
||||
ctx->uc_mcontext.mc_r8 = uc.uc_mcontext.r8;
|
||||
ctx->uc_mcontext.mc_r9 = uc.uc_mcontext.r9;
|
||||
ctx->uc_mcontext.mc_rax = uc.uc_mcontext.rax;
|
||||
ctx->uc_mcontext.mc_rbx = uc.uc_mcontext.rbx;
|
||||
ctx->uc_mcontext.mc_rbp = uc.uc_mcontext.rbp;
|
||||
ctx->uc_mcontext.mc_r10 = uc.uc_mcontext.r10;
|
||||
ctx->uc_mcontext.mc_r11 = uc.uc_mcontext.r11;
|
||||
ctx->uc_mcontext.mc_r12 = uc.uc_mcontext.r12;
|
||||
ctx->uc_mcontext.mc_r13 = uc.uc_mcontext.r13;
|
||||
ctx->uc_mcontext.mc_r14 = uc.uc_mcontext.r14;
|
||||
ctx->uc_mcontext.mc_r15 = uc.uc_mcontext.r15;
|
||||
ctx->uc_mcontext.mc_trapno = uc.uc_mcontext.trapno;
|
||||
ctx->uc_mcontext.mc_fs = uc.uc_mcontext.fs;
|
||||
ctx->uc_mcontext.mc_gs = uc.uc_mcontext.gs;
|
||||
ctx->uc_mcontext.mc_flags = uc.uc_mcontext.eflags;
|
||||
ctx->uc_mcontext.mc_err = uc.uc_mcontext.err;
|
||||
ctx->uc_mcontext.mc_rip = uc.uc_mcontext.rip;
|
||||
ctx->uc_mcontext.mc_rsp = uc.uc_mcontext.rsp;
|
||||
memcpy(&ctx->uc_mcontext.mc_fpstate, &uc.__fpustate, 512);
|
||||
flags = __sighandflags[sig & (NSIG - 1)];
|
||||
if (~flags & SA_SIGINFO) {
|
||||
((sigaction_f)(_base + rva))(sig, 0, 0);
|
||||
} else {
|
||||
repstosb(&g, 0, sizeof(g));
|
||||
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
|
||||
g.uc.uc_stack.ss_sp = ctx->uc_stack.ss_sp;
|
||||
g.uc.uc_stack.ss_size = ctx->uc_stack.ss_size;
|
||||
g.uc.uc_stack.ss_flags = ctx->uc_stack.ss_flags;
|
||||
g.uc.uc_flags = ctx->uc_flags;
|
||||
memcpy(&g.uc.uc_sigmask, &ctx->uc_sigmask,
|
||||
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
|
||||
g.uc.uc_mcontext.r8 = ctx->uc_mcontext.mc_r8;
|
||||
g.uc.uc_mcontext.r9 = ctx->uc_mcontext.mc_r9;
|
||||
g.uc.uc_mcontext.r10 = ctx->uc_mcontext.mc_r10;
|
||||
g.uc.uc_mcontext.r11 = ctx->uc_mcontext.mc_r11;
|
||||
g.uc.uc_mcontext.r12 = ctx->uc_mcontext.mc_r12;
|
||||
g.uc.uc_mcontext.r13 = ctx->uc_mcontext.mc_r13;
|
||||
g.uc.uc_mcontext.r14 = ctx->uc_mcontext.mc_r14;
|
||||
g.uc.uc_mcontext.r15 = ctx->uc_mcontext.mc_r15;
|
||||
g.uc.uc_mcontext.rdi = ctx->uc_mcontext.mc_rdi;
|
||||
g.uc.uc_mcontext.rsi = ctx->uc_mcontext.mc_rsi;
|
||||
g.uc.uc_mcontext.rbp = ctx->uc_mcontext.mc_rbp;
|
||||
g.uc.uc_mcontext.rbx = ctx->uc_mcontext.mc_rbx;
|
||||
g.uc.uc_mcontext.rdx = ctx->uc_mcontext.mc_rdx;
|
||||
g.uc.uc_mcontext.rax = ctx->uc_mcontext.mc_rax;
|
||||
g.uc.uc_mcontext.rcx = ctx->uc_mcontext.mc_rcx;
|
||||
g.uc.uc_mcontext.rsp = ctx->uc_mcontext.mc_rsp;
|
||||
g.uc.uc_mcontext.rip = ctx->uc_mcontext.mc_rip;
|
||||
g.uc.uc_mcontext.eflags = ctx->uc_mcontext.mc_flags;
|
||||
g.uc.uc_mcontext.fs = ctx->uc_mcontext.mc_fs;
|
||||
g.uc.uc_mcontext.gs = ctx->uc_mcontext.mc_gs;
|
||||
g.uc.uc_mcontext.err = ctx->uc_mcontext.mc_err;
|
||||
g.uc.uc_mcontext.trapno = ctx->uc_mcontext.mc_trapno;
|
||||
memcpy(&g.uc.__fpustate, &ctx->uc_mcontext.mc_fpstate, 512);
|
||||
g.si.si_signo = freebsdinfo->si_signo;
|
||||
g.si.si_errno = freebsdinfo->si_errno;
|
||||
g.si.si_code = freebsdinfo->si_code;
|
||||
if (freebsdinfo->si_pid) {
|
||||
g.si.si_pid = freebsdinfo->si_pid;
|
||||
g.si.si_uid = freebsdinfo->si_uid;
|
||||
} else {
|
||||
g.si.si_addr = (void *)freebsdinfo->si_addr;
|
||||
}
|
||||
g.si.si_value = freebsdinfo->si_value;
|
||||
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
|
||||
ctx->uc_stack.ss_sp = g.uc.uc_stack.ss_sp;
|
||||
ctx->uc_stack.ss_size = g.uc.uc_stack.ss_size;
|
||||
ctx->uc_stack.ss_flags = g.uc.uc_stack.ss_flags;
|
||||
ctx->uc_flags = g.uc.uc_flags;
|
||||
memcpy(&ctx->uc_sigmask, &g.uc.uc_sigmask,
|
||||
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->uc_sigmask)));
|
||||
ctx->uc_mcontext.mc_rdi = g.uc.uc_mcontext.rdi;
|
||||
ctx->uc_mcontext.mc_rsi = g.uc.uc_mcontext.rsi;
|
||||
ctx->uc_mcontext.mc_rdx = g.uc.uc_mcontext.rdx;
|
||||
ctx->uc_mcontext.mc_rcx = g.uc.uc_mcontext.rcx;
|
||||
ctx->uc_mcontext.mc_r8 = g.uc.uc_mcontext.r8;
|
||||
ctx->uc_mcontext.mc_r9 = g.uc.uc_mcontext.r9;
|
||||
ctx->uc_mcontext.mc_rax = g.uc.uc_mcontext.rax;
|
||||
ctx->uc_mcontext.mc_rbx = g.uc.uc_mcontext.rbx;
|
||||
ctx->uc_mcontext.mc_rbp = g.uc.uc_mcontext.rbp;
|
||||
ctx->uc_mcontext.mc_r10 = g.uc.uc_mcontext.r10;
|
||||
ctx->uc_mcontext.mc_r11 = g.uc.uc_mcontext.r11;
|
||||
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);
|
||||
}
|
||||
}
|
||||
/*
|
||||
|
|
|
@ -19,11 +19,13 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/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/typedef/sigaction_f.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
||||
#define RDI 0
|
||||
#define RSI 1
|
||||
|
@ -57,50 +59,6 @@ union sigval_netbsd {
|
|||
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 {
|
||||
uint32_t __bits[4];
|
||||
};
|
||||
|
@ -127,19 +85,23 @@ struct ucontext_netbsd {
|
|||
|
||||
void __sigenter_netbsd(int sig, struct siginfo_netbsd *si,
|
||||
struct ucontext_netbsd *ctx) {
|
||||
int rva;
|
||||
int rva, flags;
|
||||
ucontext_t uc;
|
||||
struct siginfo si2;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
bzero(&uc, sizeof(uc));
|
||||
bzero(&si2, sizeof(si2));
|
||||
if (si) {
|
||||
si2.si_signo = si->_signo;
|
||||
si2.si_code = si->_code;
|
||||
si2.si_errno = si->_errno;
|
||||
}
|
||||
if (ctx) {
|
||||
flags = __sighandflags[sig & (NSIG - 1)];
|
||||
if (~flags & SA_SIGINFO) {
|
||||
((sigaction_f)(_base + rva))(sig, 0, 0);
|
||||
} else {
|
||||
bzero(&uc, sizeof(uc));
|
||||
bzero(&si2, sizeof(si2));
|
||||
si2.si_signo = si->si_signo;
|
||||
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_flags = ctx->uc_flags;
|
||||
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.rsp = ctx->uc_mcontext.__gregs[RSP];
|
||||
*uc.uc_mcontext.fpregs = ctx->uc_mcontext.__fpregs;
|
||||
}
|
||||
((sigaction_f)(_base + rva))(sig, &si2, &uc);
|
||||
if (ctx) {
|
||||
((sigaction_f)(_base + rva))(sig, &si2, &uc);
|
||||
ctx->uc_mcontext.__gregs[RDI] = uc.uc_mcontext.rdi;
|
||||
ctx->uc_mcontext.__gregs[RSI] = uc.uc_mcontext.rsi;
|
||||
ctx->uc_mcontext.__gregs[RDX] = uc.uc_mcontext.rdx;
|
||||
|
|
|
@ -19,145 +19,91 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/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/ucontext-openbsd.internal.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/intrin/repstosb.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
||||
union sigval_openbsd {
|
||||
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,
|
||||
void __sigenter_openbsd(int sig, struct siginfo_openbsd *openbsdinfo,
|
||||
struct ucontext_openbsd *ctx) {
|
||||
int rva;
|
||||
ucontext_t uc;
|
||||
struct siginfo si2;
|
||||
int rva, flags;
|
||||
struct Goodies {
|
||||
ucontext_t uc;
|
||||
struct siginfo si;
|
||||
} g;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
bzero(&uc, sizeof(uc));
|
||||
bzero(&si2, sizeof(si2));
|
||||
if (si) {
|
||||
si2.si_signo = si->si_signo;
|
||||
si2.si_code = si->si_code;
|
||||
si2.si_errno = si->si_errno;
|
||||
}
|
||||
if (ctx) {
|
||||
uc.uc_mcontext.fpregs = &uc.__fpustate;
|
||||
memcpy(&uc.uc_sigmask, &ctx->sc_mask,
|
||||
MIN(sizeof(uc.uc_sigmask), sizeof(ctx->sc_mask)));
|
||||
uc.uc_mcontext.rdi = ctx->sc_rdi;
|
||||
uc.uc_mcontext.rsi = ctx->sc_rsi;
|
||||
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;
|
||||
flags = __sighandflags[sig & (NSIG - 1)];
|
||||
if (~flags & SA_SIGINFO) {
|
||||
((sigaction_f)(_base + rva))(sig, 0, 0);
|
||||
} else {
|
||||
repstosb(&g, 0, sizeof(g));
|
||||
g.si.si_signo = openbsdinfo->si_signo;
|
||||
g.si.si_code = openbsdinfo->si_code;
|
||||
g.si.si_errno = openbsdinfo->si_errno;
|
||||
if (openbsdinfo->si_pid) {
|
||||
g.si.si_pid = openbsdinfo->si_pid;
|
||||
g.si.si_uid = openbsdinfo->si_uid;
|
||||
} else {
|
||||
g.si.si_addr = (void *)openbsdinfo->si_addr;
|
||||
}
|
||||
}
|
||||
((sigaction_f)(_base + rva))(sig, &si2, &uc);
|
||||
if (ctx) {
|
||||
ctx->sc_rdi = uc.uc_mcontext.rdi;
|
||||
ctx->sc_rsi = uc.uc_mcontext.rsi;
|
||||
ctx->sc_rdx = uc.uc_mcontext.rdx;
|
||||
ctx->sc_rcx = uc.uc_mcontext.rcx;
|
||||
ctx->sc_r8 = uc.uc_mcontext.r8;
|
||||
ctx->sc_r9 = uc.uc_mcontext.r9;
|
||||
ctx->sc_rax = uc.uc_mcontext.rax;
|
||||
ctx->sc_rbx = uc.uc_mcontext.rbx;
|
||||
ctx->sc_rbp = uc.uc_mcontext.rbp;
|
||||
ctx->sc_r10 = uc.uc_mcontext.r10;
|
||||
ctx->sc_r11 = uc.uc_mcontext.r11;
|
||||
ctx->sc_r12 = uc.uc_mcontext.r12;
|
||||
ctx->sc_r13 = uc.uc_mcontext.r13;
|
||||
ctx->sc_r14 = uc.uc_mcontext.r14;
|
||||
ctx->sc_r15 = uc.uc_mcontext.r15;
|
||||
ctx->sc_trapno = uc.uc_mcontext.trapno;
|
||||
ctx->sc_fs = uc.uc_mcontext.fs;
|
||||
ctx->sc_gs = uc.uc_mcontext.gs;
|
||||
ctx->sc_err = uc.uc_mcontext.err;
|
||||
ctx->sc_rip = uc.uc_mcontext.rip;
|
||||
ctx->sc_rsp = uc.uc_mcontext.rsp;
|
||||
g.si.si_value = openbsdinfo->si_value;
|
||||
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
|
||||
memcpy(&g.uc.uc_sigmask, &ctx->sc_mask,
|
||||
MIN(sizeof(g.uc.uc_sigmask), sizeof(ctx->sc_mask)));
|
||||
g.uc.uc_mcontext.rdi = ctx->sc_rdi;
|
||||
g.uc.uc_mcontext.rsi = ctx->sc_rsi;
|
||||
g.uc.uc_mcontext.rdx = ctx->sc_rdx;
|
||||
g.uc.uc_mcontext.rcx = ctx->sc_rcx;
|
||||
g.uc.uc_mcontext.r8 = ctx->sc_r8;
|
||||
g.uc.uc_mcontext.r9 = ctx->sc_r9;
|
||||
g.uc.uc_mcontext.rax = ctx->sc_rax;
|
||||
g.uc.uc_mcontext.rbx = ctx->sc_rbx;
|
||||
g.uc.uc_mcontext.rbp = ctx->sc_rbp;
|
||||
g.uc.uc_mcontext.r10 = ctx->sc_r10;
|
||||
g.uc.uc_mcontext.r11 = ctx->sc_r11;
|
||||
g.uc.uc_mcontext.r12 = ctx->sc_r12;
|
||||
g.uc.uc_mcontext.r13 = ctx->sc_r13;
|
||||
g.uc.uc_mcontext.r14 = ctx->sc_r14;
|
||||
g.uc.uc_mcontext.r15 = ctx->sc_r15;
|
||||
g.uc.uc_mcontext.trapno = ctx->sc_trapno;
|
||||
g.uc.uc_mcontext.fs = ctx->sc_fs;
|
||||
g.uc.uc_mcontext.gs = ctx->sc_gs;
|
||||
g.uc.uc_mcontext.err = ctx->sc_err;
|
||||
g.uc.uc_mcontext.rip = ctx->sc_rip;
|
||||
g.uc.uc_mcontext.rsp = ctx->sc_rsp;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/metasigaltstack.h"
|
||||
#include "libc/calls/struct/siginfo-xnu.internal.h"
|
||||
#include "libc/calls/struct/siginfo.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/repstosb.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
|
@ -30,24 +32,6 @@
|
|||
* @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 {
|
||||
char __mmst_reg[10];
|
||||
char __mmst_rsrv[6];
|
||||
|
@ -467,71 +451,76 @@ noasan static void linuxssefpustate2xnu(
|
|||
}
|
||||
|
||||
noasan void __sigenter_xnu(void *fn, int infostyle, int sig,
|
||||
struct __darwin_siginfo *xnuinfo,
|
||||
struct siginfo_xnu *xnuinfo,
|
||||
struct __darwin_ucontext *xnuctx) {
|
||||
int rva;
|
||||
intptr_t ax;
|
||||
int rva, flags;
|
||||
struct Goodies {
|
||||
ucontext_t uc;
|
||||
siginfo_t si;
|
||||
} g;
|
||||
rva = __sighandrvas[sig & (NSIG - 1)];
|
||||
if (rva >= kSigactionMinRva) {
|
||||
repstosb(&g, 0, sizeof(g));
|
||||
if (xnuctx) {
|
||||
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
|
||||
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
|
||||
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
|
||||
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
|
||||
g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size;
|
||||
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
|
||||
if (xnuctx->uc_mcontext) {
|
||||
if (xnuctx->uc_mcsize >=
|
||||
sizeof(struct __darwin_x86_exception_state64)) {
|
||||
xnuexceptionstate2linux(&g.uc.uc_mcontext,
|
||||
&xnuctx->uc_mcontext->__es);
|
||||
}
|
||||
if (xnuctx->uc_mcsize >=
|
||||
(sizeof(struct __darwin_x86_exception_state64) +
|
||||
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);
|
||||
flags = __sighandflags[sig & (NSIG - 1)];
|
||||
if (~flags & SA_SIGINFO) {
|
||||
((sigaction_f)(_base + rva))(sig, 0, 0);
|
||||
} else {
|
||||
repstosb(&g, 0, sizeof(g));
|
||||
if (xnuctx) {
|
||||
g.uc.uc_flags = xnuctx->uc_onstack ? SA_ONSTACK : 0;
|
||||
g.uc.uc_sigmask.__bits[0] = xnuctx->uc_sigmask;
|
||||
g.uc.uc_stack.ss_sp = xnuctx->uc_stack.ss_sp;
|
||||
g.uc.uc_stack.ss_flags = xnuctx->uc_stack.ss_flags;
|
||||
g.uc.uc_stack.ss_size = xnuctx->uc_stack.ss_size;
|
||||
g.uc.uc_mcontext.fpregs = &g.uc.__fpustate;
|
||||
if (xnuctx->uc_mcontext) {
|
||||
if (xnuctx->uc_mcsize >=
|
||||
sizeof(struct __darwin_x86_exception_state64)) {
|
||||
xnuexceptionstate2linux(&g.uc.uc_mcontext,
|
||||
&xnuctx->uc_mcontext->__es);
|
||||
}
|
||||
if (xnuctx->uc_mcsize >=
|
||||
(sizeof(struct __darwin_x86_exception_state64) +
|
||||
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) {
|
||||
g.si.si_signo = xnuinfo->si_signo;
|
||||
g.si.si_errno = xnuinfo->si_errno;
|
||||
g.si.si_code = xnuinfo->si_code;
|
||||
if (xnuinfo->si_pid) {
|
||||
g.si.si_pid = xnuinfo->si_pid;
|
||||
g.si.si_uid = xnuinfo->si_uid;
|
||||
g.si.si_status = xnuinfo->si_status;
|
||||
} else {
|
||||
g.si.si_addr = (void *)xnuinfo->si_addr;
|
||||
if (xnuinfo) {
|
||||
g.si.si_signo = xnuinfo->si_signo;
|
||||
g.si.si_errno = xnuinfo->si_errno;
|
||||
g.si.si_code = xnuinfo->si_code;
|
||||
if (xnuinfo->si_pid) {
|
||||
g.si.si_pid = xnuinfo->si_pid;
|
||||
g.si.si_uid = xnuinfo->si_uid;
|
||||
} 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);
|
||||
if (xnuctx) {
|
||||
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_size = g.uc.uc_stack.ss_size;
|
||||
if (xnuctx->uc_mcontext) {
|
||||
if (xnuctx->uc_mcsize >=
|
||||
sizeof(struct __darwin_x86_exception_state64)) {
|
||||
linuxexceptionstate2xnu(&xnuctx->uc_mcontext->__es,
|
||||
&g.uc.uc_mcontext);
|
||||
}
|
||||
if (xnuctx->uc_mcsize >=
|
||||
(sizeof(struct __darwin_x86_exception_state64) +
|
||||
sizeof(struct __darwin_x86_thread_state64))) {
|
||||
linuxthreadstate2xnu(&xnuctx->uc_mcontext->__ss, &g.uc,
|
||||
&g.uc.uc_mcontext);
|
||||
}
|
||||
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
|
||||
linuxssefpustate2xnu(&xnuctx->uc_mcontext->__fs, &g.uc.__fpustate);
|
||||
((sigaction_f)(_base + rva))(sig, &g.si, &g.uc);
|
||||
if (xnuctx) {
|
||||
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_size = g.uc.uc_stack.ss_size;
|
||||
if (xnuctx->uc_mcontext) {
|
||||
if (xnuctx->uc_mcsize >=
|
||||
sizeof(struct __darwin_x86_exception_state64)) {
|
||||
linuxexceptionstate2xnu(&xnuctx->uc_mcontext->__es,
|
||||
&g.uc.uc_mcontext);
|
||||
}
|
||||
if (xnuctx->uc_mcsize >=
|
||||
(sizeof(struct __darwin_x86_exception_state64) +
|
||||
sizeof(struct __darwin_x86_thread_state64))) {
|
||||
linuxthreadstate2xnu(&xnuctx->uc_mcontext->__ss, &g.uc,
|
||||
&g.uc.uc_mcontext);
|
||||
}
|
||||
if (xnuctx->uc_mcsize >= sizeof(struct __darwin_mcontext64)) {
|
||||
linuxssefpustate2xnu(&xnuctx->uc_mcontext->__fs, &g.uc.__fpustate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
*
|
||||
* @return old signal handler on success or SIG_ERR w/ errno
|
||||
* @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) {
|
||||
struct sigaction old, sa = {.sa_handler = func, .sa_flags = SA_RESTART};
|
||||
|
|
39
libc/calls/struct/siginfo-freebsd.internal.h
Normal file
39
libc/calls/struct/siginfo-freebsd.internal.h
Normal 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_ */
|
53
libc/calls/struct/siginfo-netbsd.internal.h
Normal file
53
libc/calls/struct/siginfo-netbsd.internal.h
Normal 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_ */
|
36
libc/calls/struct/siginfo-openbsd.internal.h
Normal file
36
libc/calls/struct/siginfo-openbsd.internal.h
Normal 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_ */
|
22
libc/calls/struct/siginfo-xnu.internal.h
Normal file
22
libc/calls/struct/siginfo-xnu.internal.h
Normal 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_ */
|
|
@ -15,7 +15,7 @@ struct siginfo {
|
|||
uint32_t si_uid;
|
||||
};
|
||||
struct {
|
||||
int32_t si_timerid;
|
||||
int32_t si_timerid; /* SIGALRM */
|
||||
int32_t si_overrun;
|
||||
};
|
||||
};
|
||||
|
@ -23,7 +23,8 @@ struct siginfo {
|
|||
union sigval si_value; /* provided by third arg of sigqueue(2) */
|
||||
struct {
|
||||
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 {
|
||||
int64_t si_band;
|
||||
int64_t si_band; /* SIGPOLL */
|
||||
int32_t si_fd;
|
||||
};
|
||||
struct {
|
||||
|
|
|
@ -4,43 +4,6 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
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 {
|
||||
void *ss_sp;
|
||||
uint64_t ss_size;
|
||||
|
|
42
libc/calls/struct/ucontext-openbsd.internal.h
Normal file
42
libc/calls/struct/ucontext-openbsd.internal.h
Normal 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_ */
|
|
@ -96,7 +96,9 @@ static textwindows bool IsDirectorySymlink(const char16_t *path) {
|
|||
static textwindows int sys_rmdir_nt(const char16_t *path) {
|
||||
int e, ms;
|
||||
for (ms = 1;; ms *= 2) {
|
||||
if (RemoveDirectory(path)) return 0;
|
||||
if (RemoveDirectory(path)) {
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* Files can linger, for absolutely no reason.
|
||||
* 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.
|
||||
* Never could have imagined it'd be this bad.
|
||||
*/
|
||||
if ((e = GetLastError()) == kNtErrorDirNotEmpty && ms <= 512) {
|
||||
if (GetLastError() == kNtErrorDirNotEmpty && ms <= 2048) {
|
||||
Sleep(ms);
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -121,7 +122,7 @@ static textwindows int sys_unlink_nt(const char16_t *path) {
|
|||
} else if (DeleteFile(path)) {
|
||||
return 0;
|
||||
} else {
|
||||
return __winerr();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
7
libc/elf/pf2prot.internal.h
Normal file
7
libc/elf/pf2prot.internal.h
Normal 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_ */
|
|
@ -57,7 +57,7 @@ STATIC_YOINK("_init_asan");
|
|||
|
||||
#define ASAN_MORGUE_ITEMS 512
|
||||
#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.
|
||||
|
@ -177,7 +177,8 @@ static uint64_t __asan_roundup2pow(uint64_t x) {
|
|||
static char *__asan_utf8cpy(char *p, unsigned c) {
|
||||
uint64_t z;
|
||||
z = tpenc(c);
|
||||
do *p++ = z;
|
||||
do
|
||||
*p++ = z;
|
||||
while ((z >>= 8));
|
||||
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) {
|
||||
addr = bp->addr;
|
||||
if (addr == weakaddr("__gc") && weakaddr("__gc")) {
|
||||
do --gi;
|
||||
do
|
||||
--gi;
|
||||
while ((addr = garbage->p[gi].ret) == weakaddr("__gc"));
|
||||
}
|
||||
bt->p[i] = addr;
|
||||
|
@ -1307,7 +1309,8 @@ void __asan_map_shadow(uintptr_t p, size_t n) {
|
|||
if (sm.addr == MAP_FAILED ||
|
||||
weaken(TrackMemoryInterval)(
|
||||
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");
|
||||
__asan_die()();
|
||||
__asan_unreachable();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,49 +16,22 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/asmflag.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/nt/files.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"
|
||||
|
||||
extern typeof(DeleteFile) *const __imp_DeleteFileW __msabi;
|
||||
|
||||
/**
|
||||
* Modifies restrictions on virtual memory address range.
|
||||
*
|
||||
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
* Deletes existing file.
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
*/
|
||||
noasan noubsan privileged int mprotect(void *addr, size_t len, int prot) {
|
||||
bool cf;
|
||||
int64_t rc;
|
||||
uint32_t oldprot;
|
||||
char protbuf[4];
|
||||
if (!IsWindows()) {
|
||||
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;
|
||||
textwindows bool32 DeleteFile(const char16_t *lpPathName) {
|
||||
bool32 ok;
|
||||
ok = __imp_DeleteFileW(lpPathName);
|
||||
if (!ok) __winerr();
|
||||
STRACE("DeleteFile(%#hs) → %hhhd% m", lpPathName, ok);
|
||||
return ok;
|
||||
}
|
|
@ -25,7 +25,7 @@ const char *DescribeFlags(char *p, size_t n, struct DescribeFlags *d, size_t m,
|
|||
char b[21];
|
||||
size_t i, j, k;
|
||||
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;
|
||||
if (t) {
|
||||
if (i + 1 < n) p[i++] = '|';
|
||||
|
|
|
@ -10,6 +10,11 @@ struct thatispacked DescribeFlags {
|
|||
|
||||
const char *DescribeFlags(char *, size_t, struct DescribeFlags *, size_t,
|
||||
const char *, unsigned);
|
||||
|
||||
const char *DescribeMapFlags(int);
|
||||
const char *DescribeProtFlags(int);
|
||||
const char *DescribeRemapFlags(int);
|
||||
|
||||
const char *DescribeNtPageFlags(uint32_t);
|
||||
const char *DescribeNtFileMapFlags(uint32_t);
|
||||
const char *DescribeNtFileFlagsAndAttributes(uint32_t);
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,51 +16,29 @@
|
|||
│ 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/runtime/runtime.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/enum/consolemodeflags.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/consts/sa.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
|
||||
jmp_buf jb;
|
||||
bool gotsegv;
|
||||
struct sigaction old[2];
|
||||
|
||||
void OnSigSegv(int sig) {
|
||||
gotsegv = true;
|
||||
longjmp(jb, 1);
|
||||
}
|
||||
|
||||
void SetUp(void) {
|
||||
sigaction(SIGBUS, NULL, &old[0]);
|
||||
sigaction(SIGSEGV, NULL, &old[1]);
|
||||
}
|
||||
|
||||
void TearDown(void) {
|
||||
sigaction(SIGBUS, &old[0], NULL);
|
||||
sigaction(SIGSEGV, &old[1], NULL);
|
||||
}
|
||||
|
||||
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));
|
||||
const char *DescribeMapFlags(int x) {
|
||||
static char mapflags[256];
|
||||
const struct DescribeFlags kMapFlags[] = {
|
||||
{MAP_ANONYMOUS, "ANONYMOUS"}, //
|
||||
{MAP_PRIVATE, "PRIVATE"}, //
|
||||
{MAP_SHARED, "SHARED"}, //
|
||||
{MAP_FIXED, "FIXED"}, //
|
||||
{MAP_FIXED_NOREPLACE, "FIXED_NOREPLACE"}, //
|
||||
{MAP_GROWSDOWN, "GROWSDOWN"}, //
|
||||
{MAP_CONCEAL, "CONCEAL"}, //
|
||||
{MAP_HUGETLB, "HUGETLB"}, //
|
||||
{MAP_LOCKED, "LOCKED"}, //
|
||||
{MAP_NORESERVE, "NORESERVE"}, //
|
||||
{MAP_NONBLOCK, "NONBLOCK"}, //
|
||||
{MAP_POPULATE, "POPULATE"}, //
|
||||
{MAP_STACK, "STACK"}, // order matters
|
||||
};
|
||||
return DescribeFlags(mapflags, sizeof(mapflags), kMapFlags,
|
||||
ARRAYLEN(kMapFlags), "MAP_", x);
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
/*-*- 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 │
|
||||
│ 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 │
|
||||
|
@ -16,27 +16,18 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/nt/enum/filemapflags.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
privileged struct ProtectNt __nt2prot(int prot) {
|
||||
if (prot & PROT_WRITE) {
|
||||
if (prot & PROT_EXEC) {
|
||||
return (struct ProtectNt){kNtPageExecuteReadwrite,
|
||||
kNtFileMapWrite | kNtFileMapExecute};
|
||||
} else {
|
||||
return (struct ProtectNt){kNtPageReadwrite, kNtFileMapWrite};
|
||||
}
|
||||
} else if (prot & PROT_READ) {
|
||||
if (prot & PROT_EXEC) {
|
||||
return (struct ProtectNt){kNtPageExecuteRead,
|
||||
kNtFileMapRead | kNtFileMapExecute};
|
||||
} else {
|
||||
return (struct ProtectNt){kNtPageReadonly, kNtFileMapRead};
|
||||
}
|
||||
} else {
|
||||
return (struct ProtectNt){kNtPageNoaccess};
|
||||
}
|
||||
static const struct DescribeFlags kProtFlags[] = {
|
||||
{PROT_READ, "READ"}, //
|
||||
{PROT_WRITE, "WRITE"}, //
|
||||
{PROT_EXEC, "EXEC"}, //
|
||||
};
|
||||
|
||||
const char *DescribeProtFlags(int x) {
|
||||
static char protflags[64];
|
||||
return DescribeFlags(protflags, sizeof(protflags), kProtFlags,
|
||||
ARRAYLEN(kProtFlags), "PROT_", x);
|
||||
}
|
32
libc/intrin/describeremapflags.greg.c
Normal file
32
libc/intrin/describeremapflags.greg.c
Normal 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);
|
||||
}
|
|
@ -65,12 +65,14 @@ o/$(MODE)/libc/intrin/kprintf.greg.o: \
|
|||
$(NO_MAGIC)
|
||||
|
||||
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/closehandle.greg.o \
|
||||
o/$(MODE)/libc/intrin/openprocess.greg.o \
|
||||
o/$(MODE)/libc/intrin/createthread.greg.o \
|
||||
o/$(MODE)/libc/intrin/createprocess.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/unmapviewoffile.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/flushfilebuffers.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/setcurrentdirectory.greg.o \
|
||||
o/$(MODE)/libc/intrin/mapviewoffileexnuma.greg.o \
|
||||
o/$(MODE)/libc/intrin/createfilemappingnuma.greg.o \
|
||||
o/$(MODE)/libc/intrin/generateconsolectrlevent.greg.o \
|
||||
|
|
|
@ -438,7 +438,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
|
|||
i = 0;
|
||||
m = (1 << base) - 1;
|
||||
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));
|
||||
goto EmitNumber;
|
||||
|
||||
|
@ -487,8 +488,8 @@ privileged static size_t kformat(char *b, size_t n, const char *fmt, va_list va,
|
|||
goto EmitChar;
|
||||
|
||||
case 'm':
|
||||
if (!(x = errno) && sign == ' ' &&
|
||||
(!IsWindows() || !__imp_GetLastError())) {
|
||||
if (!(x = errno) && sign == ' ' /* && */
|
||||
/* (!IsWindows() || !__imp_GetLastError()) */) {
|
||||
break;
|
||||
} else if (weaken(strerror_r) &&
|
||||
!weaken(strerror_r)(x, z, sizeof(z))) {
|
||||
|
|
|
@ -18,20 +18,30 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/nt/enum/pageflags.h"
|
||||
#include "libc/runtime/directmap.internal.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)) {
|
||||
case PROT_READ:
|
||||
return kNtPageReadonly;
|
||||
case PROT_EXEC:
|
||||
case PROT_EXEC | PROT_READ:
|
||||
return kNtPageExecuteRead;
|
||||
case PROT_WRITE:
|
||||
case PROT_READ | PROT_WRITE:
|
||||
return kNtPageReadwrite;
|
||||
case PROT_READ | PROT_EXEC:
|
||||
return kNtPageExecuteRead;
|
||||
if (iscow) {
|
||||
return kNtPageWritecopy;
|
||||
} else {
|
||||
return kNtPageReadwrite;
|
||||
}
|
||||
case PROT_WRITE | PROT_EXEC:
|
||||
case PROT_READ | PROT_WRITE | PROT_EXEC:
|
||||
return kNtPageExecuteReadwrite;
|
||||
if (iscow) {
|
||||
return kNtPageExecuteWritecopy;
|
||||
} else {
|
||||
return kNtPageExecuteReadwrite;
|
||||
}
|
||||
default:
|
||||
return kNtPageNoaccess;
|
||||
}
|
||||
|
|
37
libc/intrin/removedirectory.greg.c
Normal file
37
libc/intrin/removedirectory.greg.c
Normal 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;
|
||||
}
|
37
libc/intrin/setcurrentdirectory.greg.c
Normal file
37
libc/intrin/setcurrentdirectory.greg.c
Normal 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;
|
||||
}
|
|
@ -19,6 +19,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/nt/memory.h"
|
||||
|
||||
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
|
||||
|
@ -27,13 +28,19 @@ extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
|
|||
* Protects memory on the New Technology.
|
||||
* @note this wrapper takes care of ABI, STRACE(), and __winerr()
|
||||
*/
|
||||
bool32 VirtualProtect(void *lpAddress, uint64_t dwSize, uint32_t flNewProtect,
|
||||
uint32_t *lpflOldProtect) {
|
||||
textwindows bool32 VirtualProtect(void *lpAddress, uint64_t dwSize,
|
||||
uint32_t flNewProtect,
|
||||
uint32_t *lpflOldProtect) {
|
||||
bool32 bOk;
|
||||
char oldbuf[64];
|
||||
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,
|
||||
DescribeNtPageFlags(flNewProtect),
|
||||
DescribeNtPageFlags(*lpflOldProtect), bOk);
|
||||
DescribeNtPageFlags(flNewProtect), oldbuf, bOk);
|
||||
return bOk;
|
||||
}
|
||||
|
|
|
@ -82,6 +82,8 @@ const char *GetSiCodeName(int sig, int si_code) {
|
|||
strcpy(b + 5, "MAPERR"); /* address not mapped to object */
|
||||
} else if (si_code == SEGV_ACCERR) {
|
||||
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) {
|
||||
strcpy(b, "FPE_???");
|
||||
|
@ -129,10 +131,12 @@ const char *GetSiCodeName(int sig, int si_code) {
|
|||
strcpy(b + 4, "ADRERR"); /* non-existent physical address */
|
||||
} else if (si_code == BUS_OBJERR) {
|
||||
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) {
|
||||
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) {
|
||||
strcpy(b + 4, "BUS_AO"); /* Linux 2.6.32+ */
|
||||
strcpy(b + 4, "MCEERR_AO"); /* Linux 2.6.32+ */
|
||||
}
|
||||
} else if (sig == SIGIO) {
|
||||
strcpy(b, "POLL_???");
|
||||
|
|
|
@ -78,7 +78,7 @@ noasan void CheckForMemoryLeaks(void) {
|
|||
exit(1);
|
||||
}
|
||||
__cxa_finalize(0);
|
||||
STRACE("checking for memory leaks");
|
||||
STRACE("checking for memory leaks% m");
|
||||
if (!IsAsan()) {
|
||||
/* TODO(jart): How can we make this work without ASAN? */
|
||||
return;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
.imp kernel32,__imp_DeleteFileW,DeleteFileW,0
|
||||
|
||||
.text.windows
|
||||
DeleteFile:
|
||||
__DeleteFile:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
|
@ -11,5 +11,5 @@ DeleteFile:
|
|||
call *__imp_DeleteFileW(%rip)
|
||||
leave
|
||||
ret
|
||||
.endfn DeleteFile,globl
|
||||
.endfn __DeleteFile,globl
|
||||
.previous
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
.imp kernel32,__imp_RemoveDirectoryW,RemoveDirectoryW,0
|
||||
|
||||
.text.windows
|
||||
RemoveDirectory:
|
||||
__RemoveDirectory:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
|
@ -11,5 +11,5 @@ RemoveDirectory:
|
|||
call *__imp_RemoveDirectoryW(%rip)
|
||||
leave
|
||||
ret
|
||||
.endfn RemoveDirectory,globl
|
||||
.endfn __RemoveDirectory,globl
|
||||
.previous
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
.imp kernel32,__imp_SetCurrentDirectoryW,SetCurrentDirectoryW,0
|
||||
|
||||
.text.windows
|
||||
SetCurrentDirectory:
|
||||
__SetCurrentDirectory:
|
||||
push %rbp
|
||||
mov %rsp,%rbp
|
||||
.profilable
|
||||
|
@ -11,5 +11,5 @@ SetCurrentDirectory:
|
|||
call *__imp_SetCurrentDirectoryW(%rip)
|
||||
leave
|
||||
ret
|
||||
.endfn SetCurrentDirectory,globl
|
||||
.endfn __SetCurrentDirectory,globl
|
||||
.previous
|
||||
|
|
|
@ -228,7 +228,6 @@ imp 'DeleteAtom' DeleteAtom kernel32 270
|
|||
imp 'DeleteBoundaryDescriptor' DeleteBoundaryDescriptor kernel32 0
|
||||
imp 'DeleteCriticalSection' DeleteCriticalSection kernel32 0 1
|
||||
imp 'DeleteFiber' DeleteFiber kernel32 0
|
||||
imp 'DeleteFile' DeleteFileW kernel32 0 1
|
||||
imp 'DeleteFileA' DeleteFileA kernel32 0 1
|
||||
imp 'DeleteFileTransacted' DeleteFileTransactedW kernel32 276
|
||||
imp 'DeleteFileTransactedA' DeleteFileTransactedA kernel32 275
|
||||
|
@ -1033,7 +1032,6 @@ imp 'ReleaseMutex' ReleaseMutex kernel32 0 1
|
|||
imp 'ReleaseSRWLockExclusive' ReleaseSRWLockExclusive kernel32 0 1
|
||||
imp 'ReleaseSRWLockShared' ReleaseSRWLockShared kernel32 0 1
|
||||
imp 'ReleaseSemaphore' ReleaseSemaphore kernel32 0 3
|
||||
imp 'RemoveDirectory' RemoveDirectoryW kernel32 0 1
|
||||
imp 'RemoveDirectoryA' RemoveDirectoryA kernel32 0 1
|
||||
imp 'RemoveDirectoryTransacted' RemoveDirectoryTransactedW kernel32 1206
|
||||
imp 'RemoveDirectoryTransactedA' RemoveDirectoryTransactedA kernel32 1205
|
||||
|
@ -1099,7 +1097,6 @@ imp 'SetConsoleTitleA' SetConsoleTitleA kernel32 0 1
|
|||
imp 'SetConsoleWindowInfo' SetConsoleWindowInfo kernel32 0 3
|
||||
imp 'SetCriticalSectionSpinCount' SetCriticalSectionSpinCount kernel32 0 2
|
||||
imp 'SetCurrentConsoleFontEx' SetCurrentConsoleFontEx kernel32 0
|
||||
imp 'SetCurrentDirectory' SetCurrentDirectoryW kernel32 0 1
|
||||
imp 'SetCurrentDirectoryA' SetCurrentDirectoryA kernel32 0 1
|
||||
imp 'SetDefaultCommConfig' SetDefaultCommConfigW kernel32 1298
|
||||
imp 'SetDefaultCommConfigA' SetDefaultCommConfigA kernel32 1297
|
||||
|
@ -1360,6 +1357,7 @@ imp '__CreateNamedPipe' CreateNamedPipeW kernel32 0 8
|
|||
imp '__CreatePipe' CreatePipe kernel32 0 4
|
||||
imp '__CreateProcess' CreateProcessW kernel32 0 10
|
||||
imp '__CreateThread' CreateThread kernel32 0 6
|
||||
imp '__DeleteFile' DeleteFileW kernel32 0 1
|
||||
imp '__DeviceIoControl' DeviceIoControl kernel32 0 8
|
||||
imp '__FlushFileBuffers' FlushFileBuffers kernel32 0 1
|
||||
imp '__FlushViewOfFile' FlushViewOfFile kernel32 0 2
|
||||
|
@ -1368,6 +1366,8 @@ imp '__GetFileAttributes' GetFileAttributesW kernel32 0 1
|
|||
imp '__MapViewOfFileEx' MapViewOfFileEx kernel32 0 6
|
||||
imp '__MapViewOfFileExNuma' MapViewOfFileExNuma kernel32 0 7
|
||||
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 '__UnmapViewOfFile' UnmapViewOfFile kernel32 0 1
|
||||
imp '__VirtualProtect' VirtualProtect kernel32 0 4
|
||||
|
|
|
@ -14,11 +14,10 @@ struct DirectMap {
|
|||
};
|
||||
|
||||
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);
|
||||
int sys_munmap_metal(void *, size_t);
|
||||
uint32_t __prot2nt(int, int);
|
||||
struct ProtectNt __nt2prot(int);
|
||||
uint32_t __prot2nt(int, bool);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -106,7 +106,6 @@ textwindows void WinMainForked(void) {
|
|||
struct DirectMap dm;
|
||||
uint64_t size, upsize;
|
||||
int64_t reader, writer;
|
||||
uint32_t flags1, flags2;
|
||||
struct MemoryInterval *maps;
|
||||
char16_t fvar[21 + 1 + 21 + 1];
|
||||
int64_t oncrash, savetsc, savebir;
|
||||
|
@ -163,24 +162,21 @@ textwindows void WinMainForked(void) {
|
|||
size = maps[i].size;
|
||||
if (maps[i].flags & MAP_PRIVATE) {
|
||||
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
|
||||
// doesn't mark it inheritable across fork() for MAP_PRIVATE
|
||||
if (!(maps[i].h =
|
||||
CreateFileMapping(-1, 0, flags1, upsize >> 32, upsize, 0)) ||
|
||||
!MapViewOfFileEx(maps[i].h, flags2, 0, 0, upsize, addr) ||
|
||||
if (!(maps[i].h = CreateFileMapping(-1, 0, kNtPageExecuteReadwrite,
|
||||
upsize >> 32, upsize, 0)) ||
|
||||
!MapViewOfFileEx(maps[i].h, kNtFileMapWrite | kNtFileMapExecute, 0, 0,
|
||||
upsize, addr) ||
|
||||
!ReadAll(reader, addr, size)) {
|
||||
ExitProcess(44);
|
||||
}
|
||||
} else {
|
||||
// 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)) {
|
||||
ExitProcess(45);
|
||||
}
|
||||
|
@ -203,11 +199,8 @@ textwindows void WinMainForked(void) {
|
|||
_mmi.p = maps;
|
||||
_mmi.n = specialz / sizeof(_mmi.p[0]);
|
||||
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),
|
||||
ROUNDUP(maps[i].size, FRAMESIZE),
|
||||
__nt2prot(maps[i].prot).flags1, &oldprot);
|
||||
}
|
||||
VirtualProtect((void *)((uint64_t)maps[i].x << 16), maps[i].size,
|
||||
__prot2nt(maps[i].prot, maps[i].iscow), &oldprot);
|
||||
}
|
||||
|
||||
// we're all done reading!
|
||||
|
@ -263,8 +256,7 @@ textwindows int sys_fork_nt(void) {
|
|||
}
|
||||
#endif
|
||||
if (ntspawn(GetProgramExecutableName(), args, environ, forkvar,
|
||||
&kNtIsInheritable, NULL, true,
|
||||
0 /* kNtCreateNewProcessGroup */, NULL, &startinfo,
|
||||
&kNtIsInheritable, NULL, true, 0, NULL, &startinfo,
|
||||
&procinfo) != -1) {
|
||||
CloseHandle(reader);
|
||||
CloseHandle(procinfo.hThread);
|
||||
|
|
|
@ -31,7 +31,7 @@ _jmpstack:
|
|||
mov %rcx,%rsi
|
||||
mov %r8,%rdx
|
||||
mov %r9,%rcx
|
||||
xor %rbp,%rbp
|
||||
xor %ebp,%ebp
|
||||
call *%rax
|
||||
ud2
|
||||
.unreachable
|
||||
.endfn _jmpstack,globl,hidden
|
||||
|
|
|
@ -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,
|
||||
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 */
|
||||
unsigned i;
|
||||
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].offset = offset;
|
||||
mm->p[i].size = size;
|
||||
mm->p[i].iscow = iscow;
|
||||
mm->p[i].readonlyfile = readonlyfile;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ struct MemoryInterval {
|
|||
int flags;
|
||||
long offset;
|
||||
long size;
|
||||
bool iscow;
|
||||
bool readonlyfile;
|
||||
};
|
||||
|
||||
struct MemoryIntervals {
|
||||
|
@ -50,12 +52,11 @@ extern hidden struct MemoryIntervals _mmi;
|
|||
|
||||
const char *DescribeFrame(int);
|
||||
void PrintSystemMappings(int) hidden;
|
||||
char *DescribeProt(int, char[hasatleast 4]);
|
||||
char *DescribeMapping(int, int, char[hasatleast 8]) hidden;
|
||||
bool AreMemoryIntervalsOk(const struct MemoryIntervals *) nosideeffect hidden;
|
||||
void PrintMemoryIntervals(int, const struct MemoryIntervals *) hidden;
|
||||
int TrackMemoryInterval(struct MemoryIntervals *, int, int, long, int, int,
|
||||
long, long) hidden;
|
||||
bool, bool, long, long) hidden;
|
||||
int ReleaseMemoryIntervals(struct MemoryIntervals *, int, int,
|
||||
void (*)(struct MemoryIntervals *, int, int)) hidden;
|
||||
void ReleaseMemoryNt(struct MemoryIntervals *, int, int) hidden;
|
||||
|
|
|
@ -25,16 +25,19 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/log/backtrace.internal.h"
|
||||
#include "libc/log/libfatal.internal.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/rand/rand.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
|
@ -45,9 +48,14 @@
|
|||
#define SHADE(x) (((intptr_t)(x) >> 3) + 0x7fff8000)
|
||||
#define FRAME(x) ((int)((intptr_t)(x) >> 16))
|
||||
|
||||
forceinline wontreturn void Die(void) {
|
||||
if (weaken(__die)) weaken(__die)();
|
||||
abort();
|
||||
static wontreturn void OnUnrecoverableMmapError(const char *s) {
|
||||
if (IsTiny()) {
|
||||
unreachable;
|
||||
} else {
|
||||
STRACE("%s %m", s);
|
||||
__restorewintty();
|
||||
_Exit(199);
|
||||
}
|
||||
}
|
||||
|
||||
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))) {
|
||||
return true;
|
||||
} else {
|
||||
STRACE("mmap(%.12p, %p) ENOMEM (automap interval exhausted)", ADDR(*res),
|
||||
ADDR(n + 1));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
STRACE("mmap(%.12p, %p) ENOMEM (automap failed)", ADDR(*res), ADDR(n + 1));
|
||||
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);
|
||||
if (UNLIKELY(dm.addr == MAP_FAILED)) {
|
||||
if (IsWindows() && (flags & MAP_FIXED)) {
|
||||
STRACE("mmap(%.12p, %'ld) → %m (%s)", addr, size,
|
||||
"can't recover from MAP_FIXED errors on Windows");
|
||||
assert(!"MapMemory() failed");
|
||||
Die();
|
||||
OnUnrecoverableMmapError(
|
||||
"can't recover from MAP_FIXED errors on Windows");
|
||||
}
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if (UNLIKELY(dm.addr != addr)) {
|
||||
STRACE("KERNEL DIDN'T RESPECT MAP_FIXED");
|
||||
assert(!"MapMemory() failed");
|
||||
Die();
|
||||
OnUnrecoverableMmapError("KERNEL DIDN'T RESPECT MAP_FIXED");
|
||||
}
|
||||
if (!IsWindows() && (flags & MAP_FIXED)) {
|
||||
if (UntrackMemoryIntervals(addr, size)) {
|
||||
STRACE("FIXED UNTRACK FAILED %m");
|
||||
assert(!"MapMemory() failed");
|
||||
Die();
|
||||
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
|
||||
}
|
||||
}
|
||||
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags, off,
|
||||
size)) {
|
||||
if (TrackMemoryInterval(&_mmi, x, x + (n - 1), dm.maphandle, prot, flags,
|
||||
false, false, off, size)) {
|
||||
if (sys_munmap(addr, n) == -1) {
|
||||
STRACE("TRACK MUNMAP FAILED %m");
|
||||
assert(!"MapMemory() failed");
|
||||
Die();
|
||||
OnUnrecoverableMmapError("TRACK MUNMAP 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) {
|
||||
int64_t oi, sz;
|
||||
struct DirectMap dm;
|
||||
bool iscow, readonlyfile;
|
||||
size_t i, m = (n - 1) * FRAMESIZE;
|
||||
assert(m < size && m + FRAMESIZE >= size);
|
||||
oi = fd == -1 ? 0 : off + m;
|
||||
sz = size - m;
|
||||
dm = sys_mmap(addr + m, sz, prot, f, fd, oi);
|
||||
if (dm.addr == MAP_FAILED) {
|
||||
STRACE("MapMemories(%.12p+%lx/%lx) %m", addr, m, size);
|
||||
return MAP_FAILED;
|
||||
}
|
||||
if (dm.addr == MAP_FAILED) return MAP_FAILED;
|
||||
iscow = (flags & MAP_PRIVATE) && fd != -1;
|
||||
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,
|
||||
flags, oi, sz) == -1) {
|
||||
STRACE("MapMemories(%.12p+%lx/%lx) unrecoverable failure #1 %m", addr, m,
|
||||
size);
|
||||
assert(!"MapMemories() failed");
|
||||
Die();
|
||||
flags, readonlyfile, iscow, oi, sz) == -1) {
|
||||
OnUnrecoverableMmapError("MapMemories unrecoverable #1");
|
||||
}
|
||||
for (i = 0; i < m; i += FRAMESIZE) {
|
||||
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);
|
||||
if (dm.addr == MAP_FAILED ||
|
||||
TrackMemoryInterval(&_mmi, x + i / FRAMESIZE, x + i / FRAMESIZE,
|
||||
dm.maphandle, prot, flags, oi, sz) == -1) {
|
||||
STRACE("MapMemories(%p+%x/%x) unrecoverable failure #2 %m", addr, i,
|
||||
size);
|
||||
assert(!"MapMemories() failed");
|
||||
Die();
|
||||
dm.maphandle, prot, flags, readonlyfile, iscow, oi,
|
||||
sz) == -1) {
|
||||
OnUnrecoverableMmapError("MapMemories unrecoverable #2");
|
||||
}
|
||||
}
|
||||
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,
|
||||
int64_t off) {
|
||||
void *res;
|
||||
char *p = addr;
|
||||
struct DirectMap dm;
|
||||
int a, b, i, f, m, n, x;
|
||||
char mode[8], *p = addr;
|
||||
if (UNLIKELY(!size)) {
|
||||
STRACE("mmap(%.12p, %'zu) EINVAL (size=0)", p, size);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(!IsLegalSize(size))) {
|
||||
STRACE("mmap(%.12p, %'zu) EINVAL (size isn't 48-bit)", p, size);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 48-bit)", p, size);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("mmap(%.12p, %'zu) EINVAL (p isn't 64kb aligned)", p, size);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(fd < -1)) {
|
||||
if (!IsTiny() && UNLIKELY(!size)) {
|
||||
STRACE("size=0");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(!IsLegalSize(size))) {
|
||||
STRACE("size isn't 48-bit");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(!IsLegalPointer(p))) {
|
||||
STRACE("p isn't 48-bit");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("p isn't 64kb aligned");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(fd < -1)) {
|
||||
STRACE("mmap(%.12p, %'zu, fd=%d) EBADF", p, size, fd);
|
||||
return VIP(ebadf());
|
||||
}
|
||||
if (UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
|
||||
STRACE("mmap(%.12p, %'zu, %s, %d, %'ld) EINVAL (fd anonymous mismatch)", p,
|
||||
size, DescribeMapping(prot, flags, mode), fd, off);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
|
||||
STRACE("mmap(%.12p, %'zu) EINVAL (MAP_SHARED ^ MAP_PRIVATE)", p, size);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(off < 0)) {
|
||||
STRACE("mmap(%.12p, %'zu, off=%'ld) EINVAL (neg off)", p, size, off);
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(INT64_MAX - size < off)) {
|
||||
STRACE("mmap(%.12p, %'zu, off=%'ld) EINVAL (too large)", p, size, off);
|
||||
return VIP(einval());
|
||||
}
|
||||
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)) {
|
||||
res = VIP(ebadf());
|
||||
} else if (!IsTiny() && UNLIKELY(!((fd != -1) ^ !!(flags & MAP_ANONYMOUS)))) {
|
||||
STRACE("fd anonymous mismatch");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() &&
|
||||
UNLIKELY(!(!!(flags & MAP_PRIVATE) ^ !!(flags & MAP_SHARED)))) {
|
||||
STRACE("MAP_SHARED ^ MAP_PRIVATE");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(off < 0)) {
|
||||
STRACE("neg off");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(INT64_MAX - size < off)) {
|
||||
STRACE("too large");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && UNLIKELY(!ALIGNED(off))) {
|
||||
STRACE("p isn't 64kb aligned");
|
||||
res = VIP(einval());
|
||||
} else if (!IsTiny() && (flags & MAP_FIXED_NOREPLACE) && IsMapped(p, size)) {
|
||||
#ifdef SYSDEBUG
|
||||
if (OverlapsImageSpace(p, size)) {
|
||||
STRACE("mmap(%.12p, %'zu) EFAULT (overlaps image)", p, size);
|
||||
STRACE("overlaps image");
|
||||
} else {
|
||||
STRACE("mmap(%.12p, %'zu) EFAULT (overlaps existing)", p, size);
|
||||
STRACE("overlaps existing");
|
||||
}
|
||||
return VIP(efault());
|
||||
}
|
||||
if (__isfdkind(fd, kFdZip)) {
|
||||
STRACE("mmap(%.12p, %'zu) EINVAL (fd is zipos handle)", p, size);
|
||||
return VIP(einval());
|
||||
}
|
||||
STRACE("mmap(%.12p, %'zu, %s, %d, %'ld)% m", p, size,
|
||||
DescribeMapping(prot, flags, mode), fd, off);
|
||||
if (fd == -1) {
|
||||
size = ROUNDUP(size, FRAMESIZE);
|
||||
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();
|
||||
#endif
|
||||
res = VIP(efault());
|
||||
} else if (!IsTiny() && __isfdkind(fd, kFdZip)) {
|
||||
STRACE("fd is zipos handle");
|
||||
res = VIP(einval());
|
||||
} else {
|
||||
if (fd == -1) {
|
||||
size = ROUNDUP(size, FRAMESIZE);
|
||||
if (IsWindows()) {
|
||||
prot |= PROT_WRITE; /* kludge */
|
||||
}
|
||||
}
|
||||
} else if (!NeedAutomap(p, size)) {
|
||||
x = FRAME(p);
|
||||
} else if (!Automap(n, &x)) {
|
||||
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) return MAP_FAILED;
|
||||
}
|
||||
if (!IsWindows()) {
|
||||
return MapMemory(p, size, prot, flags, fd, off, f, x, n);
|
||||
} else {
|
||||
return MapMemories(p, size, prot, flags, fd, off, f, x, n);
|
||||
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)) {
|
||||
OnUnrecoverableMmapError("FIXED UNTRACK FAILED");
|
||||
}
|
||||
}
|
||||
} else if (!NeedAutomap(p, size)) {
|
||||
x = FRAME(p);
|
||||
} else if (!Automap(n, &x)) {
|
||||
STRACE("AUTOMAP OUT OF MEMORY D:");
|
||||
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;
|
||||
}
|
||||
|
|
107
libc/runtime/mprotect.greg.c
Normal file
107
libc/runtime/mprotect.greg.c
Normal 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;
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/intrin/asan.internal.h"
|
||||
#include "libc/intrin/describeflags.internal.h"
|
||||
#include "libc/macros.internal.h"
|
||||
#include "libc/nt/runtime.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
|
||||
*/
|
||||
void *mremap(void *p, size_t n, size_t m, int f, ... /* void *q */) {
|
||||
enosys();
|
||||
return MAP_FAILED;
|
||||
void *q;
|
||||
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;
|
||||
struct DirectMap dm;
|
||||
int a, b, prot, flags;
|
||||
assert(!__vforked);
|
||||
if (UNLIKELY(!m)) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (m=0)", p, n, m, f);
|
||||
STRACE("m=0");
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(!n)) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n=0)", p, n, m, f);
|
||||
} else if (UNLIKELY(!n)) {
|
||||
STRACE("n=0");
|
||||
return VIP(eopnotsupp());
|
||||
}
|
||||
if (UNLIKELY(!ALIGNED(n))) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n align)", p, n, m, f);
|
||||
} else if (UNLIKELY(!ALIGNED(n))) {
|
||||
STRACE("n align");
|
||||
return VIP(eopnotsupp());
|
||||
}
|
||||
if (UNLIKELY(!ALIGNED(m))) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EOPNOTSUPP (n align)", p, n, m, f);
|
||||
} else if (UNLIKELY(!ALIGNED(m))) {
|
||||
STRACE("n align");
|
||||
return VIP(eopnotsupp());
|
||||
}
|
||||
if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (64kb align)", p, n, m, f);
|
||||
} else if (UNLIKELY(!ALIGNED(p))) {
|
||||
STRACE("64kb align");
|
||||
return VIP(einval());
|
||||
}
|
||||
if (UNLIKELY(!IsLegalSize(n))) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (n too big)", p, n, m, f);
|
||||
} else if (UNLIKELY(!IsLegalSize(n))) {
|
||||
STRACE("n too big");
|
||||
return VIP(enomem());
|
||||
}
|
||||
if (UNLIKELY(!IsLegalSize(m))) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (m too big)", p, n, m, f);
|
||||
} else if (UNLIKELY(!IsLegalSize(m))) {
|
||||
STRACE("m too big");
|
||||
return VIP(enomem());
|
||||
}
|
||||
if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) {
|
||||
STRACE("mremap(%p, %'zu, %'zu, %#b) EINVAL (bad flag)", p, n, m, f);
|
||||
} else if (f & ~(MREMAP_MAYMOVE | MREMAP_FIXED)) {
|
||||
STRACE("bad flag");
|
||||
return VIP(einval());
|
||||
}
|
||||
if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) {
|
||||
STRACE("munmap(%p, %'zu) EFAULT (interval not tracked)", p, n);
|
||||
} else if (!IsMemtracked(FRAME(p), FRAME((intptr_t)p + (n - 1)))) {
|
||||
STRACE("interval not tracked");
|
||||
return VIP(efault());
|
||||
}
|
||||
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 */
|
||||
}
|
||||
if (f & MREMAP_FIXED) {
|
||||
va_start(va, f);
|
||||
q = va_arg(va, void *);
|
||||
va_end(va);
|
||||
if (!ALIGNED(q)) return VIP(einval());
|
||||
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 (TrackMemoryInterval(&_mmi, ((uintptr_t)p + n) >> 16,
|
||||
((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)) {
|
||||
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 (ReleaseMemoryIntervals(&_mmi, (uintptr_t)p >> 16,
|
||||
((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 (!OverlapsShadowSpace(p, n)) {
|
||||
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 {
|
||||
return q;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -29,6 +29,29 @@
|
|||
|
||||
#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) {
|
||||
char *a, *b;
|
||||
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;
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -52,7 +52,9 @@
|
|||
#if defined(__GNUC__) && defined(__ELF__) && !defined(__STRICT_ANSI__)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
extern char ape_stack_prot[] __attribute__((__weak__));
|
||||
extern char ape_stack_memsz[] __attribute__((__weak__));
|
||||
extern char ape_stack_align[] __attribute__((__weak__));
|
||||
|
||||
#define GetStackSize() ((uintptr_t)ape_stack_memsz)
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/strace.internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/elf/pf2prot.internal.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
|
@ -42,6 +43,7 @@
|
|||
#include "libc/nt/process.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/runtime/directmap.internal.h"
|
||||
#include "libc/runtime/internal.h"
|
||||
#include "libc/runtime/memtrack.internal.h"
|
||||
|
@ -53,8 +55,10 @@
|
|||
#if IsTiny()
|
||||
extern typeof(CreateFileMapping) *const __imp_CreateFileMappingW __msabi;
|
||||
extern typeof(MapViewOfFileEx) *const __imp_MapViewOfFileEx __msabi;
|
||||
extern typeof(VirtualProtect) *const __imp_VirtualProtect __msabi;
|
||||
#define CreateFileMapping __imp_CreateFileMappingW
|
||||
#define MapViewOfFileEx __imp_MapViewOfFileEx
|
||||
#define VirtualProtect __imp_VirtualProtect
|
||||
#endif
|
||||
|
||||
#define AT_EXECFN 31L
|
||||
|
@ -114,12 +118,11 @@ forceinline void MakeLongDoubleLongAgain(void) {
|
|||
static noasan textwindows wontreturn noinstrument void WinMainNew(
|
||||
const char16_t *cmdline) {
|
||||
bool32 rc;
|
||||
int64_t h;
|
||||
int version;
|
||||
int i, count;
|
||||
int64_t hand;
|
||||
int64_t h, hand;
|
||||
uint32_t oldprot;
|
||||
struct WinArgs *wa;
|
||||
const char16_t *env16;
|
||||
int i, prot, count, version;
|
||||
intptr_t stackaddr, allocaddr;
|
||||
size_t allocsize, argsize, stacksize;
|
||||
version = NtGetPeb()->OSMajorVersion;
|
||||
|
@ -152,9 +155,13 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
|
|||
CreateFileMapping(-1, &kNtIsInheritable, kNtPageExecuteReadwrite,
|
||||
allocsize >> 32, allocsize, NULL)),
|
||||
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].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].size = allocsize;
|
||||
_mmi.i = 1;
|
||||
|
@ -175,8 +182,8 @@ static noasan textwindows wontreturn noinstrument void WinMainNew(
|
|||
wa->auxv[0][0] = pushpop(AT_EXECFN);
|
||||
wa->auxv[0][1] = (intptr_t)wa->argv[0];
|
||||
STRACE("WinMainNew() switching stacks");
|
||||
_jmpstack((char *)stackaddr + stacksize, cosmo, count, wa->argv, wa->envp,
|
||||
wa->auxv);
|
||||
_jmpstack((char *)(stackaddr + stacksize - (intptr_t)ape_stack_align), cosmo,
|
||||
count, wa->argv, wa->envp, wa->auxv);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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_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_CONCEAL 0 0 0 0x8000 0 0 # omit from dumps
|
||||
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_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_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_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 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
|
||||
|
@ -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 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_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_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
|
||||
|
@ -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_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_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_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
|
||||
|
|
2
libc/sysv/consts/BUS_OOMERR.S
Normal file
2
libc/sysv/consts/BUS_OOMERR.S
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon sicode,BUS_OOMERR,-1,-1,100,-1,-1,-1
|
|
@ -1,2 +1,2 @@
|
|||
#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
|
||||
|
|
2
libc/sysv/consts/SEGV_PKUERR.S
Normal file
2
libc/sysv/consts/SEGV_PKUERR.S
Normal file
|
@ -0,0 +1,2 @@
|
|||
#include "libc/sysv/consts/syscon.internal.h"
|
||||
.syscon sicode,SEGV_PKUERR,-1,-1,100,-1,-1,-1
|
|
@ -23,6 +23,7 @@ extern const long TRAP_BRKPT;
|
|||
extern const long TRAP_TRACE;
|
||||
extern const long SEGV_MAPERR;
|
||||
extern const long SEGV_ACCERR;
|
||||
extern const long SEGV_PKUERR;
|
||||
extern const long FPE_INTDIV;
|
||||
extern const long FPE_INTOVF;
|
||||
extern const long FPE_FLTDIV;
|
||||
|
@ -44,6 +45,7 @@ extern const long BUS_ADRERR;
|
|||
extern const long BUS_OBJERR;
|
||||
extern const long BUS_MCEERR_AR;
|
||||
extern const long BUS_MCEERR_AO;
|
||||
extern const long BUS_OOMERR;
|
||||
extern const long POLL_IN;
|
||||
extern const long POLL_OUT;
|
||||
extern const long POLL_MSG;
|
||||
|
@ -87,6 +89,7 @@ COSMOPOLITAN_C_END_
|
|||
#define SI_ASYNCNL SYMBOLIC(SI_ASYNCNL)
|
||||
#define SI_KERNEL SYMBOLIC(SI_KERNEL)
|
||||
#define SI_NOINFO SYMBOLIC(SI_NOINFO)
|
||||
#define SEGV_PKUERR SYMBOLIC(SEGV_PKUERR)
|
||||
#define FPE_INTDIV SYMBOLIC(FPE_INTDIV)
|
||||
#define FPE_INTOVF SYMBOLIC(FPE_INTOVF)
|
||||
#define FPE_FLTDIV SYMBOLIC(FPE_FLTDIV)
|
||||
|
@ -99,6 +102,7 @@ COSMOPOLITAN_C_END_
|
|||
#define ILL_ILLADR SYMBOLIC(ILL_ILLADR)
|
||||
#define ILL_ILLTRP SYMBOLIC(ILL_ILLTRP)
|
||||
#define ILL_PRVOPC SYMBOLIC(ILL_PRVOPC)
|
||||
#define BUS_OOMERR SYMBOLIC(BUS_OOMERR)
|
||||
#define BUS_MCEERR_AR SYMBOLIC(BUS_MCEERR_AR)
|
||||
#define BUS_MCEERR_AO SYMBOLIC(BUS_MCEERR_AO)
|
||||
|
||||
|
|
|
@ -360,7 +360,7 @@ _init_systemfive_stack:
|
|||
mov __NR_mmap,%eax
|
||||
movabs $ape_stack_vaddr,%rdi
|
||||
mov $ape_stack_memsz,%esi
|
||||
mov $PROT_READ|PROT_WRITE,%edx
|
||||
mov $ape_stack_prot,%edx
|
||||
mov $MAP_PRIVATE|MAP_FIXED,%r10d
|
||||
or MAP_ANONYMOUS,%r10d
|
||||
or $-1,%r8d
|
||||
|
@ -548,6 +548,7 @@ syscon_windows:/*
|
|||
.previous
|
||||
#endif /* DEBUGSYS */
|
||||
|
||||
.weak ape_stack_prot
|
||||
.weak ape_stack_vaddr
|
||||
.weak ape_stack_memsz
|
||||
.weak ape_stack_align
|
||||
|
|
|
@ -124,11 +124,15 @@ TEST(sigaction, debugBreak_handlerCanReadCpuState) {
|
|||
// test fpu crash (unrecoverable)
|
||||
// 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;
|
||||
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 OnFpe(int sig, struct siginfo *si, struct ucontext *ctx) {
|
||||
SkipOverFaultingInstruction(ctx);
|
||||
ctx->uc_mcontext.rax = 42;
|
||||
ctx->uc_mcontext.rdx = 0;
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ static void RunTrackMemoryIntervalTest(const struct MemoryIntervals t[2], int x,
|
|||
struct MemoryIntervals *mm;
|
||||
mm = memcpy(malloc(sizeof(*t)), t, sizeof(*t));
|
||||
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);
|
||||
CheckMemoryIntervalsEqual(mm, t + 1);
|
||||
free(mm);
|
||||
|
@ -102,10 +102,10 @@ TEST(TrackMemoryInterval, TestFull) {
|
|||
mm = calloc(1, sizeof(struct MemoryIntervals));
|
||||
for (i = 0; i < mm->n; ++i) {
|
||||
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);
|
||||
}
|
||||
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);
|
||||
CheckMemoryIntervalsAreOk(mm);
|
||||
free(mm);
|
||||
|
|
212
test/libc/runtime/mprotect_test.c
Normal file
212
test/libc/runtime/mprotect_test.c
Normal 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);
|
||||
}
|
|
@ -35,8 +35,8 @@ testonly dontdiscard uint8_t *unbingx86op(const char16_t *codez) {
|
|||
* Long mode instruction length decoder.
|
||||
*/
|
||||
testonly int ild(const char16_t *codez) {
|
||||
int error;
|
||||
struct XedDecodedInst xedd;
|
||||
enum XedError error;
|
||||
error = xed_instruction_length_decode(
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64),
|
||||
gc(unbingx86op(codez)), strlen16(codez) + 16);
|
||||
|
@ -47,8 +47,8 @@ testonly int ild(const char16_t *codez) {
|
|||
* Real mode instruction length decoder.
|
||||
*/
|
||||
testonly int ildreal(const char16_t *codez) {
|
||||
int error;
|
||||
struct XedDecodedInst xedd;
|
||||
enum XedError error;
|
||||
error = xed_instruction_length_decode(
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_REAL),
|
||||
gc(unbingx86op(codez)), strlen16(codez) + 16);
|
||||
|
@ -59,8 +59,8 @@ testonly int ildreal(const char16_t *codez) {
|
|||
* Legacy mode instruction length decoder.
|
||||
*/
|
||||
testonly int ildlegacy(const char16_t *codez) {
|
||||
int error;
|
||||
struct XedDecodedInst xedd;
|
||||
enum XedError error;
|
||||
error = xed_instruction_length_decode(
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LEGACY_32),
|
||||
gc(unbingx86op(codez)), strlen16(codez) + 16);
|
||||
|
|
9
third_party/dlmalloc/dlmalloc.c
vendored
9
third_party/dlmalloc/dlmalloc.c
vendored
|
@ -380,9 +380,14 @@ int dlmalloc_sys_trim(struct MallocState *m, size_t pad) {
|
|||
size_t newsize = sp->size - extra;
|
||||
(void)newsize; /* placate people compiling -Wunused-variable */
|
||||
/* Prefer mremap, fall back to munmap */
|
||||
if ((mremap(sp->base, sp->size, newsize, 0, 0) != MAP_FAILED) ||
|
||||
(munmap(sp->base + newsize, extra) == 0)) {
|
||||
int err = errno;
|
||||
if (mremap(sp->base, sp->size, newsize, 0, 0) != MAP_FAILED) {
|
||||
released = extra;
|
||||
} else {
|
||||
errno = err;
|
||||
if (!munmap(sp->base + newsize, extra)) {
|
||||
released = extra;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include "libc/errno.h"
|
||||
#include "third_party/dlmalloc/dlmalloc.internal.h"
|
||||
|
||||
/* 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 oldmmsize = oldsize + offset + MMAP_FOOT_PAD;
|
||||
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);
|
||||
errno = err;
|
||||
if (cp != CMFAIL) {
|
||||
mchunkptr newp = (mchunkptr)(cp + offset);
|
||||
size_t psize = newmmsize - offset - MMAP_FOOT_PAD;
|
||||
|
|
2
third_party/python/Python/xedmodule.c
vendored
2
third_party/python/Python/xedmodule.c
vendored
|
@ -46,9 +46,9 @@ too short, and lower numbers represent other errors.");
|
|||
static PyObject *
|
||||
xed_ild(PyObject *self, PyObject *args)
|
||||
{
|
||||
int e;
|
||||
Py_ssize_t n;
|
||||
const char *p;
|
||||
enum XedError e;
|
||||
struct XedDecodedInst xedd;
|
||||
if (!PyArg_ParseTuple(args, "y#:ild", &p, &n)) return 0;
|
||||
xed_decoded_inst_zero_set_mode(&xedd, XED_MACHINE_MODE_LONG_64);
|
||||
|
|
440
third_party/xed/x86.h
vendored
440
third_party/xed/x86.h
vendored
|
@ -38,277 +38,58 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
enum XedMachineMode {
|
||||
XED_MACHINE_MODE_REAL = XED_MODE_REAL,
|
||||
XED_MACHINE_MODE_LEGACY_32 = XED_MODE_LEGACY,
|
||||
XED_MACHINE_MODE_LONG_64 = XED_MODE_LONG,
|
||||
XED_MACHINE_MODE_UNREAL = 1 << 2 | XED_MODE_REAL,
|
||||
XED_MACHINE_MODE_LEGACY_16 = 2 << 2 | XED_MODE_REAL,
|
||||
XED_MACHINE_MODE_LONG_COMPAT_16 = 3 << 2 | XED_MODE_REAL,
|
||||
XED_MACHINE_MODE_LONG_COMPAT_32 = 4 << 2 | XED_MODE_LEGACY,
|
||||
XED_MACHINE_MODE_LAST,
|
||||
};
|
||||
#define XED_MACHINE_MODE_REAL XED_MODE_REAL
|
||||
#define XED_MACHINE_MODE_LEGACY_32 XED_MODE_LEGACY
|
||||
#define XED_MACHINE_MODE_LONG_64 XED_MODE_LONG
|
||||
#define XED_MACHINE_MODE_UNREAL (1 << 2 | XED_MODE_REAL)
|
||||
#define XED_MACHINE_MODE_LEGACY_16 (2 << 2 | XED_MODE_REAL)
|
||||
#define XED_MACHINE_MODE_LONG_COMPAT_16 (3 << 2 | XED_MODE_REAL)
|
||||
#define XED_MACHINE_MODE_LONG_COMPAT_32 (4 << 2 | XED_MODE_LEGACY)
|
||||
#define XED_MACHINE_MODE_LAST (XED_MACHINE_MODE_LONG_COMPAT_32 + 1)
|
||||
|
||||
enum XedError {
|
||||
XED_ERROR_NONE,
|
||||
XED_ERROR_BUFFER_TOO_SHORT,
|
||||
XED_ERROR_GENERAL_ERROR,
|
||||
XED_ERROR_INVALID_FOR_CHIP,
|
||||
XED_ERROR_BAD_REGISTER,
|
||||
XED_ERROR_BAD_LOCK_PREFIX,
|
||||
XED_ERROR_BAD_REP_PREFIX,
|
||||
XED_ERROR_BAD_LEGACY_PREFIX,
|
||||
XED_ERROR_BAD_REX_PREFIX,
|
||||
XED_ERROR_BAD_EVEX_UBIT,
|
||||
XED_ERROR_BAD_MAP,
|
||||
XED_ERROR_BAD_EVEX_V_PRIME,
|
||||
XED_ERROR_BAD_EVEX_Z_NO_MASKING,
|
||||
XED_ERROR_NO_OUTPUT_POINTER,
|
||||
XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED,
|
||||
XED_ERROR_BAD_MEMOP_INDEX,
|
||||
XED_ERROR_CALLBACK_PROBLEM,
|
||||
XED_ERROR_GATHER_REGS,
|
||||
XED_ERROR_INSTR_TOO_LONG,
|
||||
XED_ERROR_INVALID_MODE,
|
||||
XED_ERROR_BAD_EVEX_LL,
|
||||
XED_ERROR_UNIMPLEMENTED,
|
||||
XED_ERROR_LAST
|
||||
};
|
||||
#define XED_ERROR_NONE 0
|
||||
#define XED_ERROR_BUFFER_TOO_SHORT 1
|
||||
#define XED_ERROR_GENERAL_ERROR 2
|
||||
#define XED_ERROR_INVALID_FOR_CHIP 3
|
||||
#define XED_ERROR_BAD_REGISTER 4
|
||||
#define XED_ERROR_BAD_LOCK_PREFIX 5
|
||||
#define XED_ERROR_BAD_REP_PREFIX 6
|
||||
#define XED_ERROR_BAD_LEGACY_PREFIX 7
|
||||
#define XED_ERROR_BAD_REX_PREFIX 8
|
||||
#define XED_ERROR_BAD_EVEX_UBIT 9
|
||||
#define XED_ERROR_BAD_MAP 10
|
||||
#define XED_ERROR_BAD_EVEX_V_PRIME 11
|
||||
#define XED_ERROR_BAD_EVEX_Z_NO_MASKING 12
|
||||
#define XED_ERROR_NO_OUTPUT_POINTER 13
|
||||
#define XED_ERROR_NO_AGEN_CALL_BACK_REGISTERED 14
|
||||
#define XED_ERROR_BAD_MEMOP_INDEX 15
|
||||
#define XED_ERROR_CALLBACK_PROBLEM 16
|
||||
#define XED_ERROR_GATHER_REGS 17
|
||||
#define XED_ERROR_INSTR_TOO_LONG 18
|
||||
#define XED_ERROR_INVALID_MODE 19
|
||||
#define XED_ERROR_BAD_EVEX_LL 20
|
||||
#define XED_ERROR_UNIMPLEMENTED 21
|
||||
#define XED_ERROR_LAST 22
|
||||
|
||||
enum XedAddressWidth {
|
||||
XED_ADDRESS_WIDTH_INVALID = 0,
|
||||
XED_ADDRESS_WIDTH_16b = 2,
|
||||
XED_ADDRESS_WIDTH_32b = 4,
|
||||
XED_ADDRESS_WIDTH_64b = 8,
|
||||
XED_ADDRESS_WIDTH_LAST
|
||||
};
|
||||
#define XED_ADDRESS_WIDTH_INVALID 0
|
||||
#define XED_ADDRESS_WIDTH_16b 2
|
||||
#define XED_ADDRESS_WIDTH_32b 4
|
||||
#define XED_ADDRESS_WIDTH_64b 8
|
||||
#define XED_ADDRESS_WIDTH_LAST 9
|
||||
|
||||
enum XedChip {
|
||||
XED_CHIP_INVALID = 1,
|
||||
XED_CHIP_I86 = 2,
|
||||
XED_CHIP_I86FP = 3,
|
||||
XED_CHIP_I186 = 4,
|
||||
XED_CHIP_I186FP = 5,
|
||||
XED_CHIP_I286REAL = 6,
|
||||
XED_CHIP_I286 = 7,
|
||||
XED_CHIP_I2186FP = 8,
|
||||
XED_CHIP_I386REAL = 9,
|
||||
XED_CHIP_I386 = 10,
|
||||
XED_CHIP_I386FP = 11,
|
||||
XED_CHIP_I486REAL = 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];
|
||||
};
|
||||
#define XED_ILD_MAP0 0 /* 8086+ ... */
|
||||
#define XED_ILD_MAP1 1 /* 286+ 0x0F,... */
|
||||
#define XED_ILD_MAP2 2 /* Core2+ 0x0F,0x38,... */
|
||||
#define XED_ILD_MAP3 3 /* Core2+ 0x0F,0x3A,... */
|
||||
#define XED_ILD_MAP4 4
|
||||
#define XED_ILD_MAP5 5
|
||||
#define XED_ILD_MAP6 6
|
||||
#define XED_ILD_MAPAMD 7
|
||||
#define XED_ILD_MAP_XOP8 8
|
||||
#define XED_ILD_MAP_XOP9 9
|
||||
#define XED_ILD_MAP_XOPA 10
|
||||
#define XED_ILD_MAP_LAST 11
|
||||
#define XED_ILD_MAP_INVALID 12
|
||||
|
||||
struct XedOperands { /*
|
||||
┌rep
|
||||
|
@ -341,7 +122,7 @@ struct XedOperands { /*
|
|||
uint8_t opcode;
|
||||
uint8_t srm : 3;
|
||||
};
|
||||
uint8_t map : 4; // enum XedIldMap
|
||||
uint8_t map : 4;
|
||||
};
|
||||
uint16_t dispatch;
|
||||
};
|
||||
|
@ -353,16 +134,16 @@ struct XedOperands { /*
|
|||
uint8_t scale : 2;
|
||||
};
|
||||
};
|
||||
bool osz : 1; // operand size override prefix
|
||||
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 rexr : 1; // rex.r or rex.wr or etc. see modrm table
|
||||
bool rex : 1; // any rex prefix including rex
|
||||
bool rexx : 1; // rex.x or rex.wx or etc. see sib table
|
||||
bool rexrr : 1; // evex
|
||||
bool asz : 1; // address size override
|
||||
int64_t disp; // displacement(%xxx) mostly sign-extended
|
||||
uint64_t uimm0; // $immediate mostly sign-extended
|
||||
bool osz : 1; /* operand size override prefix */
|
||||
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 rexr : 1; /* rex.r or rex.wr or etc. see modrm table */
|
||||
bool rex : 1; /* any rex prefix including rex */
|
||||
bool rexx : 1; /* rex.x or rex.wx or etc. see sib table */
|
||||
bool rexrr : 1; /* evex */
|
||||
bool asz : 1; /* address size override */
|
||||
int64_t disp; /* displacement(%xxx) mostly sign-extended */
|
||||
uint64_t uimm0; /* $immediate mostly sign-extended */
|
||||
bool out_of_bytes : 1;
|
||||
bool is_intel_specific : 1;
|
||||
bool ild_f2 : 1;
|
||||
|
@ -372,7 +153,7 @@ struct XedOperands { /*
|
|||
bool amd3dnow : 1;
|
||||
bool lock : 1;
|
||||
union {
|
||||
uint8_t modrm; // selects address register
|
||||
uint8_t modrm; /* selects address register */
|
||||
struct {
|
||||
uint8_t rm : 3;
|
||||
uint8_t reg : 3;
|
||||
|
@ -380,33 +161,33 @@ struct XedOperands { /*
|
|||
};
|
||||
};
|
||||
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;
|
||||
bool imm_signed : 1; // internal
|
||||
bool disp_unsigned : 1; // internal
|
||||
uint8_t seg_ovd : 3; // XED_SEG_xx
|
||||
uint8_t error : 5; // enum XedError
|
||||
uint8_t mode : 2; // real,legacy,long
|
||||
uint8_t hint : 3; // static branch prediction
|
||||
uint8_t uimm1; // enter $x,$y
|
||||
uint8_t disp_width; // in bits
|
||||
uint8_t imm_width; // in bits
|
||||
uint8_t mode_first_prefix; // see xed_set_chip_modes()
|
||||
bool imm_signed : 1; /* internal */
|
||||
bool disp_unsigned : 1; /* internal */
|
||||
uint8_t seg_ovd : 3; /* XED_SEG_xx */
|
||||
uint8_t error : 5; /* enum XedError */
|
||||
uint8_t mode : 2; /* real,legacy,long */
|
||||
uint8_t hint : 3; /* static branch prediction */
|
||||
uint8_t uimm1; /* enter $x,$y */
|
||||
uint8_t disp_width; /* in bits */
|
||||
uint8_t imm_width; /* in bits */
|
||||
uint8_t mode_first_prefix; /* see xed_set_chip_modes() */
|
||||
uint8_t nrexes;
|
||||
uint8_t nprefixes;
|
||||
uint8_t nseg_prefixes;
|
||||
uint8_t ubit; // vex
|
||||
uint8_t vexvalid; // vex
|
||||
uint8_t vexdest3; // vex
|
||||
uint8_t vexdest4; // vex
|
||||
uint8_t vexdest210; // vex
|
||||
uint8_t vex_prefix; // vex
|
||||
uint8_t zeroing; // evex
|
||||
uint8_t bcrc; // evex
|
||||
uint8_t llrc; // evex
|
||||
uint8_t vl; // evex
|
||||
uint8_t mask; // evex
|
||||
uint8_t imm1_bytes; // evex
|
||||
uint8_t ubit; /* vex */
|
||||
uint8_t vexvalid; /* vex */
|
||||
uint8_t vexdest3; /* vex */
|
||||
uint8_t vexdest4; /* vex */
|
||||
uint8_t vexdest210; /* vex */
|
||||
uint8_t vex_prefix; /* vex */
|
||||
uint8_t zeroing; /* evex */
|
||||
uint8_t bcrc; /* evex */
|
||||
uint8_t llrc; /* evex */
|
||||
uint8_t vl; /* evex */
|
||||
uint8_t mask; /* evex */
|
||||
uint8_t imm1_bytes; /* evex */
|
||||
uint8_t pos_disp;
|
||||
uint8_t pos_imm;
|
||||
uint8_t pos_imm1;
|
||||
|
@ -421,8 +202,7 @@ struct XedDecodedInst {
|
|||
struct XedOperands op;
|
||||
};
|
||||
|
||||
forceinline void xed_operands_set_mode(struct XedOperands *p,
|
||||
enum XedMachineMode mmode) {
|
||||
forceinline void xed_operands_set_mode(struct XedOperands *p, int mmode) {
|
||||
p->realmode = false;
|
||||
switch (mmode) {
|
||||
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 uint64_t kXedChipFeatures[XED_CHIP_LAST][3];
|
||||
extern const uint8_t kXedEamode[2][3];
|
||||
|
||||
struct XedDecodedInst *xed_decoded_inst_zero_set_mode(struct XedDecodedInst *,
|
||||
enum XedMachineMode);
|
||||
|
||||
enum XedError xed_instruction_length_decode(struct XedDecodedInst *,
|
||||
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);
|
||||
int);
|
||||
int xed_instruction_length_decode(struct XedDecodedInst *, const void *,
|
||||
size_t);
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
2
third_party/xed/x86features.c
vendored
2
third_party/xed/x86features.c
vendored
|
@ -16,7 +16,7 @@
|
|||
│ See the License for the specific language governing permissions and │
|
||||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "third_party/xed/x86isa.h"
|
||||
|
||||
asm(".ident\t\"\\n\\n\
|
||||
Xed (Apache 2.0)\\n\
|
||||
|
|
6
third_party/xed/x86ild.greg.c
vendored
6
third_party/xed/x86ild.greg.c
vendored
|
@ -1115,7 +1115,7 @@ privileged static void xed_decode_instruction_length(
|
|||
* Clears instruction decoder state.
|
||||
*/
|
||||
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));
|
||||
xed_operands_set_mode(&p->op, mmode);
|
||||
return p;
|
||||
|
@ -1131,8 +1131,8 @@ privileged struct XedDecodedInst *xed_decoded_inst_zero_set_mode(
|
|||
* @note binary footprint increases ~4kb if this is used
|
||||
* @see biggest code in gdb/clang/tensorflow binaries
|
||||
*/
|
||||
privileged enum XedError xed_instruction_length_decode(
|
||||
struct XedDecodedInst *xedd, const void *itext, size_t bytes) {
|
||||
privileged int xed_instruction_length_decode(struct XedDecodedInst *xedd,
|
||||
const void *itext, size_t bytes) {
|
||||
__builtin_memcpy(xedd->bytes, itext, MIN(15, bytes));
|
||||
xedd->op.max_bytes = MIN(15, bytes);
|
||||
xed_decode_instruction_length(xedd);
|
||||
|
|
7
third_party/xed/x86isa.c
vendored
7
third_party/xed/x86isa.c
vendored
|
@ -17,6 +17,7 @@
|
|||
│ limitations under the License. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "third_party/xed/x86.h"
|
||||
#include "third_party/xed/x86isa.h"
|
||||
|
||||
asm(".ident\t\"\\n\\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]\"");
|
||||
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;
|
||||
n = isa_set / 64;
|
||||
r = isa_set - (64 * n);
|
||||
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;
|
||||
n = isa_set / 64;
|
||||
r = isa_set - (64 * n);
|
||||
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 (chip < XED_CHIP_LAST) {
|
||||
p->f[0] = kXedChipFeatures[chip][0];
|
||||
|
|
259
third_party/xed/x86isa.h
vendored
Normal file
259
third_party/xed/x86isa.h
vendored
Normal 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_ */
|
|
@ -38,7 +38,7 @@ const struct IdName kXedModeNames[] = {
|
|||
{XED_MACHINE_MODE_UNREAL, "unreal"},
|
||||
};
|
||||
|
||||
enum XedMachineMode g_mode;
|
||||
int g_mode;
|
||||
struct XedDecodedInst g_xedd;
|
||||
|
||||
wontreturn void ShowUsage(int rc, FILE *f) {
|
||||
|
|
|
@ -367,7 +367,6 @@ static bool hasonworkerstart;
|
|||
static bool hasonhttprequest;
|
||||
static bool hascontenttype;
|
||||
static bool ishandlingrequest;
|
||||
static bool keyboardinterrupt;
|
||||
static bool listeningonport443;
|
||||
static bool hasonprocesscreate;
|
||||
static bool hasonprocessdestroy;
|
||||
|
@ -384,6 +383,7 @@ static int changeuid;
|
|||
static int changegid;
|
||||
static int isyielding;
|
||||
static int statuscode;
|
||||
static int shutdownsig;
|
||||
static int sslpskindex;
|
||||
static int oldloglevel;
|
||||
static int maxpayloadsize;
|
||||
|
@ -477,24 +477,24 @@ static void OnUsr2(void) {
|
|||
meltdown = true;
|
||||
}
|
||||
|
||||
static void OnTerm(void) {
|
||||
static void OnTerm(int sig) {
|
||||
if (!terminated) {
|
||||
shutdownsig = sig;
|
||||
terminated = true;
|
||||
} else {
|
||||
killed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void OnInt(void) {
|
||||
keyboardinterrupt = true;
|
||||
OnTerm();
|
||||
static void OnInt(int sig) {
|
||||
OnTerm(sig);
|
||||
}
|
||||
|
||||
static void OnHup(void) {
|
||||
static void OnHup(int sig) {
|
||||
if (daemonize) {
|
||||
OnUsr1();
|
||||
} else {
|
||||
OnTerm();
|
||||
OnTerm(sig);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1182,6 +1182,18 @@ static void HandleWorkerExit(int pid, int ws, struct rusage *ru) {
|
|||
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) {
|
||||
int ws, pid;
|
||||
struct rusage ru;
|
||||
|
@ -1198,7 +1210,7 @@ static void WaitAll(void) {
|
|||
killed = false;
|
||||
terminated = false;
|
||||
WARNF("(srvr) redbean shall terminate harder");
|
||||
LOGIFNEG1(kill(0, SIGTERM));
|
||||
KillGroup();
|
||||
}
|
||||
errno = 0;
|
||||
continue;
|
||||
|
@ -6680,15 +6692,11 @@ static void Listen(void) {
|
|||
|
||||
static void HandleShutdown(void) {
|
||||
CloseServerFds();
|
||||
if (keyboardinterrupt) {
|
||||
INFOF("(srvr) received keyboard interrupt");
|
||||
} else {
|
||||
INFOF("(srvr) received term signal");
|
||||
if (!killed) {
|
||||
terminated = false;
|
||||
}
|
||||
DEBUGF("(srvr) sending TERM to process group");
|
||||
LOGIFNEG1(kill(0, SIGTERM));
|
||||
INFOF("(srvr) received %s", strsignal(shutdownsig));
|
||||
if (shutdownsig == SIGTERM) {
|
||||
if (!killed) terminated = false;
|
||||
INFOF("(srvr) killing process group");
|
||||
KillGroup();
|
||||
}
|
||||
WaitAll();
|
||||
}
|
||||
|
@ -6918,7 +6926,9 @@ void RedBean(int argc, char *argv[]) {
|
|||
// to children. the downside to doing this seems to be that
|
||||
// ctrl-c isn't propagating as expected when running redbean
|
||||
// underneath strace.com :|
|
||||
setpgid(getpid(), getpid());
|
||||
if (!IsWindows()) {
|
||||
setpgid(getpid(), getpid());
|
||||
}
|
||||
if (logpath) {
|
||||
close(2);
|
||||
open(logpath, O_APPEND | O_WRONLY | O_CREAT, 0640);
|
||||
|
|
Loading…
Reference in a new issue