mirror of
https://github.com/FEX-Emu/libunwind.git
synced 2024-11-27 16:30:50 +00:00
x86_64: Use sigprocmask from signal frames
Currently setcontext for x86_64 restores the signal mask, even
though it is never saved anywhere. This means the signal mask
is often garbage after an unw_resume.
(changed in commit f8a15e9679
)
It looks like this was a fix for the Gtest-resume-sig function -
testing if signal masks are restored across signal frames. The
root issue looks like that x86_64 only uses sigreturn for the exact
signal frame, and not for any decedant frames as well (as i64 does).
Instead, modify Gresume to use sigreturn if *any* frame on the stack
is a signal frame, so that we correct fixup the signal mask and any
sigaltstacks. The sigreturn os-specific functions are changed slightly
to copy in the saved ucontext structure if we are jumping farther
up the stack.
This should fix sigprocmask reported issues such as
https://github.com/dropbox/pyston/blob/master/libunwind_patches/0002-pyston-stop-x86_64-setcontext-restoring-uninitialize.patch
Tests pass on freebsd, linux
This commit is contained in:
parent
b707e13ca0
commit
29483327be
@ -192,6 +192,24 @@ x86_64_sigreturn (unw_cursor_t *cursor)
|
||||
ucontext_t *uc = (ucontext_t *)(c->sigcontext_addr +
|
||||
offsetof(struct sigframe, sf_uc));
|
||||
|
||||
uc->uc_mcontext.mc_r8 = c->uc->uc_mcontext.mc_r8;
|
||||
uc->uc_mcontext.mc_r9 = c->uc->uc_mcontext.mc_r9;
|
||||
uc->uc_mcontext.mc_r10 = c->uc->uc_mcontext.mc_r10;
|
||||
uc->uc_mcontext.mc_r11 = c->uc->uc_mcontext.mc_r11;
|
||||
uc->uc_mcontext.mc_r12 = c->uc->uc_mcontext.mc_r12;
|
||||
uc->uc_mcontext.mc_r13 = c->uc->uc_mcontext.mc_r13;
|
||||
uc->uc_mcontext.mc_r14 = c->uc->uc_mcontext.mc_r14;
|
||||
uc->uc_mcontext.mc_r15 = c->uc->uc_mcontext.mc_r15;
|
||||
uc->uc_mcontext.mc_rdi = c->uc->uc_mcontext.mc_rdi;
|
||||
uc->uc_mcontext.mc_rsi = c->uc->uc_mcontext.mc_rsi;
|
||||
uc->uc_mcontext.mc_rbp = c->uc->uc_mcontext.mc_rbp;
|
||||
uc->uc_mcontext.mc_rbx = c->uc->uc_mcontext.mc_rbx;
|
||||
uc->uc_mcontext.mc_rdx = c->uc->uc_mcontext.mc_rdx;
|
||||
uc->uc_mcontext.mc_rax = c->uc->uc_mcontext.mc_rax;
|
||||
uc->uc_mcontext.mc_rcx = c->uc->uc_mcontext.mc_rcx;
|
||||
uc->uc_mcontext.mc_rsp = c->uc->uc_mcontext.mc_rsp;
|
||||
uc->uc_mcontext.mc_rip = c->uc->uc_mcontext.mc_rip;
|
||||
|
||||
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
|
||||
(unsigned long long) c->dwarf.ip, uc);
|
||||
sigreturn(uc);
|
||||
|
@ -69,8 +69,6 @@ tdep_reuse_frame (struct dwarf_cursor *dw, struct dwarf_reg_state *rs)
|
||||
c->frame_info.cfa_reg_offset = 0;
|
||||
c->sigcontext_addr = dw->cfa;
|
||||
}
|
||||
else
|
||||
c->sigcontext_addr = 0;
|
||||
|
||||
Debug(5, "reuse frame ip=0x%lx cfa=0x%lx format=%d addr=0x%lx offset=%+d\n",
|
||||
dw->ip, dw->cfa, c->sigcontext_format, c->sigcontext_addr,
|
||||
@ -140,6 +138,10 @@ x86_64_sigreturn (unw_cursor_t *cursor)
|
||||
{
|
||||
struct cursor *c = (struct cursor *) cursor;
|
||||
struct sigcontext *sc = (struct sigcontext *) c->sigcontext_addr;
|
||||
struct mcontext_t *sc_mcontext = &((struct ucontext*)sc)->uc_mcontext;
|
||||
/* Copy in saved uc - all preserved regs are at the start of sigcontext */
|
||||
memcpy(sc_mcontext, &c->uc->uc_mcontext,
|
||||
DWARF_NUM_PRESERVED_REGS * sizeof(unw_word_t));
|
||||
|
||||
Debug (8, "resuming at ip=%llx via sigreturn(%p)\n",
|
||||
(unsigned long long) c->dwarf.ip, sc);
|
||||
|
@ -44,7 +44,7 @@ x86_64_local_resume (unw_addr_space_t as, unw_cursor_t *cursor, void *arg)
|
||||
at least. */
|
||||
dwarf_make_proc_info (&c->dwarf);
|
||||
|
||||
if (unlikely (c->sigcontext_format != X86_64_SCF_NONE))
|
||||
if (unlikely (c->sigcontext_addr != X86_64_SCF_NONE))
|
||||
{
|
||||
x86_64_sigreturn(cursor);
|
||||
abort();
|
||||
|
@ -25,19 +25,12 @@ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
|
||||
#include "ucontext_i.h"
|
||||
#if defined __linux__
|
||||
#include <asm/unistd.h>
|
||||
#define SIG_SETMASK 2
|
||||
#define SIGSET_BYTE_SIZE (64/8)
|
||||
#elif defined __FreeBSD__
|
||||
#include <sys/syscall.h>
|
||||
#endif
|
||||
|
||||
/* int _Ux86_64_setcontext (const ucontext_t *ucp)
|
||||
|
||||
Restores the machine context provided.
|
||||
Unlike the libc implementation, doesn't clobber %rax
|
||||
|
||||
|
||||
*/
|
||||
.global _Ux86_64_setcontext
|
||||
.type _Ux86_64_setcontext, @function
|
||||
@ -45,32 +38,11 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
_Ux86_64_setcontext:
|
||||
|
||||
#if defined __linux__
|
||||
/* restore signal mask
|
||||
sigprocmask(SIG_SETMASK, ucp->uc_sigmask, NULL, sizeof(sigset_t)) */
|
||||
push %rdi
|
||||
mov $__NR_rt_sigprocmask, %rax
|
||||
lea UC_SIGMASK(%rdi), %rsi
|
||||
mov $SIG_SETMASK, %rdi
|
||||
xor %rdx, %rdx
|
||||
mov $SIGSET_BYTE_SIZE, %r10
|
||||
syscall
|
||||
pop %rdi
|
||||
|
||||
/* restore fp state */
|
||||
mov UC_MCONTEXT_FPREGS_PTR(%rdi),%r8
|
||||
fldenv (%r8)
|
||||
ldmxcsr FPREGS_OFFSET_MXCSR(%r8)
|
||||
#elif defined __FreeBSD__
|
||||
/* restore signal mask */
|
||||
pushq %rdi
|
||||
xorl %edx,%edx
|
||||
leaq UC_SIGMASK(%rdi),%rsi
|
||||
movl $3,%edi/* SIG_SETMASK */
|
||||
movl $SYS_sigprocmask,%eax
|
||||
movq %rcx,%r10
|
||||
syscall
|
||||
popq %rdi
|
||||
|
||||
/* restore fp state */
|
||||
cmpq $UC_MCONTEXT_FPOWNED_FPU,UC_MCONTEXT_OWNEDFP(%rdi)
|
||||
jne 1f
|
||||
|
@ -74,7 +74,7 @@ handler (int sig)
|
||||
#endif
|
||||
{
|
||||
unw_word_t ip;
|
||||
sigset_t mask, oldmask;
|
||||
sigset_t mask;
|
||||
unw_context_t uc;
|
||||
unw_cursor_t c;
|
||||
char foo;
|
||||
@ -95,17 +95,13 @@ handler (int sig)
|
||||
|
||||
sigemptyset (&mask);
|
||||
sigaddset (&mask, SIGUSR2);
|
||||
sigprocmask (SIG_BLOCK, &mask, &oldmask);
|
||||
sigprocmask (SIG_BLOCK, &mask, NULL);
|
||||
kill (getpid (), SIGUSR2); /* pend SIGUSR2 */
|
||||
|
||||
signal (SIGUSR1, SIG_IGN);
|
||||
|
||||
if ((ret = unw_getcontext (&uc)) < 0)
|
||||
panic ("unw_getcontext() failed: ret=%d\n", ret);
|
||||
#if UNW_TARGET_X86_64
|
||||
/* unw_getcontext() doesn't save signal mask to avoid a syscall */
|
||||
uc.uc_sigmask = oldmask;
|
||||
#endif
|
||||
if ((ret = unw_init_local (&c, &uc)) < 0)
|
||||
panic ("unw_init_local() failed: ret=%d\n", ret);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user