Implement swapcontext() and makecontext()

This change introduces support for Linux-style uc_context manipulation
that's fast and works well on all supported OSes and architectures. It
also integrates with the Cosmpolitan runtime which can show backtraces
comprised of multiple stacks and fibers. See the test and example code
for further details. This will be used by Mold once it's been vendored
This commit is contained in:
Justine Tunney 2023-07-02 03:50:29 -07:00
parent 7ec84655b4
commit 197aa0d465
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
28 changed files with 617 additions and 355 deletions

View file

@ -214,7 +214,9 @@ o/$(MODE)/libc/calls/pledge-linux.o: private \
# these assembly files are safe to build on aarch64
o/$(MODE)/libc/calls/getcontext.o: libc/calls/getcontext.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/calls/setcontext2.o: libc/calls/setcontext2.S
o/$(MODE)/libc/calls/swapcontext.o: libc/calls/swapcontext.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/libc/calls/tailcontext.o: libc/calls/tailcontext.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
LIBC_CALLS_LIBS = $(foreach x,$(LIBC_CALLS_ARTIFACTS),$($(x)))

View file

@ -20,132 +20,14 @@
// Gets machine state.
//
// @return 0 on success, or -1 w/ errno
// @see makecontext()
// @see swapcontext()
// @see setcontext()
// @threadsafe
.ftrace1
getcontext:
#ifdef __x86_64__
pushf
pop 176(%rdi)
movaps %xmm0,480(%rdi)
movaps %xmm1,496(%rdi)
movaps %xmm2,512(%rdi)
movaps %xmm3,528(%rdi)
movaps %xmm4,544(%rdi)
movaps %xmm5,560(%rdi)
movaps %xmm6,576(%rdi)
movaps %xmm7,592(%rdi)
movaps %xmm8,608(%rdi)
movaps %xmm9,624(%rdi)
movaps %xmm10,640(%rdi)
movaps %xmm11,656(%rdi)
movaps %xmm12,672(%rdi)
movaps %xmm13,688(%rdi)
movaps %xmm14,704(%rdi)
movaps %xmm15,720(%rdi)
mov %r8,40(%rdi)
mov %r9,48(%rdi)
mov %r10,56(%rdi)
mov %r11,64(%rdi)
mov %r12,72(%rdi)
mov %r13,80(%rdi)
mov %r14,88(%rdi)
mov %r15,96(%rdi)
mov %rdi,104(%rdi)
mov %rsi,112(%rdi)
mov %rbp,120(%rdi)
mov %rbx,128(%rdi)
mov %rdx,136(%rdi)
mov %rax,144(%rdi)
mov %rcx,152(%rdi)
lea 320(%rdi),%rax
mov %rax,224(%rdi)
lea 8(%rsp),%rax
mov %rax,160(%rdi)
mov (%rsp),%rax
mov %rax,168(%rdi)
jmp __getcontext
#elif defined(__aarch64__)
stp x0,x1,[x0,184]
stp x2,x3,[x0,200]
stp x4,x5,[x0,216]
stp x6,x7,[x0,232]
stp x8,x9,[x0,248]
stp x10,x11,[x0,264]
stp x12,x13,[x0,280]
stp x14,x15,[x0,296]
stp x16,x17,[x0,312]
stp x18,x19,[x0,328]
stp x20,x21,[x0,344]
stp x22,x23,[x0,360]
stp x24,x25,[x0,376]
stp x26,x27,[x0,392]
stp x28,x29,[x0,408]
str x30,[x0,424]
mov x1,sp
str x1,[x0,432] // sp = caller's sp
str x30,[x0,440] // pc = caller's pc
b __getcontext
#else
#error "unsupported architecture"
#endif
.ftrace2
#include "libc/calls/getcontext.inc"
jmp __getcontextsig
.endfn getcontext,globl
.end
////////////////////////////////////////////////////////////////////////////////
noasan noubsan dontinstrument int getcontext(ucontext_t *uc) {
asm volatile("movaps\t%%xmm0,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[0]));
asm volatile("movaps\t%%xmm1,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[1]));
asm volatile("movaps\t%%xmm2,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[2]));
asm volatile("movaps\t%%xmm3,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[3]));
asm volatile("movaps\t%%xmm4,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[4]));
asm volatile("movaps\t%%xmm5,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[5]));
asm volatile("movaps\t%%xmm6,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[6]));
asm volatile("movaps\t%%xmm7,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[7]));
asm volatile("movaps\t%%xmm8,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[8]));
asm volatile("movaps\t%%xmm9,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[9]));
asm volatile("movaps\t%%xmm10,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[10]));
asm volatile("movaps\t%%xmm11,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[11]));
asm volatile("movaps\t%%xmm12,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[12]));
asm volatile("movaps\t%%xmm13,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[13]));
asm volatile("movaps\t%%xmm14,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[14]));
asm volatile("movaps\t%%xmm15,%0" : /* no outputs */ : "m"(uc->__fpustate.xmm[15]));
asm volatile("mov\t%%r8,%0" : "=m"(uc->uc_mcontext.r8));
asm volatile("mov\t%%r9,%0" : "=m"(uc->uc_mcontext.r9));
asm volatile("mov\t%%r10,%0" : "=m"(uc->uc_mcontext.r10));
asm volatile("mov\t%%r11,%0" : "=m"(uc->uc_mcontext.r11));
asm volatile("mov\t%%r12,%0" : "=m"(uc->uc_mcontext.r12));
asm volatile("mov\t%%r13,%0" : "=m"(uc->uc_mcontext.r13));
asm volatile("mov\t%%r14,%0" : "=m"(uc->uc_mcontext.r14));
asm volatile("mov\t%%r15,%0" : "=m"(uc->uc_mcontext.r15));
asm volatile("mov\t%%rdi,%0" : "=m"(uc->uc_mcontext.rdi));
asm volatile("mov\t%%rsi,%0" : "=m"(uc->uc_mcontext.rsi));
asm volatile("mov\t%%rbp,%0" : "=m"(uc->uc_mcontext.rbp));
asm volatile("mov\t%%rbx,%0" : "=m"(uc->uc_mcontext.rbx));
asm volatile("mov\t%%rdx,%0" : "=m"(uc->uc_mcontext.rdx));
asm volatile("mov\t%%rax,%0" : "=m"(uc->uc_mcontext.rax));
asm volatile("mov\t%%rcx,%0" : "=m"(uc->uc_mcontext.rcx));
uc->uc_mcontext.fpregs = &uc->__fpustate;
asm volatile("lea\t8(%%rsp),%%rax\n\t"
"mov\t%%rax,%0"
: "=m"(uc->uc_mcontext.rsp)
: /* no inputs */
: "rax");
asm volatile("mov\t(%%rsp),%%rax\n\t"
"mov\t%%rax,%0"
: "=m"(uc->uc_mcontext.rip)
: /* no inputs */
: "rax");
return 0;
}
noasan noubsan dontinstrument int getcontext(ucontext_t *uc) {
asm volatile("stp\tx0,x1,%0" : "=m"(uc->uc_mcontext.regs[0]));
asm volatile("stp\tx2,x3,%0" : "=m"(uc->uc_mcontext.regs[2]));
asm volatile("mov\tx1,sp\n\tstr\tx1,%0" : "=m"(uc->uc_mcontext.sp));
asm volatile("str\tx30,%0" : "=m"(uc->uc_mcontext.pc));
return 0;
}

89
libc/calls/getcontext.inc Normal file
View file

@ -0,0 +1,89 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-
│vi: set et ft=asm ts=8 tw=8 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.
╚─────────────────────────────────────────────────────────────────────────────*/
// @fileoverview textual include for loading processor state
#ifdef __x86_64__
mov %r8,40(%rdi)
mov %r9,48(%rdi)
mov %r10,56(%rdi)
mov %r11,64(%rdi)
mov %r12,72(%rdi)
mov %r13,80(%rdi)
mov %r14,88(%rdi)
mov %r15,96(%rdi)
mov %rdi,104(%rdi)
mov %rsi,112(%rdi)
mov %rbp,120(%rdi)
mov %rbx,128(%rdi)
mov %rdx,136(%rdi)
mov %rcx,152(%rdi)
lea 8(%rsp),%rax
mov %rax,160(%rdi) // rsp = caller's rsp
mov (%rsp),%rax
mov %rax,168(%rdi) // rip = return address
lea 608(%rdi),%rax
movaps %xmm0,-0x80(%rax)
movaps %xmm1,-0x70(%rax)
movaps %xmm2,-0x60(%rax)
movaps %xmm3,-0x50(%rax)
movaps %xmm4,-0x40(%rax)
movaps %xmm5,-0x30(%rax)
movaps %xmm6,-0x20(%rax)
movaps %xmm7,-0x10(%rax)
movaps %xmm8,0x00(%rax)
movaps %xmm9,0x10(%rax)
movaps %xmm10,0x20(%rax)
movaps %xmm11,0x30(%rax)
movaps %xmm12,0x40(%rax)
movaps %xmm13,0x50(%rax)
movaps %xmm14,0x60(%rax)
movaps %xmm15,0x70(%rax)
lea 320(%rdi),%rax // rax = &__fpustate
mov %rax,224(%rdi) // fpregs = rax
#elif defined(__aarch64__)
#define REGS(i) 184+i*8
stp xzr,x1,[x0,REGS(0)] // x0 = 0
stp x2,x3,[x0,REGS(2)]
stp x4,x5,[x0,REGS(4)]
stp x6,x7,[x0,REGS(6)]
stp x8,x9,[x0,REGS(8)]
stp x10,x11,[x0,REGS(10)]
stp x12,x13,[x0,REGS(12)]
stp x14,x15,[x0,REGS(14)]
stp x16,x17,[x0,REGS(16)]
stp x18,x19,[x0,REGS(18)]
stp x20,x21,[x0,REGS(20)]
stp x22,x23,[x0,REGS(22)]
stp x24,x25,[x0,REGS(24)]
stp x26,x27,[x0,REGS(26)]
stp x28,x29,[x0,REGS(28)]
str x30,[x0,REGS(30)]
mov x15,sp
stp x15,x30,[x0,REGS(31)] // sp, pc = caller sp, ret address
str xzr,[x0,448] // pstate = 0
str xzr,[x0,456] // no vectors yet
#else
#error "unsupported architecture"
#endif

View file

@ -1,136 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
// tailed called by setcontext() implementation
__setcontext:
#ifdef __x86_64__
mov 224(%rdi),%rax
test %rax,%rax
je 1f
movaps 160(%rax),%xmm0
movaps 176(%rax),%xmm1
movaps 192(%rax),%xmm2
movaps 208(%rax),%xmm3
movaps 224(%rax),%xmm4
movaps 240(%rax),%xmm5
movaps 256(%rax),%xmm6
movaps 272(%rax),%xmm7
movaps 288(%rax),%xmm8
movaps 304(%rax),%xmm9
movaps 320(%rax),%xmm10
movaps 336(%rax),%xmm11
movaps 352(%rax),%xmm12
movaps 368(%rax),%xmm13
movaps 384(%rax),%xmm14
movaps 400(%rax),%xmm15
1: push 176(%rdi)
popf
mov %rsi,%rsp
mov 40(%rdi),%r8
mov 48(%rdi),%r9
mov 56(%rdi),%r10
mov 64(%rdi),%r11
mov 72(%rdi),%r12
mov 80(%rdi),%r13
mov 88(%rdi),%r14
mov 96(%rdi),%r15
mov 112(%rdi),%rsi
mov 120(%rdi),%rbp
mov 128(%rdi),%rbx
mov 136(%rdi),%rdx
mov 144(%rdi),%rax
mov 152(%rdi),%rcx
xor %rax,%rax
push 168(%rdi)
mov 104(%rdi),%rdi
ret
#elif defined(__aarch64__)
mov sp,x1 // sp = second argument
ldr x30,[x0,440] // return address <- pc
ldp x28,x29,[x0,408] // x0 and x30 discarded
ldp x26,x27,[x0,392]
ldp x24,x25,[x0,376]
ldp x22,x23,[x0,360]
ldp x20,x21,[x0,344]
ldp x18,x19,[x0,328]
ldp x16,x17,[x0,312]
ldp x14,x15,[x0,296]
ldp x12,x13,[x0,280]
ldp x10,x11,[x0,264]
ldp x8,x9,[x0,248]
ldp x6,x7,[x0,232]
ldp x4,x5,[x0,216]
ldp x2,x3,[x0,200]
ldr x1,[x0,192]
mov w0,0
ret
#else
#error "unsupported architecture"
#endif
.endfn __setcontext,globl
.end
////////////////////////////////////////////////////////////////////////////////
noasan noubsan int __setcontext(const ucontext_t *uc) {
if (uc->uc_mcontext.fpregs) {
asm volatile("movaps\t%0,%%xmm0" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[0]));
asm volatile("movaps\t%0,%%xmm1" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[1]));
asm volatile("movaps\t%0,%%xmm2" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[2]));
asm volatile("movaps\t%0,%%xmm3" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[3]));
asm volatile("movaps\t%0,%%xmm4" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[4]));
asm volatile("movaps\t%0,%%xmm5" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[5]));
asm volatile("movaps\t%0,%%xmm6" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[6]));
asm volatile("movaps\t%0,%%xmm7" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[7]));
asm volatile("movaps\t%0,%%xmm8" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[8]));
asm volatile("movaps\t%0,%%xmm9" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[9]));
asm volatile("movaps\t%0,%%xmm10" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[10]));
asm volatile("movaps\t%0,%%xmm11" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[11]));
asm volatile("movaps\t%0,%%xmm12" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[12]));
asm volatile("movaps\t%0,%%xmm13" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[13]));
asm volatile("movaps\t%0,%%xmm14" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[14]));
asm volatile("movaps\t%0,%%xmm15" : /* no outputs */ : "m"(uc->uc_mcontext.fpregs->xmm[15]));
}
asm volatile("mov\t%0,%%r8" : /* no outputs */ : "m"(uc->uc_mcontext.r8));
asm volatile("mov\t%0,%%r9" : /* no outputs */ : "m"(uc->uc_mcontext.r9));
asm volatile("mov\t%0,%%r10" : /* no outputs */ : "m"(uc->uc_mcontext.r10));
asm volatile("mov\t%0,%%r11" : /* no outputs */ : "m"(uc->uc_mcontext.r11));
asm volatile("mov\t%0,%%r12" : /* no outputs */ : "m"(uc->uc_mcontext.r12));
asm volatile("mov\t%0,%%r13" : /* no outputs */ : "m"(uc->uc_mcontext.r13));
asm volatile("mov\t%0,%%r14" : /* no outputs */ : "m"(uc->uc_mcontext.r14));
asm volatile("mov\t%0,%%r15" : /* no outputs */ : "m"(uc->uc_mcontext.r15));
asm volatile("mov\t%0,%%rsi" : /* no outputs */ : "m"(uc->uc_mcontext.rsi));
asm volatile("mov\t%0,%%rbp" : /* no outputs */ : "m"(uc->uc_mcontext.rbp));
asm volatile("mov\t%0,%%rbx" : /* no outputs */ : "m"(uc->uc_mcontext.rbx));
asm volatile("mov\t%0,%%rdx" : /* no outputs */ : "m"(uc->uc_mcontext.rdx));
asm volatile("mov\t%0,%%rax" : /* no outputs */ : "m"(uc->uc_mcontext.rax));
asm volatile("mov\t%0,%%rcx" : /* no outputs */ : "m"(uc->uc_mcontext.rcx));
asm volatile("mov\t%0,%%rsp" : /* no outputs */ : "m"(uc->uc_mcontext.rsp));
asm volatile("xor\t%%rax,%%rax\n\t"
"push\t%0\n\t"
"mov\t%1,%%rdi\n\t"
"ret"
: /* no outputs */
: "m"(uc->uc_mcontext.rip), "m"(uc->uc_mcontext.rdi));
__builtin_unreachable();
}

View file

@ -6,9 +6,25 @@
COSMOPOLITAN_C_START_
#ifdef __x86_64__
#define SP rsp
#define PC rip
#define SP rsp
#define BP rbp
#define ARG0 rdi
#define ARG1 rsi
#define ARG2 rdx
#define ARG3 rcx
#define ARG4 r8
#define ARG5 r9
#elif defined(__aarch64__)
#define SP sp
#define PC pc
#define SP sp
#define BP regs[29]
#define ARG0 regs[0]
#define ARG1 regs[1]
#define ARG2 regs[2]
#define ARG3 regs[3]
#define ARG4 regs[4]
#define ARG5 regs[5]
#else
#error "unsupported architecture"
#endif

View file

@ -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
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2023 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,19 +16,45 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/ucontext.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/runtime/stack.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
#include "libc/macros.internal.h"
// this is tail called by the getcontext() implementation
int __getcontext(ucontext_t *uc) {
uc->uc_flags = 0;
uc->uc_link = 0;
uc->uc_stack.ss_sp = (void *)uc->uc_mcontext.SP;
uc->uc_stack.ss_flags = SS_ONSTACK;
uc->uc_stack.ss_size = uc->uc_mcontext.SP - GetStackAddr();
return sigprocmask(SIG_SETMASK, 0, &uc->uc_sigmask);
}
// Saves machine to 𝑥 and activates 𝑦, i.e.
//
// getcontext(x);
// setcontext(y);
//
// Except using this API is safer and goes 2x faster:
//
// swapcontext(x, y);
//
// @return 0 on success, or -1 w/ errno
// @returnstwice
// @threadsafe
.ftrace1
swapcontext:
.ftrace2
#include "libc/calls/getcontext.inc"
#ifdef __x86_64__
push %rbp
mov %rsp,%rbp
push %rsi
push %rsi
call __swapcontextsig
pop %rdi
pop %rdi
pop %rbp
test %eax,%eax
jnz 1f
#elif defined(__aarch64__)
stp x29,x30,[sp,#-32]!
mov x29,sp
str x1,[sp,16]
bl __swapcontextsig
ldr x1,[sp,16]
ldp x29,x30,[sp],#32
cbnz w0,1f
mov x0,x1
#endif
jmp __tailcontext
1: ret
.endfn swapcontext,globl

89
libc/calls/tailcontext.S Normal file
View file

@ -0,0 +1,89 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 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/macros.internal.h"
// tailed called by setcontext() implementation
__tailcontext:
#ifdef __x86_64__
lea 608(%rdi),%rax
movaps -0x80(%rax),%xmm0
movaps -0x70(%rax),%xmm1
movaps -0x60(%rax),%xmm2
movaps -0x50(%rax),%xmm3
movaps -0x40(%rax),%xmm4
movaps -0x30(%rax),%xmm5
movaps -0x20(%rax),%xmm6
movaps -0x10(%rax),%xmm7
movaps 0x00(%rax),%xmm8
movaps 0x10(%rax),%xmm9
movaps 0x20(%rax),%xmm10
movaps 0x30(%rax),%xmm11
movaps 0x40(%rax),%xmm12
movaps 0x50(%rax),%xmm13
movaps 0x60(%rax),%xmm14
movaps 0x70(%rax),%xmm15
mov 40(%rdi),%r8
mov 48(%rdi),%r9
mov 56(%rdi),%r10
mov 64(%rdi),%r11
mov 72(%rdi),%r12
mov 80(%rdi),%r13
mov 88(%rdi),%r14
mov 96(%rdi),%r15
mov 112(%rdi),%rsi
mov 120(%rdi),%rbp
mov 128(%rdi),%rbx
mov 136(%rdi),%rdx
mov 152(%rdi),%rcx
mov 160(%rdi),%rsp
push 168(%rdi)
mov 104(%rdi),%rdi
xor %eax,%eax
ret
#elif defined(__aarch64__)
#define REGS(i) 184+i*8
ldp x1,x16,[x0,REGS(31)] // sp, pc
mov sp,x1
ldr x30,[x0,REGS(30)]
ldp x28,x29,[x0,REGS(28)]
ldp x26,x27,[x0,REGS(26)]
ldp x24,x25,[x0,REGS(24)]
ldp x22,x23,[x0,REGS(22)]
ldp x20,x21,[x0,REGS(20)]
ldp x18,x19,[x0,REGS(18)]
ldr x17,[x0,REGS(17)]
ldp x14,x15,[x0,REGS(14)]
ldp x12,x13,[x0,REGS(12)]
ldp x10,x11,[x0,REGS(10)]
ldp x8,x9,[x0,REGS(8)]
ldp x6,x7,[x0,REGS(6)]
ldp x4,x5,[x0,REGS(4)]
ldp x2,x3,[x0,REGS(2)]
ldp x0,x1,[x0,REGS(0)]
br x16
#else
#error "unsupported architecture"
#endif
.endfn __tailcontext,globl

View file

@ -16,26 +16,30 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/struct/sigset.h"
#include "libc/calls/struct/ucontext.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/calls/struct/sigset.h"
#include "libc/sysv/consts/sig.h"
#include "libc/sysv/consts/ss.h"
int __setcontext(const ucontext_t *, uintptr_t);
int __tailcontext(const ucontext_t *);
/**
* Sets machine context.
*
* @return -1 on error w/ errno, otherwise won't return unless sent back
* @see swapcontext()
* @see makecontext()
* @see getcontext()
* @threadsafe
*/
int setcontext(const ucontext_t *uc) {
uintptr_t sp;
if (sigprocmask(SIG_SETMASK, &uc->uc_sigmask, 0)) return -1;
if (uc->uc_stack.ss_flags & (SS_DISABLE | SS_ONSTACK)) {
sp = uc->uc_mcontext.SP;
} else {
sp = (uintptr_t)uc->uc_stack.ss_sp & -16;
}
return __setcontext(uc, sp);
return __tailcontext(uc);
}
int __getcontextsig(ucontext_t *uc) {
return sigprocmask(SIG_SETMASK, 0, &uc->uc_sigmask);
}
int __swapcontextsig(ucontext_t *x, const ucontext_t *y) {
return sigprocmask(SIG_SETMASK, &y->uc_sigmask, &x->uc_sigmask);
}

View file

@ -41,24 +41,24 @@ struct sigcontext {
#ifdef __x86_64__
union {
struct {
uint64_t r8;
uint64_t r9;
uint64_t r10;
uint64_t r11;
uint64_t r12;
uint64_t r13;
uint64_t r14;
uint64_t r15;
uint64_t rdi;
uint64_t rsi;
uint64_t rbp;
uint64_t rbx;
uint64_t rdx;
uint64_t rax;
uint64_t rcx;
uint64_t rsp;
uint64_t rip;
uint64_t eflags;
uint64_t r8; /* 40 */
uint64_t r9; /* 48 */
uint64_t r10; /* 56 */
uint64_t r11; /* 64 */
uint64_t r12; /* 72 */
uint64_t r13; /* 80 */
uint64_t r14; /* 88 */
uint64_t r15; /* 96 */
uint64_t rdi; /* 104 */
uint64_t rsi; /* 112 */
uint64_t rbp; /* 120 */
uint64_t rbx; /* 128 */
uint64_t rdx; /* 136 */
uint64_t rax; /* 144 */
uint64_t rcx; /* 152 */
uint64_t rsp; /* 160 */
uint64_t rip; /* 168 */
uint64_t eflags; /* 176 */
uint16_t cs;
uint16_t gs;
uint16_t fs;
@ -102,8 +102,10 @@ struct ucontext {
typedef struct ucontext ucontext_t;
int getcontext(ucontext_t *);
int setcontext(const ucontext_t *);
int getcontext(ucontext_t *) dontthrow;
int setcontext(const ucontext_t *) dontthrow;
int swapcontext(ucontext_t *, const ucontext_t *) dontthrow returnstwice;
void makecontext(ucontext_t *, void (*)(), int, ...) dontthrow nocallback;
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -21,10 +21,10 @@
#include "libc/calls/struct/ucontext.internal.h"
#include "libc/calls/ucontext.h"
#include "libc/intrin/describebacktrace.internal.h"
#include "libc/intrin/kprintf.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/enum/exceptionhandleractions.h"
#include "libc/nt/enum/signal.h"
#include "libc/nt/enum/status.h"
#include "libc/nt/runtime.h"
#include "libc/nt/struct/ntexceptionpointers.h"
#include "libc/str/str.h"
@ -90,6 +90,10 @@ unsigned __wincrash(struct NtExceptionPointers *ep) {
code = SI_USER;
sig = SIGABRT;
break;
case kNtStatusIntegerOverflow:
code = FPE_INTOVF;
sig = SIGFPE;
break;
case kNtSignalFltDivideByZero:
code = FPE_FLTDIV;
sig = SIGFPE;

View file

@ -1,8 +0,0 @@
#ifndef COSMOPOLITAN_LIBC_CALLS_WINERR_INTERNAL_H_
#define COSMOPOLITAN_LIBC_CALLS_WINERR_INTERNAL_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_CALLS_WINERR_INTERNAL_H_ */