mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-07-17 08:00:32 +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
|
@ -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);
|
||||
|
|
44
libc/intrin/describemapflags.greg.c
Normal file
44
libc/intrin/describemapflags.greg.c
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*-*- 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/nt/enum/consolemodeflags.h"
|
||||
#include "libc/sysv/consts/map.h"
|
||||
#include "libc/sysv/consts/prot.h"
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue