libunwind-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Libunwind-devel] [PATCH] Use sigprocmask from signal frames


From: Dave Watson
Subject: [Libunwind-devel] [PATCH] Use sigprocmask from signal frames
Date: Wed, 30 Nov 2016 11:40:20 -0800
User-agent: Mutt/1.6.0 (2016-04-01)

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 f8a15e9679e59872ca2)

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
---
 src/x86_64/Gos-freebsd.c | 18 ++++++++++++++++++
 src/x86_64/Gos-linux.c   |  6 ++++--
 src/x86_64/Gresume.c     |  2 +-
 src/x86_64/setcontext.S  | 32 ++------------------------------
 tests/Gtest-resume-sig.c |  8 ++------
 5 files changed, 27 insertions(+), 39 deletions(-)

diff --git a/src/x86_64/Gos-freebsd.c b/src/x86_64/Gos-freebsd.c
index e7e8da1..8701aef 100644
--- a/src/x86_64/Gos-freebsd.c
+++ b/src/x86_64/Gos-freebsd.c
@@ -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);
diff --git a/src/x86_64/Gos-linux.c b/src/x86_64/Gos-linux.c
index 9e1acfc..d1e98ea 100644
--- a/src/x86_64/Gos-linux.c
+++ b/src/x86_64/Gos-linux.c
@@ -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);
diff --git a/src/x86_64/Gresume.c b/src/x86_64/Gresume.c
index 6880d94..b590b1a 100644
--- a/src/x86_64/Gresume.c
+++ b/src/x86_64/Gresume.c
@@ -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();
diff --git a/src/x86_64/setcontext.S b/src/x86_64/setcontext.S
index 1af8b67..eb21c47 100644
--- a/src/x86_64/setcontext.S
+++ b/src/x86_64/setcontext.S
@@ -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 */
+    /* 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
diff --git a/tests/Gtest-resume-sig.c b/tests/Gtest-resume-sig.c
index 147ecd0..846bba9 100644
--- a/tests/Gtest-resume-sig.c
+++ b/tests/Gtest-resume-sig.c
@@ -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);
 
-- 
2.8.0-rc2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]