[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Libunwind-devel] [PATCH] Use sigprocmask from signal frames,
Dave Watson <=